Part of #100 (EPIC). Workstream N. One issue = one PR.
Source: zmem deep audit 2026-09-10 (https://claude.ai/code/artifact/39012f75-25f0-441b-978f-cc90a3bd3a9d) and issue plan v3 (https://claude.ai/code/artifact/59e74242-17da-4416-9b00-0b0cf347837c); dependency DAG computed over all open PRs (edge kinds: Depends on = merged artifact, Schema after = migration lane, Gated on = #100 measurement/decision gate).
Labels: bug, severity:medium. Depends on: none. Blocks: N-4 (#187), N-5 (#188), #96.
Problem. Claude shell-form hooks run under Git Bash with backslash and CRLF failures reported in 2026; the launcher hands .sh paths to whatever shell the host picks.
Design. hooks/hooks.claude.json entries become command: "node", args: ["${CLAUDE_PLUGIN_ROOT}/hooks/zmem-launch.js", "<verb>"]; the launcher exports resolveShell() (Git Bash via ZMEM_BASH_PATH, then Git for Windows install paths; Python via the existing chain) and spawns the wrapper with absolute paths converted for bash; N-4 (#187) and N-5 (#188) consume resolveShell().
Acceptance criteria. (a) tests/test_launcher.js runs every Claude verb with PATH stripped of Git Bash and asserts the committed expected envelope per verb. (b) Manifest test: every Claude entry has args and no shell metacharacters. (c) tests/test_release_parity.py passes. (d) test-windows green; no test removed.
Part of #100 (EPIC). Workstream N. One issue = one PR.
Source: zmem deep audit 2026-09-10 (https://claude.ai/code/artifact/39012f75-25f0-441b-978f-cc90a3bd3a9d) and issue plan v3 (https://claude.ai/code/artifact/59e74242-17da-4416-9b00-0b0cf347837c); dependency DAG computed over all open PRs (edge kinds: Depends on = merged artifact, Schema after = migration lane, Gated on = #100 measurement/decision gate).
Labels: bug, severity:medium. Depends on: none. Blocks: N-4 (#187), N-5 (#188), #96.
Problem. Claude shell-form hooks run under Git Bash with backslash and CRLF failures reported in 2026; the launcher hands
.shpaths to whatever shell the host picks.Design.
hooks/hooks.claude.jsonentries becomecommand: "node",args: ["${CLAUDE_PLUGIN_ROOT}/hooks/zmem-launch.js", "<verb>"]; the launcher exportsresolveShell()(Git Bash viaZMEM_BASH_PATH, then Git for Windows install paths; Python via the existing chain) and spawns the wrapper with absolute paths converted for bash; N-4 (#187) and N-5 (#188) consumeresolveShell().Acceptance criteria. (a)
tests/test_launcher.jsruns every Claude verb withPATHstripped of Git Bash and asserts the committed expected envelope per verb. (b) Manifest test: every Claude entry hasargsand no shell metacharacters. (c)tests/test_release_parity.pypasses. (d)test-windowsgreen; no test removed.