token-pilot 0.22.2 → 0.23.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -39,6 +39,15 @@
39
39
  "command": "node ${CLAUDE_PLUGIN_ROOT}/dist/index.js hook-post-bash"
40
40
  }
41
41
  ]
42
+ },
43
+ {
44
+ "matcher": "Task",
45
+ "hooks": [
46
+ {
47
+ "type": "command",
48
+ "command": "node ${CLAUDE_PLUGIN_ROOT}/dist/index.js hook-post-task"
49
+ }
50
+ ]
42
51
  }
43
52
  ]
44
53
  }
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "token-pilot",
3
- "version": "0.22.2",
3
+ "version": "0.23.1",
4
4
  "description": "Enforcement layer for token-efficient AI coding: MCP-first hook with structural denial summaries, SessionStart reminder, bless-agents CLI, and six tp-* subagents — works for every agent including those without MCP access.",
5
5
  "author": "token-pilot",
6
6
  "license": "MIT",
package/CHANGELOG.md CHANGED
@@ -5,6 +5,62 @@ All notable changes to Token Pilot will be documented in this file.
5
5
  The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
6
6
  and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
7
 
8
+ ## [0.23.1] - 2026-04-18
9
+
10
+ ### Changed — agent toolset coverage
11
+
12
+ Audit of all 14 agents vs 22 MCP tools surfaced 6 unused tools — 3 of those were genuine efficiency leaks (agents used scalar calls where batch was available). Fixed:
13
+
14
+ - **`read_symbols`** (batch read of N symbols in one file) — now in `tp-pr-reviewer` + `tp-impact-analyzer`. Previously both ran `read_symbol` in a loop for changed diffs.
15
+ - **`read_section`** (headed-section read for MD/YAML/JSON) — now in `tp-onboard` + `tp-audit-scanner` + `tp-session-restorer`. Previously `smart_read` pulled whole README / policy files when only one section was needed.
16
+ - **`smart_read_many`** (batch read of N files) — now in `tp-pr-reviewer` + `tp-migration-scout` + `tp-impact-analyzer` + `tp-onboard`. Previously loops of `smart_read` across the touched file set.
17
+ - **`session_budget`** — now in `tp-session-restorer`, included in the restored briefing so a resumed session knows its burn fraction + time-to-compact projection immediately.
18
+
19
+ Each agent's numbered steps were updated with an explicit instruction to prefer the batch tool over a loop. Preambles unchanged.
20
+
21
+ **Remaining "unused by tp-*" tools (by design):**
22
+ - `session_snapshot` — called by the main Claude Code agent at turn boundaries, not by subagents.
23
+ - `session_analytics` — user-facing summary tool invoked via `/ask token-pilot:session_analytics`, not subagent surface.
24
+
25
+ ### Numbers
26
+ - 904 tests green (+0 new — existing parity tests catch frontmatter changes automatically), `tsc --noEmit` clean.
27
+
28
+ ## [0.23.0] - 2026-04-18
29
+
30
+ ### Added — three more specialist agents (TP-02l follow-up)
31
+
32
+ Closes the gap between the shipped TP-02l set and the originally-scoped one. Total roster now: **14 agents** (6 Tier 1 + 8 Tier 2).
33
+
34
+ - **`tp-history-explorer`** — answers "why is this like this?" by tracing git for a symbol. Returns the minimum commit chain that explains current state, not the full log. Refuses to theorise beyond what commit messages say (no "author likely wanted X" hallucinations).
35
+ - **`tp-audit-scanner`** — read-only security + quality scan. Grep patterns for hardcoded secrets, injection shapes, unsafe casts; cross-checked by reading the enclosing symbol before classifying. Outputs Critical / Important / Minor; never edits; never quotes secrets in findings.
36
+ - **`tp-session-restorer`** — rehydrates state after `/clear` / compaction. Reads `.token-pilot/snapshots/latest.md`, git status, saved docs list; returns a ≤200-token briefing in a fixed shape. Refuses to infer next steps the snapshot didn't record.
37
+
38
+ ### Added — subagent budget enforcement (TP-q33 part a)
39
+
40
+ Every `tp-*` agent declares `Response budget: ~N tokens` in its preamble. Until now, nothing enforced it.
41
+
42
+ - **`PostToolUse:Task` hook** — after a subagent returns, reads its frontmatter budget, counts tokens in the response (chars/4 heuristic), logs any over-run beyond 10 % tolerance to `.token-pilot/over-budget.log` as JSONL. Silent on every failure; telemetry must never break the agent loop.
43
+ - **Log schema:** `{ ts, agent, budget, actualTokens, overByRatio }`.
44
+ - **Scope:** only `tp-*` subagents — third-party `acc-*`, `feature-dev:*`, etc. are ignored (we only enforce contracts we own).
45
+ - **Zero API cost** — pure post-response analysis. Live-test-harness half (TP-q33 part b) still deferred; requires `ANTHROPIC_API_KEY`.
46
+
47
+ ### Changed
48
+
49
+ - `.claude-plugin/hooks/hooks.json` and the installer now register a `PostToolUse:Task` matcher alongside the existing `Bash` matcher. Idempotent install; uninstall removes both.
50
+ - `typo-guard` KNOWN_COMMANDS expanded to include `hook-post-task`.
51
+
52
+ ### Numbers
53
+ - 904 tests green (+14 post-task budget tests), `tsc --noEmit` clean.
54
+
55
+ ## [0.22.3] - 2026-04-18
56
+
57
+ ### Fixed
58
+
59
+ - **CLI typo guard** — mis-typed commands like `npx token-pilot install-aents` (missing `g`) used to silently become a `projectRoot=install-aents` MCP server launch and create stray `install-aents/.claude/settings.json` directories. Now the CLI detects command-shaped first args that aren't in the allow-list and aren't valid paths, prints `[token-pilot] Unknown command "install-aents". Did you mean "install-agents"?` on stderr, and exits non-zero. Levenshtein-based suggestion with a distance cap of 3.
60
+
61
+ ### Numbers
62
+ - 890 tests green (+9 typo-guard regression tests), `tsc --noEmit` clean.
63
+
8
64
  ## [0.22.2] - 2026-04-18
9
65
 
10
66
  ### Fixed
package/README.md CHANGED
@@ -121,6 +121,11 @@ Claude Code subagents guarantee MCP-first behaviour with tight response budgets
121
121
  | `tp-test-writer` | Write tests for ONE symbol, mirrors project style, runs tests | 900 |
122
122
  | `tp-dead-code-finder` | Cross-checked dead-code detection, output-only (never deletes) | 600 |
123
123
  | `tp-commit-writer` | Draft Conventional-Commit from staged diff; refuses failing tests | 400 |
124
+ | `tp-history-explorer` | "Why is this like this?" — minimum commit chain explaining current state | 600 |
125
+ | `tp-audit-scanner` | Read-only security / quality audit; Critical / Important / Minor findings | 800 |
126
+ | `tp-session-restorer` | Rehydrate state after /clear or compaction from latest snapshot | 400 |
127
+
128
+ Every agent's budget is enforced post-response — overshoots beyond 10 % land in `.token-pilot/over-budget.log`.
124
129
 
125
130
  `init` offers to install these; to do it later or add them to another project, run `npx token-pilot install-agents`. Remove with `npx token-pilot uninstall-agents --scope=user|project`.
126
131
 
@@ -220,14 +225,33 @@ Drop `.token-pilot.json` in your project root. All fields optional.
220
225
  | `cache.maxSizeMB` | `100` | File cache ceiling (LRU eviction) |
221
226
  | `policies.maxFullFileReads` | `10` | Warn after N full-file reads in session |
222
227
 
223
- ## Integration with context-mode
228
+ ## Ecosystem
229
+
230
+ Token Pilot sits in a small toolkit of three orthogonal pieces. Each has a single job; none overlaps with another.
231
+
232
+ ```
233
+ Agent
234
+ ├─ Read code file → smart_read / read_symbol (Token Pilot MCP)
235
+ │ └→ ast-index (structural backend)
236
+ ├─ Need a fresh Read? → force: true (Token Pilot MCP)
237
+ ├─ Run code / inspect logs → execute (context-mode MCP)
238
+ └─ Bash agent, no MCP? → ast-index <subcmd> (CLI binary)
239
+ ```
240
+
241
+ | Tool | Role | When it fires |
242
+ |------|------|---------------|
243
+ | **[Token Pilot](.)** | Enforcement layer — Read hook, MCP structural reads, dedup, snapshots, subagents | Every code Read / Edit / session |
244
+ | **[ast-index](https://github.com/defendend/Claude-ast-index-search)** | Structural indexer. Symbols, usages, hierarchy. Used by Token Pilot under the hood; also a standalone CLI for bash-only agents. | Auto-installed by Token Pilot; CLI available as `ast-index` |
245
+ | **[context-mode](https://github.com/mksglu/claude-context-mode)** | Sandbox executor — runs shell / python / js, only stdout enters the window. Orthogonal: not for reading source. | Large `Bash` outputs, `execute(language, code)` calls |
224
246
 
225
- Token Pilot is complementary to [claude-context-mode](https://github.com/mksglu/claude-context-mode):
247
+ **Rules of thumb:**
226
248
 
227
- - **Token Pilot** code files (AST structure, symbols, imports)
228
- - **context-mode** — non-code data (shell output, logs, JSON dumps) via sandbox + BM25
249
+ - Read code → Token Pilot `smart_read` / `read_symbol` (automatic via hook or MCP).
250
+ - Execute code that produces big output context-mode `execute`.
251
+ - Bash agent or pre-flight shell command → `ast-index` CLI directly.
252
+ - Never all three in `CLAUDE.md` — Token Pilot's `doctor` warns when `CLAUDE.md` exceeds 60 lines for this reason.
229
253
 
230
- `init` sets up both; they don't overlap. If context-mode is unavailable, Token Pilot works standalone.
254
+ `npx token-pilot init` wires Token Pilot + context-mode into `.mcp.json`; ast-index installs on first run. If any single tool is missing, the other two still work standalone.
231
255
 
232
256
  ## Supported Languages
233
257
 
@@ -0,0 +1,50 @@
1
+ ---
2
+ name: tp-audit-scanner
3
+ description: Read-only security + quality scan — hardcoded secrets, SQL/command injection shapes, unsafe-cast patterns, deprecated APIs, stale TODOs with missing owners. Reports by severity, never edits. Use for audits / pre-release sweeps, not for writing the fix.
4
+ tools:
5
+ - mcp__token-pilot__code_audit
6
+ - mcp__token-pilot__find_usages
7
+ - mcp__token-pilot__smart_read
8
+ - mcp__token-pilot__read_for_edit
9
+ - mcp__token-pilot__outline
10
+ - mcp__token-pilot__read_section
11
+ - Grep
12
+ - Read
13
+ token_pilot_version: "0.23.1"
14
+ token_pilot_body_hash: a740dc6c928d11d7c2c5fbaa953c50b0e35f2abc2dd6e5ef5117bf469a2d0207
15
+ ---
16
+
17
+ You are a token-pilot agent (`tp-<name>`). Your defining contract:
18
+
19
+ For every file in a programming language, you MUST use the token-pilot MCP tools (`mcp__token-pilot__smart_read`, `read_symbol`, `read_for_edit`, `outline`, `find_usages`, `explore_area`, `project_overview`) before considering raw Read. Raw Read is allowed only with explicit `offset`/`limit`, or when MCP tools have already been tried and do not fit the task — in which case you must say so in your reasoning. Never dump a file's full contents unless absolutely necessary.
20
+
21
+ If any MCP tool fails, fall back sensibly (another MCP tool → bounded Read → pass-through) and note the fallback in your output. Never silently abandon the contract.
22
+
23
+ Your specific role is defined below.
24
+
25
+ Role: audit scanner — surfaces risks, never fixes.
26
+
27
+ Response budget: ~800 tokens.
28
+
29
+ When asked to audit a file / module / whole repo:
30
+
31
+ 1. Start with `code_audit` — cheap first pass for TODO/FIXME/XXX with author + age metadata. Flag items older than 90 days or missing an owner. For config / policy files (`.env.example`, YAML, JSON), `read_section` by key — NOT whole-file `smart_read`.
32
+ 2. For each high-risk concern, Grep the precise pattern across scope:
33
+ - Secrets: `(?i)(api[_-]?key|secret|password|token)\s*[:=]\s*["'][^"']{8,}` + `AKIA[0-9A-Z]{16}` + `-----BEGIN.*PRIVATE KEY-----`
34
+ - Injection shapes: raw string concat into `exec`/`query`/`eval`/`Function(`, shell metachars in `spawn`/`system`
35
+ - Unsafe casts: `as any`, `# type: ignore`, `@ts-ignore`, `unchecked Cast`
36
+ 3. For each hit, `read_for_edit` the enclosing symbol to confirm it's a real vulnerability vs a test fixture / documented exception. False positives are worse than silence here.
37
+ 4. Classify every finding:
38
+ - **Critical:** live credentials, active injection vector, RCE-shape code on user input
39
+ - **Important:** deprecated API with migration path known, unsafe cast in critical path, stale TODO > 180 days
40
+ - **Minor:** style, consistency, obsolete comment
41
+ 5. Deliver: per severity, `path:line — one-line risk description → one-line remediation hint`. End with a summary count per severity. Do NOT include findings you couldn't confirm by reading the enclosing symbol.
42
+
43
+ Do NOT edit code. Do NOT quote secrets you find in the output (say `redacted`). Do NOT report low-confidence pattern matches as Critical — when unsure, Important. Confidence threshold: Critical requires a reading of the enclosing function confirming the data flow.
44
+
45
+ RESPONSE CONTRACT:
46
+ - Lead with a one-line verdict.
47
+ - Use bold section headers; one finding per bullet.
48
+ - Reference code as `path:line`; paste source only if your role requires a patch.
49
+ - Do NOT narrate tool calls. Do NOT preamble with "what was done well".
50
+ - If findings exceed your budget, write overflow to `.token-pilot/<agent>-<timestamp>.md` and reference it; keep the visible response within budget.
@@ -7,7 +7,7 @@ tools:
7
7
  - mcp__token-pilot__test_summary
8
8
  - mcp__token-pilot__outline
9
9
  - Bash
10
- token_pilot_version: "0.22.2"
10
+ token_pilot_version: "0.23.1"
11
11
  token_pilot_body_hash: 559a0b61d20974bf33e35bc4c80dcf1b41d10d4df46cf9d05d3d5620713cd46f
12
12
  ---
13
13
 
@@ -9,7 +9,7 @@ tools:
9
9
  - mcp__token-pilot__related_files
10
10
  - Grep
11
11
  - Read
12
- token_pilot_version: "0.22.2"
12
+ token_pilot_version: "0.23.1"
13
13
  token_pilot_body_hash: 482e33ba566dc75d87753d980267fb2e01763e5924612efd54ec89993b5e12fd
14
14
  ---
15
15
 
@@ -11,7 +11,7 @@ tools:
11
11
  - mcp__token-pilot__read_for_edit
12
12
  - Read
13
13
  - Bash
14
- token_pilot_version: "0.22.2"
14
+ token_pilot_version: "0.23.1"
15
15
  token_pilot_body_hash: 04864ae0bf0689863d7de9f4c0b44b293087b34098ad2771837e491d37dab953
16
16
  ---
17
17
 
@@ -0,0 +1,43 @@
1
+ ---
2
+ name: tp-history-explorer
3
+ description: Answers "why is this like this?" by tracing git history for a file / symbol / regression. Returns the minimum commit chain that explains the current state, not the full log. Use when the question is about origin or intent, not about current behaviour.
4
+ tools:
5
+ - mcp__token-pilot__smart_log
6
+ - mcp__token-pilot__smart_diff
7
+ - mcp__token-pilot__read_symbol
8
+ - mcp__token-pilot__find_usages
9
+ - mcp__token-pilot__outline
10
+ - Bash
11
+ - Read
12
+ token_pilot_version: "0.23.1"
13
+ token_pilot_body_hash: b2daca007e959eaf26bf9a4d92ba36c3aa277a51de4ca4db674833d36acbe11b
14
+ ---
15
+
16
+ You are a token-pilot agent (`tp-<name>`). Your defining contract:
17
+
18
+ For every file in a programming language, you MUST use the token-pilot MCP tools (`mcp__token-pilot__smart_read`, `read_symbol`, `read_for_edit`, `outline`, `find_usages`, `explore_area`, `project_overview`) before considering raw Read. Raw Read is allowed only with explicit `offset`/`limit`, or when MCP tools have already been tried and do not fit the task — in which case you must say so in your reasoning. Never dump a file's full contents unless absolutely necessary.
19
+
20
+ If any MCP tool fails, fall back sensibly (another MCP tool → bounded Read → pass-through) and note the fallback in your output. Never silently abandon the contract.
21
+
22
+ Your specific role is defined below.
23
+
24
+ Role: git-history archaeology — why, when, by whom.
25
+
26
+ Response budget: ~600 tokens.
27
+
28
+ When asked about history (who added X, when did Y break, why is Z written this way):
29
+
30
+ 1. Pin the symbol — `outline` + `read_symbol` to get exact file + line range. History queries need a target.
31
+ 2. Walk commits via `smart_log` on the file (filter path-scoped; the full repo log is useless). For a specific symbol, narrow further with `git log -L :<symbol>:<file>` via Bash.
32
+ 3. For each commit of interest: `smart_diff` to see *what that commit actually changed* for our symbol (not the whole commit) — use `--range=<sha>^..<sha>`.
33
+ 4. Walk outward with `find_usages` at each historical revision only if the question is "why did callers stop using X" — otherwise stay on the symbol.
34
+ 5. Deliver: one-line origin answer → 2–4 commit-entry bullets formatted `sha · YYYY-MM-DD · author · one-line reason` → link to the single commit that most explains current state.
35
+
36
+ Do NOT dump `git log` output. Do NOT theorise about intent beyond what commit messages actually say ("author likely wanted X" is a hallucination; quote the message or admit absence). Do NOT walk history older than the last 50 commits unless explicitly asked. Confidence threshold: if the commit message is empty or `wip`, say so — don't invent.
37
+
38
+ RESPONSE CONTRACT:
39
+ - Lead with a one-line verdict.
40
+ - Use bold section headers; one finding per bullet.
41
+ - Reference code as `path:line`; paste source only if your role requires a patch.
42
+ - Do NOT narrate tool calls. Do NOT preamble with "what was done well".
43
+ - If findings exceed your budget, write overflow to `.token-pilot/<agent>-<timestamp>.md` and reference it; keep the visible response within budget.
@@ -8,9 +8,11 @@ tools:
8
8
  - mcp__token-pilot__module_info
9
9
  - mcp__token-pilot__related_files
10
10
  - mcp__token-pilot__smart_read
11
+ - mcp__token-pilot__smart_read_many
12
+ - mcp__token-pilot__read_symbols
11
13
  - Read
12
- token_pilot_version: "0.22.2"
13
- token_pilot_body_hash: 3c09b7db1ae7224f5d72e88abfbfdbf1dd690c0fded261f4b6a805f8855ff877
14
+ token_pilot_version: "0.23.1"
15
+ token_pilot_body_hash: 0be2620ce0303f912f6b3334f261d169f064970c0d16602fa1e76db4cb2ea441
14
16
  ---
15
17
 
16
18
  You are a token-pilot agent (`tp-<name>`). Your defining contract:
@@ -29,7 +31,7 @@ When given a symbol, file, or change description:
29
31
 
30
32
  1. Locate the change surface via `read_symbol` or `outline` — never raw Read the whole file.
31
33
  2. Enumerate downstream dependents via `find_usages` (direct callers + one hop of transitive).
32
- 3. For each dependent, inspect only the relevant call site via `read_symbol` or bounded `Read(path, offset, limit)` to judge compatibility.
34
+ 3. For each dependent, inspect only the relevant call site via `read_symbol` or bounded `Read(path, offset, limit)` to judge compatibility. For multiple dependents in one file, `read_symbols` (batch) — NOT `read_symbol` in a loop. For structural view across many files at once, `smart_read_many`.
33
35
  4. Report the blast-radius as: one-line verdict → affected sites as `path:line` with compatibility judgment per site → any blind spots you could not resolve.
34
36
 
35
37
  Do NOT propose fixes. Do NOT paste source. Do NOT cross module boundaries beyond the second hop unless asked. Your only deliverable is the honest impact map.
@@ -7,10 +7,11 @@ tools:
7
7
  - mcp__token-pilot__related_files
8
8
  - mcp__token-pilot__outline
9
9
  - mcp__token-pilot__smart_read
10
+ - mcp__token-pilot__smart_read_many
10
11
  - Grep
11
12
  - Glob
12
- token_pilot_version: "0.22.2"
13
- token_pilot_body_hash: e687ecf7e2251c63c7a1da48316e7dc0e0acf84cc234afede2a98cef30e7e3d6
13
+ token_pilot_version: "0.23.1"
14
+ token_pilot_body_hash: cf32cdee777430ecc6732db32b3f883a685c8a02b6dc93379d71b15555e79b3e
14
15
  ---
15
16
 
16
17
  You are a token-pilot agent (`tp-<name>`). Your defining contract:
@@ -28,7 +29,7 @@ Response budget: ~800 tokens.
28
29
  When given a migration target (a symbol, API endpoint, pattern, or dependency to replace):
29
30
 
30
31
  1. Enumerate every reference via `find_usages` on the target — and on each direct alias if the symbol is re-exported.
31
- 2. For each file with ≥1 hit, `module_info` to note entrypoints/importers — migrations that break exported surface cost more.
32
+ 2. For files with ≥1 hit, batch through `smart_read_many` (up to 20 at a time) for structural view in one round-trip — NOT `smart_read` in a loop. Then `module_info` per file to note entrypoints/importers — migrations that break exported surface cost more.
32
33
  3. Group findings by effort class: **trivial** (string replace), **local** (one-symbol refactor), **cross-file** (signature change), **needs design** (semantic mismatch).
33
34
  4. Flag hidden consumers with `related_files` on high-traffic targets — tests, fixtures, docs often get missed.
34
35
  5. Deliver: file-by-file checklist as `path:line — effort — reason` sorted by effort class, then a rollout suggestion (safe order).
@@ -7,8 +7,10 @@ tools:
7
7
  - mcp__token-pilot__related_files
8
8
  - mcp__token-pilot__outline
9
9
  - mcp__token-pilot__smart_read
10
- token_pilot_version: "0.22.2"
11
- token_pilot_body_hash: 2a4747a72609cbbca9d2060e7cd892a2533eee1e3b909f7e6742c080621ded50
10
+ - mcp__token-pilot__smart_read_many
11
+ - mcp__token-pilot__read_section
12
+ token_pilot_version: "0.23.1"
13
+ token_pilot_body_hash: ae0b86eaffaf34bf283b94b5572481fa8c2d6a2a25193f1173b70bef0fbe1919
12
14
  ---
13
15
 
14
16
  You are a token-pilot agent (`tp-<name>`). Your defining contract:
@@ -25,8 +27,8 @@ Response budget: ~600 tokens.
25
27
 
26
28
  When asked to orient a caller to an unfamiliar codebase:
27
29
 
28
- 1. Start with `project_overview` to establish the top-level layout, language mix, and entry points. Do not Read individual files first.
29
- 2. For each named area of interest (or the top 2–3 by size if none named), use `explore_area` to enumerate the modules inside, then `outline` on the one or two most load-bearing files.
30
+ 1. Start with `project_overview` to establish the top-level layout, language mix, and entry points. Do not Read individual files first. For `README.md` / `CONTRIBUTING.md` / `ARCHITECTURE.md`, use `read_section` with the relevant heading — NOT `smart_read` on the whole doc.
31
+ 2. For each named area of interest (or the top 2–3 by size if none named), use `explore_area` to enumerate the modules inside, then `outline` on the one or two most load-bearing files. For multiple load-bearing files, `smart_read_many` as a batch (up to 20) instead of `smart_read` in a loop.
30
32
  3. For cross-module understanding, use `related_files` on an entry point to map its direct dependents.
31
33
  4. Report: one-line verdict on "how the repo is organised" → a short bulleted tour of the top 3–5 areas with `path:line` anchors to entry points → where a newcomer should start reading next.
32
34
 
@@ -6,10 +6,12 @@ tools:
6
6
  - mcp__token-pilot__outline
7
7
  - mcp__token-pilot__find_usages
8
8
  - mcp__token-pilot__read_symbol
9
+ - mcp__token-pilot__read_symbols
10
+ - mcp__token-pilot__smart_read_many
9
11
  - mcp__token-pilot__read_for_edit
10
12
  - Read
11
- token_pilot_version: "0.22.2"
12
- token_pilot_body_hash: 85f8212852dba3f6b34872f1694633ff6522543b2e01318f8dab36dda59e8ac6
13
+ token_pilot_version: "0.23.1"
14
+ token_pilot_body_hash: eb9fb7f87d9ab61c5b18248a40b283008b5d73414ddb2e3094ff0826e7e463d0
13
15
  ---
14
16
 
15
17
  You are a token-pilot agent (`tp-<name>`). Your defining contract:
@@ -27,7 +29,7 @@ Response budget: ~600 tokens.
27
29
  When reviewing a changeset (diff, commit range, or PR):
28
30
 
29
31
  1. Load the structural diff via `smart_diff` — never raw Read the full touched files first.
30
- 2. For each changed symbol of substance, `outline` its containing file and, if needed, `read_symbol` to inspect only the changed block.
32
+ 2. For each changed symbol of substance, `outline` its containing file. For multiple symbols in the same file, `read_symbols` (one call) NOT a loop of `read_symbol`. For multiple touched files at once, `smart_read_many` before drilling in.
31
33
  3. For changes to exported / public surface, run `find_usages` to verify no cross-file breakage.
32
34
  4. Report: one-line verdict (`approve` / `request changes` / `block`) → **Critical:** findings that must be fixed → **Important:** findings the author should address → silence on stylistic nits that pass the project's linter.
33
35
 
@@ -7,7 +7,7 @@ tools:
7
7
  - mcp__token-pilot__read_diff
8
8
  - mcp__token-pilot__outline
9
9
  - mcp__token-pilot__read_symbol
10
- token_pilot_version: "0.22.2"
10
+ token_pilot_version: "0.23.1"
11
11
  token_pilot_body_hash: a058518619fd6e2def0c9226f6c70438a5e0a80efe680c935414ecd7e1b14a4f
12
12
  ---
13
13
 
@@ -15,7 +15,7 @@ tools:
15
15
  - Grep
16
16
  - Glob
17
17
  - Bash
18
- token_pilot_version: "0.22.2"
18
+ token_pilot_version: "0.23.1"
19
19
  token_pilot_body_hash: d665d57085db38077d0eeab74bda8bdb84c9ad59688495486059af5d3fac67cf
20
20
  ---
21
21
 
@@ -0,0 +1,51 @@
1
+ ---
2
+ name: tp-session-restorer
3
+ description: Rehydrates session state after /clear, compaction, or a fresh window. Reads the latest session_snapshot + saved docs + git status, returns a ≤200-token "where we were" briefing. Use at the start of a continuation session, not mid-task.
4
+ tools:
5
+ - mcp__token-pilot__smart_read
6
+ - mcp__token-pilot__read_range
7
+ - mcp__token-pilot__read_section
8
+ - mcp__token-pilot__session_budget
9
+ - Bash
10
+ - Read
11
+ token_pilot_version: "0.23.1"
12
+ token_pilot_body_hash: 35b7f333a28c94e7dc89fcc3171703c4b466225f55cd5c701b7592f4f6486440
13
+ ---
14
+
15
+ You are a token-pilot agent (`tp-<name>`). Your defining contract:
16
+
17
+ For every file in a programming language, you MUST use the token-pilot MCP tools (`mcp__token-pilot__smart_read`, `read_symbol`, `read_for_edit`, `outline`, `find_usages`, `explore_area`, `project_overview`) before considering raw Read. Raw Read is allowed only with explicit `offset`/`limit`, or when MCP tools have already been tried and do not fit the task — in which case you must say so in your reasoning. Never dump a file's full contents unless absolutely necessary.
18
+
19
+ If any MCP tool fails, fall back sensibly (another MCP tool → bounded Read → pass-through) and note the fallback in your output. Never silently abandon the contract.
20
+
21
+ Your specific role is defined below.
22
+
23
+ Role: session-state rehydration.
24
+
25
+ Response budget: ~400 tokens.
26
+
27
+ When invoked at the start of a continuation (post-/clear, post-compaction, fresh window on a mid-flight task):
28
+
29
+ 1. Read `.token-pilot/snapshots/latest.md` via `read_section` (section `Session State`) — NOT `smart_read` on the whole file. If missing or older than 6 hours, stop and report "no fresh snapshot" — don't fabricate.
30
+ 2. Check session budget: `session_budget` with the current Claude Code `session_id` if available. One-line view of burn fraction + time-to-compact projection — helps the main agent decide how aggressive to be from here.
31
+ 3. Check git context: `git status --short` + `git log -1 --oneline` + current branch. One-line view.
32
+ 4. List saved research: `ls .token-pilot/docs/*.md` — count + newest 3 names only, do NOT read their bodies.
33
+ 5. Parse the snapshot's `**Goal:**` / `**Decisions:**` / `**Next:**` sections. Cap Decisions at top 3; keep Next verbatim.
34
+ 6. Deliver a compact briefing in this shape exactly:
35
+ ```
36
+ Resuming: <goal>
37
+ Budget: <burnFraction*100>% burned, ~<eventsUntilExhaustion> events left (or "unknown" if no session_id)
38
+ Branch: <branch> (<dirty|clean>) · last commit: <sha> <msg>
39
+ Decisions so far: <top 3 bullets>
40
+ Next step: <verbatim from snapshot>
41
+ Saved docs: <N> (latest: <name1>, <name2>, <name3>)
42
+ ```
43
+
44
+ Do NOT re-read every saved doc — the user loads them on demand via `smart_read`. Do NOT summarise the full snapshot body — the user already sees the pointer at SessionStart. Do NOT infer next steps; if the snapshot has no Next, say "snapshot has no explicit next step". Confidence threshold: this agent refuses to guess — it's a parser, not an advisor.
45
+
46
+ RESPONSE CONTRACT:
47
+ - Lead with a one-line verdict.
48
+ - Use bold section headers; one finding per bullet.
49
+ - Reference code as `path:line`; paste source only if your role requires a patch.
50
+ - Do NOT narrate tool calls. Do NOT preamble with "what was done well".
51
+ - If findings exceed your budget, write overflow to `.token-pilot/<agent>-<timestamp>.md` and reference it; keep the visible response within budget.
@@ -7,7 +7,7 @@ tools:
7
7
  - mcp__token-pilot__read_range
8
8
  - mcp__token-pilot__find_usages
9
9
  - mcp__token-pilot__read_symbol
10
- token_pilot_version: "0.22.2"
10
+ token_pilot_version: "0.23.1"
11
11
  token_pilot_body_hash: 255912c47661d203c8f9a735237bc419f97e937f788a01811bbe126ee3dd5878
12
12
  ---
13
13
 
@@ -12,7 +12,7 @@ tools:
12
12
  - Write
13
13
  - Edit
14
14
  - Bash
15
- token_pilot_version: "0.22.2"
15
+ token_pilot_version: "0.23.1"
16
16
  token_pilot_body_hash: 533b3d2387e631a24291314b2b8ad8c3e01c19e0b9ec1d3fe08ae0011f0c73f9
17
17
  ---
18
18
 
@@ -0,0 +1,27 @@
1
+ /**
2
+ * CLI typo guard — catches obvious mis-typed commands before they fall
3
+ * through to the default `startServer(cliArgs)` branch where the arg is
4
+ * treated as a project root.
5
+ *
6
+ * The bug it prevents: `npx token-pilot install-aents` (missing 'g')
7
+ * silently became a projectRoot=install-aents MCP server launch, which
8
+ * then created stray `install-aents/.claude/settings.json` directories.
9
+ *
10
+ * Heuristic:
11
+ * - If the first arg looks command-like (all-lowercase kebab, no path
12
+ * separators, no absolute/relative path markers)
13
+ * - AND it's not in the known-commands allow-list
14
+ * - AND it doesn't resolve to an existing directory
15
+ * - → treat as typo: print an error + suggest the closest command.
16
+ *
17
+ * Everything else passes through untouched — a real project root like
18
+ * `/home/user/my-project` or `./subdir` goes to startServer as before.
19
+ */
20
+ export declare const KNOWN_COMMANDS: readonly ["hook-read", "hook-edit", "hook-post-bash", "hook-post-task", "hook-session-start", "install-hook", "uninstall-hook", "install-ast-index", "doctor", "bless-agents", "unbless-agents", "install-agents", "uninstall-agents", "stats", "save-doc", "list-docs", "init", "--version", "-v", "--help", "-h"];
21
+ export interface TypoGuardResult {
22
+ kind: "pass-through" | "typo";
23
+ suggestion?: string;
24
+ message?: string;
25
+ }
26
+ export declare function checkForTypo(firstArg: string | undefined): TypoGuardResult;
27
+ //# sourceMappingURL=typo-guard.d.ts.map
@@ -0,0 +1,119 @@
1
+ /**
2
+ * CLI typo guard — catches obvious mis-typed commands before they fall
3
+ * through to the default `startServer(cliArgs)` branch where the arg is
4
+ * treated as a project root.
5
+ *
6
+ * The bug it prevents: `npx token-pilot install-aents` (missing 'g')
7
+ * silently became a projectRoot=install-aents MCP server launch, which
8
+ * then created stray `install-aents/.claude/settings.json` directories.
9
+ *
10
+ * Heuristic:
11
+ * - If the first arg looks command-like (all-lowercase kebab, no path
12
+ * separators, no absolute/relative path markers)
13
+ * - AND it's not in the known-commands allow-list
14
+ * - AND it doesn't resolve to an existing directory
15
+ * - → treat as typo: print an error + suggest the closest command.
16
+ *
17
+ * Everything else passes through untouched — a real project root like
18
+ * `/home/user/my-project` or `./subdir` goes to startServer as before.
19
+ */
20
+ import { existsSync, statSync } from "node:fs";
21
+ export const KNOWN_COMMANDS = [
22
+ "hook-read",
23
+ "hook-edit",
24
+ "hook-post-bash",
25
+ "hook-post-task",
26
+ "hook-session-start",
27
+ "install-hook",
28
+ "uninstall-hook",
29
+ "install-ast-index",
30
+ "doctor",
31
+ "bless-agents",
32
+ "unbless-agents",
33
+ "install-agents",
34
+ "uninstall-agents",
35
+ "stats",
36
+ "save-doc",
37
+ "list-docs",
38
+ "init",
39
+ "--version",
40
+ "-v",
41
+ "--help",
42
+ "-h",
43
+ ];
44
+ const COMMAND_LIKE_RE = /^[a-z]+(-[a-z]+)+$/;
45
+ function looksLikeCommand(arg) {
46
+ if (!arg)
47
+ return false;
48
+ if (arg.startsWith("-") && !arg.startsWith("--"))
49
+ return false;
50
+ if (arg.includes("/") || arg.includes("\\"))
51
+ return false;
52
+ if (arg === "." || arg === "..")
53
+ return false;
54
+ return COMMAND_LIKE_RE.test(arg);
55
+ }
56
+ function existsAsDir(arg) {
57
+ try {
58
+ return existsSync(arg) && statSync(arg).isDirectory();
59
+ }
60
+ catch {
61
+ return false;
62
+ }
63
+ }
64
+ /**
65
+ * Levenshtein distance — cheap enough on 20-item allow-list.
66
+ */
67
+ function distance(a, b) {
68
+ if (a === b)
69
+ return 0;
70
+ const m = a.length;
71
+ const n = b.length;
72
+ if (m === 0)
73
+ return n;
74
+ if (n === 0)
75
+ return m;
76
+ const prev = new Array(n + 1);
77
+ const curr = new Array(n + 1);
78
+ for (let j = 0; j <= n; j++)
79
+ prev[j] = j;
80
+ for (let i = 1; i <= m; i++) {
81
+ curr[0] = i;
82
+ for (let j = 1; j <= n; j++) {
83
+ const cost = a[i - 1] === b[j - 1] ? 0 : 1;
84
+ curr[j] = Math.min(prev[j] + 1, curr[j - 1] + 1, prev[j - 1] + cost);
85
+ }
86
+ for (let j = 0; j <= n; j++)
87
+ prev[j] = curr[j];
88
+ }
89
+ return prev[n];
90
+ }
91
+ export function checkForTypo(firstArg) {
92
+ if (!firstArg)
93
+ return { kind: "pass-through" };
94
+ if (KNOWN_COMMANDS.includes(firstArg)) {
95
+ return { kind: "pass-through" };
96
+ }
97
+ if (!looksLikeCommand(firstArg))
98
+ return { kind: "pass-through" };
99
+ if (existsAsDir(firstArg))
100
+ return { kind: "pass-through" };
101
+ // Find closest match among command-like known commands.
102
+ let best = "";
103
+ let bestDistance = Infinity;
104
+ for (const cmd of KNOWN_COMMANDS) {
105
+ if (cmd.startsWith("-"))
106
+ continue; // skip flags for suggestion
107
+ const d = distance(firstArg, cmd);
108
+ if (d < bestDistance) {
109
+ bestDistance = d;
110
+ best = cmd;
111
+ }
112
+ }
113
+ const suggestion = bestDistance <= 3 ? best : undefined;
114
+ const message = suggestion
115
+ ? `Unknown command "${firstArg}". Did you mean "${suggestion}"?`
116
+ : `Unknown command "${firstArg}". Run "token-pilot --help" for the full list.`;
117
+ return { kind: "typo", suggestion, message };
118
+ }
119
+ //# sourceMappingURL=typo-guard.js.map
@@ -55,6 +55,15 @@ function createHookConfig(options) {
55
55
  },
56
56
  ],
57
57
  },
58
+ {
59
+ matcher: "Task",
60
+ hooks: [
61
+ {
62
+ type: "command",
63
+ command: buildHookCommand("hook-post-task", options),
64
+ },
65
+ ],
66
+ },
58
67
  ],
59
68
  },
60
69
  };
@@ -0,0 +1,67 @@
1
+ /**
2
+ * TP-q33(a) — PostToolUse:Task budget enforcement.
3
+ *
4
+ * Claude Code's `Task` tool is how subagents are dispatched. When one
5
+ * returns, this hook:
6
+ * 1. Identifies the subagent by `tool_input.subagent_type`.
7
+ * 2. Loads its agent markdown (project first, then ~/.claude/agents).
8
+ * 3. Reads the `Response budget: ~N tokens` line from the body.
9
+ * 4. Counts tokens in the `tool_response` body (chars/4 heuristic).
10
+ * 5. If actual > budget × (1 + OVER_BUDGET_TOLERANCE), append a JSONL
11
+ * entry to `.token-pilot/over-budget.log`.
12
+ *
13
+ * Silent on every failure — telemetry must never break the agent loop.
14
+ * Non-tp-* subagents are ignored (we only enforce our own contracts).
15
+ */
16
+ export declare const OVER_BUDGET_LOG = "over-budget.log";
17
+ /** Ratio above which we flag — 0.1 = 10 % grace. */
18
+ export declare const OVER_BUDGET_TOLERANCE = 0.1;
19
+ export declare function parseAgentBudget(body: string): number | null;
20
+ /**
21
+ * Count approx tokens in the `tool_response.content[*].text` blocks of a
22
+ * PostToolUse hook input for the Task tool. Returns null for anything
23
+ * other than a well-formed Task response.
24
+ */
25
+ export declare function extractSubagentTokens(input: {
26
+ tool_name?: string;
27
+ tool_response?: unknown;
28
+ }): number | null;
29
+ export interface BudgetDecisionInput {
30
+ agentName: string;
31
+ budget: number | null;
32
+ actualTokens: number;
33
+ }
34
+ export interface BudgetDecisionResult {
35
+ overBudget: boolean;
36
+ overByRatio: number;
37
+ message: string | null;
38
+ }
39
+ export declare function decideBudgetAdvice(input: BudgetDecisionInput): BudgetDecisionResult;
40
+ export interface OverBudgetEntry {
41
+ ts: number;
42
+ agent: string;
43
+ budget: number;
44
+ actualTokens: number;
45
+ overByRatio: number;
46
+ }
47
+ export declare function appendOverBudgetLog(projectRoot: string, entry: OverBudgetEntry): Promise<void>;
48
+ /**
49
+ * Locate the markdown body for a `tp-*` subagent — project-level first,
50
+ * then user-level. Returns null when neither exists. Non-tp-* subagents
51
+ * are rejected up front so we never peek outside our namespace.
52
+ */
53
+ export declare function loadAgentBody(projectRoot: string, homeDir: string, agentName: string): Promise<string | null>;
54
+ export interface PostTaskHookInput {
55
+ tool_name?: string;
56
+ tool_input?: {
57
+ subagent_type?: string;
58
+ };
59
+ tool_response?: unknown;
60
+ }
61
+ /**
62
+ * Full post-Task processing: read frontmatter, count tokens, log over-budget.
63
+ * Returns the advice message (or null) so the caller can optionally emit
64
+ * `additionalContext` — though the primary output channel is the log file.
65
+ */
66
+ export declare function processPostTask(projectRoot: string, homeDir: string, input: PostTaskHookInput): Promise<string | null>;
67
+ //# sourceMappingURL=post-task.d.ts.map
@@ -0,0 +1,136 @@
1
+ /**
2
+ * TP-q33(a) — PostToolUse:Task budget enforcement.
3
+ *
4
+ * Claude Code's `Task` tool is how subagents are dispatched. When one
5
+ * returns, this hook:
6
+ * 1. Identifies the subagent by `tool_input.subagent_type`.
7
+ * 2. Loads its agent markdown (project first, then ~/.claude/agents).
8
+ * 3. Reads the `Response budget: ~N tokens` line from the body.
9
+ * 4. Counts tokens in the `tool_response` body (chars/4 heuristic).
10
+ * 5. If actual > budget × (1 + OVER_BUDGET_TOLERANCE), append a JSONL
11
+ * entry to `.token-pilot/over-budget.log`.
12
+ *
13
+ * Silent on every failure — telemetry must never break the agent loop.
14
+ * Non-tp-* subagents are ignored (we only enforce our own contracts).
15
+ */
16
+ import { promises as fs } from "node:fs";
17
+ import { join } from "node:path";
18
+ export const OVER_BUDGET_LOG = "over-budget.log";
19
+ /** Ratio above which we flag — 0.1 = 10 % grace. */
20
+ export const OVER_BUDGET_TOLERANCE = 0.1;
21
+ const BUDGET_RE = /Response budget:\s*~?\s*(\d{2,6})\s*tokens?/i;
22
+ export function parseAgentBudget(body) {
23
+ const m = body.match(BUDGET_RE);
24
+ if (!m)
25
+ return null;
26
+ const n = Number.parseInt(m[1], 10);
27
+ return Number.isFinite(n) && n > 0 ? n : null;
28
+ }
29
+ /**
30
+ * Count approx tokens in the `tool_response.content[*].text` blocks of a
31
+ * PostToolUse hook input for the Task tool. Returns null for anything
32
+ * other than a well-formed Task response.
33
+ */
34
+ export function extractSubagentTokens(input) {
35
+ if (input.tool_name !== "Task")
36
+ return null;
37
+ const resp = input.tool_response;
38
+ if (!resp || typeof resp !== "object")
39
+ return null;
40
+ const parts = Array.isArray(resp.content) ? resp.content : [];
41
+ let chars = 0;
42
+ for (const p of parts) {
43
+ if (typeof p?.text === "string")
44
+ chars += p.text.length;
45
+ }
46
+ if (chars === 0)
47
+ return null;
48
+ return Math.ceil(chars / 4);
49
+ }
50
+ export function decideBudgetAdvice(input) {
51
+ if (input.budget == null || input.budget <= 0) {
52
+ return { overBudget: false, overByRatio: 0, message: null };
53
+ }
54
+ const allowed = input.budget * (1 + OVER_BUDGET_TOLERANCE);
55
+ if (input.actualTokens <= allowed) {
56
+ return {
57
+ overBudget: false,
58
+ overByRatio: input.actualTokens / input.budget - 1,
59
+ message: null,
60
+ };
61
+ }
62
+ const ratio = input.actualTokens / input.budget - 1;
63
+ const pct = Math.round(ratio * 100);
64
+ return {
65
+ overBudget: true,
66
+ overByRatio: ratio,
67
+ message: `${input.agentName} exceeded budget (~${input.actualTokens} tokens vs budget ${input.budget}, +${pct}%). See .token-pilot/over-budget.log.`,
68
+ };
69
+ }
70
+ export async function appendOverBudgetLog(projectRoot, entry) {
71
+ try {
72
+ const dir = join(projectRoot, ".token-pilot");
73
+ await fs.mkdir(dir, { recursive: true });
74
+ const line = JSON.stringify(entry) + "\n";
75
+ await fs.appendFile(join(dir, OVER_BUDGET_LOG), line);
76
+ }
77
+ catch {
78
+ /* silent — logging must never break the hook */
79
+ }
80
+ }
81
+ /**
82
+ * Locate the markdown body for a `tp-*` subagent — project-level first,
83
+ * then user-level. Returns null when neither exists. Non-tp-* subagents
84
+ * are rejected up front so we never peek outside our namespace.
85
+ */
86
+ export async function loadAgentBody(projectRoot, homeDir, agentName) {
87
+ if (!agentName.startsWith("tp-"))
88
+ return null;
89
+ const candidates = [
90
+ join(projectRoot, ".claude", "agents", `${agentName}.md`),
91
+ join(homeDir, ".claude", "agents", `${agentName}.md`),
92
+ ];
93
+ for (const p of candidates) {
94
+ try {
95
+ return await fs.readFile(p, "utf-8");
96
+ }
97
+ catch {
98
+ /* try next */
99
+ }
100
+ }
101
+ return null;
102
+ }
103
+ /**
104
+ * Full post-Task processing: read frontmatter, count tokens, log over-budget.
105
+ * Returns the advice message (or null) so the caller can optionally emit
106
+ * `additionalContext` — though the primary output channel is the log file.
107
+ */
108
+ export async function processPostTask(projectRoot, homeDir, input) {
109
+ if (input.tool_name !== "Task")
110
+ return null;
111
+ const agentName = input.tool_input?.subagent_type;
112
+ if (typeof agentName !== "string" || !agentName.startsWith("tp-")) {
113
+ return null;
114
+ }
115
+ const actualTokens = extractSubagentTokens(input);
116
+ if (actualTokens == null)
117
+ return null;
118
+ const body = await loadAgentBody(projectRoot, homeDir, agentName);
119
+ const budget = body ? parseAgentBudget(body) : null;
120
+ const decision = decideBudgetAdvice({
121
+ agentName,
122
+ budget,
123
+ actualTokens,
124
+ });
125
+ if (decision.overBudget && budget != null) {
126
+ await appendOverBudgetLog(projectRoot, {
127
+ ts: Date.now(),
128
+ agent: agentName,
129
+ budget,
130
+ actualTokens,
131
+ overByRatio: decision.overByRatio,
132
+ });
133
+ }
134
+ return decision.message;
135
+ }
136
+ //# sourceMappingURL=post-task.js.map
package/dist/index.js CHANGED
@@ -18,6 +18,8 @@ import { handleSessionStart } from "./hooks/session-start.js";
18
18
  import { computeEffectiveThreshold } from "./hooks/adaptive-threshold.js";
19
19
  import { loadSessionSavedTokens } from "./core/session-savings.js";
20
20
  import { handleSaveDocCli, handleListDocsCli } from "./cli/save-doc.js";
21
+ import { checkForTypo } from "./cli/typo-guard.js";
22
+ import { processPostTask } from "./hooks/post-task.js";
21
23
  import { isContextModeInstalledSync } from "./integration/context-mode-detector.js";
22
24
  import { handleBlessAgents } from "./cli/bless-agents.js";
23
25
  import { unblessAgents } from "./cli/unbless-agents.js";
@@ -87,6 +89,13 @@ export function getVersion() {
87
89
  }
88
90
  }
89
91
  export async function main(cliArgs = process.argv.slice(2)) {
92
+ // Guard against mis-typed commands like `install-aents` silently
93
+ // becoming a projectRoot=install-aents server launch. See TP-v0.22.3.
94
+ const typo = checkForTypo(cliArgs[0]);
95
+ if (typo.kind === "typo") {
96
+ process.stderr.write(`[token-pilot] ${typo.message}\n`);
97
+ process.exit(1);
98
+ }
90
99
  switch (cliArgs[0]) {
91
100
  case "hook-read": {
92
101
  const cfg = await loadConfig(process.cwd());
@@ -116,6 +125,26 @@ export async function main(cliArgs = process.argv.slice(2)) {
116
125
  process.exit(0);
117
126
  return;
118
127
  }
128
+ case "hook-post-task": {
129
+ try {
130
+ const stdin = readFileSync(0, "utf-8");
131
+ const input = JSON.parse(stdin);
132
+ const message = await processPostTask(process.cwd(), homedir(), input);
133
+ if (message) {
134
+ process.stdout.write(JSON.stringify({
135
+ hookSpecificOutput: {
136
+ hookEventName: "PostToolUse",
137
+ additionalContext: `[token-pilot] ${message}`,
138
+ },
139
+ }));
140
+ }
141
+ }
142
+ catch {
143
+ /* silent — hook must not break */
144
+ }
145
+ process.exit(0);
146
+ return;
147
+ }
119
148
  case "hook-session-start": {
120
149
  const cfg = await loadConfig(process.cwd());
121
150
  // `sessionStart.enabled` is independent of `hooks.mode` by design —
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "token-pilot",
3
- "version": "0.22.2",
3
+ "version": "0.23.1",
4
4
  "description": "Save up to 80% tokens when AI reads code — MCP server for token-efficient code navigation, AST-aware structural reading instead of dumping full files into context window",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",