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
|
@@ -1,33 +1,49 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.DEFAULT_EXPIRED_DAYS = exports.DEFAULT_STALE_DAYS = void 0;
|
|
3
4
|
exports.buildContext = buildContext;
|
|
4
5
|
exports.formatContextForInjection = formatContextForInjection;
|
|
6
|
+
exports.formatContextForTool = formatContextForTool;
|
|
5
7
|
exports.estimateTokens = estimateTokens;
|
|
8
|
+
exports.getStalenessStatus = getStalenessStatus;
|
|
6
9
|
const database_1 = require("./database");
|
|
7
10
|
const logger_1 = require("./logger");
|
|
8
11
|
function buildContext(projectPath, toolName) {
|
|
9
12
|
const db = (0, database_1.getDb)();
|
|
10
|
-
const profile = readProfile(db);
|
|
11
|
-
const blindSpots = readBlindSpots(db);
|
|
12
|
-
const topPatterns = readTopPatterns(db);
|
|
13
|
+
const profile = readProfile(db, projectPath);
|
|
14
|
+
const blindSpots = readBlindSpots(db, projectPath);
|
|
15
|
+
const topPatterns = readTopPatterns(db, projectPath);
|
|
13
16
|
const recentActivity = readRecentActivity(db, projectPath);
|
|
14
17
|
const skills = readSkills(db);
|
|
15
18
|
const collaborators = readCollaborators(db);
|
|
16
19
|
const toolStats = toolName ? readToolStats(db, toolName) : null;
|
|
17
|
-
const
|
|
18
|
-
const
|
|
20
|
+
const stackDNA = readStackDNA(db, projectPath);
|
|
21
|
+
const dbPredictions = readPredictions(db, projectPath);
|
|
22
|
+
const lastSession = readLastSession(db, projectPath);
|
|
23
|
+
const triedApproaches = readTriedApproaches(db, projectPath);
|
|
24
|
+
const mostTouchedFiles = readMostTouchedFiles(db, projectPath);
|
|
25
|
+
const openQuestions = readOpenQuestions(db, projectPath);
|
|
26
|
+
const whoYouAre = buildWhoYouAre(profile, skills, collaborators, stackDNA, blindSpots);
|
|
27
|
+
const rightNow = buildRightNow(recentActivity, profile, lastSession);
|
|
19
28
|
const yourStyle = buildYourStyle(topPatterns, profile, skills);
|
|
20
29
|
const watchOut = buildWatchOut(blindSpots, profile);
|
|
21
30
|
const predictions = buildPredictions(blindSpots, recentActivity, toolStats);
|
|
22
31
|
const toolHint = toolName ? buildToolHint(toolName) : undefined;
|
|
32
|
+
const staleness = buildStalenessInfo(profile, recentActivity);
|
|
23
33
|
return {
|
|
24
34
|
whoYouAre,
|
|
25
35
|
rightNow,
|
|
26
36
|
yourStyle,
|
|
27
37
|
watchOut,
|
|
28
38
|
predictions,
|
|
39
|
+
dbPredictions,
|
|
29
40
|
injectedAt: new Date().toISOString(),
|
|
30
41
|
toolHint,
|
|
42
|
+
lastSession,
|
|
43
|
+
triedApproaches,
|
|
44
|
+
mostTouchedFiles,
|
|
45
|
+
openQuestions,
|
|
46
|
+
staleness,
|
|
31
47
|
};
|
|
32
48
|
}
|
|
33
49
|
function formatContextForInjection(ctx, compact = false) {
|
|
@@ -36,20 +52,77 @@ function formatContextForInjection(ctx, compact = false) {
|
|
|
36
52
|
}
|
|
37
53
|
return fullContext(ctx);
|
|
38
54
|
}
|
|
55
|
+
function formatContextForTool(ctx, toolName) {
|
|
56
|
+
if (!toolName)
|
|
57
|
+
return fullContext(ctx);
|
|
58
|
+
const t = toolName.toLowerCase().trim();
|
|
59
|
+
if (t === 'claude-code' || t === 'claude' || t === 'claude-code-cli') {
|
|
60
|
+
return fullContext(ctx);
|
|
61
|
+
}
|
|
62
|
+
if (t === 'cursor' || t === 'cursor-ide' || t === 'cursor-ai') {
|
|
63
|
+
return formatForCursor(ctx);
|
|
64
|
+
}
|
|
65
|
+
if (t === 'windsurf' || t === 'codeium' || t === 'windsurf-ide') {
|
|
66
|
+
return formatForWindsurf(ctx);
|
|
67
|
+
}
|
|
68
|
+
if (t === 'copilot' || t === 'github-copilot') {
|
|
69
|
+
return formatForCopilot(ctx);
|
|
70
|
+
}
|
|
71
|
+
if (t === 'antigravity' || t === 'aider' || t === 'continue-dev') {
|
|
72
|
+
return formatForAntigravity(ctx);
|
|
73
|
+
}
|
|
74
|
+
return fullContext(ctx);
|
|
75
|
+
}
|
|
39
76
|
function estimateTokens(text) {
|
|
40
77
|
return Math.ceil(text.length / 4);
|
|
41
78
|
}
|
|
42
79
|
function fullContext(ctx) {
|
|
43
80
|
let out = '';
|
|
44
|
-
out += '
|
|
81
|
+
out += '━━━ CELL CONTEXT ━━━\n\n';
|
|
82
|
+
if (ctx.staleness?.warning) {
|
|
83
|
+
out += '⚠ ' + ctx.staleness.warning + '\n\n';
|
|
84
|
+
}
|
|
45
85
|
out += '▸ WHO YOU ARE\n';
|
|
46
86
|
out += ctx.whoYouAre + '\n\n';
|
|
47
87
|
out += '▸ RIGHT NOW\n';
|
|
48
88
|
out += ctx.rightNow + '\n\n';
|
|
89
|
+
if (ctx.lastSession) {
|
|
90
|
+
const ago = ctx.lastSession.endTime ? formatRelativeTime(ctx.lastSession.endTime) : 'active';
|
|
91
|
+
out += '▸ LAST SESSION (' + ago + ')\n';
|
|
92
|
+
out += `Tool: ${ctx.lastSession.toolName}\n`;
|
|
93
|
+
if (ctx.lastSession.contextSnapshot) {
|
|
94
|
+
out += `Working on: ${ctx.lastSession.contextSnapshot}\n`;
|
|
95
|
+
}
|
|
96
|
+
if (ctx.lastSession.keyDecisions.length > 0) {
|
|
97
|
+
out += 'Key decisions: ' + ctx.lastSession.keyDecisions.slice(0, 3).join(' · ') + '\n';
|
|
98
|
+
}
|
|
99
|
+
out += '\n';
|
|
100
|
+
}
|
|
101
|
+
if (ctx.triedApproaches.length > 0) {
|
|
102
|
+
out += '▸ TRIED ALREADY (don\'t suggest these)\n';
|
|
103
|
+
for (const a of ctx.triedApproaches.slice(0, 5)) {
|
|
104
|
+
out += `→ ${a.approach} — ${a.status}${a.count > 1 ? ` (${a.count}x)` : ''}\n`;
|
|
105
|
+
}
|
|
106
|
+
out += '\n';
|
|
107
|
+
}
|
|
108
|
+
if (ctx.openQuestions.length > 0) {
|
|
109
|
+
out += '▸ OPEN QUESTIONS\n';
|
|
110
|
+
for (const q of ctx.openQuestions.slice(0, 5)) {
|
|
111
|
+
out += `→ [${q.priority}] ${q.question}\n`;
|
|
112
|
+
}
|
|
113
|
+
out += '\n';
|
|
114
|
+
}
|
|
49
115
|
out += '▸ YOUR STYLE\n';
|
|
50
116
|
out += ctx.yourStyle + '\n\n';
|
|
51
117
|
out += '▸ WATCH OUT\n';
|
|
52
118
|
out += ctx.watchOut + '\n\n';
|
|
119
|
+
if (ctx.mostTouchedFiles.length > 0) {
|
|
120
|
+
out += '▸ HOT FILES (recently active)\n';
|
|
121
|
+
for (const f of ctx.mostTouchedFiles.slice(0, 5)) {
|
|
122
|
+
out += `→ ${f.filePath} (${f.touchCount} touches, ${f.sessionCount} sessions)\n`;
|
|
123
|
+
}
|
|
124
|
+
out += '\n';
|
|
125
|
+
}
|
|
53
126
|
out += '▸ PREDICTIONS\n';
|
|
54
127
|
out += ctx.predictions;
|
|
55
128
|
if (ctx.toolHint) {
|
|
@@ -59,10 +132,21 @@ function fullContext(ctx) {
|
|
|
59
132
|
}
|
|
60
133
|
function compactContext(ctx) {
|
|
61
134
|
let out = '';
|
|
135
|
+
if (ctx.staleness?.warning) {
|
|
136
|
+
out += '⚠ ' + ctx.staleness.warning + '\n\n';
|
|
137
|
+
}
|
|
62
138
|
out += '## Developer Context\n';
|
|
63
139
|
out += ctx.whoYouAre.replace(/\n/g, ' | ') + '\n\n';
|
|
64
140
|
out += '### Current\n';
|
|
65
141
|
out += ctx.rightNow.replace(/\n/g, ' | ') + '\n\n';
|
|
142
|
+
if (ctx.triedApproaches.length > 0) {
|
|
143
|
+
out += '### Tried (skip these)\n';
|
|
144
|
+
out += ctx.triedApproaches.slice(0, 3).map(a => `${a.approach}(${a.status})`).join(' | ') + '\n\n';
|
|
145
|
+
}
|
|
146
|
+
if (ctx.openQuestions.length > 0) {
|
|
147
|
+
out += '### Open Questions\n';
|
|
148
|
+
out += ctx.openQuestions.slice(0, 3).map(q => `[${q.priority}] ${q.question}`).join(' | ') + '\n\n';
|
|
149
|
+
}
|
|
66
150
|
out += '### Style\n';
|
|
67
151
|
out += ctx.yourStyle.replace(/\n/g, ' | ') + '\n\n';
|
|
68
152
|
out += '### Blind Spots\n';
|
|
@@ -74,16 +158,142 @@ function compactContext(ctx) {
|
|
|
74
158
|
}
|
|
75
159
|
return out;
|
|
76
160
|
}
|
|
77
|
-
function
|
|
161
|
+
function formatForCursor(ctx) {
|
|
162
|
+
const lines = [];
|
|
163
|
+
lines.push('@context fivo-cell');
|
|
164
|
+
if (ctx.staleness?.warning)
|
|
165
|
+
lines.push('! ' + ctx.staleness.warning);
|
|
166
|
+
if (ctx.lastSession) {
|
|
167
|
+
lines.push('last: ' + ctx.lastSession.toolName + ' (' + (ctx.lastSession.endTime ? formatRelativeTime(ctx.lastSession.endTime) : 'active') + ')');
|
|
168
|
+
if (ctx.lastSession.contextSnapshot)
|
|
169
|
+
lines.push('working: ' + ctx.lastSession.contextSnapshot);
|
|
170
|
+
}
|
|
171
|
+
lines.push('');
|
|
172
|
+
lines.push('style: ' + (ctx.yourStyle.split('\n')[0] || ''));
|
|
173
|
+
if (ctx.triedApproaches.length > 0) {
|
|
174
|
+
lines.push('avoid: ' + ctx.triedApproaches.slice(0, 3).map(a => `${a.approach}[${a.status}]`).join(', '));
|
|
175
|
+
}
|
|
176
|
+
if (ctx.openQuestions.length > 0) {
|
|
177
|
+
lines.push('q: ' + ctx.openQuestions.slice(0, 2).map(q => `${q.question.slice(0, 50)}…`).join(' | '));
|
|
178
|
+
}
|
|
179
|
+
if (ctx.mostTouchedFiles.length > 0) {
|
|
180
|
+
lines.push('hot: ' + ctx.mostTouchedFiles.slice(0, 3).map(f => f.filePath).join(', '));
|
|
181
|
+
}
|
|
182
|
+
if (ctx.watchOut) {
|
|
183
|
+
const topBlindSpot = ctx.watchOut.split('\n').find(l => l.trim().startsWith('-'));
|
|
184
|
+
if (topBlindSpot)
|
|
185
|
+
lines.push('watch: ' + topBlindSpot.replace(/^-\s*/, '').slice(0, 80));
|
|
186
|
+
}
|
|
187
|
+
return lines.join('\n');
|
|
188
|
+
}
|
|
189
|
+
function formatForWindsurf(ctx) {
|
|
190
|
+
const lines = [];
|
|
191
|
+
lines.push('# Cell Context');
|
|
192
|
+
if (ctx.staleness?.warning)
|
|
193
|
+
lines.push('> ⚠ ' + ctx.staleness.warning);
|
|
194
|
+
if (ctx.lastSession) {
|
|
195
|
+
lines.push('## Last Session');
|
|
196
|
+
lines.push(`- **Tool**: ${ctx.lastSession.toolName}`);
|
|
197
|
+
if (ctx.lastSession.contextSnapshot)
|
|
198
|
+
lines.push(`- **Working on**: ${ctx.lastSession.contextSnapshot}`);
|
|
199
|
+
if (ctx.lastSession.keyDecisions.length > 0)
|
|
200
|
+
lines.push(`- **Decisions**: ${ctx.lastSession.keyDecisions.slice(0, 2).join(', ')}`);
|
|
201
|
+
}
|
|
202
|
+
if (ctx.openQuestions.length > 0) {
|
|
203
|
+
lines.push('## Open Questions');
|
|
204
|
+
for (const q of ctx.openQuestions.slice(0, 3)) {
|
|
205
|
+
lines.push(`- [${q.priority}] ${q.question}`);
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
lines.push('## Style');
|
|
209
|
+
lines.push(ctx.yourStyle.split('\n')[0] || '');
|
|
210
|
+
lines.push('## Suggestions');
|
|
211
|
+
if (ctx.watchOut) {
|
|
212
|
+
const spots = ctx.watchOut.split('\n').filter(l => l.trim().startsWith('-')).slice(0, 3);
|
|
213
|
+
spots.forEach(s => lines.push('- ' + s.replace(/^-\s*/, '')));
|
|
214
|
+
}
|
|
215
|
+
if (ctx.mostTouchedFiles.length > 0) {
|
|
216
|
+
lines.push('## Active Files');
|
|
217
|
+
ctx.mostTouchedFiles.slice(0, 3).forEach(f => lines.push(`- ${f.filePath} (${f.touchCount} touches)`));
|
|
218
|
+
}
|
|
219
|
+
return lines.join('\n');
|
|
220
|
+
}
|
|
221
|
+
function formatForCopilot(ctx) {
|
|
222
|
+
const parts = [];
|
|
223
|
+
if (ctx.staleness?.warning)
|
|
224
|
+
parts.push('⚠ ' + ctx.staleness.warning.replace(/`/g, ''));
|
|
225
|
+
parts.push('Project: ' + (ctx.lastSession?.project || 'unknown'));
|
|
226
|
+
if (ctx.lastSession?.contextSnapshot)
|
|
227
|
+
parts.push('Working: ' + ctx.lastSession.contextSnapshot.slice(0, 60));
|
|
228
|
+
if (ctx.triedApproaches.length > 0) {
|
|
229
|
+
const a = ctx.triedApproaches[0];
|
|
230
|
+
parts.push(`Avoid: ${a.approach} (${a.status})`);
|
|
231
|
+
}
|
|
232
|
+
const styleLine = ctx.yourStyle.split('\n')[0] || '';
|
|
233
|
+
if (styleLine)
|
|
234
|
+
parts.push('Style: ' + styleLine.slice(0, 80));
|
|
235
|
+
return parts.join(' · ');
|
|
236
|
+
}
|
|
237
|
+
function formatForAntigravity(ctx) {
|
|
238
|
+
const lines = [];
|
|
239
|
+
lines.push('## Cell Context — Structured');
|
|
240
|
+
if (ctx.staleness?.warning)
|
|
241
|
+
lines.push('> ⚠ ' + ctx.staleness.warning);
|
|
242
|
+
lines.push('');
|
|
243
|
+
lines.push('```yaml');
|
|
244
|
+
lines.push(`project: ${ctx.lastSession?.project || 'unknown'}`);
|
|
245
|
+
lines.push(`tool_hint: ${ctx.toolHint || 'general'}`);
|
|
246
|
+
if (ctx.lastSession) {
|
|
247
|
+
lines.push(`last_session:`);
|
|
248
|
+
lines.push(` tool: ${ctx.lastSession.toolName}`);
|
|
249
|
+
lines.push(` when: ${ctx.lastSession.endTime || 'active'}`);
|
|
250
|
+
if (ctx.lastSession.contextSnapshot)
|
|
251
|
+
lines.push(` context: "${ctx.lastSession.contextSnapshot}"`);
|
|
252
|
+
}
|
|
253
|
+
if (ctx.triedApproaches.length > 0) {
|
|
254
|
+
lines.push(`tried_approaches:`);
|
|
255
|
+
ctx.triedApproaches.slice(0, 3).forEach(a => {
|
|
256
|
+
lines.push(` - approach: "${a.approach}"`);
|
|
257
|
+
lines.push(` status: ${a.status}`);
|
|
258
|
+
});
|
|
259
|
+
}
|
|
260
|
+
if (ctx.openQuestions.length > 0) {
|
|
261
|
+
lines.push(`open_questions:`);
|
|
262
|
+
ctx.openQuestions.slice(0, 3).forEach(q => {
|
|
263
|
+
lines.push(` - priority: ${q.priority}`);
|
|
264
|
+
lines.push(` question: "${q.question}"`);
|
|
265
|
+
});
|
|
266
|
+
}
|
|
267
|
+
lines.push('```');
|
|
268
|
+
return lines.join('\n');
|
|
269
|
+
}
|
|
270
|
+
function readProfile(db, projectPath) {
|
|
78
271
|
try {
|
|
79
|
-
const row =
|
|
272
|
+
const row = projectPath
|
|
273
|
+
? db.prepare('SELECT * FROM developer_profiles WHERE project = ? ORDER BY scanned_at DESC LIMIT 1').get(projectPath)
|
|
274
|
+
: db.prepare('SELECT * FROM developer_profiles ORDER BY scanned_at DESC LIMIT 1').get();
|
|
80
275
|
if (row) {
|
|
81
276
|
return {
|
|
82
|
-
name: row.
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
277
|
+
name: row.project || '',
|
|
278
|
+
project: row.project || '',
|
|
279
|
+
naming_style: row.naming_style || '',
|
|
280
|
+
quote_style: row.quote_style || '',
|
|
281
|
+
semicolon_style: row.semicolon_style || '',
|
|
282
|
+
indent_style: row.indent_style || '',
|
|
283
|
+
async_style: row.async_style || '',
|
|
284
|
+
error_handling: row.error_handling || '',
|
|
285
|
+
function_style: row.function_style || '',
|
|
286
|
+
import_style: row.import_style || '',
|
|
287
|
+
export_style: row.export_style || '',
|
|
288
|
+
comment_style: row.comment_style || '',
|
|
289
|
+
architecture_style: row.architecture_style || '',
|
|
290
|
+
test_pattern: row.test_pattern || '',
|
|
291
|
+
top_patterns: safeJson(row.top_patterns),
|
|
292
|
+
strengths: safeJson(row.strengths),
|
|
293
|
+
improvements: safeJson(row.improvements),
|
|
294
|
+
files_scanned: row.files_scanned || 0,
|
|
295
|
+
total_lines: row.total_lines || 0,
|
|
296
|
+
scanned_at: row.scanned_at || '',
|
|
87
297
|
};
|
|
88
298
|
}
|
|
89
299
|
}
|
|
@@ -92,17 +302,23 @@ function readProfile(db) {
|
|
|
92
302
|
}
|
|
93
303
|
return {};
|
|
94
304
|
}
|
|
95
|
-
function readBlindSpots(db) {
|
|
305
|
+
function readBlindSpots(db, projectPath) {
|
|
96
306
|
try {
|
|
97
|
-
|
|
307
|
+
if (projectPath) {
|
|
308
|
+
return db.prepare("SELECT pattern_type, pattern_value, count, trust_score FROM code_patterns WHERE category = 'blind_spots' AND project = ? ORDER BY trust_score DESC, count DESC LIMIT 10").all(projectPath);
|
|
309
|
+
}
|
|
310
|
+
return db.prepare("SELECT pattern_type, pattern_value, count, trust_score FROM code_patterns WHERE category = 'blind_spots' ORDER BY trust_score DESC, count DESC LIMIT 10").all();
|
|
98
311
|
}
|
|
99
312
|
catch {
|
|
100
313
|
return [];
|
|
101
314
|
}
|
|
102
315
|
}
|
|
103
|
-
function readTopPatterns(db) {
|
|
316
|
+
function readTopPatterns(db, projectPath) {
|
|
104
317
|
try {
|
|
105
|
-
|
|
318
|
+
if (projectPath) {
|
|
319
|
+
return db.prepare("SELECT pattern_type, pattern_value, category, count, trust_score FROM code_patterns WHERE project = ? AND category != 'blind_spots' ORDER BY trust_score DESC, count DESC LIMIT 15").all(projectPath);
|
|
320
|
+
}
|
|
321
|
+
return db.prepare("SELECT pattern_type, pattern_value, category, count, trust_score FROM code_patterns WHERE category != 'blind_spots' ORDER BY trust_score DESC, count DESC LIMIT 15").all();
|
|
106
322
|
}
|
|
107
323
|
catch {
|
|
108
324
|
return [];
|
|
@@ -111,9 +327,9 @@ function readTopPatterns(db) {
|
|
|
111
327
|
function readRecentActivity(db, projectPath) {
|
|
112
328
|
try {
|
|
113
329
|
if (projectPath) {
|
|
114
|
-
return db.prepare('SELECT * FROM
|
|
330
|
+
return db.prepare('SELECT * FROM scans WHERE project = ? ORDER BY completed_at DESC LIMIT 5').all(projectPath);
|
|
115
331
|
}
|
|
116
|
-
return db.prepare('SELECT * FROM
|
|
332
|
+
return db.prepare('SELECT * FROM scans ORDER BY completed_at DESC LIMIT 5').all();
|
|
117
333
|
}
|
|
118
334
|
catch {
|
|
119
335
|
return [];
|
|
@@ -143,21 +359,161 @@ function readToolStats(db, toolName) {
|
|
|
143
359
|
return null;
|
|
144
360
|
}
|
|
145
361
|
}
|
|
146
|
-
function
|
|
362
|
+
function readStackDNA(db, projectPath) {
|
|
363
|
+
try {
|
|
364
|
+
const query = projectPath
|
|
365
|
+
? "SELECT pattern_value FROM code_patterns WHERE pattern_type = 'project_dna' AND project = ?"
|
|
366
|
+
: "SELECT pattern_value FROM code_patterns WHERE pattern_type = 'project_dna'";
|
|
367
|
+
const params = projectPath ? [projectPath] : [];
|
|
368
|
+
const row = db.prepare(query).get(...(params));
|
|
369
|
+
if (row?.pattern_value)
|
|
370
|
+
return JSON.parse(row.pattern_value);
|
|
371
|
+
return null;
|
|
372
|
+
}
|
|
373
|
+
catch {
|
|
374
|
+
return null;
|
|
375
|
+
}
|
|
376
|
+
}
|
|
377
|
+
function readPredictions(db, projectPath) {
|
|
378
|
+
try {
|
|
379
|
+
const errors = db.prepare("SELECT error_message, COUNT(*) as cnt FROM error_log GROUP BY error_message HAVING cnt > 1 ORDER BY cnt DESC LIMIT 5").all();
|
|
380
|
+
return errors.map(e => `${e.error_message} — ${e.cnt}x repeated`);
|
|
381
|
+
}
|
|
382
|
+
catch {
|
|
383
|
+
return [];
|
|
384
|
+
}
|
|
385
|
+
}
|
|
386
|
+
function readLastSession(db, projectPath) {
|
|
387
|
+
try {
|
|
388
|
+
const query = projectPath
|
|
389
|
+
? 'SELECT * FROM sessions WHERE project = ? AND end_time IS NOT NULL ORDER BY end_time DESC LIMIT 1'
|
|
390
|
+
: 'SELECT * FROM sessions WHERE end_time IS NOT NULL ORDER BY end_time DESC LIMIT 1';
|
|
391
|
+
const params = projectPath ? [projectPath] : [];
|
|
392
|
+
const row = db.prepare(query).get(...(params));
|
|
393
|
+
if (!row)
|
|
394
|
+
return undefined;
|
|
395
|
+
return {
|
|
396
|
+
id: Number(row.id),
|
|
397
|
+
toolName: String(row.tool_name || ''),
|
|
398
|
+
project: String(row.project || ''),
|
|
399
|
+
startTime: String(row.start_time || ''),
|
|
400
|
+
endTime: row.end_time ? String(row.end_time) : undefined,
|
|
401
|
+
filesTouched: safeJson(String(row.files_touched)) || [],
|
|
402
|
+
keyDecisions: safeJson(String(row.key_decisions)) || [],
|
|
403
|
+
contextSnapshot: String(row.context_snapshot || ''),
|
|
404
|
+
};
|
|
405
|
+
}
|
|
406
|
+
catch {
|
|
407
|
+
return undefined;
|
|
408
|
+
}
|
|
409
|
+
}
|
|
410
|
+
function readTriedApproaches(db, projectPath) {
|
|
411
|
+
try {
|
|
412
|
+
const query = projectPath
|
|
413
|
+
? `SELECT approach, status, COUNT(*) as count, MAX(reason) as last_reason, MAX(created_at) as last_seen
|
|
414
|
+
FROM session_approaches
|
|
415
|
+
WHERE project = ?
|
|
416
|
+
GROUP BY LOWER(approach)
|
|
417
|
+
ORDER BY count DESC, last_seen DESC
|
|
418
|
+
LIMIT 10`
|
|
419
|
+
: `SELECT approach, status, COUNT(*) as count, MAX(reason) as last_reason, MAX(created_at) as last_seen
|
|
420
|
+
FROM session_approaches
|
|
421
|
+
GROUP BY LOWER(approach)
|
|
422
|
+
ORDER BY count DESC, last_seen DESC
|
|
423
|
+
LIMIT 10`;
|
|
424
|
+
const params = projectPath ? [projectPath] : [];
|
|
425
|
+
const rows = db.prepare(query).all(...(params));
|
|
426
|
+
return rows.map(r => ({
|
|
427
|
+
approach: r.approach,
|
|
428
|
+
status: r.status,
|
|
429
|
+
count: r.count,
|
|
430
|
+
lastReason: r.last_reason,
|
|
431
|
+
lastSeen: r.last_seen,
|
|
432
|
+
}));
|
|
433
|
+
}
|
|
434
|
+
catch {
|
|
435
|
+
return [];
|
|
436
|
+
}
|
|
437
|
+
}
|
|
438
|
+
function readMostTouchedFiles(db, projectPath) {
|
|
439
|
+
try {
|
|
440
|
+
const query = projectPath
|
|
441
|
+
? `SELECT file_path, SUM(touch_count) as total_touches, COUNT(DISTINCT session_id) as session_count, MAX(last_touched) as last_touched
|
|
442
|
+
FROM session_files
|
|
443
|
+
WHERE project = ?
|
|
444
|
+
GROUP BY file_path
|
|
445
|
+
ORDER BY total_touches DESC, last_touched DESC
|
|
446
|
+
LIMIT 10`
|
|
447
|
+
: `SELECT file_path, SUM(touch_count) as total_touches, COUNT(DISTINCT session_id) as session_count, MAX(last_touched) as last_touched
|
|
448
|
+
FROM session_files
|
|
449
|
+
GROUP BY file_path
|
|
450
|
+
ORDER BY total_touches DESC, last_touched DESC
|
|
451
|
+
LIMIT 10`;
|
|
452
|
+
const params = projectPath ? [projectPath] : [];
|
|
453
|
+
const rows = db.prepare(query).all(...(params));
|
|
454
|
+
return rows.map(r => ({
|
|
455
|
+
filePath: r.file_path,
|
|
456
|
+
touchCount: r.total_touches,
|
|
457
|
+
sessionCount: r.session_count,
|
|
458
|
+
lastTouched: r.last_touched,
|
|
459
|
+
}));
|
|
460
|
+
}
|
|
461
|
+
catch {
|
|
462
|
+
return [];
|
|
463
|
+
}
|
|
464
|
+
}
|
|
465
|
+
function readOpenQuestions(db, projectPath) {
|
|
466
|
+
try {
|
|
467
|
+
const query = projectPath
|
|
468
|
+
? `SELECT * FROM session_questions
|
|
469
|
+
WHERE project = ? AND resolved = 0
|
|
470
|
+
ORDER BY CASE priority WHEN 'high' THEN 1 WHEN 'medium' THEN 2 ELSE 3 END, created_at DESC
|
|
471
|
+
LIMIT 10`
|
|
472
|
+
: `SELECT * FROM session_questions
|
|
473
|
+
WHERE resolved = 0
|
|
474
|
+
ORDER BY CASE priority WHEN 'high' THEN 1 WHEN 'medium' THEN 2 ELSE 3 END, created_at DESC
|
|
475
|
+
LIMIT 10`;
|
|
476
|
+
const params = projectPath ? [projectPath] : [];
|
|
477
|
+
const rows = db.prepare(query).all(...(params));
|
|
478
|
+
return rows.map(r => ({
|
|
479
|
+
id: Number(r.id),
|
|
480
|
+
question: String(r.question || ''),
|
|
481
|
+
priority: String(r.priority || 'medium'),
|
|
482
|
+
resolved: Boolean(r.resolved),
|
|
483
|
+
answer: r.answer ? String(r.answer) : null,
|
|
484
|
+
createdAt: String(r.created_at || ''),
|
|
485
|
+
}));
|
|
486
|
+
}
|
|
487
|
+
catch {
|
|
488
|
+
return [];
|
|
489
|
+
}
|
|
490
|
+
}
|
|
491
|
+
function buildWhoYouAre(profile, skills, collaborators, stackDNA, blindSpots) {
|
|
147
492
|
const lines = [];
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
const
|
|
151
|
-
lines.push(`
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
493
|
+
if (profile.project) {
|
|
494
|
+
const files = profile.files_scanned || 0;
|
|
495
|
+
const lines1 = profile.total_lines || 0;
|
|
496
|
+
lines.push(`Project: ${profile.project} (${files} files, ${lines1} lines)`);
|
|
497
|
+
}
|
|
498
|
+
if (stackDNA && typeof stackDNA === 'object') {
|
|
499
|
+
const s = stackDNA;
|
|
500
|
+
const parts = [];
|
|
501
|
+
if (s.languages && s.languages.length > 0)
|
|
502
|
+
parts.push(`Languages: ${s.languages.join(', ')}`);
|
|
503
|
+
if (s.frontend && s.frontend !== 'none')
|
|
504
|
+
parts.push(`Frontend: ${s.frontend}`);
|
|
505
|
+
if (s.backend && s.backend !== 'none')
|
|
506
|
+
parts.push(`Backend: ${s.backend}`);
|
|
507
|
+
if (s.database && s.database[0] !== 'none')
|
|
508
|
+
parts.push(`DB: ${s.database.join(', ')}`);
|
|
509
|
+
if (s.orm && s.orm !== 'none')
|
|
510
|
+
parts.push(`ORM: ${s.orm}`);
|
|
511
|
+
if (s.testing && s.testing[0] !== 'none')
|
|
512
|
+
parts.push(`Test: ${s.testing.join(', ')}`);
|
|
513
|
+
if (s.validation && s.validation !== 'none')
|
|
514
|
+
parts.push(`Validation: ${s.validation}`);
|
|
515
|
+
if (parts.length > 0)
|
|
516
|
+
lines.push(parts.join(' · '));
|
|
161
517
|
}
|
|
162
518
|
const skillLanguages = skills.filter((s) => s.level !== 'learning' && s.level !== 'new').map((s) => s.language);
|
|
163
519
|
if (skillLanguages.length > 0)
|
|
@@ -166,32 +522,76 @@ function buildWhoYouAre(profile, skills, collaborators) {
|
|
|
166
522
|
const names = collaborators.slice(0, 3).map((c) => c.name).filter(Boolean);
|
|
167
523
|
lines.push(`Team: ${names.join(', ')} (${collaborators.length} total)`);
|
|
168
524
|
}
|
|
525
|
+
const strengths = profile.strengths || [];
|
|
526
|
+
if (strengths.length > 0) {
|
|
527
|
+
lines.push(`Strengths: ${strengths.slice(0, 3).join(' · ')}`);
|
|
528
|
+
}
|
|
529
|
+
if (blindSpots && blindSpots.length > 0) {
|
|
530
|
+
const top = blindSpots.slice(0, 3).map(b => `${b.pattern_value || b.description || 'unknown'} (${b.count || 0}x)`).filter(Boolean);
|
|
531
|
+
if (top.length > 0)
|
|
532
|
+
lines.push(`⚠ Blind spots: ${top.join(' | ')}`);
|
|
533
|
+
}
|
|
169
534
|
if (lines.length === 0) {
|
|
170
535
|
lines.push('Developer profile — run `cell scan` to build profile');
|
|
171
|
-
lines.push('Stack: TypeScript, Node.js, React, Express');
|
|
172
536
|
}
|
|
173
537
|
return lines.join('\n');
|
|
174
538
|
}
|
|
175
|
-
function buildRightNow(activity, profile) {
|
|
539
|
+
function buildRightNow(activity, profile, lastSession) {
|
|
176
540
|
const lines = [];
|
|
177
|
-
if (
|
|
178
|
-
const
|
|
179
|
-
lines.push(`Last
|
|
180
|
-
|
|
541
|
+
if (lastSession) {
|
|
542
|
+
const ago = lastSession.endTime ? formatRelativeTime(lastSession.endTime) : 'in progress';
|
|
543
|
+
lines.push(`Last session: ${ago} (${lastSession.toolName})`);
|
|
544
|
+
if (lastSession.contextSnapshot) {
|
|
545
|
+
lines.push(`Working on: ${lastSession.contextSnapshot}`);
|
|
546
|
+
}
|
|
547
|
+
if (lastSession.keyDecisions.length > 0) {
|
|
548
|
+
lines.push(`Decisions: ${lastSession.keyDecisions.slice(0, 3).join(' · ')}`);
|
|
549
|
+
}
|
|
550
|
+
if (lastSession.filesTouched.length > 0) {
|
|
551
|
+
lines.push(`Current file: ${lastSession.filesTouched[0]}`);
|
|
552
|
+
}
|
|
553
|
+
}
|
|
554
|
+
else if (activity.length > 0) {
|
|
555
|
+
const lastScan = activity[0];
|
|
556
|
+
lines.push(`Last scan: ${lastScan.files_scanned || 0} files scanned`);
|
|
557
|
+
if (lastScan.completed_at) {
|
|
558
|
+
lines.push(`Last active: ${formatRelativeTime(lastScan.completed_at)}`);
|
|
559
|
+
}
|
|
560
|
+
if (lastScan.project) {
|
|
561
|
+
lines.push(`Project: ${lastScan.project}`);
|
|
562
|
+
}
|
|
181
563
|
}
|
|
182
564
|
else {
|
|
183
565
|
lines.push('No recent activity detected');
|
|
184
566
|
lines.push('Run `cell scan` to refresh');
|
|
185
567
|
}
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
const latest = products[products.length - 1];
|
|
189
|
-
lines.push(`Latest project: ${latest.name || 'unknown'} ${latest.latestVersion ? '(' + latest.latestVersion + ')' : ''}`);
|
|
568
|
+
if (profile.scanned_at) {
|
|
569
|
+
lines.push(`Profile last built: ${formatRelativeTime(profile.scanned_at)}`);
|
|
190
570
|
}
|
|
191
571
|
return lines.join('\n');
|
|
192
572
|
}
|
|
193
573
|
function buildYourStyle(patterns, profile, skills) {
|
|
194
574
|
const lines = [];
|
|
575
|
+
const styleBits = [];
|
|
576
|
+
if (profile.quote_style)
|
|
577
|
+
styleBits.push(`Quotes: ${profile.quote_style}`);
|
|
578
|
+
if (profile.semicolon_style)
|
|
579
|
+
styleBits.push(`Semicolons: ${profile.semicolon_style}`);
|
|
580
|
+
if (profile.indent_style)
|
|
581
|
+
styleBits.push(`Indent: ${profile.indent_style}`);
|
|
582
|
+
if (profile.naming_style)
|
|
583
|
+
styleBits.push(`Naming: ${profile.naming_style}`);
|
|
584
|
+
if (profile.async_style)
|
|
585
|
+
styleBits.push(`Async: ${profile.async_style}`);
|
|
586
|
+
if (profile.error_handling)
|
|
587
|
+
styleBits.push(`Errors: ${profile.error_handling}`);
|
|
588
|
+
if (profile.function_style)
|
|
589
|
+
styleBits.push(`Functions: ${profile.function_style}`);
|
|
590
|
+
if (profile.test_pattern)
|
|
591
|
+
styleBits.push(`Tests: ${profile.test_pattern}`);
|
|
592
|
+
if (styleBits.length > 0) {
|
|
593
|
+
lines.push(styleBits.join(' · '));
|
|
594
|
+
}
|
|
195
595
|
const categories = new Map();
|
|
196
596
|
for (const p of patterns) {
|
|
197
597
|
const cat = String(p.category || '');
|
|
@@ -201,65 +601,65 @@ function buildYourStyle(patterns, profile, skills) {
|
|
|
201
601
|
if (sortedCats.length > 0) {
|
|
202
602
|
lines.push(`Top patterns: ${sortedCats.map(([c, n]) => `${c}(${n})`).join(', ')}`);
|
|
203
603
|
}
|
|
204
|
-
const topRules = patterns.slice(0, 5).map((p) => p.rule).filter(Boolean);
|
|
205
|
-
if (topRules.length > 0) {
|
|
206
|
-
lines.push('Style preferences:');
|
|
207
|
-
for (const r of topRules) {
|
|
208
|
-
lines.push(` - ${r}`);
|
|
209
|
-
}
|
|
210
|
-
}
|
|
211
604
|
const doList = [];
|
|
212
|
-
const dontList = [];
|
|
213
605
|
for (const p of patterns) {
|
|
214
|
-
const rule = String(p.
|
|
606
|
+
const rule = String(p.pattern_value || '');
|
|
215
607
|
const cat = String(p.category || '');
|
|
216
|
-
if (cat === 'typescript_strict' || rule.
|
|
608
|
+
if (cat === 'typescript_strict' || rule.toLowerCase().includes('type')) {
|
|
217
609
|
doList.push('DO: TypeScript strict mode');
|
|
218
610
|
}
|
|
219
|
-
if (cat === '
|
|
611
|
+
if (cat === 'async' || rule.toLowerCase().includes('async') || profile.async_style === 'uses-async') {
|
|
220
612
|
doList.push('DO: Use async/await, not .then()');
|
|
221
613
|
}
|
|
222
|
-
if (cat === 'null_safety' || rule.includes('optional
|
|
614
|
+
if (cat === 'null_safety' || rule.toLowerCase().includes('optional')) {
|
|
223
615
|
doList.push('DO: Use optional chaining');
|
|
224
616
|
}
|
|
225
|
-
if (cat === 'destructuring' || rule.includes('
|
|
617
|
+
if (cat === 'destructuring' || rule.toLowerCase().includes('destructur')) {
|
|
226
618
|
doList.push('DO: Use destructuring over index access');
|
|
227
619
|
}
|
|
228
620
|
}
|
|
229
|
-
const unique = new Set(doList);
|
|
230
|
-
if (unique.
|
|
231
|
-
lines.push(
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
621
|
+
const unique = [...new Set(doList)];
|
|
622
|
+
if (unique.length > 0) {
|
|
623
|
+
lines.push('');
|
|
624
|
+
lines.push('DO list:');
|
|
625
|
+
unique.forEach(d => lines.push(' ' + d));
|
|
626
|
+
}
|
|
627
|
+
lines.push('');
|
|
628
|
+
lines.push("DON'T list:");
|
|
629
|
+
lines.push(' - Use var (use const/let)');
|
|
630
|
+
lines.push(' - Skip try/catch on async');
|
|
631
|
+
lines.push(' - Skip null checks on API responses');
|
|
235
632
|
return lines.join('\n');
|
|
236
633
|
}
|
|
237
634
|
function buildWatchOut(blindSpots, profile) {
|
|
238
635
|
const lines = [];
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
lines.push('Run `cell scan` to detect
|
|
242
|
-
lines.push('Common checks: error handling, null safety, test coverage');
|
|
636
|
+
if (blindSpots.length === 0) {
|
|
637
|
+
lines.push('No blind spots detected yet.');
|
|
638
|
+
lines.push('Run `cell scan` to detect error handling, null safety, and validation gaps');
|
|
243
639
|
return lines.join('\n');
|
|
244
640
|
}
|
|
245
|
-
lines.push(
|
|
641
|
+
lines.push(`Top blind spots (${blindSpots.length} total):`);
|
|
246
642
|
const top = blindSpots.slice(0, 5);
|
|
247
643
|
for (const s of top) {
|
|
248
|
-
const desc = String(s.description || '');
|
|
644
|
+
const desc = String(s.pattern_value || s.description || 'unknown');
|
|
645
|
+
const count = s.count || 0;
|
|
646
|
+
const trust = s.trust_score || 0;
|
|
249
647
|
if (desc)
|
|
250
|
-
lines.push(` - [${
|
|
648
|
+
lines.push(` - [${count}x, trust ${trust}] ${desc}`);
|
|
649
|
+
}
|
|
650
|
+
if (profile.improvements && Array.isArray(profile.improvements) && profile.improvements.length > 0) {
|
|
651
|
+
lines.push('');
|
|
652
|
+
lines.push('Suggested improvements:');
|
|
653
|
+
const improvements = profile.improvements;
|
|
654
|
+
improvements.slice(0, 3).forEach((imp) => lines.push(' - ' + imp));
|
|
251
655
|
}
|
|
252
|
-
lines.push('Always flag if:');
|
|
253
|
-
lines.push(' - async function missing try/catch');
|
|
254
|
-
lines.push(' - API response used without null check');
|
|
255
|
-
lines.push(' - Database operation without validation');
|
|
256
656
|
return lines.join('\n');
|
|
257
657
|
}
|
|
258
658
|
function buildPredictions(blindSpots, activity, toolStats) {
|
|
259
659
|
const lines = [];
|
|
260
|
-
const
|
|
261
|
-
if (
|
|
262
|
-
lines.push(`⚠ ${
|
|
660
|
+
const highTrustBlindSpots = blindSpots.filter((b) => b.trust_score >= 80).length;
|
|
661
|
+
if (highTrustBlindSpots > 0) {
|
|
662
|
+
lines.push(`⚠ ${highTrustBlindSpots} high-confidence blind spots likely to recur`);
|
|
263
663
|
}
|
|
264
664
|
if (toolStats) {
|
|
265
665
|
const acceptRate = toolStats.acceptance_rate;
|
|
@@ -271,9 +671,9 @@ function buildPredictions(blindSpots, activity, toolStats) {
|
|
|
271
671
|
}
|
|
272
672
|
}
|
|
273
673
|
if (activity.length > 0) {
|
|
274
|
-
const
|
|
275
|
-
if (
|
|
276
|
-
lines.push(
|
|
674
|
+
const lastScan = activity[0];
|
|
675
|
+
if (lastScan.completed_at) {
|
|
676
|
+
lines.push(`Last scan: ${formatRelativeTime(lastScan.completed_at)}`);
|
|
277
677
|
}
|
|
278
678
|
}
|
|
279
679
|
if (lines.length === 0) {
|
|
@@ -322,4 +722,58 @@ function safeJson(val) {
|
|
|
322
722
|
return val;
|
|
323
723
|
}
|
|
324
724
|
}
|
|
725
|
+
exports.DEFAULT_STALE_DAYS = 7;
|
|
726
|
+
exports.DEFAULT_EXPIRED_DAYS = 30;
|
|
727
|
+
function getStalenessStatus(timestamp, staleDays = exports.DEFAULT_STALE_DAYS, expiredDays = exports.DEFAULT_EXPIRED_DAYS) {
|
|
728
|
+
if (!timestamp)
|
|
729
|
+
return 'unknown';
|
|
730
|
+
const t = new Date(timestamp).getTime();
|
|
731
|
+
if (!Number.isFinite(t))
|
|
732
|
+
return 'unknown';
|
|
733
|
+
const ageMs = Date.now() - t;
|
|
734
|
+
if (ageMs < 0)
|
|
735
|
+
return 'fresh';
|
|
736
|
+
const days = ageMs / (1000 * 60 * 60 * 24);
|
|
737
|
+
if (days < staleDays)
|
|
738
|
+
return 'fresh';
|
|
739
|
+
if (days < expiredDays)
|
|
740
|
+
return 'stale';
|
|
741
|
+
return 'expired';
|
|
742
|
+
}
|
|
743
|
+
function daysSince(timestamp) {
|
|
744
|
+
if (!timestamp)
|
|
745
|
+
return null;
|
|
746
|
+
const t = new Date(timestamp).getTime();
|
|
747
|
+
if (!Number.isFinite(t))
|
|
748
|
+
return null;
|
|
749
|
+
const days = (Date.now() - t) / (1000 * 60 * 60 * 24);
|
|
750
|
+
return Math.max(0, Math.round(days * 10) / 10);
|
|
751
|
+
}
|
|
752
|
+
function buildStalenessInfo(profile, recentActivity) {
|
|
753
|
+
const profileTs = profile.scanned_at || undefined;
|
|
754
|
+
const scanTs = recentActivity[0]?.completed_at || undefined;
|
|
755
|
+
const profileLevel = getStalenessStatus(profileTs);
|
|
756
|
+
const scanLevel = getStalenessStatus(scanTs);
|
|
757
|
+
const daysSinceProfile = daysSince(profileTs);
|
|
758
|
+
const daysSinceScan = daysSince(scanTs);
|
|
759
|
+
const shouldRescan = profileLevel === 'stale' || profileLevel === 'expired' || scanLevel === 'stale' || scanLevel === 'expired';
|
|
760
|
+
let warning = null;
|
|
761
|
+
if (profileLevel === 'expired') {
|
|
762
|
+
warning = `Profile is ${daysSinceProfile ?? '?'} days old — run \`cell scan\` to refresh (context may be outdated)`;
|
|
763
|
+
}
|
|
764
|
+
else if (profileLevel === 'stale') {
|
|
765
|
+
warning = `Profile is ${daysSinceProfile ?? '?'} days old — consider running \`cell scan\` to keep context fresh`;
|
|
766
|
+
}
|
|
767
|
+
else if (scanLevel === 'expired' || scanLevel === 'stale') {
|
|
768
|
+
warning = `Last scan is ${daysSinceScan ?? '?'} days old — run \`cell scan\` to refresh`;
|
|
769
|
+
}
|
|
770
|
+
return {
|
|
771
|
+
profile: profileLevel,
|
|
772
|
+
scan: scanLevel,
|
|
773
|
+
daysSinceProfile,
|
|
774
|
+
daysSinceScan,
|
|
775
|
+
shouldRescan,
|
|
776
|
+
warning,
|
|
777
|
+
};
|
|
778
|
+
}
|
|
325
779
|
//# sourceMappingURL=prompt-builder.js.map
|