mirror of
https://github.com/EveryInc/compound-engineering-plugin.git
synced 2026-06-19 15:41:46 +02:00
4cc1ee6fe2
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
80 lines
4.5 KiB
TypeScript
80 lines
4.5 KiB
TypeScript
import { readFileSync } from "fs"
|
|
import path from "path"
|
|
import { describe, expect, test } from "bun:test"
|
|
|
|
const SKILL_PATH = path.join(
|
|
process.cwd(),
|
|
"plugins/compound-engineering/skills/ce-worktree/SKILL.md",
|
|
)
|
|
const SKILL_BODY = readFileSync(SKILL_PATH, "utf8")
|
|
|
|
describe("ce-worktree SKILL.md", () => {
|
|
// Regression guard for https://github.com/EveryInc/compound-engineering-plugin/issues/764.
|
|
//
|
|
// The runtime Bash tool runs from the user's project CWD, not the skill
|
|
// directory — so `bash scripts/worktree-manager.sh` resolves against the
|
|
// user's project root, where the script does not exist, and fails with
|
|
// "No such file or directory". The fix is to invoke via
|
|
// `${CLAUDE_SKILL_DIR}` so the path resolves to the skill's own scripts
|
|
// directory across both marketplace-cached installs and `claude --plugin-dir`
|
|
// local development.
|
|
test("does not invoke worktree-manager.sh via a bare relative path", () => {
|
|
const codeFenceMatches = SKILL_BODY.match(/^bash scripts\/worktree-manager\.sh/gm)
|
|
expect(
|
|
codeFenceMatches,
|
|
"ce-worktree/SKILL.md re-introduced the bare 'bash scripts/worktree-manager.sh' antipattern — use 'bash \"${CLAUDE_SKILL_DIR}/scripts/worktree-manager.sh\"' instead. Bare relative paths fail at runtime because the Bash tool's CWD is the user's project, not the skill directory.",
|
|
).toBeNull()
|
|
})
|
|
|
|
test("instructs the agent to invoke worktree-manager.sh via a CLAUDE_SKILL_DIR-prefixed path", () => {
|
|
// Allow either `${CLAUDE_SKILL_DIR}` or `${CLAUDE_SKILL_DIR:-.}` (the
|
|
// cross-platform fallback form); both resolve correctly on Claude Code.
|
|
const skillDirPrefixed = /bash "\$\{CLAUDE_SKILL_DIR(?::-[^}]*)?\}\/scripts\/worktree-manager\.sh"/
|
|
expect(
|
|
skillDirPrefixed.test(SKILL_BODY),
|
|
"ce-worktree/SKILL.md must instruct the agent to run 'bash \"${CLAUDE_SKILL_DIR}/scripts/worktree-manager.sh\"' (or with a :- fallback) — relative paths fail at runtime because the Bash tool's CWD is the user's project, not the skill directory.",
|
|
).toBe(true)
|
|
})
|
|
|
|
// Regression guard for the cross-platform portability concern raised on
|
|
// PR #772. ce-worktree has no `ce_platforms` restriction, so it is exported
|
|
// to Codex/Gemini/Pi/etc. via filterSkillsByPlatform; none of those
|
|
// converters substitute `${CLAUDE_SKILL_DIR}`. Without a `:-` fallback,
|
|
// the variable expands to empty on those targets and `bash
|
|
// "/scripts/worktree-manager.sh"` fails. The `:-.` fallback yields the
|
|
// original bare-relative path (preserving prior behavior on those
|
|
// platforms) while Claude Code still gets the resolved skill directory.
|
|
test("uses a :- fallback so non-Claude targets get the bare relative path", () => {
|
|
expect(
|
|
SKILL_BODY.includes(`\${CLAUDE_SKILL_DIR:-.}/scripts/worktree-manager.sh`),
|
|
"ce-worktree/SKILL.md must use the `${CLAUDE_SKILL_DIR:-.}` fallback form so non-Claude targets (Codex, Gemini, Pi, etc.) — where the env var is unset — fall back to the bare relative path rather than expanding to '/scripts/worktree-manager.sh'.",
|
|
).toBe(true)
|
|
})
|
|
|
|
// Regression guard: each script invocation is `bash <abs-path>` at runtime,
|
|
// which does not match the user's typical allow rules (most have
|
|
// `Bash(bash -c:*)` at most, not `Bash(bash:*)`). Without `allowed-tools`
|
|
// granting permission for the specific script, users without
|
|
// `defaultMode: bypassPermissions` get an approval prompt every time they
|
|
// run the skill. The pattern is pinned to the script filename —
|
|
// `Bash(bash *)` would be too broad.
|
|
test("declares a narrow allowed-tools pattern for worktree-manager.sh", () => {
|
|
const frontmatter = SKILL_BODY.match(/^---\n([\s\S]*?)\n---/)
|
|
expect(frontmatter, "ce-worktree/SKILL.md must have YAML frontmatter").not.toBeNull()
|
|
const allowedTools = frontmatter![1].match(/^allowed-tools:\s*(.+)$/m)
|
|
expect(
|
|
allowedTools,
|
|
"ce-worktree/SKILL.md must declare `allowed-tools:` so users without bypassPermissions don't get a prompt every run.",
|
|
).not.toBeNull()
|
|
const tools = allowedTools![1]
|
|
expect(
|
|
tools.includes(`Bash(bash *worktree-manager.sh)`),
|
|
`ce-worktree/SKILL.md allowed-tools must include 'Bash(bash *worktree-manager.sh)' so the runtime Bash call passes the permission check without granting blanket Bash access (got: ${tools})`,
|
|
).toBe(true)
|
|
expect(
|
|
/Bash\(bash \*\)/.test(tools),
|
|
`ce-worktree/SKILL.md allowed-tools must NOT use the broad 'Bash(bash *)' pattern — pin to the script filename instead (got: ${tools})`,
|
|
).toBe(false)
|
|
})
|
|
})
|