cortex-mcp 1.2.4 → 1.4.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (63) hide show
  1. package/dist/db/memory-store.d.ts +2 -2
  2. package/dist/db/memory-store.d.ts.map +1 -1
  3. package/dist/db/memory-store.js +26 -4
  4. package/dist/db/memory-store.js.map +1 -1
  5. package/dist/memory/auto-learner.d.ts.map +1 -1
  6. package/dist/memory/auto-learner.js +62 -23
  7. package/dist/memory/auto-learner.js.map +1 -1
  8. package/dist/memory/convention-detector.d.ts +11 -0
  9. package/dist/memory/convention-detector.d.ts.map +1 -0
  10. package/dist/memory/convention-detector.js +294 -0
  11. package/dist/memory/convention-detector.js.map +1 -0
  12. package/dist/memory/correction-detector.d.ts +33 -0
  13. package/dist/memory/correction-detector.d.ts.map +1 -0
  14. package/dist/memory/correction-detector.js +129 -0
  15. package/dist/memory/correction-detector.js.map +1 -0
  16. package/dist/memory/error-learner.d.ts +26 -0
  17. package/dist/memory/error-learner.d.ts.map +1 -0
  18. package/dist/memory/error-learner.js +145 -0
  19. package/dist/memory/error-learner.js.map +1 -0
  20. package/dist/memory/file-relationships.d.ts +47 -0
  21. package/dist/memory/file-relationships.d.ts.map +1 -0
  22. package/dist/memory/file-relationships.js +130 -0
  23. package/dist/memory/file-relationships.js.map +1 -0
  24. package/dist/memory/impact-analyzer.d.ts +16 -0
  25. package/dist/memory/impact-analyzer.d.ts.map +1 -0
  26. package/dist/memory/impact-analyzer.js +189 -0
  27. package/dist/memory/impact-analyzer.js.map +1 -0
  28. package/dist/memory/instructions-generator.d.ts +30 -0
  29. package/dist/memory/instructions-generator.d.ts.map +1 -0
  30. package/dist/memory/instructions-generator.js +117 -0
  31. package/dist/memory/instructions-generator.js.map +1 -0
  32. package/dist/memory/pre-flight.d.ts +24 -0
  33. package/dist/memory/pre-flight.d.ts.map +1 -0
  34. package/dist/memory/pre-flight.js +121 -0
  35. package/dist/memory/pre-flight.js.map +1 -0
  36. package/dist/memory/preference-learner.d.ts +28 -0
  37. package/dist/memory/preference-learner.d.ts.map +1 -0
  38. package/dist/memory/preference-learner.js +144 -0
  39. package/dist/memory/preference-learner.js.map +1 -0
  40. package/dist/memory/regression-guard.d.ts +35 -0
  41. package/dist/memory/regression-guard.d.ts.map +1 -0
  42. package/dist/memory/regression-guard.js +90 -0
  43. package/dist/memory/regression-guard.js.map +1 -0
  44. package/dist/memory/resume-work.d.ts +37 -0
  45. package/dist/memory/resume-work.d.ts.map +1 -0
  46. package/dist/memory/resume-work.js +122 -0
  47. package/dist/memory/resume-work.js.map +1 -0
  48. package/dist/memory/success-tracker.d.ts +33 -0
  49. package/dist/memory/success-tracker.d.ts.map +1 -0
  50. package/dist/memory/success-tracker.js +75 -0
  51. package/dist/memory/success-tracker.js.map +1 -0
  52. package/dist/memory/tool-recommender.d.ts +29 -0
  53. package/dist/memory/tool-recommender.d.ts.map +1 -0
  54. package/dist/memory/tool-recommender.js +117 -0
  55. package/dist/memory/tool-recommender.js.map +1 -0
  56. package/dist/memory/usage-stats.d.ts +59 -0
  57. package/dist/memory/usage-stats.d.ts.map +1 -0
  58. package/dist/memory/usage-stats.js +122 -0
  59. package/dist/memory/usage-stats.js.map +1 -0
  60. package/dist/server/mcp-handler.d.ts.map +1 -1
  61. package/dist/server/mcp-handler.js +634 -14
  62. package/dist/server/mcp-handler.js.map +1 -1
  63. package/package.json +1 -1
@@ -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: 'cortex', version: '2.0.0' },
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: 'Brain Context',
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
- : 'Project was already scanned. No new memories created.',
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 (depends on actionContext but is safe to run in parallel)
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
- let ftsResults = memoryStore.searchFTS(args.topic, 15);
981
- ftsResults = (0, confidence_decay_1.applyConfidenceDecay)(ftsResults);
982
- ftsResults = (0, attention_ranker_1.rankByAttention)(ftsResults, actionContext);
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 ftsResults) {
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: Trim to token budget ───────────────
1056
- let output = parts.join('\n');
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
- // Keep critical sections, trim lower-priority ones
1060
- output = output.slice(0, MAX_CHARS) + '\n\n> (Context trimmed to fit token budget. Use `recall_memory` for specific queries.)';
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