Skip to content

v0.33.0: bugfix batch from tool-audit (B1-B14)#28

Merged
Shahinyanm merged 3 commits into
masterfrom
v0.33.0-bugfix-batch
May 8, 2026
Merged

v0.33.0: bugfix batch from tool-audit (B1-B14)#28
Shahinyanm merged 3 commits into
masterfrom
v0.33.0-bugfix-batch

Conversation

@Shahinyanm
Copy link
Copy Markdown
Member

Summary

Surfaced from cross-machine tp-report.txt audit + external code review on 2026-05-08. 1255/1255 tests pass. Tracked under beads epic token-pilot-n2r.

Bugs fixed

P0 — release blocker (silent breakage)

  • B1+B3 install-agents probes ~/.claude/plugins/cache for fresher tp-* templates when the running CLI is stale (e.g. global v0.20.1 shipping only 6 of 25 agents). New helper pickFreshestAgentsSource().
  • B2 user settings.json hooks pinned to /home/.../npx/<hash>/.../dist/index.js were calling old binaries even after the plugin cache shipped a new minor — that's why v0.31.0 PreToolUse:Task silently no-op'd in real sessions. Three pieces:
    1. new isStaleTokenPilotHookCommand() detects the npx-cache + pinned-version pattern
    2. installHook() filters those entries before re-writing
    3. new isTokenPilotPluginEnabled() short-circuits manual install when the bundled plugin is enabled — hooks/hooks.json with ${CLAUDE_PLUGIN_ROOT} is the source of truth
    4. new CLI: token-pilot migrate-hooks cleans user + project settings idempotently

P1 — functional

  • B6 smart_log malformed gitArgs (git log -- HEAD -- foo.ts treated HEAD as pathspec)
  • B7+B8 project root detection on WSL caught C:\\Windows / /mnt/c/Windows / UNC paths. New isWindowsSystemPath() + prefer CLAUDE_PROJECT_DIR.
  • B10 ast-index exec() failed permanently when init silently errored at startup → lazy retry with friendlier error.
  • B14 subagents (general-purpose, code-analyzer, feature-dev:*) loop on raw Read after hook-pre-read deny because their prompts don't know about MCP tools. PreToolUse:Task now always injects a SUBAGENT_TOOL_GUIDE additionalContext for non-tp-* dispatches.
  • B4 TOKEN_PILOT_FORCE_SUBAGENTS=1 was a silent no-op when the agent catalog was empty. Now hard-denies with "run install-agents" diagnostic.

P2

  • B5 hook-events.jsonl fragmented across monorepo subdirs (apps/admin, apps/api, packages/prisma). New loadEventsTree() walks repo root and merges; stats uses it by default, opt out via --no-merge.
  • B9 read_range rejected start_line/end_line when transport sent them as strings. New coerceIntFromAny() accepts numeric strings, rejects everything else.

Deferred

  • B11 belonged to a different package (epitaxy) — not ours.
  • B12, B13 (docs path drift, retroactive ADR for 6 new tools) filed for follow-up.

Test plan

  • npx tsc --noEmit clean (pre-existing unreachable-after-exit warnings unchanged)
  • npx vitest run → 1255/1255 pass
  • npm run build → 25 agents composed, dist refreshed
  • tp-report.txt scenario verified: stale npx-cache hook entries removed by migrate-hooks
  • manual smoke after merge: enable plugin in fresh project, dispatch general-purpose Task → expect additionalContext injection in subagent prompt

Migration note for users on stale installs

npm install -g token-pilot@latest
token-pilot migrate-hooks   # cleans pinned npx paths from settings.json
# restart Claude Code

🤖 Generated with Claude Code

Shahinyanm added 3 commits May 8, 2026 12:50
Surfaced from cross-machine tp-report.txt audit + external code review
on 2026-05-08. 1255 tests pass; full diff in beads token-pilot-n2r.

P0 (release blocker — silent breakage):
- B1+B3: install-agents probes ~/.claude/plugins/cache for fresher tp-*
  templates when running CLI is stale (e.g. global v0.20.1 binary
  shipping only 6 of 25 agents). New: pickFreshestAgentsSource().
- B2:    user settings.json hooks pinned to /home/.../npx/<hash>/...
  paths kept calling old binary even after plugin cache shipped a
  new minor (e.g. PreToolUse:Task in v0.31.0 silently no-op'd).
  - new helper isStaleTokenPilotHookCommand() detects the pattern
  - installHook() now filters those entries before re-writing
  - new helper isTokenPilotPluginEnabled() short-circuits manual
    install when the bundled plugin is already enabled — the
    plugin's hooks/hooks.json with ${CLAUDE_PLUGIN_ROOT} is the
    source of truth in that case
  - new CLI subcommand: `token-pilot migrate-hooks` cleans both
    user-level + project-level settings.json idempotently

P1 (functional):
- B6:  smart_log gitArgs malformed — `git log -- HEAD -- foo.ts`
  treated HEAD as pathspec; removed the leading `'--'` separator.
- B7+B8: project root detection on WSL caught C:\\Windows /
  /mnt/c/Windows / UNC paths. New: prefer CLAUDE_PROJECT_DIR over
  INIT_CWD/PWD/cwd; reject Windows system paths via new
  isWindowsSystemPath().
- B10: ast-index `exec()` failed permanently when init silently
  errored at server startup. Added lazy retry with a friendlier
  error pointing at `npx token-pilot install-ast-index`.
- B14: subagents (general-purpose, code-analyzer, feature-dev:*)
  loop on raw Read after hook-pre-read deny because their prompts
  don't know about MCP tools. PreToolUse:Task now ALWAYS injects a
  generic SUBAGENT_TOOL_GUIDE additionalContext for non-tp-*
  dispatches (empty / no-match / escape paths included).
- B4:  TOKEN_PILOT_FORCE_SUBAGENTS=1 was a silent no-op when the
  agent catalog was empty. Now hard-denies with a clear
  "run install-agents" diagnostic.

P2:
- B5:  hook-events.jsonl was fragmented across monorepo subdirs
  (e.g. apps/admin, apps/api, packages/prisma). New
  loadEventsTree() walks the repo root and merges; `stats` uses
  it by default, opt out with `--no-merge`.
- B9:  read_range rejected start_line/end_line when the MCP
  transport sent them as strings ("10"). New coerceIntFromAny()
  accepts numeric strings, rejects everything else.

P3 deferred:
- B11 belonged to a different package (epitaxy) — not ours.
- B12, B13 (docs path drift, retroactive ADR for 6 new tools)
  filed for a follow-up — non-blocking for v0.33.0.

Manifests bumped 0.32.0 → 0.33.0; agents rebuilt (25/25).
Closes the visibility gap exposed by tp-report.txt: every silent
hook throw, edge-case branch, and stale-config slipped past us
because we had no place to write them. 14 new tests; 1269/1269 pass.

Pack 1 — error channel
- new src/core/error-log.ts:
    appendError, loadErrors, formatErrorList,
    classifyError (ENOENT/parse_error/timeout/EACCES/...),
    safeBasename / safePathInfo (privacy helpers),
    rotation (5 MB) + 30d archive retention,
    TOKEN_PILOT_NO_ERROR_LOG=1 opt-out.
- new src/hooks/safe-runner.ts:
    runHookEntryPoint(opts, fn) wraps every hook entry point;
    on throw → structured record to ~/.token-pilot/hook-errors.jsonl;
    always exits 0 so Claude Code never sees a hook failure.
- wraps all 8 entry points in src/index.ts:
    hook-read, hook-edit, hook-pre-bash, hook-pre-grep,
    hook-pre-task, hook-post-bash, hook-post-task,
    hook-session-start.
- new CLI: `token-pilot errors [--tail=N --code=X --hook=Y --level=L]`.

Pack 2 — diagnostic events
- HookEvent extended with optional level/code/detail/duration_ms +
  union now includes "diagnostic".
- new helper appendDiagnostic(projectRoot, args).
- emit points wired:
    * hook-pre-task → `force_subagents_no_agents`
      when TOKEN_PILOT_FORCE_SUBAGENTS=1 and the agent index is empty
    * startServer detect path → `wsl_path_rejected`
      one event per WSL/UNC candidate that isWindowsSystemPath() filters
- doctor extended with a new "runtime health" section:
    * top error codes from last 100 records
    * stale npx-cache / pinned-version hook entries in
      user-level + project-level settings.json (B2 leftover scan)
    * tp-* agent inventory: installed vs catalog
    * cwd safety: warns when CLAUDE_PROJECT_DIR or process.cwd()
      lands on a Windows system path

Pack 3 — timing groundwork
- HookEvent gains optional duration_ms.
- runHookEntryPoint measures wall-clock and exposes onTiming hook
  for callers that want to log a `hook_slow` diagnostic.
  (Per-event emit deferred — needs a threshold tuned from real data.)

Privacy: error records carry only sanitized input (basename, ext,
short metadata). No file content, no prompts, no full paths.
Fully local — nothing is sent anywhere.

Tests:
- tests/core/error-log.test.ts (14 tests) — classifier, sanitizers,
  loadErrors filters/tail, formatErrorList top-codes.
- 1255 prior tests untouched and pass.
External review surfaced four functional MCP bugs (UNC project root,
git cwd, read_range schema, find_usages init) plus a fifth version-
mismatch claim. All four functional ones are fixed in v0.33.0 (B6,
B7, B8, B9, B10); the fifth belongs to a different package and is
filed as not-applicable. Document tracks origin → root cause →
commit → verification steps so future readers can cross-reference
the report against the fix without rerunning the audit.
@Shahinyanm Shahinyanm merged commit 36b40d4 into master May 8, 2026
0 of 2 checks passed
@Shahinyanm Shahinyanm deleted the v0.33.0-bugfix-batch branch May 8, 2026 09:26
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant