fivocell 3.1.0 → 4.1.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/dist/__tests__/behavior-intelligence-bug.test.d.ts +2 -0
- package/dist/__tests__/behavior-intelligence-bug.test.d.ts.map +1 -0
- package/dist/__tests__/behavior-intelligence-bug.test.js +21 -0
- package/dist/__tests__/behavior-intelligence-bug.test.js.map +1 -0
- package/dist/__tests__/code-scanner-arrow-return-type.test.d.ts +2 -0
- package/dist/__tests__/code-scanner-arrow-return-type.test.d.ts.map +1 -0
- package/dist/__tests__/code-scanner-arrow-return-type.test.js +76 -0
- package/dist/__tests__/code-scanner-arrow-return-type.test.js.map +1 -0
- package/dist/__tests__/code-scanner-blindspot.test.d.ts +2 -0
- package/dist/__tests__/code-scanner-blindspot.test.d.ts.map +1 -0
- package/dist/__tests__/code-scanner-blindspot.test.js +18 -0
- package/dist/__tests__/code-scanner-blindspot.test.js.map +1 -0
- package/dist/__tests__/code-scanner-error-recovery.test.d.ts +2 -0
- package/dist/__tests__/code-scanner-error-recovery.test.d.ts.map +1 -0
- package/dist/__tests__/code-scanner-error-recovery.test.js +21 -0
- package/dist/__tests__/code-scanner-error-recovery.test.js.map +1 -0
- package/dist/__tests__/code-scanner-n1-detection.test.d.ts +2 -0
- package/dist/__tests__/code-scanner-n1-detection.test.d.ts.map +1 -0
- package/dist/__tests__/code-scanner-n1-detection.test.js +113 -0
- package/dist/__tests__/code-scanner-n1-detection.test.js.map +1 -0
- package/dist/__tests__/code-scanner-nesting.test.d.ts +2 -0
- package/dist/__tests__/code-scanner-nesting.test.d.ts.map +1 -0
- package/dist/__tests__/code-scanner-nesting.test.js +113 -0
- package/dist/__tests__/code-scanner-nesting.test.js.map +1 -0
- package/dist/__tests__/code-scanner-null-check.test.d.ts +2 -0
- package/dist/__tests__/code-scanner-null-check.test.d.ts.map +1 -0
- package/dist/__tests__/code-scanner-null-check.test.js +126 -0
- package/dist/__tests__/code-scanner-null-check.test.js.map +1 -0
- package/dist/__tests__/code-scanner-sql-fix.test.d.ts +2 -0
- package/dist/__tests__/code-scanner-sql-fix.test.d.ts.map +1 -0
- package/dist/__tests__/code-scanner-sql-fix.test.js +21 -0
- package/dist/__tests__/code-scanner-sql-fix.test.js.map +1 -0
- package/dist/__tests__/code-scanner-trust-score.test.d.ts +1 -0
- package/dist/__tests__/code-scanner-trust-score.test.d.ts.map +1 -0
- package/dist/__tests__/code-scanner-trust-score.test.js +39 -0
- package/dist/__tests__/code-scanner-trust-score.test.js.map +1 -0
- package/dist/__tests__/code-scanner-validation.test.d.ts +2 -0
- package/dist/__tests__/code-scanner-validation.test.d.ts.map +1 -0
- package/dist/__tests__/code-scanner-validation.test.js +131 -0
- package/dist/__tests__/code-scanner-validation.test.js.map +1 -0
- package/dist/__tests__/community-store.test.d.ts +2 -0
- package/dist/__tests__/community-store.test.d.ts.map +1 -0
- package/dist/__tests__/community-store.test.js +231 -0
- package/dist/__tests__/community-store.test.js.map +1 -0
- package/dist/__tests__/enhanced-blind-spots.test.d.ts +2 -0
- package/dist/__tests__/enhanced-blind-spots.test.d.ts.map +1 -0
- package/dist/__tests__/enhanced-blind-spots.test.js +302 -0
- package/dist/__tests__/enhanced-blind-spots.test.js.map +1 -0
- package/dist/__tests__/knowledge-graph-store.test.d.ts +2 -0
- package/dist/__tests__/knowledge-graph-store.test.d.ts.map +1 -0
- package/dist/__tests__/knowledge-graph-store.test.js +252 -0
- package/dist/__tests__/knowledge-graph-store.test.js.map +1 -0
- package/dist/__tests__/live-watcher.test.d.ts +2 -0
- package/dist/__tests__/live-watcher.test.d.ts.map +1 -0
- package/dist/__tests__/live-watcher.test.js +312 -0
- package/dist/__tests__/live-watcher.test.js.map +1 -0
- package/dist/__tests__/mcp-cell-tools.test.d.ts +2 -0
- package/dist/__tests__/mcp-cell-tools.test.d.ts.map +1 -0
- package/dist/__tests__/mcp-cell-tools.test.js +176 -0
- package/dist/__tests__/mcp-cell-tools.test.js.map +1 -0
- package/dist/__tests__/multi-project.test.d.ts +2 -0
- package/dist/__tests__/multi-project.test.d.ts.map +1 -0
- package/dist/__tests__/multi-project.test.js +145 -0
- package/dist/__tests__/multi-project.test.js.map +1 -0
- package/dist/__tests__/pc-scanner-paths.test.d.ts +2 -0
- package/dist/__tests__/pc-scanner-paths.test.d.ts.map +1 -0
- package/dist/__tests__/pc-scanner-paths.test.js +16 -0
- package/dist/__tests__/pc-scanner-paths.test.js.map +1 -0
- package/dist/__tests__/prompt-builder-realdata.test.d.ts +2 -0
- package/dist/__tests__/prompt-builder-realdata.test.d.ts.map +1 -0
- package/dist/__tests__/prompt-builder-realdata.test.js +94 -0
- package/dist/__tests__/prompt-builder-realdata.test.js.map +1 -0
- package/dist/__tests__/prompt-builder-sessions.test.d.ts +2 -0
- package/dist/__tests__/prompt-builder-sessions.test.d.ts.map +1 -0
- package/dist/__tests__/prompt-builder-sessions.test.js +124 -0
- package/dist/__tests__/prompt-builder-sessions.test.js.map +1 -0
- package/dist/__tests__/security.test.d.ts +1 -0
- package/dist/__tests__/security.test.d.ts.map +1 -0
- package/dist/__tests__/security.test.js +161 -0
- package/dist/__tests__/security.test.js.map +1 -0
- package/dist/__tests__/session-bridge.test.d.ts +2 -0
- package/dist/__tests__/session-bridge.test.d.ts.map +1 -0
- package/dist/__tests__/session-bridge.test.js +158 -0
- package/dist/__tests__/session-bridge.test.js.map +1 -0
- package/dist/__tests__/session-memory-tables.test.d.ts +2 -0
- package/dist/__tests__/session-memory-tables.test.d.ts.map +1 -0
- package/dist/__tests__/session-memory-tables.test.js +169 -0
- package/dist/__tests__/session-memory-tables.test.js.map +1 -0
- package/dist/__tests__/staleness-detection.test.d.ts +2 -0
- package/dist/__tests__/staleness-detection.test.d.ts.map +1 -0
- package/dist/__tests__/staleness-detection.test.js +105 -0
- package/dist/__tests__/staleness-detection.test.js.map +1 -0
- package/dist/__tests__/team-collaboration.test.d.ts +2 -0
- package/dist/__tests__/team-collaboration.test.d.ts.map +1 -0
- package/dist/__tests__/team-collaboration.test.js +224 -0
- package/dist/__tests__/team-collaboration.test.js.map +1 -0
- package/dist/__tests__/tool-specific-format.test.d.ts +2 -0
- package/dist/__tests__/tool-specific-format.test.d.ts.map +1 -0
- package/dist/__tests__/tool-specific-format.test.js +132 -0
- package/dist/__tests__/tool-specific-format.test.js.map +1 -0
- package/dist/__tests__/usage-intelligence-store.test.d.ts +2 -0
- package/dist/__tests__/usage-intelligence-store.test.d.ts.map +1 -0
- package/dist/__tests__/usage-intelligence-store.test.js +266 -0
- package/dist/__tests__/usage-intelligence-store.test.js.map +1 -0
- package/dist/ai-bridge.d.ts +20 -0
- package/dist/ai-bridge.d.ts.map +1 -0
- package/dist/ai-bridge.js +250 -0
- package/dist/ai-bridge.js.map +1 -0
- package/dist/behavior-intelligence.d.ts.map +1 -1
- package/dist/behavior-intelligence.js +12 -1
- package/dist/behavior-intelligence.js.map +1 -1
- package/dist/cli.js +501 -4
- package/dist/cli.js.map +1 -1
- package/dist/code-scanner.d.ts.map +1 -1
- package/dist/code-scanner.js +426 -69
- package/dist/code-scanner.js.map +1 -1
- package/dist/core/community-store.d.ts +128 -0
- package/dist/core/community-store.d.ts.map +1 -0
- package/dist/core/community-store.js +329 -0
- package/dist/core/community-store.js.map +1 -0
- package/dist/core/database.d.ts +0 -3
- package/dist/core/database.d.ts.map +1 -1
- package/dist/core/database.js +287 -15
- package/dist/core/database.js.map +1 -1
- package/dist/core/enhanced-blind-spots.d.ts +27 -0
- package/dist/core/enhanced-blind-spots.d.ts.map +1 -0
- package/dist/core/enhanced-blind-spots.js +591 -0
- package/dist/core/enhanced-blind-spots.js.map +1 -0
- package/dist/core/knowledge-graph-store.d.ts +69 -0
- package/dist/core/knowledge-graph-store.d.ts.map +1 -0
- package/dist/core/knowledge-graph-store.js +269 -0
- package/dist/core/knowledge-graph-store.js.map +1 -0
- package/dist/core/live-watcher.d.ts +52 -0
- package/dist/core/live-watcher.d.ts.map +1 -0
- package/dist/core/live-watcher.js +369 -0
- package/dist/core/live-watcher.js.map +1 -0
- package/dist/core/project-registry.d.ts +24 -0
- package/dist/core/project-registry.d.ts.map +1 -0
- package/dist/core/project-registry.js +70 -0
- package/dist/core/project-registry.js.map +1 -0
- package/dist/core/prompt-builder.d.ts +50 -0
- package/dist/core/prompt-builder.d.ts.map +1 -1
- package/dist/core/prompt-builder.js +533 -79
- package/dist/core/prompt-builder.js.map +1 -1
- package/dist/core/security.d.ts +23 -0
- package/dist/core/security.d.ts.map +1 -0
- package/dist/core/security.js +117 -0
- package/dist/core/security.js.map +1 -0
- package/dist/core/session-memory.d.ts +64 -0
- package/dist/core/session-memory.d.ts.map +1 -1
- package/dist/core/session-memory.js +111 -0
- package/dist/core/session-memory.js.map +1 -1
- package/dist/core/usage-intelligence-store.d.ts +126 -0
- package/dist/core/usage-intelligence-store.d.ts.map +1 -0
- package/dist/core/usage-intelligence-store.js +405 -0
- package/dist/core/usage-intelligence-store.js.map +1 -0
- package/dist/daemon/server.d.ts.map +1 -1
- package/dist/daemon/server.js +936 -17
- package/dist/daemon/server.js.map +1 -1
- package/dist/knowledge-graph-builder.d.ts +16 -0
- package/dist/knowledge-graph-builder.d.ts.map +1 -0
- package/dist/knowledge-graph-builder.js +186 -0
- package/dist/knowledge-graph-builder.js.map +1 -0
- package/dist/pc-scanner.d.ts +1 -0
- package/dist/pc-scanner.d.ts.map +1 -1
- package/dist/pc-scanner.js +58 -30
- package/dist/pc-scanner.js.map +1 -1
- package/dist/stack-detector.d.ts +34 -0
- package/dist/stack-detector.d.ts.map +1 -0
- package/dist/stack-detector.js +471 -0
- package/dist/stack-detector.js.map +1 -0
- package/dist/team-intel.d.ts +31 -0
- package/dist/team-intel.d.ts.map +1 -0
- package/dist/team-intel.js +310 -0
- package/dist/team-intel.js.map +1 -0
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -55,7 +55,36 @@ const C = {
|
|
|
55
55
|
};
|
|
56
56
|
const project = path.basename(process.cwd());
|
|
57
57
|
// ─── Parse ──────────────────────────────────────────────────────────────────
|
|
58
|
-
|
|
58
|
+
// Parse args, treating double-quoted values as single tokens (so paths with spaces survive).
|
|
59
|
+
function parseArgs(argv) {
|
|
60
|
+
const out = [];
|
|
61
|
+
let buf = '';
|
|
62
|
+
let inQuote = false;
|
|
63
|
+
for (const a of argv) {
|
|
64
|
+
if (inQuote) {
|
|
65
|
+
buf += ' ' + a;
|
|
66
|
+
if (a.endsWith('"')) {
|
|
67
|
+
out.push(buf.slice(0, -1));
|
|
68
|
+
buf = '';
|
|
69
|
+
inQuote = false;
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
else if (a.startsWith('"') && !a.endsWith('"')) {
|
|
73
|
+
buf = a.slice(1);
|
|
74
|
+
inQuote = true;
|
|
75
|
+
}
|
|
76
|
+
else if (a.startsWith('"') && a.endsWith('"') && a.length > 1) {
|
|
77
|
+
out.push(a.slice(1, -1));
|
|
78
|
+
}
|
|
79
|
+
else {
|
|
80
|
+
out.push(a);
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
if (buf)
|
|
84
|
+
out.push(buf);
|
|
85
|
+
return out;
|
|
86
|
+
}
|
|
87
|
+
const args = parseArgs(process.argv.slice(2));
|
|
59
88
|
const cmd = args[0] || '';
|
|
60
89
|
switch (cmd) {
|
|
61
90
|
case 'start':
|
|
@@ -67,6 +96,9 @@ switch (cmd) {
|
|
|
67
96
|
case 'scan':
|
|
68
97
|
doScan();
|
|
69
98
|
break;
|
|
99
|
+
case 'analyze':
|
|
100
|
+
doAnalyze();
|
|
101
|
+
break;
|
|
70
102
|
case 'status':
|
|
71
103
|
doStatus();
|
|
72
104
|
break;
|
|
@@ -76,6 +108,12 @@ switch (cmd) {
|
|
|
76
108
|
case 'community':
|
|
77
109
|
doCommunity();
|
|
78
110
|
break;
|
|
111
|
+
case 'watch':
|
|
112
|
+
doWatch();
|
|
113
|
+
break;
|
|
114
|
+
case 'blindspots':
|
|
115
|
+
doBlindspots();
|
|
116
|
+
break;
|
|
79
117
|
case 'help':
|
|
80
118
|
doHelp();
|
|
81
119
|
break;
|
|
@@ -157,6 +195,82 @@ function doStop() {
|
|
|
157
195
|
}
|
|
158
196
|
console.log();
|
|
159
197
|
}
|
|
198
|
+
// ─── cell analyze ───────────────────────────────────────────────────────────
|
|
199
|
+
function doAnalyze() {
|
|
200
|
+
console.log();
|
|
201
|
+
console.log(C.bold(' Cell AI Analysis'));
|
|
202
|
+
console.log(C.dim(' ────────────────'));
|
|
203
|
+
console.log();
|
|
204
|
+
const sub = args[1] || '';
|
|
205
|
+
// ─── Save AI-generated insights ────────────────────────────────────
|
|
206
|
+
if (sub === '--save' && args[2]) {
|
|
207
|
+
const category = args[2];
|
|
208
|
+
console.log(C.primary(` Save AI insights for: ${category}`));
|
|
209
|
+
console.log(C.dim(' Paste the AI-generated response below (Ctrl+Z or Ctrl+D to finish):'));
|
|
210
|
+
console.log();
|
|
211
|
+
// Read from stdin
|
|
212
|
+
const chunks = [];
|
|
213
|
+
process.stdin.on('data', (chunk) => chunks.push(chunk));
|
|
214
|
+
process.stdin.on('end', () => {
|
|
215
|
+
const content = Buffer.concat(chunks).toString().trim();
|
|
216
|
+
if (content) {
|
|
217
|
+
const { saveAIInsight } = require('./ai-bridge');
|
|
218
|
+
saveAIInsight(project, category, content);
|
|
219
|
+
console.log(C.success(` Insights saved: ${category}`));
|
|
220
|
+
console.log(C.dim(` .cell/personal/insights/${category}.md`));
|
|
221
|
+
console.log();
|
|
222
|
+
process.exit(0);
|
|
223
|
+
}
|
|
224
|
+
else {
|
|
225
|
+
console.log(C.warn(' No content provided.'));
|
|
226
|
+
console.log();
|
|
227
|
+
process.exit(1);
|
|
228
|
+
}
|
|
229
|
+
});
|
|
230
|
+
process.stdin.resume();
|
|
231
|
+
return;
|
|
232
|
+
}
|
|
233
|
+
// ─── Show insights ─────────────────────────────────────────────────
|
|
234
|
+
if (sub === '--show') {
|
|
235
|
+
const { getAIInsights } = require('./ai-bridge');
|
|
236
|
+
const insights = getAIInsights(project);
|
|
237
|
+
if (insights.length === 0) {
|
|
238
|
+
console.log(C.dim(' No AI insights yet. Run: cell analyze'));
|
|
239
|
+
console.log();
|
|
240
|
+
return;
|
|
241
|
+
}
|
|
242
|
+
for (const i of insights) {
|
|
243
|
+
console.log(C.bold(` ${i.category}`));
|
|
244
|
+
console.log(C.dim(` ${i.timestamp} | Source: ${i.source}`));
|
|
245
|
+
console.log(i.content.substring(0, 300));
|
|
246
|
+
console.log(C.dim(' ...'));
|
|
247
|
+
console.log();
|
|
248
|
+
}
|
|
249
|
+
return;
|
|
250
|
+
}
|
|
251
|
+
// ─── Default: Generate prompts ─────────────────────────────────────
|
|
252
|
+
const { getAnalysisCommand } = require('./ai-bridge');
|
|
253
|
+
const { intro, prompts } = getAnalysisCommand(process.cwd());
|
|
254
|
+
console.log(C.dim(intro));
|
|
255
|
+
console.log();
|
|
256
|
+
for (const p of prompts) {
|
|
257
|
+
console.log(C.bold(` ━━━ ${p.title} ━━━`));
|
|
258
|
+
console.log(C.dim(` Tokens: ~${p.tokensEstimate} | Category: ${p.category}`));
|
|
259
|
+
console.log();
|
|
260
|
+
const promptLines = p.prompt.split('\n');
|
|
261
|
+
for (const line of promptLines.slice(0, 10)) {
|
|
262
|
+
console.log(` ${C.dim('│')} ${line}`);
|
|
263
|
+
}
|
|
264
|
+
if (promptLines.length > 10) {
|
|
265
|
+
console.log(` ${C.dim('│')} ... (${promptLines.length - 10} more lines)`);
|
|
266
|
+
}
|
|
267
|
+
console.log();
|
|
268
|
+
console.log(C.primary(` → Copy to AI tool, get answer, then: cell analyze --save ${p.category}`));
|
|
269
|
+
console.log();
|
|
270
|
+
}
|
|
271
|
+
console.log(C.dim(' cell analyze --show View saved insights'));
|
|
272
|
+
console.log();
|
|
273
|
+
}
|
|
160
274
|
// ─── cell scan ───────────────────────────────────────────────────────────────
|
|
161
275
|
function doScan() {
|
|
162
276
|
const banner = figlet_1.default.textSync('CELL', { font: 'ANSI Shadow', horizontalLayout: 'fitted' });
|
|
@@ -222,9 +336,25 @@ function showProjectStatus() {
|
|
|
222
336
|
console.log();
|
|
223
337
|
console.log(C.bold(' 📂 Personal Layer'));
|
|
224
338
|
console.log(C.dim(' ─────────────────'));
|
|
225
|
-
|
|
339
|
+
// Stack fingerprint (from stack-detector)
|
|
340
|
+
try {
|
|
341
|
+
const { detectProjectDNA } = require('./stack-detector');
|
|
342
|
+
const dna = detectProjectDNA(process.cwd());
|
|
343
|
+
if (dna && dna.stack.trustScore > 0) {
|
|
344
|
+
const s = dna.stack;
|
|
345
|
+
console.log(` Stack: ${C.num(s.languages?.join(', ') || '')} · ${s.frontend !== 'none' ? s.frontend + ' + ' : ''}${s.backend}${s.database[0] !== 'none' ? ' · ' + s.database.join(', ') : ''}`);
|
|
346
|
+
console.log(` ${s.orm !== 'none' ? 'ORM: ' + s.orm + ' · ' : ''}Test: ${s.testing.join(', ')}${s.validation !== 'none' ? ' · Validation: ' + s.validation : ''}`);
|
|
347
|
+
console.log(` Arch: ${dna.architecture.type} (${dna.architecture.confidence}), Entry: ${dna.architecture.entryPoints.join(', ')}`);
|
|
348
|
+
console.log(` Style: ${C.num(profile.quoteStyle)} quotes, ${C.num(profile.semicolonStyle)} semis, ${C.num(profile.indentStyle)}`);
|
|
349
|
+
}
|
|
350
|
+
else {
|
|
351
|
+
console.log(` Style: ${C.num(profile.quoteStyle)} quotes, ${C.num(profile.semicolonStyle)} semis, ${C.num(profile.indentStyle)}`);
|
|
352
|
+
}
|
|
353
|
+
}
|
|
354
|
+
catch {
|
|
355
|
+
console.log(` Style: ${C.num(profile.quoteStyle)} quotes, ${C.num(profile.semicolonStyle)} semis, ${C.num(profile.indentStyle)}`);
|
|
356
|
+
}
|
|
226
357
|
console.log(` Code: ${C.num(profile.functionStyle)} functions, ${C.num(profile.asyncStyle)}, ${C.num(profile.errorHandling)} errors`);
|
|
227
|
-
console.log(` Arch: ${C.num(profile.architectureStyle)}, ${C.num(profile.testPattern)} tests`);
|
|
228
358
|
if (profile.strengths.length) {
|
|
229
359
|
for (const s of profile.strengths)
|
|
230
360
|
console.log(` ${C.success('+')} ${s}`);
|
|
@@ -392,6 +522,22 @@ function doTeam() {
|
|
|
392
522
|
console.log();
|
|
393
523
|
return;
|
|
394
524
|
}
|
|
525
|
+
// ─── team onboard ───────────────────────────────────────────────────
|
|
526
|
+
if (sub === 'onboard' && args[2]) {
|
|
527
|
+
const newMember = args[2];
|
|
528
|
+
const teamPath = path.join(process.cwd(), '.cell', 'team');
|
|
529
|
+
console.log(C.primary(` Generating onboarding guide for ${newMember}...`));
|
|
530
|
+
const { generateOnboardingGuide, formatOnboardingText } = require('./team-intel');
|
|
531
|
+
const guide = generateOnboardingGuide(teamPath, newMember);
|
|
532
|
+
if (guide) {
|
|
533
|
+
console.log(formatOnboardingText(guide));
|
|
534
|
+
}
|
|
535
|
+
else {
|
|
536
|
+
console.log(C.warn(' No team data found. Run: cell team push <your-name> first.'));
|
|
537
|
+
}
|
|
538
|
+
console.log();
|
|
539
|
+
return;
|
|
540
|
+
}
|
|
395
541
|
// ─── team status ────────────────────────────────────────────────────
|
|
396
542
|
if (sub === 'status') {
|
|
397
543
|
const { teamStatus } = require('./team-git');
|
|
@@ -432,11 +578,191 @@ function doTeam() {
|
|
|
432
578
|
console.log(C.success(` + Strongest: ${intel.summary.strongestArea}`));
|
|
433
579
|
if (intel.summary.weakestArea)
|
|
434
580
|
console.log(C.warn(` ! Weakest: ${intel.summary.weakestArea}`));
|
|
581
|
+
// Team pattern library
|
|
582
|
+
const teamPath = path.join(process.cwd(), '.cell', 'team');
|
|
583
|
+
try {
|
|
584
|
+
const { buildTeamPatternLibrary } = require('./team-intel');
|
|
585
|
+
const rules = buildTeamPatternLibrary(teamPath);
|
|
586
|
+
if (rules.length > 0) {
|
|
587
|
+
console.log(C.bold(' 📋 Pattern Library:'));
|
|
588
|
+
const doRules = rules.filter((r) => r.type === 'do').slice(0, 3);
|
|
589
|
+
const dontRules = rules.filter((r) => r.type === 'dont').slice(0, 2);
|
|
590
|
+
for (const r of doRules) {
|
|
591
|
+
console.log(` ${C.success('✓')} ${r.rule} (${r.agreement}% agreement)`);
|
|
592
|
+
}
|
|
593
|
+
for (const r of dontRules) {
|
|
594
|
+
console.log(` ${C.warn('✗')} ${r.rule}`);
|
|
595
|
+
}
|
|
596
|
+
}
|
|
597
|
+
}
|
|
598
|
+
catch { }
|
|
435
599
|
if (intel.summary.criticalBlindSpots > 0)
|
|
436
600
|
console.log(C.warn(` ! ${intel.summary.criticalBlindSpots} critical blind spots`));
|
|
437
601
|
console.log();
|
|
438
602
|
return;
|
|
439
603
|
}
|
|
604
|
+
// ─── team silos ─────────────────────────────────────────────────────
|
|
605
|
+
if (sub === 'silos') {
|
|
606
|
+
const { detectKnowledgeSilos } = require('./team-collaboration');
|
|
607
|
+
const silos = detectKnowledgeSilos();
|
|
608
|
+
console.log(C.bold(` Knowledge Silos: ${silos.length}`));
|
|
609
|
+
console.log();
|
|
610
|
+
if (silos.length === 0) {
|
|
611
|
+
console.log(C.dim(' No silos detected. Knowledge is well distributed.'));
|
|
612
|
+
}
|
|
613
|
+
else {
|
|
614
|
+
for (const s of silos.slice(0, 10)) {
|
|
615
|
+
const riskColor = s.riskLevel === 'high' ? C.warn : s.riskLevel === 'medium' ? C.primary : C.dim;
|
|
616
|
+
console.log(` ${riskColor('●')} ${s.name} — ${s.knowledgeArea}`);
|
|
617
|
+
console.log(C.dim(` ${s.members.join(', ')} (bus factor: ${s.busFactor})`));
|
|
618
|
+
}
|
|
619
|
+
}
|
|
620
|
+
console.log();
|
|
621
|
+
return;
|
|
622
|
+
}
|
|
623
|
+
// ─── team bus-factor ───────────────────────────────────────────────
|
|
624
|
+
if (sub === 'bus-factor') {
|
|
625
|
+
const { calculateBusFactor } = require('./team-collaboration');
|
|
626
|
+
const report = calculateBusFactor();
|
|
627
|
+
console.log(C.bold(` Bus Factor: ${report.overallScore}/100`));
|
|
628
|
+
console.log();
|
|
629
|
+
if (report.singlePointsOfFailure.length > 0) {
|
|
630
|
+
console.log(C.warn(' Single Points of Failure:'));
|
|
631
|
+
for (const spof of report.singlePointsOfFailure.slice(0, 5)) {
|
|
632
|
+
console.log(C.warn(` ⚠ ${spof}`));
|
|
633
|
+
}
|
|
634
|
+
console.log();
|
|
635
|
+
}
|
|
636
|
+
if (report.members.length > 0) {
|
|
637
|
+
console.log(C.dim(' Top members:'));
|
|
638
|
+
for (const m of report.members.slice(0, 5)) {
|
|
639
|
+
console.log(` ${m.name}: score ${m.score} (${m.risk} risk)`);
|
|
640
|
+
}
|
|
641
|
+
}
|
|
642
|
+
console.log();
|
|
643
|
+
return;
|
|
644
|
+
}
|
|
645
|
+
// ─── team health ───────────────────────────────────────────────────
|
|
646
|
+
if (sub === 'health') {
|
|
647
|
+
const { getTeamHealth } = require('./team-collaboration');
|
|
648
|
+
const health = getTeamHealth(args[2]);
|
|
649
|
+
console.log(C.bold(` Team Health: ${health.score}/100`));
|
|
650
|
+
console.log();
|
|
651
|
+
console.log(C.dim(` Bus factor: ${health.busFactor}, Silos: ${health.siloCount}, Edges: ${health.collaborationEdges}`));
|
|
652
|
+
if (health.strengths.length > 0) {
|
|
653
|
+
console.log(C.success(' Strengths:'));
|
|
654
|
+
for (const s of health.strengths.slice(0, 3))
|
|
655
|
+
console.log(C.success(` + ${s}`));
|
|
656
|
+
}
|
|
657
|
+
if (health.skillGaps.length > 0) {
|
|
658
|
+
console.log(C.warn(' Skill gaps:'));
|
|
659
|
+
for (const g of health.skillGaps.slice(0, 3))
|
|
660
|
+
console.log(C.warn(` ! ${g}`));
|
|
661
|
+
}
|
|
662
|
+
if (health.recommendations.length > 0) {
|
|
663
|
+
console.log(C.primary(' Recommendations:'));
|
|
664
|
+
for (const r of health.recommendations.slice(0, 3))
|
|
665
|
+
console.log(` → ${r}`);
|
|
666
|
+
}
|
|
667
|
+
console.log();
|
|
668
|
+
return;
|
|
669
|
+
}
|
|
670
|
+
// ─── community sub-commands ─────────────────────────────────────────
|
|
671
|
+
if (sub === 'community' || sub === 'comm') {
|
|
672
|
+
const csub = args[2];
|
|
673
|
+
if (csub === 'stats') {
|
|
674
|
+
const { getCommunityStats } = require('./core/community-store');
|
|
675
|
+
const stats = getCommunityStats();
|
|
676
|
+
console.log(C.bold(' Community Stats'));
|
|
677
|
+
console.log(C.dim(` Patterns: ${stats.totalPatterns}, Insights: ${stats.totalInsights}, Benchmarks: ${stats.totalBenchmarks}`));
|
|
678
|
+
console.log(C.dim(` Total votes: ${stats.totalVotes}`));
|
|
679
|
+
if (Object.keys(stats.byCategory).length > 0) {
|
|
680
|
+
console.log(C.dim(' By category:'));
|
|
681
|
+
for (const [cat, count] of Object.entries(stats.byCategory)) {
|
|
682
|
+
console.log(` ${cat}: ${count}`);
|
|
683
|
+
}
|
|
684
|
+
}
|
|
685
|
+
console.log();
|
|
686
|
+
return;
|
|
687
|
+
}
|
|
688
|
+
if (csub === 'share' && args[3]) {
|
|
689
|
+
const { shareCommunityPattern, validatePrivacy } = require('./core/community-store');
|
|
690
|
+
const rule = args[3];
|
|
691
|
+
const category = args[4] || 'general';
|
|
692
|
+
const language = args[5];
|
|
693
|
+
const validation = validatePrivacy(rule);
|
|
694
|
+
if (!validation.safe) {
|
|
695
|
+
console.log(C.warn(' Blocked — privacy violations:'));
|
|
696
|
+
for (const e of validation.errors)
|
|
697
|
+
console.log(C.warn(` ✗ ${e}`));
|
|
698
|
+
console.log();
|
|
699
|
+
return;
|
|
700
|
+
}
|
|
701
|
+
const result = shareCommunityPattern({ category, rule, language });
|
|
702
|
+
console.log(C.success(` Shared: ${result.patternId}`));
|
|
703
|
+
if (result.warnings.length > 0) {
|
|
704
|
+
console.log(C.dim(' Warnings:'));
|
|
705
|
+
for (const w of result.warnings)
|
|
706
|
+
console.log(C.dim(` - ${w}`));
|
|
707
|
+
}
|
|
708
|
+
console.log();
|
|
709
|
+
return;
|
|
710
|
+
}
|
|
711
|
+
if (csub === 'trends') {
|
|
712
|
+
const { getTechEvolution } = require('./core/community-store');
|
|
713
|
+
const trends = getTechEvolution();
|
|
714
|
+
console.log(C.bold(' Technology Trends'));
|
|
715
|
+
for (const t of trends.slice(0, 10)) {
|
|
716
|
+
const arrow = t.trend30d > 0 ? C.success('↑') : t.trend30d < 0 ? C.warn('↓') : C.dim('→');
|
|
717
|
+
console.log(` ${arrow} ${t.technology} — ${t.adoptionPhase} (${t.currentUsage} signals)`);
|
|
718
|
+
}
|
|
719
|
+
console.log();
|
|
720
|
+
return;
|
|
721
|
+
}
|
|
722
|
+
console.log(C.dim(' Usage: cell team community [stats|share <rule> <category>|trends]'));
|
|
723
|
+
console.log();
|
|
724
|
+
return;
|
|
725
|
+
}
|
|
726
|
+
// ─── team usage (Phase 6) ──────────────────────────────────────────
|
|
727
|
+
if (sub === 'usage') {
|
|
728
|
+
const { getUsageDashboard, getDecisionPatterns, detectRepeatMistakes, getBurnoutSignals } = require('./core/usage-intelligence-store');
|
|
729
|
+
const project = args[2] || 'Fivo-Cell';
|
|
730
|
+
const dash = getUsageDashboard(project);
|
|
731
|
+
console.log(C.bold(` Usage Dashboard — ${project}`));
|
|
732
|
+
console.log();
|
|
733
|
+
console.log(C.dim(` Decisions: ${dash.decisions.total} (${dash.decisions.right} right, ${dash.decisions.wrong} wrong)`));
|
|
734
|
+
if (dash.decisions.topPatterns.length > 0) {
|
|
735
|
+
console.log(C.bold(' Decision Patterns:'));
|
|
736
|
+
for (const p of dash.decisions.topPatterns.slice(0, 3)) {
|
|
737
|
+
console.log(` ${p.advice}`);
|
|
738
|
+
}
|
|
739
|
+
}
|
|
740
|
+
console.log();
|
|
741
|
+
console.log(C.dim(` Mistakes: ${dash.mistakes.total} repeated (${dash.mistakes.critical} critical)`));
|
|
742
|
+
if (dash.mistakes.top.length > 0) {
|
|
743
|
+
for (const m of dash.mistakes.top.slice(0, 3)) {
|
|
744
|
+
console.log(` ${C.warn('!')} ${m.errorType} (${m.count}x) — ${m.suggestion}`);
|
|
745
|
+
}
|
|
746
|
+
}
|
|
747
|
+
console.log();
|
|
748
|
+
console.log(C.dim(` AI: ${dash.ai.modelsUsed} models, avg acceptance ${dash.ai.avgAcceptance}%`));
|
|
749
|
+
if (dash.ai.topModel !== 'none')
|
|
750
|
+
console.log(C.dim(` Top model: ${dash.ai.topModel}`));
|
|
751
|
+
console.log();
|
|
752
|
+
console.log(C.dim(` Productivity: flow ${dash.productivity.flowScore}, friction ${dash.productivity.frictionScore}`));
|
|
753
|
+
console.log();
|
|
754
|
+
console.log(C.dim(` Skills: ${dash.skills.improving} improving, ${dash.skills.plateau} plateau, ${dash.skills.regressing} regressing`));
|
|
755
|
+
console.log();
|
|
756
|
+
const burnoutColor = dash.burnout.risk === 'high' ? C.warn : dash.burnout.risk === 'medium' ? C.primary : C.success;
|
|
757
|
+
console.log(burnoutColor(` Burnout risk: ${dash.burnout.risk.toUpperCase()}`));
|
|
758
|
+
if (dash.burnout.signals.length > 0) {
|
|
759
|
+
for (const s of dash.burnout.signals)
|
|
760
|
+
console.log(C.dim(` - ${s}`));
|
|
761
|
+
}
|
|
762
|
+
console.log(C.dim(` ${dash.burnout.advice}`));
|
|
763
|
+
console.log();
|
|
764
|
+
return;
|
|
765
|
+
}
|
|
440
766
|
if (sub === 'add' && args[2]) {
|
|
441
767
|
const name = args[2];
|
|
442
768
|
const role = args[3] || 'developer';
|
|
@@ -471,9 +797,176 @@ function doTeam() {
|
|
|
471
797
|
console.log(` ${C.primary('cell team push <name>')} Share your patterns with team`);
|
|
472
798
|
console.log(` ${C.primary('cell team pull')} Pull team data from git`);
|
|
473
799
|
console.log(` ${C.primary('cell team status')} Team intelligence dashboard`);
|
|
800
|
+
console.log(` ${C.primary('cell team silos')} Knowledge silo detection`);
|
|
801
|
+
console.log(` ${C.primary('cell team bus-factor')} Bus factor analysis`);
|
|
802
|
+
console.log(` ${C.primary('cell team health [proj]')} Team health score`);
|
|
803
|
+
console.log(` ${C.primary('cell team community')} Community stats/share/trends`);
|
|
804
|
+
console.log(` ${C.primary('cell team usage [proj]')} Personal usage intelligence`);
|
|
474
805
|
console.log(` ${C.primary('cell team add/remove')} Manage members`);
|
|
475
806
|
console.log();
|
|
476
807
|
}
|
|
808
|
+
// ─── cell watch ─────────────────────────────────────────────────────────────
|
|
809
|
+
function doWatch() {
|
|
810
|
+
console.log();
|
|
811
|
+
console.log(C.bold(' Cell Live Watcher'));
|
|
812
|
+
console.log(C.dim(' ─────────────────'));
|
|
813
|
+
console.log();
|
|
814
|
+
const sub = args[1] || 'daemon';
|
|
815
|
+
const project = args[2] || path.basename(process.cwd());
|
|
816
|
+
const dir = args[3] || process.cwd();
|
|
817
|
+
// If invoked with no subcommand: run as a long-lived watcher daemon (for .bat auto-restart loop)
|
|
818
|
+
if (sub === 'daemon' || sub === '') {
|
|
819
|
+
runWatchDaemon(project, dir);
|
|
820
|
+
return;
|
|
821
|
+
}
|
|
822
|
+
try {
|
|
823
|
+
const liveWatcher = require('./core/live-watcher');
|
|
824
|
+
const http = require('http');
|
|
825
|
+
function callDaemon(toolName, toolArgs) {
|
|
826
|
+
return new Promise((resolve, reject) => {
|
|
827
|
+
const body = JSON.stringify({ method: 'tools/call', params: { name: toolName, arguments: toolArgs } });
|
|
828
|
+
const req = http.request({ hostname: '127.0.0.1', port: 9876, path: '/mcp', method: 'POST', headers: { 'Content-Type': 'application/json', 'Content-Length': Buffer.byteLength(body) } }, (res) => {
|
|
829
|
+
let data = '';
|
|
830
|
+
res.on('data', (chunk) => { data += chunk; });
|
|
831
|
+
res.on('end', () => {
|
|
832
|
+
try {
|
|
833
|
+
const parsed = JSON.parse(data);
|
|
834
|
+
resolve(parsed.result || parsed);
|
|
835
|
+
}
|
|
836
|
+
catch (e) {
|
|
837
|
+
reject(e);
|
|
838
|
+
}
|
|
839
|
+
});
|
|
840
|
+
});
|
|
841
|
+
req.on('error', reject);
|
|
842
|
+
req.write(body);
|
|
843
|
+
req.end();
|
|
844
|
+
});
|
|
845
|
+
}
|
|
846
|
+
if (sub === 'start' || sub === 'stop') {
|
|
847
|
+
// Watcher state lives in daemon's in-memory map; CLI must talk to daemon
|
|
848
|
+
const toolName = sub === 'start' ? 'cell_watch_start' : 'cell_watch_stop';
|
|
849
|
+
const toolArgs = { project };
|
|
850
|
+
if (sub === 'start')
|
|
851
|
+
toolArgs.dir = dir;
|
|
852
|
+
callDaemon(toolName, toolArgs).then((r) => {
|
|
853
|
+
const ok = sub === 'start' ? r.started : r.stopped;
|
|
854
|
+
console.log(ok ? C.success(` ✓ ${r.message}`) : C.warn(` ! ${r.message}`));
|
|
855
|
+
console.log();
|
|
856
|
+
}).catch((e) => {
|
|
857
|
+
const msg = e instanceof Error ? e.message : String(e);
|
|
858
|
+
console.log(C.warn(` Daemon not running (${msg}). Start with: cell start`));
|
|
859
|
+
console.log();
|
|
860
|
+
});
|
|
861
|
+
return;
|
|
862
|
+
}
|
|
863
|
+
if (sub === 'events') {
|
|
864
|
+
const events = liveWatcher.getLiveEvents(project, 20);
|
|
865
|
+
if (events.length === 0) {
|
|
866
|
+
console.log(C.dim(` No live events for ${project} yet. Start watcher with: cell watch start ${project}`));
|
|
867
|
+
}
|
|
868
|
+
else {
|
|
869
|
+
console.log(C.bold(` Recent events for ${project} (${events.length}):`));
|
|
870
|
+
for (const e of events) {
|
|
871
|
+
const icon = e.eventType === 'file_save' ? '~' : e.eventType === 'file_create' ? '+' : e.eventType === 'file_delete' ? '-' : '*';
|
|
872
|
+
console.log(` ${C.dim(icon)} ${C.dim(e.createdAt)} ${e.eventType}: ${C.num(e.filePath)}`);
|
|
873
|
+
}
|
|
874
|
+
}
|
|
875
|
+
}
|
|
876
|
+
else if (sub === 'refresh') {
|
|
877
|
+
const result = liveWatcher.performAutoRefresh(project, true);
|
|
878
|
+
console.log(C.success(` ✓ Refresh logged: ${result.details} (${result.durationMs}ms)`));
|
|
879
|
+
}
|
|
880
|
+
else if (sub === 'check') {
|
|
881
|
+
const check = liveWatcher.checkIfNeedsRefresh(project);
|
|
882
|
+
const needs = check.needsRefresh;
|
|
883
|
+
console.log(needs ? C.warn(` ⚠ Needs refresh: ${check.reason}`) : C.success(` ✓ ${check.reason}`));
|
|
884
|
+
console.log(C.dim(` Data age: ${check.dataAge} | Recommended: ${check.recommendedAction}`));
|
|
885
|
+
}
|
|
886
|
+
else {
|
|
887
|
+
// status
|
|
888
|
+
const status = liveWatcher.getWatcherStatus(project);
|
|
889
|
+
const active = liveWatcher.getActiveWatchers();
|
|
890
|
+
if (status && status.active) {
|
|
891
|
+
console.log(C.success(` ● ${project}: ${C.bold('LIVE')} — ${status.eventCount} events, last: ${status.lastEventAt || 'never'}`));
|
|
892
|
+
}
|
|
893
|
+
else {
|
|
894
|
+
console.log(C.dim(` ○ ${project}: not watched`));
|
|
895
|
+
}
|
|
896
|
+
if (active.length > 1 || (active.length === 1 && active[0]?.project !== project)) {
|
|
897
|
+
console.log();
|
|
898
|
+
console.log(C.bold(' Other active watchers:'));
|
|
899
|
+
for (const a of active) {
|
|
900
|
+
if (a.project !== project)
|
|
901
|
+
console.log(` ● ${a.project} (${a.eventCount} events)`);
|
|
902
|
+
}
|
|
903
|
+
}
|
|
904
|
+
}
|
|
905
|
+
}
|
|
906
|
+
catch (err) {
|
|
907
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
908
|
+
console.log(C.warn(` Watch error: ${msg}`));
|
|
909
|
+
}
|
|
910
|
+
console.log();
|
|
911
|
+
}
|
|
912
|
+
// ─── cell blindspots ────────────────────────────────────────────────────────
|
|
913
|
+
function doBlindspots() {
|
|
914
|
+
console.log();
|
|
915
|
+
console.log(C.bold(' Cell Blind Spots'));
|
|
916
|
+
console.log(C.dim(' ────────────────'));
|
|
917
|
+
console.log();
|
|
918
|
+
const dir = args[1] || process.cwd();
|
|
919
|
+
const maxFiles = parseInt(args[2] || '200', 10);
|
|
920
|
+
try {
|
|
921
|
+
const { scanDirectoryForBlindSpots, formatBlindSpotReport, summarizeBlindSpots } = require('./core/enhanced-blind-spots');
|
|
922
|
+
console.log(C.dim(` Scanning ${dir} (max ${maxFiles} files)...`));
|
|
923
|
+
const spots = scanDirectoryForBlindSpots(dir, maxFiles);
|
|
924
|
+
console.log();
|
|
925
|
+
console.log(formatBlindSpotReport(spots));
|
|
926
|
+
const summary = summarizeBlindSpots(spots);
|
|
927
|
+
if (Object.keys(summary.byCategory).length > 0) {
|
|
928
|
+
console.log();
|
|
929
|
+
console.log(C.dim(' By category:'));
|
|
930
|
+
for (const [cat, count] of Object.entries(summary.byCategory)) {
|
|
931
|
+
console.log(` ${C.num(String(count))} ${cat}`);
|
|
932
|
+
}
|
|
933
|
+
}
|
|
934
|
+
}
|
|
935
|
+
catch (err) {
|
|
936
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
937
|
+
console.log(C.warn(` Blind spot scan failed: ${msg}`));
|
|
938
|
+
}
|
|
939
|
+
console.log();
|
|
940
|
+
}
|
|
941
|
+
// Long-lived watcher daemon — auto-attaches to current project, runs forever.
|
|
942
|
+
// Used by fivo-cell-daemon.bat to keep a watcher alive in the background.
|
|
943
|
+
function runWatchDaemon(project, dir) {
|
|
944
|
+
const liveWatcher = require('./core/live-watcher');
|
|
945
|
+
const result = liveWatcher.startWatcher(project, dir);
|
|
946
|
+
if (!result.started) {
|
|
947
|
+
// "already running" means the daemon process already has a watcher; keep this process alive anyway
|
|
948
|
+
console.log(` Watcher for ${project}: ${result.message}`);
|
|
949
|
+
}
|
|
950
|
+
else {
|
|
951
|
+
console.log(` ✓ Watcher attached: ${result.message}`);
|
|
952
|
+
}
|
|
953
|
+
console.log(` Watching ${dir} for changes. Press Ctrl+C to stop.`);
|
|
954
|
+
console.log();
|
|
955
|
+
// Keep the process alive — the file watcher uses fs.watch which keeps the event loop busy,
|
|
956
|
+
// but we add an explicit interval as a belt-and-braces guard against premature exit.
|
|
957
|
+
const keepAlive = setInterval(() => { }, 60_000);
|
|
958
|
+
process.on('SIGINT', () => {
|
|
959
|
+
clearInterval(keepAlive);
|
|
960
|
+
liveWatcher.stopWatcher(project);
|
|
961
|
+
console.log(`\n Watcher stopped for ${project}.`);
|
|
962
|
+
process.exit(0);
|
|
963
|
+
});
|
|
964
|
+
process.on('SIGTERM', () => {
|
|
965
|
+
clearInterval(keepAlive);
|
|
966
|
+
liveWatcher.stopWatcher(project);
|
|
967
|
+
process.exit(0);
|
|
968
|
+
});
|
|
969
|
+
}
|
|
477
970
|
// ─── cell community ─────────────────────────────────────────────────────────
|
|
478
971
|
function doCommunity() {
|
|
479
972
|
console.log();
|
|
@@ -546,9 +1039,13 @@ function doHelp() {
|
|
|
546
1039
|
console.log(` ${C.primary('cell start')} Start daemon + MCP (port 9876)`);
|
|
547
1040
|
console.log(` ${C.primary('cell stop')} Stop daemon`);
|
|
548
1041
|
console.log(` ${C.primary('cell scan')} Scan codebase + build layers`);
|
|
1042
|
+
console.log(` ${C.primary('cell analyze')} AI prompts from scan data`);
|
|
549
1043
|
console.log(` ${C.primary('cell status')} What Cell knows about you`);
|
|
550
1044
|
console.log(` ${C.primary('cell team')} Team collaboration (git-based)`);
|
|
551
|
-
console.log(` ${C.primary('cell community')} Community
|
|
1045
|
+
console.log(` ${C.primary('cell community')} Community patterns + benchmarks`);
|
|
1046
|
+
console.log(` ${C.primary('cell watch [start|stop|events|check|status] [proj] [dir]')} Live file watcher`);
|
|
1047
|
+
console.log(` ${C.primary('cell watch daemon [proj] [dir]')} Run as long-lived watcher (for .bat)`);
|
|
1048
|
+
console.log(` ${C.primary('cell blindspots [dir] [maxFiles]')} Scan for blind spots (15+ types)`);
|
|
552
1049
|
console.log(` ${C.primary('cell help')} Show this help`);
|
|
553
1050
|
console.log();
|
|
554
1051
|
console.log(C.dim(' Install: npm i -g fivocell'));
|