* fix(#1342): scope worktree-path-guard to GSD executor runs; fail open for no-repo targets
The PreToolUse worktree-path-guard fired for any Write/Edit in any linked git
worktree, with no check for active GSD work — so Claude Code plan-mode writing
~/.claude/plans/<slug>.md from a manually-created worktree was hard-blocked.
- Gate enforcement on the GSD isolated-executor branch namespace
(^worktree-agent-[A-Za-z0-9._/-]+$, per worktree-branch-check.md #2924); the
guard is a no-op in non-GSD linked worktrees.
- Fail open when a target resolves to no git repository (e.g. ~/.claude/plans/)
instead of blocking — that is not the #260 main-repo vector. A target inside
a .git directory still blocks (git rev-parse --is-inside-git-dir).
- The #260 different-git-root hard block (escape to the main repo) is preserved.
Detached-HEAD executors no-op the gate; this is accepted because they are
fail-closed by worktree-branch-check.md (exit 42) before committing.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
* chore(#1342): add changeset for worktree-path-guard scoping fix
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
* test(#1342): build dot-dot traversal path portably (Windows drive-letter fix)
The traversal test built its file_path by stripping a leading slash from an
absolute externalDir and path.join-ing it after a `..` chain. On Windows the
drive letter (C:\) is not a leading slash, so it survived and path.resolve
produced an invalid doubled-drive path (C:\C:\Users\...), which resolves to no
git repo — the hook failed open (exit 0) and the test expected a block (exit 2).
Use path.relative(worktreeDir, externalTarget) + string concat so the file_path
carries literal `..` segments that resolve to externalTarget on both posix and
win32 (no drive doubling). Verified with path.win32/path.posix.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>