token-pilot 0.29.0 → 0.30.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.
Files changed (50) hide show
  1. package/CHANGELOG.md +35 -0
  2. package/README.md +39 -390
  3. package/agents/tp-api-surface-tracker.md +1 -1
  4. package/agents/tp-audit-scanner.md +1 -1
  5. package/agents/tp-commit-writer.md +1 -1
  6. package/agents/tp-context-engineer.md +1 -1
  7. package/agents/tp-dead-code-finder.md +1 -1
  8. package/agents/tp-debugger.md +1 -1
  9. package/agents/tp-dep-health.md +1 -1
  10. package/agents/tp-doc-writer.md +1 -1
  11. package/agents/tp-history-explorer.md +1 -1
  12. package/agents/tp-impact-analyzer.md +1 -1
  13. package/agents/tp-incident-timeline.md +1 -1
  14. package/agents/tp-incremental-builder.md +1 -1
  15. package/agents/tp-migration-scout.md +1 -1
  16. package/agents/tp-onboard.md +1 -1
  17. package/agents/tp-performance-profiler.md +1 -1
  18. package/agents/tp-pr-reviewer.md +1 -1
  19. package/agents/tp-refactor-planner.md +1 -1
  20. package/agents/tp-review-impact.md +1 -1
  21. package/agents/tp-run.md +1 -1
  22. package/agents/tp-session-restorer.md +1 -1
  23. package/agents/tp-ship-coordinator.md +1 -1
  24. package/agents/tp-spec-writer.md +1 -1
  25. package/agents/tp-test-coverage-gapper.md +1 -1
  26. package/agents/tp-test-triage.md +1 -1
  27. package/agents/tp-test-writer.md +1 -1
  28. package/dist/cli/tool-audit.d.ts +5 -0
  29. package/dist/cli/tool-audit.js +9 -1
  30. package/dist/core/policy-engine.d.ts +1 -5
  31. package/dist/core/policy-engine.js +9 -24
  32. package/dist/hooks/pre-bash.d.ts +2 -1
  33. package/dist/hooks/pre-bash.js +3 -1
  34. package/dist/hooks/pre-grep.d.ts +2 -1
  35. package/dist/hooks/pre-grep.js +3 -1
  36. package/dist/index.js +4 -2
  37. package/dist/server/enforcement-mode.d.ts +47 -0
  38. package/dist/server/enforcement-mode.js +59 -0
  39. package/dist/server/tool-definitions.d.ts +20 -0
  40. package/dist/server/tool-definitions.js +111 -8
  41. package/dist/server/tool-profiles.d.ts +19 -1
  42. package/dist/server/tool-profiles.js +38 -4
  43. package/dist/server.d.ts +2 -0
  44. package/dist/server.js +68 -16
  45. package/docs/agents.md +82 -0
  46. package/docs/configuration.md +117 -0
  47. package/docs/hooks.md +99 -0
  48. package/docs/installation.md +143 -0
  49. package/docs/tools.md +61 -0
  50. package/package.json +2 -2
@@ -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.29.0"
13
+ token_pilot_version: "0.30.0"
14
14
  token_pilot_body_hash: 4e82f7b3c6446663e958fb6bf5eb5348bbdf33389269c888ce0dab766e50561f
15
15
  ---
16
16
 
@@ -11,7 +11,7 @@ tools:
11
11
  - Bash
12
12
  - Read
13
13
  model: sonnet
14
- token_pilot_version: "0.29.0"
14
+ token_pilot_version: "0.30.0"
15
15
  token_pilot_body_hash: 8b9f454a47e57e3761668de788850ef97d5d6f127b059cf8e0cef03deaca3f98
16
16
  ---
17
17
 
@@ -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.29.0"
14
+ token_pilot_version: "0.30.0"
15
15
  token_pilot_body_hash: 91003b244472c4e65d840b55474a86ce04fba379859d588cc0fa54850b0e1e4f
16
16
  ---
17
17
 
@@ -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.29.0"
11
+ token_pilot_version: "0.30.0"
12
12
  token_pilot_body_hash: 45f972c6b36929491a529322bac3c34fd44872f7be4a974d25c7e27cb12e9dc3
13
13
  ---
14
14
 
@@ -9,7 +9,7 @@ tools:
9
9
  - mcp__token-pilot__module_info
10
10
  - Bash
11
11
  model: sonnet
12
- token_pilot_version: "0.29.0"
12
+ token_pilot_version: "0.30.0"
13
13
  token_pilot_body_hash: 3c1c66f952ac63a5936bec86fefda8c842fb9713bca81e48ca5bb568ccb5f367
14
14
  ---
15
15
 
package/agents/tp-run.md CHANGED
@@ -16,7 +16,7 @@ tools:
16
16
  - Glob
17
17
  - Bash
18
18
  model: haiku
19
- token_pilot_version: "0.29.0"
19
+ token_pilot_version: "0.30.0"
20
20
  token_pilot_body_hash: de342efe1e3ee265df1773ebde1241555750ab17de249190a5c1c200f1f8f51a
21
21
  ---
22
22
 
@@ -9,7 +9,7 @@ tools:
9
9
  - mcp__token-pilot__session_budget
10
10
  - Bash
11
11
  - Read
12
- token_pilot_version: "0.29.0"
12
+ token_pilot_version: "0.30.0"
13
13
  token_pilot_body_hash: d031f30e9cc4ea454aa256427659ed27249d820b75dc8b9b99c81ba7635230a7
14
14
  ---
15
15
 
@@ -11,7 +11,7 @@ tools:
11
11
  - Read
12
12
  - Grep
13
13
  model: sonnet
14
- token_pilot_version: "0.29.0"
14
+ token_pilot_version: "0.30.0"
15
15
  token_pilot_body_hash: 6b1c27b3dc4fad622cebff7c49e079fc764ca0ae57ef5bc4e61b563d8321092d
16
16
  ---
17
17
 
@@ -9,7 +9,7 @@ tools:
9
9
  - Read
10
10
  - Write
11
11
  model: sonnet
12
- token_pilot_version: "0.29.0"
12
+ token_pilot_version: "0.30.0"
13
13
  token_pilot_body_hash: 4ae44482db80a8a3a43794c6ecb665ec0b5385a274e1e5b2e3a404956075be88
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.29.0"
13
+ token_pilot_version: "0.30.0"
14
14
  token_pilot_body_hash: 6d862d1bcaeda3fb13099f51e40faaaf45d16d7d41d1b938609500192aa606f2
15
15
  ---
16
16
 
@@ -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.29.0"
11
+ token_pilot_version: "0.30.0"
12
12
  token_pilot_body_hash: f4e0dcbd2b4e8648efcafc9d53101a66bf394d7c90e97df7581ac47fcfbff5cb
13
13
  ---
14
14
 
@@ -13,7 +13,7 @@ tools:
13
13
  - Edit
14
14
  - Bash
15
15
  model: sonnet
16
- token_pilot_version: "0.29.0"
16
+ token_pilot_version: "0.30.0"
17
17
  token_pilot_body_hash: 960fe9e907e9c7d13b14dcc22af99e8cc7e7335f99791fa808df76ac21e1f5e9
18
18
  ---
19
19
 
@@ -22,6 +22,11 @@ export interface ToolAuditRow {
22
22
  /** Calls where the recorder claimed NO savings (pass-through) — separate so
23
23
  * they don't poison the reduction average. */
24
24
  noneCalls: number;
25
+ /** Calls where the MCP response was served from the session cache (the model
26
+ * replayed cached tokens). These contribute to `saved` but the mechanism
27
+ * is token re-use, not structural compression — useful to split out so the
28
+ * "Est.Saved*" column is understood correctly. */
29
+ cacheHitCalls: number;
25
30
  /** True when reduction is below the low-value threshold AND we have enough
26
31
  * samples (≥5) to make a claim — avoids flagging tools after 1 bad run. */
27
32
  lowValue: boolean;
@@ -24,12 +24,15 @@ export function aggregateToolCalls(events, lowValueThreshold = 20, minSamples =
24
24
  tokensReturned: 0,
25
25
  tokensWouldBe: 0,
26
26
  noneCalls: 0,
27
+ cacheHitCalls: 0,
27
28
  };
28
29
  row.count++;
29
30
  row.tokensReturned += e.tokensReturned;
30
31
  row.tokensWouldBe += e.tokensWouldBe;
31
32
  if (e.savingsCategory === "none")
32
33
  row.noneCalls++;
34
+ if (e.sessionCacheHit)
35
+ row.cacheHitCalls++;
33
36
  byTool.set(e.tool, row);
34
37
  }
35
38
  const rows = [];
@@ -47,6 +50,7 @@ export function aggregateToolCalls(events, lowValueThreshold = 20, minSamples =
47
50
  saved,
48
51
  reductionPct,
49
52
  noneCalls: r.noneCalls,
53
+ cacheHitCalls: r.cacheHitCalls,
50
54
  lowValue,
51
55
  });
52
56
  }
@@ -74,7 +78,7 @@ Run a few MCP tool calls from your AI client, then re-run \`npx token-pilot tool
74
78
  lines.push(`Token Pilot — tool audit`);
75
79
  lines.push(` ${opts.totalEvents} calls across ${rows.length} tools (cumulative across sessions)`);
76
80
  lines.push("");
77
- lines.push(" Tool Calls Saved Returned Reduction");
81
+ lines.push(" Tool Calls Est.Saved* Returned Reduction");
78
82
  lines.push(" ─────────────────────────────────────────────────────────────────");
79
83
  for (const r of rows) {
80
84
  const tool = r.tool.padEnd(24);
@@ -91,6 +95,10 @@ Run a few MCP tool calls from your AI client, then re-run \`npx token-pilot tool
91
95
  lines.push("Low-value tools flagged above have <20% token reduction across ≥5 calls.");
92
96
  lines.push("Consider: check their `none` passthrough count, or whether a cheaper alternative (Grep, Read) would do the job.");
93
97
  }
98
+ lines.push("");
99
+ lines.push("* Est.Saved is estimated against a full-file read baseline. Actual prompt");
100
+ lines.push(" savings depend on client caching — use `cacheHitCalls` in --json output");
101
+ lines.push(" to distinguish structural compression from cache re-use.");
94
102
  return lines.join("\n");
95
103
  }
96
104
  export async function runToolAudit(opts) {
@@ -6,8 +6,6 @@
6
6
  export interface PolicyConfig {
7
7
  /** Advisory hints when an expensive tool is used where a cheaper alternative exists */
8
8
  preferCheapReads: boolean;
9
- /** Track if read_for_edit was called before edit (advisory) */
10
- requireReadForEditBeforeEdit: boolean;
11
9
  /** Always cache project overview in session cache */
12
10
  cacheProjectOverview: boolean;
13
11
  /** Warn after N full-file reads in a session */
@@ -25,13 +23,11 @@ export declare const DEFAULT_POLICIES: PolicyConfig;
25
23
  export interface PolicyCheckContext {
26
24
  fullFileReadsCount: number;
27
25
  tokensReturned: number;
28
- readForEditCalled?: Set<string>;
29
- editTargetPath?: string;
30
26
  totalCallCount?: number;
31
27
  totalTokensReturned?: number;
32
28
  }
33
29
  export interface PolicyAdvisory {
34
- level: 'info' | 'warn';
30
+ level: "info" | "warn";
35
31
  message: string;
36
32
  }
37
33
  /**
@@ -5,7 +5,6 @@
5
5
  */
6
6
  export const DEFAULT_POLICIES = {
7
7
  preferCheapReads: true,
8
- requireReadForEditBeforeEdit: true,
9
8
  cacheProjectOverview: true,
10
9
  maxFullFileReads: 10,
11
10
  warnOnLargeReads: true,
@@ -14,14 +13,11 @@ export const DEFAULT_POLICIES = {
14
13
  compactionTokenThreshold: 8000,
15
14
  };
16
15
  /** Full-file read tools that count toward maxFullFileReads */
17
- const FULL_READ_TOOLS = new Set([
18
- 'smart_read',
19
- 'smart_read_many',
20
- ]);
16
+ const FULL_READ_TOOLS = new Set(["smart_read", "smart_read_many"]);
21
17
  /** Tools that indicate a cheaper alternative may exist */
22
18
  const EXPENSIVE_TOOLS = {
23
- smart_read: 'Consider read_symbol() or read_range() for targeted reads',
24
- smart_read_many: 'Consider reading files individually with read_symbol()',
19
+ smart_read: "Consider read_symbol() or read_range() for targeted reads",
20
+ smart_read_many: "Consider reading files individually with read_symbol()",
25
21
  };
26
22
  /**
27
23
  * Check policy rules and return advisory messages.
@@ -33,7 +29,7 @@ export function checkPolicy(policy, tool, context) {
33
29
  FULL_READ_TOOLS.has(tool) &&
34
30
  context.fullFileReadsCount >= policy.maxFullFileReads) {
35
31
  return {
36
- level: 'warn',
32
+ level: "warn",
37
33
  message: `POLICY: ${context.fullFileReadsCount} full-file reads this session (limit: ${policy.maxFullFileReads}). Consider read_symbol() or read_range() for targeted access.`,
38
34
  };
39
35
  }
@@ -41,7 +37,7 @@ export function checkPolicy(policy, tool, context) {
41
37
  if (policy.warnOnLargeReads &&
42
38
  context.tokensReturned > policy.largeReadThreshold) {
43
39
  return {
44
- level: 'info',
40
+ level: "info",
45
41
  message: `POLICY: Large response (~${context.tokensReturned} tokens). Future reads on this file: use read_symbol() or read_range() for targeted access.`,
46
42
  };
47
43
  }
@@ -50,29 +46,18 @@ export function checkPolicy(policy, tool, context) {
50
46
  // Only advise when token count is high enough to matter
51
47
  if (context.tokensReturned > 500) {
52
48
  return {
53
- level: 'info',
49
+ level: "info",
54
50
  message: `POLICY: ${EXPENSIVE_TOOLS[tool]}`,
55
51
  };
56
52
  }
57
53
  }
58
- // 4. Require read_for_edit before edit
59
- if (policy.requireReadForEditBeforeEdit &&
60
- tool === 'edit' &&
61
- context.editTargetPath &&
62
- context.readForEditCalled &&
63
- !context.readForEditCalled.has(context.editTargetPath)) {
64
- return {
65
- level: 'info',
66
- message: `POLICY: Consider using read_for_edit("${context.editTargetPath}") before editing to get precise edit context.`,
67
- };
68
- }
69
- // 5. Session compaction advisory — by call count
54
+ // 4. Session compaction advisory — by call count
70
55
  if (policy.compactionCallThreshold > 0 &&
71
56
  context.totalCallCount !== undefined &&
72
57
  context.totalCallCount > 0 &&
73
58
  context.totalCallCount % policy.compactionCallThreshold === 0) {
74
59
  return {
75
- level: 'info',
60
+ level: "info",
76
61
  message: `COMPACTION: ${context.totalCallCount} tool calls this session. Consider calling session_snapshot() to capture state, then compact context.`,
77
62
  };
78
63
  }
@@ -84,7 +69,7 @@ export function checkPolicy(policy, tool, context) {
84
69
  context.totalCallCount % 5 === 0 // don't spam every call, check every 5th
85
70
  ) {
86
71
  return {
87
- level: 'info',
72
+ level: "info",
88
73
  message: `COMPACTION: ~${context.totalTokensReturned} tokens returned this session. Consider calling session_snapshot() to capture state, then compact context.`,
89
74
  };
90
75
  }
@@ -24,6 +24,7 @@
24
24
  * `bash -c`, heredocs, or eval'd strings slip through. Acceptable for
25
25
  * v0.28.0; tighten only if tool-audit shows repeated escapes.
26
26
  */
27
+ import type { EnforcementMode } from "../server/enforcement-mode.js";
27
28
  export interface PreBashInput {
28
29
  tool_name?: string;
29
30
  tool_input?: {
@@ -49,6 +50,6 @@ export type PreBashDecision = {
49
50
  */
50
51
  export declare function extractWrappedCommands(command: string): string[];
51
52
  export declare function detectHeavyPattern(command: string): PreBashDecision;
52
- export declare function decidePreBash(input: PreBashInput): PreBashDecision;
53
+ export declare function decidePreBash(input: PreBashInput, mode?: EnforcementMode): PreBashDecision;
53
54
  export declare function renderPreBashOutput(decision: PreBashDecision): string | null;
54
55
  //# sourceMappingURL=pre-bash.d.ts.map
@@ -143,7 +143,9 @@ function detectHeavyPatternSingle(command) {
143
143
  }
144
144
  return { kind: "allow" };
145
145
  }
146
- export function decidePreBash(input) {
146
+ export function decidePreBash(input, mode = "deny") {
147
+ if (mode === "advisory")
148
+ return { kind: "allow" };
147
149
  if (input.tool_name !== "Bash")
148
150
  return { kind: "allow" };
149
151
  const cmd = input.tool_input?.command;
@@ -20,6 +20,7 @@
20
20
  * find_usages after the block, we keep it. If they bypass via `-E` or
21
21
  * raw shell, we soften to advisory.
22
22
  */
23
+ import type { EnforcementMode } from "../server/enforcement-mode.js";
23
24
  export interface PreGrepInput {
24
25
  tool_name?: string;
25
26
  tool_input?: {
@@ -51,7 +52,7 @@ export declare function isSymbolLikePattern(pattern: string): boolean;
51
52
  * Pure decision function. Given a PreToolUse hook input for Grep,
52
53
  * return whether to allow or deny (with a suggestion).
53
54
  */
54
- export declare function decidePreGrep(input: PreGrepInput): PreGrepDecision;
55
+ export declare function decidePreGrep(input: PreGrepInput, mode?: EnforcementMode): PreGrepDecision;
55
56
  /**
56
57
  * Render the Claude Code hook JSON response.
57
58
  */
@@ -64,7 +64,9 @@ export function isSymbolLikePattern(pattern) {
64
64
  * Pure decision function. Given a PreToolUse hook input for Grep,
65
65
  * return whether to allow or deny (with a suggestion).
66
66
  */
67
- export function decidePreGrep(input) {
67
+ export function decidePreGrep(input, mode = "deny") {
68
+ if (mode === "advisory")
69
+ return { kind: "allow" };
68
70
  if (input.tool_name !== "Grep")
69
71
  return { kind: "allow" };
70
72
  const pattern = input.tool_input?.pattern;
package/dist/index.js CHANGED
@@ -52,6 +52,7 @@ import { assessClaudeMd } from "./cli/claudemd-hygiene.js";
52
52
  import { decidePostBashAdvice, renderPostBashHookOutput, } from "./hooks/post-bash.js";
53
53
  import { decidePreBash, renderPreBashOutput } from "./hooks/pre-bash.js";
54
54
  import { decidePreGrep, renderPreGrepOutput } from "./hooks/pre-grep.js";
55
+ import { parseEnforcementMode } from "./server/enforcement-mode.js";
55
56
  const execFileAsync = promisify(execFile);
56
57
  export const CODE_EXTENSIONS = new Set([
57
58
  "ts",
@@ -152,7 +153,7 @@ export async function main(cliArgs = process.argv.slice(2)) {
152
153
  try {
153
154
  const stdin = readFileSync(0, "utf-8");
154
155
  const input = JSON.parse(stdin);
155
- const decision = decidePreBash(input);
156
+ const decision = decidePreBash(input, parseEnforcementMode(process.env.TOKEN_PILOT_MODE));
156
157
  const rendered = renderPreBashOutput(decision);
157
158
  if (rendered)
158
159
  process.stdout.write(rendered);
@@ -169,7 +170,7 @@ export async function main(cliArgs = process.argv.slice(2)) {
169
170
  try {
170
171
  const stdin = readFileSync(0, "utf-8");
171
172
  const input = JSON.parse(stdin);
172
- const decision = decidePreGrep(input);
173
+ const decision = decidePreGrep(input, parseEnforcementMode(process.env.TOKEN_PILOT_MODE));
173
174
  const rendered = renderPreGrepOutput(decision);
174
175
  if (rendered)
175
176
  process.stdout.write(rendered);
@@ -386,6 +387,7 @@ export async function startServer(cliArgs = process.argv.slice(2)) {
386
387
  });
387
388
  const server = await createServer(projectRoot, {
388
389
  skipAstIndex: isDangerousRoot(projectRoot),
390
+ enforcementMode: parseEnforcementMode(process.env.TOKEN_PILOT_MODE),
389
391
  });
390
392
  const transport = new StdioServerTransport();
391
393
  await server.connect(transport);
@@ -0,0 +1,47 @@
1
+ /**
2
+ * v0.30.0 — TOKEN_PILOT_MODE enforcement modes.
3
+ *
4
+ * Controls how aggressively token-pilot blocks heavy native tools and
5
+ * caps MCP tool output sizes. Three modes:
6
+ *
7
+ * advisory — hooks always allow, no MCP output caps. Observation-only.
8
+ * Use when measuring baseline token usage or debugging.
9
+ *
10
+ * deny — DEFAULT. Hooks deny heavy Bash/Grep patterns and suggest
11
+ * cheaper MCP alternatives. No auto-caps on MCP output.
12
+ * This is the "smart redirect" mode — the agent learns the
13
+ * right tool but can still produce large MCP responses.
14
+ *
15
+ * strict — deny + MCP output auto-caps. smart_read is capped at
16
+ * max_tokens=2000 when the caller doesn't set it; explore_area
17
+ * defaults include=['outline'] when the caller doesn't set it.
18
+ * Cap values are v0.30.0 initial estimates — tune from real
19
+ * tool-audit data in a follow-up PR (#8).
20
+ *
21
+ * Set via TOKEN_PILOT_MODE environment variable (case-insensitive, trimmed).
22
+ * Unknown values fall back to "deny" with a warning.
23
+ *
24
+ * Separate from `hooks.mode` (HookMode) which controls only the PreToolUse:Read
25
+ * hook (deny-enhanced vs advisory for large file reads). TOKEN_PILOT_MODE
26
+ * covers Bash and Grep hooks plus MCP output caps.
27
+ */
28
+ export type EnforcementMode = "advisory" | "deny" | "strict";
29
+ export declare const ENFORCEMENT_MODE_NAMES: readonly ["advisory", "deny", "strict"];
30
+ /**
31
+ * Parse TOKEN_PILOT_MODE from an env-var string. Returns "deny" for
32
+ * missing or empty values. Emits a warning for unrecognised values.
33
+ */
34
+ export declare function parseEnforcementMode(raw: string | undefined, warn?: (msg: string) => void): EnforcementMode;
35
+ /**
36
+ * The cap applied to smart_read max_tokens in strict mode when the
37
+ * caller has not supplied an explicit max_tokens.
38
+ * v0.30.0 initial estimate — tune from tool-audit data.
39
+ */
40
+ export declare const STRICT_SMART_READ_MAX_TOKENS = 2000;
41
+ /**
42
+ * The include sections applied to explore_area in strict mode when the
43
+ * caller has not supplied an explicit include array.
44
+ * v0.30.0 initial estimate — outline-only keeps footprint minimal.
45
+ */
46
+ export declare const STRICT_EXPLORE_AREA_INCLUDE: Array<"outline" | "imports" | "tests" | "changes">;
47
+ //# sourceMappingURL=enforcement-mode.d.ts.map
@@ -0,0 +1,59 @@
1
+ /**
2
+ * v0.30.0 — TOKEN_PILOT_MODE enforcement modes.
3
+ *
4
+ * Controls how aggressively token-pilot blocks heavy native tools and
5
+ * caps MCP tool output sizes. Three modes:
6
+ *
7
+ * advisory — hooks always allow, no MCP output caps. Observation-only.
8
+ * Use when measuring baseline token usage or debugging.
9
+ *
10
+ * deny — DEFAULT. Hooks deny heavy Bash/Grep patterns and suggest
11
+ * cheaper MCP alternatives. No auto-caps on MCP output.
12
+ * This is the "smart redirect" mode — the agent learns the
13
+ * right tool but can still produce large MCP responses.
14
+ *
15
+ * strict — deny + MCP output auto-caps. smart_read is capped at
16
+ * max_tokens=2000 when the caller doesn't set it; explore_area
17
+ * defaults include=['outline'] when the caller doesn't set it.
18
+ * Cap values are v0.30.0 initial estimates — tune from real
19
+ * tool-audit data in a follow-up PR (#8).
20
+ *
21
+ * Set via TOKEN_PILOT_MODE environment variable (case-insensitive, trimmed).
22
+ * Unknown values fall back to "deny" with a warning.
23
+ *
24
+ * Separate from `hooks.mode` (HookMode) which controls only the PreToolUse:Read
25
+ * hook (deny-enhanced vs advisory for large file reads). TOKEN_PILOT_MODE
26
+ * covers Bash and Grep hooks plus MCP output caps.
27
+ */
28
+ export const ENFORCEMENT_MODE_NAMES = [
29
+ "advisory",
30
+ "deny",
31
+ "strict",
32
+ ];
33
+ /**
34
+ * Parse TOKEN_PILOT_MODE from an env-var string. Returns "deny" for
35
+ * missing or empty values. Emits a warning for unrecognised values.
36
+ */
37
+ export function parseEnforcementMode(raw, warn = (m) => process.stderr.write(m + "\n")) {
38
+ if (!raw || raw.trim() === "")
39
+ return "deny";
40
+ const v = raw.trim().toLowerCase();
41
+ if (v === "advisory" || v === "deny" || v === "strict")
42
+ return v;
43
+ warn(`[token-pilot] Unknown TOKEN_PILOT_MODE="${raw}", falling back to "deny". ` +
44
+ `Valid values: advisory | deny | strict.`);
45
+ return "deny";
46
+ }
47
+ /**
48
+ * The cap applied to smart_read max_tokens in strict mode when the
49
+ * caller has not supplied an explicit max_tokens.
50
+ * v0.30.0 initial estimate — tune from tool-audit data.
51
+ */
52
+ export const STRICT_SMART_READ_MAX_TOKENS = 2000;
53
+ /**
54
+ * The include sections applied to explore_area in strict mode when the
55
+ * caller has not supplied an explicit include array.
56
+ * v0.30.0 initial estimate — outline-only keeps footprint minimal.
57
+ */
58
+ export const STRICT_EXPLORE_AREA_INCLUDE = ["outline"];
59
+ //# sourceMappingURL=enforcement-mode.js.map
@@ -1,6 +1,26 @@
1
1
  /**
2
2
  * MCP tool definitions and system instructions.
3
3
  * Pure static data — no runtime dependencies.
4
+ *
5
+ * v0.30.0 — Profile-specific instructions. Each profile advertises only
6
+ * the tools it includes; instructions are trimmed to match so the agent
7
+ * doesn't hallucinate tools that aren't in tools/list.
8
+ *
9
+ * minimal — 5 core tools, minimal context overhead
10
+ * nav — 10 exploration tools, no editing
11
+ * edit — nav + 6 edit-prep tools (DEFAULT)
12
+ * full — everything including audit tools
13
+ */
14
+ import type { ToolProfile } from "./tool-profiles.js";
15
+ /**
16
+ * Select MCP instructions for the given tool profile.
17
+ * Each profile only mentions tools that are actually advertised in its
18
+ * tools/list — prevents the agent from calling tools it can't see.
19
+ */
20
+ export declare function getMcpInstructions(profile: ToolProfile): string;
21
+ /**
22
+ * @deprecated Use getMcpInstructions(profile) instead.
23
+ * Kept for backward-compat — resolves to the full profile instructions.
4
24
  */
5
25
  export declare const MCP_INSTRUCTIONS: string;
6
26
  export declare const TOOL_DEFINITIONS: ({