token-pilot 0.24.1 → 0.26.5

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.
Files changed (47) hide show
  1. package/.claude-plugin/marketplace.json +29 -12
  2. package/.claude-plugin/plugin.json +23 -5
  3. package/CHANGELOG.md +182 -0
  4. package/README.md +128 -15
  5. package/dist/agents/tp-api-surface-tracker.md +4 -3
  6. package/dist/agents/tp-audit-scanner.md +1 -1
  7. package/dist/agents/tp-commit-writer.md +1 -1
  8. package/dist/agents/tp-dead-code-finder.md +22 -7
  9. package/dist/agents/tp-debugger.md +1 -1
  10. package/dist/agents/tp-dep-health.md +3 -2
  11. package/dist/agents/tp-history-explorer.md +1 -1
  12. package/dist/agents/tp-impact-analyzer.md +1 -1
  13. package/dist/agents/tp-incident-timeline.md +1 -1
  14. package/dist/agents/tp-migration-scout.md +1 -1
  15. package/dist/agents/tp-onboard.md +1 -1
  16. package/dist/agents/tp-pr-reviewer.md +1 -1
  17. package/dist/agents/tp-refactor-planner.md +1 -1
  18. package/dist/agents/tp-review-impact.md +1 -1
  19. package/dist/agents/tp-run.md +1 -1
  20. package/dist/agents/tp-session-restorer.md +1 -1
  21. package/dist/agents/tp-test-coverage-gapper.md +1 -1
  22. package/dist/agents/tp-test-triage.md +1 -1
  23. package/dist/agents/tp-test-writer.md +1 -1
  24. package/dist/cli/detect-client.d.ts +39 -0
  25. package/dist/cli/detect-client.js +106 -0
  26. package/dist/cli/install-agents.d.ts +1 -0
  27. package/dist/cli/install-agents.js +31 -1
  28. package/dist/cli/tool-audit.d.ts +58 -0
  29. package/dist/cli/tool-audit.js +123 -0
  30. package/dist/cli/typo-guard.d.ts +1 -1
  31. package/dist/cli/typo-guard.js +1 -0
  32. package/dist/core/tool-call-log.d.ts +63 -0
  33. package/dist/core/tool-call-log.js +171 -0
  34. package/dist/handlers/read-symbols.js +23 -1
  35. package/dist/hooks/installer.js +27 -12
  36. package/dist/index.js +55 -0
  37. package/dist/server/profile-recommender.d.ts +48 -0
  38. package/dist/server/profile-recommender.js +102 -0
  39. package/dist/server/token-estimates.d.ts +17 -3
  40. package/dist/server/token-estimates.js +77 -45
  41. package/dist/server/tool-definitions.js +1 -1
  42. package/dist/server/tool-profiles.d.ts +46 -0
  43. package/dist/server/tool-profiles.js +81 -0
  44. package/dist/server.js +38 -1
  45. package/package.json +1 -1
  46. package/start.sh +0 -0
  47. package/.mcp.json +0 -8
@@ -10,7 +10,7 @@ tools:
10
10
  - mcp__token-pilot__smart_read_many
11
11
  - mcp__token-pilot__read_for_edit
12
12
  - Read
13
- token_pilot_version: "0.24.1"
13
+ token_pilot_version: "0.26.5"
14
14
  token_pilot_body_hash: eb9fb7f87d9ab61c5b18248a40b283008b5d73414ddb2e3094ff0826e7e463d0
15
15
  ---
16
16
 
@@ -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.24.1"
10
+ token_pilot_version: "0.26.5"
11
11
  token_pilot_body_hash: a058518619fd6e2def0c9226f6c70438a5e0a80efe680c935414ecd7e1b14a4f
12
12
  ---
13
13
 
@@ -8,7 +8,7 @@ tools:
8
8
  - mcp__token-pilot__outline
9
9
  - mcp__token-pilot__module_info
10
10
  - Bash
11
- token_pilot_version: "0.24.1"
11
+ token_pilot_version: "0.26.5"
12
12
  token_pilot_body_hash: 72b635f511492188587d6cb6fd70f936ae34cf5df1f9cd9eff7849cf1231e185
13
13
  ---
14
14
 
@@ -15,7 +15,7 @@ tools:
15
15
  - Grep
16
16
  - Glob
17
17
  - Bash
18
- token_pilot_version: "0.24.1"
18
+ token_pilot_version: "0.26.5"
19
19
  token_pilot_body_hash: d665d57085db38077d0eeab74bda8bdb84c9ad59688495486059af5d3fac67cf
20
20
  ---
21
21
 
@@ -9,7 +9,7 @@ tools:
9
9
  - mcp__token-pilot__session_budget
10
10
  - Bash
11
11
  - Read
12
- token_pilot_version: "0.24.1"
12
+ token_pilot_version: "0.26.5"
13
13
  token_pilot_body_hash: 35b7f333a28c94e7dc89fcc3171703c4b466225f55cd5c701b7592f4f6486440
14
14
  ---
15
15
 
@@ -10,7 +10,7 @@ tools:
10
10
  - mcp__token-pilot__test_summary
11
11
  - Glob
12
12
  - Grep
13
- token_pilot_version: "0.24.1"
13
+ token_pilot_version: "0.26.5"
14
14
  token_pilot_body_hash: cc3d1f46fdb95ac3caf9344f69f1ddcd5ce5a175ee70aa150b7f9fda93edb152
15
15
  ---
16
16
 
@@ -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.24.1"
10
+ token_pilot_version: "0.26.5"
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.24.1"
15
+ token_pilot_version: "0.26.5"
16
16
  token_pilot_body_hash: 533b3d2387e631a24291314b2b8ad8c3e01c19e0b9ec1d3fe08ae0011f0c73f9
17
17
  ---
18
18
 
@@ -0,0 +1,39 @@
1
+ /**
2
+ * v0.26.0 — AI-client detection for install-agents.
3
+ *
4
+ * `tp-*` subagents are a Claude Code concept: `.md` files in
5
+ * `~/.claude/agents/` with `tools:` frontmatter, invoked via the `Task`
6
+ * tool. Other clients (Cursor, Codex CLI, Gemini CLI, Cline) read MCP
7
+ * tool descriptions directly and have no subagent surface — they still
8
+ * get our MCP tools + Read hook, but the 19 tp-* delegates sit idle.
9
+ *
10
+ * This detector tries to recognise the active client from env vars and
11
+ * on-disk config directories, so `install-agents` can warn non-Claude
12
+ * users before silently creating a dir nothing will read.
13
+ *
14
+ * Note: detection is best-effort. It returns the *most likely* client or
15
+ * "unknown" — never throws, never asks the user. A false "claude-code"
16
+ * result only costs one unused directory; a false "cursor" would print a
17
+ * misleading warning. We err on the side of "claude-code" when in doubt.
18
+ */
19
+ export type DetectedClient = "claude-code" | "cursor" | "codex" | "gemini" | "cline" | "unknown";
20
+ export interface DetectionResult {
21
+ client: DetectedClient;
22
+ source: string;
23
+ subagentsSupported: boolean;
24
+ }
25
+ /**
26
+ * Identify which AI client is likely running token-pilot, by inspecting
27
+ * env vars first (cheapest) then filesystem markers.
28
+ *
29
+ * @param homeDir user's home directory (injected for tests)
30
+ * @param projectRoot current project root (injected for tests)
31
+ * @param env process.env (injected for tests)
32
+ */
33
+ export declare function detectClient(homeDir: string, projectRoot: string, env?: NodeJS.ProcessEnv): Promise<DetectionResult>;
34
+ /**
35
+ * Compose a human-readable warning for `install-agents` to print when
36
+ * the detected client doesn't support subagents. Null when it does.
37
+ */
38
+ export declare function nonClaudeClientWarning(detection: DetectionResult): string | null;
39
+ //# sourceMappingURL=detect-client.d.ts.map
@@ -0,0 +1,106 @@
1
+ /**
2
+ * v0.26.0 — AI-client detection for install-agents.
3
+ *
4
+ * `tp-*` subagents are a Claude Code concept: `.md` files in
5
+ * `~/.claude/agents/` with `tools:` frontmatter, invoked via the `Task`
6
+ * tool. Other clients (Cursor, Codex CLI, Gemini CLI, Cline) read MCP
7
+ * tool descriptions directly and have no subagent surface — they still
8
+ * get our MCP tools + Read hook, but the 19 tp-* delegates sit idle.
9
+ *
10
+ * This detector tries to recognise the active client from env vars and
11
+ * on-disk config directories, so `install-agents` can warn non-Claude
12
+ * users before silently creating a dir nothing will read.
13
+ *
14
+ * Note: detection is best-effort. It returns the *most likely* client or
15
+ * "unknown" — never throws, never asks the user. A false "claude-code"
16
+ * result only costs one unused directory; a false "cursor" would print a
17
+ * misleading warning. We err on the side of "claude-code" when in doubt.
18
+ */
19
+ import { promises as fs } from "node:fs";
20
+ import { join } from "node:path";
21
+ /**
22
+ * Identify which AI client is likely running token-pilot, by inspecting
23
+ * env vars first (cheapest) then filesystem markers.
24
+ *
25
+ * @param homeDir user's home directory (injected for tests)
26
+ * @param projectRoot current project root (injected for tests)
27
+ * @param env process.env (injected for tests)
28
+ */
29
+ export async function detectClient(homeDir, projectRoot, env = process.env) {
30
+ // 1. Env-var signals — fastest, most reliable when set.
31
+ if (env.CLAUDE_PLUGIN_ROOT) {
32
+ return {
33
+ client: "claude-code",
34
+ source: "CLAUDE_PLUGIN_ROOT env",
35
+ subagentsSupported: true,
36
+ };
37
+ }
38
+ if (env.CURSOR_TRACE_ID || env.CURSOR_SESSION_ID) {
39
+ return {
40
+ client: "cursor",
41
+ source: "CURSOR_* env",
42
+ subagentsSupported: false,
43
+ };
44
+ }
45
+ if (env.GEMINI_CLI === "1" || env.GOOGLE_CLOUD_CODE === "1") {
46
+ return {
47
+ client: "gemini",
48
+ source: "GEMINI_* env",
49
+ subagentsSupported: false,
50
+ };
51
+ }
52
+ if (env.OPENAI_CODEX === "1" || env.CODEX_MODE) {
53
+ return {
54
+ client: "codex",
55
+ source: "CODEX_* env",
56
+ subagentsSupported: false,
57
+ };
58
+ }
59
+ // 2. Filesystem signals. Order matters — check the ones with the
60
+ // strongest on-disk footprint first.
61
+ const markers = [
62
+ [
63
+ join(homeDir, ".claude", "agents"),
64
+ "~/.claude/agents/",
65
+ "claude-code",
66
+ true,
67
+ ],
68
+ [join(homeDir, ".claude"), "~/.claude/", "claude-code", true],
69
+ [join(projectRoot, ".cursor"), ".cursor/", "cursor", false],
70
+ [join(homeDir, ".cursor"), "~/.cursor/", "cursor", false],
71
+ [join(homeDir, ".codex"), "~/.codex/", "codex", false],
72
+ [join(homeDir, ".gemini"), "~/.gemini/", "gemini", false],
73
+ [join(projectRoot, ".gemini"), ".gemini/", "gemini", false],
74
+ ];
75
+ for (const [path, source, client, subagentsSupported] of markers) {
76
+ try {
77
+ await fs.access(path);
78
+ return { client, source, subagentsSupported };
79
+ }
80
+ catch {
81
+ /* try next */
82
+ }
83
+ }
84
+ // 3. Nothing recognised — assume Claude Code (safest default: the user
85
+ // explicitly ran `install-agents`, so they likely have Claude Code
86
+ // but haven't used it yet, or ran via CI where env vars are sparse).
87
+ return {
88
+ client: "unknown",
89
+ source: "no markers found",
90
+ subagentsSupported: true,
91
+ };
92
+ }
93
+ /**
94
+ * Compose a human-readable warning for `install-agents` to print when
95
+ * the detected client doesn't support subagents. Null when it does.
96
+ */
97
+ export function nonClaudeClientWarning(detection) {
98
+ if (detection.subagentsSupported)
99
+ return null;
100
+ return (`[token-pilot] Detected ${detection.client} (${detection.source}).\n` +
101
+ `[token-pilot] tp-* subagents are a Claude Code concept and will NOT be\n` +
102
+ `[token-pilot] auto-invoked in ${detection.client}. Your MCP tools and Read hook\n` +
103
+ `[token-pilot] still work fully. If you meant to install for Claude Code (multiple\n` +
104
+ `[token-pilot] AI clients coexist), pass --scope=user explicitly and re-run.`);
105
+ }
106
+ //# sourceMappingURL=detect-client.js.map
@@ -84,6 +84,7 @@ export declare function handleInstallAgents(argv: string[], opts?: {
84
84
  homeDir?: string;
85
85
  projectRoot?: string;
86
86
  isTTY?: boolean;
87
+ env?: NodeJS.ProcessEnv;
87
88
  }): Promise<number>;
88
89
  export interface StartupReminderOptions {
89
90
  projectRoot: string;
@@ -29,6 +29,7 @@ import { homedir } from "node:os";
29
29
  import { dirname, join } from "node:path";
30
30
  import { fileURLToPath } from "node:url";
31
31
  import { parseFrontmatter } from "./agent-frontmatter.js";
32
+ import { detectClient, nonClaudeClientWarning } from "./detect-client.js";
32
33
  function targetDirFor(opts) {
33
34
  const root = opts.scope === "user" ? opts.homeDir : opts.projectRoot;
34
35
  return join(root, ".claude", "agents");
@@ -301,6 +302,35 @@ export async function handleInstallAgents(argv, opts) {
301
302
  const scopeArg = parseFlag(argv, "scope");
302
303
  const force = parseFlag(argv, "force") !== undefined;
303
304
  const projectRoot = opts?.projectRoot ?? process.cwd();
305
+ const homeDir = opts?.homeDir ?? homedir();
306
+ const env = opts?.env ?? process.env;
307
+ // v0.26.5 — plugin-aware note. If we're running as a Claude Code
308
+ // plugin (CLAUDE_PLUGIN_ROOT set), `install-agents` is still useful —
309
+ // tp-* subagents are separate from plugin hooks. But the directory
310
+ // the plugin installer created is the authoritative one; we print a
311
+ // short note so the user doesn't think they need to reinstall on
312
+ // every plugin update.
313
+ if (env.CLAUDE_PLUGIN_ROOT) {
314
+ process.stderr.write("[token-pilot] Note: you're running as a Claude Code plugin. " +
315
+ "install-agents still works for tp-* subagents (those are separate " +
316
+ "from plugin hooks). Continuing.\n");
317
+ }
318
+ // v0.26.0 — detect non-Claude clients where tp-* subagents have no
319
+ // runtime. We still let users force-install via --scope (they may run
320
+ // multiple clients side-by-side), but we warn loudly so nobody ends
321
+ // up with a ghost ~/.claude/agents/ directory nothing invokes.
322
+ const detection = await detectClient(homeDir, projectRoot, env);
323
+ const warning = nonClaudeClientWarning(detection);
324
+ if (warning) {
325
+ process.stderr.write(warning + "\n");
326
+ if (scopeArg === undefined) {
327
+ // Silent bail is worse than a warning — return 0 so CI/postinstall
328
+ // don't treat this as a failure, but skip creating the directory.
329
+ process.stderr.write("[token-pilot] Skipping agent install (pass --scope to override).\n");
330
+ return 0;
331
+ }
332
+ process.stderr.write(`[token-pilot] --scope=${scopeArg} supplied — proceeding anyway.\n`);
333
+ }
304
334
  let scope;
305
335
  if (scopeArg === "user" || scopeArg === "project") {
306
336
  scope = scopeArg;
@@ -330,7 +360,7 @@ export async function handleInstallAgents(argv, opts) {
330
360
  const result = await installAgents({
331
361
  scope,
332
362
  projectRoot,
333
- homeDir: opts?.homeDir ?? homedir(),
363
+ homeDir,
334
364
  distAgentsDir,
335
365
  force,
336
366
  });
@@ -0,0 +1,58 @@
1
+ /**
2
+ * v0.26.2 — `npx token-pilot tool-audit`.
3
+ *
4
+ * Reads `.token-pilot/tool-calls.jsonl` + archives and emits a per-tool
5
+ * savings distribution across every session the user has ever run. The
6
+ * whole point is to answer "which tools actually save tokens" with
7
+ * data, not with a single field-report session.
8
+ *
9
+ * Output is human-readable by default; `--json` for scripts/CI.
10
+ * Exit code is always 0 — this is a diagnostic, not a gate. A future
11
+ * `tool-audit --fail-below=20` could turn it into a CI signal once we
12
+ * trust the baseline.
13
+ */
14
+ import { type ToolCallEvent } from "../core/tool-call-log.js";
15
+ export interface ToolAuditRow {
16
+ tool: string;
17
+ count: number;
18
+ tokensReturned: number;
19
+ tokensWouldBe: number;
20
+ saved: number;
21
+ reductionPct: number;
22
+ /** Calls where the recorder claimed NO savings (pass-through) — separate so
23
+ * they don't poison the reduction average. */
24
+ noneCalls: number;
25
+ /** True when reduction is below the low-value threshold AND we have enough
26
+ * samples (≥5) to make a claim — avoids flagging tools after 1 bad run. */
27
+ lowValue: boolean;
28
+ }
29
+ /**
30
+ * Aggregate raw events into one row per tool. Pure — tested in
31
+ * isolation from the filesystem.
32
+ */
33
+ export declare function aggregateToolCalls(events: ToolCallEvent[], lowValueThreshold?: number, minSamples?: number): ToolAuditRow[];
34
+ /**
35
+ * Format rows as a fixed-width table for the terminal. Pure.
36
+ */
37
+ export declare function formatTable(rows: ToolAuditRow[], opts: {
38
+ totalEvents: number;
39
+ }): string;
40
+ export interface ToolAuditOptions {
41
+ projectRoot: string;
42
+ json?: boolean;
43
+ /** For tests. */
44
+ now?: Date;
45
+ }
46
+ export declare function runToolAudit(opts: ToolAuditOptions): Promise<{
47
+ stdout: string;
48
+ exitCode: number;
49
+ rows: ToolAuditRow[];
50
+ }>;
51
+ /**
52
+ * CLI entry. `argv` is the raw `process.argv.slice(2)` after
53
+ * dispatching to this subcommand.
54
+ */
55
+ export declare function handleToolAudit(argv: string[], opts?: {
56
+ projectRoot?: string;
57
+ }): Promise<number>;
58
+ //# sourceMappingURL=tool-audit.d.ts.map
@@ -0,0 +1,123 @@
1
+ /**
2
+ * v0.26.2 — `npx token-pilot tool-audit`.
3
+ *
4
+ * Reads `.token-pilot/tool-calls.jsonl` + archives and emits a per-tool
5
+ * savings distribution across every session the user has ever run. The
6
+ * whole point is to answer "which tools actually save tokens" with
7
+ * data, not with a single field-report session.
8
+ *
9
+ * Output is human-readable by default; `--json` for scripts/CI.
10
+ * Exit code is always 0 — this is a diagnostic, not a gate. A future
11
+ * `tool-audit --fail-below=20` could turn it into a CI signal once we
12
+ * trust the baseline.
13
+ */
14
+ import { loadAllToolCalls } from "../core/tool-call-log.js";
15
+ /**
16
+ * Aggregate raw events into one row per tool. Pure — tested in
17
+ * isolation from the filesystem.
18
+ */
19
+ export function aggregateToolCalls(events, lowValueThreshold = 20, minSamples = 5) {
20
+ const byTool = new Map();
21
+ for (const e of events) {
22
+ const row = byTool.get(e.tool) ?? {
23
+ count: 0,
24
+ tokensReturned: 0,
25
+ tokensWouldBe: 0,
26
+ noneCalls: 0,
27
+ };
28
+ row.count++;
29
+ row.tokensReturned += e.tokensReturned;
30
+ row.tokensWouldBe += e.tokensWouldBe;
31
+ if (e.savingsCategory === "none")
32
+ row.noneCalls++;
33
+ byTool.set(e.tool, row);
34
+ }
35
+ const rows = [];
36
+ for (const [tool, r] of byTool) {
37
+ const saved = Math.max(0, r.tokensWouldBe - r.tokensReturned);
38
+ const reductionPct = r.tokensWouldBe > 0
39
+ ? Math.round((1 - r.tokensReturned / r.tokensWouldBe) * 100)
40
+ : 0;
41
+ const lowValue = r.count >= minSamples && reductionPct < lowValueThreshold;
42
+ rows.push({
43
+ tool,
44
+ count: r.count,
45
+ tokensReturned: r.tokensReturned,
46
+ tokensWouldBe: r.tokensWouldBe,
47
+ saved,
48
+ reductionPct,
49
+ noneCalls: r.noneCalls,
50
+ lowValue,
51
+ });
52
+ }
53
+ // Sort by tokens saved desc — the first row is your biggest
54
+ // contributor to overall savings, low-value tools sink to the bottom.
55
+ rows.sort((a, b) => b.saved - a.saved);
56
+ return rows;
57
+ }
58
+ function fmtTokens(n) {
59
+ if (n >= 1_000_000)
60
+ return (n / 1_000_000).toFixed(1) + "M";
61
+ if (n >= 1_000)
62
+ return (n / 1_000).toFixed(1) + "k";
63
+ return String(n);
64
+ }
65
+ /**
66
+ * Format rows as a fixed-width table for the terminal. Pure.
67
+ */
68
+ export function formatTable(rows, opts) {
69
+ if (rows.length === 0) {
70
+ return `No tool calls recorded yet.
71
+ Run a few MCP tool calls from your AI client, then re-run \`npx token-pilot tool-audit\`.`;
72
+ }
73
+ const lines = [];
74
+ lines.push(`Token Pilot — tool audit`);
75
+ lines.push(` ${opts.totalEvents} calls across ${rows.length} tools (cumulative across sessions)`);
76
+ lines.push("");
77
+ lines.push(" Tool Calls Saved Returned Reduction");
78
+ lines.push(" ─────────────────────────────────────────────────────────────────");
79
+ for (const r of rows) {
80
+ const tool = r.tool.padEnd(24);
81
+ const count = String(r.count).padStart(6);
82
+ const saved = fmtTokens(r.saved).padStart(9);
83
+ const returned = fmtTokens(r.tokensReturned).padStart(9);
84
+ const pct = `${r.reductionPct}%`.padStart(6);
85
+ const flag = r.lowValue ? " ⚠ low-value" : "";
86
+ lines.push(` ${tool} ${count} ${saved} ${returned} ${pct}${flag}`);
87
+ }
88
+ const lowValueRows = rows.filter((r) => r.lowValue);
89
+ if (lowValueRows.length > 0) {
90
+ lines.push("");
91
+ lines.push("Low-value tools flagged above have <20% token reduction across ≥5 calls.");
92
+ lines.push("Consider: check their `none` passthrough count, or whether a cheaper alternative (Grep, Read) would do the job.");
93
+ }
94
+ return lines.join("\n");
95
+ }
96
+ export async function runToolAudit(opts) {
97
+ const events = await loadAllToolCalls(opts.projectRoot);
98
+ const rows = aggregateToolCalls(events);
99
+ if (opts.json) {
100
+ return {
101
+ stdout: JSON.stringify({ totalEvents: events.length, tools: rows }, null, 2),
102
+ exitCode: 0,
103
+ rows,
104
+ };
105
+ }
106
+ return {
107
+ stdout: formatTable(rows, { totalEvents: events.length }),
108
+ exitCode: 0,
109
+ rows,
110
+ };
111
+ }
112
+ /**
113
+ * CLI entry. `argv` is the raw `process.argv.slice(2)` after
114
+ * dispatching to this subcommand.
115
+ */
116
+ export async function handleToolAudit(argv, opts) {
117
+ const json = argv.includes("--json");
118
+ const projectRoot = opts?.projectRoot ?? process.cwd();
119
+ const { stdout, exitCode } = await runToolAudit({ projectRoot, json });
120
+ process.stdout.write(stdout + "\n");
121
+ return exitCode;
122
+ }
123
+ //# sourceMappingURL=tool-audit.js.map
@@ -17,7 +17,7 @@
17
17
  * Everything else passes through untouched — a real project root like
18
18
  * `/home/user/my-project` or `./subdir` goes to startServer as before.
19
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"];
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", "tool-audit", "save-doc", "list-docs", "init", "--version", "-v", "--help", "-h"];
21
21
  export interface TypoGuardResult {
22
22
  kind: "pass-through" | "typo";
23
23
  suggestion?: string;
@@ -33,6 +33,7 @@ export const KNOWN_COMMANDS = [
33
33
  "install-agents",
34
34
  "uninstall-agents",
35
35
  "stats",
36
+ "tool-audit",
36
37
  "save-doc",
37
38
  "list-docs",
38
39
  "init",
@@ -0,0 +1,63 @@
1
+ /**
2
+ * v0.26.2 — persistent MCP tool-call log.
3
+ *
4
+ * Separate from `hook-events.jsonl` (which records Read-hook outcomes),
5
+ * this file accumulates every MCP tool invocation with its token
6
+ * accounting across ALL sessions. Used by `npx token-pilot tool-audit`
7
+ * to produce a per-tool savings distribution that survives `/clear`,
8
+ * session restarts, and even reboots — i.e. the data-driven base we
9
+ * need before pruning or modifying tools based on "savings".
10
+ *
11
+ * Why not piggy-back on hook-events.jsonl? Different data model: hook
12
+ * events are a denied/allowed bitstream keyed by filepath+lineCount,
13
+ * tool calls are rich records with tokensReturned, wouldBe, category,
14
+ * delegation status. Forcing both into one schema would hurt both
15
+ * readers.
16
+ *
17
+ * File path: `<projectRoot>/.token-pilot/tool-calls.jsonl`. Rotation,
18
+ * retention, and best-effort error handling follow the same contract
19
+ * as event-log.ts — identical 10 MB / 30-day / 100 MB caps so overall
20
+ * .token-pilot/ disk usage stays predictable.
21
+ */
22
+ import type { SavingsCategory } from "./session-analytics.js";
23
+ export declare const TOOL_LOG_ROTATION_BYTES = 10000000;
24
+ export declare const TOOL_LOG_RETENTION_MAX_AGE_DAYS = 30;
25
+ export declare const TOOL_LOG_RETENTION_MAX_TOTAL_BYTES = 100000000;
26
+ /**
27
+ * Persisted shape of one MCP tool call. Mirrors the in-memory
28
+ * `ToolCall` in session-analytics.ts but trims runtime-only fields
29
+ * (intent, decisionTrace — those are re-derivable from args/tool if
30
+ * ever needed, not worth the disk cost).
31
+ */
32
+ export interface ToolCallEvent {
33
+ ts: number;
34
+ session_id: string;
35
+ tool: string;
36
+ path?: string;
37
+ tokensReturned: number;
38
+ tokensWouldBe: number;
39
+ savingsCategory: SavingsCategory;
40
+ sessionCacheHit?: boolean;
41
+ delegatedToContextMode?: boolean;
42
+ }
43
+ export declare function currentToolLogPath(projectRoot: string): string;
44
+ /**
45
+ * Append one tool call. Never throws — telemetry must not break the
46
+ * tool-response path (the caller awaits this but treats errors as
47
+ * silent via `.catch(() => undefined)` at the call site).
48
+ */
49
+ export declare function appendToolCall(projectRoot: string, event: ToolCallEvent): Promise<void>;
50
+ /**
51
+ * Read every tool-call event from the current file + all archives.
52
+ * Malformed JSONL lines are skipped silently — one bad line should not
53
+ * poison the dataset. Returns events in *insertion order within each
54
+ * file*, which happens to be chronological because append-only.
55
+ */
56
+ export declare function loadAllToolCalls(projectRoot: string): Promise<ToolCallEvent[]>;
57
+ export declare function retentionDeletions(files: Array<{
58
+ path: string;
59
+ mtime: Date;
60
+ size: number;
61
+ }>, now: Date, maxAgeDays?: number, maxTotalBytes?: number): string[];
62
+ export declare function applyRetention(projectRoot: string, now?: Date): Promise<void>;
63
+ //# sourceMappingURL=tool-call-log.d.ts.map