token-pilot 0.9.0 → 0.12.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/dist/server.js CHANGED
@@ -28,9 +28,13 @@ import { handleRelatedFiles } from './handlers/related-files.js';
28
28
  import { handleOutline } from './handlers/outline.js';
29
29
  import { handleCodeAudit } from './handlers/code-audit.js';
30
30
  import { handleModuleInfo } from './handlers/module-info.js';
31
+ import { handleSmartDiff } from './handlers/smart-diff.js';
32
+ import { handleExploreArea } from './handlers/explore-area.js';
33
+ import { handleSmartLog } from './handlers/smart-log.js';
34
+ import { handleTestSummary } from './handlers/test-summary.js';
31
35
  import { detectContextMode } from './integration/context-mode-detector.js';
32
36
  import { estimateTokens } from './core/token-estimator.js';
33
- import { resolveSafePath, validateSmartReadArgs, validateReadSymbolArgs, validateReadRangeArgs, validateReadDiffArgs, validateFindUsagesArgs, validateSmartReadManyArgs, validateReadForEditArgs, validateRelatedFilesArgs, validateOutlineArgs, validateFindUnusedArgs, validateCodeAuditArgs, validateProjectOverviewArgs, validateModuleInfoArgs, } from './core/validation.js';
37
+ import { resolveSafePath, validateSmartReadArgs, validateReadSymbolArgs, validateReadRangeArgs, validateReadDiffArgs, validateFindUsagesArgs, validateSmartReadManyArgs, validateReadForEditArgs, validateRelatedFilesArgs, validateOutlineArgs, validateFindUnusedArgs, validateCodeAuditArgs, validateProjectOverviewArgs, validateModuleInfoArgs, validateSmartDiffArgs, validateExploreAreaArgs, validateSmartLogArgs, validateTestSummaryArgs, } from './core/validation.js';
34
38
  export async function createServer(projectRoot, options) {
35
39
  const config = await loadConfig(projectRoot);
36
40
  const astIndex = new AstIndexClient(projectRoot, config.astIndex.timeout, {
@@ -183,6 +187,10 @@ export async function createServer(projectRoot, options) {
183
187
  '• Reading file again → smart_read (returns compact reminder, not full content)',
184
188
  '• Multiple files → smart_read_many (batch, max 20)',
185
189
  '• Code quality audit → code_audit (TODOs, deprecated, structural code patterns)',
190
+ '• Reviewing git changes → smart_diff (structural diff with symbol mapping, not raw patch)',
191
+ '• Starting work on an area → explore_area (outline + imports + tests + git log in one call)',
192
+ '• Understanding commit history → smart_log (structured git log with categories, not raw output)',
193
+ '• Running tests → test_summary (structured pass/fail summary, not 200 lines of raw output)',
186
194
  '',
187
195
  'WHEN TO USE DEFAULT TOOLS (Token Pilot adds no value):',
188
196
  '• Small files (≤200 lines) → smart_read returns full content anyway, same as Read',
@@ -201,7 +209,7 @@ export async function createServer(projectRoot, options) {
201
209
  '• Deep dive into specific code → read_symbol (after finding issues)',
202
210
  '• Module architecture → module_info (deps, dependents, public API, unused deps)',
203
211
  '',
204
- 'WORKFLOW: project_overview → smart_read → read_symbol → read_for_edit → edit → read_diff',
212
+ 'WORKFLOW: project_overview → explore_area → smart_read → read_symbol → read_for_edit → edit → smart_diff',
205
213
  ].join('\n'),
206
214
  });
207
215
  server.setRequestHandler(ListToolsRequestSchema, () => ({
@@ -401,6 +409,60 @@ export async function createServer(projectRoot, options) {
401
409
  required: ['module'],
402
410
  },
403
411
  },
412
+ // --- Diff & exploration ---
413
+ {
414
+ name: 'smart_diff',
415
+ description: 'Use INSTEAD OF raw git diff. Shows changed files with AST symbol mapping — which functions/classes were modified/added/removed. Small diffs include hunks, large diffs show summary.',
416
+ inputSchema: {
417
+ type: 'object',
418
+ properties: {
419
+ scope: { type: 'string', enum: ['unstaged', 'staged', 'commit', 'branch'], description: 'Diff scope (default: "unstaged")' },
420
+ path: { type: 'string', description: 'Filter to specific file or directory' },
421
+ ref: { type: 'string', description: 'Git ref — required for scope="commit" (commit hash) or scope="branch" (branch name)' },
422
+ },
423
+ },
424
+ },
425
+ {
426
+ name: 'explore_area',
427
+ description: 'One-call exploration of a directory: outline (all symbols), imports (external deps + who imports this area), tests (matching test files), recent git changes. Use INSTEAD OF separate outline + related_files + git log calls.',
428
+ inputSchema: {
429
+ type: 'object',
430
+ properties: {
431
+ path: { type: 'string', description: 'Directory path (or file path — will use its parent directory)' },
432
+ include: {
433
+ type: 'array',
434
+ items: { type: 'string', enum: ['outline', 'imports', 'tests', 'changes'] },
435
+ description: 'Sections to include (default: all)',
436
+ },
437
+ },
438
+ required: ['path'],
439
+ },
440
+ },
441
+ {
442
+ name: 'smart_log',
443
+ description: 'Use INSTEAD OF raw git log. Structured commit history with category detection (feat/fix/refactor/docs), file stats, author breakdown. Filters by path and ref.',
444
+ inputSchema: {
445
+ type: 'object',
446
+ properties: {
447
+ path: { type: 'string', description: 'Filter to specific file or directory' },
448
+ count: { type: 'number', description: 'Number of commits (default: 10, max: 50)' },
449
+ ref: { type: 'string', description: 'Git ref — branch, tag, or commit (default: HEAD)' },
450
+ },
451
+ },
452
+ },
453
+ {
454
+ name: 'test_summary',
455
+ description: 'Run tests and return structured summary: total/passed/failed/skipped + failure details. 200 lines of raw output → 10-15 lines. Supports vitest, jest, pytest, phpunit, go test, cargo test.',
456
+ inputSchema: {
457
+ type: 'object',
458
+ properties: {
459
+ command: { type: 'string', description: 'Test command to run (e.g., "npm test", "pytest", "go test ./...")' },
460
+ runner: { type: 'string', enum: ['vitest', 'jest', 'pytest', 'phpunit', 'go', 'cargo', 'rspec', 'mocha'], description: 'Force specific parser (auto-detected if omitted)' },
461
+ timeout: { type: 'number', description: 'Timeout in ms (default: 60000, max: 300000)' },
462
+ },
463
+ required: ['command'],
464
+ },
465
+ },
404
466
  ],
405
467
  }));
406
468
  // Helper: get real full-file token count for honest analytics
@@ -553,6 +615,40 @@ export async function createServer(projectRoot, options) {
553
615
  analytics.record({ tool: 'module_info', path: moduleArgs.module, tokensReturned: estimateTokens(moduleText), tokensWouldBe: moduleWouldBe, timestamp: Date.now() });
554
616
  return moduleResult;
555
617
  }
618
+ case 'smart_diff': {
619
+ const sdArgs = validateSmartDiffArgs(args);
620
+ const sdResult = await handleSmartDiff(sdArgs, projectRoot, astIndex);
621
+ const sdText = sdResult.content[0]?.text ?? '';
622
+ const sdTokens = estimateTokens(sdText);
623
+ analytics.record({ tool: 'smart_diff', path: sdArgs.path ?? sdArgs.scope ?? 'unstaged', tokensReturned: sdTokens, tokensWouldBe: sdResult.rawTokens || sdTokens, timestamp: Date.now() });
624
+ return { content: sdResult.content };
625
+ }
626
+ case 'explore_area': {
627
+ const eaArgs = validateExploreAreaArgs(args);
628
+ const eaResult = await handleExploreArea(eaArgs, projectRoot, astIndex);
629
+ const eaText = eaResult.content[0]?.text ?? '';
630
+ const eaTokens = estimateTokens(eaText);
631
+ // Without explore_area, agent would call: outline + related_files + git log = ~3-5x tokens
632
+ const eaWouldBe = eaTokens * 4;
633
+ analytics.record({ tool: 'explore_area', path: eaArgs.path, tokensReturned: eaTokens, tokensWouldBe: eaWouldBe, timestamp: Date.now() });
634
+ return eaResult;
635
+ }
636
+ case 'smart_log': {
637
+ const slArgs = validateSmartLogArgs(args);
638
+ const slResult = await handleSmartLog(slArgs, projectRoot);
639
+ const slText = slResult.content[0]?.text ?? '';
640
+ const slTokens = estimateTokens(slText);
641
+ analytics.record({ tool: 'smart_log', path: slArgs.path ?? 'all', tokensReturned: slTokens, tokensWouldBe: slResult.rawTokens || slTokens, timestamp: Date.now() });
642
+ return { content: slResult.content };
643
+ }
644
+ case 'test_summary': {
645
+ const tsArgs = validateTestSummaryArgs(args);
646
+ const tsResult = await handleTestSummary(tsArgs, projectRoot);
647
+ const tsText = tsResult.content[0]?.text ?? '';
648
+ const tsTokens = estimateTokens(tsText);
649
+ analytics.record({ tool: 'test_summary', path: tsArgs.command, tokensReturned: tsTokens, tokensWouldBe: tsResult.rawTokens || tsTokens, timestamp: Date.now() });
650
+ return { content: tsResult.content };
651
+ }
556
652
  default:
557
653
  return {
558
654
  content: [{ type: 'text', text: `Unknown tool: ${name}` }],
package/dist/types.d.ts CHANGED
@@ -115,6 +115,10 @@ export interface TokenPilotConfig {
115
115
  adviseDelegation: boolean;
116
116
  largeNonCodeThreshold: number;
117
117
  };
118
+ updates: {
119
+ checkOnStartup: boolean;
120
+ autoUpdate: boolean;
121
+ };
118
122
  ignore: string[];
119
123
  }
120
124
  //# sourceMappingURL=types.d.ts.map
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "token-pilot",
3
- "version": "0.9.0",
3
+ "version": "0.12.0",
4
4
  "description": "Save 60-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",