fivocell 2.0.0 → 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.
- package/README.md +104 -697
- package/dist/behavioral-tracker.d.ts +90 -0
- package/dist/behavioral-tracker.d.ts.map +1 -0
- package/dist/behavioral-tracker.js +185 -0
- package/dist/behavioral-tracker.js.map +1 -0
- package/dist/cli.d.ts +1 -6
- package/dist/cli.d.ts.map +1 -1
- package/dist/cli.js +430 -3862
- package/dist/cli.js.map +1 -1
- package/dist/code-scanner.d.ts +51 -0
- package/dist/code-scanner.d.ts.map +1 -0
- package/dist/code-scanner.js +966 -0
- package/dist/code-scanner.js.map +1 -0
- package/dist/community-intel.d.ts +34 -0
- package/dist/community-intel.d.ts.map +1 -0
- package/dist/community-intel.js +148 -0
- package/dist/community-intel.js.map +1 -0
- package/dist/daemon/lifecycle.d.ts +0 -15
- package/dist/daemon/lifecycle.d.ts.map +1 -1
- package/dist/daemon/lifecycle.js +88 -231
- package/dist/daemon/lifecycle.js.map +1 -1
- package/dist/daemon/server.d.ts.map +1 -1
- package/dist/daemon/server.js +368 -19
- package/dist/daemon/server.js.map +1 -1
- package/dist/developer-intelligence.d.ts +18 -0
- package/dist/developer-intelligence.d.ts.map +1 -0
- package/dist/developer-intelligence.js +180 -0
- package/dist/developer-intelligence.js.map +1 -0
- package/dist/layers.d.ts +92 -0
- package/dist/layers.d.ts.map +1 -0
- package/dist/layers.js +226 -0
- package/dist/layers.js.map +1 -0
- package/dist/mcp-server.d.ts +194 -1842
- package/dist/mcp-server.d.ts.map +1 -1
- package/dist/mcp-server.js +169 -875
- package/dist/mcp-server.js.map +1 -1
- package/dist/pc-scanner.d.ts +46 -0
- package/dist/pc-scanner.d.ts.map +1 -0
- package/dist/pc-scanner.js +488 -0
- package/dist/pc-scanner.js.map +1 -0
- package/dist/predictive-engine.d.ts +19 -0
- package/dist/predictive-engine.d.ts.map +1 -0
- package/dist/predictive-engine.js +107 -0
- package/dist/predictive-engine.js.map +1 -0
- package/dist/style-pull.d.ts +1 -1
- package/dist/style-pull.js +2 -2
- package/dist/team-git.d.ts +47 -0
- package/dist/team-git.d.ts.map +1 -0
- package/dist/team-git.js +305 -0
- package/dist/team-git.js.map +1 -0
- package/package.json +1 -1
package/dist/daemon/server.js
CHANGED
|
@@ -204,16 +204,104 @@ app.get('/health', (_req, res) => {
|
|
|
204
204
|
});
|
|
205
205
|
});
|
|
206
206
|
app.post('/signal', (req, res) => {
|
|
207
|
-
const { type, originalCode, editedCode, context } = req.body;
|
|
208
|
-
if (!type
|
|
209
|
-
res.status(400).json({ error: 'type
|
|
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
210
|
return;
|
|
211
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 });
|
|
285
|
+
return;
|
|
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 || {};
|
|
212
300
|
let signal;
|
|
213
301
|
let patternsExtracted = 0;
|
|
214
302
|
switch (type) {
|
|
215
303
|
case 'edit_diff': {
|
|
216
|
-
signal = engines.signalCapture.captureEditDiff(originalCode || '', editedCode || '',
|
|
304
|
+
signal = engines.signalCapture.captureEditDiff(originalCode || '', editedCode || '', ctx);
|
|
217
305
|
try {
|
|
218
306
|
const result = engines.extractionCascade.extract(originalCode || '', editedCode || '');
|
|
219
307
|
patternsExtracted = engines.learningLayer.process(result, true);
|
|
@@ -226,35 +314,28 @@ app.post('/signal', (req, res) => {
|
|
|
226
314
|
break;
|
|
227
315
|
}
|
|
228
316
|
case 'accept': {
|
|
229
|
-
signal = engines.signalCapture.captureAccept(originalCode || '',
|
|
317
|
+
signal = engines.signalCapture.captureAccept(originalCode || '', ctx);
|
|
230
318
|
const dummy = engines.patternStore.getAllPatterns().slice(0, 1);
|
|
231
319
|
for (const p of dummy) {
|
|
232
320
|
const step = (0, workflow_tracker_1.recordStep)(p, 'accept');
|
|
233
321
|
(0, outcome_recorder_1.recordOutcome)(p, 'accept', step.sessionId, true, 0);
|
|
234
|
-
(0, failure_memory_1.recordFailure)(p, false,
|
|
235
|
-
(0, time_saved_1.recordTimeSaved)({
|
|
236
|
-
patternId: p.patternId,
|
|
237
|
-
category: p.category,
|
|
238
|
-
description: p.description,
|
|
239
|
-
from: p.from,
|
|
240
|
-
to: p.to,
|
|
241
|
-
language: context?.language || 'unknown',
|
|
242
|
-
});
|
|
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' });
|
|
243
324
|
}
|
|
244
325
|
break;
|
|
245
326
|
}
|
|
246
327
|
case 'reject': {
|
|
247
|
-
signal = engines.signalCapture.captureReject(originalCode || '',
|
|
328
|
+
signal = engines.signalCapture.captureReject(originalCode || '', ctx);
|
|
248
329
|
const dummyR = engines.patternStore.getAllPatterns().slice(0, 1);
|
|
249
330
|
for (const p of dummyR) {
|
|
250
331
|
const step = (0, workflow_tracker_1.recordStep)(p, 'reject');
|
|
251
332
|
(0, outcome_recorder_1.recordOutcome)(p, 'reject', step.sessionId, false, 0);
|
|
252
|
-
(0, failure_memory_1.recordFailure)(p, true,
|
|
333
|
+
(0, failure_memory_1.recordFailure)(p, true, ctx.language || 'unknown');
|
|
253
334
|
}
|
|
254
335
|
break;
|
|
255
336
|
}
|
|
256
337
|
case 'retry': {
|
|
257
|
-
signal = engines.signalCapture.captureRetry(originalCode || '',
|
|
338
|
+
signal = engines.signalCapture.captureRetry(originalCode || '', ctx);
|
|
258
339
|
const dummyRt = engines.patternStore.getAllPatterns().slice(0, 1);
|
|
259
340
|
for (const p of dummyRt) {
|
|
260
341
|
const step = (0, workflow_tracker_1.recordStep)(p, 'retry');
|
|
@@ -1562,20 +1643,288 @@ app.post('/cloud/push', (req, res) => {
|
|
|
1562
1643
|
pushToCloud(req.body?.data || {}, req.body?.type || 'pattern').then(r => res.json(r));
|
|
1563
1644
|
}).catch(e => res.status(500).json({ error: String(e) }));
|
|
1564
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
|
+
});
|
|
1565
1886
|
app.use((_req, res) => { res.status(404).json({ error: 'not found' }); });
|
|
1566
1887
|
app.use((err, _req, res, _next) => {
|
|
1567
1888
|
console.error('Daemon error:', err.message);
|
|
1568
1889
|
res.status(500).json({ error: 'internal server error' });
|
|
1569
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
|
+
});
|
|
1570
1899
|
try {
|
|
1571
1900
|
(0, ai_memory_1.initializeMemory)();
|
|
1572
1901
|
}
|
|
1573
1902
|
catch (e) {
|
|
1574
1903
|
console.error('AI memory init failed:', e);
|
|
1575
1904
|
}
|
|
1576
|
-
|
|
1905
|
+
// ─── Start with port conflict handling ─────────────────────────────────
|
|
1906
|
+
const server = app.listen(PORT, () => {
|
|
1577
1907
|
console.log(`Cell Daemon running on http://localhost:${PORT}`);
|
|
1578
|
-
console.log(`
|
|
1908
|
+
console.log(`MCP endpoint: POST http://localhost:${PORT}/mcp`);
|
|
1579
1909
|
console.log(`Health: http://localhost:${PORT}/health`);
|
|
1580
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);
|
|
1581
1930
|
//# sourceMappingURL=server.js.map
|