fivocell 1.0.5 → 3.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (182) hide show
  1. package/README.md +63 -464
  2. package/bin/cell.js +2 -2
  3. package/dist/behavior-intelligence.d.ts +90 -0
  4. package/dist/behavior-intelligence.d.ts.map +1 -0
  5. package/dist/behavior-intelligence.js +595 -0
  6. package/dist/behavior-intelligence.js.map +1 -0
  7. package/dist/behavioral-tracker.d.ts +90 -0
  8. package/dist/behavioral-tracker.d.ts.map +1 -0
  9. package/dist/behavioral-tracker.js +185 -0
  10. package/dist/behavioral-tracker.js.map +1 -0
  11. package/dist/cli.js +417 -1659
  12. package/dist/cli.js.map +1 -1
  13. package/dist/cloud-sync.d.ts +66 -0
  14. package/dist/cloud-sync.d.ts.map +1 -0
  15. package/dist/cloud-sync.js +328 -0
  16. package/dist/cloud-sync.js.map +1 -0
  17. package/dist/code-scanner.d.ts +51 -0
  18. package/dist/code-scanner.d.ts.map +1 -0
  19. package/dist/code-scanner.js +966 -0
  20. package/dist/code-scanner.js.map +1 -0
  21. package/dist/community-intel.d.ts +34 -0
  22. package/dist/community-intel.d.ts.map +1 -0
  23. package/dist/community-intel.js +148 -0
  24. package/dist/community-intel.js.map +1 -0
  25. package/dist/community-intelligence.d.ts +42 -0
  26. package/dist/community-intelligence.d.ts.map +1 -0
  27. package/dist/community-intelligence.js +160 -0
  28. package/dist/community-intelligence.js.map +1 -0
  29. package/dist/community-v2.d.ts +106 -0
  30. package/dist/community-v2.d.ts.map +1 -0
  31. package/dist/community-v2.js +378 -0
  32. package/dist/community-v2.js.map +1 -0
  33. package/dist/core/__tests__/chapter8-hostile.test.js +1 -1
  34. package/dist/core/__tests__/chapter8-hostile.test.js.map +1 -1
  35. package/dist/core/__tests__/chapter9-hostile.test.js +1 -1
  36. package/dist/core/__tests__/chapter9-hostile.test.js.map +1 -1
  37. package/dist/core/__tests__/complexity-analyzer.test.js +15 -15
  38. package/dist/core/__tests__/team-composer.test.js +2 -1
  39. package/dist/core/__tests__/team-composer.test.js.map +1 -1
  40. package/dist/core/convention-detector.d.ts.map +1 -1
  41. package/dist/core/convention-detector.js +11 -23
  42. package/dist/core/convention-detector.js.map +1 -1
  43. package/dist/core/cost-optimizer.d.ts.map +1 -1
  44. package/dist/core/cost-optimizer.js +13 -25
  45. package/dist/core/cost-optimizer.js.map +1 -1
  46. package/dist/core/database.d.ts +28 -0
  47. package/dist/core/database.d.ts.map +1 -0
  48. package/dist/core/database.js +587 -0
  49. package/dist/core/database.js.map +1 -0
  50. package/dist/core/knowledge-graph.d.ts.map +1 -1
  51. package/dist/core/knowledge-graph.js +9 -24
  52. package/dist/core/knowledge-graph.js.map +1 -1
  53. package/dist/core/logger.d.ts +9 -0
  54. package/dist/core/logger.d.ts.map +1 -0
  55. package/dist/core/logger.js +26 -0
  56. package/dist/core/logger.js.map +1 -0
  57. package/dist/core/playbook-generator.js +48 -48
  58. package/dist/core/privacy-manager.d.ts.map +1 -1
  59. package/dist/core/privacy-manager.js +5 -0
  60. package/dist/core/privacy-manager.js.map +1 -1
  61. package/dist/core/project-dna.d.ts.map +1 -1
  62. package/dist/core/project-dna.js +6 -19
  63. package/dist/core/project-dna.js.map +1 -1
  64. package/dist/core/prompt-builder.d.ts +18 -0
  65. package/dist/core/prompt-builder.d.ts.map +1 -0
  66. package/dist/core/prompt-builder.js +325 -0
  67. package/dist/core/prompt-builder.js.map +1 -0
  68. package/dist/core/session-memory.d.ts +90 -0
  69. package/dist/core/session-memory.d.ts.map +1 -0
  70. package/dist/core/session-memory.js +229 -0
  71. package/dist/core/session-memory.js.map +1 -0
  72. package/dist/core/signal-capture.d.ts +5 -0
  73. package/dist/core/signal-capture.d.ts.map +1 -1
  74. package/dist/core/signal-capture.js +67 -0
  75. package/dist/core/signal-capture.js.map +1 -1
  76. package/dist/core/team-composer.d.ts.map +1 -1
  77. package/dist/core/team-composer.js +16 -6
  78. package/dist/core/team-composer.js.map +1 -1
  79. package/dist/cross-model-memory.d.ts +95 -0
  80. package/dist/cross-model-memory.d.ts.map +1 -0
  81. package/dist/cross-model-memory.js +229 -0
  82. package/dist/cross-model-memory.js.map +1 -0
  83. package/dist/daemon/lifecycle.d.ts +3 -0
  84. package/dist/daemon/lifecycle.d.ts.map +1 -1
  85. package/dist/daemon/lifecycle.js +98 -64
  86. package/dist/daemon/lifecycle.js.map +1 -1
  87. package/dist/daemon/server.d.ts.map +1 -1
  88. package/dist/daemon/server.js +637 -25
  89. package/dist/daemon/server.js.map +1 -1
  90. package/dist/developer-intelligence.d.ts +18 -0
  91. package/dist/developer-intelligence.d.ts.map +1 -0
  92. package/dist/developer-intelligence.js +180 -0
  93. package/dist/developer-intelligence.js.map +1 -0
  94. package/dist/first-run.d.ts +8 -0
  95. package/dist/first-run.d.ts.map +1 -0
  96. package/dist/first-run.js +182 -0
  97. package/dist/first-run.js.map +1 -0
  98. package/dist/focus-report.d.ts +32 -0
  99. package/dist/focus-report.d.ts.map +1 -0
  100. package/dist/focus-report.js +293 -0
  101. package/dist/focus-report.js.map +1 -0
  102. package/dist/ide-intelligence.d.ts +118 -0
  103. package/dist/ide-intelligence.d.ts.map +1 -0
  104. package/dist/ide-intelligence.js +284 -0
  105. package/dist/ide-intelligence.js.map +1 -0
  106. package/dist/index.d.ts +22 -0
  107. package/dist/index.d.ts.map +1 -1
  108. package/dist/index.js +119 -2
  109. package/dist/index.js.map +1 -1
  110. package/dist/insight-generator.d.ts +58 -0
  111. package/dist/insight-generator.d.ts.map +1 -0
  112. package/dist/insight-generator.js +314 -0
  113. package/dist/insight-generator.js.map +1 -0
  114. package/dist/journey-memory.d.ts +75 -0
  115. package/dist/journey-memory.d.ts.map +1 -0
  116. package/dist/journey-memory.js +360 -0
  117. package/dist/journey-memory.js.map +1 -0
  118. package/dist/layers.d.ts +92 -0
  119. package/dist/layers.d.ts.map +1 -0
  120. package/dist/layers.js +226 -0
  121. package/dist/layers.js.map +1 -0
  122. package/dist/mcp-server.d.ts +406 -0
  123. package/dist/mcp-server.d.ts.map +1 -0
  124. package/dist/mcp-server.js +414 -0
  125. package/dist/mcp-server.js.map +1 -0
  126. package/dist/onboarding-scan.d.ts +174 -0
  127. package/dist/onboarding-scan.d.ts.map +1 -0
  128. package/dist/onboarding-scan.js +1039 -0
  129. package/dist/onboarding-scan.js.map +1 -0
  130. package/dist/pc-scanner.d.ts +46 -0
  131. package/dist/pc-scanner.d.ts.map +1 -0
  132. package/dist/pc-scanner.js +488 -0
  133. package/dist/pc-scanner.js.map +1 -0
  134. package/dist/personal-intelligence.d.ts +97 -0
  135. package/dist/personal-intelligence.d.ts.map +1 -0
  136. package/dist/personal-intelligence.js +408 -0
  137. package/dist/personal-intelligence.js.map +1 -0
  138. package/dist/predictive-engine.d.ts +19 -0
  139. package/dist/predictive-engine.d.ts.map +1 -0
  140. package/dist/predictive-engine.js +107 -0
  141. package/dist/predictive-engine.js.map +1 -0
  142. package/dist/predictive-intelligence.d.ts +95 -0
  143. package/dist/predictive-intelligence.d.ts.map +1 -0
  144. package/dist/predictive-intelligence.js +544 -0
  145. package/dist/predictive-intelligence.js.map +1 -0
  146. package/dist/production.d.ts +67 -0
  147. package/dist/production.d.ts.map +1 -0
  148. package/dist/production.js +333 -0
  149. package/dist/production.js.map +1 -0
  150. package/dist/senior-features.d.ts +63 -0
  151. package/dist/senior-features.d.ts.map +1 -0
  152. package/dist/senior-features.js +325 -0
  153. package/dist/senior-features.js.map +1 -0
  154. package/dist/style-pull.d.ts +40 -0
  155. package/dist/style-pull.d.ts.map +1 -0
  156. package/dist/style-pull.js +385 -0
  157. package/dist/style-pull.js.map +1 -0
  158. package/dist/team-collaboration.d.ts +116 -0
  159. package/dist/team-collaboration.d.ts.map +1 -0
  160. package/dist/team-collaboration.js +375 -0
  161. package/dist/team-collaboration.js.map +1 -0
  162. package/dist/team-git.d.ts +47 -0
  163. package/dist/team-git.d.ts.map +1 -0
  164. package/dist/team-git.js +305 -0
  165. package/dist/team-git.js.map +1 -0
  166. package/dist/team-intelligence.d.ts +64 -0
  167. package/dist/team-intelligence.d.ts.map +1 -0
  168. package/dist/team-intelligence.js +289 -0
  169. package/dist/team-intelligence.js.map +1 -0
  170. package/dist/test-watch.d.ts +2 -0
  171. package/dist/test-watch.d.ts.map +1 -0
  172. package/dist/test-watch.js +8 -0
  173. package/dist/test-watch.js.map +1 -0
  174. package/dist/user-intelligence.d.ts +69 -0
  175. package/dist/user-intelligence.d.ts.map +1 -0
  176. package/dist/user-intelligence.js +553 -0
  177. package/dist/user-intelligence.js.map +1 -0
  178. package/dist/work-style.d.ts +49 -0
  179. package/dist/work-style.d.ts.map +1 -0
  180. package/dist/work-style.js +247 -0
  181. package/dist/work-style.js.map +1 -0
  182. package/package.json +3 -2
@@ -113,7 +113,10 @@ const recommendation_store_1 = require("../core/recommendation-store");
113
113
  const community_intelligence_1 = require("../core/community-intelligence");
114
114
  const org_intelligence_1 = require("../core/org-intelligence");
115
115
  const cross_layer_intelligence_1 = require("../core/cross-layer-intelligence");
116
+ const database_1 = require("../core/database");
117
+ const logger_1 = require("../core/logger");
116
118
  const CELL_DIR = path.join(os.homedir(), '.fivo', 'cell');
119
+ (0, database_1.initializeDatabase)();
117
120
  const META_PATH = path.join(CELL_DIR, 'cell-meta.json');
118
121
  const PORT = 9876;
119
122
  function getCloudConfig() {
@@ -121,7 +124,9 @@ function getCloudConfig() {
121
124
  if (fs.existsSync(META_PATH))
122
125
  return JSON.parse(fs.readFileSync(META_PATH, 'utf-8'));
123
126
  }
124
- catch { }
127
+ catch (e) {
128
+ logger_1.logger.warn('Failed to read cell-meta.json: ' + String(e));
129
+ }
125
130
  return { cloudSyncEnabled: true };
126
131
  }
127
132
  const app = (0, express_1.default)();
@@ -199,16 +204,104 @@ app.get('/health', (_req, res) => {
199
204
  });
200
205
  });
201
206
  app.post('/signal', (req, res) => {
202
- const { type, originalCode, editedCode, context } = req.body;
203
- if (!type || !context) {
204
- res.status(400).json({ error: 'type and context required' });
207
+ const { type, originalCode, editedCode, context, file, fromFile, costMs, durationMs, switchCount, language, errorMessage, errorType, line, fixApplied, fixWorked, timeToFixMs, decision, approach, result, worked, task, files, description, stuckId, resolution, project } = req.body;
208
+ if (!type) {
209
+ res.status(400).json({ error: 'type required' });
210
+ return;
211
+ }
212
+ // ─── Behavioral Signals ───────────────────────────────────────
213
+ if (type === 'error') {
214
+ const { logError, getErrorPatterns } = require('../behavioral-tracker');
215
+ const r = logError({ project, file, errorType, errorMessage, line });
216
+ // Check if repeat mistake — send warning
217
+ let warning = null;
218
+ try {
219
+ const patterns = getErrorPatterns(project);
220
+ const match = patterns.find((p) => p.error_type === errorType);
221
+ if (match && match.count >= 2) {
222
+ warning = `⚠ Repeat mistake! "${errorType}" has occurred ${match.count}x before. Fix the root cause.`;
223
+ }
224
+ }
225
+ catch { }
226
+ res.json({ recorded: true, id: r.id, warning });
227
+ return;
228
+ }
229
+ if (type === 'error_fix') {
230
+ const { logErrorFix } = require('../behavioral-tracker');
231
+ logErrorFix({ errorId: stuckId || 0, fixApplied: fixApplied || '', worked: fixWorked || false, timeToFixMs: timeToFixMs || 0 });
232
+ res.json({ recorded: true });
233
+ return;
234
+ }
235
+ if (type === 'decision') {
236
+ const { logDecision } = require('../behavioral-tracker');
237
+ const r = logDecision({ project, file, decision, approach, result, worked, context: req.body.context || '' });
238
+ // Auto-track in session memory
239
+ try {
240
+ const { SessionMemory } = require('../core/session-memory');
241
+ const mem = new SessionMemory();
242
+ const lastSess = mem.getLastSessionForProject(project || '');
243
+ if (lastSess && !lastSess.endTime) {
244
+ const decs = JSON.parse(String(lastSess.keyDecisions || '[]'));
245
+ decs.push(`${decision}: ${approach || result || ''}`);
246
+ mem.endSession(lastSess.id, { keyDecisions: decs, contextSnapshot: req.body.context || decision });
247
+ }
248
+ }
249
+ catch { }
250
+ res.json({ recorded: true, id: r.id });
251
+ return;
252
+ }
253
+ if (type === 'context') {
254
+ const { logContext } = require('../behavioral-tracker');
255
+ const r = logContext({ project, task, files });
256
+ // Auto-start session if none exists
257
+ try {
258
+ const { SessionMemory } = require('../core/session-memory');
259
+ const mem = new SessionMemory();
260
+ const lastSess = mem.getLastSessionForProject(project || '');
261
+ if (!lastSess || lastSess.endTime) {
262
+ const tool = req.body.tool || 'cli';
263
+ mem.startSession(tool, project || '');
264
+ if (files && files.length > 0) {
265
+ const newSess = mem.getLastSessionForProject(project || '');
266
+ if (newSess)
267
+ mem.endSession(newSess.id, { filesTouched: files, contextSnapshot: task });
268
+ }
269
+ }
270
+ }
271
+ catch { }
272
+ res.json({ recorded: true, id: r.id });
273
+ return;
274
+ }
275
+ if (type === 'stuck') {
276
+ const { logStuck } = require('../behavioral-tracker');
277
+ const r = logStuck({ project, file, description });
278
+ res.json({ recorded: true, id: r.id });
279
+ return;
280
+ }
281
+ if (type === 'stuck_resolved') {
282
+ const { logStuckResolved } = require('../behavioral-tracker');
283
+ logStuckResolved(stuckId || 0, resolution || '');
284
+ res.json({ recorded: true });
205
285
  return;
206
286
  }
287
+ // ─── IDE Signals ──────────────────────────────────────────────
288
+ if (type === 'tab_switch' || type === 'focus_block' || type === 'file_save') {
289
+ try {
290
+ const db = (0, database_1.getDb)();
291
+ db.prepare('INSERT INTO behavior_events (event_type, project, file_path, description, severity, evidence) VALUES (?, ?, ?, ?, ?, ?)')
292
+ .run(type, '', file || '', JSON.stringify({ fromFile, costMs, durationMs, switchCount, language }), 'low', JSON.stringify(req.body));
293
+ }
294
+ catch { }
295
+ res.json({ recorded: true, type });
296
+ return;
297
+ }
298
+ // ─── Legacy Signals ──────────────────────────────────────────
299
+ const ctx = context || {};
207
300
  let signal;
208
301
  let patternsExtracted = 0;
209
302
  switch (type) {
210
303
  case 'edit_diff': {
211
- signal = engines.signalCapture.captureEditDiff(originalCode || '', editedCode || '', context);
304
+ signal = engines.signalCapture.captureEditDiff(originalCode || '', editedCode || '', ctx);
212
305
  try {
213
306
  const result = engines.extractionCascade.extract(originalCode || '', editedCode || '');
214
307
  patternsExtracted = engines.learningLayer.process(result, true);
@@ -221,35 +314,28 @@ app.post('/signal', (req, res) => {
221
314
  break;
222
315
  }
223
316
  case 'accept': {
224
- signal = engines.signalCapture.captureAccept(originalCode || '', context);
317
+ signal = engines.signalCapture.captureAccept(originalCode || '', ctx);
225
318
  const dummy = engines.patternStore.getAllPatterns().slice(0, 1);
226
319
  for (const p of dummy) {
227
320
  const step = (0, workflow_tracker_1.recordStep)(p, 'accept');
228
321
  (0, outcome_recorder_1.recordOutcome)(p, 'accept', step.sessionId, true, 0);
229
- (0, failure_memory_1.recordFailure)(p, false, context?.language || 'unknown');
230
- (0, time_saved_1.recordTimeSaved)({
231
- patternId: p.patternId,
232
- category: p.category,
233
- description: p.description,
234
- from: p.from,
235
- to: p.to,
236
- language: context?.language || 'unknown',
237
- });
322
+ (0, failure_memory_1.recordFailure)(p, false, ctx.language || 'unknown');
323
+ (0, time_saved_1.recordTimeSaved)({ patternId: p.patternId, category: p.category, description: p.description, from: p.from, to: p.to, language: ctx.language || 'unknown' });
238
324
  }
239
325
  break;
240
326
  }
241
327
  case 'reject': {
242
- signal = engines.signalCapture.captureReject(originalCode || '', context);
328
+ signal = engines.signalCapture.captureReject(originalCode || '', ctx);
243
329
  const dummyR = engines.patternStore.getAllPatterns().slice(0, 1);
244
330
  for (const p of dummyR) {
245
331
  const step = (0, workflow_tracker_1.recordStep)(p, 'reject');
246
332
  (0, outcome_recorder_1.recordOutcome)(p, 'reject', step.sessionId, false, 0);
247
- (0, failure_memory_1.recordFailure)(p, true, context?.language || 'unknown');
333
+ (0, failure_memory_1.recordFailure)(p, true, ctx.language || 'unknown');
248
334
  }
249
335
  break;
250
336
  }
251
337
  case 'retry': {
252
- signal = engines.signalCapture.captureRetry(originalCode || '', context);
338
+ signal = engines.signalCapture.captureRetry(originalCode || '', ctx);
253
339
  const dummyRt = engines.patternStore.getAllPatterns().slice(0, 1);
254
340
  for (const p of dummyRt) {
255
341
  const step = (0, workflow_tracker_1.recordStep)(p, 'retry');
@@ -318,15 +404,25 @@ app.get('/confidence/:patternId', (req, res) => {
318
404
  });
319
405
  // ─── IMPACT TRACKING ──────────────────────────────────
320
406
  const impactLog = [];
407
+ function persistImpact(entry) {
408
+ try {
409
+ const db = (0, database_1.getDb)();
410
+ db.prepare('INSERT INTO outcomes (outcome_type, pattern_id, project, description, created_at) VALUES (?, ?, ?, ?, ?)')
411
+ .run('impact', entry.patternId, '', `Applied via ${entry.surface}`, new Date(entry.timestamp).toISOString());
412
+ }
413
+ catch { /* best-effort */ }
414
+ }
321
415
  app.post('/impact/record', (req, res) => {
322
416
  const { patternId, surface } = req.body;
323
417
  if (!patternId) {
324
418
  res.status(400).json({ error: 'patternId required' });
325
419
  return;
326
420
  }
327
- impactLog.push({ patternId, timestamp: Date.now(), surface: surface || 'unknown' });
421
+ const entry = { patternId, timestamp: Date.now(), surface: surface || 'unknown' };
422
+ impactLog.push(entry);
328
423
  if (impactLog.length > 10000)
329
424
  impactLog.splice(0, impactLog.length - 10000);
425
+ persistImpact(entry);
330
426
  res.json({ recorded: true });
331
427
  });
332
428
  app.get('/impact/weekly', (_req, res) => {
@@ -368,7 +464,9 @@ app.post('/onboarding/scan', (req, res) => {
368
464
  insights.push('TypeScript strict mode → You likely prefer const over let');
369
465
  }
370
466
  }
371
- catch { }
467
+ catch (e) {
468
+ logger_1.logger.warn('Failed to read tsconfig: ' + String(e));
469
+ }
372
470
  try {
373
471
  const eslintPaths = ['.eslintrc.json', '.eslintrc.js', '.eslintrc.yaml', '.eslintrc.yml', 'eslint.config.js'];
374
472
  for (const eslintFile of eslintPaths) {
@@ -379,12 +477,16 @@ app.post('/onboarding/scan', (req, res) => {
379
477
  if (JSON.stringify(eslint).includes('singlequote') || JSON.stringify(eslint).includes('single'))
380
478
  insights.push('ESLint single quotes → You prefer \' over \"');
381
479
  }
382
- catch { }
480
+ catch (e) {
481
+ logger_1.logger.warn('Failed to parse eslint config: ' + String(e));
482
+ }
383
483
  break;
384
484
  }
385
485
  }
386
486
  }
387
- catch { }
487
+ catch (e) {
488
+ logger_1.logger.warn('Failed to read eslint: ' + String(e));
489
+ }
388
490
  try {
389
491
  const pkgPath = path.join(dir, 'package.json');
390
492
  if (fs.existsSync(pkgPath)) {
@@ -404,7 +506,9 @@ app.post('/onboarding/scan', (req, res) => {
404
506
  insights.push('Zod → You prefer schema validation');
405
507
  }
406
508
  }
407
- catch { }
509
+ catch (e) {
510
+ logger_1.logger.warn('Failed to read package.json: ' + String(e));
511
+ }
408
512
  res.json({ insights, count: insights.length, projectPath: dir });
409
513
  });
410
514
  // ─── LOCAL DASHBOARD HTML ─────────────────────────────
@@ -1299,20 +1403,528 @@ app.post('/intelligence/reset', (_req, res) => {
1299
1403
  (0, cross_layer_intelligence_1.resetCrossLayer)();
1300
1404
  res.json({ reset: true });
1301
1405
  });
1406
+ // ─── CONTEXT INJECTION ───────────────────────────────
1407
+ const prompt_builder_1 = require("../core/prompt-builder");
1408
+ const session_memory_1 = require("../core/session-memory");
1409
+ const sessionMemory = new session_memory_1.SessionMemory();
1410
+ app.post('/session/start', (req, res) => {
1411
+ const { toolName, project } = req.body;
1412
+ const id = sessionMemory.startSession(toolName || 'unknown', project || 'unknown');
1413
+ res.json({ sessionId: id });
1414
+ });
1415
+ app.post('/session/end', (req, res) => {
1416
+ const { sessionId, filesTouched, keyDecisions, contextSnapshot } = req.body;
1417
+ sessionMemory.endSession(Number(sessionId), { filesTouched, keyDecisions, contextSnapshot });
1418
+ res.json({ ended: true });
1419
+ });
1420
+ app.get('/session/history', (req, res) => {
1421
+ const limit = Number(req.query.limit) || 10;
1422
+ const sessions = sessionMemory.getRecentSessions(limit);
1423
+ const stats = sessionMemory.getSessionStats();
1424
+ const chain = sessionMemory.buildContextChain();
1425
+ res.json({ sessions, stats, contextChain: chain });
1426
+ });
1427
+ app.get('/session/search', (req, res) => {
1428
+ const query = String(req.query.q || '');
1429
+ const results = query ? sessionMemory.searchSessions(query) : [];
1430
+ res.json({ query, results: results.slice(0, 10) });
1431
+ });
1432
+ app.get('/session/bugs', (req, res) => {
1433
+ const bugs = sessionMemory.getBugHistory(String(req.query.project || ''));
1434
+ const repeats = sessionMemory.getRepeatBugs();
1435
+ res.json({ bugs: bugs.slice(0, 20), repeatBugs: repeats });
1436
+ });
1437
+ app.get('/session/decisions', (req, res) => {
1438
+ const decisions = sessionMemory.getDecisionHistory(String(req.query.project || ''));
1439
+ const summary = sessionMemory.getDecisionSummary();
1440
+ res.json({ decisions: decisions.slice(0, 20), summary });
1441
+ });
1442
+ app.get('/context/inject', (req, res) => {
1443
+ const projectPath = req.query.projectPath;
1444
+ const toolName = req.query.tool;
1445
+ const compact = req.query.compact === 'true' || req.query.compact === '1';
1446
+ const ctx = (0, prompt_builder_1.buildContext)(projectPath, toolName);
1447
+ const text = (0, prompt_builder_1.formatContextForInjection)(ctx, compact);
1448
+ res.json({ content: [{ type: 'text', text }], context: ctx });
1449
+ });
1450
+ app.get('/predict', (req, res) => {
1451
+ const project = String(req.query.project || '');
1452
+ const type = String(req.query.type || '');
1453
+ Promise.resolve().then(() => __importStar(require('../predictive-intelligence'))).then(({ getAllPredictions }) => {
1454
+ const predictions = getAllPredictions(project || undefined);
1455
+ const filtered = type ? predictions.filter(p => p.type === type) : predictions;
1456
+ res.json({ predictions: filtered, count: filtered.length });
1457
+ }).catch(e => res.status(500).json({ error: String(e) }));
1458
+ });
1459
+ app.get('/predict-risk/:file', (req, res) => {
1460
+ const file = req.params.file;
1461
+ Promise.resolve().then(() => __importStar(require('../predictive-intelligence'))).then(({ calculateFileRisk }) => {
1462
+ res.json(calculateFileRisk(file));
1463
+ }).catch(e => res.status(500).json({ error: String(e) }));
1464
+ });
1465
+ app.get('/predict-time/:feature', (req, res) => {
1466
+ const feature = req.params.feature;
1467
+ Promise.resolve().then(() => __importStar(require('../predictive-intelligence'))).then(({ estimateFeatureTime }) => {
1468
+ res.json(estimateFeatureTime(feature));
1469
+ }).catch(e => res.status(500).json({ error: String(e) }));
1470
+ });
1471
+ app.get('/tools/compare', (_req, res) => {
1472
+ Promise.resolve().then(() => __importStar(require('../cross-model-memory'))).then(({ compareTools }) => {
1473
+ res.json({ tools: compareTools() });
1474
+ }).catch(e => res.status(500).json({ error: String(e) }));
1475
+ });
1476
+ app.get('/tools/suggest', (req, res) => {
1477
+ const taskType = String(req.query.task || '');
1478
+ if (!taskType) {
1479
+ res.status(400).json({ error: 'task query param required' });
1480
+ return;
1481
+ }
1482
+ Promise.resolve().then(() => __importStar(require('../cross-model-memory'))).then(({ suggestTool }) => {
1483
+ res.json({ suggestions: suggestTool(taskType) });
1484
+ }).catch(e => res.status(500).json({ error: String(e) }));
1485
+ });
1486
+ app.get('/tools/history', (_req, res) => {
1487
+ Promise.resolve().then(() => __importStar(require('../cross-model-memory'))).then(({ getModelHistory }) => {
1488
+ res.json({ history: getModelHistory() });
1489
+ }).catch(e => res.status(500).json({ error: String(e) }));
1490
+ });
1491
+ app.get('/tools/context/:tool', (req, res) => {
1492
+ const tool = req.params.tool;
1493
+ Promise.resolve().then(() => __importStar(require('../cross-model-memory'))).then(({ buildToolSpecificContext }) => {
1494
+ res.json({ context: buildToolSpecificContext(tool) });
1495
+ }).catch(e => res.status(500).json({ error: String(e) }));
1496
+ });
1497
+ app.get('/team/health', (req, res) => {
1498
+ const project = String(req.query.project || '') || undefined;
1499
+ Promise.resolve().then(() => __importStar(require('../team-collaboration'))).then(({ getTeamHealth }) => {
1500
+ res.json(getTeamHealth(project));
1501
+ }).catch(e => res.status(500).json({ error: String(e) }));
1502
+ });
1503
+ app.get('/team/silos', (_req, res) => {
1504
+ Promise.resolve().then(() => __importStar(require('../team-collaboration'))).then(({ detectKnowledgeSilos, calculateBusFactor, suggestKnowledgeTransfer }) => {
1505
+ res.json({ silos: detectKnowledgeSilos(), busFactor: calculateBusFactor(), transfers: suggestKnowledgeTransfer() });
1506
+ }).catch(e => res.status(500).json({ error: String(e) }));
1507
+ });
1508
+ app.get('/team/style', (req, res) => {
1509
+ const project = String(req.query.project || '') || undefined;
1510
+ Promise.resolve().then(() => __importStar(require('../team-collaboration'))).then(({ composeTeamStyle }) => {
1511
+ res.json(composeTeamStyle(project));
1512
+ }).catch(e => res.status(500).json({ error: String(e) }));
1513
+ });
1514
+ app.get('/team/retro', (req, res) => {
1515
+ const days = parseInt(String(req.query.days || '14')) || 14;
1516
+ const project = String(req.query.project || '') || undefined;
1517
+ Promise.resolve().then(() => __importStar(require('../team-collaboration'))).then(({ generateSprintRetro }) => {
1518
+ res.json(generateSprintRetro(days, project));
1519
+ }).catch(e => res.status(500).json({ error: String(e) }));
1520
+ });
1521
+ app.get('/team/onboard/:team', (req, res) => {
1522
+ const team = req.params.team;
1523
+ const project = String(req.query.project || '') || undefined;
1524
+ Promise.resolve().then(() => __importStar(require('../team-collaboration'))).then(({ generateOnboardingDoc }) => {
1525
+ res.json(generateOnboardingDoc(team, project));
1526
+ }).catch(e => res.status(500).json({ error: String(e) }));
1527
+ });
1528
+ app.get('/community/compare', (_req, res) => {
1529
+ Promise.resolve().then(() => __importStar(require('../community-v2'))).then(({ benchmarkPersonal, benchmarkBlindSpots }) => {
1530
+ res.json({ benchmarks: benchmarkPersonal(), blindSpots: benchmarkBlindSpots() });
1531
+ }).catch(e => res.status(500).json({ error: String(e) }));
1532
+ });
1533
+ app.get('/community/trends', (_req, res) => {
1534
+ Promise.resolve().then(() => __importStar(require('../community-v2'))).then(({ detectTrends, getCommunityStats }) => {
1535
+ res.json({ trends: detectTrends(), stats: getCommunityStats() });
1536
+ }).catch(e => res.status(500).json({ error: String(e) }));
1537
+ });
1538
+ app.get('/community/insights', (_req, res) => {
1539
+ Promise.resolve().then(() => __importStar(require('../community-v2'))).then(({ generateInsights }) => {
1540
+ res.json({ insights: generateInsights() });
1541
+ }).catch(e => res.status(500).json({ error: String(e) }));
1542
+ });
1543
+ app.get('/personal/rhythm', (_req, res) => {
1544
+ Promise.resolve().then(() => __importStar(require('../personal-intelligence'))).then(({ detectCodingRhythm }) => {
1545
+ res.json(detectCodingRhythm());
1546
+ }).catch(e => res.status(500).json({ error: String(e) }));
1547
+ });
1548
+ app.get('/personal/burnout', (_req, res) => {
1549
+ Promise.resolve().then(() => __importStar(require('../personal-intelligence'))).then(({ detectBurnout }) => {
1550
+ res.json(detectBurnout());
1551
+ }).catch(e => res.status(500).json({ error: String(e) }));
1552
+ });
1553
+ app.get('/personal/mastery', (_req, res) => {
1554
+ Promise.resolve().then(() => __importStar(require('../personal-intelligence'))).then(({ getTechMasteryMap }) => {
1555
+ res.json({ mastery: getTechMasteryMap() });
1556
+ }).catch(e => res.status(500).json({ error: String(e) }));
1557
+ });
1558
+ app.get('/personal/growth', (_req, res) => {
1559
+ Promise.resolve().then(() => __importStar(require('../personal-intelligence'))).then(({ getCareerTrajectory }) => {
1560
+ res.json(getCareerTrajectory());
1561
+ }).catch(e => res.status(500).json({ error: String(e) }));
1562
+ });
1563
+ app.get('/personal/weekly', (_req, res) => {
1564
+ Promise.resolve().then(() => __importStar(require('../personal-intelligence'))).then(({ generateWeeklyDigest }) => {
1565
+ res.json(generateWeeklyDigest());
1566
+ }).catch(e => res.status(500).json({ error: String(e) }));
1567
+ });
1568
+ app.get('/production/health', (_req, res) => {
1569
+ Promise.resolve().then(() => __importStar(require('../production'))).then(({ getHealthStatus }) => {
1570
+ res.json(getHealthStatus());
1571
+ }).catch(e => res.status(500).json({ error: String(e) }));
1572
+ });
1573
+ app.get('/production/metrics', (_req, res) => {
1574
+ Promise.resolve().then(() => __importStar(require('../production'))).then(({ getMetrics }) => {
1575
+ res.json(getMetrics());
1576
+ }).catch(e => res.status(500).json({ error: String(e) }));
1577
+ });
1578
+ app.get('/production/security', (_req, res) => {
1579
+ Promise.resolve().then(() => __importStar(require('../production'))).then(() => {
1580
+ const fs = require('fs');
1581
+ const path = require('path');
1582
+ const os = require('os');
1583
+ const secFile = path.join(os.homedir(), '.fivo', 'cell', 'security.json');
1584
+ if (fs.existsSync(secFile)) {
1585
+ res.json(JSON.parse(fs.readFileSync(secFile, 'utf-8')));
1586
+ }
1587
+ else {
1588
+ res.status(404).json({ error: 'no security config' });
1589
+ }
1590
+ }).catch(e => res.status(500).json({ error: String(e) }));
1591
+ });
1592
+ app.post('/production/backup', (_req, res) => {
1593
+ Promise.resolve().then(() => __importStar(require('../production'))).then(({ autoBackup }) => {
1594
+ res.json(autoBackup());
1595
+ }).catch(e => res.status(500).json({ error: String(e) }));
1596
+ });
1597
+ app.post('/production/optimize', (_req, res) => {
1598
+ Promise.resolve().then(() => __importStar(require('../production'))).then(({ optimizeDatabase }) => {
1599
+ res.json(optimizeDatabase());
1600
+ }).catch(e => res.status(500).json({ error: String(e) }));
1601
+ });
1602
+ app.get('/ide/debug-style', (_req, res) => {
1603
+ Promise.resolve().then(() => __importStar(require('../ide-intelligence'))).then(({ initializeIDETables, getDebugStyle }) => {
1604
+ initializeIDETables();
1605
+ res.json(getDebugStyle());
1606
+ }).catch(e => res.status(500).json({ error: String(e) }));
1607
+ });
1608
+ app.get('/ide/prompt-style', (_req, res) => {
1609
+ Promise.resolve().then(() => __importStar(require('../ide-intelligence'))).then(({ initializeIDETables, getPromptStyle }) => {
1610
+ initializeIDETables();
1611
+ res.json(getPromptStyle());
1612
+ }).catch(e => res.status(500).json({ error: String(e) }));
1613
+ });
1614
+ app.get('/ide/focus', (_req, res) => {
1615
+ Promise.resolve().then(() => __importStar(require('../ide-intelligence'))).then(({ initializeIDETables, getFocusAnalysis }) => {
1616
+ initializeIDETables();
1617
+ res.json(getFocusAnalysis());
1618
+ }).catch(e => res.status(500).json({ error: String(e) }));
1619
+ });
1620
+ app.get('/ide/insights', (_req, res) => {
1621
+ Promise.resolve().then(() => __importStar(require('../ide-intelligence'))).then(({ initializeIDETables, getIDEInsights }) => {
1622
+ initializeIDETables();
1623
+ res.json(getIDEInsights());
1624
+ }).catch(e => res.status(500).json({ error: String(e) }));
1625
+ });
1626
+ app.get('/cloud/status', (_req, res) => {
1627
+ Promise.resolve().then(() => __importStar(require('../cloud-sync'))).then(({ getSyncStatus }) => {
1628
+ res.json(getSyncStatus());
1629
+ }).catch(e => res.status(500).json({ error: String(e) }));
1630
+ });
1631
+ app.post('/cloud/validate', (req, res) => {
1632
+ Promise.resolve().then(() => __importStar(require('../cloud-sync'))).then(({ validatePayload }) => {
1633
+ res.json(validatePayload(req.body || {}));
1634
+ }).catch(e => res.status(500).json({ error: String(e) }));
1635
+ });
1636
+ app.get('/cloud/queue', (_req, res) => {
1637
+ Promise.resolve().then(() => __importStar(require('../cloud-sync'))).then(({ getPendingQueue, retryFailedEntries }) => {
1638
+ res.json({ pending: getPendingQueue(), retryable: retryFailedEntries() });
1639
+ }).catch(e => res.status(500).json({ error: String(e) }));
1640
+ });
1641
+ app.post('/cloud/push', (req, res) => {
1642
+ Promise.resolve().then(() => __importStar(require('../cloud-sync'))).then(({ pushToCloud }) => {
1643
+ pushToCloud(req.body?.data || {}, req.body?.type || 'pattern').then(r => res.json(r));
1644
+ }).catch(e => res.status(500).json({ error: String(e) }));
1645
+ });
1646
+ // ─── CODE SCANNER (Deep Learning) ──────────────────────
1647
+ app.post('/scan/codebase', (req, res) => {
1648
+ const { dir, project } = req.body;
1649
+ if (!dir) {
1650
+ res.status(400).json({ error: 'dir required' });
1651
+ return;
1652
+ }
1653
+ Promise.resolve().then(() => __importStar(require('../code-scanner'))).then(({ scanCodebase }) => {
1654
+ const result = scanCodebase(dir, project || require('path').basename(dir));
1655
+ res.json(result);
1656
+ }).catch(e => res.status(500).json({ error: String(e) }));
1657
+ });
1658
+ app.get('/scan/profile/:project', (req, res) => {
1659
+ Promise.resolve().then(() => __importStar(require('../code-scanner'))).then(({ getDeveloperProfile }) => {
1660
+ const profile = getDeveloperProfile(req.params.project);
1661
+ if (!profile) {
1662
+ res.status(404).json({ error: 'no profile — run scan first' });
1663
+ return;
1664
+ }
1665
+ res.json(profile);
1666
+ }).catch(e => res.status(500).json({ error: String(e) }));
1667
+ });
1668
+ app.get('/scan/patterns/:project', (req, res) => {
1669
+ const category = req.query.category;
1670
+ Promise.resolve().then(() => __importStar(require('../code-scanner'))).then(({ getCodePatterns }) => {
1671
+ res.json({ patterns: getCodePatterns(req.params.project, category) });
1672
+ }).catch(e => res.status(500).json({ error: String(e) }));
1673
+ });
1674
+ app.get('/scan/report/:project', (req, res) => {
1675
+ Promise.resolve().then(() => __importStar(require('../code-scanner'))).then(({ getDeveloperProfile, getCodePatterns }) => {
1676
+ const profile = getDeveloperProfile(req.params.project);
1677
+ const patterns = getCodePatterns(req.params.project);
1678
+ res.json({ project: req.params.project, profile, patterns, patternCount: patterns.length });
1679
+ }).catch(e => res.status(500).json({ error: String(e) }));
1680
+ });
1681
+ // ─── BEHAVIORAL TRACKING ──────────────────────────────────────
1682
+ app.get('/behavior/summary', (req, res) => {
1683
+ const { getBehaviorSummary } = require('../behavioral-tracker');
1684
+ res.json(getBehaviorSummary(String(req.query.project || undefined)));
1685
+ });
1686
+ app.get('/behavior/errors', (req, res) => {
1687
+ const { getErrorPatterns, getRecentErrors } = require('../behavioral-tracker');
1688
+ res.json({ patterns: getErrorPatterns(String(req.query.project || undefined)), recent: getRecentErrors(10, String(req.query.project || undefined)) });
1689
+ });
1690
+ app.get('/behavior/decisions', (req, res) => {
1691
+ const { getDecisions } = require('../behavioral-tracker');
1692
+ res.json({ decisions: getDecisions(String(req.query.project || undefined), 20) });
1693
+ });
1694
+ app.get('/behavior/context', (req, res) => {
1695
+ const { getCurrentContext } = require('../behavioral-tracker');
1696
+ res.json(getCurrentContext(String(req.query.project || undefined)) || { task: 'none', files: [] });
1697
+ });
1698
+ app.get('/behavior/stuck', (req, res) => {
1699
+ const { getStuckPatterns } = require('../behavioral-tracker');
1700
+ res.json({ stuck: getStuckPatterns(String(req.query.project || undefined)) });
1701
+ });
1702
+ // ─── Session Bridge Helper ────────────────────────────────────────────────
1703
+ function formatSessionBridge(fromTool, toTool, context, decisions) {
1704
+ const lines = [];
1705
+ lines.push(`═══ CROSS-SESSION BRIDGE ═══`);
1706
+ lines.push(`From: ${fromTool} → To: ${toTool}`);
1707
+ if (context)
1708
+ lines.push(`Last context: ${context}`);
1709
+ if (decisions && decisions !== 'none' && decisions !== '[]') {
1710
+ lines.push(`Decisions made: ${decisions}`);
1711
+ }
1712
+ lines.push(`Cell remembers. No need to re-explain.`);
1713
+ return lines.join('\n');
1714
+ }
1715
+ // ─── MCP ENDPOINTS (merged from mcp-server.ts) ─────────────────────────────
1716
+ const MCP_TOOLS = [
1717
+ { name: 'cell_get_dev_profile', description: 'Developer profile — naming, style, errors, architecture', inputSchema: { type: 'object', properties: { project: { type: 'string' } }, required: ['project'] } },
1718
+ { name: 'cell_get_code_patterns', description: 'Code patterns by category', inputSchema: { type: 'object', properties: { project: { type: 'string' }, category: { type: 'string' } }, required: ['project'] } },
1719
+ { name: 'cell_deep_scan', description: 'Deep scan codebase', inputSchema: { type: 'object', properties: { dir: { type: 'string' }, project: { type: 'string' } }, required: ['dir'] } },
1720
+ { name: 'cell_scan_report', description: 'Full scan report', inputSchema: { type: 'object', properties: { project: { type: 'string' } }, required: ['project'] } },
1721
+ { name: 'cell_send_signal', description: 'Send learning signal', inputSchema: { type: 'object', properties: { type: { type: 'string' }, originalCode: { type: 'string' }, editedCode: { type: 'string' }, file: { type: 'string' }, language: { type: 'string' } }, required: ['type'] } },
1722
+ { name: 'cell_get_context', description: 'Full context injection', inputSchema: { type: 'object', properties: { project: { type: 'string' }, tool: { type: 'string' } }, required: ['project'] } },
1723
+ { name: 'cell_scan_full_pc', description: 'Scan entire PC for all code projects', inputSchema: { type: 'object', properties: {} } },
1724
+ { name: 'cell_behavior_summary', description: 'Behavioral summary', inputSchema: { type: 'object', properties: { project: { type: 'string' } }, required: ['project'] } },
1725
+ { name: 'cell_log_error', description: 'Log an error encounter', inputSchema: { type: 'object', properties: { project: { type: 'string' }, file: { type: 'string' }, errorType: { type: 'string' }, errorMessage: { type: 'string' }, line: { type: 'number' } }, required: ['errorType', 'errorMessage'] } },
1726
+ { name: 'cell_log_fix', description: 'Log how an error was fixed', inputSchema: { type: 'object', properties: { errorId: { type: 'number' }, fixApplied: { type: 'string' }, worked: { type: 'boolean' }, timeToFixMs: { type: 'number' } }, required: ['errorId', 'fixApplied', 'worked'] } },
1727
+ { name: 'cell_log_decision', description: 'Log a coding decision', inputSchema: { type: 'object', properties: { project: { type: 'string' }, file: { type: 'string' }, decision: { type: 'string' }, approach: { type: 'string' }, worked: { type: 'boolean' } }, required: ['decision'] } },
1728
+ { name: 'cell_log_context', description: 'Log current context', inputSchema: { type: 'object', properties: { project: { type: 'string' }, task: { type: 'string' }, files: { type: 'array', items: { type: 'string' } } }, required: ['task'] } },
1729
+ { name: 'cell_log_stuck', description: 'Log when stuck', inputSchema: { type: 'object', properties: { project: { type: 'string' }, file: { type: 'string' }, description: { type: 'string' } }, required: ['description'] } },
1730
+ { name: 'cell_session_bridge', description: 'Cross-session memory bridge — get last session context when switching tools', inputSchema: { type: 'object', properties: { project: { type: 'string' }, tool: { type: 'string' } }, required: ['project'] } },
1731
+ { name: 'cell_predict', description: 'Predictive intelligence — repeat mistakes, decision regret, energy warnings, complexity traps', inputSchema: { type: 'object', properties: { project: { type: 'string' } }, required: [] } },
1732
+ ];
1733
+ async function handleMCPToolCall(name, args) {
1734
+ switch (name) {
1735
+ case 'cell_get_dev_profile': {
1736
+ const { getDeveloperProfile } = require('../code-scanner');
1737
+ const profile = getDeveloperProfile(args.project);
1738
+ if (!profile)
1739
+ return { error: 'no profile — run cell scan first' };
1740
+ return { project: args.project, profile };
1741
+ }
1742
+ case 'cell_get_code_patterns': {
1743
+ const { getCodePatterns } = require('../code-scanner');
1744
+ return { project: args.project, patterns: getCodePatterns(args.project, args.category) };
1745
+ }
1746
+ case 'cell_deep_scan': {
1747
+ const { scanCodebase } = require('../code-scanner');
1748
+ const result = scanCodebase(args.dir, args.project || path.basename(args.dir));
1749
+ return { project: result.project, filesScanned: result.filesScanned, totalLines: result.totalLines, profile: result.profile, strengths: result.profile.strengths, improvements: result.profile.improvements };
1750
+ }
1751
+ case 'cell_scan_report': {
1752
+ const { getDeveloperProfile, getCodePatterns } = require('../code-scanner');
1753
+ const profile = getDeveloperProfile(args.project);
1754
+ const patterns = getCodePatterns(args.project);
1755
+ return { project: args.project, profile, patterns, patternCount: patterns.length };
1756
+ }
1757
+ case 'cell_send_signal': {
1758
+ const { logError, logDecision, logContext, logStuck } = require('../behavioral-tracker');
1759
+ const type = args.type;
1760
+ if (type === 'error')
1761
+ return logError({ project: args.project, file: args.file, errorType: 'manual', errorMessage: String(args.editedCode || ''), line: 0 });
1762
+ if (type === 'decision')
1763
+ return logDecision({ project: args.project, file: args.file, decision: String(args.originalCode || ''), approach: String(args.editedCode || ''), worked: true });
1764
+ if (type === 'context')
1765
+ return logContext({ project: args.project, task: String(args.originalCode || ''), files: [] });
1766
+ if (type === 'stuck')
1767
+ return logStuck({ project: args.project, file: args.file, description: String(args.originalCode || '') });
1768
+ return { recorded: true };
1769
+ }
1770
+ case 'cell_get_context': {
1771
+ const { buildContext, formatContextForInjection } = require('../core/prompt-builder');
1772
+ const ctx = buildContext(args.project, args.tool);
1773
+ return { content: [{ type: 'text', text: formatContextForInjection(ctx, false) }], context: ctx };
1774
+ }
1775
+ case 'cell_scan_full_pc': {
1776
+ const { scanFullPC } = require('../pc-scanner');
1777
+ const result = scanFullPC();
1778
+ return { totalProjects: result.totalProjects, totalFiles: result.totalFiles, totalLines: result.totalLines, profile: result.aggregatedProfile };
1779
+ }
1780
+ case 'cell_behavior_summary': {
1781
+ const { getBehaviorSummary } = require('../behavioral-tracker');
1782
+ return getBehaviorSummary(args.project);
1783
+ }
1784
+ case 'cell_log_error': {
1785
+ const { logError } = require('../behavioral-tracker');
1786
+ return logError({ project: args.project, file: args.file, errorType: args.errorType, errorMessage: args.errorMessage, line: args.line });
1787
+ }
1788
+ case 'cell_log_fix': {
1789
+ const { logErrorFix } = require('../behavioral-tracker');
1790
+ logErrorFix({ errorId: args.errorId, fixApplied: args.fixApplied, worked: args.worked, timeToFixMs: args.timeToFixMs });
1791
+ return { recorded: true };
1792
+ }
1793
+ case 'cell_log_decision': {
1794
+ const { logDecision } = require('../behavioral-tracker');
1795
+ return logDecision({ project: args.project, file: args.file, decision: args.decision, approach: args.approach, worked: args.worked });
1796
+ }
1797
+ case 'cell_log_context': {
1798
+ const { logContext } = require('../behavioral-tracker');
1799
+ return logContext({ project: args.project, task: args.task, files: args.files });
1800
+ }
1801
+ case 'cell_log_stuck': {
1802
+ const { logStuck } = require('../behavioral-tracker');
1803
+ return logStuck({ project: args.project, file: args.file, description: args.description });
1804
+ }
1805
+ case 'cell_session_bridge': {
1806
+ const { SessionMemory } = require('../core/session-memory');
1807
+ const memory = new SessionMemory();
1808
+ const project = args.project;
1809
+ const tool = args.tool || 'unknown';
1810
+ try {
1811
+ // Get last session for this project
1812
+ const lastSession = memory.getLastSessionForProject(project);
1813
+ // Start new session for current tool
1814
+ const newSessionId = memory.startSession(tool, project);
1815
+ // If there was a previous session with a different tool, bridge it
1816
+ let bridgeContext = '';
1817
+ if (lastSession && lastSession.toolName !== tool) {
1818
+ const decisions = lastSession.keyDecisions ? JSON.stringify(lastSession.keyDecisions) : 'none';
1819
+ bridgeContext = formatSessionBridge(lastSession.toolName, tool, lastSession.contextSnapshot, decisions);
1820
+ }
1821
+ // Get recent sessions for context chain
1822
+ const recentSessions = memory.getRecentSessions(3).filter((s) => s.project === project);
1823
+ const sessionHistory = recentSessions.map((s) => ({
1824
+ tool: s.toolName,
1825
+ when: s.startTime,
1826
+ files: JSON.parse(String(s.filesTouched || '[]')),
1827
+ decisions: JSON.parse(String(s.keyDecisions || '[]')),
1828
+ }));
1829
+ return {
1830
+ newSessionId,
1831
+ lastSession: lastSession ? {
1832
+ tool: lastSession.toolName,
1833
+ startedAt: lastSession.startTime,
1834
+ context: lastSession.contextSnapshot,
1835
+ } : null,
1836
+ bridgeContext,
1837
+ sessionHistory,
1838
+ message: bridgeContext || 'No previous session to bridge. Start a new session!',
1839
+ };
1840
+ }
1841
+ catch (err) {
1842
+ const msg = err instanceof Error ? err.message : String(err);
1843
+ return { error: `Session bridge failed: ${msg}`, crossedSession: false };
1844
+ }
1845
+ }
1846
+ case 'cell_predict': {
1847
+ const { generatePredictions } = require('../predictive-engine');
1848
+ return generatePredictions(args.project);
1849
+ }
1850
+ default:
1851
+ return { error: `unknown tool: ${name}` };
1852
+ }
1853
+ }
1854
+ app.post('/mcp', async (req, res) => {
1855
+ const rpc = req.body;
1856
+ const { method, params, id } = rpc;
1857
+ try {
1858
+ let result;
1859
+ switch (method) {
1860
+ case 'initialize':
1861
+ result = { protocolVersion: params?.protocolVersion || '2024-11-05', capabilities: { tools: { listChanged: false } }, serverInfo: { name: 'fivo-cell', version: '3.0.0' } };
1862
+ break;
1863
+ case 'notifications/initialized':
1864
+ res.status(204).end();
1865
+ return;
1866
+ case 'ping':
1867
+ result = {};
1868
+ break;
1869
+ case 'tools/list':
1870
+ result = { tools: MCP_TOOLS };
1871
+ break;
1872
+ case 'tools/call':
1873
+ result = await handleMCPToolCall(params?.name || '', params?.arguments || {});
1874
+ break;
1875
+ default:
1876
+ res.status(200).json({ jsonrpc: '2.0', id, error: { code: -32601, message: `Method not found: ${method}` } });
1877
+ return;
1878
+ }
1879
+ res.status(200).json({ jsonrpc: '2.0', id, result });
1880
+ }
1881
+ catch (err) {
1882
+ const message = err instanceof Error ? err.message : String(err);
1883
+ res.status(200).json({ jsonrpc: '2.0', id, error: { code: -1, message } });
1884
+ }
1885
+ });
1302
1886
  app.use((_req, res) => { res.status(404).json({ error: 'not found' }); });
1303
1887
  app.use((err, _req, res, _next) => {
1304
1888
  console.error('Daemon error:', err.message);
1305
1889
  res.status(500).json({ error: 'internal server error' });
1306
1890
  });
1891
+ // ─── Self-Healing ──────────────────────────────────────────────────────
1892
+ process.on('uncaughtException', (err) => {
1893
+ console.error('[cell] Uncaught:', err.message);
1894
+ // Don't exit — keep serving
1895
+ });
1896
+ process.on('unhandledRejection', (reason) => {
1897
+ console.error('[cell] Unhandled rejection:', String(reason));
1898
+ });
1307
1899
  try {
1308
1900
  (0, ai_memory_1.initializeMemory)();
1309
1901
  }
1310
1902
  catch (e) {
1311
1903
  console.error('AI memory init failed:', e);
1312
1904
  }
1313
- app.listen(PORT, () => {
1905
+ // ─── Start with port conflict handling ─────────────────────────────────
1906
+ const server = app.listen(PORT, () => {
1314
1907
  console.log(`Cell Daemon running on http://localhost:${PORT}`);
1315
- console.log(`Modules loaded: ${Object.keys(engines).length}`);
1908
+ console.log(`MCP endpoint: POST http://localhost:${PORT}/mcp`);
1316
1909
  console.log(`Health: http://localhost:${PORT}/health`);
1317
1910
  });
1911
+ server.on('error', (err) => {
1912
+ if (err.code === 'EADDRINUSE') {
1913
+ console.error(`[cell] Port ${PORT} in use. Kill existing daemon first: cell stop`);
1914
+ }
1915
+ else {
1916
+ console.error(`[cell] Server error: ${err.message}`);
1917
+ }
1918
+ });
1919
+ server.on('close', () => {
1920
+ console.log('[cell] Daemon stopped.');
1921
+ });
1922
+ // Graceful shutdown
1923
+ const gracefulShutdown = () => {
1924
+ console.log('[cell] Daemon shutting down...');
1925
+ server.close();
1926
+ process.exit(0);
1927
+ };
1928
+ process.on('SIGTERM', gracefulShutdown);
1929
+ process.on('SIGINT', gracefulShutdown);
1318
1930
  //# sourceMappingURL=server.js.map