token-pilot 0.16.2 → 0.18.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/CHANGELOG.md +33 -0
- package/dist/config/defaults.js +5 -0
- package/dist/core/context-registry.d.ts +4 -0
- package/dist/core/context-registry.js +13 -0
- package/dist/core/validation.d.ts +6 -0
- package/dist/core/validation.js +25 -2
- package/dist/formatters/structure.d.ts +1 -0
- package/dist/formatters/structure.js +48 -2
- package/dist/handlers/csv-sections.d.ts +35 -0
- package/dist/handlers/csv-sections.js +129 -0
- package/dist/handlers/find-usages.js +65 -13
- package/dist/handlers/json-sections.d.ts +17 -0
- package/dist/handlers/json-sections.js +66 -0
- package/dist/handlers/markdown-sections.d.ts +15 -0
- package/dist/handlers/markdown-sections.js +49 -0
- package/dist/handlers/non-code.js +48 -11
- package/dist/handlers/read-for-edit.d.ts +4 -1
- package/dist/handlers/read-for-edit.js +113 -2
- package/dist/handlers/read-section.d.ts +12 -0
- package/dist/handlers/read-section.js +96 -0
- package/dist/handlers/read-symbol.d.ts +1 -0
- package/dist/handlers/read-symbol.js +20 -4
- package/dist/handlers/smart-read-many.js +9 -0
- package/dist/handlers/smart-read.d.ts +1 -0
- package/dist/handlers/smart-read.js +57 -0
- package/dist/handlers/symbol-display-constants.d.ts +10 -0
- package/dist/handlers/symbol-display-constants.js +10 -0
- package/dist/handlers/yaml-sections.d.ts +17 -0
- package/dist/handlers/yaml-sections.js +46 -0
- package/dist/server/tool-definitions.d.ts +161 -16
- package/dist/server/tool-definitions.js +53 -16
- package/dist/server.js +19 -2
- package/dist/types.d.ts +6 -0
- package/package.json +1 -1
|
@@ -9,26 +9,33 @@ export const MCP_INSTRUCTIONS = [
|
|
|
9
9
|
'1. New codebase / unfamiliar project → project_overview',
|
|
10
10
|
'2. Starting work on a directory → explore_area (outline + imports + tests + git log in one call)',
|
|
11
11
|
'3. Need to read a code file → smart_read (NOT Read/cat — returns structure, 60-80% fewer tokens)',
|
|
12
|
+
' - For navigation/browsing: smart_read(scope="nav") — names + lines only, 2-3x smaller',
|
|
13
|
+
' - For public API overview: smart_read(scope="exports")',
|
|
12
14
|
'4. Need one function/class body → read_symbol (loads only that symbol, NOT the whole file)',
|
|
13
|
-
'
|
|
14
|
-
'5.
|
|
15
|
-
'6.
|
|
16
|
-
'7.
|
|
17
|
-
'8.
|
|
18
|
-
'9.
|
|
19
|
-
'
|
|
20
|
-
'
|
|
21
|
-
'
|
|
22
|
-
'
|
|
23
|
-
'
|
|
24
|
-
'
|
|
25
|
-
'
|
|
15
|
+
' - Preparing edit? Add include_edit_context=true to skip separate read_for_edit call',
|
|
16
|
+
'5. Need MULTIPLE function/class bodies from same file → read_symbols (batch — one call instead of N)',
|
|
17
|
+
'6. Preparing an edit → read_for_edit (returns exact text for Edit old_string)',
|
|
18
|
+
'7. Verify edits after editing → read_diff (only changed hunks — REQUIRES smart_read BEFORE editing)',
|
|
19
|
+
'8. Multiple files at once → smart_read_many (batch up to 20 files)',
|
|
20
|
+
'9. Find where a symbol is used → find_usages (semantic: definitions + imports + usages)',
|
|
21
|
+
' - For initial discovery: find_usages(mode="list") — file:line only, 5-10x smaller',
|
|
22
|
+
'10. Understand file dependencies → related_files (imports, importers, tests — ranked by relevance)',
|
|
23
|
+
'11. List all symbols in a directory → outline (classes, functions, methods in one call)',
|
|
24
|
+
'12. Review git changes → smart_diff (NOT git diff — maps changes to functions/classes)',
|
|
25
|
+
'13. Commit history → smart_log (NOT git log — structured with categories)',
|
|
26
|
+
'14. Run tests → test_summary (NOT raw test output — structured pass/fail)',
|
|
27
|
+
'15. Code quality → code_audit (TODOs, deprecated, structural patterns)',
|
|
28
|
+
'16. Dead code → find_unused (unreferenced symbols across project)',
|
|
29
|
+
'17. Module architecture → module_info (deps, dependents, public API)',
|
|
30
|
+
'18. Read markdown/yaml/json/csv section → read_section (loads one heading/key/row-range, NOT the whole file)',
|
|
31
|
+
' - For editing sections: read_for_edit(path, section="Section Name")',
|
|
26
32
|
'',
|
|
27
33
|
'USE DEFAULT TOOLS ONLY FOR: regex text search → Grep | exact raw content → Read | non-code configs → Read',
|
|
28
34
|
'',
|
|
29
35
|
'WORKFLOWS:',
|
|
30
36
|
'• Explore: project_overview → explore_area → smart_read → read_symbol',
|
|
31
|
-
'• Edit: smart_read →
|
|
37
|
+
'• Edit: smart_read → read_symbol(include_edit_context=true) → Edit → read_diff',
|
|
38
|
+
'• Docs: smart_read (outline) → read_section → read_for_edit(section=) → Edit → read_diff',
|
|
32
39
|
'• Refactor: find_usages → read_symbols → read_for_edit → Edit → test_summary',
|
|
33
40
|
'• Audit: code_audit + find_unused + Grep (for regex patterns)',
|
|
34
41
|
].join('\n');
|
|
@@ -44,6 +51,11 @@ export const TOOL_DEFINITIONS = [
|
|
|
44
51
|
show_imports: { type: 'boolean', description: 'Include import details (default: true)' },
|
|
45
52
|
show_docs: { type: 'boolean', description: 'Include doc comments (default: true)' },
|
|
46
53
|
depth: { type: 'number', description: 'Max depth for nested symbols (default: 2)' },
|
|
54
|
+
scope: {
|
|
55
|
+
type: 'string',
|
|
56
|
+
enum: ['full', 'nav', 'exports'],
|
|
57
|
+
description: 'Output scope: full (default, all details), nav (names + lines only, 2-3x smaller), exports (public API only)',
|
|
58
|
+
},
|
|
47
59
|
},
|
|
48
60
|
required: ['path'],
|
|
49
61
|
},
|
|
@@ -59,13 +71,17 @@ export const TOOL_DEFINITIONS = [
|
|
|
59
71
|
context_before: { type: 'number', description: 'Lines of context before (default: 2)' },
|
|
60
72
|
context_after: { type: 'number', description: 'Lines of context after (default: 0)' },
|
|
61
73
|
show: { type: 'string', enum: ['full', 'head', 'tail', 'outline'], description: 'Display mode: full (all lines), head (first 50), tail (last 30), outline (head + methods + tail). Default: auto (full ≤300 lines, outline >300)' },
|
|
74
|
+
include_edit_context: {
|
|
75
|
+
type: 'boolean',
|
|
76
|
+
description: 'Append raw code block for Edit old_string (saves a read_for_edit call)',
|
|
77
|
+
},
|
|
62
78
|
},
|
|
63
79
|
required: ['path', 'symbol'],
|
|
64
80
|
},
|
|
65
81
|
},
|
|
66
82
|
{
|
|
67
83
|
name: 'read_symbols',
|
|
68
|
-
description: 'Batch read MULTIPLE symbols from ONE file
|
|
84
|
+
description: 'Batch read MULTIPLE symbols from ONE file for UNDERSTANDING code — saves N-1 round-trips vs calling read_symbol N times. Returns formatted symbol bodies with show modes (full/head/tail/outline). Use this when READING code, not editing. For edit preparation use read_for_edit instead.',
|
|
69
85
|
inputSchema: {
|
|
70
86
|
type: 'object',
|
|
71
87
|
properties: {
|
|
@@ -95,6 +111,18 @@ export const TOOL_DEFINITIONS = [
|
|
|
95
111
|
required: ['path', 'start_line', 'end_line'],
|
|
96
112
|
},
|
|
97
113
|
},
|
|
114
|
+
{
|
|
115
|
+
name: 'read_section',
|
|
116
|
+
description: 'Read a specific section from Markdown, YAML, JSON, or CSV files. Markdown: by heading name. YAML/JSON: by top-level key. CSV: by row range (rows:1-50). Much cheaper than reading the whole file.',
|
|
117
|
+
inputSchema: {
|
|
118
|
+
type: 'object',
|
|
119
|
+
properties: {
|
|
120
|
+
path: { type: 'string', description: 'Path to .md, .yaml, .yml, .json, or .csv file' },
|
|
121
|
+
heading: { type: 'string', description: 'Section heading (Markdown), top-level key (YAML/JSON), or row range "rows:1-50" (CSV). Case-insensitive.' },
|
|
122
|
+
},
|
|
123
|
+
required: ['path', 'heading'],
|
|
124
|
+
},
|
|
125
|
+
},
|
|
98
126
|
{
|
|
99
127
|
name: 'read_diff',
|
|
100
128
|
description: 'Use INSTEAD OF re-reading whole file after edits. Shows only changed hunks. REQUIRES: call smart_read or read_for_edit BEFORE editing to create baseline snapshot.',
|
|
@@ -109,7 +137,7 @@ export const TOOL_DEFINITIONS = [
|
|
|
109
137
|
},
|
|
110
138
|
{
|
|
111
139
|
name: 'read_for_edit',
|
|
112
|
-
description: 'Use INSTEAD OF Read when preparing an
|
|
140
|
+
description: 'Use INSTEAD OF Read when preparing an EDIT. Returns exact RAW code around a symbol or line — copy directly as old_string for Edit tool. Supports batch: pass "symbols" array to get multiple edit contexts in one call. Unlike read_symbols (for reading/understanding), this returns unformatted code optimized for copy-paste into Edit. Optional: include_callers, include_tests, include_changes for enriched context.',
|
|
113
141
|
inputSchema: {
|
|
114
142
|
type: 'object',
|
|
115
143
|
properties: {
|
|
@@ -125,6 +153,10 @@ export const TOOL_DEFINITIONS = [
|
|
|
125
153
|
include_callers: { type: 'boolean', description: 'Show top callers of this symbol (saves a separate find_usages call)' },
|
|
126
154
|
include_tests: { type: 'boolean', description: 'Show related test file and test names' },
|
|
127
155
|
include_changes: { type: 'boolean', description: 'Show recent git changes in the target region' },
|
|
156
|
+
section: {
|
|
157
|
+
type: 'string',
|
|
158
|
+
description: 'Section to edit: heading (Markdown), top-level key (YAML/JSON), or "rows:1-50" (CSV). Returns raw section content for Edit old_string.',
|
|
159
|
+
},
|
|
128
160
|
},
|
|
129
161
|
required: ['path'],
|
|
130
162
|
},
|
|
@@ -157,6 +189,11 @@ export const TOOL_DEFINITIONS = [
|
|
|
157
189
|
limit: { type: 'number', description: 'Max results per category (default: 50, max: 500)' },
|
|
158
190
|
lang: { type: 'string', description: 'Filter by language/extension (e.g., "php", "typescript")' },
|
|
159
191
|
context_lines: { type: 'number', description: 'Lines of source context around each match (0-10). When set, shows surrounding code — saves follow-up read_symbol calls.' },
|
|
192
|
+
mode: {
|
|
193
|
+
type: 'string',
|
|
194
|
+
enum: ['full', 'list'],
|
|
195
|
+
description: 'Output mode: full (with context, default), list (file:line only, 5-10x smaller for initial discovery)',
|
|
196
|
+
},
|
|
160
197
|
},
|
|
161
198
|
required: ['symbol'],
|
|
162
199
|
},
|
package/dist/server.js
CHANGED
|
@@ -36,12 +36,13 @@ import { handleSmartDiff } from './handlers/smart-diff.js';
|
|
|
36
36
|
import { handleExploreArea } from './handlers/explore-area.js';
|
|
37
37
|
import { handleSmartLog } from './handlers/smart-log.js';
|
|
38
38
|
import { handleTestSummary } from './handlers/test-summary.js';
|
|
39
|
+
import { handleReadSection } from './handlers/read-section.js';
|
|
39
40
|
import { detectContextMode } from './integration/context-mode-detector.js';
|
|
40
41
|
import { estimateTokens } from './core/token-estimator.js';
|
|
41
42
|
import { checkPolicy, isFullReadTool } from './core/policy-engine.js';
|
|
42
43
|
import { MCP_INSTRUCTIONS, TOOL_DEFINITIONS } from './server/tool-definitions.js';
|
|
43
44
|
import { createTokenEstimates } from './server/token-estimates.js';
|
|
44
|
-
import { validateSmartReadArgs, validateReadSymbolArgs, validateReadSymbolsArgs, validateReadRangeArgs, validateReadDiffArgs, validateFindUsagesArgs, validateSmartReadManyArgs, validateReadForEditArgs, validateRelatedFilesArgs, validateOutlineArgs, validateFindUnusedArgs, validateCodeAuditArgs, validateProjectOverviewArgs, validateModuleInfoArgs, validateSmartDiffArgs, validateExploreAreaArgs, validateSmartLogArgs, validateTestSummaryArgs, } from './core/validation.js';
|
|
45
|
+
import { validateSmartReadArgs, validateReadSymbolArgs, validateReadSymbolsArgs, validateReadRangeArgs, validateReadDiffArgs, validateFindUsagesArgs, validateSmartReadManyArgs, validateReadForEditArgs, validateRelatedFilesArgs, validateOutlineArgs, validateFindUnusedArgs, validateCodeAuditArgs, validateProjectOverviewArgs, validateModuleInfoArgs, validateSmartDiffArgs, validateExploreAreaArgs, validateSmartLogArgs, validateTestSummaryArgs, validateReadSectionArgs, } from './core/validation.js';
|
|
45
46
|
export async function createServer(projectRoot, options) {
|
|
46
47
|
const config = await loadConfig(projectRoot);
|
|
47
48
|
const astIndex = new AstIndexClient(projectRoot, config.astIndex.timeout, {
|
|
@@ -273,6 +274,7 @@ export async function createServer(projectRoot, options) {
|
|
|
273
274
|
return nonCodeResult;
|
|
274
275
|
}
|
|
275
276
|
}
|
|
277
|
+
// Dedup is handled inside handleSmartRead (step 5)
|
|
276
278
|
const result = await handleSmartRead(validArgs, projectRoot, astIndex, fileCache, contextRegistry, config);
|
|
277
279
|
const text = result.content[0]?.text ?? '';
|
|
278
280
|
const fullTokensSR = await fullFileTokens(validArgs.path);
|
|
@@ -283,6 +285,7 @@ export async function createServer(projectRoot, options) {
|
|
|
283
285
|
}
|
|
284
286
|
case 'read_symbol': {
|
|
285
287
|
const symArgs = validateReadSymbolArgs(args);
|
|
288
|
+
// Dedup is handled inside handleReadSymbol
|
|
286
289
|
const symResult = await handleReadSymbol(symArgs, projectRoot, symbolResolver, fileCache, contextRegistry, astIndex, config.smartRead.advisoryReminders);
|
|
287
290
|
const symText = symResult.content[0]?.text ?? '';
|
|
288
291
|
const symTokens = estimateTokens(symText);
|
|
@@ -308,6 +311,20 @@ export async function createServer(projectRoot, options) {
|
|
|
308
311
|
recordWithTrace({ tool: 'read_range', path: rangeArgs.path, tokensReturned: rangeTokens, tokensWouldBe: fullTokensRange || rangeTokens, timestamp: Date.now(), savingsCategory: detectSavingsCategory(rangeText), absPath: resolve(projectRoot, rangeArgs.path), args: rangeArgs });
|
|
309
312
|
return rangeResult;
|
|
310
313
|
}
|
|
314
|
+
case 'read_section': {
|
|
315
|
+
const secArgs = validateReadSectionArgs(args);
|
|
316
|
+
const secResult = await handleReadSection(secArgs, projectRoot, contextRegistry);
|
|
317
|
+
const secText = secResult.content[0]?.text ?? '';
|
|
318
|
+
const secTokens = estimateTokens(secText);
|
|
319
|
+
const fullTokensSec = await fullFileTokens(secArgs.path);
|
|
320
|
+
recordWithTrace({
|
|
321
|
+
tool: 'read_section', path: secArgs.path,
|
|
322
|
+
tokensReturned: secTokens, tokensWouldBe: fullTokensSec || secTokens,
|
|
323
|
+
timestamp: Date.now(), savingsCategory: 'compression',
|
|
324
|
+
absPath: resolve(projectRoot, secArgs.path), args: secArgs,
|
|
325
|
+
});
|
|
326
|
+
return secResult;
|
|
327
|
+
}
|
|
311
328
|
case 'read_diff': {
|
|
312
329
|
const diffArgs = validateReadDiffArgs(args);
|
|
313
330
|
const diffResult = await handleReadDiff(diffArgs, projectRoot, fileCache, contextRegistry);
|
|
@@ -319,7 +336,7 @@ export async function createServer(projectRoot, options) {
|
|
|
319
336
|
}
|
|
320
337
|
case 'read_for_edit': {
|
|
321
338
|
const editArgs = validateReadForEditArgs(args);
|
|
322
|
-
const editResult = await handleReadForEdit(editArgs, projectRoot, symbolResolver, fileCache, contextRegistry, astIndex);
|
|
339
|
+
const editResult = await handleReadForEdit(editArgs, projectRoot, symbolResolver, fileCache, contextRegistry, astIndex, { actionableHints: config.display.actionableHints });
|
|
323
340
|
const editText = editResult.content[0]?.text ?? '';
|
|
324
341
|
const editTokens = estimateTokens(editText);
|
|
325
342
|
const fullTokensEdit = await fullFileTokens(editArgs.path);
|
package/dist/types.d.ts
CHANGED
|
@@ -59,6 +59,7 @@ export interface ContextEntry {
|
|
|
59
59
|
contentHash: string;
|
|
60
60
|
tokenEstimate: number;
|
|
61
61
|
loadedAt: number;
|
|
62
|
+
symbolNames?: string[];
|
|
62
63
|
}
|
|
63
64
|
export interface LoadedRegion {
|
|
64
65
|
type: 'structure' | 'symbol' | 'range' | 'full';
|
|
@@ -89,6 +90,10 @@ export interface TokenPilotConfig {
|
|
|
89
90
|
smallFileThreshold: number;
|
|
90
91
|
showDependencyHints: boolean;
|
|
91
92
|
advisoryReminders: boolean;
|
|
93
|
+
autoDelta: {
|
|
94
|
+
enabled: boolean;
|
|
95
|
+
maxAgeSec: number;
|
|
96
|
+
};
|
|
92
97
|
};
|
|
93
98
|
git: {
|
|
94
99
|
watchHead: boolean;
|
|
@@ -110,6 +115,7 @@ export interface TokenPilotConfig {
|
|
|
110
115
|
showReferences: boolean;
|
|
111
116
|
maxDepth: number;
|
|
112
117
|
showTokenSavings: boolean;
|
|
118
|
+
actionableHints: boolean;
|
|
113
119
|
};
|
|
114
120
|
contextMode: {
|
|
115
121
|
enabled: boolean | 'auto';
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "token-pilot",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.18.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",
|