Repository navigation
buildHookCommand writes an unquoted command, breaking on Windows under bash -c #1
Description
buildHookCommand writes the hook command unquoted, which breaks on Windows when Claude Code invokes it via bash -c
Summary
commitly init on Windows writes a hooks.* entry into ~/.claude/settings.json whose command string is the resolved executable path joined with the rest of the argv via a plain .join(" "), with no quoting around any element. On Windows, Claude Code runs hook commands through bash -c "<command>". Bash interprets an unquoted backslash as an escape character, so a Windows path like C:\Users\<user>\.bun\bin\commitly.exe gets mangled into C:UsersDELL.bunbincommitly.exe (each \ + letter pair is silently collapsed whenever the letter isn't a recognized bash escape sequence).
Root cause
src/hooks/install.ts:
export async function resolveCommitlyArgv(): Promise<string[]> {
const which = await Bun.$`which commitly`.quiet().nothrow();
const resolved = which.exitCode === 0 ? which.stdout.toString().trim() : "";
if (resolved) return [resolved];
const cliPath = new URL("../cli.ts", import.meta.url).pathname;
return ["bun", cliPath];
}
export async function buildHookCommand(tool: string, event: string): Promise<string> {
const argv = await resolveCommitlyArgv();
return [...argv, "hook", tool, event].join(" ");
}Neither the resolved executable path nor any other argv element is quoted before being joined into the final shell command string.
Observed failure (Windows, real install)
After commitly init --scope user --tools claude-code, the written SessionStart/Stop/SessionEnd hook commands looked like:
C:\Users\<user>\.bun\bin\commitly.exe hook claude-code SessionStart
Claude Code on Windows runs this via bash, and every subsequent session logged a non-blocking hook failure:
Failed with non-blocking status code: /usr/bin/bash: line 1:
C:UsersDELL.bunbincommitly.exe: command not found
(username redacted; this is a real, reproducible install, not a hypothetical)
As a result, commitly doctor reported 0 event(s) across 0 session(s) — the hook was silently failing on every session, and no events were ever captured.
Fix applied locally (workaround, not a PR)
Manually quoting the executable path in the three written command strings ("C:\Users\<user>\.bun\bin\commitly.exe" hook claude-code SessionStart) resolved it immediately — commitly doctor went from 0 event(s) to real captured events after the fix, and a fresh Claude Code session with the corrected hook produced no error.
Suggested fix
Quote each argv element in buildHookCommand (and anywhere else a resolved path is joined into a shell command string) before joining, e.g. wrapping any element containing a backslash, space, or other shell-significant character in double quotes. This would need to hold for both the which commitly resolution path and the ["bun", cliPath] fallback path, since both can contain Windows-style paths.
Environment
- OS: Windows (Claude Code hooks run through bash on this platform)
commitlyinstalled viagit clone+bun install+bun link(per this repo's own README, sincecommitlyon npm is an unrelated package)- Bun 1.4.2
Activity