fix(skills): replace case statements blocked by permission check#701
Conversation
…n check Claude Code's shell permission checker AST-rejects `case` statements in `!` backtick pre-resolution commands with "Contains case_statement", failing the skill at load time before its body runs. Replace with permission-clean forms: `git rev-parse --path-format=absolute --git-common-dir` for worktree-stable repo names in ce-compound and ce-sessions; `grep -q` with `&&`/`||` chaining for CLAUDE_SKILL_DIR pattern matching in ce-update. Add a regression test that fails any new `case`/`esac` block in a pre-resolution command. Co-Authored-By: Claude Opus 4.7 (1M context) <[email protected]>
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: e1f08cad82
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
Parse `!` pre-resolution blocks across the full file body so multi-line commands are also checked. Add unit tests for single-line and multi-line parsing. Reviewer flagged that the line-by-line extractor would miss any `case ... esac` reintroduced inside a wrapped `!` block. Co-Authored-By: Claude Opus 4.7 (1M context) <[email protected]>
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 31a6448476
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
Guard the pre-resolved repo name so it stays empty when the skill is invoked outside a git repository. The `--path-format=absolute` form returns nothing in that case, but `basename "$(dirname "")"` produces a literal `.` which downstream logic in ce-compound and ce-sessions would treat as a valid repo name and pass to ce-session-historian. Capture the output and short-circuit on empty so the empty/sentinel failure path the SKILL.md gate already handles is preserved. Co-Authored-By: Claude Opus 4.7 (1M context) <[email protected]>
Roll the empty-fallback guard through the remaining places that share the same `git rev-parse` shape so the fix doesn't regress through the back door: - ce-session-historian.agent.md: replaced the documented `case "$common" in /*) ... esac` runtime fallback with the empty-guarded `--path-format=absolute --git-common-dir` form. The agent only runs this when pre-resolution from the dispatch prompt is empty, but with the new pre-resolution guard that case now happens cleanly outside a repo, so the agent's runtime fallback would have hit Claude Code's permission denial on `case_statement` instead of producing nothing. - AGENTS.md "Reading Config Files from Skills": replaced the unguarded config-reader idiom with subshell-scoped `[ -n "$top" ]` and `[ -n "$common" ]` checks. Outside a git repo, `dirname ""` resolves to `.` and the unguarded `cat "./.compound-engineering/config.local.yaml"` could pick up a stray file from the user's CWD; guarded, both branches fail and the `__NO_CONFIG__` sentinel takes over. Verified with a stray-file repro: old form cats the stray, new form hits the sentinel. - ce-work-beta/SKILL.md: same idiom update as AGENTS.md, since this is the only current consumer of the documented pattern. Co-Authored-By: Claude Opus 4.7 (1M context) <[email protected]>
…ryInc#701) Co-authored-by: Claude Opus 4.7 (1M context) <[email protected]>
/ce-compoundand/ce-sessionswere failing at skill-load withError: Shell command permission check failed ... Contains case_statement. Claude Code's shell permission checker AST-rejects bashcasein!backtick pre-resolution commands. PR #699 introduced the offending block in ce-compound and ce-sessions; ce-update has carried the same shape against${CLAUDE_SKILL_DIR}since PR #656 and would fail identically the next time/ce-updateran.ce-compound and ce-sessions now use
basename "$(dirname "$(git rev-parse --path-format=absolute --git-common-dir)")"for a worktree-stable repo name. This is the conditional-free idiom already documented in plugin AGENTS.md, with identical output in regular checkouts and worktrees. ce-update usesgrep -qplus&&/||chaining for its${CLAUDE_SKILL_DIR}pattern match. Output is identical to the originalcaseforms across all branches.tests/skill-shell-safety.test.tsscans every!block underplugins/*/skills/**/*.mdand fails any newcase/esac, guarding against reintroduction. The existingfrontmatter.test.tsvalidates the YAML header but never the body of!commands.