diff --git a/.agents/skills/worktrees-pnpm/SKILL.md b/.agents/skills/worktrees-pnpm/SKILL.md index affa9591..ab18930e 100644 --- a/.agents/skills/worktrees-pnpm/SKILL.md +++ b/.agents/skills/worktrees-pnpm/SKILL.md @@ -109,8 +109,15 @@ printf '{"hook_event_name":"WorktreeCreate","cwd":"%s","worktree_id":"probe"}' " | .agents/skills/worktrees-pnpm/scripts/worktree-create.sh # expect: /worktrees/probe on stdout, git chatter on stderr, exit 0 +# The id field is not stable across callers, so .worktreeId and .name are read +# too — `.name` is what a background agent's payload actually carries. +printf '{"hook_event_name":"WorktreeCreate","cwd":"%s","name":"probe-name"}' "$PWD" \ + | .agents/skills/worktrees-pnpm/scripts/worktree-create.sh +# expect: /worktrees/probe-name + printf '{"hook_event_name":"WorktreeRemove","worktree_path":"%s"}' "$PWD/worktrees/probe" \ | .agents/skills/worktrees-pnpm/scripts/worktree-remove.sh +# ...and the same for worktrees/probe-name ``` **2. Add the ignores** described in the next section. Skipping this is the single most common way diff --git a/.agents/skills/worktrees-pnpm/scripts/worktree-create.sh b/.agents/skills/worktrees-pnpm/scripts/worktree-create.sh index eeeaf84b..24d317cc 100755 --- a/.agents/skills/worktrees-pnpm/scripts/worktree-create.sh +++ b/.agents/skills/worktrees-pnpm/scripts/worktree-create.sh @@ -18,16 +18,26 @@ # Layout: /path/to/ -> /path/to//worktrees/ # # Contract (docs: code.claude.com/docs/en/hooks): -# stdin - JSON with .worktree_id (and .base_path, .cwd, .session_id, ...) +# stdin - JSON identifying the worktree, plus .base_path, .cwd, .session_id, ... +# The id field is NOT stable across callers: a background agent's +# payload carries `.name` (e.g. "agent-a5e1de46e730bdfd7") and no +# `.worktree_id` at all, so all three spellings are read +# (.worktree_id, .worktreeId, .name). Accepting only one of them +# fails worktree creation outright with a message that reads like the +# harness sent nothing. `.name` is the weakest of the three — it is +# justified by one captured payload, not a guaranteed contract — so a +# caller that sends an unrelated `.name` while genuinely lacking both +# id fields lands on the validation below and fails loudly, which is +# the intended floor rather than an accident. # stdout - the absolute path of the created worktree, plain text, REQUIRED # exit - non-zero, or zero with empty stdout, fails worktree creation # This hook replaces the default logic entirely, so it must run `git worktree add`. set -euo pipefail payload=$(cat) -worktree_id=$(printf '%s' "$payload" | jq -r '.worktree_id // empty') +worktree_id=$(printf '%s' "$payload" | jq -r '.worktree_id // .worktreeId // .name // empty') if [ -z "$worktree_id" ]; then - echo "WorktreeCreate: no .worktree_id on stdin" >&2 + echo "WorktreeCreate: stdin carried none of .worktree_id/.worktreeId/.name" >&2 exit 1 fi