Releases: Digital-Threads/token-pilot
v0.46.0
UserPromptSubmit per-turn reinforcement hook
Re-injects a one-line token-pilot anchor on every user message so the mandatory-tool rules don't decay out of attention over a long session (caveman-style). additionalContext only, never blocks the prompt. Toggles: sessionStart.enabled, TOKEN_PILOT_BYPASS=1, TOKEN_PILOT_PROMPT_REMINDER=0.
Security
npm audit fix cleared all transitive runtime advisories (hono/qs/path-to-regexp/fast-uri/ip-address/express-rate-limit) pulled via the MCP SDK HTTP stack — production audit now reports 0 vulnerabilities. CI audit gate scoped to production deps.
Full changelog: see CHANGELOG.md
v0.45.1 — refuse multi-repo workspace parent (cross-project index bleed)
Fixed — refuse a multi-repo workspace parent (cross-project index bleed)
start.sh always passes an explicit project root, so startServer's git-root narrowing (the !explicitRoot branch) never runs. When a session launches from a non-git workspace parent that nests several project repos (e.g. /work/loom holding token-pilot, loom-host, aimux, …), the raw parent was used verbatim and ast-index indexed every sibling into one index — find_usages / read_symbol then bled matches across unrelated projects (or returned symbol not found). isDangerousRoot only caught system/home dirs, so the parent slipped through.
New guard isMultiRepoParent(root) (core/validation.ts): a non-git directory with ≥2 immediate child git repos. On match, ast-index is disabled (skipAstIndex) and a warning tells the user to set CLAUDE_PROJECT_DIR to the specific project — fail safe instead of bleeding. Wired into startServer and the server.ts MCP-roots auto-detect. Single-repo roots, monorepos, and roots that are themselves a git repo are unaffected.
PR #45.
v0.45.0 — adoption fixes: full default + tool-error visibility
Changed — default tool profile is now full (adoption fix)
The advice surface (rules, SessionStart/PostToolUse banners, the pre-edit hook)
references read_for_edit, batch reads, test_summary etc. unconditionally,
but the old default (edit) and any trimmed profile hide some of those — so the
model calls a hidden tool, hits No such tool available, and falls back to raw
Read/Bash. Those dead round-trips cost far more than the ~2k tokens the trim
saved. Default is now full (advertise everything); trimmed profiles stay
opt-in via TOKEN_PILOT_PROFILE=nav|edit|minimal. When a trimmed profile is
active the SessionStart banner now prepends a caveat naming what's hidden.
The profile recommender no longer pushes a trim: it used to suggest
TOKEN_PILOT_PROFILE=nav for read-heavy usage and print an "apply to
.mcp.json" snippet — users applied it, then the next edit session hit the
trimmed-away read_for_edit / read_range / batch reads. It now always
recommends full. And token-pilot doctor loudly flags an explicit trimmed
profile, names the hidden tools, and tells you to remove it.
Added — tool failures are logged (no more silent breakage)
createServer's tool dispatch now writes handler exceptions / validation errors
(and unknown-tool names that reach the server) to ~/.token-pilot/hook-errors.jsonl,
visible via token-pilot errors. Previously tp breakage vanished while telemetry
reported "all ok". (No such tool available is rejected at the Claude Code layer
before reaching us and stays invisible by design — the full default removes its
main source.)
Fixed — read_section is docs-only
Clarified that read_section reads Markdown/YAML/JSON/CSV by heading/key/row —
not code by line/symbol (use read_range / read_symbol). Removed its
misleading placement under "Batch variants" in the SessionStart banner.
Added — bounded-read leak closed (gate on read span, not bound presence)
PreToolUse:Read passed any offset/limit Read straight through, so
Read(file, limit=2000) (Claude Code's default page) pulled a whole big file
hook-free and un-counted in the adaptive burn signal — the #1 invisible
leak. The hook now measures the span a Read actually pulls
(effectiveReadSpanLines) and applies the same deny threshold: a default-page
or offset-no-limit read of a big file denies with a structural summary, while a
genuinely narrow slice (limit < threshold) still passes. Cost estimates are
scaled by the span so bounded denies don't over-report savings.
Added — parent_session_id capture in SubagentStop (groundwork)
A subagent's MCP server runs with CLAUDE_CODE_SESSION_ID = the agent
session, so subagent savings get tagged with that id and the statusline's
main-session badge drops them (savings look flat when subagents do the reading).
SubagentStop now captures parent_session_id (which CC ships in the payload),
enabling a future child→parent rollup in the badge. Additive/no-op when absent.
Security — vitest 3.2.4 → 3.2.6
Patches GHSA-5xrq-8626-4rwp (Vitest UI arbitrary file read/exec, critical).
Dev-only dependency; shipped runtime deps unchanged. The other 32 Dependabot
alerts were already resolved (installed transitive versions at/above the
patched version) and auto-close on re-scan.
Docs
Fable-5 economic positioning in the README — savings are in tokens, value is in
tokens × price; keep the premium thread lean.
v0.42.3 — statusline TP-only by default
install-statusline now installs just the [TP] badge by default instead of the caveman+TP chain. --chain opts into both. An existing chain switches to TP-only (drops the caveman badge); caveman's own statusLine is never replaced without --chain/--force. 1355/1355 tests.
v0.42.2 — statusline reads cwd (fix blank badge)
tp-statusline.sh read only workspace.current_dir, but Claude Code 2.1.165 sends a top-level cwd. When it did, the badge went blank. Now reads both. 1350/1350 tests.
v0.42.1 — statusline shows cumulative savings
Fixes the bare [TP] badge. tp-statusline.sh filtered savings by current session, so fresh sessions showed nothing. Now sums the whole project's saved tokens — a live-growing total. 1349/1349 tests.
v0.42.0 — one-command statusline setup
token-pilot install-statusline wires the additive savings badge into settings.json — no hand-editing JSON. Non-destructive: never clobbers a statusLine you set for caveman or custom (upgrades caveman-only/tp-only to the chain wrapper so both badges show; --force to replace a custom one). The badge live-updates and sits alongside the session name, unlike the removed sessionTitle. 1349/1349 tests.
v0.41.1 — stop overwriting the session name
v0.36.0's [TP] Nk saved window-title badge used sessionTitle, which OVERWRITES Claude Code's session name — intrusive. Removed it. The cumulative-savings badge lives in the additive statusline instead (hooks/tp-statusline.sh, the same channel caveman uses), so it sits alongside the session name instead of replacing it. 1333/1333 tests.
v0.41.0 — SubagentStop budget feedback (env-gated, CC 2.1.163+)
CC 2.1.163 lets Stop/SubagentStop hooks return additionalContext. TOKEN_PILOT_SUBAGENT_FEEDBACK=1 makes SubagentStop emit a wind-down note when an active token-pilot workflow is at ≥90% of its budget — so a hundred-agent /workflow run stops before blowing the ceiling.
Default OFF, requires CC 2.1.163+ (older CC labels the return a hook error — verified against the 2.1.161 bundle before shipping). Telemetry-only default path unchanged. 1333/1333 tests.
v0.40.0 — task telemetry via SubagentStop (root cause fixed)
Resolves the multi-release "0 task events" mystery with a clean in-session proof.
Proof: fresh 0.39.3 session — dispatched a real subagent → 0 events; same session Read-deny → 1 event written. So PostToolUse:Task does not fire for the dispatch tool (the whole history explained). async was never the cause.
Fix: capture via SubagentStop — CC's canonical subagent-completion event, fires once per subagent. New hook-subagent-stop writes event:"task" with subagent_type=agent_type (adoption signal) + best-effort transcript tokens. PostToolUse:Task kept as secondary.
1328/1328 tests pass. Verified e2e against dist.