Skip to content

Commit dc6f0df

Browse files
committed
fix: write session end hook output to /dev/tty
Claude Code started capturing stderr from SessionEnd hooks instead of passing it through to the terminal, making the output invisible on macOS. Write directly to /dev/tty to bypass the capture, with stderr fallback for Windows where /dev/tty doesn't exist.
1 parent 30cb607 commit dc6f0df

File tree

2 files changed

+9
-4
lines changed

2 files changed

+9
-4
lines changed

CLAUDE.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ Claude Code stores logs at `~/.claude/projects/<project-slug>/`. Sessions are `<
4242
- **Local timezone everywhere** — local midnight for cutoffs, `parsed.Local()` for date bucketing. Never `UTC()` for user-facing dates
4343
- **MCP detection is best-effort** — returns nil/empty on error; statusline never fails due to missing config
4444
- **Config**`~/.goccc.json` stores currency, thresholds, and statusline config. `initConfig()` loads once. JSON output costs always in USD
45-
- **Session end hook**uses `os.Exit(2)` + ANSI escape to overwrite Claude Code's "hook failed" prefix. Silently exits on any error
45+
- **Session end hook**writes to `/dev/tty` (bypasses Claude Code's stderr capture), falls back to stderr on Windows. Silently exits on any error
4646
- **Statusline segments** — registry in `statusline_config.go`. Segments with no data auto-hide. `"|"` forces line break
4747

4848
## Don't

statusline.go

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -307,8 +307,13 @@ func runSessionEnd(baseDir string) {
307307
}
308308

309309
line := formatSessionEnd(sCost, tCost, reqs, dur, models)
310-
// ANSI: erase line + carriage return to overwrite Claude Code's
311-
// "SessionEnd hook [...] failed: " prefix before our content.
312-
fmt.Fprintf(os.Stderr, "\x1b[2K\r\n%s", line)
310+
// Write to /dev/tty to bypass Claude Code's stderr capture.
311+
// Falls back to stderr for platforms without /dev/tty (Windows).
312+
w := os.Stderr
313+
if tty, err := os.OpenFile("/dev/tty", os.O_WRONLY, 0); err == nil {
314+
w = tty
315+
defer func() { _ = tty.Close() }()
316+
}
317+
_, _ = fmt.Fprintf(w, "\x1b[2K\r\n%s\n", line)
313318
os.Exit(2)
314319
}

0 commit comments

Comments
 (0)