cortex-mcp 1.0.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 (176) hide show
  1. package/CHANGELOG.md +54 -0
  2. package/LICENSE +21 -0
  3. package/README.md +202 -0
  4. package/dist/cli/setup.d.ts +12 -0
  5. package/dist/cli/setup.d.ts.map +1 -0
  6. package/dist/cli/setup.js +293 -0
  7. package/dist/cli/setup.js.map +1 -0
  8. package/dist/config/config.d.ts +13 -0
  9. package/dist/config/config.d.ts.map +1 -0
  10. package/dist/config/config.js +33 -0
  11. package/dist/config/config.js.map +1 -0
  12. package/dist/core/event-bus.d.ts +19 -0
  13. package/dist/core/event-bus.d.ts.map +1 -0
  14. package/dist/core/event-bus.js +51 -0
  15. package/dist/core/event-bus.js.map +1 -0
  16. package/dist/db/database.d.ts +19 -0
  17. package/dist/db/database.d.ts.map +1 -0
  18. package/dist/db/database.js +254 -0
  19. package/dist/db/database.js.map +1 -0
  20. package/dist/db/event-log.d.ts +28 -0
  21. package/dist/db/event-log.d.ts.map +1 -0
  22. package/dist/db/event-log.js +87 -0
  23. package/dist/db/event-log.js.map +1 -0
  24. package/dist/db/memory-store.d.ts +65 -0
  25. package/dist/db/memory-store.d.ts.map +1 -0
  26. package/dist/db/memory-store.js +370 -0
  27. package/dist/db/memory-store.js.map +1 -0
  28. package/dist/embedding-worker.d.ts +3 -0
  29. package/dist/embedding-worker.d.ts.map +1 -0
  30. package/dist/embedding-worker.js +94 -0
  31. package/dist/embedding-worker.js.map +1 -0
  32. package/dist/hooks/cortex-run.d.ts +15 -0
  33. package/dist/hooks/cortex-run.d.ts.map +1 -0
  34. package/dist/hooks/cortex-run.js +148 -0
  35. package/dist/hooks/cortex-run.js.map +1 -0
  36. package/dist/hooks/git-capture.d.ts +21 -0
  37. package/dist/hooks/git-capture.d.ts.map +1 -0
  38. package/dist/hooks/git-capture.js +178 -0
  39. package/dist/hooks/git-capture.js.map +1 -0
  40. package/dist/hooks/git-hooks.d.ts +12 -0
  41. package/dist/hooks/git-hooks.d.ts.map +1 -0
  42. package/dist/hooks/git-hooks.js +130 -0
  43. package/dist/hooks/git-hooks.js.map +1 -0
  44. package/dist/mcp-stdio.d.ts +10 -0
  45. package/dist/mcp-stdio.d.ts.map +1 -0
  46. package/dist/mcp-stdio.js +247 -0
  47. package/dist/mcp-stdio.js.map +1 -0
  48. package/dist/memory/anticipation-engine.d.ts +19 -0
  49. package/dist/memory/anticipation-engine.d.ts.map +1 -0
  50. package/dist/memory/anticipation-engine.js +76 -0
  51. package/dist/memory/anticipation-engine.js.map +1 -0
  52. package/dist/memory/attention-ranker.d.ts +19 -0
  53. package/dist/memory/attention-ranker.d.ts.map +1 -0
  54. package/dist/memory/attention-ranker.js +97 -0
  55. package/dist/memory/attention-ranker.js.map +1 -0
  56. package/dist/memory/auto-learner.d.ts +20 -0
  57. package/dist/memory/auto-learner.d.ts.map +1 -0
  58. package/dist/memory/auto-learner.js +179 -0
  59. package/dist/memory/auto-learner.js.map +1 -0
  60. package/dist/memory/confidence-decay.d.ts +22 -0
  61. package/dist/memory/confidence-decay.d.ts.map +1 -0
  62. package/dist/memory/confidence-decay.js +54 -0
  63. package/dist/memory/confidence-decay.js.map +1 -0
  64. package/dist/memory/embedding-manager.d.ts +5 -0
  65. package/dist/memory/embedding-manager.d.ts.map +1 -0
  66. package/dist/memory/embedding-manager.js +118 -0
  67. package/dist/memory/embedding-manager.js.map +1 -0
  68. package/dist/memory/export-import.d.ts +49 -0
  69. package/dist/memory/export-import.d.ts.map +1 -0
  70. package/dist/memory/export-import.js +131 -0
  71. package/dist/memory/export-import.js.map +1 -0
  72. package/dist/memory/git-memory.d.ts +15 -0
  73. package/dist/memory/git-memory.d.ts.map +1 -0
  74. package/dist/memory/git-memory.js +178 -0
  75. package/dist/memory/git-memory.js.map +1 -0
  76. package/dist/memory/learning-rate.d.ts +24 -0
  77. package/dist/memory/learning-rate.d.ts.map +1 -0
  78. package/dist/memory/learning-rate.js +95 -0
  79. package/dist/memory/learning-rate.js.map +1 -0
  80. package/dist/memory/llm-enhancer.d.ts +54 -0
  81. package/dist/memory/llm-enhancer.d.ts.map +1 -0
  82. package/dist/memory/llm-enhancer.js +270 -0
  83. package/dist/memory/llm-enhancer.js.map +1 -0
  84. package/dist/memory/memory-cache.d.ts +5 -0
  85. package/dist/memory/memory-cache.d.ts.map +1 -0
  86. package/dist/memory/memory-cache.js +37 -0
  87. package/dist/memory/memory-cache.js.map +1 -0
  88. package/dist/memory/memory-consolidator.d.ts +14 -0
  89. package/dist/memory/memory-consolidator.d.ts.map +1 -0
  90. package/dist/memory/memory-consolidator.js +156 -0
  91. package/dist/memory/memory-consolidator.js.map +1 -0
  92. package/dist/memory/memory-decay.d.ts +10 -0
  93. package/dist/memory/memory-decay.d.ts.map +1 -0
  94. package/dist/memory/memory-decay.js +79 -0
  95. package/dist/memory/memory-decay.js.map +1 -0
  96. package/dist/memory/memory-quality.d.ts +37 -0
  97. package/dist/memory/memory-quality.d.ts.map +1 -0
  98. package/dist/memory/memory-quality.js +203 -0
  99. package/dist/memory/memory-quality.js.map +1 -0
  100. package/dist/memory/memory-ranker.d.ts +14 -0
  101. package/dist/memory/memory-ranker.d.ts.map +1 -0
  102. package/dist/memory/memory-ranker.js +68 -0
  103. package/dist/memory/memory-ranker.js.map +1 -0
  104. package/dist/memory/meta-memory.d.ts +11 -0
  105. package/dist/memory/meta-memory.d.ts.map +1 -0
  106. package/dist/memory/meta-memory.js +141 -0
  107. package/dist/memory/meta-memory.js.map +1 -0
  108. package/dist/memory/session-tracker.d.ts +39 -0
  109. package/dist/memory/session-tracker.d.ts.map +1 -0
  110. package/dist/memory/session-tracker.js +127 -0
  111. package/dist/memory/session-tracker.js.map +1 -0
  112. package/dist/memory/temporal-engine.d.ts +25 -0
  113. package/dist/memory/temporal-engine.d.ts.map +1 -0
  114. package/dist/memory/temporal-engine.js +106 -0
  115. package/dist/memory/temporal-engine.js.map +1 -0
  116. package/dist/retrieval/hybrid-retriever.d.ts +23 -0
  117. package/dist/retrieval/hybrid-retriever.d.ts.map +1 -0
  118. package/dist/retrieval/hybrid-retriever.js +120 -0
  119. package/dist/retrieval/hybrid-retriever.js.map +1 -0
  120. package/dist/scanners/architecture-graph.d.ts +30 -0
  121. package/dist/scanners/architecture-graph.d.ts.map +1 -0
  122. package/dist/scanners/architecture-graph.js +315 -0
  123. package/dist/scanners/architecture-graph.js.map +1 -0
  124. package/dist/scanners/code-verifier.d.ts +70 -0
  125. package/dist/scanners/code-verifier.d.ts.map +1 -0
  126. package/dist/scanners/code-verifier.js +374 -0
  127. package/dist/scanners/code-verifier.js.map +1 -0
  128. package/dist/scanners/context-builder.d.ts +19 -0
  129. package/dist/scanners/context-builder.d.ts.map +1 -0
  130. package/dist/scanners/context-builder.js +102 -0
  131. package/dist/scanners/context-builder.js.map +1 -0
  132. package/dist/scanners/export-map.d.ts +22 -0
  133. package/dist/scanners/export-map.d.ts.map +1 -0
  134. package/dist/scanners/export-map.js +249 -0
  135. package/dist/scanners/export-map.js.map +1 -0
  136. package/dist/scanners/file-verifier.d.ts +22 -0
  137. package/dist/scanners/file-verifier.d.ts.map +1 -0
  138. package/dist/scanners/file-verifier.js +140 -0
  139. package/dist/scanners/file-verifier.js.map +1 -0
  140. package/dist/scanners/project-scanner.d.ts +31 -0
  141. package/dist/scanners/project-scanner.d.ts.map +1 -0
  142. package/dist/scanners/project-scanner.js +398 -0
  143. package/dist/scanners/project-scanner.js.map +1 -0
  144. package/dist/security/encryption.d.ts +15 -0
  145. package/dist/security/encryption.d.ts.map +1 -0
  146. package/dist/security/encryption.js +116 -0
  147. package/dist/security/encryption.js.map +1 -0
  148. package/dist/security/feature-gate.d.ts +30 -0
  149. package/dist/security/feature-gate.d.ts.map +1 -0
  150. package/dist/security/feature-gate.js +91 -0
  151. package/dist/security/feature-gate.js.map +1 -0
  152. package/dist/security/license.d.ts +24 -0
  153. package/dist/security/license.d.ts.map +1 -0
  154. package/dist/security/license.js +168 -0
  155. package/dist/security/license.js.map +1 -0
  156. package/dist/security/rate-limiter.d.ts +20 -0
  157. package/dist/security/rate-limiter.d.ts.map +1 -0
  158. package/dist/security/rate-limiter.js +60 -0
  159. package/dist/security/rate-limiter.js.map +1 -0
  160. package/dist/server/dashboard.d.ts +3 -0
  161. package/dist/server/dashboard.d.ts.map +1 -0
  162. package/dist/server/dashboard.js +258 -0
  163. package/dist/server/dashboard.js.map +1 -0
  164. package/dist/server/mcp-handler.d.ts +12 -0
  165. package/dist/server/mcp-handler.d.ts.map +1 -0
  166. package/dist/server/mcp-handler.js +1392 -0
  167. package/dist/server/mcp-handler.js.map +1 -0
  168. package/dist/strategies/embedders/local-minilm.d.ts +35 -0
  169. package/dist/strategies/embedders/local-minilm.d.ts.map +1 -0
  170. package/dist/strategies/embedders/local-minilm.js +176 -0
  171. package/dist/strategies/embedders/local-minilm.js.map +1 -0
  172. package/dist/types.d.ts +207 -0
  173. package/dist/types.d.ts.map +1 -0
  174. package/dist/types.js +83 -0
  175. package/dist/types.js.map +1 -0
  176. package/package.json +87 -0
@@ -0,0 +1,1392 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.createMCPHandler = createMCPHandler;
4
+ const types_1 = require("../types");
5
+ const memory_cache_1 = require("../memory/memory-cache");
6
+ const memory_ranker_1 = require("../memory/memory-ranker");
7
+ const embedding_manager_1 = require("../memory/embedding-manager");
8
+ const memory_quality_1 = require("../memory/memory-quality");
9
+ const project_scanner_1 = require("../scanners/project-scanner");
10
+ const file_verifier_1 = require("../scanners/file-verifier");
11
+ const context_builder_1 = require("../scanners/context-builder");
12
+ const code_verifier_1 = require("../scanners/code-verifier");
13
+ const auto_learner_1 = require("../memory/auto-learner");
14
+ const session_tracker_1 = require("../memory/session-tracker");
15
+ const anticipation_engine_1 = require("../memory/anticipation-engine");
16
+ const memory_consolidator_1 = require("../memory/memory-consolidator");
17
+ const attention_ranker_1 = require("../memory/attention-ranker");
18
+ const temporal_engine_1 = require("../memory/temporal-engine");
19
+ const learning_rate_1 = require("../memory/learning-rate");
20
+ const meta_memory_1 = require("../memory/meta-memory");
21
+ const confidence_decay_1 = require("../memory/confidence-decay");
22
+ const git_memory_1 = require("../memory/git-memory");
23
+ const export_map_1 = require("../scanners/export-map");
24
+ const architecture_graph_1 = require("../scanners/architecture-graph");
25
+ const rate_limiter_1 = require("../security/rate-limiter");
26
+ const license_1 = require("../security/license");
27
+ const feature_gate_1 = require("../security/feature-gate");
28
+ const export_import_1 = require("../memory/export-import");
29
+ const llm_enhancer_1 = require("../memory/llm-enhancer");
30
+ // --- Query Expansion (Synonym Map) ---
31
+ const SYNONYMS = {
32
+ auth: ['authentication', 'login', 'signin', 'sign-in', 'credentials'],
33
+ login: ['auth', 'authentication', 'signin', 'sign-in'],
34
+ db: ['database', 'sql', 'postgresql', 'postgres', 'mongodb', 'sqlite'],
35
+ database: ['db', 'sql', 'postgresql', 'postgres', 'mongodb', 'sqlite'],
36
+ api: ['endpoint', 'route', 'rest', 'graphql', 'http'],
37
+ error: ['bug', 'fix', 'issue', 'problem', 'crash', 'fail'],
38
+ bug: ['error', 'fix', 'issue', 'problem', 'crash'],
39
+ style: ['css', 'design', 'theme', 'color', 'font', 'layout'],
40
+ test: ['testing', 'jest', 'vitest', 'spec', 'unittest'],
41
+ deploy: ['deployment', 'ci', 'cd', 'pipeline', 'docker', 'build'],
42
+ };
43
+ function expandQuery(query) {
44
+ const words = query.toLowerCase().split(/\s+/).filter(w => w.length > 2);
45
+ const expanded = new Set(words);
46
+ for (const word of words) {
47
+ if (expanded.size >= 8)
48
+ break; // Cap expansion to prevent FTS hang
49
+ const syns = SYNONYMS[word];
50
+ if (syns) {
51
+ for (const s of syns.slice(0, 2)) {
52
+ if (expanded.size >= 8)
53
+ break;
54
+ expanded.add(s);
55
+ }
56
+ }
57
+ }
58
+ return Array.from(expanded).join(' OR ');
59
+ }
60
+ // --- MCP Tool Definitions ---
61
+ const MCP_TOOLS = [
62
+ {
63
+ name: 'recall_memory',
64
+ description: 'Search the persistent memory database for relevant past decisions, corrections, bugs, conventions, and insights from previous coding sessions. ALWAYS call this before answering user questions to check for relevant context.',
65
+ inputSchema: {
66
+ type: 'object',
67
+ properties: {
68
+ query: { type: 'string', description: 'What to search for in memory (e.g. "authentication bug fix", "database decision")' },
69
+ maxResults: { type: 'number', description: 'Maximum results to return (default 10)' },
70
+ currentFile: { type: 'string', description: 'Currently active file path (for relevance boosting)' },
71
+ },
72
+ required: ['query'],
73
+ },
74
+ },
75
+ {
76
+ name: 'store_memory',
77
+ description: 'Actively store an important decision, correction, bug fix, convention, or insight into the persistent memory database so it is remembered across sessions.',
78
+ inputSchema: {
79
+ type: 'object',
80
+ properties: {
81
+ type: { type: 'string', enum: ['DECISION', 'CORRECTION', 'BUG_FIX', 'CONVENTION', 'INSIGHT'], description: 'Type of memory' },
82
+ content: { type: 'string', description: 'What to remember — be concise and specific' },
83
+ reason: { type: 'string', description: 'Why this matters (optional)' },
84
+ files: { type: 'array', items: { type: 'string' }, description: 'Related file paths (optional)' },
85
+ tags: { type: 'array', items: { type: 'string' }, description: 'Tags for categorization (optional)' },
86
+ },
87
+ required: ['type', 'content'],
88
+ },
89
+ },
90
+ {
91
+ name: 'get_stats',
92
+ description: 'Get statistics about the memory database (active memories, total events, etc).',
93
+ inputSchema: {
94
+ type: 'object',
95
+ properties: {},
96
+ },
97
+ },
98
+ {
99
+ name: 'scan_project',
100
+ description: 'Scan the project to capture its stack, structure, config, and recent git history. Run once per project to solve the "Day 1 Empty Brain" problem.',
101
+ inputSchema: {
102
+ type: 'object',
103
+ properties: {
104
+ workspaceRoot: { type: 'string', description: 'Root directory of the project to scan' },
105
+ },
106
+ required: ['workspaceRoot'],
107
+ },
108
+ },
109
+ {
110
+ name: 'verify_files',
111
+ description: 'Verify file paths against the real file system to catch hallucinated paths. Pass AI-generated text and get back which file paths are valid and which are hallucinated.',
112
+ inputSchema: {
113
+ type: 'object',
114
+ properties: {
115
+ text: { type: 'string', description: 'Text containing file paths to verify (e.g. AI response)' },
116
+ workspaceRoot: { type: 'string', description: 'Root directory of the project' },
117
+ },
118
+ required: ['text', 'workspaceRoot'],
119
+ },
120
+ },
121
+ {
122
+ name: 'get_context',
123
+ description: 'Get dynamic context based on the current file and project. Returns compressed context with corrections, decisions, conventions, and file-specific history.',
124
+ inputSchema: {
125
+ type: 'object',
126
+ properties: {
127
+ currentFile: { type: 'string', description: 'Currently active file path' },
128
+ maxChars: { type: 'number', description: 'Maximum characters for context (default 3000)' },
129
+ },
130
+ },
131
+ },
132
+ {
133
+ name: 'verify_code',
134
+ description: 'Verify AI-generated code for hallucinations: checks if imported packages exist in package.json, if imported functions are actually exported from source files, and if referenced env variables exist in .env files.',
135
+ inputSchema: {
136
+ type: 'object',
137
+ properties: {
138
+ code: { type: 'string', description: 'The code to verify for hallucinated imports, exports, and env variables' },
139
+ workspaceRoot: { type: 'string', description: 'Root directory of the project' },
140
+ },
141
+ required: ['code'],
142
+ },
143
+ },
144
+ {
145
+ name: 'force_recall',
146
+ description: 'MANDATORY: Call this at the START of every conversation. Returns ALL corrections, decisions, conventions, and bug fixes. Also searches for topic-specific memories. This is the single entry point for complete context injection.',
147
+ inputSchema: {
148
+ type: 'object',
149
+ properties: {
150
+ topic: { type: 'string', description: 'What the user is asking about (used to search for relevant memories)' },
151
+ currentFile: { type: 'string', description: 'Currently active file path (optional)' },
152
+ },
153
+ required: ['topic'],
154
+ },
155
+ },
156
+ {
157
+ name: 'quick_store',
158
+ description: 'Quick-store a memory with just one sentence. Auto-classifies as CORRECTION, DECISION, CONVENTION, or BUG_FIX. Use this whenever you make or learn something worth remembering. Example: "Never use var, always use const in this project"',
159
+ inputSchema: {
160
+ type: 'object',
161
+ properties: {
162
+ memory: { type: 'string', description: 'One sentence describing the decision, correction, convention, or bug fix' },
163
+ },
164
+ required: ['memory'],
165
+ },
166
+ },
167
+ {
168
+ name: 'update_memory',
169
+ description: 'Update or supersede an existing memory when a decision changes. Use this when you previously stored something that is now outdated or incorrect. The old memory will be deactivated and replaced with the new content.',
170
+ inputSchema: {
171
+ type: 'object',
172
+ properties: {
173
+ id: { type: 'string', description: 'ID of the memory to update (from recall_memory results)' },
174
+ content: { type: 'string', description: 'New content to replace the old memory with' },
175
+ reason: { type: 'string', description: 'Why the memory is being updated (e.g. "switched from PostgreSQL to MongoDB")' },
176
+ },
177
+ required: ['id', 'content'],
178
+ },
179
+ },
180
+ {
181
+ name: 'list_memories',
182
+ description: 'List all stored memories grouped by type (DECISION, CORRECTION, CONVENTION, BUG_FIX, INSIGHT). Use this to browse what Cortex knows, or to find a memory ID for update_memory or delete_memory.',
183
+ inputSchema: {
184
+ type: 'object',
185
+ properties: {
186
+ type: { type: 'string', enum: ['DECISION', 'CORRECTION', 'CONVENTION', 'BUG_FIX', 'INSIGHT', 'ALL'], description: 'Filter by type (default: ALL)' },
187
+ limit: { type: 'number', description: 'Max memories to return per type (default: 20)' },
188
+ },
189
+ },
190
+ },
191
+ {
192
+ name: 'delete_memory',
193
+ description: 'Permanently deactivate a specific memory by ID. Use this to remove outdated or incorrect memories. The memory is soft-deleted (history preserved). Get the ID from list_memories or recall_memory.',
194
+ inputSchema: {
195
+ type: 'object',
196
+ properties: {
197
+ id: { type: 'string', description: 'ID of the memory to delete' },
198
+ reason: { type: 'string', description: 'Why this memory is being deleted (optional)' },
199
+ },
200
+ required: ['id'],
201
+ },
202
+ },
203
+ {
204
+ name: 'auto_learn',
205
+ description: 'CALL THIS AFTER EVERY RESPONSE. Pass the text of your response and Cortex will automatically extract and store any decisions, corrections, conventions, or bug fixes — with zero manual effort. This is how Cortex learns passively.',
206
+ inputSchema: {
207
+ type: 'object',
208
+ properties: {
209
+ text: { type: 'string', description: 'The text of your response to scan for memory-worthy patterns' },
210
+ context: { type: 'string', description: 'Optional: what the user was asking about (helps with categorization)' },
211
+ },
212
+ required: ['text'],
213
+ },
214
+ },
215
+ {
216
+ name: 'export_memories',
217
+ description: 'Export all active memories to a JSON bundle. Returns the full backup data that can be saved or transferred to another machine.',
218
+ inputSchema: {
219
+ type: 'object',
220
+ properties: {},
221
+ },
222
+ },
223
+ {
224
+ name: 'import_memories',
225
+ description: 'Import memories from a previously exported JSON bundle. Duplicates are automatically skipped.',
226
+ inputSchema: {
227
+ type: 'object',
228
+ properties: {
229
+ data: { type: 'string', description: 'The JSON string of an exported memory bundle' },
230
+ },
231
+ required: ['data'],
232
+ },
233
+ },
234
+ {
235
+ name: 'health_check',
236
+ description: 'Check the health and status of the Cortex server. Returns memory count, DB size, rate limit status, and uptime.',
237
+ inputSchema: {
238
+ type: 'object',
239
+ properties: {},
240
+ },
241
+ },
242
+ ];
243
+ // --- Dynamic Context via ContextBuilder ---
244
+ let cachedContextBuilder = null;
245
+ function getContextBuilder(memoryStore) {
246
+ if (!cachedContextBuilder) {
247
+ cachedContextBuilder = new context_builder_1.ContextBuilder(memoryStore);
248
+ }
249
+ return cachedContextBuilder;
250
+ }
251
+ // --- Core Handler ---
252
+ function createMCPHandler(memoryStore, eventLog, workspaceRoot) {
253
+ async function handleMCPRequest(rpc) {
254
+ const id = rpc.id;
255
+ switch (rpc.method) {
256
+ case 'initialize':
257
+ return {
258
+ jsonrpc: '2.0',
259
+ id,
260
+ result: {
261
+ protocolVersion: '2024-11-05',
262
+ capabilities: { tools: {}, resources: {} },
263
+ serverInfo: { name: 'cortex', version: '2.0.0' },
264
+ },
265
+ };
266
+ case 'notifications/initialized':
267
+ return null;
268
+ case 'tools/list':
269
+ return {
270
+ jsonrpc: '2.0',
271
+ id,
272
+ result: { tools: MCP_TOOLS },
273
+ };
274
+ case 'resources/list':
275
+ return {
276
+ jsonrpc: '2.0',
277
+ id,
278
+ result: {
279
+ resources: [{
280
+ uri: 'memory://brain/context',
281
+ name: 'Brain Context',
282
+ description: 'Top memories — corrections, decisions, conventions. Read this before every response.',
283
+ mimeType: 'text/plain',
284
+ }],
285
+ },
286
+ };
287
+ case 'resources/read': {
288
+ const uri = rpc.params?.uri;
289
+ if (uri === 'memory://brain/context') {
290
+ return {
291
+ jsonrpc: '2.0',
292
+ id,
293
+ result: {
294
+ contents: [{
295
+ uri: 'memory://brain/context',
296
+ mimeType: 'text/plain',
297
+ text: getContextBuilder(memoryStore).build(),
298
+ }],
299
+ },
300
+ };
301
+ }
302
+ return {
303
+ jsonrpc: '2.0',
304
+ id,
305
+ error: { code: -32602, message: `Unknown resource: ${uri}` },
306
+ };
307
+ }
308
+ case 'tools/call': {
309
+ const toolName = rpc.params?.name;
310
+ const args = rpc.params?.arguments || {};
311
+ // Input validation
312
+ if (args.query && typeof args.query === 'string' && args.query.length > 1000) {
313
+ return {
314
+ jsonrpc: '2.0', id,
315
+ result: { content: [{ type: 'text', text: 'Error: query too long (max 1000 chars)' }], isError: true },
316
+ };
317
+ }
318
+ if (args.content && typeof args.content === 'string' && args.content.length > 5000) {
319
+ return {
320
+ jsonrpc: '2.0', id,
321
+ result: { content: [{ type: 'text', text: 'Error: content too long (max 5000 chars)' }], isError: true },
322
+ };
323
+ }
324
+ if (toolName === 'recall_memory') {
325
+ return await handleRecallMemory(id, args);
326
+ }
327
+ else if (toolName === 'store_memory') {
328
+ return await handleStoreMemory(id, args);
329
+ }
330
+ else if (toolName === 'get_stats') {
331
+ return handleGetStats(id);
332
+ }
333
+ else if (toolName === 'scan_project') {
334
+ return await handleScanProject(id, args);
335
+ }
336
+ else if (toolName === 'verify_files') {
337
+ return handleVerifyFiles(id, args);
338
+ }
339
+ else if (toolName === 'get_context') {
340
+ return handleGetContext(id, args);
341
+ }
342
+ else if (toolName === 'verify_code') {
343
+ return handleVerifyCode(id, args);
344
+ }
345
+ else if (toolName === 'force_recall') {
346
+ return await handleForceRecall(id, args);
347
+ }
348
+ else if (toolName === 'quick_store') {
349
+ return handleQuickStore(id, args);
350
+ }
351
+ else if (toolName === 'update_memory') {
352
+ return handleUpdateMemory(id, args);
353
+ }
354
+ else if (toolName === 'list_memories') {
355
+ return handleListMemories(id, args);
356
+ }
357
+ else if (toolName === 'delete_memory') {
358
+ return handleDeleteMemory(id, args);
359
+ }
360
+ else if (toolName === 'auto_learn') {
361
+ return handleAutoLearn(id, args);
362
+ }
363
+ else if (toolName === 'export_memories') {
364
+ return handleExportMemories(id);
365
+ }
366
+ else if (toolName === 'import_memories') {
367
+ return handleImportMemories(id, args);
368
+ }
369
+ else if (toolName === 'health_check') {
370
+ return handleHealthCheck(id);
371
+ }
372
+ else {
373
+ return {
374
+ jsonrpc: '2.0', id,
375
+ result: { content: [{ type: 'text', text: `Unknown tool: ${toolName}` }], isError: true },
376
+ };
377
+ }
378
+ }
379
+ // Backward compatibility
380
+ case 'recall_memory':
381
+ return await handleRecallMemory(id, rpc.params || {});
382
+ case 'store_memory':
383
+ return await handleStoreMemory(id, rpc.params || {});
384
+ case 'get_stats':
385
+ return handleGetStats(id);
386
+ default:
387
+ return {
388
+ jsonrpc: '2.0', id,
389
+ error: { code: -32601, message: `Method not found: ${rpc.method}` },
390
+ };
391
+ }
392
+ }
393
+ async function handleRecallMemory(id, args) {
394
+ const queryText = args.query || '';
395
+ const maxResults = Math.min(args.maxResults || 10, 50);
396
+ const currentFile = args.currentFile;
397
+ console.log(` [SEARCH] recall: "${queryText}" (max ${maxResults})`);
398
+ let ranked = [];
399
+ const t0 = Date.now();
400
+ // 0. Check cache
401
+ const cacheKey = `recall:${queryText}:${maxResults}`;
402
+ const cached = (0, memory_cache_1.getCached)(cacheKey);
403
+ if (cached) {
404
+ console.log(` [CACHE] Hit in ${Date.now() - t0}ms`);
405
+ // Parse cached JSON string back to object if needed, or if cached is already ScoredMemory[]
406
+ // Assuming getCached returns the object directly
407
+ return { jsonrpc: '2.0', id, result: { content: [{ type: 'text', text: (0, memory_ranker_1.formatResults)(cached, queryText) }] } };
408
+ }
409
+ try {
410
+ // 1. FTS — try expanded query first, fall back to raw
411
+ let ftsResults = [];
412
+ try {
413
+ const expanded = expandQuery(queryText);
414
+ if (expanded !== queryText) {
415
+ // console.log(` Expansion: ${queryText} -> ${expanded}`);
416
+ ftsResults = memoryStore.searchFTS(expanded, maxResults * 2);
417
+ }
418
+ }
419
+ catch (e) { /* non-fatal */ }
420
+ if (ftsResults.length === 0) {
421
+ ftsResults = memoryStore.searchFTS(queryText, maxResults * 2);
422
+ }
423
+ console.log(` [FTS] ${ftsResults.length} results`);
424
+ // 2. Vector Search (if worker ready)
425
+ let vectorResults = [];
426
+ if ((0, embedding_manager_1.isWorkerReady)()) {
427
+ const embedding = await (0, embedding_manager_1.embedText)(queryText);
428
+ vectorResults = memoryStore.searchVector(new Float32Array(embedding), maxResults * 2);
429
+ if (vectorResults.length > 0) {
430
+ console.log(` [VECTOR] ${vectorResults.length} results`);
431
+ }
432
+ }
433
+ // 3. Hybrid Ranking
434
+ const rawRanked = (0, memory_ranker_1.rankResults)(ftsResults, vectorResults, maxResults * 2, currentFile);
435
+ // Map RankedResult to ScoredMemory
436
+ ranked = rawRanked.map(r => ({
437
+ ...r,
438
+ matchMethod: 'hybrid'
439
+ }));
440
+ // 3b. Context-based boost (if current file provided)
441
+ if (args.currentFile) {
442
+ // Boost memories related to this file or its directory
443
+ // Implementation in memory-ranker.ts (pending)
444
+ }
445
+ // 3c. Apply attention-based re-ranking (debugging→bugs, coding→conventions)
446
+ const recallContext = (0, attention_ranker_1.detectActionContext)(queryText, currentFile);
447
+ ranked = (0, attention_ranker_1.rankByAttention)(ranked, recallContext);
448
+ // 3d. Causal chain enrichment — follow graph edges from top results
449
+ const enriched = [];
450
+ const seenIds = new Set();
451
+ for (const r of ranked.slice(0, maxResults)) {
452
+ if (seenIds.has(r.memory.id))
453
+ continue;
454
+ seenIds.add(r.memory.id);
455
+ enriched.push(r);
456
+ // Follow 1-hop causal links for top 5 results
457
+ if (enriched.length <= 5) {
458
+ try {
459
+ const related = memoryStore.getRelated(r.memory.id, 1, 2);
460
+ for (const rel of related) {
461
+ if (!seenIds.has(rel.memory.id)) {
462
+ seenIds.add(rel.memory.id);
463
+ enriched.push({ ...rel, score: rel.score * 0.6 });
464
+ }
465
+ }
466
+ }
467
+ catch { /* non-fatal */ }
468
+ }
469
+ }
470
+ // 3b. Apply confidence decay (old unused memories rank lower)
471
+ ranked = (0, confidence_decay_1.applyConfidenceDecay)(enriched.map(r => ({ memory: r.memory, score: r.score, matchMethod: 'hybrid' })));
472
+ // Limit to requested count
473
+ ranked = ranked.slice(0, maxResults);
474
+ // 4. Touch for access tracking (reinforcement — used memories get stronger)
475
+ if (ranked.length > 0) {
476
+ await Promise.all(ranked.map(m => {
477
+ try {
478
+ return memoryStore.touch(m.memory.id);
479
+ }
480
+ catch {
481
+ return Promise.resolve();
482
+ }
483
+ }));
484
+ (0, confidence_decay_1.runDecayMaintenance)(memoryStore); // Opportunistic decay
485
+ }
486
+ (0, memory_cache_1.setCache)(cacheKey, ranked);
487
+ console.log(` [OK] ${ranked.length} results in ${Date.now() - t0}ms`);
488
+ return {
489
+ jsonrpc: '2.0', id,
490
+ result: { content: [{ type: 'text', text: (0, memory_ranker_1.formatResults)(ranked, queryText) }] },
491
+ };
492
+ }
493
+ catch (err) {
494
+ console.error(` [ERROR] recall failed:`, err.message);
495
+ return {
496
+ jsonrpc: '2.0', id,
497
+ result: { content: [{ type: 'text', text: `Brain has ${memoryStore.activeCount()} memories but search failed: ${err.message}` }], isError: true },
498
+ };
499
+ }
500
+ }
501
+ async function handleStoreMemory(id, args) {
502
+ const { type, content, reason, files, tags } = args;
503
+ // Rate limit check
504
+ const rateCheck = (0, rate_limiter_1.checkRateLimit)('store');
505
+ if (!rateCheck.allowed) {
506
+ return {
507
+ jsonrpc: '2.0', id,
508
+ result: { content: [{ type: 'text', text: `[WARN] Rate limited: ${rateCheck.reason}` }], isError: true },
509
+ };
510
+ }
511
+ if (!type || !content) {
512
+ return {
513
+ jsonrpc: '2.0', id,
514
+ result: { content: [{ type: 'text', text: 'Error: "type" and "content" are required' }], isError: true },
515
+ };
516
+ }
517
+ const validTypes = {
518
+ DECISION: types_1.MemoryType.DECISION,
519
+ CORRECTION: types_1.MemoryType.CORRECTION,
520
+ BUG_FIX: types_1.MemoryType.BUG_FIX,
521
+ CONVENTION: types_1.MemoryType.CONVENTION,
522
+ INSIGHT: types_1.MemoryType.INSIGHT,
523
+ FAILED_SUGGESTION: types_1.MemoryType.FAILED_SUGGESTION,
524
+ CONVERSATION: types_1.MemoryType.CONVERSATION,
525
+ PROVEN_PATTERN: types_1.MemoryType.PROVEN_PATTERN,
526
+ };
527
+ const memType = validTypes[type];
528
+ if (!memType) {
529
+ return {
530
+ jsonrpc: '2.0', id,
531
+ result: { content: [{ type: 'text', text: `Error: Invalid type "${type}". Use: DECISION, CORRECTION, BUG_FIX, CONVENTION, INSIGHT` }], isError: true },
532
+ };
533
+ }
534
+ try {
535
+ // License check — gate memory storage
536
+ const activeCount = memoryStore.getActive(9999).length;
537
+ const storeCheck = (0, feature_gate_1.canStoreMemory)(activeCount);
538
+ if (!storeCheck.allowed) {
539
+ return {
540
+ jsonrpc: '2.0', id,
541
+ result: { content: [{ type: 'text', text: storeCheck.message }], isError: true },
542
+ };
543
+ }
544
+ // Input sanitization — strip control chars
545
+ const sanitized = content.replace(/[\x00-\x08\x0B\x0C\x0E-\x1F]/g, '');
546
+ // Optional LLM enhancement (if API key configured)
547
+ let enhancedTags = tags || [type.toLowerCase()];
548
+ let enhancedAction = `Stored via MCP: ${sanitized.slice(0, 200)}`;
549
+ if ((0, llm_enhancer_1.isLLMAvailable)()) {
550
+ try {
551
+ const enhanced = await (0, llm_enhancer_1.enhanceMemory)(sanitized, { files });
552
+ if (enhanced.tags?.length)
553
+ enhancedTags = [...new Set([...enhancedTags, ...enhanced.tags])];
554
+ if (enhanced.action)
555
+ enhancedAction = enhanced.action;
556
+ }
557
+ catch { /* LLM failed, use defaults */ }
558
+ }
559
+ // Quality gate + contradiction detection
560
+ const memory = (0, memory_quality_1.storeWithQuality)(memoryStore, {
561
+ type: memType,
562
+ intent: sanitized.slice(0, 300),
563
+ action: enhancedAction,
564
+ reason: reason || undefined,
565
+ importance: type === 'CORRECTION' ? 0.95 : type === 'DECISION' ? 0.85 : 0.7,
566
+ confidence: 1.0,
567
+ tags: enhancedTags,
568
+ relatedFiles: files || [],
569
+ });
570
+ if (!memory) {
571
+ return {
572
+ jsonrpc: '2.0', id,
573
+ result: { content: [{ type: 'text', text: `Memory rejected by quality check: "${sanitized.slice(0, 100)}" — too short, too generic, or duplicate` }], isError: true },
574
+ };
575
+ }
576
+ // Active contradiction detection — find and resolve conflicts
577
+ let contradictionNote = '';
578
+ try {
579
+ const contradiction = (0, memory_quality_1.findContradiction)(memoryStore, memType, sanitized);
580
+ if (contradiction) {
581
+ memoryStore.deactivate(contradiction.existingId, memory.id);
582
+ memoryStore.addEdge({
583
+ sourceId: contradiction.existingId,
584
+ targetId: memory.id,
585
+ relation: 'superseded_by',
586
+ weight: 0.95,
587
+ timestamp: Date.now(),
588
+ });
589
+ contradictionNote = ` [WARN] Superseded conflicting memory: "${contradiction.existingIntent.slice(0, 60)}"`;
590
+ }
591
+ }
592
+ catch { /* non-fatal */ }
593
+ // Auto-edge creation — link to recent memories of same type/files
594
+ try {
595
+ const recent = memoryStore.getByType(memType, 5);
596
+ for (const r of recent) {
597
+ if (r.id !== memory.id) {
598
+ memoryStore.addEdge({
599
+ sourceId: memory.id,
600
+ targetId: r.id,
601
+ relation: 'related_to',
602
+ weight: 0.5,
603
+ timestamp: Date.now(),
604
+ });
605
+ break; // Link to most recent only
606
+ }
607
+ }
608
+ }
609
+ catch { /* non-fatal */ }
610
+ // Feed session tracker
611
+ (0, session_tracker_1.feedSession)({ decision: `[${type}] ${sanitized.slice(0, 60)}` });
612
+ // Queue background embedding
613
+ if ((0, embedding_manager_1.isWorkerReady)()) {
614
+ const embedText_ = [sanitized, reason || ''].join(' ').trim();
615
+ (0, embedding_manager_1.embedText)(embedText_).then((vector) => {
616
+ memoryStore.storeVector(memory.id, new Float32Array(vector));
617
+ }).catch(() => { });
618
+ }
619
+ (0, memory_cache_1.invalidateCache)();
620
+ console.log(` [STORE] ${type}: "${args.content.slice(0, 50)}..."`);
621
+ return {
622
+ jsonrpc: '2.0', id,
623
+ result: { content: [{ type: 'text', text: `[OK] Created memory: ${memory.id}\n(Active: ${memoryStore.activeCount()})${contradictionNote}` }] },
624
+ };
625
+ }
626
+ catch (err) {
627
+ return {
628
+ jsonrpc: '2.0', id,
629
+ result: { content: [{ type: 'text', text: `Failed to store memory: ${err.message}` }], isError: true },
630
+ };
631
+ }
632
+ }
633
+ function handleGetStats(id) {
634
+ return {
635
+ jsonrpc: '2.0', id,
636
+ result: {
637
+ content: [{
638
+ type: 'text',
639
+ text: JSON.stringify({
640
+ activeMemories: memoryStore.activeCount(),
641
+ totalMemories: memoryStore.totalCount(),
642
+ totalEvents: eventLog.count(),
643
+ vectorSearchReady: (0, embedding_manager_1.isWorkerReady)(),
644
+ cacheSize: (0, memory_cache_1.cacheSize)(),
645
+ }, null, 2),
646
+ }],
647
+ },
648
+ };
649
+ }
650
+ // --- New Tool Handlers ---
651
+ async function handleScanProject(id, args) {
652
+ const root = args.workspaceRoot || workspaceRoot;
653
+ if (!root) {
654
+ return {
655
+ jsonrpc: '2.0', id,
656
+ result: { content: [{ type: 'text', text: 'Error: workspaceRoot is required' }], isError: true },
657
+ };
658
+ }
659
+ try {
660
+ const scanner = new project_scanner_1.ProjectScanner(memoryStore, root);
661
+ const count = await scanner.scan();
662
+ // Deep scan: Export Map (anti-hallucination) + Architecture Graph
663
+ let extraMemories = 0;
664
+ try {
665
+ const exportMap = (0, export_map_1.buildExportMap)(root);
666
+ extraMemories += (0, export_map_1.storeExportMap)(memoryStore, exportMap);
667
+ }
668
+ catch { /* non-fatal */ }
669
+ try {
670
+ const archGraph = (0, architecture_graph_1.buildArchitectureGraph)(root);
671
+ extraMemories += (0, architecture_graph_1.storeArchitectureGraph)(memoryStore, archGraph);
672
+ }
673
+ catch { /* non-fatal */ }
674
+ (0, memory_cache_1.invalidateCache)();
675
+ const total = count + extraMemories;
676
+ return {
677
+ jsonrpc: '2.0', id,
678
+ result: {
679
+ content: [{
680
+ type: 'text',
681
+ text: total > 0
682
+ ? `Project scanned successfully. ${total} memories created (stack, structure, config, git history, export map, architecture graph).`
683
+ : 'Project was already scanned. No new memories created.',
684
+ }],
685
+ },
686
+ };
687
+ }
688
+ catch (err) {
689
+ return {
690
+ jsonrpc: '2.0', id,
691
+ result: { content: [{ type: 'text', text: `Scan error: ${err.message}` }], isError: true },
692
+ };
693
+ }
694
+ }
695
+ function handleVerifyFiles(id, args) {
696
+ const root = args.workspaceRoot || workspaceRoot;
697
+ if (!root || !args.text) {
698
+ return {
699
+ jsonrpc: '2.0', id,
700
+ result: { content: [{ type: 'text', text: 'Error: text and workspaceRoot are required' }], isError: true },
701
+ };
702
+ }
703
+ try {
704
+ const verifier = new file_verifier_1.FileVerifier(root);
705
+ const result = verifier.verifyText(args.text);
706
+ const lines = [];
707
+ if (result.valid.length > 0) {
708
+ lines.push(`[OK] Valid paths (${result.valid.length}): ${result.valid.join(', ')}`);
709
+ }
710
+ if (result.invalid.length > 0) {
711
+ lines.push(`[FAIL] Hallucinated paths (${result.invalid.length}): ${result.invalid.join(', ')}`);
712
+ for (const [bad, suggestions] of Object.entries(result.suggestions)) {
713
+ lines.push(` ${bad} → did you mean: ${suggestions.join(' or ')}?`);
714
+ }
715
+ }
716
+ if (result.valid.length === 0 && result.invalid.length === 0) {
717
+ lines.push('No file paths detected in the text.');
718
+ }
719
+ return {
720
+ jsonrpc: '2.0', id,
721
+ result: { content: [{ type: 'text', text: lines.join('\n') }] },
722
+ };
723
+ }
724
+ catch (err) {
725
+ return {
726
+ jsonrpc: '2.0', id,
727
+ result: { content: [{ type: 'text', text: `Verify error: ${err.message}` }], isError: true },
728
+ };
729
+ }
730
+ }
731
+ function handleGetContext(id, args) {
732
+ try {
733
+ const builder = getContextBuilder(memoryStore);
734
+ const context = builder.build({
735
+ currentFile: args.currentFile,
736
+ maxChars: args.maxChars,
737
+ });
738
+ return {
739
+ jsonrpc: '2.0', id,
740
+ result: { content: [{ type: 'text', text: context }] },
741
+ };
742
+ }
743
+ catch (err) {
744
+ return {
745
+ jsonrpc: '2.0', id,
746
+ result: { content: [{ type: 'text', text: `Context error: ${err.message}` }], isError: true },
747
+ };
748
+ }
749
+ }
750
+ function handleVerifyCode(id, args) {
751
+ const root = args.workspaceRoot || workspaceRoot;
752
+ if (!root || !args.code) {
753
+ return {
754
+ jsonrpc: '2.0', id,
755
+ result: { content: [{ type: 'text', text: 'Error: code and workspaceRoot are required' }], isError: true },
756
+ };
757
+ }
758
+ try {
759
+ const result = (0, code_verifier_1.verifyCode)(args.code, root);
760
+ const lines = [];
761
+ // Imports
762
+ if (result.imports.valid.length > 0 || result.imports.invalid.length > 0) {
763
+ lines.push('## Package Imports');
764
+ if (result.imports.valid.length > 0) {
765
+ lines.push(`[OK] Valid: ${result.imports.valid.join(', ')}`);
766
+ }
767
+ if (result.imports.invalid.length > 0) {
768
+ lines.push(`[FAIL] NOT IN package.json: ${result.imports.invalid.join(', ')}`);
769
+ for (const [bad, suggestions] of Object.entries(result.imports.suggestions)) {
770
+ lines.push(` ${bad} → did you mean: ${suggestions.join(' or ')}?`);
771
+ }
772
+ }
773
+ }
774
+ // Exports
775
+ if (result.exports.valid.length > 0 || result.exports.invalid.length > 0) {
776
+ lines.push('\n## Function/Class Exports');
777
+ if (result.exports.valid.length > 0) {
778
+ lines.push(`[OK] Valid: ${result.exports.valid.join(', ')}`);
779
+ }
780
+ if (result.exports.invalid.length > 0) {
781
+ lines.push(`[FAIL] NOT EXPORTED: ${result.exports.invalid.join(', ')}`);
782
+ for (const [file, available] of Object.entries(result.exports.available)) {
783
+ lines.push(` ${file} exports: ${available.join(', ')}`);
784
+ }
785
+ }
786
+ }
787
+ // Env vars
788
+ if (result.envVars.valid.length > 0 || result.envVars.invalid.length > 0) {
789
+ lines.push('\n## Environment Variables');
790
+ if (result.envVars.valid.length > 0) {
791
+ lines.push(`[OK] Valid: ${result.envVars.valid.join(', ')}`);
792
+ }
793
+ if (result.envVars.invalid.length > 0) {
794
+ lines.push(`[FAIL] NOT IN .env: ${result.envVars.invalid.join(', ')}`);
795
+ if (result.envVars.available.length > 0) {
796
+ lines.push(` Available vars: ${result.envVars.available.join(', ')}`);
797
+ }
798
+ }
799
+ }
800
+ if (lines.length === 0) {
801
+ lines.push('No imports, exports, or env vars detected in the code.');
802
+ }
803
+ return {
804
+ jsonrpc: '2.0', id,
805
+ result: { content: [{ type: 'text', text: lines.join('\n') }] },
806
+ };
807
+ }
808
+ catch (err) {
809
+ return {
810
+ jsonrpc: '2.0', id,
811
+ result: { content: [{ type: 'text', text: `Verify error: ${err.message}` }], isError: true },
812
+ };
813
+ }
814
+ }
815
+ function handleQuickStore(id, args) {
816
+ // Rate limit check
817
+ const rateCheck = (0, rate_limiter_1.checkRateLimit)('store');
818
+ if (!rateCheck.allowed) {
819
+ return {
820
+ jsonrpc: '2.0', id,
821
+ result: { content: [{ type: 'text', text: `[WARN] Rate limited: ${rateCheck.reason}` }], isError: true },
822
+ };
823
+ }
824
+ const text = args.memory?.trim();
825
+ if (!text || text.length < 5) {
826
+ return {
827
+ jsonrpc: '2.0', id,
828
+ result: { content: [{ type: 'text', text: 'Error: provide a memory sentence (min 5 chars)' }], isError: true },
829
+ };
830
+ }
831
+ // Auto-classify based on keywords
832
+ const lower = text.toLowerCase();
833
+ let type;
834
+ let label;
835
+ if (/\b(don'?t|never|wrong|instead|not|avoid|stop|incorrect)\b/.test(lower)) {
836
+ type = types_1.MemoryType.CORRECTION;
837
+ label = 'CORRECTION';
838
+ }
839
+ else if (/\b(fix|bug|broke|crash|error|patch|regression)\b/.test(lower)) {
840
+ type = types_1.MemoryType.BUG_FIX;
841
+ label = 'BUG_FIX';
842
+ }
843
+ else if (/\b(always|convention|style|format|standard|rule|must)\b/.test(lower)) {
844
+ type = types_1.MemoryType.CONVENTION;
845
+ label = 'CONVENTION';
846
+ }
847
+ else if (/\b(use|chose|decided|pick|select|go with|switch to|migrate)\b/.test(lower)) {
848
+ type = types_1.MemoryType.DECISION;
849
+ label = 'DECISION';
850
+ }
851
+ else {
852
+ type = types_1.MemoryType.INSIGHT;
853
+ label = 'INSIGHT';
854
+ }
855
+ try {
856
+ const sanitized = text.replace(/[\x00-\x08\x0B\x0C\x0E-\x1F]/g, '');
857
+ const memory = (0, memory_quality_1.storeWithQuality)(memoryStore, {
858
+ type,
859
+ intent: sanitized.slice(0, 300),
860
+ action: `Quick-stored: ${sanitized.slice(0, 200)}`,
861
+ importance: type === types_1.MemoryType.CORRECTION ? 0.95 : type === types_1.MemoryType.DECISION ? 0.85 : 0.7,
862
+ confidence: 1.0,
863
+ tags: [label.toLowerCase()],
864
+ relatedFiles: [],
865
+ });
866
+ if (!memory) {
867
+ return {
868
+ jsonrpc: '2.0', id,
869
+ result: { content: [{ type: 'text', text: `Rejected: too short, generic, or duplicate` }], isError: true },
870
+ };
871
+ }
872
+ return {
873
+ jsonrpc: '2.0', id,
874
+ result: { content: [{ type: 'text', text: `Memory stored as ${label}: "${sanitized.slice(0, 100)}"` }] },
875
+ };
876
+ }
877
+ catch (err) {
878
+ return {
879
+ jsonrpc: '2.0', id,
880
+ result: { content: [{ type: 'text', text: `Store error: ${err.message}` }], isError: true },
881
+ };
882
+ }
883
+ }
884
+ async function handleForceRecall(id, args) {
885
+ try {
886
+ const parts = [];
887
+ // ─── BRAIN LAYER 0: End previous session + start new one ─────────
888
+ (0, session_tracker_1.endSession)(memoryStore); // Save previous session summary
889
+ (0, session_tracker_1.startSession)();
890
+ if (args.topic)
891
+ (0, session_tracker_1.feedSession)({ topic: args.topic });
892
+ // ─── BRAIN LAYER 1: Maintenance (runs in background) ─────────────
893
+ try {
894
+ // Decay old unused memories
895
+ (0, confidence_decay_1.runDecayMaintenance)(memoryStore);
896
+ // Boost frequently corrected topics
897
+ (0, learning_rate_1.boostFrequentCorrections)(memoryStore);
898
+ // Consolidate similar memories if needed
899
+ if ((0, memory_consolidator_1.shouldConsolidate)(memoryStore)) {
900
+ (0, memory_consolidator_1.consolidateMemories)(memoryStore);
901
+ }
902
+ }
903
+ catch { /* maintenance errors are non-fatal */ }
904
+ // ─── BRAIN LAYER 2: Attention Context ────────────────────────────
905
+ const actionContext = (0, license_1.isPro)() ? (0, attention_ranker_1.detectActionContext)(args.topic, args.currentFile) : {};
906
+ const attentionLabel = (0, license_1.isPro)() ? (0, attention_ranker_1.formatAttentionContext)(actionContext) : '';
907
+ if (attentionLabel)
908
+ parts.push(attentionLabel);
909
+ // ─── BRAIN LAYER 3: Session Continuity ───────────────────────────
910
+ const sessions = (0, session_tracker_1.getRecentSessions)(memoryStore, 3);
911
+ if (sessions.length > 0) {
912
+ parts.push('\n## 🧵 Recent Sessions (where we left off)');
913
+ for (const s of sessions)
914
+ parts.push(s);
915
+ }
916
+ // ─── BRAIN LAYER 4: Hot Corrections (learning rate) ──────────────
917
+ const hotCorrections = (0, learning_rate_1.formatHotCorrections)(memoryStore);
918
+ if (hotCorrections)
919
+ parts.push('\n' + hotCorrections);
920
+ // ─── BRAIN LAYER 5: Core Context (corrections, decisions, etc) ───
921
+ const builder = getContextBuilder(memoryStore);
922
+ const fullContext = builder.build({
923
+ currentFile: args.currentFile,
924
+ maxChars: 8000, // leave room for brain layers
925
+ });
926
+ parts.push(fullContext);
927
+ // ─── BRAIN LAYER 6: Anticipation (file-aware proactive recall) ───
928
+ if (args.currentFile && (0, license_1.isPro)()) {
929
+ const anticipated = (0, anticipation_engine_1.formatAnticipation)((0, anticipation_engine_1.anticipate)(memoryStore, args.currentFile));
930
+ if (anticipated)
931
+ parts.push('\n' + anticipated);
932
+ }
933
+ // ─── BRAIN LAYER 7: Temporal Context (what changed recently) ─────
934
+ if ((0, license_1.isPro)()) {
935
+ const temporal = (0, temporal_engine_1.formatTemporalContext)(memoryStore);
936
+ if (temporal)
937
+ parts.push('\n' + temporal);
938
+ }
939
+ // ─── BRAIN LAYER 8: Workspace State (git changes) ────────────────
940
+ try {
941
+ const workspace = (0, temporal_engine_1.getWorkspaceDiff)(workspaceRoot || '');
942
+ if (workspace)
943
+ parts.push('\n' + workspace);
944
+ }
945
+ catch { /* git not available */ }
946
+ // ─── BRAIN LAYER 8.5: Git Memory (commit capture + file changes) ───
947
+ if ((0, license_1.isPro)()) {
948
+ try {
949
+ // Capture recent commits as memories
950
+ const commitsCaptured = (0, git_memory_1.captureGitCommits)(memoryStore, workspaceRoot || '', 5);
951
+ if (commitsCaptured > 0) {
952
+ parts.push(`\n> Captured ${commitsCaptured} new git commit(s) as memories`);
953
+ }
954
+ // Show uncommitted file changes
955
+ const fileChanges = (0, git_memory_1.detectFileChanges)(workspaceRoot || '');
956
+ const fileChangeText = (0, git_memory_1.formatFileChanges)(fileChanges);
957
+ if (fileChangeText)
958
+ parts.push('\n' + fileChangeText);
959
+ }
960
+ catch { /* git not available */ }
961
+ } // end isPro() for git memory
962
+ // ─── BRAIN LAYER 9: Topic-Specific Search ────────────────────────
963
+ if (args.topic) {
964
+ try {
965
+ let ftsResults = memoryStore.searchFTS(args.topic, 15);
966
+ // Apply confidence decay + attention ranking
967
+ ftsResults = (0, confidence_decay_1.applyConfidenceDecay)(ftsResults);
968
+ ftsResults = (0, attention_ranker_1.rankByAttention)(ftsResults, actionContext);
969
+ // Causal chain: follow graph edges for top results
970
+ const seen = new Set();
971
+ const enriched = [];
972
+ for (const r of ftsResults) {
973
+ if (seen.has(r.memory.id))
974
+ continue;
975
+ seen.add(r.memory.id);
976
+ enriched.push(r);
977
+ // Follow causal links (1 hop)
978
+ try {
979
+ const related = memoryStore.getRelated(r.memory.id, 1, 3);
980
+ for (const rel of related) {
981
+ if (!seen.has(rel.memory.id)) {
982
+ seen.add(rel.memory.id);
983
+ enriched.push({ ...rel, score: rel.score * 0.7 });
984
+ }
985
+ }
986
+ }
987
+ catch { }
988
+ }
989
+ if (enriched.length > 0) {
990
+ parts.push('\n## Topic: "' + args.topic + '"');
991
+ for (const m of enriched.slice(0, 15)) {
992
+ parts.push(`- [${m.memory.type}] ${m.memory.intent}${m.memory.reason ? ` — ${m.memory.reason}` : ''}`);
993
+ }
994
+ }
995
+ }
996
+ catch {
997
+ parts.push('\n> Note: Topic search unavailable (FTS index needs rebuild).');
998
+ }
999
+ }
1000
+ // ─── BRAIN LAYER 10: Knowledge Gaps (meta-memory) ────────────────
1001
+ try {
1002
+ const gaps = (0, meta_memory_1.detectKnowledgeGaps)(memoryStore, workspaceRoot || '');
1003
+ const gapText = (0, meta_memory_1.formatKnowledgeGaps)(gaps);
1004
+ if (gapText)
1005
+ parts.push('\n' + gapText);
1006
+ }
1007
+ catch { /* non-fatal */ }
1008
+ // ─── BRAIN LAYER 11: Export Map (anti-hallucination) ──────────────
1009
+ if (workspaceRoot && (0, license_1.isPro)()) {
1010
+ try {
1011
+ const exportMap = (0, export_map_1.buildExportMap)(workspaceRoot);
1012
+ if (exportMap.totalExports > 0) {
1013
+ const exportText = (0, export_map_1.formatExportMap)(exportMap);
1014
+ if (exportText)
1015
+ parts.push('\n' + exportText);
1016
+ }
1017
+ }
1018
+ catch { /* non-fatal */ }
1019
+ }
1020
+ // ─── BRAIN LAYER 12: Architecture Graph (deep understanding) ──────
1021
+ if (workspaceRoot && (0, license_1.isPro)()) {
1022
+ try {
1023
+ const archGraph = (0, architecture_graph_1.buildArchitectureGraph)(workspaceRoot);
1024
+ if (archGraph.totalFiles > 0) {
1025
+ const archText = (0, architecture_graph_1.formatArchitectureGraph)(archGraph);
1026
+ if (archText)
1027
+ parts.push('\n' + archText);
1028
+ }
1029
+ }
1030
+ catch { /* non-fatal */ }
1031
+ }
1032
+ // ─── SMART CONTEXT SELECTION: Trim to token budget ───────────────
1033
+ let output = parts.join('\n');
1034
+ const MAX_CHARS = 12000; // ~3000 tokens — fits any model
1035
+ if (output.length > MAX_CHARS) {
1036
+ // Keep critical sections, trim lower-priority ones
1037
+ output = output.slice(0, MAX_CHARS) + '\n\n> (Context trimmed to fit token budget. Use `recall_memory` for specific queries.)';
1038
+ }
1039
+ return {
1040
+ jsonrpc: '2.0', id,
1041
+ result: { content: [{ type: 'text', text: output }] },
1042
+ };
1043
+ }
1044
+ catch (err) {
1045
+ return {
1046
+ jsonrpc: '2.0', id,
1047
+ result: { content: [{ type: 'text', text: `Force recall error: ${err.message}` }], isError: true },
1048
+ };
1049
+ }
1050
+ }
1051
+ function handleUpdateMemory(id, args) {
1052
+ try {
1053
+ const memoryId = args.id;
1054
+ const newContent = args.content;
1055
+ const reason = args.reason || 'Updated by AI';
1056
+ if (!memoryId || !newContent) {
1057
+ return {
1058
+ jsonrpc: '2.0', id,
1059
+ result: { content: [{ type: 'text', text: 'Error: id and content are required' }], isError: true },
1060
+ };
1061
+ }
1062
+ // Get the existing memory
1063
+ const existing = memoryStore.get(memoryId);
1064
+ if (!existing) {
1065
+ return {
1066
+ jsonrpc: '2.0', id,
1067
+ result: { content: [{ type: 'text', text: `Error: Memory ${memoryId} not found` }], isError: true },
1068
+ };
1069
+ }
1070
+ // Create the new (replacement) memory
1071
+ const newMemory = memoryStore.add({
1072
+ type: existing.type,
1073
+ intent: newContent,
1074
+ action: newContent,
1075
+ reason,
1076
+ tags: existing.tags,
1077
+ relatedFiles: existing.relatedFiles,
1078
+ confidence: existing.confidence,
1079
+ importance: existing.importance,
1080
+ });
1081
+ // Deactivate the old memory, pointing to the new one
1082
+ memoryStore.deactivate(memoryId, newMemory.id);
1083
+ (0, memory_cache_1.invalidateCache)();
1084
+ return {
1085
+ jsonrpc: '2.0', id,
1086
+ result: {
1087
+ content: [{
1088
+ type: 'text',
1089
+ text: `Memory updated.\n\nOld: "${existing.intent}"\nNew: "${newContent}"\nReason: ${reason}\n\nOld memory deactivated (ID: ${memoryId})\nNew memory ID: ${newMemory.id}`,
1090
+ }],
1091
+ },
1092
+ };
1093
+ }
1094
+ catch (err) {
1095
+ return {
1096
+ jsonrpc: '2.0', id,
1097
+ result: { content: [{ type: 'text', text: `Update error: ${err.message}` }], isError: true },
1098
+ };
1099
+ }
1100
+ }
1101
+ function handleListMemories(id, args) {
1102
+ try {
1103
+ const filterType = args?.type && args.type !== 'ALL' ? args.type : null;
1104
+ const limit = args?.limit || 20;
1105
+ const TYPES = ['CORRECTION', 'DECISION', 'CONVENTION', 'BUG_FIX', 'INSIGHT'];
1106
+ const typesToShow = filterType ? [filterType] : TYPES;
1107
+ const parts = ['# Cortex Memory Bank\n'];
1108
+ let totalCount = 0;
1109
+ for (const type of typesToShow) {
1110
+ const memories = memoryStore.getByType(type, limit);
1111
+ if (memories.length === 0)
1112
+ continue;
1113
+ const emoji = {
1114
+ CORRECTION: '[COR]', DECISION: '[DEC]', CONVENTION: '[CON]',
1115
+ BUG_FIX: '[BUG]', INSIGHT: '[INS]',
1116
+ };
1117
+ parts.push(`## ${emoji[type] || '[---]'} ${type} (${memories.length})\n`);
1118
+ for (const m of memories) {
1119
+ const age = Math.floor((Date.now() - m.createdAt) / (24 * 60 * 60 * 1000));
1120
+ const accessed = m.accessCount > 0 ? ` · accessed ${m.accessCount}x` : '';
1121
+ parts.push(`- **${m.intent}**`);
1122
+ parts.push(` \`id: ${m.id}\` · ${age}d old${accessed}`);
1123
+ if (m.reason)
1124
+ parts.push(` _${m.reason}_`);
1125
+ }
1126
+ parts.push('');
1127
+ totalCount += memories.length;
1128
+ }
1129
+ if (totalCount === 0) {
1130
+ parts.push('_No memories stored yet. Use `quick_store` to add some._');
1131
+ }
1132
+ else {
1133
+ parts.push(`\n_Total: ${totalCount} active memories. Use \`update_memory\` or \`delete_memory\` with the ID shown._`);
1134
+ }
1135
+ return {
1136
+ jsonrpc: '2.0', id,
1137
+ result: { content: [{ type: 'text', text: parts.join('\n') }] },
1138
+ };
1139
+ }
1140
+ catch (err) {
1141
+ return {
1142
+ jsonrpc: '2.0', id,
1143
+ result: { content: [{ type: 'text', text: `List error: ${err.message}` }], isError: true },
1144
+ };
1145
+ }
1146
+ }
1147
+ function handleDeleteMemory(id, args) {
1148
+ try {
1149
+ const memoryId = args.id;
1150
+ const reason = args.reason || 'Deleted by AI';
1151
+ if (!memoryId) {
1152
+ return {
1153
+ jsonrpc: '2.0', id,
1154
+ result: { content: [{ type: 'text', text: 'Error: id is required' }], isError: true },
1155
+ };
1156
+ }
1157
+ const existing = memoryStore.get(memoryId);
1158
+ if (!existing) {
1159
+ return {
1160
+ jsonrpc: '2.0', id,
1161
+ result: { content: [{ type: 'text', text: `Error: Memory ${memoryId} not found` }], isError: true },
1162
+ };
1163
+ }
1164
+ if (!existing.isActive) {
1165
+ return {
1166
+ jsonrpc: '2.0', id,
1167
+ result: { content: [{ type: 'text', text: `Memory ${memoryId} is already inactive` }], isError: true },
1168
+ };
1169
+ }
1170
+ memoryStore.deactivate(memoryId);
1171
+ (0, memory_cache_1.invalidateCache)();
1172
+ return {
1173
+ jsonrpc: '2.0', id,
1174
+ result: {
1175
+ content: [{
1176
+ type: 'text',
1177
+ text: `Memory deleted.\n\nContent: "${existing.intent}"\nType: ${existing.type}\nReason: ${reason}\n\nMemory ID ${memoryId} has been deactivated.`,
1178
+ }],
1179
+ },
1180
+ };
1181
+ }
1182
+ catch (err) {
1183
+ return {
1184
+ jsonrpc: '2.0', id,
1185
+ result: { content: [{ type: 'text', text: `Delete error: ${err.message}` }], isError: true },
1186
+ };
1187
+ }
1188
+ }
1189
+ async function handleAutoLearn(id, args) {
1190
+ try {
1191
+ // PRO feature gate
1192
+ if (!(0, license_1.isPro)()) {
1193
+ return {
1194
+ jsonrpc: '2.0', id,
1195
+ result: { content: [{ type: 'text', text: (0, feature_gate_1.getUpgradeMessage)('auto_learn') }] },
1196
+ };
1197
+ }
1198
+ // Rate limit check
1199
+ const rateCheck = (0, rate_limiter_1.checkRateLimit)('auto_learn');
1200
+ if (!rateCheck.allowed) {
1201
+ return {
1202
+ jsonrpc: '2.0', id,
1203
+ result: { content: [{ type: 'text', text: `(auto_learn rate limited: ${rateCheck.reason})` }] },
1204
+ };
1205
+ }
1206
+ const text = args.text;
1207
+ if (!text || text.length < 20) {
1208
+ return {
1209
+ jsonrpc: '2.0', id,
1210
+ result: { content: [{ type: 'text', text: '(auto_learn: text too short, nothing extracted)' }] },
1211
+ };
1212
+ }
1213
+ // Extract memory-worthy patterns (regex-based)
1214
+ let extracted = (0, auto_learner_1.extractMemories)(text);
1215
+ // LLM enhancement: when API key is available and regex found nothing,
1216
+ // use LLM to catch implicit patterns that keywords miss
1217
+ if (extracted.length === 0 && (0, llm_enhancer_1.isLLMAvailable)() && text.length > 50) {
1218
+ try {
1219
+ const llmResult = await (0, llm_enhancer_1.enhanceMemory)(text);
1220
+ if (llmResult && llmResult.intent && llmResult.intent.length > 10) {
1221
+ extracted.push({
1222
+ type: (llmResult.type || 'INSIGHT'),
1223
+ content: llmResult.intent,
1224
+ confidence: 0.7,
1225
+ reason: 'LLM-extracted (regex missed this)',
1226
+ });
1227
+ }
1228
+ }
1229
+ catch { /* LLM failed, fall through to no-patterns path */ }
1230
+ }
1231
+ if (extracted.length === 0) {
1232
+ // Still feed session even if no patterns extracted (for topic tracking)
1233
+ if (text.length > 50) {
1234
+ (0, session_tracker_1.feedSession)({ topic: text.slice(0, 80) });
1235
+ }
1236
+ return {
1237
+ jsonrpc: '2.0', id,
1238
+ result: { content: [{ type: 'text', text: '(auto_learn: no memory-worthy patterns detected)' }] },
1239
+ };
1240
+ }
1241
+ // Store each extracted memory + feed session tracker
1242
+ const stored = [];
1243
+ const skipped = [];
1244
+ for (const item of extracted) {
1245
+ try {
1246
+ // Feed the session tracker with extracted patterns
1247
+ switch (item.type) {
1248
+ case 'DECISION':
1249
+ (0, session_tracker_1.feedSession)({ decision: item.content });
1250
+ break;
1251
+ case 'FAILED_ATTEMPT':
1252
+ (0, session_tracker_1.feedSession)({ failedAttempt: item.content });
1253
+ break;
1254
+ case 'BUSINESS_RULE':
1255
+ (0, session_tracker_1.feedSession)({ businessRule: item.content });
1256
+ break;
1257
+ case 'GOTCHA':
1258
+ (0, session_tracker_1.feedSession)({ gotcha: item.content });
1259
+ break;
1260
+ case 'CURRENT_TASK':
1261
+ (0, session_tracker_1.feedSession)({ currentTask: item.content });
1262
+ break;
1263
+ default:
1264
+ (0, session_tracker_1.feedSession)({ topic: item.content.slice(0, 60) });
1265
+ break;
1266
+ }
1267
+ const result = (0, memory_quality_1.storeWithQuality)(memoryStore, {
1268
+ type: item.type,
1269
+ intent: item.content,
1270
+ action: item.content,
1271
+ reason: item.reason,
1272
+ confidence: item.confidence,
1273
+ importance: item.confidence,
1274
+ tags: [item.type.toLowerCase()],
1275
+ });
1276
+ if (result.stored) {
1277
+ stored.push(`[${item.type}] ${item.content.slice(0, 60)}${item.content.length > 60 ? '…' : ''}`);
1278
+ }
1279
+ else {
1280
+ skipped.push(`[${item.type}] ${item.content.slice(0, 40)}… (duplicate)`);
1281
+ }
1282
+ }
1283
+ catch {
1284
+ // Skip individual failures silently
1285
+ }
1286
+ }
1287
+ if (stored.length > 0) {
1288
+ (0, memory_cache_1.invalidateCache)();
1289
+ }
1290
+ const lines = ['**Auto-Learn Results:**'];
1291
+ if (stored.length > 0) {
1292
+ lines.push(`\nStored ${stored.length} new memory${stored.length > 1 ? 'ies' : 'y'}:`);
1293
+ stored.forEach(s => lines.push(` • ${s}`));
1294
+ }
1295
+ if (skipped.length > 0) {
1296
+ lines.push(`\nSkipped ${skipped.length} duplicate${skipped.length > 1 ? 's' : ''}:`);
1297
+ skipped.forEach(s => lines.push(` • ${s}`));
1298
+ }
1299
+ return {
1300
+ jsonrpc: '2.0', id,
1301
+ result: { content: [{ type: 'text', text: lines.join('\n') }] },
1302
+ };
1303
+ }
1304
+ catch (err) {
1305
+ return {
1306
+ jsonrpc: '2.0', id,
1307
+ result: { content: [{ type: 'text', text: `auto_learn error: ${err.message}` }], isError: true },
1308
+ };
1309
+ }
1310
+ }
1311
+ function handleExportMemories(id) {
1312
+ try {
1313
+ const bundle = (0, export_import_1.exportMemories)(memoryStore);
1314
+ return {
1315
+ jsonrpc: '2.0', id,
1316
+ result: {
1317
+ content: [{
1318
+ type: 'text',
1319
+ text: `**Exported ${bundle.memoryCount} memories**\n\nSave this JSON to transfer to another machine:\n\n\`\`\`json\n${JSON.stringify(bundle, null, 2)}\n\`\`\``,
1320
+ }],
1321
+ },
1322
+ };
1323
+ }
1324
+ catch (err) {
1325
+ return {
1326
+ jsonrpc: '2.0', id,
1327
+ result: { content: [{ type: 'text', text: `Export error: ${err.message}` }], isError: true },
1328
+ };
1329
+ }
1330
+ }
1331
+ function handleImportMemories(id, args) {
1332
+ try {
1333
+ const data = args.data;
1334
+ if (!data) {
1335
+ return {
1336
+ jsonrpc: '2.0', id,
1337
+ result: { content: [{ type: 'text', text: 'Error: data is required (JSON string of exported bundle)' }], isError: true },
1338
+ };
1339
+ }
1340
+ const bundle = JSON.parse(data);
1341
+ if (bundle.version !== 1) {
1342
+ return {
1343
+ jsonrpc: '2.0', id,
1344
+ result: { content: [{ type: 'text', text: `Error: Unsupported export version: ${bundle.version}` }], isError: true },
1345
+ };
1346
+ }
1347
+ // Use the shared importMemories module (dedup-aware, O(n) not O(n²))
1348
+ const { importMemories } = require('../memory/export-import');
1349
+ const result = importMemories(memoryStore, bundle);
1350
+ (0, memory_cache_1.invalidateCache)();
1351
+ return {
1352
+ jsonrpc: '2.0', id,
1353
+ result: { content: [{ type: 'text', text: `Import complete.\n\nImported: ${result.imported}\nSkipped (duplicates): ${result.skipped}\nErrors: ${result.errors}` }] },
1354
+ };
1355
+ }
1356
+ catch (err) {
1357
+ return {
1358
+ jsonrpc: '2.0', id,
1359
+ result: { content: [{ type: 'text', text: `Import error: ${err.message}` }], isError: true },
1360
+ };
1361
+ }
1362
+ }
1363
+ function handleHealthCheck(id) {
1364
+ try {
1365
+ const stats = (0, rate_limiter_1.getRateLimitStats)();
1366
+ const activeCount = memoryStore.activeCount();
1367
+ const parts = [
1368
+ '# Cortex Health Check\n',
1369
+ `| Metric | Value |`,
1370
+ `|--------|-------|`,
1371
+ `| Active Memories | ${activeCount} |`,
1372
+ `| Session Store Count | ${stats.storeCount}/30 |`,
1373
+ `| Session Auto-Learn Count | ${stats.autoLearnCount}/100 |`,
1374
+ `| Session Total Calls | ${stats.totalCalls}/500 |`,
1375
+ `| Uptime | ${Math.floor(stats.uptime / 60)}m ${stats.uptime % 60}s |`,
1376
+ `| Status | Healthy |`,
1377
+ ];
1378
+ return {
1379
+ jsonrpc: '2.0', id,
1380
+ result: { content: [{ type: 'text', text: parts.join('\n') }] },
1381
+ };
1382
+ }
1383
+ catch (err) {
1384
+ return {
1385
+ jsonrpc: '2.0', id,
1386
+ result: { content: [{ type: 'text', text: `Health check error: ${err.message}` }], isError: true },
1387
+ };
1388
+ }
1389
+ }
1390
+ return { handleMCPRequest };
1391
+ }
1392
+ //# sourceMappingURL=mcp-handler.js.map