neuronlayer 0.1.9 → 0.2.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.

Potentially problematic release.


This version of neuronlayer might be problematic. Click here for more details.

Files changed (81) hide show
  1. package/README.md +3 -2
  2. package/dist/index.js +172 -90
  3. package/dist/index.js.map +7 -0
  4. package/package.json +6 -1
  5. package/esbuild.config.js +0 -26
  6. package/src/cli/commands.ts +0 -573
  7. package/src/core/adr-exporter.ts +0 -253
  8. package/src/core/architecture/architecture-enforcement.ts +0 -228
  9. package/src/core/architecture/duplicate-detector.ts +0 -288
  10. package/src/core/architecture/index.ts +0 -6
  11. package/src/core/architecture/pattern-learner.ts +0 -306
  12. package/src/core/architecture/pattern-library.ts +0 -403
  13. package/src/core/architecture/pattern-validator.ts +0 -324
  14. package/src/core/change-intelligence/bug-correlator.ts +0 -544
  15. package/src/core/change-intelligence/change-intelligence.ts +0 -264
  16. package/src/core/change-intelligence/change-tracker.ts +0 -334
  17. package/src/core/change-intelligence/fix-suggester.ts +0 -340
  18. package/src/core/change-intelligence/index.ts +0 -5
  19. package/src/core/code-verifier.ts +0 -843
  20. package/src/core/confidence/confidence-scorer.ts +0 -251
  21. package/src/core/confidence/conflict-checker.ts +0 -289
  22. package/src/core/confidence/index.ts +0 -5
  23. package/src/core/confidence/source-tracker.ts +0 -263
  24. package/src/core/confidence/warning-detector.ts +0 -241
  25. package/src/core/context-rot/compaction.ts +0 -284
  26. package/src/core/context-rot/context-health.ts +0 -243
  27. package/src/core/context-rot/context-rot-prevention.ts +0 -213
  28. package/src/core/context-rot/critical-context.ts +0 -221
  29. package/src/core/context-rot/drift-detector.ts +0 -255
  30. package/src/core/context-rot/index.ts +0 -7
  31. package/src/core/context.ts +0 -263
  32. package/src/core/decision-extractor.ts +0 -339
  33. package/src/core/decisions.ts +0 -69
  34. package/src/core/deja-vu.ts +0 -421
  35. package/src/core/engine.ts +0 -1646
  36. package/src/core/feature-context.ts +0 -726
  37. package/src/core/ghost-mode.ts +0 -465
  38. package/src/core/learning.ts +0 -519
  39. package/src/core/living-docs/activity-tracker.ts +0 -296
  40. package/src/core/living-docs/architecture-generator.ts +0 -428
  41. package/src/core/living-docs/changelog-generator.ts +0 -348
  42. package/src/core/living-docs/component-generator.ts +0 -230
  43. package/src/core/living-docs/doc-engine.ts +0 -134
  44. package/src/core/living-docs/doc-validator.ts +0 -282
  45. package/src/core/living-docs/index.ts +0 -8
  46. package/src/core/project-manager.ts +0 -301
  47. package/src/core/refresh/activity-gate.ts +0 -256
  48. package/src/core/refresh/git-staleness-checker.ts +0 -108
  49. package/src/core/refresh/index.ts +0 -27
  50. package/src/core/summarizer.ts +0 -290
  51. package/src/core/test-awareness/change-validator.ts +0 -499
  52. package/src/core/test-awareness/index.ts +0 -5
  53. package/src/index.ts +0 -90
  54. package/src/indexing/ast.ts +0 -868
  55. package/src/indexing/embeddings.ts +0 -85
  56. package/src/indexing/indexer.ts +0 -270
  57. package/src/indexing/watcher.ts +0 -78
  58. package/src/server/gateways/aggregator.ts +0 -374
  59. package/src/server/gateways/index.ts +0 -473
  60. package/src/server/gateways/memory-ghost.ts +0 -343
  61. package/src/server/gateways/memory-query.ts +0 -452
  62. package/src/server/gateways/memory-record.ts +0 -346
  63. package/src/server/gateways/memory-review.ts +0 -410
  64. package/src/server/gateways/memory-status.ts +0 -517
  65. package/src/server/gateways/memory-verify.ts +0 -392
  66. package/src/server/gateways/router.ts +0 -434
  67. package/src/server/gateways/types.ts +0 -610
  68. package/src/server/http.ts +0 -228
  69. package/src/server/mcp.ts +0 -154
  70. package/src/server/resources.ts +0 -85
  71. package/src/server/tools.ts +0 -2460
  72. package/src/storage/database.ts +0 -271
  73. package/src/storage/tier1.ts +0 -135
  74. package/src/storage/tier2.ts +0 -972
  75. package/src/storage/tier3.ts +0 -123
  76. package/src/types/documentation.ts +0 -619
  77. package/src/types/index.ts +0 -222
  78. package/src/utils/config.ts +0 -194
  79. package/src/utils/files.ts +0 -117
  80. package/src/utils/time.ts +0 -37
  81. package/src/utils/tokens.ts +0 -52
@@ -1,2460 +0,0 @@
1
- import type { NeuronLayerEngine } from '../core/engine.js';
2
-
3
- export interface ToolDefinition {
4
- name: string;
5
- description: string;
6
- inputSchema: {
7
- type: 'object';
8
- properties: Record<string, unknown>;
9
- required?: string[];
10
- };
11
- }
12
-
13
- export const toolDefinitions: ToolDefinition[] = [
14
- {
15
- name: 'get_context',
16
- description: 'Get relevant codebase context for a query. Use this to understand code, find related files, and get architectural decisions.',
17
- inputSchema: {
18
- type: 'object',
19
- properties: {
20
- query: {
21
- type: 'string',
22
- description: 'What you are trying to understand or do'
23
- },
24
- current_file: {
25
- type: 'string',
26
- description: 'Path to the file currently being discussed (optional)'
27
- },
28
- max_tokens: {
29
- type: 'number',
30
- description: 'Maximum tokens to return (default: 6000)'
31
- }
32
- },
33
- required: ['query']
34
- }
35
- },
36
- {
37
- name: 'search_codebase',
38
- description: 'Search the codebase semantically. Returns files and code snippets matching the query.',
39
- inputSchema: {
40
- type: 'object',
41
- properties: {
42
- query: {
43
- type: 'string',
44
- description: 'Search query'
45
- },
46
- limit: {
47
- type: 'number',
48
- description: 'Maximum number of results (default: 10)'
49
- }
50
- },
51
- required: ['query']
52
- }
53
- },
54
- {
55
- name: 'record_decision',
56
- description: 'Record an architectural or design decision. Use this to save important decisions about the codebase.',
57
- inputSchema: {
58
- type: 'object',
59
- properties: {
60
- title: {
61
- type: 'string',
62
- description: 'Short title for the decision'
63
- },
64
- description: {
65
- type: 'string',
66
- description: 'Why this decision was made, context, tradeoffs'
67
- },
68
- files: {
69
- type: 'array',
70
- items: { type: 'string' },
71
- description: 'Related files (optional)'
72
- },
73
- tags: {
74
- type: 'array',
75
- items: { type: 'string' },
76
- description: 'Tags like "architecture", "database", "security" (optional)'
77
- }
78
- },
79
- required: ['title', 'description']
80
- }
81
- },
82
- {
83
- name: 'get_file_context',
84
- description: 'Get the content and metadata of a specific file.',
85
- inputSchema: {
86
- type: 'object',
87
- properties: {
88
- path: {
89
- type: 'string',
90
- description: 'Relative path to the file'
91
- }
92
- },
93
- required: ['path']
94
- }
95
- },
96
- {
97
- name: 'get_project_summary',
98
- description: 'Get a summary of the project structure, languages, and recent decisions.',
99
- inputSchema: {
100
- type: 'object',
101
- properties: {}
102
- }
103
- },
104
- {
105
- name: 'get_symbol',
106
- description: 'Find a function, class, interface, or type by name. Returns the symbol definition and location.',
107
- inputSchema: {
108
- type: 'object',
109
- properties: {
110
- name: {
111
- type: 'string',
112
- description: 'Name of the symbol to find (function, class, interface, or type)'
113
- },
114
- kind: {
115
- type: 'string',
116
- enum: ['function', 'class', 'interface', 'type', 'method', 'enum'],
117
- description: 'Type of symbol to find (optional, searches all if not specified)'
118
- },
119
- limit: {
120
- type: 'number',
121
- description: 'Maximum number of results (default: 10)'
122
- }
123
- },
124
- required: ['name']
125
- }
126
- },
127
- {
128
- name: 'get_dependencies',
129
- description: 'Get the dependencies of a file - what it imports and what imports it.',
130
- inputSchema: {
131
- type: 'object',
132
- properties: {
133
- path: {
134
- type: 'string',
135
- description: 'Relative path to the file'
136
- }
137
- },
138
- required: ['path']
139
- }
140
- },
141
- {
142
- name: 'find_circular_deps',
143
- description: 'Find circular dependencies in the project. Circular imports cause subtle bugs, make refactoring dangerous, and can lead to undefined values at runtime. Use this to detect and fix import cycles.',
144
- inputSchema: {
145
- type: 'object',
146
- properties: {},
147
- required: []
148
- }
149
- },
150
- {
151
- name: 'get_impact_analysis',
152
- description: 'Analyze the full impact of changing a file. Shows all directly and indirectly affected files, affected tests, and circular dependencies. Use this BEFORE making changes to understand the blast radius and risk level.',
153
- inputSchema: {
154
- type: 'object',
155
- properties: {
156
- file: {
157
- type: 'string',
158
- description: 'File path to analyze impact for'
159
- },
160
- depth: {
161
- type: 'number',
162
- description: 'How many hops to follow in the dependency graph (default: 3)'
163
- },
164
- include_tests: {
165
- type: 'boolean',
166
- description: 'Include affected tests in the analysis (default: true)'
167
- }
168
- },
169
- required: ['file']
170
- }
171
- },
172
- {
173
- name: 'get_file_summary',
174
- description: 'Get a compressed summary of a file (10x smaller than full content). Use this for quick overview without reading full file.',
175
- inputSchema: {
176
- type: 'object',
177
- properties: {
178
- path: {
179
- type: 'string',
180
- description: 'Relative path to the file'
181
- }
182
- },
183
- required: ['path']
184
- }
185
- },
186
- {
187
- name: 'get_predicted_files',
188
- description: 'Get files predicted to be relevant based on current context and query. Useful for proactive exploration.',
189
- inputSchema: {
190
- type: 'object',
191
- properties: {
192
- current_file: {
193
- type: 'string',
194
- description: 'Path to the current file being discussed'
195
- },
196
- query: {
197
- type: 'string',
198
- description: 'What you are trying to understand or do'
199
- }
200
- },
201
- required: ['current_file', 'query']
202
- }
203
- },
204
- {
205
- name: 'get_learning_stats',
206
- description: 'Get usage statistics and learning metrics for the project.',
207
- inputSchema: {
208
- type: 'object',
209
- properties: {}
210
- }
211
- },
212
- {
213
- name: 'mark_context_useful',
214
- description: 'Provide feedback on whether the retrieved context was useful. Helps improve future retrieval.',
215
- inputSchema: {
216
- type: 'object',
217
- properties: {
218
- query: {
219
- type: 'string',
220
- description: 'The query that was made'
221
- },
222
- was_useful: {
223
- type: 'boolean',
224
- description: 'Whether the context was useful'
225
- }
226
- },
227
- required: ['query', 'was_useful']
228
- }
229
- },
230
- // Phase 4: Multi-project tools
231
- {
232
- name: 'list_projects',
233
- description: 'List all registered projects across your system.',
234
- inputSchema: {
235
- type: 'object',
236
- properties: {}
237
- }
238
- },
239
- {
240
- name: 'switch_project',
241
- description: 'Switch to a different registered project.',
242
- inputSchema: {
243
- type: 'object',
244
- properties: {
245
- project_id: {
246
- type: 'string',
247
- description: 'The project ID to switch to'
248
- }
249
- },
250
- required: ['project_id']
251
- }
252
- },
253
- {
254
- name: 'search_all_projects',
255
- description: 'Search across all registered projects for code or files.',
256
- inputSchema: {
257
- type: 'object',
258
- properties: {
259
- query: {
260
- type: 'string',
261
- description: 'Search query'
262
- },
263
- limit: {
264
- type: 'number',
265
- description: 'Maximum results per project (default: 5)'
266
- }
267
- },
268
- required: ['query']
269
- }
270
- },
271
- {
272
- name: 'record_decision_with_author',
273
- description: 'Record an architectural decision with author attribution and status.',
274
- inputSchema: {
275
- type: 'object',
276
- properties: {
277
- title: {
278
- type: 'string',
279
- description: 'Short title for the decision'
280
- },
281
- description: {
282
- type: 'string',
283
- description: 'Why this decision was made, context, tradeoffs'
284
- },
285
- author: {
286
- type: 'string',
287
- description: 'Author of the decision'
288
- },
289
- status: {
290
- type: 'string',
291
- enum: ['proposed', 'accepted', 'deprecated', 'superseded'],
292
- description: 'Status of the decision (default: accepted)'
293
- },
294
- files: {
295
- type: 'array',
296
- items: { type: 'string' },
297
- description: 'Related files (optional)'
298
- },
299
- tags: {
300
- type: 'array',
301
- items: { type: 'string' },
302
- description: 'Tags (optional)'
303
- }
304
- },
305
- required: ['title', 'description', 'author']
306
- }
307
- },
308
- {
309
- name: 'update_decision_status',
310
- description: 'Update the status of an existing decision (e.g., mark as deprecated or superseded).',
311
- inputSchema: {
312
- type: 'object',
313
- properties: {
314
- decision_id: {
315
- type: 'string',
316
- description: 'ID of the decision to update'
317
- },
318
- status: {
319
- type: 'string',
320
- enum: ['proposed', 'accepted', 'deprecated', 'superseded'],
321
- description: 'New status for the decision'
322
- },
323
- superseded_by: {
324
- type: 'string',
325
- description: 'ID of the decision that supersedes this one (if status is superseded)'
326
- }
327
- },
328
- required: ['decision_id', 'status']
329
- }
330
- },
331
- {
332
- name: 'export_decisions_to_adr',
333
- description: 'Export all decisions to ADR (Architecture Decision Records) markdown files.',
334
- inputSchema: {
335
- type: 'object',
336
- properties: {
337
- output_dir: {
338
- type: 'string',
339
- description: 'Output directory for ADR files (default: docs/decisions)'
340
- },
341
- format: {
342
- type: 'string',
343
- enum: ['madr', 'nygard', 'simple'],
344
- description: 'ADR format to use (default: madr)'
345
- },
346
- include_index: {
347
- type: 'boolean',
348
- description: 'Generate README index file (default: true)'
349
- }
350
- }
351
- }
352
- },
353
- {
354
- name: 'discover_projects',
355
- description: 'Discover potential projects in common locations on your system.',
356
- inputSchema: {
357
- type: 'object',
358
- properties: {}
359
- }
360
- },
361
- // Phase 5: Active Feature Context tools
362
- {
363
- name: 'get_active_context',
364
- description: 'Get the current feature context including files being worked on, recent changes, and recent questions. Use this to understand what the user is currently working on.',
365
- inputSchema: {
366
- type: 'object',
367
- properties: {}
368
- }
369
- },
370
- {
371
- name: 'set_feature_context',
372
- description: 'Start tracking a new feature. Tell NeuronLayer what you are working on for better context.',
373
- inputSchema: {
374
- type: 'object',
375
- properties: {
376
- name: {
377
- type: 'string',
378
- description: 'Name of the feature (e.g., "payment integration", "auth refactor")'
379
- },
380
- files: {
381
- type: 'array',
382
- items: { type: 'string' },
383
- description: 'Initial files to track (optional)'
384
- }
385
- },
386
- required: ['name']
387
- }
388
- },
389
- {
390
- name: 'list_recent_contexts',
391
- description: 'List recently worked on features/contexts that can be switched back to.',
392
- inputSchema: {
393
- type: 'object',
394
- properties: {}
395
- }
396
- },
397
- {
398
- name: 'switch_feature_context',
399
- description: 'Switch back to a previously worked on feature context.',
400
- inputSchema: {
401
- type: 'object',
402
- properties: {
403
- context_id: {
404
- type: 'string',
405
- description: 'ID of the context to switch to (from list_recent_contexts)'
406
- }
407
- },
408
- required: ['context_id']
409
- }
410
- },
411
- // Phase 6: Living Documentation tools
412
- {
413
- name: 'generate_docs',
414
- description: 'Generate documentation for a file or the entire architecture.',
415
- inputSchema: {
416
- type: 'object',
417
- properties: {
418
- path: {
419
- type: 'string',
420
- description: 'Path to document (omit for architecture overview)'
421
- },
422
- type: {
423
- type: 'string',
424
- enum: ['component', 'architecture'],
425
- description: 'Type of documentation to generate'
426
- }
427
- }
428
- }
429
- },
430
- {
431
- name: 'get_architecture',
432
- description: 'Get project architecture overview with layers, data flow, and ASCII diagram.',
433
- inputSchema: {
434
- type: 'object',
435
- properties: {}
436
- }
437
- },
438
- {
439
- name: 'get_component_doc',
440
- description: 'Get detailed documentation for a component/file including public interface, dependencies, and change history.',
441
- inputSchema: {
442
- type: 'object',
443
- properties: {
444
- path: {
445
- type: 'string',
446
- description: 'Relative path to the file'
447
- }
448
- },
449
- required: ['path']
450
- }
451
- },
452
- {
453
- name: 'get_changelog',
454
- description: 'Get changelog of recent changes grouped by day.',
455
- inputSchema: {
456
- type: 'object',
457
- properties: {
458
- since: {
459
- type: 'string',
460
- description: 'Time period: "yesterday", "today", "this week", "this month", or a date'
461
- },
462
- group_by: {
463
- type: 'string',
464
- enum: ['day', 'week'],
465
- description: 'How to group changes (default: day)'
466
- },
467
- include_decisions: {
468
- type: 'boolean',
469
- description: 'Include decisions made during this period (default: false)'
470
- }
471
- }
472
- }
473
- },
474
- {
475
- name: 'validate_docs',
476
- description: 'Check for outdated documentation and calculate documentation score.',
477
- inputSchema: {
478
- type: 'object',
479
- properties: {}
480
- }
481
- },
482
- {
483
- name: 'what_happened',
484
- description: 'Query recent project activity - commits, file changes, and decisions.',
485
- inputSchema: {
486
- type: 'object',
487
- properties: {
488
- since: {
489
- type: 'string',
490
- description: 'Time period: "yesterday", "today", "this week", "this month", or a date'
491
- },
492
- scope: {
493
- type: 'string',
494
- description: 'Limit to a specific directory or file path (optional)'
495
- }
496
- },
497
- required: ['since']
498
- }
499
- },
500
- {
501
- name: 'find_undocumented',
502
- description: 'Find code that lacks documentation - exported functions, classes, and interfaces without docstrings.',
503
- inputSchema: {
504
- type: 'object',
505
- properties: {
506
- importance: {
507
- type: 'string',
508
- enum: ['low', 'medium', 'high', 'all'],
509
- description: 'Filter by importance level (default: all)'
510
- },
511
- type: {
512
- type: 'string',
513
- enum: ['file', 'function', 'class', 'interface', 'all'],
514
- description: 'Filter by symbol type (default: all)'
515
- }
516
- }
517
- }
518
- },
519
- // Phase 7: Context Rot Prevention tools
520
- {
521
- name: 'get_context_health',
522
- description: 'Check current context health, detect drift, and get compaction suggestions.',
523
- inputSchema: {
524
- type: 'object',
525
- properties: {
526
- include_history: {
527
- type: 'boolean',
528
- description: 'Include health history (default: false)'
529
- }
530
- }
531
- }
532
- },
533
- {
534
- name: 'trigger_compaction',
535
- description: 'Manually trigger context compaction to reduce token usage.',
536
- inputSchema: {
537
- type: 'object',
538
- properties: {
539
- strategy: {
540
- type: 'string',
541
- enum: ['summarize', 'selective', 'aggressive'],
542
- description: 'Compaction strategy: summarize (gentle), selective (moderate), aggressive (maximum reduction)'
543
- },
544
- preserve_recent: {
545
- type: 'number',
546
- description: 'Number of recent messages to preserve (default: 10)'
547
- },
548
- target_utilization: {
549
- type: 'number',
550
- description: 'Target utilization percentage (e.g., 50 for 50%)'
551
- }
552
- }
553
- }
554
- },
555
- {
556
- name: 'mark_critical',
557
- description: 'Mark content as critical - it will never be compressed or removed.',
558
- inputSchema: {
559
- type: 'object',
560
- properties: {
561
- content: {
562
- type: 'string',
563
- description: 'The critical content to preserve'
564
- },
565
- type: {
566
- type: 'string',
567
- enum: ['decision', 'requirement', 'instruction', 'custom'],
568
- description: 'Type of critical content'
569
- },
570
- reason: {
571
- type: 'string',
572
- description: 'Why this is critical (optional)'
573
- }
574
- },
575
- required: ['content']
576
- }
577
- },
578
- {
579
- name: 'get_critical_context',
580
- description: 'Get all marked critical context items.',
581
- inputSchema: {
582
- type: 'object',
583
- properties: {
584
- type: {
585
- type: 'string',
586
- enum: ['decision', 'requirement', 'instruction', 'custom'],
587
- description: 'Filter by type (optional)'
588
- }
589
- }
590
- }
591
- },
592
- // Phase 8: Confidence Scoring tools
593
- {
594
- name: 'get_confidence',
595
- description: 'Get confidence score for a code suggestion. Shows how confident the AI should be based on codebase matches, decision alignment, and pattern matching.',
596
- inputSchema: {
597
- type: 'object',
598
- properties: {
599
- code: {
600
- type: 'string',
601
- description: 'The code to evaluate confidence for'
602
- },
603
- context: {
604
- type: 'string',
605
- description: 'What this code is for (optional context)'
606
- }
607
- },
608
- required: ['code']
609
- }
610
- },
611
- {
612
- name: 'list_sources',
613
- description: 'List all sources used for a code suggestion - codebase matches, related decisions, and matched patterns.',
614
- inputSchema: {
615
- type: 'object',
616
- properties: {
617
- code: {
618
- type: 'string',
619
- description: 'The code to find sources for'
620
- },
621
- context: {
622
- type: 'string',
623
- description: 'What this code is for (optional)'
624
- },
625
- include_snippets: {
626
- type: 'boolean',
627
- description: 'Include code snippets from matches (default: false)'
628
- }
629
- },
630
- required: ['code']
631
- }
632
- },
633
- {
634
- name: 'check_conflicts',
635
- description: 'Check if code conflicts with past architectural decisions.',
636
- inputSchema: {
637
- type: 'object',
638
- properties: {
639
- code: {
640
- type: 'string',
641
- description: 'The code to check for conflicts'
642
- }
643
- },
644
- required: ['code']
645
- }
646
- },
647
- // Phase 9: Change Intelligence tools
648
- {
649
- name: 'what_changed',
650
- description: 'Query what changed in the codebase. Returns file changes, authors, and line counts.',
651
- inputSchema: {
652
- type: 'object',
653
- properties: {
654
- since: {
655
- type: 'string',
656
- description: 'Time period: "yesterday", "today", "this week", "last week", or a date'
657
- },
658
- file: {
659
- type: 'string',
660
- description: 'Filter to specific file or folder (optional)'
661
- },
662
- author: {
663
- type: 'string',
664
- description: 'Filter by author name (optional)'
665
- }
666
- },
667
- required: ['since']
668
- }
669
- },
670
- {
671
- name: 'why_broke',
672
- description: 'Diagnose why something broke. Correlates errors with recent changes and finds similar past bugs.',
673
- inputSchema: {
674
- type: 'object',
675
- properties: {
676
- error: {
677
- type: 'string',
678
- description: 'The error message or symptom'
679
- },
680
- file: {
681
- type: 'string',
682
- description: 'File where error occurs (optional)'
683
- },
684
- line: {
685
- type: 'number',
686
- description: 'Line number (optional)'
687
- }
688
- },
689
- required: ['error']
690
- }
691
- },
692
- {
693
- name: 'find_similar_bugs',
694
- description: 'Find similar bugs from history with their fixes.',
695
- inputSchema: {
696
- type: 'object',
697
- properties: {
698
- error: {
699
- type: 'string',
700
- description: 'Error message to search for'
701
- },
702
- limit: {
703
- type: 'number',
704
- description: 'Max results (default 5)'
705
- }
706
- },
707
- required: ['error']
708
- }
709
- },
710
- {
711
- name: 'suggest_fix',
712
- description: 'Get fix suggestions for an error based on history and patterns.',
713
- inputSchema: {
714
- type: 'object',
715
- properties: {
716
- error: {
717
- type: 'string',
718
- description: 'Error to fix'
719
- },
720
- context: {
721
- type: 'string',
722
- description: 'Additional context (e.g., "database query", "API call")'
723
- }
724
- },
725
- required: ['error']
726
- }
727
- },
728
- // Phase 10: Architecture Enforcement tools
729
- {
730
- name: 'validate_pattern',
731
- description: 'Validate code against established project patterns. Returns a score, violations, and suggestions for improvement.',
732
- inputSchema: {
733
- type: 'object',
734
- properties: {
735
- code: {
736
- type: 'string',
737
- description: 'The code to validate against patterns'
738
- },
739
- type: {
740
- type: 'string',
741
- enum: ['error_handling', 'api_call', 'component', 'state_management', 'data_fetching', 'authentication', 'validation', 'logging', 'custom', 'auto'],
742
- description: 'Type of pattern to validate against (default: auto-detect)'
743
- }
744
- },
745
- required: ['code']
746
- }
747
- },
748
- {
749
- name: 'suggest_existing',
750
- description: 'Find existing functions that match your intent. Prevents creating duplicate functionality.',
751
- inputSchema: {
752
- type: 'object',
753
- properties: {
754
- intent: {
755
- type: 'string',
756
- description: 'What you are trying to do (e.g., "validate email", "format date", "fetch user data")'
757
- },
758
- limit: {
759
- type: 'number',
760
- description: 'Maximum number of suggestions (default: 5)'
761
- }
762
- },
763
- required: ['intent']
764
- }
765
- },
766
- {
767
- name: 'learn_pattern',
768
- description: 'Teach a new pattern to the system. The pattern will be stored and used for future validations.',
769
- inputSchema: {
770
- type: 'object',
771
- properties: {
772
- code: {
773
- type: 'string',
774
- description: 'Example code that demonstrates the pattern'
775
- },
776
- name: {
777
- type: 'string',
778
- description: 'Name for this pattern (e.g., "API Error Handler", "Form Validation")'
779
- },
780
- description: {
781
- type: 'string',
782
- description: 'Description of when and how to use this pattern'
783
- },
784
- category: {
785
- type: 'string',
786
- enum: ['error_handling', 'api_call', 'component', 'state_management', 'data_fetching', 'authentication', 'validation', 'logging', 'custom'],
787
- description: 'Category for this pattern (auto-detected if not provided)'
788
- }
789
- },
790
- required: ['code', 'name']
791
- }
792
- },
793
- {
794
- name: 'list_patterns',
795
- description: 'List all learned patterns in the project. Can filter by category.',
796
- inputSchema: {
797
- type: 'object',
798
- properties: {
799
- category: {
800
- type: 'string',
801
- enum: ['error_handling', 'api_call', 'component', 'state_management', 'data_fetching', 'authentication', 'validation', 'logging', 'custom'],
802
- description: 'Filter by pattern category (optional)'
803
- }
804
- }
805
- }
806
- },
807
- {
808
- name: 'get_pattern',
809
- description: 'Get details of a specific pattern including examples, anti-patterns, and rules.',
810
- inputSchema: {
811
- type: 'object',
812
- properties: {
813
- id: {
814
- type: 'string',
815
- description: 'Pattern ID to retrieve'
816
- }
817
- },
818
- required: ['id']
819
- }
820
- },
821
- {
822
- name: 'add_pattern_example',
823
- description: 'Add an example or anti-pattern to an existing pattern.',
824
- inputSchema: {
825
- type: 'object',
826
- properties: {
827
- pattern_id: {
828
- type: 'string',
829
- description: 'ID of the pattern to add to'
830
- },
831
- code: {
832
- type: 'string',
833
- description: 'Example code'
834
- },
835
- explanation: {
836
- type: 'string',
837
- description: 'Explanation of this example'
838
- },
839
- is_anti_pattern: {
840
- type: 'boolean',
841
- description: 'If true, marks this as what NOT to do (default: false)'
842
- }
843
- },
844
- required: ['pattern_id', 'code', 'explanation']
845
- }
846
- },
847
- {
848
- name: 'get_architecture_stats',
849
- description: 'Get statistics about patterns and functions in the codebase.',
850
- inputSchema: {
851
- type: 'object',
852
- properties: {}
853
- }
854
- },
855
- // Phase 11: Test-Aware Suggestions tools
856
- {
857
- name: 'get_related_tests',
858
- description: 'Get tests related to a file or function. Use this to understand test coverage before making changes.',
859
- inputSchema: {
860
- type: 'object',
861
- properties: {
862
- file: {
863
- type: 'string',
864
- description: 'File path to find tests for'
865
- },
866
- function: {
867
- type: 'string',
868
- description: 'Function name to find tests for (optional)'
869
- }
870
- },
871
- required: ['file']
872
- }
873
- },
874
- {
875
- name: 'check_tests',
876
- description: 'Check if a code change would break tests. Returns predicted failures and suggested fixes.',
877
- inputSchema: {
878
- type: 'object',
879
- properties: {
880
- change: {
881
- type: 'string',
882
- description: 'The proposed code change'
883
- },
884
- file: {
885
- type: 'string',
886
- description: 'File being changed'
887
- }
888
- },
889
- required: ['change', 'file']
890
- }
891
- },
892
- {
893
- name: 'suggest_test_update',
894
- description: 'Get suggested test updates for a code change. Use this after check_tests shows failures.',
895
- inputSchema: {
896
- type: 'object',
897
- properties: {
898
- change: {
899
- type: 'string',
900
- description: 'The code change'
901
- },
902
- failing_tests: {
903
- type: 'array',
904
- items: { type: 'string' },
905
- description: 'Test IDs that would fail (optional, from check_tests)'
906
- }
907
- },
908
- required: ['change']
909
- }
910
- },
911
- {
912
- name: 'get_test_coverage',
913
- description: 'Get test coverage for a file. Shows which functions are covered and which need tests.',
914
- inputSchema: {
915
- type: 'object',
916
- properties: {
917
- file: {
918
- type: 'string',
919
- description: 'File path to check coverage for'
920
- }
921
- },
922
- required: ['file']
923
- }
924
- },
925
- // Intelligent Refresh System tools
926
- {
927
- name: 'memory_refresh',
928
- description: 'Trigger a manual refresh of the memory layer. Syncs git changes, updates importance scores, and executes pending maintenance tasks. Use this when you need the latest state after external changes (e.g., git pull).',
929
- inputSchema: {
930
- type: 'object',
931
- properties: {
932
- force: {
933
- type: 'boolean',
934
- description: 'Force refresh even if no changes detected (default: false)'
935
- }
936
- }
937
- }
938
- },
939
- {
940
- name: 'get_refresh_status',
941
- description: 'Get the current status of the intelligent refresh system including idle tasks, last activity, and git state.',
942
- inputSchema: {
943
- type: 'object',
944
- properties: {}
945
- }
946
- }
947
- ];
948
-
949
- export async function handleToolCall(
950
- engine: NeuronLayerEngine,
951
- toolName: string,
952
- args: Record<string, unknown>
953
- ): Promise<unknown> {
954
- switch (toolName) {
955
- case 'get_context': {
956
- const query = args.query as string;
957
- const currentFile = args.current_file as string | undefined;
958
- const maxTokens = args.max_tokens as number | undefined;
959
-
960
- const result = await engine.getContext(query, currentFile, maxTokens);
961
-
962
- return {
963
- context: result.context,
964
- sources: result.sources,
965
- token_count: result.tokenCount,
966
- decisions: result.decisions.map(d => ({
967
- id: d.id,
968
- title: d.title,
969
- description: d.description,
970
- created_at: d.createdAt.toISOString()
971
- }))
972
- };
973
- }
974
-
975
- case 'search_codebase': {
976
- const query = args.query as string;
977
- const limit = (args.limit as number) || 10;
978
-
979
- const results = await engine.searchCodebase(query, limit);
980
-
981
- return {
982
- results: results.map(r => ({
983
- file: r.file,
984
- preview: r.preview,
985
- relevance: r.similarity,
986
- line_start: r.lineStart,
987
- line_end: r.lineEnd
988
- }))
989
- };
990
- }
991
-
992
- case 'record_decision': {
993
- const title = args.title as string;
994
- const description = args.description as string;
995
- const files = args.files as string[] | undefined;
996
- const tags = args.tags as string[] | undefined;
997
-
998
- const decision = await engine.recordDecision(title, description, files, tags);
999
-
1000
- return {
1001
- id: decision.id,
1002
- title: decision.title,
1003
- description: decision.description,
1004
- files: decision.files,
1005
- tags: decision.tags,
1006
- created_at: decision.createdAt.toISOString(),
1007
- message: 'Decision recorded successfully'
1008
- };
1009
- }
1010
-
1011
- case 'get_file_context': {
1012
- const path = args.path as string;
1013
-
1014
- const result = await engine.getFileContext(path);
1015
-
1016
- if (!result) {
1017
- return {
1018
- error: `File not found: ${path}`
1019
- };
1020
- }
1021
-
1022
- return {
1023
- path,
1024
- content: result.content,
1025
- language: result.language,
1026
- lines: result.lines
1027
- };
1028
- }
1029
-
1030
- case 'get_project_summary': {
1031
- const summary = engine.getProjectSummary();
1032
-
1033
- return {
1034
- name: summary.name,
1035
- description: summary.description,
1036
- languages: summary.languages,
1037
- total_files: summary.totalFiles,
1038
- total_lines: summary.totalLines,
1039
- key_directories: summary.keyDirectories,
1040
- recent_decisions: summary.recentDecisions.map(d => ({
1041
- id: d.id,
1042
- title: d.title,
1043
- description: d.description,
1044
- created_at: d.createdAt.toISOString()
1045
- })),
1046
- dependencies: summary.dependencies,
1047
- architecture_notes: summary.architectureNotes
1048
- };
1049
- }
1050
-
1051
- case 'get_symbol': {
1052
- const name = args.name as string;
1053
- const kind = args.kind as string | undefined;
1054
- const limit = (args.limit as number) || 10;
1055
-
1056
- const results = await engine.searchSymbols(name, kind, limit);
1057
-
1058
- if (results.length === 0) {
1059
- return {
1060
- message: `No symbols found matching "${name}"`,
1061
- results: []
1062
- };
1063
- }
1064
-
1065
- return {
1066
- results: results.map(s => ({
1067
- name: s.name,
1068
- kind: s.kind,
1069
- file: s.filePath,
1070
- line_start: s.lineStart,
1071
- line_end: s.lineEnd,
1072
- signature: s.signature || null,
1073
- exported: s.exported
1074
- }))
1075
- };
1076
- }
1077
-
1078
- case 'get_dependencies': {
1079
- const path = args.path as string;
1080
-
1081
- const result = engine.getFileDependencies(path);
1082
-
1083
- return {
1084
- file: path,
1085
- imports: result.imports,
1086
- imported_by: result.importedBy,
1087
- symbols: result.symbols
1088
- };
1089
- }
1090
-
1091
- case 'find_circular_deps': {
1092
- const cycles = engine.findCircularDependencies();
1093
-
1094
- if (cycles.length === 0) {
1095
- return {
1096
- status: 'clean',
1097
- message: 'No circular dependencies found',
1098
- cycles: []
1099
- };
1100
- }
1101
-
1102
- return {
1103
- status: 'cycles_found',
1104
- message: `Found ${cycles.length} circular dependency chain(s)`,
1105
- cycles: cycles.map((cycle, i) => ({
1106
- id: i + 1,
1107
- files: cycle,
1108
- length: cycle.length - 1, // -1 because last element repeats first
1109
- description: cycle.join(' → ')
1110
- })),
1111
- recommendation: 'Break cycles by extracting shared code into a separate module, using dependency injection, or restructuring imports.'
1112
- };
1113
- }
1114
-
1115
- case 'get_impact_analysis': {
1116
- const filePath = args.file as string;
1117
- const depth = (args.depth as number) || 3;
1118
- const includeTests = args.include_tests !== false;
1119
-
1120
- // Get transitive dependents (files affected by changing this file)
1121
- const affected = engine.getTransitiveDependents(filePath, depth);
1122
-
1123
- // Get what this file imports
1124
- const deps = engine.getFileDependencies(filePath);
1125
-
1126
- // Get affected tests if requested
1127
- let affectedTests: Array<{ name: string; file: string }> = [];
1128
- if (includeTests) {
1129
- const allAffectedFiles = [filePath, ...affected.map(a => a.file)];
1130
- const testSet = new Set<string>();
1131
-
1132
- for (const f of allAffectedFiles) {
1133
- const tests = engine.getTestsForFile(f);
1134
- for (const t of tests) {
1135
- if (!testSet.has(t.id)) {
1136
- testSet.add(t.id);
1137
- affectedTests.push({ name: t.name, file: t.file });
1138
- }
1139
- }
1140
- }
1141
- }
1142
-
1143
- // Check for circular dependencies involving this file
1144
- const allCycles = engine.findCircularDependencies();
1145
- const relevantCycles = allCycles.filter(cycle => cycle.includes(filePath));
1146
-
1147
- // Calculate risk level
1148
- const totalAffected = affected.length;
1149
- const riskLevel = totalAffected > 10 ? 'HIGH' : totalAffected > 5 ? 'MEDIUM' : 'LOW';
1150
-
1151
- // Build risk factors
1152
- const riskFactors: string[] = [];
1153
- if (totalAffected > 10) riskFactors.push(`${totalAffected} files depend on this`);
1154
- if (relevantCycles.length > 0) riskFactors.push(`Involved in ${relevantCycles.length} circular dependency chain(s)`);
1155
- if (affectedTests.length > 5) riskFactors.push(`${affectedTests.length} tests may need updates`);
1156
- if (deps.imports.length > 10) riskFactors.push(`File has ${deps.imports.length} dependencies`);
1157
-
1158
- return {
1159
- file: filePath,
1160
- risk_level: riskLevel,
1161
- risk_factors: riskFactors.length > 0 ? riskFactors : ['No significant risk factors detected'],
1162
- summary: {
1163
- total_affected_files: totalAffected,
1164
- direct_dependents: affected.filter(a => a.depth === 1).length,
1165
- indirect_dependents: affected.filter(a => a.depth > 1).length,
1166
- affected_tests: affectedTests.length,
1167
- circular_dependencies: relevantCycles.length
1168
- },
1169
- direct_dependents: affected.filter(a => a.depth === 1).map(a => ({
1170
- file: a.file,
1171
- imports: a.imports
1172
- })),
1173
- indirect_dependents: affected.filter(a => a.depth > 1).map(a => ({
1174
- file: a.file,
1175
- depth: a.depth,
1176
- imports: a.imports
1177
- })),
1178
- this_file_imports: deps.imports.map(i => i.file),
1179
- affected_tests: affectedTests,
1180
- circular_dependencies: relevantCycles.map(cycle => cycle.join(' → ')),
1181
- recommendation: riskLevel === 'HIGH'
1182
- ? 'High-impact change. Consider breaking it into smaller changes and testing incrementally.'
1183
- : riskLevel === 'MEDIUM'
1184
- ? 'Moderate impact. Review affected files and ensure tests cover the changes.'
1185
- : 'Low-risk change. Standard review and testing should suffice.'
1186
- };
1187
- }
1188
-
1189
- case 'get_file_summary': {
1190
- const path = args.path as string;
1191
-
1192
- const summary = engine.getFileSummary(path);
1193
-
1194
- if (!summary) {
1195
- return {
1196
- error: `File not found or no summary available: ${path}`
1197
- };
1198
- }
1199
-
1200
- return {
1201
- path,
1202
- summary,
1203
- message: 'Compressed summary (use get_file_context for full content)'
1204
- };
1205
- }
1206
-
1207
- case 'get_predicted_files': {
1208
- const currentFile = args.current_file as string;
1209
- const query = args.query as string;
1210
-
1211
- const predicted = engine.getPredictedFiles(currentFile, query);
1212
-
1213
- // Pre-fetch these files into hot cache
1214
- const preFetched = await engine.preFetchFiles(currentFile, query);
1215
-
1216
- return {
1217
- predicted_files: predicted,
1218
- pre_fetched: preFetched,
1219
- message: `Predicted ${predicted.length} relevant files, pre-fetched ${preFetched} into cache`
1220
- };
1221
- }
1222
-
1223
- case 'get_learning_stats': {
1224
- const stats = engine.getLearningStats();
1225
-
1226
- return {
1227
- usage: {
1228
- total_queries: stats.usageStats.totalQueries,
1229
- total_file_views: stats.usageStats.totalFileViews,
1230
- recent_activity: stats.usageStats.recentActivity,
1231
- top_files: stats.usageStats.topFiles
1232
- },
1233
- compression: {
1234
- files_with_summaries: stats.compressionStats.totalFiles,
1235
- avg_compression_ratio: stats.compressionStats.avgCompression.toFixed(1) + 'x',
1236
- tokens_saved: stats.compressionStats.totalTokensSaved
1237
- },
1238
- cache: {
1239
- hot_cache_size: stats.hotCacheStats.size,
1240
- cached_files: stats.hotCacheStats.files
1241
- }
1242
- };
1243
- }
1244
-
1245
- case 'mark_context_useful': {
1246
- const query = args.query as string;
1247
- const wasUseful = args.was_useful as boolean;
1248
-
1249
- engine.markContextUsefulness(query, wasUseful);
1250
-
1251
- return {
1252
- message: `Feedback recorded: context was ${wasUseful ? 'useful' : 'not useful'}`,
1253
- query
1254
- };
1255
- }
1256
-
1257
- // Phase 4: Multi-project tools
1258
- case 'list_projects': {
1259
- const projects = engine.listProjects();
1260
- const activeProject = engine.getActiveProject();
1261
-
1262
- return {
1263
- projects: projects.map(p => ({
1264
- id: p.id,
1265
- name: p.name,
1266
- path: p.path,
1267
- is_active: activeProject?.id === p.id,
1268
- total_files: p.totalFiles,
1269
- total_decisions: p.totalDecisions,
1270
- languages: p.languages,
1271
- last_accessed: new Date(p.lastAccessed).toISOString()
1272
- })),
1273
- active_project: activeProject?.name || null
1274
- };
1275
- }
1276
-
1277
- case 'switch_project': {
1278
- const projectId = args.project_id as string;
1279
- const success = engine.switchProject(projectId);
1280
-
1281
- if (!success) {
1282
- return {
1283
- error: `Project not found: ${projectId}`,
1284
- message: 'Use list_projects to see available projects'
1285
- };
1286
- }
1287
-
1288
- const project = engine.getProject(projectId);
1289
- return {
1290
- message: `Switched to project: ${project?.name}`,
1291
- project: project ? {
1292
- id: project.id,
1293
- name: project.name,
1294
- path: project.path
1295
- } : null
1296
- };
1297
- }
1298
-
1299
- case 'search_all_projects': {
1300
- const query = args.query as string;
1301
- const limit = (args.limit as number) || 5;
1302
-
1303
- const results = await engine.searchAllProjects(query, limit);
1304
-
1305
- return {
1306
- results: results.map(r => ({
1307
- project: r.project,
1308
- project_id: r.projectId,
1309
- matches: r.results.map(m => ({
1310
- file: m.file,
1311
- preview: m.preview,
1312
- relevance: m.similarity
1313
- }))
1314
- })),
1315
- total_projects_searched: results.length
1316
- };
1317
- }
1318
-
1319
- case 'record_decision_with_author': {
1320
- const title = args.title as string;
1321
- const description = args.description as string;
1322
- const author = args.author as string;
1323
- const status = (args.status as 'proposed' | 'accepted' | 'deprecated' | 'superseded') || 'accepted';
1324
- const files = args.files as string[] | undefined;
1325
- const tags = args.tags as string[] | undefined;
1326
-
1327
- const decision = await engine.recordDecisionWithAuthor(
1328
- title,
1329
- description,
1330
- author,
1331
- files,
1332
- tags,
1333
- status
1334
- );
1335
-
1336
- return {
1337
- id: decision.id,
1338
- title: decision.title,
1339
- description: decision.description,
1340
- author: decision.author,
1341
- status: decision.status,
1342
- files: decision.files,
1343
- tags: decision.tags,
1344
- created_at: decision.createdAt.toISOString(),
1345
- message: 'Decision recorded with author attribution'
1346
- };
1347
- }
1348
-
1349
- case 'update_decision_status': {
1350
- const decisionId = args.decision_id as string;
1351
- const status = args.status as 'proposed' | 'accepted' | 'deprecated' | 'superseded';
1352
- const supersededBy = args.superseded_by as string | undefined;
1353
-
1354
- const success = engine.updateDecisionStatus(decisionId, status, supersededBy);
1355
-
1356
- if (!success) {
1357
- return {
1358
- error: `Decision not found: ${decisionId}`
1359
- };
1360
- }
1361
-
1362
- return {
1363
- message: `Decision ${decisionId} status updated to: ${status}`,
1364
- decision_id: decisionId,
1365
- new_status: status,
1366
- superseded_by: supersededBy || null
1367
- };
1368
- }
1369
-
1370
- case 'export_decisions_to_adr': {
1371
- const outputDir = args.output_dir as string | undefined;
1372
- const format = args.format as 'madr' | 'nygard' | 'simple' | undefined;
1373
- const includeIndex = args.include_index as boolean | undefined;
1374
-
1375
- const exportedFiles = engine.exportAllDecisionsToADR({
1376
- outputDir,
1377
- format,
1378
- includeIndex
1379
- });
1380
-
1381
- return {
1382
- message: `Exported ${exportedFiles.length} ADR files`,
1383
- files: exportedFiles,
1384
- format: format || 'madr'
1385
- };
1386
- }
1387
-
1388
- case 'discover_projects': {
1389
- const discovered = engine.discoverProjects();
1390
-
1391
- return {
1392
- message: `Discovered ${discovered.length} potential projects`,
1393
- projects: discovered.map(p => ({
1394
- path: p,
1395
- name: p.split(/[/\\]/).pop()
1396
- }))
1397
- };
1398
- }
1399
-
1400
- // Phase 5: Active Feature Context tools
1401
- case 'get_active_context': {
1402
- const hotContext = engine.getHotContext();
1403
- const summary = engine.getActiveContextSummary();
1404
-
1405
- return {
1406
- summary: hotContext.summary || 'No active context',
1407
- current_feature: summary ? {
1408
- name: summary.name,
1409
- files_count: summary.files,
1410
- changes_count: summary.changes,
1411
- duration_minutes: summary.duration
1412
- } : null,
1413
- active_files: hotContext.files.map(f => ({
1414
- path: f.path,
1415
- touch_count: f.touchCount,
1416
- has_content: f.content !== null
1417
- })),
1418
- recent_changes: hotContext.changes.slice(0, 5).map(c => ({
1419
- file: c.file,
1420
- diff: c.diff,
1421
- when: c.timestamp.toISOString()
1422
- })),
1423
- recent_queries: hotContext.queries.map(q => ({
1424
- query: q.query,
1425
- files_used: q.filesUsed,
1426
- when: q.timestamp.toISOString()
1427
- }))
1428
- };
1429
- }
1430
-
1431
- case 'set_feature_context': {
1432
- const name = args.name as string;
1433
- const files = args.files as string[] | undefined;
1434
-
1435
- const context = engine.startFeatureContext(name);
1436
-
1437
- // Track initial files if provided
1438
- if (files && files.length > 0) {
1439
- for (const file of files) {
1440
- engine.trackFileOpened(file);
1441
- }
1442
- }
1443
-
1444
- return {
1445
- success: true,
1446
- message: `Now tracking: ${name}`,
1447
- context_id: context.id,
1448
- name: context.name
1449
- };
1450
- }
1451
-
1452
- case 'list_recent_contexts': {
1453
- const current = engine.getActiveContextSummary();
1454
- const recent = engine.getRecentFeatureContexts();
1455
-
1456
- return {
1457
- current: current ? {
1458
- name: current.name,
1459
- files: current.files,
1460
- changes: current.changes,
1461
- duration_minutes: current.duration
1462
- } : null,
1463
- recent: recent.map(c => ({
1464
- id: c.id,
1465
- name: c.name,
1466
- files_count: c.files.length,
1467
- changes_count: c.changes.length,
1468
- status: c.status,
1469
- last_active: c.lastActiveAt.toISOString()
1470
- }))
1471
- };
1472
- }
1473
-
1474
- case 'switch_feature_context': {
1475
- const contextId = args.context_id as string;
1476
- const success = engine.switchFeatureContext(contextId);
1477
-
1478
- if (!success) {
1479
- return {
1480
- success: false,
1481
- error: `Context not found: ${contextId}`,
1482
- message: 'Use list_recent_contexts to see available contexts'
1483
- };
1484
- }
1485
-
1486
- const summary = engine.getActiveContextSummary();
1487
- return {
1488
- success: true,
1489
- message: `Switched to: ${summary?.name || 'Unknown'}`,
1490
- current: summary ? {
1491
- name: summary.name,
1492
- files: summary.files,
1493
- changes: summary.changes
1494
- } : null
1495
- };
1496
- }
1497
-
1498
- // Phase 6: Living Documentation tools
1499
- case 'generate_docs': {
1500
- const path = args.path as string | undefined;
1501
- const type = (args.type as string) || (path ? 'component' : 'architecture');
1502
-
1503
- if (type === 'architecture' || !path) {
1504
- const arch = await engine.getArchitecture();
1505
- return {
1506
- type: 'architecture',
1507
- name: arch.name,
1508
- description: arch.description,
1509
- diagram: arch.diagram,
1510
- layers: arch.layers.map(l => ({
1511
- name: l.name,
1512
- directory: l.directory,
1513
- files_count: l.files.length,
1514
- purpose: l.purpose
1515
- })),
1516
- data_flow: arch.dataFlow,
1517
- dependencies_count: arch.dependencies.length,
1518
- generated_at: arch.generatedAt.toISOString()
1519
- };
1520
- } else {
1521
- const doc = await engine.getComponentDoc(path);
1522
- return {
1523
- type: 'component',
1524
- file: doc.file,
1525
- name: doc.name,
1526
- purpose: doc.purpose,
1527
- public_interface: doc.publicInterface.map(s => ({
1528
- name: s.name,
1529
- kind: s.kind,
1530
- signature: s.signature,
1531
- line: s.lineStart
1532
- })),
1533
- dependencies_count: doc.dependencies.length,
1534
- dependents_count: doc.dependents.length,
1535
- complexity: doc.complexity,
1536
- documentation_score: doc.documentationScore
1537
- };
1538
- }
1539
- }
1540
-
1541
- case 'get_architecture': {
1542
- const arch = await engine.getArchitecture();
1543
-
1544
- return {
1545
- name: arch.name,
1546
- description: arch.description,
1547
- diagram: arch.diagram,
1548
- layers: arch.layers.map(l => ({
1549
- name: l.name,
1550
- directory: l.directory,
1551
- files: l.files,
1552
- purpose: l.purpose
1553
- })),
1554
- data_flow: arch.dataFlow,
1555
- key_components: arch.keyComponents.map(c => ({
1556
- name: c.name,
1557
- file: c.file,
1558
- purpose: c.purpose,
1559
- exports: c.exports
1560
- })),
1561
- dependencies: arch.dependencies.map(d => ({
1562
- name: d.name,
1563
- version: d.version,
1564
- type: d.type
1565
- })),
1566
- generated_at: arch.generatedAt.toISOString()
1567
- };
1568
- }
1569
-
1570
- case 'get_component_doc': {
1571
- const path = args.path as string;
1572
-
1573
- try {
1574
- const doc = await engine.getComponentDoc(path);
1575
-
1576
- return {
1577
- file: doc.file,
1578
- name: doc.name,
1579
- purpose: doc.purpose,
1580
- last_modified: doc.lastModified.toISOString(),
1581
- public_interface: doc.publicInterface.map(s => ({
1582
- name: s.name,
1583
- kind: s.kind,
1584
- signature: s.signature,
1585
- description: s.description,
1586
- line_start: s.lineStart,
1587
- line_end: s.lineEnd,
1588
- exported: s.exported
1589
- })),
1590
- dependencies: doc.dependencies,
1591
- dependents: doc.dependents,
1592
- change_history: doc.changeHistory.slice(0, 10).map(h => ({
1593
- date: h.date.toISOString(),
1594
- change: h.change,
1595
- author: h.author,
1596
- commit: h.commit,
1597
- lines_added: h.linesChanged.added,
1598
- lines_removed: h.linesChanged.removed
1599
- })),
1600
- contributors: doc.contributors,
1601
- complexity: doc.complexity,
1602
- documentation_score: doc.documentationScore
1603
- };
1604
- } catch (error) {
1605
- return {
1606
- error: `Failed to generate component doc: ${error instanceof Error ? error.message : 'Unknown error'}`
1607
- };
1608
- }
1609
- }
1610
-
1611
- case 'get_changelog': {
1612
- const since = args.since as string | undefined;
1613
- const groupBy = args.group_by as 'day' | 'week' | undefined;
1614
- const includeDecisions = args.include_decisions as boolean | undefined;
1615
-
1616
- const changelogs = await engine.getChangelog({
1617
- since,
1618
- groupBy,
1619
- includeDecisions
1620
- });
1621
-
1622
- return {
1623
- period: since || 'this week',
1624
- days: changelogs.map(day => ({
1625
- date: day.date.toISOString().split('T')[0],
1626
- summary: day.summary,
1627
- features: day.features.map(f => ({
1628
- description: f.description,
1629
- files: f.files,
1630
- commit: f.commit
1631
- })),
1632
- fixes: day.fixes.map(f => ({
1633
- description: f.description,
1634
- files: f.files,
1635
- commit: f.commit
1636
- })),
1637
- refactors: day.refactors.map(r => ({
1638
- description: r.description,
1639
- files: r.files,
1640
- commit: r.commit
1641
- })),
1642
- decisions: day.decisions,
1643
- metrics: {
1644
- commits: day.metrics.commits,
1645
- files_changed: day.metrics.filesChanged,
1646
- lines_added: day.metrics.linesAdded,
1647
- lines_removed: day.metrics.linesRemoved
1648
- }
1649
- })),
1650
- total_days: changelogs.length
1651
- };
1652
- }
1653
-
1654
- case 'validate_docs': {
1655
- const result = await engine.validateDocs();
1656
-
1657
- return {
1658
- is_valid: result.isValid,
1659
- score: result.score,
1660
- outdated_docs: result.outdatedDocs.map(d => ({
1661
- file: d.file,
1662
- reason: d.reason,
1663
- severity: d.severity,
1664
- last_doc_update: d.lastDocUpdate.toISOString(),
1665
- last_code_change: d.lastCodeChange.toISOString()
1666
- })),
1667
- undocumented_count: result.undocumentedCode.length,
1668
- suggestions: result.suggestions.slice(0, 10).map(s => ({
1669
- file: s.file,
1670
- suggestion: s.suggestion,
1671
- priority: s.priority
1672
- })),
1673
- message: result.isValid
1674
- ? `Documentation score: ${result.score}% - Looking good!`
1675
- : `Documentation score: ${result.score}% - ${result.suggestions.length} suggestions available`
1676
- };
1677
- }
1678
-
1679
- case 'what_happened': {
1680
- const since = args.since as string;
1681
- const scope = args.scope as string | undefined;
1682
-
1683
- const result = await engine.whatHappened(since, scope);
1684
-
1685
- return {
1686
- time_range: {
1687
- since: result.timeRange.since.toISOString(),
1688
- until: result.timeRange.until.toISOString()
1689
- },
1690
- scope: result.scope,
1691
- summary: result.summary,
1692
- changes: result.changes.slice(0, 20).map(c => ({
1693
- timestamp: c.timestamp.toISOString(),
1694
- type: c.type,
1695
- description: c.description,
1696
- details: c.details
1697
- })),
1698
- decisions: result.decisions.map(d => ({
1699
- id: d.id,
1700
- title: d.title,
1701
- date: d.date.toISOString()
1702
- })),
1703
- files_affected: result.filesAffected.slice(0, 20),
1704
- total_changes: result.changes.length,
1705
- total_files: result.filesAffected.length
1706
- };
1707
- }
1708
-
1709
- case 'find_undocumented': {
1710
- const importance = args.importance as 'low' | 'medium' | 'high' | 'all' | undefined;
1711
- const type = args.type as 'file' | 'function' | 'class' | 'interface' | 'all' | undefined;
1712
-
1713
- const items = await engine.findUndocumented({ importance, type });
1714
-
1715
- // Group by file for better readability
1716
- const byFile = new Map<string, typeof items>();
1717
- for (const item of items) {
1718
- if (!byFile.has(item.file)) {
1719
- byFile.set(item.file, []);
1720
- }
1721
- byFile.get(item.file)!.push(item);
1722
- }
1723
-
1724
- return {
1725
- total: items.length,
1726
- by_importance: {
1727
- high: items.filter(i => i.importance === 'high').length,
1728
- medium: items.filter(i => i.importance === 'medium').length,
1729
- low: items.filter(i => i.importance === 'low').length
1730
- },
1731
- items: items.slice(0, 30).map(i => ({
1732
- file: i.file,
1733
- symbol: i.symbol,
1734
- type: i.type,
1735
- importance: i.importance
1736
- })),
1737
- files_affected: byFile.size,
1738
- message: items.length === 0
1739
- ? 'All exported code is documented!'
1740
- : `Found ${items.length} undocumented items across ${byFile.size} files`
1741
- };
1742
- }
1743
-
1744
- // Phase 7: Context Rot Prevention tools
1745
- case 'get_context_health': {
1746
- const includeHistory = args.include_history as boolean | undefined;
1747
-
1748
- const health = engine.getContextHealth();
1749
- const drift = engine.detectDrift();
1750
-
1751
- const result: Record<string, unknown> = {
1752
- health: health.health,
1753
- tokens_used: health.tokensUsed,
1754
- tokens_limit: health.tokensLimit,
1755
- utilization: `${health.utilizationPercent}%`,
1756
- drift_score: health.driftScore,
1757
- drift_detected: health.driftDetected,
1758
- relevance_score: health.relevanceScore,
1759
- critical_context_count: health.criticalContextCount,
1760
- compaction_needed: health.compactionNeeded,
1761
- suggestions: health.suggestions,
1762
- drift_details: {
1763
- missing_requirements: drift.missingRequirements,
1764
- contradictions: drift.contradictions.length,
1765
- topic_shift: drift.topicShift,
1766
- suggested_reminders: drift.suggestedReminders
1767
- }
1768
- };
1769
-
1770
- if (includeHistory) {
1771
- // Note: getHealthHistory would need to be exposed from engine
1772
- result.message = 'Health history tracking available';
1773
- }
1774
-
1775
- return result;
1776
- }
1777
-
1778
- case 'trigger_compaction': {
1779
- const strategy = (args.strategy as 'summarize' | 'selective' | 'aggressive') || 'summarize';
1780
- const preserveRecent = args.preserve_recent as number | undefined;
1781
- const targetUtilization = args.target_utilization as number | undefined;
1782
-
1783
- const result = engine.triggerCompaction({
1784
- strategy,
1785
- preserveRecent,
1786
- targetUtilization,
1787
- preserveCritical: true
1788
- });
1789
-
1790
- return {
1791
- success: result.success,
1792
- strategy: result.strategy,
1793
- tokens_before: result.tokensBefore,
1794
- tokens_after: result.tokensAfter,
1795
- tokens_saved: result.tokensSaved,
1796
- reduction: `${Math.round((result.tokensSaved / result.tokensBefore) * 100)}%`,
1797
- preserved_critical: result.preservedCritical,
1798
- summarized_chunks: result.summarizedChunks,
1799
- removed_chunks: result.removedChunks,
1800
- summaries: result.summaries,
1801
- message: result.success
1802
- ? `Compaction successful: saved ${result.tokensSaved} tokens (${Math.round((result.tokensSaved / result.tokensBefore) * 100)}% reduction)`
1803
- : 'Compaction failed'
1804
- };
1805
- }
1806
-
1807
- case 'mark_critical': {
1808
- const content = args.content as string;
1809
- const type = args.type as 'decision' | 'requirement' | 'instruction' | 'custom' | undefined;
1810
- const reason = args.reason as string | undefined;
1811
-
1812
- const critical = engine.markCritical(content, { type, reason });
1813
-
1814
- return {
1815
- id: critical.id,
1816
- type: critical.type,
1817
- content: critical.content,
1818
- reason: critical.reason,
1819
- created_at: critical.createdAt.toISOString(),
1820
- never_compress: critical.neverCompress,
1821
- message: `Marked as critical ${critical.type}: "${content.slice(0, 50)}${content.length > 50 ? '...' : ''}"`
1822
- };
1823
- }
1824
-
1825
- case 'get_critical_context': {
1826
- const type = args.type as 'decision' | 'requirement' | 'instruction' | 'custom' | undefined;
1827
-
1828
- const items = engine.getCriticalContext(type);
1829
-
1830
- // Group by type
1831
- const byType: Record<string, number> = {
1832
- decision: 0,
1833
- requirement: 0,
1834
- instruction: 0,
1835
- custom: 0
1836
- };
1837
-
1838
- for (const item of items) {
1839
- byType[item.type] = (byType[item.type] || 0) + 1;
1840
- }
1841
-
1842
- return {
1843
- total: items.length,
1844
- by_type: byType,
1845
- items: items.map(item => ({
1846
- id: item.id,
1847
- type: item.type,
1848
- content: item.content,
1849
- reason: item.reason,
1850
- created_at: item.createdAt.toISOString()
1851
- })),
1852
- summary: engine.getContextSummaryForAI(),
1853
- message: items.length === 0
1854
- ? 'No critical context marked. Consider marking important decisions and requirements.'
1855
- : `${items.length} critical items will be preserved during compaction`
1856
- };
1857
- }
1858
-
1859
- // Phase 8: Confidence Scoring tools
1860
- case 'get_confidence': {
1861
- const code = args.code as string;
1862
- const context = args.context as string | undefined;
1863
-
1864
- const result = await engine.getConfidence(code, context);
1865
-
1866
- return {
1867
- confidence: result.confidence,
1868
- score: result.score,
1869
- reasoning: result.reasoning,
1870
- indicator: engine.getConfidenceIndicator(result.confidence),
1871
- sources: {
1872
- codebase: result.sources.codebase.map(m => ({
1873
- file: m.file,
1874
- line: m.line,
1875
- function: m.function,
1876
- similarity: m.similarity,
1877
- usage_count: m.usageCount
1878
- })),
1879
- decisions: result.sources.decisions.map(d => ({
1880
- id: d.id,
1881
- title: d.title,
1882
- relevance: d.relevance,
1883
- date: d.date.toISOString()
1884
- })),
1885
- patterns: result.sources.patterns.map(p => ({
1886
- pattern: p.pattern,
1887
- confidence: p.confidence,
1888
- examples: p.examples
1889
- })),
1890
- used_general_knowledge: result.sources.usedGeneralKnowledge
1891
- },
1892
- warnings: result.warnings.map(w => ({
1893
- type: w.type,
1894
- message: w.message,
1895
- severity: w.severity,
1896
- suggestion: w.suggestion,
1897
- related_decision: w.relatedDecision
1898
- })),
1899
- formatted: engine.formatConfidenceResult(result),
1900
- message: `${result.confidence.toUpperCase()} confidence (${result.score}%): ${result.reasoning}`
1901
- };
1902
- }
1903
-
1904
- case 'list_sources': {
1905
- const code = args.code as string;
1906
- const context = args.context as string | undefined;
1907
- const includeSnippets = args.include_snippets as boolean | undefined;
1908
-
1909
- const sources = await engine.listConfidenceSources(code, context, includeSnippets);
1910
-
1911
- // Calculate weights
1912
- const hasCodebase = sources.codebase.length > 0;
1913
- const hasDecisions = sources.decisions.length > 0;
1914
-
1915
- let codebaseWeight = 50;
1916
- let decisionWeight = 30;
1917
- let patternWeight = 20;
1918
-
1919
- if (!hasCodebase) {
1920
- codebaseWeight = 0;
1921
- decisionWeight += 25;
1922
- patternWeight += 25;
1923
- }
1924
-
1925
- if (!hasDecisions) {
1926
- decisionWeight = 0;
1927
- codebaseWeight += 15;
1928
- patternWeight += 15;
1929
- }
1930
-
1931
- return {
1932
- codebase: {
1933
- weight: `${codebaseWeight}%`,
1934
- matches: sources.codebase.map(m => ({
1935
- file: m.file,
1936
- line: m.line,
1937
- function: m.function,
1938
- similarity: m.similarity,
1939
- snippet: m.snippet,
1940
- usage_count: m.usageCount
1941
- }))
1942
- },
1943
- decisions: {
1944
- weight: `${decisionWeight}%`,
1945
- matches: sources.decisions.map(d => ({
1946
- id: d.id,
1947
- title: d.title,
1948
- relevance: d.relevance,
1949
- date: d.date.toISOString()
1950
- }))
1951
- },
1952
- patterns: {
1953
- weight: `${patternWeight}%`,
1954
- matches: sources.patterns.map(p => ({
1955
- pattern: p.pattern,
1956
- confidence: p.confidence,
1957
- examples: p.examples
1958
- }))
1959
- },
1960
- used_general_knowledge: sources.usedGeneralKnowledge,
1961
- message: sources.usedGeneralKnowledge
1962
- ? 'Sources: Based primarily on general knowledge (no strong codebase matches)'
1963
- : `Sources: Found ${sources.codebase.length} codebase matches, ${sources.decisions.length} related decisions, ${sources.patterns.length} patterns`
1964
- };
1965
- }
1966
-
1967
- case 'check_conflicts': {
1968
- const code = args.code as string;
1969
-
1970
- const result = await engine.checkCodeConflicts(code);
1971
-
1972
- return {
1973
- has_conflicts: result.hasConflicts,
1974
- conflicts: result.conflicts.map(c => ({
1975
- decision_id: c.decisionId,
1976
- decision_title: c.decisionTitle,
1977
- decision_date: c.decisionDate.toISOString(),
1978
- conflict_description: c.conflictDescription,
1979
- severity: c.severity
1980
- })),
1981
- message: result.hasConflicts
1982
- ? `Found ${result.conflicts.length} conflict(s) with past decisions`
1983
- : 'No conflicts with past decisions'
1984
- };
1985
- }
1986
-
1987
- // Phase 9: Change Intelligence tools
1988
- case 'what_changed': {
1989
- const since = args.since as string;
1990
- const file = args.file as string | undefined;
1991
- const author = args.author as string | undefined;
1992
-
1993
- const result = engine.whatChanged({ since, file, author });
1994
-
1995
- return {
1996
- period: result.period,
1997
- since: result.since.toISOString(),
1998
- until: result.until.toISOString(),
1999
- total_files: result.totalFiles,
2000
- total_lines_added: result.totalLinesAdded,
2001
- total_lines_removed: result.totalLinesRemoved,
2002
- by_author: result.byAuthor,
2003
- by_type: result.byType,
2004
- changes: result.changes.slice(0, 20).map(c => ({
2005
- file: c.file,
2006
- type: c.type,
2007
- lines_added: c.linesAdded,
2008
- lines_removed: c.linesRemoved,
2009
- author: c.author,
2010
- timestamp: c.timestamp.toISOString(),
2011
- commit_message: c.commitMessage,
2012
- commit_hash: c.commitHash.slice(0, 7)
2013
- })),
2014
- formatted: engine.formatChanges(result),
2015
- message: result.changes.length === 0
2016
- ? `No changes found since ${since}`
2017
- : `Found ${result.changes.length} changes across ${result.totalFiles} files`
2018
- };
2019
- }
2020
-
2021
- case 'why_broke': {
2022
- const error = args.error as string;
2023
- const file = args.file as string | undefined;
2024
- const line = args.line as number | undefined;
2025
-
2026
- const diagnosis = engine.whyBroke(error, { file, line });
2027
-
2028
- return {
2029
- likely_cause: diagnosis.likelyCause ? {
2030
- file: diagnosis.likelyCause.file,
2031
- author: diagnosis.likelyCause.author,
2032
- timestamp: diagnosis.likelyCause.timestamp.toISOString(),
2033
- commit_message: diagnosis.likelyCause.commitMessage,
2034
- commit_hash: diagnosis.likelyCause.commitHash.slice(0, 7),
2035
- diff: diagnosis.likelyCause.diff.slice(0, 500)
2036
- } : null,
2037
- confidence: diagnosis.confidence,
2038
- related_changes: diagnosis.relatedChanges.map(c => ({
2039
- file: c.file,
2040
- timestamp: c.timestamp.toISOString(),
2041
- commit_message: c.commitMessage
2042
- })),
2043
- past_similar_bugs: diagnosis.pastSimilarBugs.map(b => ({
2044
- error: b.error.slice(0, 100),
2045
- similarity: b.similarity,
2046
- date: b.date.toISOString(),
2047
- fix: b.fix,
2048
- file: b.file
2049
- })),
2050
- suggested_fix: diagnosis.suggestedFix,
2051
- reasoning: diagnosis.reasoning,
2052
- formatted: engine.formatDiagnosis(diagnosis),
2053
- message: diagnosis.likelyCause
2054
- ? `Found likely cause in ${diagnosis.likelyCause.file} (${diagnosis.confidence}% confidence)`
2055
- : 'Could not identify specific cause'
2056
- };
2057
- }
2058
-
2059
- case 'find_similar_bugs': {
2060
- const error = args.error as string;
2061
- const limit = args.limit as number | undefined;
2062
-
2063
- const bugs = engine.findSimilarBugs(error, limit);
2064
-
2065
- return {
2066
- total: bugs.length,
2067
- bugs: bugs.map(b => ({
2068
- id: b.id,
2069
- error: b.error.slice(0, 100),
2070
- similarity: b.similarity,
2071
- date: b.date.toISOString(),
2072
- cause: b.cause,
2073
- fix: b.fix,
2074
- file: b.file,
2075
- fix_diff: b.fixDiff?.slice(0, 200)
2076
- })),
2077
- message: bugs.length === 0
2078
- ? 'No similar bugs found in history'
2079
- : `Found ${bugs.length} similar bug(s) in history`
2080
- };
2081
- }
2082
-
2083
- case 'suggest_fix': {
2084
- const error = args.error as string;
2085
- const context = args.context as string | undefined;
2086
-
2087
- const suggestions = engine.suggestFix(error, context);
2088
-
2089
- return {
2090
- total: suggestions.length,
2091
- suggestions: suggestions.map(s => ({
2092
- confidence: s.confidence,
2093
- fix: s.fix,
2094
- reason: s.reason,
2095
- diff: s.diff,
2096
- source: s.source,
2097
- past_fix: s.pastFix ? {
2098
- date: s.pastFix.date.toISOString(),
2099
- file: s.pastFix.file
2100
- } : null
2101
- })),
2102
- formatted: engine.formatFixSuggestions(suggestions),
2103
- message: suggestions.length === 0
2104
- ? 'No fix suggestions available'
2105
- : `Found ${suggestions.length} fix suggestion(s)`
2106
- };
2107
- }
2108
-
2109
- // Phase 10: Architecture Enforcement tools
2110
- case 'validate_pattern': {
2111
- const code = args.code as string;
2112
- const type = args.type as string | undefined;
2113
-
2114
- const result = engine.validatePattern(code, type);
2115
-
2116
- return {
2117
- valid: result.valid,
2118
- score: result.score,
2119
- matched_pattern: result.matchedPattern,
2120
- violations: result.violations.map(v => ({
2121
- rule: v.rule,
2122
- message: v.message,
2123
- severity: v.severity,
2124
- suggestion: v.suggestion
2125
- })),
2126
- suggestions: result.suggestions.map(s => ({
2127
- description: s.description,
2128
- code: s.code,
2129
- priority: s.priority
2130
- })),
2131
- existing_alternatives: result.existingAlternatives.map(a => ({
2132
- name: a.name,
2133
- file: a.file,
2134
- line: a.line,
2135
- signature: a.signature,
2136
- similarity: a.similarity
2137
- })),
2138
- formatted: engine.formatValidationResult(result),
2139
- message: result.valid
2140
- ? `Pattern validation passed (score: ${result.score}/100)`
2141
- : `Pattern validation: ${result.violations.length} issue(s) found (score: ${result.score}/100)`
2142
- };
2143
- }
2144
-
2145
- case 'suggest_existing': {
2146
- const intent = args.intent as string;
2147
- const limit = args.limit as number | undefined;
2148
-
2149
- const suggestions = engine.suggestExisting(intent, limit);
2150
-
2151
- return {
2152
- total: suggestions.length,
2153
- suggestions: suggestions.map(s => ({
2154
- name: s.name,
2155
- file: s.file,
2156
- line: s.line,
2157
- signature: s.signature,
2158
- description: s.description,
2159
- usage_count: s.usageCount,
2160
- purpose: s.purpose,
2161
- similarity: s.similarity
2162
- })),
2163
- formatted: engine.formatExistingSuggestions(suggestions),
2164
- message: suggestions.length === 0
2165
- ? 'No existing functions found for this intent - this might be a new use case'
2166
- : `Found ${suggestions.length} existing function(s) that might help`
2167
- };
2168
- }
2169
-
2170
- case 'learn_pattern': {
2171
- const code = args.code as string;
2172
- const name = args.name as string;
2173
- const description = args.description as string | undefined;
2174
- const category = args.category as string | undefined;
2175
-
2176
- const result = engine.learnPattern(code, name, description, category);
2177
-
2178
- return {
2179
- success: result.success,
2180
- pattern_id: result.patternId,
2181
- message: result.message
2182
- };
2183
- }
2184
-
2185
- case 'list_patterns': {
2186
- const category = args.category as string | undefined;
2187
-
2188
- const patterns = engine.listPatterns(category);
2189
-
2190
- return {
2191
- total: patterns.length,
2192
- patterns: patterns.map(p => ({
2193
- id: p.id,
2194
- name: p.name,
2195
- category: p.category,
2196
- description: p.description,
2197
- examples_count: p.examples.length,
2198
- anti_patterns_count: p.antiPatterns.length,
2199
- rules_count: p.rules.length,
2200
- usage_count: p.usageCount,
2201
- created_at: p.createdAt.toISOString()
2202
- })),
2203
- formatted: engine.formatPatternList(patterns),
2204
- message: patterns.length === 0
2205
- ? 'No patterns found. Use learn_pattern to teach patterns.'
2206
- : `Found ${patterns.length} pattern(s)`
2207
- };
2208
- }
2209
-
2210
- case 'get_pattern': {
2211
- const id = args.id as string;
2212
-
2213
- const pattern = engine.getPattern(id);
2214
-
2215
- if (!pattern) {
2216
- return {
2217
- error: `Pattern not found: ${id}`,
2218
- message: 'Use list_patterns to see available patterns'
2219
- };
2220
- }
2221
-
2222
- return {
2223
- id: pattern.id,
2224
- name: pattern.name,
2225
- category: pattern.category,
2226
- description: pattern.description,
2227
- examples: pattern.examples.map(e => ({
2228
- code: e.code,
2229
- explanation: e.explanation,
2230
- file: e.file
2231
- })),
2232
- anti_patterns: pattern.antiPatterns.map(a => ({
2233
- code: a.code,
2234
- explanation: a.explanation
2235
- })),
2236
- rules: pattern.rules.map(r => ({
2237
- rule: r.rule,
2238
- severity: r.severity
2239
- })),
2240
- usage_count: pattern.usageCount,
2241
- created_at: pattern.createdAt.toISOString()
2242
- };
2243
- }
2244
-
2245
- case 'add_pattern_example': {
2246
- const patternId = args.pattern_id as string;
2247
- const code = args.code as string;
2248
- const explanation = args.explanation as string;
2249
- const isAntiPattern = args.is_anti_pattern as boolean | undefined;
2250
-
2251
- const success = engine.addPatternExample(patternId, code, explanation, isAntiPattern);
2252
-
2253
- if (!success) {
2254
- return {
2255
- success: false,
2256
- error: `Pattern not found: ${patternId}`,
2257
- message: 'Use list_patterns to see available patterns'
2258
- };
2259
- }
2260
-
2261
- return {
2262
- success: true,
2263
- pattern_id: patternId,
2264
- type: isAntiPattern ? 'anti-pattern' : 'example',
2265
- message: `${isAntiPattern ? 'Anti-pattern' : 'Example'} added successfully`
2266
- };
2267
- }
2268
-
2269
- case 'get_architecture_stats': {
2270
- const stats = engine.getArchitectureStats();
2271
-
2272
- return {
2273
- patterns: {
2274
- total: stats.patterns.total,
2275
- by_category: stats.patterns.byCategory,
2276
- top_patterns: stats.patterns.topPatterns
2277
- },
2278
- functions: {
2279
- total: stats.functions.total,
2280
- exported: stats.functions.exported,
2281
- by_purpose: stats.functions.byPurpose
2282
- },
2283
- message: `${stats.patterns.total} patterns learned, ${stats.functions.total} functions indexed`
2284
- };
2285
- }
2286
-
2287
- // Phase 11: Test-Aware Suggestions tools
2288
- case 'get_related_tests': {
2289
- const file = args.file as string;
2290
- const fn = args.function as string | undefined;
2291
-
2292
- const tests = engine.getRelatedTests(file, fn);
2293
-
2294
- return {
2295
- file,
2296
- function: fn || null,
2297
- total: tests.length,
2298
- tests: tests.map(t => ({
2299
- id: t.id,
2300
- name: t.name,
2301
- file: t.file,
2302
- describes: t.describes,
2303
- line_start: t.lineStart,
2304
- line_end: t.lineEnd,
2305
- assertions_count: t.assertions.length,
2306
- covers_files: t.coversFiles,
2307
- covers_functions: t.coversFunctions,
2308
- last_status: t.lastStatus,
2309
- last_run: t.lastRun?.toISOString()
2310
- })),
2311
- formatted: engine.formatTestList(tests),
2312
- message: tests.length === 0
2313
- ? `No tests found for ${file}${fn ? ` function ${fn}` : ''}`
2314
- : `Found ${tests.length} test(s) related to ${file}${fn ? ` function ${fn}` : ''}`
2315
- };
2316
- }
2317
-
2318
- case 'check_tests': {
2319
- const change = args.change as string;
2320
- const file = args.file as string;
2321
-
2322
- const result = engine.checkTests(change, file);
2323
-
2324
- return {
2325
- safe: result.safe,
2326
- coverage_percent: result.coveragePercent,
2327
- related_tests: result.relatedTests.length,
2328
- would_pass: result.wouldPass.map(t => ({
2329
- id: t.id,
2330
- name: t.name,
2331
- file: t.file
2332
- })),
2333
- would_fail: result.wouldFail.map(f => ({
2334
- test_id: f.test.id,
2335
- test_name: f.test.name,
2336
- test_file: f.test.file,
2337
- reason: f.reason,
2338
- confidence: f.confidence,
2339
- suggested_fix: f.suggestedFix,
2340
- assertion: f.assertion ? {
2341
- type: f.assertion.type,
2342
- code: f.assertion.code,
2343
- line: f.assertion.line
2344
- } : null
2345
- })),
2346
- uncertain: result.uncertain.map(t => ({
2347
- id: t.id,
2348
- name: t.name,
2349
- file: t.file
2350
- })),
2351
- suggested_updates: result.suggestedTestUpdates.map(u => ({
2352
- file: u.file,
2353
- test_name: u.testName,
2354
- line: u.line,
2355
- before: u.before,
2356
- after: u.after,
2357
- reason: u.reason
2358
- })),
2359
- formatted: engine.formatTestValidationResult(result),
2360
- message: result.safe
2361
- ? `Change is safe - ${result.coveragePercent}% test coverage, ${result.wouldPass.length} tests would pass`
2362
- : `Change may break ${result.wouldFail.length} test(s) - review suggested updates`
2363
- };
2364
- }
2365
-
2366
- case 'suggest_test_update': {
2367
- const change = args.change as string;
2368
- const failingTests = args.failing_tests as string[] | undefined;
2369
-
2370
- const updates = engine.suggestTestUpdate(change, failingTests);
2371
-
2372
- return {
2373
- total: updates.length,
2374
- updates: updates.map(u => ({
2375
- file: u.file,
2376
- test_name: u.testName,
2377
- line: u.line,
2378
- before: u.before,
2379
- after: u.after,
2380
- reason: u.reason
2381
- })),
2382
- formatted: engine.formatTestUpdates(updates),
2383
- message: updates.length === 0
2384
- ? 'No test updates needed'
2385
- : `Generated ${updates.length} suggested test update(s)`
2386
- };
2387
- }
2388
-
2389
- case 'get_test_coverage': {
2390
- const file = args.file as string;
2391
-
2392
- const coverage = engine.getTestCoverage(file);
2393
-
2394
- return {
2395
- file: coverage.file,
2396
- total_tests: coverage.totalTests,
2397
- coverage_percent: coverage.coveragePercent,
2398
- covered_functions: coverage.coveredFunctions,
2399
- uncovered_functions: coverage.uncoveredFunctions,
2400
- formatted: engine.formatTestCoverage(coverage),
2401
- message: coverage.coveragePercent === 100
2402
- ? `Full test coverage for ${file}`
2403
- : coverage.uncoveredFunctions.length > 0
2404
- ? `${coverage.coveragePercent}% coverage - ${coverage.uncoveredFunctions.length} function(s) need tests`
2405
- : `${coverage.totalTests} test(s) cover ${file}`
2406
- };
2407
- }
2408
-
2409
- // Intelligent Refresh System tools
2410
- case 'memory_refresh': {
2411
- const force = args.force as boolean | undefined;
2412
-
2413
- if (force) {
2414
- const result = engine.triggerRefresh();
2415
- return {
2416
- success: true,
2417
- forced: true,
2418
- git_synced: result.gitSynced,
2419
- importance_updated: result.importanceUpdated,
2420
- tasks_executed: result.tasksExecuted,
2421
- message: `Force refresh complete: ${result.gitSynced} git changes synced`
2422
- };
2423
- } else {
2424
- // Normal refresh - only sync if there are new commits
2425
- const gitSynced = engine.syncGitChanges();
2426
- return {
2427
- success: true,
2428
- forced: false,
2429
- git_synced: gitSynced,
2430
- message: gitSynced > 0
2431
- ? `Refresh complete: ${gitSynced} git changes synced`
2432
- : 'No new changes to sync'
2433
- };
2434
- }
2435
- }
2436
-
2437
- case 'get_refresh_status': {
2438
- const status = engine.getRefreshStatus();
2439
-
2440
- return {
2441
- last_activity: new Date(status.lastActivity).toISOString(),
2442
- is_idle: status.isIdle,
2443
- idle_duration_seconds: Math.round(status.idleDuration / 1000),
2444
- git_head: status.gitHead?.slice(0, 7) || null,
2445
- has_pending_changes: status.hasNewCommits,
2446
- idle_tasks: status.idleTasks.map(t => ({
2447
- name: t.name,
2448
- last_run: t.lastRun > 0 ? new Date(t.lastRun).toISOString() : 'never',
2449
- ready_to_run: t.readyToRun
2450
- })),
2451
- message: status.isIdle
2452
- ? `System idle for ${Math.round(status.idleDuration / 1000)}s, ${status.idleTasks.filter(t => t.readyToRun).length} task(s) ready`
2453
- : 'System active'
2454
- };
2455
- }
2456
-
2457
- default:
2458
- throw new Error(`Unknown tool: ${toolName}`);
2459
- }
2460
- }