fix(hooks): POSIX-normalize worktree path in SessionStart hook - #81
Conversation
writeSessionStartHook embedded the raw worktree path into the generated session-start.sh, unlike writeStopHook (L66) and writePreToolUseHook (L288) which convert backslashes via .replace(/\/g, "/"). On Windows this corrupted TASK_STATE_FILE (backslashes become bash escapes), so TASK_STATE.md was not re-injected after context compaction. Apply the same wtPosix conversion and add a regression test asserting the generated hook embeds a backslash-free POSIX path (exercised by the windows-latest CI job).
…ows-path # Conflicts: # tests/hooks-session-start.test.ts
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: cc83136e80
ℹ️ 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".
| expect(taskStateLine).toBeDefined(); | ||
| expect(taskStateLine).not.toContain("\\"); | ||
| expect(taskStateLine).toBe( | ||
| `TASK_STATE_FILE="${tmp.replace(/\/g, "/")}/TASK_STATE.md"`, |
There was a problem hiding this comment.
Escape the backslash in the regex literal
In any environment that runs the test suite or typecheck, this added assertion prevents the file from parsing: /\/g was intended, but the source currently reads as a malformed regex/string sequence (/\/g, "/") in the template expression), so Vitest/tsc will fail before these hook tests can run. Escape the backslash in the regex literal used to normalize tmp.
Useful? React with 👍 / 👎.
Problem (root cause)
writeSessionStartHookinsrc/core/hooks.tsembedded the raw worktree path (${worktreePath}) into the generatedsession-start.sh, unlike its siblingswriteStopHook(L66) andwritePreToolUseHook(L288), which normalize backslashes via.replace(/\/g, "/").On Windows, a worktree path like
C:\Users\…\sessionbecomesTASK_STATE_FILE="C:\Users\…\session/TASK_STATE.md"inside the bash hook, where\U,\s, … are interpreted as bash escapes. Result: after a context compaction, the SessionStart hook silently fails to re-injectTASK_STATE.md.Fix
const wtPosix = worktreePath.replace(/\/g, "/");and use${wtPosix}forTASK_STATE_FILE— matching the established pattern in the two sibling hook writers. Behavior is unchanged on POSIX; Windows is corrected.Test
tests/hooks-session-start.test.tsinstalls the hooks into a temp dir and asserts the generatedsession-start.shembeds a backslash-free POSIX path. This is exercised by the existingwindows-latestCI matrix job, where the old code would fail.Verification (local)
npm run typecheck✅ ·npm run lint✅ · new test ✅ (1 passed).hooks-circuit-breaker,hooks-blocklist) time out locally on Windows because theyspawnSync("bash", …)(slow on this machine, vitest 5s default). They are pre-existing onmainand pass on GitHub CI; a follow-up PR addsvitest.config.tswith a highertestTimeoutto remove that local flakiness.Scope: exactly 2 files (
src/core/hooks.ts,tests/hooks-session-start.test.ts).