token-pilot 0.42.3 → 0.43.0
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.
- package/.claude-plugin/marketplace.json +3 -3
- package/.claude-plugin/plugin.json +4 -2
- package/CHANGELOG.md +101 -0
- package/README.md +1 -1
- package/agents/tp-api-surface-tracker.md +1 -1
- package/agents/tp-audit-scanner.md +1 -1
- package/agents/tp-commit-writer.md +1 -1
- package/agents/tp-context-engineer.md +1 -1
- package/agents/tp-dead-code-finder.md +1 -1
- package/agents/tp-debugger.md +1 -1
- package/agents/tp-dep-health.md +1 -1
- package/agents/tp-doc-writer.md +1 -1
- package/agents/tp-history-explorer.md +1 -1
- package/agents/tp-impact-analyzer.md +1 -1
- package/agents/tp-incident-timeline.md +1 -1
- package/agents/tp-incremental-builder.md +1 -1
- package/agents/tp-migration-scout.md +1 -1
- package/agents/tp-onboard.md +1 -1
- package/agents/tp-performance-profiler.md +1 -1
- package/agents/tp-pr-reviewer.md +1 -1
- package/agents/tp-refactor-planner.md +1 -1
- package/agents/tp-review-impact.md +1 -1
- package/agents/tp-run.md +1 -1
- package/agents/tp-session-restorer.md +1 -1
- package/agents/tp-ship-coordinator.md +1 -1
- package/agents/tp-spec-writer.md +1 -1
- package/agents/tp-test-coverage-gapper.md +1 -1
- package/agents/tp-test-triage.md +1 -1
- package/agents/tp-test-writer.md +1 -1
- package/dist/ast-index/client.d.ts +16 -0
- package/dist/ast-index/client.js +30 -0
- package/dist/core/validation.d.ts +17 -0
- package/dist/core/validation.js +54 -0
- package/dist/handlers/module-route.d.ts +20 -0
- package/dist/handlers/module-route.js +73 -0
- package/dist/index.js +3 -3
- package/dist/server/tool-definitions.d.ts +250 -0
- package/dist/server/tool-definitions.js +40 -0
- package/dist/server.js +42 -2
- package/docs/tools.md +2 -1
- package/package.json +1 -1
- package/skills/guide/SKILL.md +4 -0
- package/skills/install/SKILL.md +4 -0
- package/skills/stats/SKILL.md +3 -0
|
@@ -5,15 +5,15 @@
|
|
|
5
5
|
"email": "shahinyanm@gmail.com"
|
|
6
6
|
},
|
|
7
7
|
"metadata": {
|
|
8
|
-
"description": "Token Pilot
|
|
9
|
-
"version": "0.
|
|
8
|
+
"description": "Token Pilot — save 60-90% tokens when AI reads code",
|
|
9
|
+
"version": "0.43.0"
|
|
10
10
|
},
|
|
11
11
|
"plugins": [
|
|
12
12
|
{
|
|
13
13
|
"name": "token-pilot",
|
|
14
14
|
"source": "./",
|
|
15
15
|
"description": "Reduces token consumption by 60-90% via AST-aware lazy file reading, structural symbol navigation, and cross-session tool-usage analytics. 22 MCP tools + 19 subagents + budget watchdog hooks.",
|
|
16
|
-
"version": "0.
|
|
16
|
+
"version": "0.43.0",
|
|
17
17
|
"author": {
|
|
18
18
|
"name": "Digital-Threads"
|
|
19
19
|
},
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "token-pilot",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.43.0",
|
|
4
4
|
"description": "Saves 60-90% tokens on AI code reading. AST-aware lazy reads, symbol navigation, find_usages, structural git diff/log, edit-safety guard, Task-routing matcher, cross-session telemetry (errors + diagnostics), 25 tp-* subagents tiered to haiku/sonnet/opus with budget watchdog.",
|
|
5
5
|
"author": {
|
|
6
6
|
"name": "Digital-Threads",
|
|
@@ -21,7 +21,9 @@
|
|
|
21
21
|
"mcpServers": {
|
|
22
22
|
"token-pilot": {
|
|
23
23
|
"command": "sh",
|
|
24
|
-
"args": [
|
|
24
|
+
"args": [
|
|
25
|
+
"${CLAUDE_PLUGIN_ROOT}/start.sh"
|
|
26
|
+
]
|
|
25
27
|
}
|
|
26
28
|
}
|
|
27
29
|
}
|
package/CHANGELOG.md
CHANGED
|
@@ -5,6 +5,107 @@ 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.43.0] - 2026-06-06
|
|
9
|
+
|
|
10
|
+
Bundled release: everything actionable from **ast-index 3.41→3.45** and
|
|
11
|
+
**Claude Code 2.1.163→2.1.167**, plus a statusline fix.
|
|
12
|
+
|
|
13
|
+
### Added — `module_route` MCP tool (ast-index 3.44)
|
|
14
|
+
|
|
15
|
+
New tool wrapping ast-index's `module-route` command: the transitive
|
|
16
|
+
dependency path(s) between two modules. Answers "how does module A reach
|
|
17
|
+
module B through the import graph?", traces coupling, and can emit a
|
|
18
|
+
dependency diagram.
|
|
19
|
+
|
|
20
|
+
- `from` / `to` (required), plus `all`, `maxPaths` (≤200), `maxDepth`
|
|
21
|
+
(≤50), `viaKind` (`api`/`implementation`/`all`), `format`
|
|
22
|
+
(`text`/`json`/`mermaid`/`dot`).
|
|
23
|
+
- Machine formats (json/mermaid/dot) pass through clean — no header that
|
|
24
|
+
would corrupt a diagram/parse. Text format gets a `MODULE ROUTE: a → b`
|
|
25
|
+
header.
|
|
26
|
+
- Empty output explains both causes (modules unrelated **or** the
|
|
27
|
+
module-dependency graph isn't indexed — `ast-index rebuild`).
|
|
28
|
+
- Full-profile only (not in nav/edit/minimal sets) — a specialised
|
|
29
|
+
analysis tool, like the audit tools.
|
|
30
|
+
- `exec` already sets `AST_INDEX_WALK_UP=1`, so the route resolves from a
|
|
31
|
+
monorepo subdir without passing `--walk-up`.
|
|
32
|
+
|
|
33
|
+
### Fixed — statusline now counts MCP-tool savings, not just hook denials
|
|
34
|
+
|
|
35
|
+
The badge summed only `hook-events.jsonl` (`savedTokens` from intercepted
|
|
36
|
+
raw `Read`/`Grep`). The larger share — savings from the MCP tools
|
|
37
|
+
themselves (`smart_read`, `outline`, `find_usages`, …) — lives in
|
|
38
|
+
`tool-calls.jsonl` and was **invisible** to the badge, so the displayed
|
|
39
|
+
figure undercounted real savings (often by an order of magnitude).
|
|
40
|
+
|
|
41
|
+
Two changes fix it:
|
|
42
|
+
|
|
43
|
+
- The MCP server now stamps every `tool-calls.jsonl` row with the real
|
|
44
|
+
Claude Code session id, read from `CLAUDE_CODE_SESSION_ID` (exported to
|
|
45
|
+
child processes; verified against the 2.1.167 bundle — the same value
|
|
46
|
+
the hooks receive and the statusline payload carries). Previously these
|
|
47
|
+
rows had an empty `session_id`, so they could not be attributed to a
|
|
48
|
+
session at all.
|
|
49
|
+
- The statusline sums **both** logs: `hook-events.jsonl` `savedTokens`
|
|
50
|
+
plus `tool-calls.jsonl` (`tokensWouldBe − tokensReturned`), each split
|
|
51
|
+
into the current session and the project total. Zero/negative deltas
|
|
52
|
+
(pass-throughs) are ignored.
|
|
53
|
+
|
|
54
|
+
### Added — statusline Claude.ai rate limits (CC 2.1.80+)
|
|
55
|
+
|
|
56
|
+
The badge now appends `5h:42% 7d:13%` when the statusline payload carries
|
|
57
|
+
`rate_limits` (subscribers only, after the first API response). Schema
|
|
58
|
+
verified against the 2.1.167 bundle: `rate_limits.five_hour.used_percentage`
|
|
59
|
+
and `rate_limits.seven_day.used_percentage`. Unlike the cumulative token
|
|
60
|
+
total, these numbers move every turn — the badge finally shows something
|
|
61
|
+
live. Parsed with `sed` (no `jq` dependency) and whitelisted to digits.
|
|
62
|
+
|
|
63
|
+
### Fixed — statusline bare `[TP]` in monorepos / subdirs / worktrees
|
|
64
|
+
|
|
65
|
+
The badge resolved the events log only at the exact `cwd` from the
|
|
66
|
+
payload. In a monorepo (or worktree, or any session `cd`'d into a
|
|
67
|
+
subpackage) the `.token-pilot/` dir is at the repo root, so the lookup
|
|
68
|
+
failed and rendered a bare `[TP]` with no token count. The script now
|
|
69
|
+
**walks up** to the nearest ancestor with `.token-pilot/` (bounded to 40
|
|
70
|
+
levels), the same way git finds `.git`.
|
|
71
|
+
|
|
72
|
+
### Changed — statusline shows session + project savings (`s:12.3k · 172.6k`)
|
|
73
|
+
|
|
74
|
+
The badge now renders **both** the current session's saved tokens (the
|
|
75
|
+
number you watch climb during a run) and the cumulative project total,
|
|
76
|
+
e.g. `[TP s:12.3k · 172.6k]`. A fresh session that hasn't saved anything
|
|
77
|
+
yet falls back to the project total alone (never an empty badge after
|
|
78
|
+
first use). Numbers render with one decimal (`172.6k`, not `172k`) so a
|
|
79
|
+
single turn's ~100-token savings is visible on each render — whole-`k`
|
|
80
|
+
rounding previously made the figure look frozen.
|
|
81
|
+
|
|
82
|
+
### Added — `effort: low` on the bundled skills (CC 2.1.16x)
|
|
83
|
+
|
|
84
|
+
`guide` / `install` / `stats` declare `effort: low` — they render static
|
|
85
|
+
output or run one CLI call, so they don't need a high-effort model.
|
|
86
|
+
Faster and cheaper when invoked.
|
|
87
|
+
|
|
88
|
+
### Notes — Claude Code 2.1.16x integration (no code change required)
|
|
89
|
+
|
|
90
|
+
- **`additionalContext` no longer dropped on a failed tool call** — our
|
|
91
|
+
PreToolUse routing guidance now survives a failed call (we benefit
|
|
92
|
+
automatically).
|
|
93
|
+
- **`SubagentStop` input gained `background_tasks` / `session_crons`** —
|
|
94
|
+
available to our subagent-stop hook for future budget feedback.
|
|
95
|
+
- **Glob deny rules (`"*"` denies all tools)** — usable as a second
|
|
96
|
+
enforcement layer on top of our deny hooks for stricter TP adoption.
|
|
97
|
+
|
|
98
|
+
### Deferred — `MessageDisplay` hook (researched, not shipped)
|
|
99
|
+
|
|
100
|
+
CC's new `MessageDisplay` hook transforms assistant text *as displayed*.
|
|
101
|
+
Deliberately NOT wired this release: (1) the output contract (the field
|
|
102
|
+
that returns replacement text) is not confirmable from the minified
|
|
103
|
+
2.1.167 bundle — and our rule is never to ship an unverified CC field
|
|
104
|
+
beside working hooks; (2) it is display-only, so it saves no input or
|
|
105
|
+
output tokens (the text is already generated and already in context).
|
|
106
|
+
That is caveman's cosmetic-output domain, not token-pilot's input domain.
|
|
107
|
+
Revisit once a live MessageDisplay payload pins the contract.
|
|
108
|
+
|
|
8
109
|
## [0.30.0] - 2026-04-19
|
|
9
110
|
|
|
10
111
|
### Added — `minimal` profile (5 tools, near-zero overhead)
|
package/README.md
CHANGED
|
@@ -43,7 +43,7 @@ Creates (or merges into) `.mcp.json` with `token-pilot` + [`context-mode`](https
|
|
|
43
43
|
|
|
44
44
|
## What You Get
|
|
45
45
|
|
|
46
|
-
- **
|
|
46
|
+
- **23 MCP tools** — structural reads, symbol search, git analysis, module routing, session analytics → [tools reference](docs/tools.md)
|
|
47
47
|
- **PreToolUse hooks** — block heavy `Grep`/`Bash`/`Read` calls; redirect to efficient alternatives → [hooks & modes](docs/hooks.md)
|
|
48
48
|
- **25 `tp-*` subagents** (Claude Code only) — MCP-first delegates with haiku/sonnet model tiers and budget enforcement → [agents reference](docs/agents.md)
|
|
49
49
|
- **Tool profiles** — trim advertised `tools/list` to save ~2 k tokens per session → [profiles & config](docs/configuration.md)
|
|
@@ -9,7 +9,7 @@ tools:
|
|
|
9
9
|
- mcp__token-pilot__read_symbol
|
|
10
10
|
- Bash
|
|
11
11
|
model: haiku
|
|
12
|
-
token_pilot_version: "0.
|
|
12
|
+
token_pilot_version: "0.43.0"
|
|
13
13
|
token_pilot_body_hash: dd184501203fa7f3c73f419c4ffbe33c4be75400cb64a7a51733a3fe23f6e085
|
|
14
14
|
requiredMcpServers:
|
|
15
15
|
- "token-pilot"
|
|
@@ -8,7 +8,7 @@ tools:
|
|
|
8
8
|
- mcp__token-pilot__test_summary
|
|
9
9
|
- mcp__token-pilot__outline
|
|
10
10
|
- Bash
|
|
11
|
-
token_pilot_version: "0.
|
|
11
|
+
token_pilot_version: "0.43.0"
|
|
12
12
|
token_pilot_body_hash: de64a406b5176de19f7422619c7de7949b1f28865f225402c9cea9255f377428
|
|
13
13
|
requiredMcpServers:
|
|
14
14
|
- "token-pilot"
|
package/agents/tp-debugger.md
CHANGED
package/agents/tp-dep-health.md
CHANGED
package/agents/tp-doc-writer.md
CHANGED
|
@@ -12,7 +12,7 @@ tools:
|
|
|
12
12
|
- mcp__token-pilot__read_symbols
|
|
13
13
|
- Read
|
|
14
14
|
model: sonnet
|
|
15
|
-
token_pilot_version: "0.
|
|
15
|
+
token_pilot_version: "0.43.0"
|
|
16
16
|
token_pilot_body_hash: 351a987e11eba63852f5431a16d8eb53104f4f689f82fdcc5a2bf4db948ba92f
|
|
17
17
|
requiredMcpServers:
|
|
18
18
|
- "token-pilot"
|
|
@@ -8,7 +8,7 @@ tools:
|
|
|
8
8
|
- mcp__token-pilot__read_symbol
|
|
9
9
|
- Bash
|
|
10
10
|
model: inherit
|
|
11
|
-
token_pilot_version: "0.
|
|
11
|
+
token_pilot_version: "0.43.0"
|
|
12
12
|
token_pilot_body_hash: de5722bfea374eaab096c1ae635c37879e7a91370ee3cd0532f4240be03c91eb
|
|
13
13
|
requiredMcpServers:
|
|
14
14
|
- "token-pilot"
|
package/agents/tp-onboard.md
CHANGED
|
@@ -10,7 +10,7 @@ tools:
|
|
|
10
10
|
- mcp__token-pilot__smart_read
|
|
11
11
|
- mcp__token-pilot__smart_read_many
|
|
12
12
|
- mcp__token-pilot__read_section
|
|
13
|
-
token_pilot_version: "0.
|
|
13
|
+
token_pilot_version: "0.43.0"
|
|
14
14
|
token_pilot_body_hash: 832e95633fbc8e9b0c10f3e540a327d4be062fb4b3f17a6cce6be13f414e2927
|
|
15
15
|
requiredMcpServers:
|
|
16
16
|
- "token-pilot"
|
package/agents/tp-pr-reviewer.md
CHANGED
|
@@ -11,7 +11,7 @@ tools:
|
|
|
11
11
|
- mcp__token-pilot__read_for_edit
|
|
12
12
|
- Read
|
|
13
13
|
model: sonnet
|
|
14
|
-
token_pilot_version: "0.
|
|
14
|
+
token_pilot_version: "0.43.0"
|
|
15
15
|
token_pilot_body_hash: f83f50d05b4f70285ae7afed2b1a406fc436df56e61a0aedbfb31edc7f2b6e66
|
|
16
16
|
requiredMcpServers:
|
|
17
17
|
- "token-pilot"
|
|
@@ -8,7 +8,7 @@ tools:
|
|
|
8
8
|
- mcp__token-pilot__outline
|
|
9
9
|
- mcp__token-pilot__read_symbol
|
|
10
10
|
model: sonnet
|
|
11
|
-
token_pilot_version: "0.
|
|
11
|
+
token_pilot_version: "0.43.0"
|
|
12
12
|
token_pilot_body_hash: c5f6fc122c89e16e5cf774045f92169ee3468555320b898171ba13eca5323550
|
|
13
13
|
requiredMcpServers:
|
|
14
14
|
- "token-pilot"
|
|
@@ -9,7 +9,7 @@ tools:
|
|
|
9
9
|
- mcp__token-pilot__module_info
|
|
10
10
|
- Bash
|
|
11
11
|
model: sonnet
|
|
12
|
-
token_pilot_version: "0.
|
|
12
|
+
token_pilot_version: "0.43.0"
|
|
13
13
|
token_pilot_body_hash: 8ef3c3341cbfed4eb8dd130126a9683edc57e378c92ff0ca764d584fd941c55c
|
|
14
14
|
requiredMcpServers:
|
|
15
15
|
- "token-pilot"
|
package/agents/tp-run.md
CHANGED
package/agents/tp-spec-writer.md
CHANGED
|
@@ -10,7 +10,7 @@ tools:
|
|
|
10
10
|
- mcp__token-pilot__test_summary
|
|
11
11
|
- Glob
|
|
12
12
|
- Grep
|
|
13
|
-
token_pilot_version: "0.
|
|
13
|
+
token_pilot_version: "0.43.0"
|
|
14
14
|
token_pilot_body_hash: be81eed53a3720d146cf89e4a14a7a56577633f7c84c234c412ab70d64c05b11
|
|
15
15
|
requiredMcpServers:
|
|
16
16
|
- "token-pilot"
|
package/agents/tp-test-triage.md
CHANGED
|
@@ -8,7 +8,7 @@ tools:
|
|
|
8
8
|
- mcp__token-pilot__find_usages
|
|
9
9
|
- mcp__token-pilot__read_symbol
|
|
10
10
|
model: sonnet
|
|
11
|
-
token_pilot_version: "0.
|
|
11
|
+
token_pilot_version: "0.43.0"
|
|
12
12
|
token_pilot_body_hash: 362ecf4cb03b059421ea26933473700900073dc38b3a7fe271208dfb1ae14f90
|
|
13
13
|
requiredMcpServers:
|
|
14
14
|
- "token-pilot"
|
package/agents/tp-test-writer.md
CHANGED
|
@@ -80,6 +80,22 @@ export declare class AstIndexClient {
|
|
|
80
80
|
stopPeriodicUpdate(): void;
|
|
81
81
|
modules(pattern?: string): Promise<AstIndexModuleEntry[]>;
|
|
82
82
|
moduleDeps(module: string): Promise<AstIndexModuleDep[]>;
|
|
83
|
+
/**
|
|
84
|
+
* Transitive dependency path(s) between two modules — ast-index 3.44
|
|
85
|
+
* `module-route`. Returns the raw CLI output for the requested format
|
|
86
|
+
* (text/json/mermaid/dot); the handler frames it. Null when the index
|
|
87
|
+
* is unavailable. `exec` already sets AST_INDEX_WALK_UP=1, so the
|
|
88
|
+
* `--walk-up` flag is implied and not passed here.
|
|
89
|
+
*/
|
|
90
|
+
moduleRoute(opts: {
|
|
91
|
+
from: string;
|
|
92
|
+
to: string;
|
|
93
|
+
all?: boolean;
|
|
94
|
+
maxPaths?: number;
|
|
95
|
+
maxDepth?: number;
|
|
96
|
+
viaKind?: string;
|
|
97
|
+
format?: string;
|
|
98
|
+
}): Promise<string | null>;
|
|
83
99
|
moduleDependents(module: string): Promise<AstIndexModuleDep[]>;
|
|
84
100
|
unusedDeps(module: string): Promise<AstIndexUnusedDep[]>;
|
|
85
101
|
moduleApi(module: string): Promise<AstIndexModuleApi[]>;
|
package/dist/ast-index/client.js
CHANGED
|
@@ -679,6 +679,36 @@ export class AstIndexClient {
|
|
|
679
679
|
return [];
|
|
680
680
|
}
|
|
681
681
|
}
|
|
682
|
+
/**
|
|
683
|
+
* Transitive dependency path(s) between two modules — ast-index 3.44
|
|
684
|
+
* `module-route`. Returns the raw CLI output for the requested format
|
|
685
|
+
* (text/json/mermaid/dot); the handler frames it. Null when the index
|
|
686
|
+
* is unavailable. `exec` already sets AST_INDEX_WALK_UP=1, so the
|
|
687
|
+
* `--walk-up` flag is implied and not passed here.
|
|
688
|
+
*/
|
|
689
|
+
async moduleRoute(opts) {
|
|
690
|
+
if (this.indexDisabled || this.indexOversized)
|
|
691
|
+
return null;
|
|
692
|
+
await this.ensureIndex();
|
|
693
|
+
try {
|
|
694
|
+
const cmdArgs = ["module-route", "--from", opts.from, "--to", opts.to];
|
|
695
|
+
if (opts.all)
|
|
696
|
+
cmdArgs.push("--all");
|
|
697
|
+
if (opts.maxPaths != null)
|
|
698
|
+
cmdArgs.push("--max-paths", String(opts.maxPaths));
|
|
699
|
+
if (opts.maxDepth != null)
|
|
700
|
+
cmdArgs.push("--max-depth", String(opts.maxDepth));
|
|
701
|
+
if (opts.viaKind)
|
|
702
|
+
cmdArgs.push("--via-kind", opts.viaKind);
|
|
703
|
+
if (opts.format)
|
|
704
|
+
cmdArgs.push("--format", opts.format);
|
|
705
|
+
return await this.exec(cmdArgs, 15000);
|
|
706
|
+
}
|
|
707
|
+
catch (err) {
|
|
708
|
+
console.error(`[token-pilot] ast-index module-route failed: ${err instanceof Error ? err.message : err}`);
|
|
709
|
+
return null;
|
|
710
|
+
}
|
|
711
|
+
}
|
|
682
712
|
async moduleDependents(module) {
|
|
683
713
|
if (this.indexDisabled || this.indexOversized)
|
|
684
714
|
return [];
|
|
@@ -145,6 +145,23 @@ export interface ModuleInfoArgs {
|
|
|
145
145
|
check?: "deps" | "dependents" | "api" | "unused-deps" | "all";
|
|
146
146
|
}
|
|
147
147
|
export declare function validateModuleInfoArgs(args: unknown): ModuleInfoArgs;
|
|
148
|
+
/**
|
|
149
|
+
* Validate module_route arguments.
|
|
150
|
+
*
|
|
151
|
+
* Wraps ast-index 3.44 `module-route` — the transitive dependency path
|
|
152
|
+
* between two modules. `from`/`to` are required; everything else mirrors
|
|
153
|
+
* the CLI flags with sane caps.
|
|
154
|
+
*/
|
|
155
|
+
export interface ModuleRouteArgs {
|
|
156
|
+
from: string;
|
|
157
|
+
to: string;
|
|
158
|
+
all?: boolean;
|
|
159
|
+
maxPaths?: number;
|
|
160
|
+
maxDepth?: number;
|
|
161
|
+
viaKind?: "api" | "implementation" | "all";
|
|
162
|
+
format?: "text" | "json" | "mermaid" | "dot";
|
|
163
|
+
}
|
|
164
|
+
export declare function validateModuleRouteArgs(args: unknown): ModuleRouteArgs;
|
|
148
165
|
/**
|
|
149
166
|
* Validate smart_diff arguments.
|
|
150
167
|
*/
|
package/dist/core/validation.js
CHANGED
|
@@ -428,6 +428,60 @@ export function validateModuleInfoArgs(args) {
|
|
|
428
428
|
check: check ?? "all",
|
|
429
429
|
};
|
|
430
430
|
}
|
|
431
|
+
export function validateModuleRouteArgs(args) {
|
|
432
|
+
if (!args || typeof args !== "object") {
|
|
433
|
+
throw new Error('Arguments must be an object with "from" and "to" parameters.');
|
|
434
|
+
}
|
|
435
|
+
const a = args;
|
|
436
|
+
if (typeof a.from !== "string" || a.from.length === 0) {
|
|
437
|
+
throw new Error('Required parameter "from" must be a non-empty string.');
|
|
438
|
+
}
|
|
439
|
+
if (typeof a.to !== "string" || a.to.length === 0) {
|
|
440
|
+
throw new Error('Required parameter "to" must be a non-empty string.');
|
|
441
|
+
}
|
|
442
|
+
let viaKind;
|
|
443
|
+
if (a.viaKind !== undefined && a.viaKind !== null) {
|
|
444
|
+
const valid = ["api", "implementation", "all"];
|
|
445
|
+
if (typeof a.viaKind !== "string" || !valid.includes(a.viaKind)) {
|
|
446
|
+
throw new Error(`"viaKind" must be one of: ${valid.join(", ")}`);
|
|
447
|
+
}
|
|
448
|
+
viaKind = a.viaKind;
|
|
449
|
+
}
|
|
450
|
+
let format;
|
|
451
|
+
if (a.format !== undefined && a.format !== null) {
|
|
452
|
+
const valid = ["text", "json", "mermaid", "dot"];
|
|
453
|
+
if (typeof a.format !== "string" || !valid.includes(a.format)) {
|
|
454
|
+
throw new Error(`"format" must be one of: ${valid.join(", ")}`);
|
|
455
|
+
}
|
|
456
|
+
format = a.format;
|
|
457
|
+
}
|
|
458
|
+
// Clamp numeric caps to safe ranges — never trust the caller blindly.
|
|
459
|
+
let maxPaths;
|
|
460
|
+
if (a.maxPaths !== undefined && a.maxPaths !== null) {
|
|
461
|
+
const n = Number(a.maxPaths);
|
|
462
|
+
if (!Number.isFinite(n) || n < 1) {
|
|
463
|
+
throw new Error('"maxPaths" must be a positive number.');
|
|
464
|
+
}
|
|
465
|
+
maxPaths = Math.min(Math.floor(n), 200);
|
|
466
|
+
}
|
|
467
|
+
let maxDepth;
|
|
468
|
+
if (a.maxDepth !== undefined && a.maxDepth !== null) {
|
|
469
|
+
const n = Number(a.maxDepth);
|
|
470
|
+
if (!Number.isFinite(n) || n < 1) {
|
|
471
|
+
throw new Error('"maxDepth" must be a positive number.');
|
|
472
|
+
}
|
|
473
|
+
maxDepth = Math.min(Math.floor(n), 50);
|
|
474
|
+
}
|
|
475
|
+
return {
|
|
476
|
+
from: a.from,
|
|
477
|
+
to: a.to,
|
|
478
|
+
all: a.all === true,
|
|
479
|
+
maxPaths,
|
|
480
|
+
maxDepth,
|
|
481
|
+
viaKind,
|
|
482
|
+
format,
|
|
483
|
+
};
|
|
484
|
+
}
|
|
431
485
|
export function validateSmartDiffArgs(args) {
|
|
432
486
|
if (!args || typeof args !== "object")
|
|
433
487
|
return { scope: "unstaged" };
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import type { AstIndexClient } from "../ast-index/client.js";
|
|
2
|
+
import type { ModuleRouteArgs } from "../core/validation.js";
|
|
3
|
+
/**
|
|
4
|
+
* module_route — transitive dependency path(s) between two modules.
|
|
5
|
+
*
|
|
6
|
+
* Thin wrapper over ast-index 3.44 `module-route`. The CLI already
|
|
7
|
+
* produces compact, purpose-built output (a path listing, or
|
|
8
|
+
* mermaid/dot/json for diagramming), so the handler only frames it and
|
|
9
|
+
* handles the empty / degraded cases — it does not re-parse the graph.
|
|
10
|
+
*/
|
|
11
|
+
export declare function handleModuleRoute(args: ModuleRouteArgs, _projectRoot: string, astIndex: AstIndexClient): Promise<{
|
|
12
|
+
content: Array<{
|
|
13
|
+
type: "text";
|
|
14
|
+
text: string;
|
|
15
|
+
}>;
|
|
16
|
+
meta: {
|
|
17
|
+
files: string[];
|
|
18
|
+
};
|
|
19
|
+
}>;
|
|
20
|
+
//# sourceMappingURL=module-route.d.ts.map
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* module_route — transitive dependency path(s) between two modules.
|
|
3
|
+
*
|
|
4
|
+
* Thin wrapper over ast-index 3.44 `module-route`. The CLI already
|
|
5
|
+
* produces compact, purpose-built output (a path listing, or
|
|
6
|
+
* mermaid/dot/json for diagramming), so the handler only frames it and
|
|
7
|
+
* handles the empty / degraded cases — it does not re-parse the graph.
|
|
8
|
+
*/
|
|
9
|
+
export async function handleModuleRoute(args, _projectRoot, astIndex) {
|
|
10
|
+
// Degradation check — same contract as module_info.
|
|
11
|
+
if (astIndex.isDisabled() || astIndex.isOversized()) {
|
|
12
|
+
return {
|
|
13
|
+
content: [
|
|
14
|
+
{
|
|
15
|
+
type: "text",
|
|
16
|
+
text: "⚠ ast-index unavailable — module_route requires ast-index.\n" +
|
|
17
|
+
"DEGRADED: Use module_info() on each module + related_files() to trace dependencies manually.",
|
|
18
|
+
},
|
|
19
|
+
],
|
|
20
|
+
meta: { files: [] },
|
|
21
|
+
};
|
|
22
|
+
}
|
|
23
|
+
const output = await astIndex.moduleRoute({
|
|
24
|
+
from: args.from,
|
|
25
|
+
to: args.to,
|
|
26
|
+
all: args.all,
|
|
27
|
+
maxPaths: args.maxPaths,
|
|
28
|
+
maxDepth: args.maxDepth,
|
|
29
|
+
viaKind: args.viaKind,
|
|
30
|
+
format: args.format,
|
|
31
|
+
});
|
|
32
|
+
const header = `MODULE ROUTE: ${args.from} → ${args.to}`;
|
|
33
|
+
if (output == null) {
|
|
34
|
+
return {
|
|
35
|
+
content: [
|
|
36
|
+
{
|
|
37
|
+
type: "text",
|
|
38
|
+
text: `${header}\n\n` +
|
|
39
|
+
"⚠ module-route failed (index unavailable or command error).\n" +
|
|
40
|
+
"HINT: run `npx token-pilot doctor` to check ast-index, or fall back to module_info().",
|
|
41
|
+
},
|
|
42
|
+
],
|
|
43
|
+
meta: { files: [] },
|
|
44
|
+
};
|
|
45
|
+
}
|
|
46
|
+
const body = output.trim();
|
|
47
|
+
if (body.length === 0) {
|
|
48
|
+
return {
|
|
49
|
+
content: [
|
|
50
|
+
{
|
|
51
|
+
type: "text",
|
|
52
|
+
text: `${header}\n\n` +
|
|
53
|
+
`No dependency path returned from "${args.from}" to "${args.to}" ` +
|
|
54
|
+
`(within ${args.maxDepth ?? 20} hops).\n` +
|
|
55
|
+
"This means one of:\n" +
|
|
56
|
+
" • the modules are genuinely unrelated, or\n" +
|
|
57
|
+
" • the module-dependency graph isn't indexed yet — run `ast-index rebuild`.\n" +
|
|
58
|
+
'HINT: also try a higher "maxDepth" / wider "viaKind", or module_info() to confirm each module resolves.',
|
|
59
|
+
},
|
|
60
|
+
],
|
|
61
|
+
meta: { files: [] },
|
|
62
|
+
};
|
|
63
|
+
}
|
|
64
|
+
// For machine formats (json/mermaid/dot) pass the payload through clean —
|
|
65
|
+
// a header would corrupt a diagram/parse. Text format gets the header.
|
|
66
|
+
const isMachineFormat = args.format === "json" || args.format === "mermaid" || args.format === "dot";
|
|
67
|
+
const text = isMachineFormat ? body : `${header}\n\n${body}`;
|
|
68
|
+
return {
|
|
69
|
+
content: [{ type: "text", text }],
|
|
70
|
+
meta: { files: [] },
|
|
71
|
+
};
|
|
72
|
+
}
|
|
73
|
+
//# sourceMappingURL=module-route.js.map
|
package/dist/index.js
CHANGED
|
@@ -1625,12 +1625,12 @@ Usage:
|
|
|
1625
1625
|
Quick start:
|
|
1626
1626
|
npx token-pilot init Setup .mcp.json (token-pilot + context-mode)
|
|
1627
1627
|
|
|
1628
|
-
MCP Tools (
|
|
1628
|
+
MCP Tools (23):
|
|
1629
1629
|
smart_read, read_symbol, read_symbols, read_range, read_section, read_diff,
|
|
1630
1630
|
read_for_edit, smart_read_many, find_usages, find_unused, related_files,
|
|
1631
1631
|
outline, project_overview, session_analytics, code_audit, module_info,
|
|
1632
|
-
smart_diff, explore_area, smart_log, test_summary,
|
|
1633
|
-
session_budget
|
|
1632
|
+
module_route, smart_diff, explore_area, smart_log, test_summary,
|
|
1633
|
+
session_snapshot, session_budget
|
|
1634
1634
|
`);
|
|
1635
1635
|
process.exit(0);
|
|
1636
1636
|
}
|
|
@@ -92,6 +92,13 @@ export declare const TOOL_DEFINITIONS: ({
|
|
|
92
92
|
check?: undefined;
|
|
93
93
|
pattern?: undefined;
|
|
94
94
|
name?: undefined;
|
|
95
|
+
from?: undefined;
|
|
96
|
+
to?: undefined;
|
|
97
|
+
all?: undefined;
|
|
98
|
+
maxPaths?: undefined;
|
|
99
|
+
maxDepth?: undefined;
|
|
100
|
+
viaKind?: undefined;
|
|
101
|
+
format?: undefined;
|
|
95
102
|
ref?: undefined;
|
|
96
103
|
count?: undefined;
|
|
97
104
|
command?: undefined;
|
|
@@ -176,6 +183,13 @@ export declare const TOOL_DEFINITIONS: ({
|
|
|
176
183
|
check?: undefined;
|
|
177
184
|
pattern?: undefined;
|
|
178
185
|
name?: undefined;
|
|
186
|
+
from?: undefined;
|
|
187
|
+
to?: undefined;
|
|
188
|
+
all?: undefined;
|
|
189
|
+
maxPaths?: undefined;
|
|
190
|
+
maxDepth?: undefined;
|
|
191
|
+
viaKind?: undefined;
|
|
192
|
+
format?: undefined;
|
|
179
193
|
ref?: undefined;
|
|
180
194
|
count?: undefined;
|
|
181
195
|
command?: undefined;
|
|
@@ -254,6 +268,13 @@ export declare const TOOL_DEFINITIONS: ({
|
|
|
254
268
|
check?: undefined;
|
|
255
269
|
pattern?: undefined;
|
|
256
270
|
name?: undefined;
|
|
271
|
+
from?: undefined;
|
|
272
|
+
to?: undefined;
|
|
273
|
+
all?: undefined;
|
|
274
|
+
maxPaths?: undefined;
|
|
275
|
+
maxDepth?: undefined;
|
|
276
|
+
viaKind?: undefined;
|
|
277
|
+
format?: undefined;
|
|
257
278
|
ref?: undefined;
|
|
258
279
|
count?: undefined;
|
|
259
280
|
command?: undefined;
|
|
@@ -328,6 +349,13 @@ export declare const TOOL_DEFINITIONS: ({
|
|
|
328
349
|
check?: undefined;
|
|
329
350
|
pattern?: undefined;
|
|
330
351
|
name?: undefined;
|
|
352
|
+
from?: undefined;
|
|
353
|
+
to?: undefined;
|
|
354
|
+
all?: undefined;
|
|
355
|
+
maxPaths?: undefined;
|
|
356
|
+
maxDepth?: undefined;
|
|
357
|
+
viaKind?: undefined;
|
|
358
|
+
format?: undefined;
|
|
331
359
|
ref?: undefined;
|
|
332
360
|
count?: undefined;
|
|
333
361
|
command?: undefined;
|
|
@@ -393,6 +421,13 @@ export declare const TOOL_DEFINITIONS: ({
|
|
|
393
421
|
check?: undefined;
|
|
394
422
|
pattern?: undefined;
|
|
395
423
|
name?: undefined;
|
|
424
|
+
from?: undefined;
|
|
425
|
+
to?: undefined;
|
|
426
|
+
all?: undefined;
|
|
427
|
+
maxPaths?: undefined;
|
|
428
|
+
maxDepth?: undefined;
|
|
429
|
+
viaKind?: undefined;
|
|
430
|
+
format?: undefined;
|
|
396
431
|
ref?: undefined;
|
|
397
432
|
count?: undefined;
|
|
398
433
|
command?: undefined;
|
|
@@ -458,6 +493,13 @@ export declare const TOOL_DEFINITIONS: ({
|
|
|
458
493
|
check?: undefined;
|
|
459
494
|
pattern?: undefined;
|
|
460
495
|
name?: undefined;
|
|
496
|
+
from?: undefined;
|
|
497
|
+
to?: undefined;
|
|
498
|
+
all?: undefined;
|
|
499
|
+
maxPaths?: undefined;
|
|
500
|
+
maxDepth?: undefined;
|
|
501
|
+
viaKind?: undefined;
|
|
502
|
+
format?: undefined;
|
|
461
503
|
ref?: undefined;
|
|
462
504
|
count?: undefined;
|
|
463
505
|
command?: undefined;
|
|
@@ -547,6 +589,13 @@ export declare const TOOL_DEFINITIONS: ({
|
|
|
547
589
|
check?: undefined;
|
|
548
590
|
pattern?: undefined;
|
|
549
591
|
name?: undefined;
|
|
592
|
+
from?: undefined;
|
|
593
|
+
to?: undefined;
|
|
594
|
+
all?: undefined;
|
|
595
|
+
maxPaths?: undefined;
|
|
596
|
+
maxDepth?: undefined;
|
|
597
|
+
viaKind?: undefined;
|
|
598
|
+
format?: undefined;
|
|
550
599
|
ref?: undefined;
|
|
551
600
|
count?: undefined;
|
|
552
601
|
command?: undefined;
|
|
@@ -621,6 +670,13 @@ export declare const TOOL_DEFINITIONS: ({
|
|
|
621
670
|
check?: undefined;
|
|
622
671
|
pattern?: undefined;
|
|
623
672
|
name?: undefined;
|
|
673
|
+
from?: undefined;
|
|
674
|
+
to?: undefined;
|
|
675
|
+
all?: undefined;
|
|
676
|
+
maxPaths?: undefined;
|
|
677
|
+
maxDepth?: undefined;
|
|
678
|
+
viaKind?: undefined;
|
|
679
|
+
format?: undefined;
|
|
624
680
|
ref?: undefined;
|
|
625
681
|
count?: undefined;
|
|
626
682
|
command?: undefined;
|
|
@@ -704,6 +760,13 @@ export declare const TOOL_DEFINITIONS: ({
|
|
|
704
760
|
check?: undefined;
|
|
705
761
|
pattern?: undefined;
|
|
706
762
|
name?: undefined;
|
|
763
|
+
from?: undefined;
|
|
764
|
+
to?: undefined;
|
|
765
|
+
all?: undefined;
|
|
766
|
+
maxPaths?: undefined;
|
|
767
|
+
maxDepth?: undefined;
|
|
768
|
+
viaKind?: undefined;
|
|
769
|
+
format?: undefined;
|
|
707
770
|
ref?: undefined;
|
|
708
771
|
count?: undefined;
|
|
709
772
|
command?: undefined;
|
|
@@ -770,6 +833,13 @@ export declare const TOOL_DEFINITIONS: ({
|
|
|
770
833
|
check?: undefined;
|
|
771
834
|
pattern?: undefined;
|
|
772
835
|
name?: undefined;
|
|
836
|
+
from?: undefined;
|
|
837
|
+
to?: undefined;
|
|
838
|
+
all?: undefined;
|
|
839
|
+
maxPaths?: undefined;
|
|
840
|
+
maxDepth?: undefined;
|
|
841
|
+
viaKind?: undefined;
|
|
842
|
+
format?: undefined;
|
|
773
843
|
ref?: undefined;
|
|
774
844
|
count?: undefined;
|
|
775
845
|
command?: undefined;
|
|
@@ -832,6 +902,13 @@ export declare const TOOL_DEFINITIONS: ({
|
|
|
832
902
|
check?: undefined;
|
|
833
903
|
pattern?: undefined;
|
|
834
904
|
name?: undefined;
|
|
905
|
+
from?: undefined;
|
|
906
|
+
to?: undefined;
|
|
907
|
+
all?: undefined;
|
|
908
|
+
maxPaths?: undefined;
|
|
909
|
+
maxDepth?: undefined;
|
|
910
|
+
viaKind?: undefined;
|
|
911
|
+
format?: undefined;
|
|
835
912
|
ref?: undefined;
|
|
836
913
|
count?: undefined;
|
|
837
914
|
command?: undefined;
|
|
@@ -900,6 +977,13 @@ export declare const TOOL_DEFINITIONS: ({
|
|
|
900
977
|
check?: undefined;
|
|
901
978
|
pattern?: undefined;
|
|
902
979
|
name?: undefined;
|
|
980
|
+
from?: undefined;
|
|
981
|
+
to?: undefined;
|
|
982
|
+
all?: undefined;
|
|
983
|
+
maxPaths?: undefined;
|
|
984
|
+
maxDepth?: undefined;
|
|
985
|
+
viaKind?: undefined;
|
|
986
|
+
format?: undefined;
|
|
903
987
|
ref?: undefined;
|
|
904
988
|
count?: undefined;
|
|
905
989
|
command?: undefined;
|
|
@@ -962,6 +1046,13 @@ export declare const TOOL_DEFINITIONS: ({
|
|
|
962
1046
|
check?: undefined;
|
|
963
1047
|
pattern?: undefined;
|
|
964
1048
|
name?: undefined;
|
|
1049
|
+
from?: undefined;
|
|
1050
|
+
to?: undefined;
|
|
1051
|
+
all?: undefined;
|
|
1052
|
+
maxPaths?: undefined;
|
|
1053
|
+
maxDepth?: undefined;
|
|
1054
|
+
viaKind?: undefined;
|
|
1055
|
+
format?: undefined;
|
|
965
1056
|
ref?: undefined;
|
|
966
1057
|
count?: undefined;
|
|
967
1058
|
command?: undefined;
|
|
@@ -1027,6 +1118,13 @@ export declare const TOOL_DEFINITIONS: ({
|
|
|
1027
1118
|
check?: undefined;
|
|
1028
1119
|
pattern?: undefined;
|
|
1029
1120
|
name?: undefined;
|
|
1121
|
+
from?: undefined;
|
|
1122
|
+
to?: undefined;
|
|
1123
|
+
all?: undefined;
|
|
1124
|
+
maxPaths?: undefined;
|
|
1125
|
+
maxDepth?: undefined;
|
|
1126
|
+
viaKind?: undefined;
|
|
1127
|
+
format?: undefined;
|
|
1030
1128
|
ref?: undefined;
|
|
1031
1129
|
count?: undefined;
|
|
1032
1130
|
command?: undefined;
|
|
@@ -1095,6 +1193,13 @@ export declare const TOOL_DEFINITIONS: ({
|
|
|
1095
1193
|
check?: undefined;
|
|
1096
1194
|
pattern?: undefined;
|
|
1097
1195
|
name?: undefined;
|
|
1196
|
+
from?: undefined;
|
|
1197
|
+
to?: undefined;
|
|
1198
|
+
all?: undefined;
|
|
1199
|
+
maxPaths?: undefined;
|
|
1200
|
+
maxDepth?: undefined;
|
|
1201
|
+
viaKind?: undefined;
|
|
1202
|
+
format?: undefined;
|
|
1098
1203
|
ref?: undefined;
|
|
1099
1204
|
count?: undefined;
|
|
1100
1205
|
command?: undefined;
|
|
@@ -1170,6 +1275,13 @@ export declare const TOOL_DEFINITIONS: ({
|
|
|
1170
1275
|
verbose?: undefined;
|
|
1171
1276
|
module?: undefined;
|
|
1172
1277
|
export_only?: undefined;
|
|
1278
|
+
from?: undefined;
|
|
1279
|
+
to?: undefined;
|
|
1280
|
+
all?: undefined;
|
|
1281
|
+
maxPaths?: undefined;
|
|
1282
|
+
maxDepth?: undefined;
|
|
1283
|
+
viaKind?: undefined;
|
|
1284
|
+
format?: undefined;
|
|
1173
1285
|
ref?: undefined;
|
|
1174
1286
|
count?: undefined;
|
|
1175
1287
|
command?: undefined;
|
|
@@ -1236,6 +1348,102 @@ export declare const TOOL_DEFINITIONS: ({
|
|
|
1236
1348
|
export_only?: undefined;
|
|
1237
1349
|
pattern?: undefined;
|
|
1238
1350
|
name?: undefined;
|
|
1351
|
+
from?: undefined;
|
|
1352
|
+
to?: undefined;
|
|
1353
|
+
all?: undefined;
|
|
1354
|
+
maxPaths?: undefined;
|
|
1355
|
+
maxDepth?: undefined;
|
|
1356
|
+
viaKind?: undefined;
|
|
1357
|
+
format?: undefined;
|
|
1358
|
+
ref?: undefined;
|
|
1359
|
+
count?: undefined;
|
|
1360
|
+
command?: undefined;
|
|
1361
|
+
runner?: undefined;
|
|
1362
|
+
timeout?: undefined;
|
|
1363
|
+
goal?: undefined;
|
|
1364
|
+
decisions?: undefined;
|
|
1365
|
+
confirmed?: undefined;
|
|
1366
|
+
files?: undefined;
|
|
1367
|
+
blocked?: undefined;
|
|
1368
|
+
next?: undefined;
|
|
1369
|
+
sessionId?: undefined;
|
|
1370
|
+
};
|
|
1371
|
+
required: string[];
|
|
1372
|
+
};
|
|
1373
|
+
} | {
|
|
1374
|
+
name: string;
|
|
1375
|
+
description: string;
|
|
1376
|
+
inputSchema: {
|
|
1377
|
+
type: "object";
|
|
1378
|
+
properties: {
|
|
1379
|
+
from: {
|
|
1380
|
+
type: string;
|
|
1381
|
+
description: string;
|
|
1382
|
+
};
|
|
1383
|
+
to: {
|
|
1384
|
+
type: string;
|
|
1385
|
+
description: string;
|
|
1386
|
+
};
|
|
1387
|
+
all: {
|
|
1388
|
+
type: string;
|
|
1389
|
+
description: string;
|
|
1390
|
+
};
|
|
1391
|
+
maxPaths: {
|
|
1392
|
+
type: string;
|
|
1393
|
+
description: string;
|
|
1394
|
+
};
|
|
1395
|
+
maxDepth: {
|
|
1396
|
+
type: string;
|
|
1397
|
+
description: string;
|
|
1398
|
+
};
|
|
1399
|
+
viaKind: {
|
|
1400
|
+
type: string;
|
|
1401
|
+
enum: string[];
|
|
1402
|
+
description: string;
|
|
1403
|
+
};
|
|
1404
|
+
format: {
|
|
1405
|
+
type: string;
|
|
1406
|
+
enum: string[];
|
|
1407
|
+
description: string;
|
|
1408
|
+
};
|
|
1409
|
+
path?: undefined;
|
|
1410
|
+
show_imports?: undefined;
|
|
1411
|
+
show_docs?: undefined;
|
|
1412
|
+
depth?: undefined;
|
|
1413
|
+
scope?: undefined;
|
|
1414
|
+
max_tokens?: undefined;
|
|
1415
|
+
session_id?: undefined;
|
|
1416
|
+
force?: undefined;
|
|
1417
|
+
symbol?: undefined;
|
|
1418
|
+
context_before?: undefined;
|
|
1419
|
+
context_after?: undefined;
|
|
1420
|
+
show?: undefined;
|
|
1421
|
+
include_edit_context?: undefined;
|
|
1422
|
+
symbols?: undefined;
|
|
1423
|
+
start_line?: undefined;
|
|
1424
|
+
end_line?: undefined;
|
|
1425
|
+
heading?: undefined;
|
|
1426
|
+
context_lines?: undefined;
|
|
1427
|
+
line?: undefined;
|
|
1428
|
+
context?: undefined;
|
|
1429
|
+
include_callers?: undefined;
|
|
1430
|
+
include_tests?: undefined;
|
|
1431
|
+
include_changes?: undefined;
|
|
1432
|
+
section?: undefined;
|
|
1433
|
+
paths?: undefined;
|
|
1434
|
+
kind?: undefined;
|
|
1435
|
+
limit?: undefined;
|
|
1436
|
+
lang?: undefined;
|
|
1437
|
+
mode?: undefined;
|
|
1438
|
+
include?: undefined;
|
|
1439
|
+
recursive?: undefined;
|
|
1440
|
+
max_depth?: undefined;
|
|
1441
|
+
verbose?: undefined;
|
|
1442
|
+
module?: undefined;
|
|
1443
|
+
export_only?: undefined;
|
|
1444
|
+
check?: undefined;
|
|
1445
|
+
pattern?: undefined;
|
|
1446
|
+
name?: undefined;
|
|
1239
1447
|
ref?: undefined;
|
|
1240
1448
|
count?: undefined;
|
|
1241
1449
|
command?: undefined;
|
|
@@ -1306,6 +1514,13 @@ export declare const TOOL_DEFINITIONS: ({
|
|
|
1306
1514
|
check?: undefined;
|
|
1307
1515
|
pattern?: undefined;
|
|
1308
1516
|
name?: undefined;
|
|
1517
|
+
from?: undefined;
|
|
1518
|
+
to?: undefined;
|
|
1519
|
+
all?: undefined;
|
|
1520
|
+
maxPaths?: undefined;
|
|
1521
|
+
maxDepth?: undefined;
|
|
1522
|
+
viaKind?: undefined;
|
|
1523
|
+
format?: undefined;
|
|
1309
1524
|
count?: undefined;
|
|
1310
1525
|
command?: undefined;
|
|
1311
1526
|
runner?: undefined;
|
|
@@ -1374,6 +1589,13 @@ export declare const TOOL_DEFINITIONS: ({
|
|
|
1374
1589
|
check?: undefined;
|
|
1375
1590
|
pattern?: undefined;
|
|
1376
1591
|
name?: undefined;
|
|
1592
|
+
from?: undefined;
|
|
1593
|
+
to?: undefined;
|
|
1594
|
+
all?: undefined;
|
|
1595
|
+
maxPaths?: undefined;
|
|
1596
|
+
maxDepth?: undefined;
|
|
1597
|
+
viaKind?: undefined;
|
|
1598
|
+
format?: undefined;
|
|
1377
1599
|
ref?: undefined;
|
|
1378
1600
|
count?: undefined;
|
|
1379
1601
|
command?: undefined;
|
|
@@ -1444,6 +1666,13 @@ export declare const TOOL_DEFINITIONS: ({
|
|
|
1444
1666
|
check?: undefined;
|
|
1445
1667
|
pattern?: undefined;
|
|
1446
1668
|
name?: undefined;
|
|
1669
|
+
from?: undefined;
|
|
1670
|
+
to?: undefined;
|
|
1671
|
+
all?: undefined;
|
|
1672
|
+
maxPaths?: undefined;
|
|
1673
|
+
maxDepth?: undefined;
|
|
1674
|
+
viaKind?: undefined;
|
|
1675
|
+
format?: undefined;
|
|
1447
1676
|
command?: undefined;
|
|
1448
1677
|
runner?: undefined;
|
|
1449
1678
|
timeout?: undefined;
|
|
@@ -1514,6 +1743,13 @@ export declare const TOOL_DEFINITIONS: ({
|
|
|
1514
1743
|
check?: undefined;
|
|
1515
1744
|
pattern?: undefined;
|
|
1516
1745
|
name?: undefined;
|
|
1746
|
+
from?: undefined;
|
|
1747
|
+
to?: undefined;
|
|
1748
|
+
all?: undefined;
|
|
1749
|
+
maxPaths?: undefined;
|
|
1750
|
+
maxDepth?: undefined;
|
|
1751
|
+
viaKind?: undefined;
|
|
1752
|
+
format?: undefined;
|
|
1517
1753
|
ref?: undefined;
|
|
1518
1754
|
count?: undefined;
|
|
1519
1755
|
goal?: undefined;
|
|
@@ -1603,6 +1839,13 @@ export declare const TOOL_DEFINITIONS: ({
|
|
|
1603
1839
|
check?: undefined;
|
|
1604
1840
|
pattern?: undefined;
|
|
1605
1841
|
name?: undefined;
|
|
1842
|
+
from?: undefined;
|
|
1843
|
+
to?: undefined;
|
|
1844
|
+
all?: undefined;
|
|
1845
|
+
maxPaths?: undefined;
|
|
1846
|
+
maxDepth?: undefined;
|
|
1847
|
+
viaKind?: undefined;
|
|
1848
|
+
format?: undefined;
|
|
1606
1849
|
ref?: undefined;
|
|
1607
1850
|
count?: undefined;
|
|
1608
1851
|
command?: undefined;
|
|
@@ -1660,6 +1903,13 @@ export declare const TOOL_DEFINITIONS: ({
|
|
|
1660
1903
|
check?: undefined;
|
|
1661
1904
|
pattern?: undefined;
|
|
1662
1905
|
name?: undefined;
|
|
1906
|
+
from?: undefined;
|
|
1907
|
+
to?: undefined;
|
|
1908
|
+
all?: undefined;
|
|
1909
|
+
maxPaths?: undefined;
|
|
1910
|
+
maxDepth?: undefined;
|
|
1911
|
+
viaKind?: undefined;
|
|
1912
|
+
format?: undefined;
|
|
1663
1913
|
ref?: undefined;
|
|
1664
1914
|
count?: undefined;
|
|
1665
1915
|
command?: undefined;
|
|
@@ -585,6 +585,46 @@ export const TOOL_DEFINITIONS = [
|
|
|
585
585
|
required: ["module"],
|
|
586
586
|
},
|
|
587
587
|
},
|
|
588
|
+
{
|
|
589
|
+
name: "module_route",
|
|
590
|
+
description: "Show the transitive dependency path(s) between two modules — how module A reaches module B through the import graph. Use to answer 'how does X depend on Y?', trace coupling, or generate a dependency diagram. format='mermaid'/'dot' emits a diagram; default text lists the hops.",
|
|
591
|
+
inputSchema: {
|
|
592
|
+
type: "object",
|
|
593
|
+
properties: {
|
|
594
|
+
from: {
|
|
595
|
+
type: "string",
|
|
596
|
+
description: 'Source module — the one whose dependencies are followed (name or path, e.g. "auth", "apps/api")',
|
|
597
|
+
},
|
|
598
|
+
to: {
|
|
599
|
+
type: "string",
|
|
600
|
+
description: "Target module to reach",
|
|
601
|
+
},
|
|
602
|
+
all: {
|
|
603
|
+
type: "boolean",
|
|
604
|
+
description: "Show all simple paths instead of just the shortest (default: false)",
|
|
605
|
+
},
|
|
606
|
+
maxPaths: {
|
|
607
|
+
type: "number",
|
|
608
|
+
description: "Cap on number of paths returned (default: 50, max: 200)",
|
|
609
|
+
},
|
|
610
|
+
maxDepth: {
|
|
611
|
+
type: "number",
|
|
612
|
+
description: "Cap on path length in hops (default: 20, max: 50)",
|
|
613
|
+
},
|
|
614
|
+
viaKind: {
|
|
615
|
+
type: "string",
|
|
616
|
+
enum: ["api", "implementation", "all"],
|
|
617
|
+
description: 'Restrict traversal to a dependency kind (default: "all")',
|
|
618
|
+
},
|
|
619
|
+
format: {
|
|
620
|
+
type: "string",
|
|
621
|
+
enum: ["text", "json", "mermaid", "dot"],
|
|
622
|
+
description: 'Output format: "text" (default, hop listing), "json", "mermaid" or "dot" (dependency diagram)',
|
|
623
|
+
},
|
|
624
|
+
},
|
|
625
|
+
required: ["from", "to"],
|
|
626
|
+
},
|
|
627
|
+
},
|
|
588
628
|
// --- Diff & exploration ---
|
|
589
629
|
{
|
|
590
630
|
name: "smart_diff",
|
package/dist/server.js
CHANGED
|
@@ -34,6 +34,7 @@ import { handleRelatedFiles } from "./handlers/related-files.js";
|
|
|
34
34
|
import { handleOutline } from "./handlers/outline.js";
|
|
35
35
|
import { handleCodeAudit } from "./handlers/code-audit.js";
|
|
36
36
|
import { handleModuleInfo } from "./handlers/module-info.js";
|
|
37
|
+
import { handleModuleRoute } from "./handlers/module-route.js";
|
|
37
38
|
import { handleSmartDiff } from "./handlers/smart-diff.js";
|
|
38
39
|
import { handleExploreArea } from "./handlers/explore-area.js";
|
|
39
40
|
import { handleSmartLog } from "./handlers/smart-log.js";
|
|
@@ -50,9 +51,17 @@ import { getMcpInstructions, TOOL_DEFINITIONS, } from "./server/tool-definitions
|
|
|
50
51
|
import { filterToolsByProfile, parseProfileEnv, } from "./server/tool-profiles.js";
|
|
51
52
|
import { STRICT_SMART_READ_MAX_TOKENS, STRICT_EXPLORE_AREA_INCLUDE, } from "./server/enforcement-mode.js";
|
|
52
53
|
import { createTokenEstimates } from "./server/token-estimates.js";
|
|
53
|
-
import { validateSmartReadArgs, validateReadSymbolArgs, validateReadSymbolsArgs, validateReadRangeArgs, validateReadDiffArgs, validateFindUsagesArgs, validateSmartReadManyArgs, validateReadForEditArgs, validateRelatedFilesArgs, validateOutlineArgs, validateFindUnusedArgs, validateCallTreeArgs, validateCodeAuditArgs, validateProjectOverviewArgs, validateModuleInfoArgs, validateSmartDiffArgs, validateExploreAreaArgs, validateSmartLogArgs, validateTestSummaryArgs, validateReadSectionArgs, } from "./core/validation.js";
|
|
54
|
+
import { validateSmartReadArgs, validateReadSymbolArgs, validateReadSymbolsArgs, validateReadRangeArgs, validateReadDiffArgs, validateFindUsagesArgs, validateSmartReadManyArgs, validateReadForEditArgs, validateRelatedFilesArgs, validateOutlineArgs, validateFindUnusedArgs, validateCallTreeArgs, validateCodeAuditArgs, validateProjectOverviewArgs, validateModuleInfoArgs, validateModuleRouteArgs, validateSmartDiffArgs, validateExploreAreaArgs, validateSmartLogArgs, validateTestSummaryArgs, validateReadSectionArgs, } from "./core/validation.js";
|
|
54
55
|
export async function createServer(projectRoot, options) {
|
|
55
56
|
const mode = options?.enforcementMode ?? "deny";
|
|
57
|
+
// v0.43.0 — the real Claude Code session id. CC exports it to every
|
|
58
|
+
// child process (MCP server, hooks, Bash) via CLAUDE_CODE_SESSION_ID —
|
|
59
|
+
// verified against the 2.1.167 bundle, and it is the exact same value
|
|
60
|
+
// the PreToolUse hooks receive and the statusline payload carries.
|
|
61
|
+
// Stamping it on each tool-call row lets the statusline badge attribute
|
|
62
|
+
// MCP-tool savings to the current session; before this the rows carried
|
|
63
|
+
// an empty session_id and the badge ignored them, undercounting savings.
|
|
64
|
+
const ccSessionId = process.env.CLAUDE_CODE_SESSION_ID ?? "";
|
|
56
65
|
const config = await loadConfig(projectRoot);
|
|
57
66
|
const astIndex = new AstIndexClient(projectRoot, config.astIndex.timeout, {
|
|
58
67
|
binaryPath: config.astIndex.binaryPath,
|
|
@@ -323,7 +332,7 @@ export async function createServer(projectRoot, options) {
|
|
|
323
332
|
// future prune/fix decision.
|
|
324
333
|
void appendToolCall(projectRoot, {
|
|
325
334
|
ts: rest.timestamp,
|
|
326
|
-
session_id: call.sessionId ??
|
|
335
|
+
session_id: call.sessionId ?? ccSessionId,
|
|
327
336
|
tool: rest.tool,
|
|
328
337
|
path: rest.path,
|
|
329
338
|
tokensReturned: rest.tokensReturned,
|
|
@@ -857,6 +866,37 @@ export async function createServer(projectRoot, options) {
|
|
|
857
866
|
});
|
|
858
867
|
return moduleResult;
|
|
859
868
|
}
|
|
869
|
+
case "module_route": {
|
|
870
|
+
const routeArgs = validateModuleRouteArgs(args);
|
|
871
|
+
const cachedRoute = sessionCache?.get("module_route", routeArgs);
|
|
872
|
+
if (cachedRoute) {
|
|
873
|
+
recordWithTrace({
|
|
874
|
+
tool: "module_route",
|
|
875
|
+
path: `${routeArgs.from}→${routeArgs.to}`,
|
|
876
|
+
tokensReturned: cachedRoute.tokenEstimate,
|
|
877
|
+
tokensWouldBe: cachedRoute.tokensWouldBe ?? cachedRoute.tokenEstimate,
|
|
878
|
+
timestamp: Date.now(),
|
|
879
|
+
sessionCacheHit: true,
|
|
880
|
+
savingsCategory: "cache",
|
|
881
|
+
args: routeArgs,
|
|
882
|
+
});
|
|
883
|
+
return cachedRoute.result;
|
|
884
|
+
}
|
|
885
|
+
const routeResult = await handleModuleRoute(routeArgs, projectRoot, astIndex);
|
|
886
|
+
const routeText = routeResult.content[0]?.text ?? "";
|
|
887
|
+
const routeTokens = estimateTokens(routeText);
|
|
888
|
+
sessionCache?.set("module_route", routeArgs, routeResult, { dependsOnAst: true }, routeTokens, routeTokens);
|
|
889
|
+
recordWithTrace({
|
|
890
|
+
tool: "module_route",
|
|
891
|
+
path: `${routeArgs.from}→${routeArgs.to}`,
|
|
892
|
+
tokensReturned: routeTokens,
|
|
893
|
+
tokensWouldBe: routeTokens,
|
|
894
|
+
timestamp: Date.now(),
|
|
895
|
+
savingsCategory: "compression",
|
|
896
|
+
args: routeArgs,
|
|
897
|
+
});
|
|
898
|
+
return routeResult;
|
|
899
|
+
}
|
|
860
900
|
case "smart_diff": {
|
|
861
901
|
const sdArgs = validateSmartDiffArgs(args);
|
|
862
902
|
const sdResult = await handleSmartDiff(sdArgs, projectRoot, astIndex);
|
package/docs/tools.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# MCP Tools Reference
|
|
2
2
|
|
|
3
|
-
Token Pilot exposes
|
|
3
|
+
Token Pilot exposes 23 MCP tools. All handlers remain active regardless of [tool profile](configuration.md#tool-profiles) — the profile only trims what appears in `tools/list` at session start.
|
|
4
4
|
|
|
5
5
|
## Reading
|
|
6
6
|
|
|
@@ -26,6 +26,7 @@ Token Pilot exposes 22 MCP tools. All handlers remain active regardless of [tool
|
|
|
26
26
|
| `find_unused` | manual | Dead code detection — unreferenced exported symbols |
|
|
27
27
|
| `code_audit` | multiple `Grep` | TODOs, deprecated symbols, structural patterns |
|
|
28
28
|
| `module_info` | manual | Deps, dependents, public API, unused deps |
|
|
29
|
+
| `module_route` | manual | Transitive dependency path(s) between two modules; `format=mermaid`/`dot` emits a diagram |
|
|
29
30
|
| `smart_diff` | raw `git diff` | Structural diff with symbol mapping |
|
|
30
31
|
| `explore_area` | 3–5 calls | Structure + imports + tests + recent changes in one call |
|
|
31
32
|
| `smart_log` | raw `git log` | Structured commits with category detection |
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "token-pilot",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.43.0",
|
|
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",
|
package/skills/guide/SKILL.md
CHANGED
|
@@ -3,6 +3,10 @@ name: guide
|
|
|
3
3
|
description: Show a quick-reference guide for all Token Pilot tools — when to use each one
|
|
4
4
|
command: guide
|
|
5
5
|
user_invocable: true
|
|
6
|
+
# v0.43.0 — effort (Claude Code 2.1.16x) overrides model effort while
|
|
7
|
+
# this skill runs. The guide just renders a static Markdown reference —
|
|
8
|
+
# it needs no reasoning, so `low` keeps it fast and cheap.
|
|
9
|
+
effort: low
|
|
6
10
|
# v0.36.0 — disallowed-tools is a Claude Code 2.1.152+ field that
|
|
7
11
|
# strips the listed tools from the model's surface while this skill
|
|
8
12
|
# is active. The guide just renders Markdown; it never needs Edit /
|
package/skills/install/SKILL.md
CHANGED
|
@@ -3,6 +3,10 @@ name: install
|
|
|
3
3
|
description: Install or check ast-index binary (auto-downloads if missing)
|
|
4
4
|
command: install
|
|
5
5
|
user_invocable: true
|
|
6
|
+
# v0.43.0 — effort (Claude Code 2.1.16x). install drives one
|
|
7
|
+
# `npx token-pilot install-ast-index` Bash call; no reasoning needed,
|
|
8
|
+
# so `low` keeps it fast and cheap.
|
|
9
|
+
effort: low
|
|
6
10
|
# v0.36.0 — disallowed-tools (Claude Code 2.1.152+). The install
|
|
7
11
|
# skill drives one `npx token-pilot install-ast-index` Bash command;
|
|
8
12
|
# nothing else. Keep Bash, block all write/edit/delegation tools so
|
package/skills/stats/SKILL.md
CHANGED
|
@@ -3,6 +3,9 @@ name: stats
|
|
|
3
3
|
description: Show Token Pilot session analytics — token savings, per-tool breakdown, top files, per-agent grouping
|
|
4
4
|
command: stats
|
|
5
5
|
user_invocable: true
|
|
6
|
+
# v0.43.0 — effort (Claude Code 2.1.16x). stats reads the events log and
|
|
7
|
+
# runs `token-pilot stats` variants — no reasoning, so `low` is enough.
|
|
8
|
+
effort: low
|
|
6
9
|
# v0.36.0 — disallowed-tools (Claude Code 2.1.152+). stats only reads
|
|
7
10
|
# the events log and runs `token-pilot stats` variants. No
|
|
8
11
|
# Edit/Write/Task ever — block them defensively.
|