Releases: tone4hook/headless-coding-agent-sdk
Releases · tone4hook/headless-coding-agent-sdk
v0.4.0
Highlights (breaking pre-1.0)
- error.code taxonomy:
errorevents now stamp a typedCoderErrorCode(rate_limit,auth_expired,context_too_large,network_error,timeout,binary_not_found,tool_crash,protocol_error,stalled,interrupted,unknown) plus a best-effortretryablehint.cancelledevents optionally carry'interrupted'/'stalled'. Per-adapter classifiers insrc/adapters/{claude,codex,gemini}/classify.ts. - stallTimeoutMs: new
RunOpts.stallTimeoutMsaborts a run if no normalized event is emitted for N ms; synthesizes anerrorwithcode: 'stalled'. - env hygiene: host env is now sanitized by default before spawn (strips
NODE_OPTIONS,npm_*,CLAUDECODE, etc.); auth/proxy/CA-bundle vars preserved. Opt out withcleanEnv: false; extend deny list viaadditionalDenyEnv. - detached spawn + tree-kill fallback: child CLIs now run in their own POSIX process group;
killProcessTreefalls back toprocess.kill(-pid)whentree-killerrors, so grandchildren are reliably reaped. - Claude
isolationpreset:isolation: 'strict' | 'project' | 'user'. Strict mode mints a per-spawnCLAUDE_CONFIG_DIR(viaextraEnv, never mutatesprocess.env) plus an empty MCP config so user plugins don't load. - opt-in exit cleanup:
installExitCleanup()+trackForExitCleanup()reap spawned CLIs on host SIGINT/SIGTERM/SIGHUP/uncaughtException. @tone4hook/headless-coding-agent-sdk/worktree: new subpath export withcreateWorktree/pruneStaleWorktrees.- UsageStats normalization: added
reasoningTokens; Codex now extracts cache + reasoning token breakdown; Gemini extracts cached + thoughts tokens. Newsrc/pricing.tswithestimateCostUsd(returnsundefinedfor unknown models — no NaN).
Notable behavior changes
- Env sanitation is on by default. Pass
cleanEnv: falseto restore prior pass-through behavior. errorevents now requirecode(was optionalstring).RunResult.error.codeis typed asCoderErrorCode.
206 tests, build + typecheck clean.
v0.3.0 — Codex adapter
Added
- Codex adapter — third supported CLI alongside
claudeandgemini. Newsrc/adapters/codex/module (flags, index, translate) plus factory wiring and re-exports. - Process-tree teardown helper at
src/transport/processTree.ts(withtree-killtypings) — used byspawn.tsto terminate child process trees cleanly. - Schema additions in
src/types.tsandsrc/adapters/shared/spec.tsto accommodate Codex-specific options without breaking existing Claude / Gemini call sites.
Changed
src/transport/spawn.tsupdated to support process-tree teardown.src/adapters/shared/thread.ts,claude/flags.ts,gemini/flags.tsadjusted for the unified three-adapter shape.
Tests
- New
test/codex-flags.test.tsandtest/translate-codex.test.ts; existing flag/spawn/factory tests updated. All 144 tests passing.
v0.2.1 — spawn stdin EOF fix
Fixed
- fix(transport): close stdin at EOF when no payload provided —
spawnClinow sends EOF onchild.stdinwhen noopts.stdinis supplied. Eliminates the ~3s/turn latency the Claude CLI incurred while waiting for possible stream-json stdin input before falling back to the argv-pprompt.
Per-turn time-to-first-event drops from ~3.3s to ~300ms — the chat feel goes from "noticeably sluggish" to "snappy."
Commits
v0.2.0 — UX-parity additions
Three additive features that close the parity gap with a hand-rolled HeadlessSession-style integration. All changes are strictly additive — existing consumers keep working.
Added
SharedStartOpts.unsetEnv?: string[]— env-var names to delete from the spawn env afterextraEnvis merged. Empty-stringextraEnvvalues are preserved as legitimate values, so stripping requires this explicit list. Common use: remove staleANTHROPIC_API_KEY/ANTHROPIC_AUTH_TOKEN/CLAUDE_CODE_USE_BEDROCK/CLAUDE_CODE_USE_VERTEXto force the CLI's OAuth / keychain fallback.- New
CoderStreamEventvariant{ type: 'stderr'; line: string }— every stderr line from the CLI subprocess is surfaced live as an event beforedone. The stderr buffer attached toCliExitErroron non-zero exit is preserved unchanged.⚠️ Exhaustiveswitchconsumers will see a TS error and need a newcase 'stderr'. - Claude
RunOpts.streamPartialMessagesis now wired end-to-end. When set, Claude is invoked with--include-partial-messages, and eachcontent_block_deltatext-delta is translated into{ type: 'message', role: 'assistant', text: <chunk>, delta: true }. The final aggregated message atmessage_stopcontinues to be emitted withdelta: false, andRunResult.textfiltersdelta:truechunks to avoid double-counting. Gemini silently ignores the flag. Thinking deltas are skipped in this version.
Internal
composeEnv(parentEnv, extraEnv?, unsetEnv?)helper exported fromsrc/transport/spawn.ts— single source of truth for child-env composition.mergeStdoutStderr(stdout, stderr)async generator added insrc/transport/lines.ts— merges twoAsyncIterable<string>into a tagged{ src, line }stream preserving arrival order.
Verified against
claude 2.1.118gemini 0.38.2
Tests
123/123 (was 107). Code-reviewer signed off both passes (spec compliance + code quality) on every phase.
Still deferred
- Interactive permission callback (
interactivePermissionsonRunOpts) — needs CLI prompt-protocol work. - Long-lived single-subprocess thread mode (
--input-format stream-jsonover stdin) — optional perf win.
v0.1.1
Full Changelog: v0.1.0...v0.1.1