cortex-mcp 1.2.3 → 1.4.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/README.md +9 -2
- package/dist/db/memory-store.d.ts +2 -2
- package/dist/db/memory-store.d.ts.map +1 -1
- package/dist/db/memory-store.js +26 -4
- package/dist/db/memory-store.js.map +1 -1
- package/dist/memory/auto-learner.d.ts.map +1 -1
- package/dist/memory/auto-learner.js +16 -0
- package/dist/memory/auto-learner.js.map +1 -1
- package/dist/memory/convention-detector.d.ts +11 -0
- package/dist/memory/convention-detector.d.ts.map +1 -0
- package/dist/memory/convention-detector.js +294 -0
- package/dist/memory/convention-detector.js.map +1 -0
- package/dist/memory/correction-detector.d.ts +33 -0
- package/dist/memory/correction-detector.d.ts.map +1 -0
- package/dist/memory/correction-detector.js +129 -0
- package/dist/memory/correction-detector.js.map +1 -0
- package/dist/memory/error-learner.d.ts +26 -0
- package/dist/memory/error-learner.d.ts.map +1 -0
- package/dist/memory/error-learner.js +145 -0
- package/dist/memory/error-learner.js.map +1 -0
- package/dist/memory/file-relationships.d.ts +47 -0
- package/dist/memory/file-relationships.d.ts.map +1 -0
- package/dist/memory/file-relationships.js +130 -0
- package/dist/memory/file-relationships.js.map +1 -0
- package/dist/memory/impact-analyzer.d.ts +16 -0
- package/dist/memory/impact-analyzer.d.ts.map +1 -0
- package/dist/memory/impact-analyzer.js +189 -0
- package/dist/memory/impact-analyzer.js.map +1 -0
- package/dist/memory/instructions-generator.d.ts +30 -0
- package/dist/memory/instructions-generator.d.ts.map +1 -0
- package/dist/memory/instructions-generator.js +117 -0
- package/dist/memory/instructions-generator.js.map +1 -0
- package/dist/memory/pre-flight.d.ts +24 -0
- package/dist/memory/pre-flight.d.ts.map +1 -0
- package/dist/memory/pre-flight.js +121 -0
- package/dist/memory/pre-flight.js.map +1 -0
- package/dist/memory/preference-learner.d.ts +28 -0
- package/dist/memory/preference-learner.d.ts.map +1 -0
- package/dist/memory/preference-learner.js +144 -0
- package/dist/memory/preference-learner.js.map +1 -0
- package/dist/memory/regression-guard.d.ts +35 -0
- package/dist/memory/regression-guard.d.ts.map +1 -0
- package/dist/memory/regression-guard.js +90 -0
- package/dist/memory/regression-guard.js.map +1 -0
- package/dist/memory/resume-work.d.ts +37 -0
- package/dist/memory/resume-work.d.ts.map +1 -0
- package/dist/memory/resume-work.js +122 -0
- package/dist/memory/resume-work.js.map +1 -0
- package/dist/memory/success-tracker.d.ts +33 -0
- package/dist/memory/success-tracker.d.ts.map +1 -0
- package/dist/memory/success-tracker.js +75 -0
- package/dist/memory/success-tracker.js.map +1 -0
- package/dist/memory/tool-recommender.d.ts +29 -0
- package/dist/memory/tool-recommender.d.ts.map +1 -0
- package/dist/memory/tool-recommender.js +117 -0
- package/dist/memory/tool-recommender.js.map +1 -0
- package/dist/memory/usage-stats.d.ts +59 -0
- package/dist/memory/usage-stats.d.ts.map +1 -0
- package/dist/memory/usage-stats.js +122 -0
- package/dist/memory/usage-stats.js.map +1 -0
- package/dist/server/mcp-handler.d.ts.map +1 -1
- package/dist/server/mcp-handler.js +634 -14
- package/dist/server/mcp-handler.js.map +1 -1
- package/package.json +3 -2
|
@@ -26,6 +26,20 @@ const rate_limiter_1 = require("../security/rate-limiter");
|
|
|
26
26
|
const feature_gate_1 = require("../security/feature-gate");
|
|
27
27
|
const export_import_1 = require("../memory/export-import");
|
|
28
28
|
const llm_enhancer_1 = require("../memory/llm-enhancer");
|
|
29
|
+
const usage_stats_1 = require("../memory/usage-stats");
|
|
30
|
+
const correction_detector_1 = require("../memory/correction-detector");
|
|
31
|
+
const pre_flight_1 = require("../memory/pre-flight");
|
|
32
|
+
const impact_analyzer_1 = require("../memory/impact-analyzer");
|
|
33
|
+
const resume_work_1 = require("../memory/resume-work");
|
|
34
|
+
const preference_learner_1 = require("../memory/preference-learner");
|
|
35
|
+
const convention_detector_1 = require("../memory/convention-detector");
|
|
36
|
+
const export_map_2 = require("../scanners/export-map");
|
|
37
|
+
const error_learner_1 = require("../memory/error-learner");
|
|
38
|
+
const success_tracker_1 = require("../memory/success-tracker");
|
|
39
|
+
const file_relationships_1 = require("../memory/file-relationships");
|
|
40
|
+
const instructions_generator_1 = require("../memory/instructions-generator");
|
|
41
|
+
const tool_recommender_1 = require("../memory/tool-recommender");
|
|
42
|
+
const regression_guard_1 = require("../memory/regression-guard");
|
|
29
43
|
// --- Query Expansion (Synonym Map) ---
|
|
30
44
|
const SYNONYMS = {
|
|
31
45
|
auth: ['authentication', 'login', 'signin', 'sign-in', 'credentials'],
|
|
@@ -238,6 +252,48 @@ const MCP_TOOLS = [
|
|
|
238
252
|
properties: {},
|
|
239
253
|
},
|
|
240
254
|
},
|
|
255
|
+
{
|
|
256
|
+
name: 'review_code',
|
|
257
|
+
description: 'Review code against your stored conventions, past bug patterns, and project decisions. Returns specific violations with memory references — like having a senior dev review your code.',
|
|
258
|
+
inputSchema: {
|
|
259
|
+
type: 'object',
|
|
260
|
+
properties: {
|
|
261
|
+
code: { type: 'string', description: 'The code to review' },
|
|
262
|
+
filename: { type: 'string', description: 'Optional filename for context-aware review' },
|
|
263
|
+
},
|
|
264
|
+
required: ['code'],
|
|
265
|
+
},
|
|
266
|
+
},
|
|
267
|
+
{
|
|
268
|
+
name: 'pre_check',
|
|
269
|
+
description: 'Pre-flight check: get ALL conventions, gotchas, past bugs, and corrections for a file BEFORE writing code. Like a pilot\'s checklist — call this before making any code changes to avoid repeating past mistakes.',
|
|
270
|
+
inputSchema: {
|
|
271
|
+
type: 'object',
|
|
272
|
+
properties: {
|
|
273
|
+
filename: { type: 'string', description: 'The file you are about to edit' },
|
|
274
|
+
task: { type: 'string', description: 'What you plan to do (helps find relevant past failures)' },
|
|
275
|
+
},
|
|
276
|
+
},
|
|
277
|
+
},
|
|
278
|
+
{
|
|
279
|
+
name: 'check_impact',
|
|
280
|
+
description: 'Impact analysis: before editing a file, check which other files depend on it. Shows direct and indirect dependents with risk level. Prevents breaking changes.',
|
|
281
|
+
inputSchema: {
|
|
282
|
+
type: 'object',
|
|
283
|
+
properties: {
|
|
284
|
+
file: { type: 'string', description: 'The file you plan to modify' },
|
|
285
|
+
},
|
|
286
|
+
required: ['file'],
|
|
287
|
+
},
|
|
288
|
+
},
|
|
289
|
+
{
|
|
290
|
+
name: 'resume_work',
|
|
291
|
+
description: 'Resume work after a conversation break. Returns: last session summary, current tasks, recent corrections (don\'t repeat!), recent decisions, and activity summary. Call this when starting a new conversation about ongoing work.',
|
|
292
|
+
inputSchema: {
|
|
293
|
+
type: 'object',
|
|
294
|
+
properties: {},
|
|
295
|
+
},
|
|
296
|
+
},
|
|
241
297
|
];
|
|
242
298
|
// --- Dynamic Context via ContextBuilder ---
|
|
243
299
|
let cachedContextBuilder = null;
|
|
@@ -258,8 +314,8 @@ function createMCPHandler(memoryStore, eventLog, workspaceRoot) {
|
|
|
258
314
|
id,
|
|
259
315
|
result: {
|
|
260
316
|
protocolVersion: '2024-11-05',
|
|
261
|
-
capabilities: { tools: {}, resources: {} },
|
|
262
|
-
serverInfo: { name: '
|
|
317
|
+
capabilities: { tools: {}, resources: {}, prompts: {} },
|
|
318
|
+
serverInfo: { name: 'Cortex', version: '2.0.0' },
|
|
263
319
|
},
|
|
264
320
|
};
|
|
265
321
|
case 'notifications/initialized':
|
|
@@ -277,7 +333,7 @@ function createMCPHandler(memoryStore, eventLog, workspaceRoot) {
|
|
|
277
333
|
result: {
|
|
278
334
|
resources: [{
|
|
279
335
|
uri: 'memory://brain/context',
|
|
280
|
-
name: '
|
|
336
|
+
name: 'Cortex MCP Context',
|
|
281
337
|
description: 'Top memories — corrections, decisions, conventions. Read this before every response.',
|
|
282
338
|
mimeType: 'text/plain',
|
|
283
339
|
}],
|
|
@@ -304,6 +360,97 @@ function createMCPHandler(memoryStore, eventLog, workspaceRoot) {
|
|
|
304
360
|
error: { code: -32602, message: `Unknown resource: ${uri}` },
|
|
305
361
|
};
|
|
306
362
|
}
|
|
363
|
+
case 'prompts/list':
|
|
364
|
+
return {
|
|
365
|
+
jsonrpc: '2.0', id,
|
|
366
|
+
result: {
|
|
367
|
+
prompts: [
|
|
368
|
+
{
|
|
369
|
+
name: 'cortex-review',
|
|
370
|
+
description: 'Review code against stored conventions, past bugs, and project decisions. Returns specific violations.',
|
|
371
|
+
arguments: [
|
|
372
|
+
{ name: 'code', description: 'The code to review', required: true },
|
|
373
|
+
{ name: 'filename', description: 'Filename for context-aware review', required: false },
|
|
374
|
+
],
|
|
375
|
+
},
|
|
376
|
+
{
|
|
377
|
+
name: 'cortex-debug',
|
|
378
|
+
description: 'Debug an issue using Cortex memory. Checks for similar past bugs, failed attempts, and gotchas.',
|
|
379
|
+
arguments: [
|
|
380
|
+
{ name: 'error', description: 'The error message or issue description', required: true },
|
|
381
|
+
{ name: 'file', description: 'The file where the error occurs', required: false },
|
|
382
|
+
],
|
|
383
|
+
},
|
|
384
|
+
{
|
|
385
|
+
name: 'cortex-new-feature',
|
|
386
|
+
description: 'Pre-flight checklist before building a new feature. Gets conventions, gotchas, and architecture context.',
|
|
387
|
+
arguments: [
|
|
388
|
+
{ name: 'feature', description: 'What feature you plan to build', required: true },
|
|
389
|
+
{ name: 'files', description: 'Files you plan to modify', required: false },
|
|
390
|
+
],
|
|
391
|
+
},
|
|
392
|
+
],
|
|
393
|
+
},
|
|
394
|
+
};
|
|
395
|
+
case 'prompts/get': {
|
|
396
|
+
const promptName = rpc.params?.name;
|
|
397
|
+
const promptArgs = rpc.params?.arguments || {};
|
|
398
|
+
if (promptName === 'cortex-review') {
|
|
399
|
+
return {
|
|
400
|
+
jsonrpc: '2.0', id,
|
|
401
|
+
result: {
|
|
402
|
+
description: 'Code review against Cortex memory',
|
|
403
|
+
messages: [
|
|
404
|
+
{
|
|
405
|
+
role: 'user',
|
|
406
|
+
content: {
|
|
407
|
+
type: 'text',
|
|
408
|
+
text: `Review this code against all stored conventions, past bug patterns, and project decisions.\n\nFile: ${promptArgs.filename || 'unknown'}\n\n\`\`\`\n${promptArgs.code || '(no code provided)'}\n\`\`\`\n\nUse the review_code and pre_check tools to check against stored memory. Report any violations with memory IDs.`,
|
|
409
|
+
},
|
|
410
|
+
},
|
|
411
|
+
],
|
|
412
|
+
},
|
|
413
|
+
};
|
|
414
|
+
}
|
|
415
|
+
if (promptName === 'cortex-debug') {
|
|
416
|
+
return {
|
|
417
|
+
jsonrpc: '2.0', id,
|
|
418
|
+
result: {
|
|
419
|
+
description: 'Debug with Cortex memory context',
|
|
420
|
+
messages: [
|
|
421
|
+
{
|
|
422
|
+
role: 'user',
|
|
423
|
+
content: {
|
|
424
|
+
type: 'text',
|
|
425
|
+
text: `I'm debugging this issue:\n\n${promptArgs.error || '(no error provided)'}\n\nFile: ${promptArgs.file || 'unknown'}\n\nUse recall_memory to search for similar past bugs, failed attempts, and gotchas. Check if this matches any known patterns. Use check_impact to see what other files might be affected.`,
|
|
426
|
+
},
|
|
427
|
+
},
|
|
428
|
+
],
|
|
429
|
+
},
|
|
430
|
+
};
|
|
431
|
+
}
|
|
432
|
+
if (promptName === 'cortex-new-feature') {
|
|
433
|
+
return {
|
|
434
|
+
jsonrpc: '2.0', id,
|
|
435
|
+
result: {
|
|
436
|
+
description: 'New feature pre-flight checklist',
|
|
437
|
+
messages: [
|
|
438
|
+
{
|
|
439
|
+
role: 'user',
|
|
440
|
+
content: {
|
|
441
|
+
type: 'text',
|
|
442
|
+
text: `I'm building a new feature: ${promptArgs.feature || '(no feature described)'}\n\nFiles I plan to modify: ${promptArgs.files || 'unknown'}\n\nBefore I start, run pre_check for each file, check_impact for dependency risks, and recall_memory for any relevant past work. Give me a checklist of things to watch out for.`,
|
|
443
|
+
},
|
|
444
|
+
},
|
|
445
|
+
],
|
|
446
|
+
},
|
|
447
|
+
};
|
|
448
|
+
}
|
|
449
|
+
return {
|
|
450
|
+
jsonrpc: '2.0', id,
|
|
451
|
+
error: { code: -32602, message: `Unknown prompt: ${promptName}` },
|
|
452
|
+
};
|
|
453
|
+
}
|
|
307
454
|
case 'tools/call': {
|
|
308
455
|
const toolName = rpc.params?.name;
|
|
309
456
|
const args = rpc.params?.arguments || {};
|
|
@@ -368,6 +515,18 @@ function createMCPHandler(memoryStore, eventLog, workspaceRoot) {
|
|
|
368
515
|
else if (toolName === 'health_check') {
|
|
369
516
|
return handleHealthCheck(id);
|
|
370
517
|
}
|
|
518
|
+
else if (toolName === 'review_code') {
|
|
519
|
+
return handleReviewCode(id, args);
|
|
520
|
+
}
|
|
521
|
+
else if (toolName === 'pre_check') {
|
|
522
|
+
return handlePreCheck(id, args);
|
|
523
|
+
}
|
|
524
|
+
else if (toolName === 'check_impact') {
|
|
525
|
+
return handleCheckImpact(id, args);
|
|
526
|
+
}
|
|
527
|
+
else if (toolName === 'resume_work') {
|
|
528
|
+
return handleResumeWork(id);
|
|
529
|
+
}
|
|
371
530
|
else {
|
|
372
531
|
return {
|
|
373
532
|
jsonrpc: '2.0', id,
|
|
@@ -670,16 +829,46 @@ function createMCPHandler(memoryStore, eventLog, workspaceRoot) {
|
|
|
670
829
|
extraMemories += (0, architecture_graph_1.storeArchitectureGraph)(memoryStore, archGraph);
|
|
671
830
|
}
|
|
672
831
|
catch { /* non-fatal */ }
|
|
832
|
+
// Convention auto-detection — analyze actual code patterns
|
|
833
|
+
try {
|
|
834
|
+
const conventions = (0, convention_detector_1.detectConventions)(root);
|
|
835
|
+
for (const conv of conventions) {
|
|
836
|
+
try {
|
|
837
|
+
(0, memory_quality_1.storeWithQuality)(memoryStore, {
|
|
838
|
+
type: 'CONVENTION',
|
|
839
|
+
intent: conv.pattern,
|
|
840
|
+
action: conv.evidence,
|
|
841
|
+
reason: `Auto-detected from code (${conv.category}, confidence: ${conv.confidence})`,
|
|
842
|
+
confidence: conv.confidence,
|
|
843
|
+
importance: conv.confidence,
|
|
844
|
+
tags: ['convention', 'auto-detected', conv.category],
|
|
845
|
+
});
|
|
846
|
+
extraMemories++;
|
|
847
|
+
}
|
|
848
|
+
catch { /* skip duplicates */ }
|
|
849
|
+
}
|
|
850
|
+
}
|
|
851
|
+
catch { /* non-fatal */ }
|
|
673
852
|
(0, memory_cache_1.invalidateCache)();
|
|
853
|
+
(0, usage_stats_1.trackScan)();
|
|
674
854
|
const total = count + extraMemories;
|
|
855
|
+
// Report knowledge gaps after scan
|
|
856
|
+
let gapReport = '';
|
|
857
|
+
try {
|
|
858
|
+
const gaps = (0, meta_memory_1.detectKnowledgeGaps)(memoryStore, root);
|
|
859
|
+
if (gaps.length > 0) {
|
|
860
|
+
gapReport = `\n\n${(0, meta_memory_1.formatKnowledgeGaps)(gaps)}`;
|
|
861
|
+
}
|
|
862
|
+
}
|
|
863
|
+
catch { /* non-fatal */ }
|
|
675
864
|
return {
|
|
676
865
|
jsonrpc: '2.0', id,
|
|
677
866
|
result: {
|
|
678
867
|
content: [{
|
|
679
868
|
type: 'text',
|
|
680
869
|
text: total > 0
|
|
681
|
-
? `Project scanned successfully. ${total} memories created (stack, structure, config, git history, export map, architecture graph)
|
|
682
|
-
:
|
|
870
|
+
? `Project scanned successfully. ${total} memories created (stack, structure, config, git history, export map, architecture graph, coding conventions).${gapReport}`
|
|
871
|
+
: `Project was already scanned. No new memories created.${gapReport}`,
|
|
683
872
|
}],
|
|
684
873
|
},
|
|
685
874
|
};
|
|
@@ -755,6 +944,9 @@ function createMCPHandler(memoryStore, eventLog, workspaceRoot) {
|
|
|
755
944
|
};
|
|
756
945
|
}
|
|
757
946
|
try {
|
|
947
|
+
// Track file for relationship mapping
|
|
948
|
+
if (args.filename)
|
|
949
|
+
(0, file_relationships_1.recordFileEdit)(args.filename);
|
|
758
950
|
const result = (0, code_verifier_1.verifyCode)(args.code, root);
|
|
759
951
|
const lines = [];
|
|
760
952
|
// Imports
|
|
@@ -781,6 +973,20 @@ function createMCPHandler(memoryStore, eventLog, workspaceRoot) {
|
|
|
781
973
|
for (const [file, available] of Object.entries(result.exports.available)) {
|
|
782
974
|
lines.push(` ${file} exports: ${available.join(', ')}`);
|
|
783
975
|
}
|
|
976
|
+
// Smart fix suggestions — find closest real exports
|
|
977
|
+
try {
|
|
978
|
+
const wsRoot = args.workspaceRoot || workspaceRoot;
|
|
979
|
+
if (wsRoot) {
|
|
980
|
+
const exportMap = (0, export_map_1.buildExportMap)(wsRoot);
|
|
981
|
+
for (const invalid of result.exports.invalid) {
|
|
982
|
+
const suggestions = (0, export_map_2.suggestRealExport)(exportMap, invalid);
|
|
983
|
+
if (suggestions.length > 0) {
|
|
984
|
+
lines.push(` 💡 Did you mean: ${suggestions.slice(0, 3).join(', ')}?`);
|
|
985
|
+
}
|
|
986
|
+
}
|
|
987
|
+
}
|
|
988
|
+
}
|
|
989
|
+
catch { /* non-fatal */ }
|
|
784
990
|
}
|
|
785
991
|
}
|
|
786
992
|
// Env vars
|
|
@@ -799,6 +1005,12 @@ function createMCPHandler(memoryStore, eventLog, workspaceRoot) {
|
|
|
799
1005
|
if (lines.length === 0) {
|
|
800
1006
|
lines.push('No imports, exports, or env vars detected in the code.');
|
|
801
1007
|
}
|
|
1008
|
+
// Track hallucination catches for usage stats
|
|
1009
|
+
const catchCount = result.imports.invalid.length + result.exports.invalid.length + result.envVars.invalid.length;
|
|
1010
|
+
if (catchCount > 0) {
|
|
1011
|
+
for (let i = 0; i < catchCount; i++)
|
|
1012
|
+
(0, usage_stats_1.trackCatch)();
|
|
1013
|
+
}
|
|
802
1014
|
return {
|
|
803
1015
|
jsonrpc: '2.0', id,
|
|
804
1016
|
result: { content: [{ type: 'text', text: lines.join('\n') }] },
|
|
@@ -892,9 +1104,37 @@ function createMCPHandler(memoryStore, eventLog, workspaceRoot) {
|
|
|
892
1104
|
const parts = [];
|
|
893
1105
|
// ─── BRAIN LAYER 0: End previous session + start new one ─────────
|
|
894
1106
|
(0, session_tracker_1.endSession)(memoryStore); // Save previous session summary
|
|
1107
|
+
(0, file_relationships_1.storeRelationships)(memoryStore); // Persist file co-edit relationships
|
|
895
1108
|
(0, session_tracker_1.startSession)();
|
|
1109
|
+
(0, usage_stats_1.resetSessionStats)();
|
|
896
1110
|
if (args.topic)
|
|
897
1111
|
(0, session_tracker_1.feedSession)({ topic: args.topic });
|
|
1112
|
+
// ─── BRAIN LAYER 0.5: Auto-scan on first run (Day 1 Empty Brain fix) ───
|
|
1113
|
+
if (memoryStore.activeCount() === 0 && workspaceRoot) {
|
|
1114
|
+
try {
|
|
1115
|
+
console.log(` [AUTO-SCAN] First run detected — scanning project...`);
|
|
1116
|
+
const scanner = new project_scanner_1.ProjectScanner(memoryStore, workspaceRoot);
|
|
1117
|
+
const scanCount = await scanner.scan();
|
|
1118
|
+
let extraMemories = 0;
|
|
1119
|
+
try {
|
|
1120
|
+
extraMemories += (0, export_map_1.storeExportMap)(memoryStore, (0, export_map_1.buildExportMap)(workspaceRoot));
|
|
1121
|
+
}
|
|
1122
|
+
catch { }
|
|
1123
|
+
try {
|
|
1124
|
+
extraMemories += (0, architecture_graph_1.storeArchitectureGraph)(memoryStore, (0, architecture_graph_1.buildArchitectureGraph)(workspaceRoot));
|
|
1125
|
+
}
|
|
1126
|
+
catch { }
|
|
1127
|
+
const total = scanCount + extraMemories;
|
|
1128
|
+
if (total > 0) {
|
|
1129
|
+
parts.push(`## Welcome to Cortex\n\nFirst run detected — auto-scanned your project and created ${total} memories (stack, structure, config, git history, exports, architecture). Cortex will now remember everything across sessions.`);
|
|
1130
|
+
(0, memory_cache_1.invalidateCache)();
|
|
1131
|
+
(0, usage_stats_1.trackScan)();
|
|
1132
|
+
}
|
|
1133
|
+
}
|
|
1134
|
+
catch (scanErr) {
|
|
1135
|
+
console.log(` [AUTO-SCAN] Failed: ${scanErr.message}`);
|
|
1136
|
+
}
|
|
1137
|
+
}
|
|
898
1138
|
// ─── BRAIN LAYER 1: Maintenance (runs in background) ─────────────
|
|
899
1139
|
try {
|
|
900
1140
|
// Decay old unused memories
|
|
@@ -972,17 +1212,30 @@ function createMCPHandler(memoryStore, eventLog, workspaceRoot) {
|
|
|
972
1212
|
return '';
|
|
973
1213
|
}
|
|
974
1214
|
})(),
|
|
975
|
-
// Layer 9: Topic Search
|
|
1215
|
+
// Layer 9: Topic Search — Hybrid (FTS + Vector) for deeper relevance
|
|
976
1216
|
(async () => {
|
|
977
1217
|
if (!args.topic)
|
|
978
1218
|
return '';
|
|
979
1219
|
try {
|
|
980
|
-
|
|
981
|
-
ftsResults = (
|
|
982
|
-
|
|
1220
|
+
// FTS search
|
|
1221
|
+
const ftsResults = memoryStore.searchFTS(args.topic, 15);
|
|
1222
|
+
// Vector search (semantic — catches what FTS misses)
|
|
1223
|
+
let vectorResults = [];
|
|
1224
|
+
if ((0, embedding_manager_1.isWorkerReady)()) {
|
|
1225
|
+
try {
|
|
1226
|
+
const topicEmbedding = await (0, embedding_manager_1.embedText)(args.topic);
|
|
1227
|
+
vectorResults = memoryStore.searchVector(new Float32Array(topicEmbedding), 10);
|
|
1228
|
+
}
|
|
1229
|
+
catch { /* vector search failure is non-fatal */ }
|
|
1230
|
+
}
|
|
1231
|
+
// Merge FTS + Vector, deduplicate by ID
|
|
1232
|
+
const merged = (0, memory_ranker_1.rankResults)(ftsResults, vectorResults, 20, args.currentFile);
|
|
1233
|
+
let ranked = merged.map(r => ({ ...r, matchMethod: 'hybrid' }));
|
|
1234
|
+
ranked = (0, confidence_decay_1.applyConfidenceDecay)(ranked);
|
|
1235
|
+
ranked = (0, attention_ranker_1.rankByAttention)(ranked, actionContext);
|
|
983
1236
|
const seen = new Set();
|
|
984
1237
|
const enriched = [];
|
|
985
|
-
for (const r of
|
|
1238
|
+
for (const r of ranked) {
|
|
986
1239
|
if (seen.has(r.memory.id))
|
|
987
1240
|
continue;
|
|
988
1241
|
seen.add(r.memory.id);
|
|
@@ -1052,13 +1305,58 @@ function createMCPHandler(memoryStore, eventLog, workspaceRoot) {
|
|
|
1052
1305
|
parts.push('\n' + result.value);
|
|
1053
1306
|
}
|
|
1054
1307
|
}
|
|
1055
|
-
// ─── SMART CONTEXT SELECTION:
|
|
1056
|
-
|
|
1308
|
+
// ─── SMART CONTEXT SELECTION: Priority-based trimming ────────────
|
|
1309
|
+
// Instead of dumb slicing, trim lowest-priority sections first
|
|
1057
1310
|
const MAX_CHARS = 12000; // ~3000 tokens — fits any model
|
|
1311
|
+
let output = parts.join('\n');
|
|
1058
1312
|
if (output.length > MAX_CHARS) {
|
|
1059
|
-
//
|
|
1060
|
-
|
|
1313
|
+
// Priority: highest first (kept), lowest first (trimmed)
|
|
1314
|
+
// Layers 0-5 are high priority (welcome, sessions, corrections, core context)
|
|
1315
|
+
// Layers 6-12 are lower priority (anticipation, temporal, git, topic, gaps, exports, arch)
|
|
1316
|
+
// Trim from end (lowest priority) working backwards
|
|
1317
|
+
while (output.length > MAX_CHARS && parts.length > 4) {
|
|
1318
|
+
parts.pop(); // Remove lowest-priority section
|
|
1319
|
+
output = parts.join('\n');
|
|
1320
|
+
}
|
|
1321
|
+
if (output.length > MAX_CHARS) {
|
|
1322
|
+
output = output.slice(0, MAX_CHARS);
|
|
1323
|
+
}
|
|
1324
|
+
output += '\n\n> (Some context trimmed to fit token budget. Use `recall_memory` for specific queries.)';
|
|
1325
|
+
}
|
|
1326
|
+
// Track usage stats
|
|
1327
|
+
const memoriesInOutput = (output.match(/\[(?:CORRECTION|DECISION|CONVENTION|BUG_FIX|INSIGHT)\]/g) || []).length;
|
|
1328
|
+
(0, usage_stats_1.trackRecall)(memoriesInOutput);
|
|
1329
|
+
// Inject contextual instructions (DO/DON'T/WATCH-OUT)
|
|
1330
|
+
try {
|
|
1331
|
+
const instructions = (0, instructions_generator_1.generateInstructions)(memoryStore);
|
|
1332
|
+
const instructionText = (0, instructions_generator_1.formatInstructions)(instructions);
|
|
1333
|
+
if (instructionText)
|
|
1334
|
+
output += '\n\n' + instructionText;
|
|
1061
1335
|
}
|
|
1336
|
+
catch { /* non-fatal */ }
|
|
1337
|
+
// Inject tool recommendations (what to use based on context)
|
|
1338
|
+
try {
|
|
1339
|
+
const recs = (0, tool_recommender_1.recommendTools)({
|
|
1340
|
+
topic: args.topic,
|
|
1341
|
+
currentFile: args.currentFile,
|
|
1342
|
+
isNewConversation: true,
|
|
1343
|
+
});
|
|
1344
|
+
const recText = (0, tool_recommender_1.formatRecommendations)(recs);
|
|
1345
|
+
if (recText)
|
|
1346
|
+
output += '\n\n' + recText;
|
|
1347
|
+
}
|
|
1348
|
+
catch { /* non-fatal */ }
|
|
1349
|
+
// Inject user preferences (adapts AI behavior)
|
|
1350
|
+
try {
|
|
1351
|
+
const prefText = (0, preference_learner_1.getStoredPreferences)(memoryStore);
|
|
1352
|
+
if (prefText)
|
|
1353
|
+
output += '\n\n' + prefText;
|
|
1354
|
+
}
|
|
1355
|
+
catch { /* non-fatal */ }
|
|
1356
|
+
// Append stats footer (makes value visible)
|
|
1357
|
+
const statsFooter = (0, usage_stats_1.formatStatsFooter)();
|
|
1358
|
+
if (statsFooter)
|
|
1359
|
+
output += statsFooter;
|
|
1062
1360
|
// Cache the result for short-lived reuse
|
|
1063
1361
|
(0, memory_cache_1.setCache)(cacheKey, output);
|
|
1064
1362
|
return {
|
|
@@ -1073,6 +1371,102 @@ function createMCPHandler(memoryStore, eventLog, workspaceRoot) {
|
|
|
1073
1371
|
};
|
|
1074
1372
|
}
|
|
1075
1373
|
}
|
|
1374
|
+
// ─── REVIEW CODE: Check against conventions + past bugs ─────────────
|
|
1375
|
+
function handleReviewCode(id, args) {
|
|
1376
|
+
try {
|
|
1377
|
+
const code = args.code;
|
|
1378
|
+
const filename = args.filename || '';
|
|
1379
|
+
if (!code || code.length < 10) {
|
|
1380
|
+
return {
|
|
1381
|
+
jsonrpc: '2.0', id,
|
|
1382
|
+
result: { content: [{ type: 'text', text: 'Error: provide code to review (min 10 chars)' }], isError: true },
|
|
1383
|
+
};
|
|
1384
|
+
}
|
|
1385
|
+
const violations = [];
|
|
1386
|
+
const suggestions = [];
|
|
1387
|
+
const codeLower = code.toLowerCase();
|
|
1388
|
+
// Check against stored CONVENTIONS
|
|
1389
|
+
const conventions = memoryStore.getByType('CONVENTION', 100);
|
|
1390
|
+
for (const conv of conventions) {
|
|
1391
|
+
const intentLower = conv.intent.toLowerCase();
|
|
1392
|
+
// Check for common pattern violations
|
|
1393
|
+
if (intentLower.includes('never use') || intentLower.includes("don't use") || intentLower.includes('avoid')) {
|
|
1394
|
+
// Extract the forbidden thing
|
|
1395
|
+
const match = intentLower.match(/(?:never use|don't use|avoid)\s+(\w+(?:\s+\w+)?)/i);
|
|
1396
|
+
if (match) {
|
|
1397
|
+
const forbidden = match[1].toLowerCase();
|
|
1398
|
+
if (codeLower.includes(forbidden)) {
|
|
1399
|
+
violations.push(`⚠️ **Convention Violation** \`id:${conv.id}\`: "${conv.intent}" — Found \`${forbidden}\` in your code`);
|
|
1400
|
+
}
|
|
1401
|
+
}
|
|
1402
|
+
}
|
|
1403
|
+
if (intentLower.includes('always use') || intentLower.includes('must use')) {
|
|
1404
|
+
const match = intentLower.match(/(?:always use|must use)\s+(\w+(?:\s+\w+)?)/i);
|
|
1405
|
+
if (match) {
|
|
1406
|
+
const required = match[1].toLowerCase();
|
|
1407
|
+
if (!codeLower.includes(required) && code.length > 50) {
|
|
1408
|
+
suggestions.push(`💡 **Convention Suggestion** \`id:${conv.id}\`: "${conv.intent}" — Consider using \`${required}\``);
|
|
1409
|
+
}
|
|
1410
|
+
}
|
|
1411
|
+
}
|
|
1412
|
+
}
|
|
1413
|
+
// Check against stored BUG_FIX patterns
|
|
1414
|
+
const bugFixes = memoryStore.getByType('BUG_FIX', 50);
|
|
1415
|
+
for (const bug of bugFixes) {
|
|
1416
|
+
const bugLower = bug.intent.toLowerCase();
|
|
1417
|
+
// Extract key terms from bug description
|
|
1418
|
+
const bugTerms = bugLower.split(/\s+/).filter(w => w.length > 4);
|
|
1419
|
+
const matchCount = bugTerms.filter(t => codeLower.includes(t)).length;
|
|
1420
|
+
if (matchCount >= 3) {
|
|
1421
|
+
violations.push(`🐛 **Similar Bug Pattern** \`id:${bug.id}\`: "${bug.intent}" — This code has similarities to a past bug`);
|
|
1422
|
+
}
|
|
1423
|
+
}
|
|
1424
|
+
// Check for CORRECTION patterns
|
|
1425
|
+
const corrections = memoryStore.getByType('CORRECTION', 50);
|
|
1426
|
+
for (const corr of corrections) {
|
|
1427
|
+
const corrLower = corr.intent.toLowerCase();
|
|
1428
|
+
const corrTerms = corrLower.split(/\s+/).filter(w => w.length > 4);
|
|
1429
|
+
const matchCount = corrTerms.filter(t => codeLower.includes(t)).length;
|
|
1430
|
+
if (matchCount >= 3) {
|
|
1431
|
+
violations.push(`🔄 **Past Correction Applies** \`id:${corr.id}\`: "${corr.intent}"`);
|
|
1432
|
+
}
|
|
1433
|
+
}
|
|
1434
|
+
// File-specific memories
|
|
1435
|
+
if (filename) {
|
|
1436
|
+
const fileMemories = memoryStore.getByFile(filename, 10);
|
|
1437
|
+
for (const fm of fileMemories) {
|
|
1438
|
+
suggestions.push(`📄 **File Note** \`id:${fm.id}\`: "${fm.intent}"`);
|
|
1439
|
+
}
|
|
1440
|
+
}
|
|
1441
|
+
(0, usage_stats_1.trackReview)();
|
|
1442
|
+
const lines = ['# Cortex Code Review\n'];
|
|
1443
|
+
if (violations.length > 0) {
|
|
1444
|
+
lines.push(`## ⚠️ ${violations.length} Issue${violations.length > 1 ? 's' : ''} Found\n`);
|
|
1445
|
+
violations.forEach(v => lines.push(v));
|
|
1446
|
+
}
|
|
1447
|
+
if (suggestions.length > 0) {
|
|
1448
|
+
lines.push(`\n## 💡 ${suggestions.length} Suggestion${suggestions.length > 1 ? 's' : ''}\n`);
|
|
1449
|
+
suggestions.forEach(s => lines.push(s));
|
|
1450
|
+
}
|
|
1451
|
+
if (violations.length === 0 && suggestions.length === 0) {
|
|
1452
|
+
lines.push('✅ **No issues found.** Code looks clean against your stored conventions and past bugs.');
|
|
1453
|
+
lines.push(`\n_Checked against ${conventions.length} conventions, ${bugFixes.length} bug fixes, ${corrections.length} corrections._`);
|
|
1454
|
+
}
|
|
1455
|
+
else {
|
|
1456
|
+
lines.push(`\n_Reviewed against ${conventions.length} conventions, ${bugFixes.length} bug fixes, ${corrections.length} corrections._`);
|
|
1457
|
+
}
|
|
1458
|
+
return {
|
|
1459
|
+
jsonrpc: '2.0', id,
|
|
1460
|
+
result: { content: [{ type: 'text', text: lines.join('\n') }] },
|
|
1461
|
+
};
|
|
1462
|
+
}
|
|
1463
|
+
catch (err) {
|
|
1464
|
+
return {
|
|
1465
|
+
jsonrpc: '2.0', id,
|
|
1466
|
+
result: { content: [{ type: 'text', text: `Review error: ${err.message}` }], isError: true },
|
|
1467
|
+
};
|
|
1468
|
+
}
|
|
1469
|
+
}
|
|
1076
1470
|
function handleUpdateMemory(id, args) {
|
|
1077
1471
|
try {
|
|
1078
1472
|
const memoryId = args.id;
|
|
@@ -1311,6 +1705,137 @@ function createMCPHandler(memoryStore, eventLog, workspaceRoot) {
|
|
|
1311
1705
|
}
|
|
1312
1706
|
if (stored.length > 0) {
|
|
1313
1707
|
(0, memory_cache_1.invalidateCache)();
|
|
1708
|
+
for (let i = 0; i < stored.length; i++)
|
|
1709
|
+
(0, usage_stats_1.trackStore)();
|
|
1710
|
+
}
|
|
1711
|
+
// ─── Auto-correction capture ─────────────────────────────────────
|
|
1712
|
+
// Scan AI text for self-corrections ("I apologize", "you're right")
|
|
1713
|
+
const aiCorrections = (0, correction_detector_1.detectAIAcknowledgments)(text);
|
|
1714
|
+
for (const corr of aiCorrections) {
|
|
1715
|
+
try {
|
|
1716
|
+
const corrResult = (0, memory_quality_1.storeWithQuality)(memoryStore, {
|
|
1717
|
+
type: 'CORRECTION',
|
|
1718
|
+
intent: `[AUTO-DETECTED] ${corr.fullContext}`,
|
|
1719
|
+
action: corr.fullContext,
|
|
1720
|
+
reason: `AI self-correction detected (confidence: ${corr.confidence})`,
|
|
1721
|
+
confidence: corr.confidence,
|
|
1722
|
+
importance: 0.90, // High importance — corrections prevent repeats
|
|
1723
|
+
tags: ['auto-correction', 'ai-acknowledgment'],
|
|
1724
|
+
});
|
|
1725
|
+
if (corrResult.stored) {
|
|
1726
|
+
stored.push(`[CORRECTION] ${corr.fullContext.slice(0, 60)}…`);
|
|
1727
|
+
}
|
|
1728
|
+
}
|
|
1729
|
+
catch { /* skip */ }
|
|
1730
|
+
}
|
|
1731
|
+
// Scan user context for direct corrections ("no, use X not Y")
|
|
1732
|
+
const userContext = args.context;
|
|
1733
|
+
if (userContext && userContext.length > 10) {
|
|
1734
|
+
const userCorrections = (0, correction_detector_1.detectUserCorrections)(userContext);
|
|
1735
|
+
for (const corr of userCorrections) {
|
|
1736
|
+
try {
|
|
1737
|
+
const content = corr.corrected
|
|
1738
|
+
? `User correction: use "${corr.corrected}"${corr.original ? ` instead of "${corr.original}"` : ''}`
|
|
1739
|
+
: `User correction: ${corr.fullContext}`;
|
|
1740
|
+
const corrResult = (0, memory_quality_1.storeWithQuality)(memoryStore, {
|
|
1741
|
+
type: 'CORRECTION',
|
|
1742
|
+
intent: content,
|
|
1743
|
+
action: corr.fullContext,
|
|
1744
|
+
reason: `User correction detected (confidence: ${corr.confidence})`,
|
|
1745
|
+
confidence: corr.confidence,
|
|
1746
|
+
importance: 0.95, // Very high — user corrections are gospel
|
|
1747
|
+
tags: ['auto-correction', 'user-correction'],
|
|
1748
|
+
});
|
|
1749
|
+
if (corrResult.stored) {
|
|
1750
|
+
stored.push(`[USER CORRECTION] ${content.slice(0, 60)}…`);
|
|
1751
|
+
(0, memory_cache_1.invalidateCache)();
|
|
1752
|
+
}
|
|
1753
|
+
}
|
|
1754
|
+
catch { /* skip */ }
|
|
1755
|
+
}
|
|
1756
|
+
// ─── Preference learning ─────────────────────────────────
|
|
1757
|
+
const prefs = (0, preference_learner_1.detectPreferences)(userContext);
|
|
1758
|
+
for (const pref of prefs) {
|
|
1759
|
+
try {
|
|
1760
|
+
const prefResult = (0, memory_quality_1.storeWithQuality)(memoryStore, {
|
|
1761
|
+
type: 'CONVENTION',
|
|
1762
|
+
intent: pref.preference,
|
|
1763
|
+
action: `Detected from: "${pref.evidence}"`,
|
|
1764
|
+
reason: `User preference auto-detected (${pref.category})`,
|
|
1765
|
+
confidence: pref.confidence,
|
|
1766
|
+
importance: 0.85,
|
|
1767
|
+
tags: ['preference', pref.category],
|
|
1768
|
+
});
|
|
1769
|
+
if (prefResult.stored) {
|
|
1770
|
+
stored.push(`[PREFERENCE] ${pref.preference.slice(0, 60)}…`);
|
|
1771
|
+
(0, memory_cache_1.invalidateCache)();
|
|
1772
|
+
}
|
|
1773
|
+
}
|
|
1774
|
+
catch { /* skip */ }
|
|
1775
|
+
}
|
|
1776
|
+
}
|
|
1777
|
+
// ─── Build error learning ──────────────────────────────────
|
|
1778
|
+
// Scan for TS errors, test failures in AI text
|
|
1779
|
+
if ((0, error_learner_1.containsErrors)(text)) {
|
|
1780
|
+
const errorPatterns = (0, error_learner_1.extractErrorPatterns)(text);
|
|
1781
|
+
// Extract verification steps for regression prevention
|
|
1782
|
+
const verifySteps = (0, regression_guard_1.extractVerificationSteps)(text);
|
|
1783
|
+
for (const ep of errorPatterns) {
|
|
1784
|
+
try {
|
|
1785
|
+
const baseAction = `Auto-captured from build/test output`;
|
|
1786
|
+
const actionWithVerify = (0, regression_guard_1.attachVerification)(baseAction, verifySteps);
|
|
1787
|
+
const errResult = (0, memory_quality_1.storeWithQuality)(memoryStore, {
|
|
1788
|
+
type: 'BUG_FIX',
|
|
1789
|
+
intent: `[ERROR PATTERN] ${ep.errorType}: ${ep.message}`,
|
|
1790
|
+
action: actionWithVerify,
|
|
1791
|
+
reason: `Error pattern auto-detected — avoid this in future`,
|
|
1792
|
+
confidence: ep.confidence,
|
|
1793
|
+
importance: 0.90,
|
|
1794
|
+
tags: ['error-pattern', ep.errorType.toLowerCase(), 'auto-detected'],
|
|
1795
|
+
});
|
|
1796
|
+
if (errResult.stored) {
|
|
1797
|
+
stored.push(`[ERROR LEARNED] ${ep.errorType}: ${ep.message.slice(0, 50)}…`);
|
|
1798
|
+
(0, memory_cache_1.invalidateCache)();
|
|
1799
|
+
}
|
|
1800
|
+
}
|
|
1801
|
+
catch { /* skip */ }
|
|
1802
|
+
}
|
|
1803
|
+
}
|
|
1804
|
+
// ─── Success reinforcement ─────────────────────────────────
|
|
1805
|
+
// Scan user context for praise/success signals
|
|
1806
|
+
if (userContext && userContext.length > 5) {
|
|
1807
|
+
const successSignals = (0, success_tracker_1.detectSuccess)(userContext);
|
|
1808
|
+
for (const signal of successSignals) {
|
|
1809
|
+
try {
|
|
1810
|
+
const mem = (0, success_tracker_1.buildSuccessMemory)(signal, text);
|
|
1811
|
+
const successResult = (0, memory_quality_1.storeWithQuality)(memoryStore, {
|
|
1812
|
+
type: 'INSIGHT',
|
|
1813
|
+
intent: mem.intent,
|
|
1814
|
+
action: text.slice(0, 200),
|
|
1815
|
+
reason: mem.reason,
|
|
1816
|
+
confidence: signal.confidence,
|
|
1817
|
+
importance: 0.80,
|
|
1818
|
+
tags: mem.tags,
|
|
1819
|
+
});
|
|
1820
|
+
if (successResult.stored) {
|
|
1821
|
+
stored.push(`[SUCCESS] Proven approach stored from: "${signal.trigger}"`);
|
|
1822
|
+
(0, memory_cache_1.invalidateCache)();
|
|
1823
|
+
}
|
|
1824
|
+
}
|
|
1825
|
+
catch { /* skip */ }
|
|
1826
|
+
}
|
|
1827
|
+
}
|
|
1828
|
+
// ─── File relationship tracking ────────────────────────────
|
|
1829
|
+
// Track files mentioned in context for co-edit detection
|
|
1830
|
+
if (userContext) {
|
|
1831
|
+
const filePatterns = userContext.match(/[\w-]+\.\w{1,5}/g) || [];
|
|
1832
|
+
const codeFileExts = new Set(['ts', 'tsx', 'js', 'jsx', 'css', 'py', 'go', 'rs', 'java']);
|
|
1833
|
+
for (const f of filePatterns) {
|
|
1834
|
+
const ext = f.split('.').pop()?.toLowerCase() || '';
|
|
1835
|
+
if (codeFileExts.has(ext)) {
|
|
1836
|
+
(0, file_relationships_1.recordFileEdit)(f);
|
|
1837
|
+
}
|
|
1838
|
+
}
|
|
1314
1839
|
}
|
|
1315
1840
|
const lines = ['**Auto-Learn Results:**'];
|
|
1316
1841
|
if (stored.length > 0) {
|
|
@@ -1412,6 +1937,101 @@ function createMCPHandler(memoryStore, eventLog, workspaceRoot) {
|
|
|
1412
1937
|
};
|
|
1413
1938
|
}
|
|
1414
1939
|
}
|
|
1940
|
+
// ─── Pre-Flight Check Handler ───────────────────────────────────────────────
|
|
1941
|
+
function handlePreCheck(id, args) {
|
|
1942
|
+
try {
|
|
1943
|
+
// Track file for relationship mapping
|
|
1944
|
+
if (args.filename)
|
|
1945
|
+
(0, file_relationships_1.recordFileEdit)(args.filename);
|
|
1946
|
+
const result = (0, pre_flight_1.preFlightCheck)(memoryStore, args.filename, args.task);
|
|
1947
|
+
let text = (0, pre_flight_1.formatPreFlight)(result);
|
|
1948
|
+
// Add file relationship warnings
|
|
1949
|
+
if (args.filename) {
|
|
1950
|
+
const warnings = (0, file_relationships_1.checkMissingRelated)(args.filename, memoryStore);
|
|
1951
|
+
if (warnings.length > 0) {
|
|
1952
|
+
text += '\n\n## 🔗 File Relationships\n';
|
|
1953
|
+
warnings.forEach(w => text += w + '\n');
|
|
1954
|
+
}
|
|
1955
|
+
}
|
|
1956
|
+
// Add architecture context — show file's role in the system
|
|
1957
|
+
if (args.filename && workspaceRoot) {
|
|
1958
|
+
try {
|
|
1959
|
+
const archGraph = (0, architecture_graph_1.buildArchitectureGraph)(workspaceRoot);
|
|
1960
|
+
const basename = args.filename.replace(/\\/g, '/').split('/').pop() || args.filename;
|
|
1961
|
+
// nodes is Map<string, ArchNode> — find by key ending with basename
|
|
1962
|
+
let deps = null;
|
|
1963
|
+
for (const [key, node] of archGraph.nodes) {
|
|
1964
|
+
if (key.endsWith(basename)) {
|
|
1965
|
+
deps = node;
|
|
1966
|
+
break;
|
|
1967
|
+
}
|
|
1968
|
+
}
|
|
1969
|
+
if (deps && (deps.imports?.length > 0 || deps.importedBy?.length > 0)) {
|
|
1970
|
+
text += '\n\n## \ud83c\udfd7\ufe0f Architecture Context';
|
|
1971
|
+
if (deps.imports?.length > 0) {
|
|
1972
|
+
text += `\n**Imports from:** ${deps.imports.slice(0, 10).join(', ')}`;
|
|
1973
|
+
}
|
|
1974
|
+
if (deps.importedBy?.length > 0) {
|
|
1975
|
+
text += `\n**Imported by:** ${deps.importedBy.slice(0, 10).join(', ')}`;
|
|
1976
|
+
}
|
|
1977
|
+
}
|
|
1978
|
+
}
|
|
1979
|
+
catch { /* non-fatal */ }
|
|
1980
|
+
}
|
|
1981
|
+
return {
|
|
1982
|
+
jsonrpc: '2.0', id,
|
|
1983
|
+
result: { content: [{ type: 'text', text }] },
|
|
1984
|
+
};
|
|
1985
|
+
}
|
|
1986
|
+
catch (err) {
|
|
1987
|
+
return {
|
|
1988
|
+
jsonrpc: '2.0', id,
|
|
1989
|
+
result: { content: [{ type: 'text', text: `Pre-check error: ${err.message}` }], isError: true },
|
|
1990
|
+
};
|
|
1991
|
+
}
|
|
1992
|
+
}
|
|
1993
|
+
// ─── Impact Analysis Handler ───────────────────────────────────────────────
|
|
1994
|
+
function handleCheckImpact(id, args) {
|
|
1995
|
+
try {
|
|
1996
|
+
const file = args.file;
|
|
1997
|
+
if (!file) {
|
|
1998
|
+
return {
|
|
1999
|
+
jsonrpc: '2.0', id,
|
|
2000
|
+
result: { content: [{ type: 'text', text: 'Error: file parameter is required' }], isError: true },
|
|
2001
|
+
};
|
|
2002
|
+
}
|
|
2003
|
+
const wsRoot = args.workspaceRoot || process.cwd();
|
|
2004
|
+
const result = (0, impact_analyzer_1.analyzeImpact)(file, wsRoot);
|
|
2005
|
+
const text = (0, impact_analyzer_1.formatImpact)(result);
|
|
2006
|
+
return {
|
|
2007
|
+
jsonrpc: '2.0', id,
|
|
2008
|
+
result: { content: [{ type: 'text', text }] },
|
|
2009
|
+
};
|
|
2010
|
+
}
|
|
2011
|
+
catch (err) {
|
|
2012
|
+
return {
|
|
2013
|
+
jsonrpc: '2.0', id,
|
|
2014
|
+
result: { content: [{ type: 'text', text: `Impact analysis error: ${err.message}` }], isError: true },
|
|
2015
|
+
};
|
|
2016
|
+
}
|
|
2017
|
+
}
|
|
2018
|
+
// ─── Resume Work Handler ───────────────────────────────────────────────────
|
|
2019
|
+
function handleResumeWork(id) {
|
|
2020
|
+
try {
|
|
2021
|
+
const ctx = (0, resume_work_1.buildResumeContext)(memoryStore);
|
|
2022
|
+
const text = (0, resume_work_1.formatResumeContext)(ctx);
|
|
2023
|
+
return {
|
|
2024
|
+
jsonrpc: '2.0', id,
|
|
2025
|
+
result: { content: [{ type: 'text', text }] },
|
|
2026
|
+
};
|
|
2027
|
+
}
|
|
2028
|
+
catch (err) {
|
|
2029
|
+
return {
|
|
2030
|
+
jsonrpc: '2.0', id,
|
|
2031
|
+
result: { content: [{ type: 'text', text: `Resume work error: ${err.message}` }], isError: true },
|
|
2032
|
+
};
|
|
2033
|
+
}
|
|
2034
|
+
}
|
|
1415
2035
|
return { handleMCPRequest };
|
|
1416
2036
|
}
|
|
1417
2037
|
//# sourceMappingURL=mcp-handler.js.map
|