fivocell 4.0.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.
Files changed (163) hide show
  1. package/dist/__tests__/behavior-intelligence-bug.test.d.ts +2 -0
  2. package/dist/__tests__/behavior-intelligence-bug.test.d.ts.map +1 -0
  3. package/dist/__tests__/behavior-intelligence-bug.test.js +21 -0
  4. package/dist/__tests__/behavior-intelligence-bug.test.js.map +1 -0
  5. package/dist/__tests__/code-scanner-arrow-return-type.test.d.ts +2 -0
  6. package/dist/__tests__/code-scanner-arrow-return-type.test.d.ts.map +1 -0
  7. package/dist/__tests__/code-scanner-arrow-return-type.test.js +76 -0
  8. package/dist/__tests__/code-scanner-arrow-return-type.test.js.map +1 -0
  9. package/dist/__tests__/code-scanner-blindspot.test.d.ts +2 -0
  10. package/dist/__tests__/code-scanner-blindspot.test.d.ts.map +1 -0
  11. package/dist/__tests__/code-scanner-blindspot.test.js +18 -0
  12. package/dist/__tests__/code-scanner-blindspot.test.js.map +1 -0
  13. package/dist/__tests__/code-scanner-error-recovery.test.d.ts +2 -0
  14. package/dist/__tests__/code-scanner-error-recovery.test.d.ts.map +1 -0
  15. package/dist/__tests__/code-scanner-error-recovery.test.js +21 -0
  16. package/dist/__tests__/code-scanner-error-recovery.test.js.map +1 -0
  17. package/dist/__tests__/code-scanner-n1-detection.test.d.ts +2 -0
  18. package/dist/__tests__/code-scanner-n1-detection.test.d.ts.map +1 -0
  19. package/dist/__tests__/code-scanner-n1-detection.test.js +113 -0
  20. package/dist/__tests__/code-scanner-n1-detection.test.js.map +1 -0
  21. package/dist/__tests__/code-scanner-nesting.test.d.ts +2 -0
  22. package/dist/__tests__/code-scanner-nesting.test.d.ts.map +1 -0
  23. package/dist/__tests__/code-scanner-nesting.test.js +113 -0
  24. package/dist/__tests__/code-scanner-nesting.test.js.map +1 -0
  25. package/dist/__tests__/code-scanner-null-check.test.d.ts +2 -0
  26. package/dist/__tests__/code-scanner-null-check.test.d.ts.map +1 -0
  27. package/dist/__tests__/code-scanner-null-check.test.js +126 -0
  28. package/dist/__tests__/code-scanner-null-check.test.js.map +1 -0
  29. package/dist/__tests__/code-scanner-sql-fix.test.d.ts +2 -0
  30. package/dist/__tests__/code-scanner-sql-fix.test.d.ts.map +1 -0
  31. package/dist/__tests__/code-scanner-sql-fix.test.js +21 -0
  32. package/dist/__tests__/code-scanner-sql-fix.test.js.map +1 -0
  33. package/dist/__tests__/code-scanner-trust-score.test.d.ts +1 -0
  34. package/dist/__tests__/code-scanner-trust-score.test.d.ts.map +1 -0
  35. package/dist/__tests__/code-scanner-trust-score.test.js +39 -0
  36. package/dist/__tests__/code-scanner-trust-score.test.js.map +1 -0
  37. package/dist/__tests__/code-scanner-validation.test.d.ts +2 -0
  38. package/dist/__tests__/code-scanner-validation.test.d.ts.map +1 -0
  39. package/dist/__tests__/code-scanner-validation.test.js +131 -0
  40. package/dist/__tests__/code-scanner-validation.test.js.map +1 -0
  41. package/dist/__tests__/community-store.test.d.ts +2 -0
  42. package/dist/__tests__/community-store.test.d.ts.map +1 -0
  43. package/dist/__tests__/community-store.test.js +231 -0
  44. package/dist/__tests__/community-store.test.js.map +1 -0
  45. package/dist/__tests__/enhanced-blind-spots.test.d.ts +2 -0
  46. package/dist/__tests__/enhanced-blind-spots.test.d.ts.map +1 -0
  47. package/dist/__tests__/enhanced-blind-spots.test.js +302 -0
  48. package/dist/__tests__/enhanced-blind-spots.test.js.map +1 -0
  49. package/dist/__tests__/knowledge-graph-store.test.d.ts +2 -0
  50. package/dist/__tests__/knowledge-graph-store.test.d.ts.map +1 -0
  51. package/dist/__tests__/knowledge-graph-store.test.js +252 -0
  52. package/dist/__tests__/knowledge-graph-store.test.js.map +1 -0
  53. package/dist/__tests__/live-watcher.test.d.ts +2 -0
  54. package/dist/__tests__/live-watcher.test.d.ts.map +1 -0
  55. package/dist/__tests__/live-watcher.test.js +312 -0
  56. package/dist/__tests__/live-watcher.test.js.map +1 -0
  57. package/dist/__tests__/mcp-cell-tools.test.d.ts +2 -0
  58. package/dist/__tests__/mcp-cell-tools.test.d.ts.map +1 -0
  59. package/dist/__tests__/mcp-cell-tools.test.js +176 -0
  60. package/dist/__tests__/mcp-cell-tools.test.js.map +1 -0
  61. package/dist/__tests__/multi-project.test.d.ts +2 -0
  62. package/dist/__tests__/multi-project.test.d.ts.map +1 -0
  63. package/dist/__tests__/multi-project.test.js +145 -0
  64. package/dist/__tests__/multi-project.test.js.map +1 -0
  65. package/dist/__tests__/pc-scanner-paths.test.d.ts +2 -0
  66. package/dist/__tests__/pc-scanner-paths.test.d.ts.map +1 -0
  67. package/dist/__tests__/pc-scanner-paths.test.js +16 -0
  68. package/dist/__tests__/pc-scanner-paths.test.js.map +1 -0
  69. package/dist/__tests__/prompt-builder-realdata.test.d.ts +2 -0
  70. package/dist/__tests__/prompt-builder-realdata.test.d.ts.map +1 -0
  71. package/dist/__tests__/prompt-builder-realdata.test.js +94 -0
  72. package/dist/__tests__/prompt-builder-realdata.test.js.map +1 -0
  73. package/dist/__tests__/prompt-builder-sessions.test.d.ts +2 -0
  74. package/dist/__tests__/prompt-builder-sessions.test.d.ts.map +1 -0
  75. package/dist/__tests__/prompt-builder-sessions.test.js +124 -0
  76. package/dist/__tests__/prompt-builder-sessions.test.js.map +1 -0
  77. package/dist/__tests__/security.test.d.ts +1 -0
  78. package/dist/__tests__/security.test.d.ts.map +1 -0
  79. package/dist/__tests__/security.test.js +161 -0
  80. package/dist/__tests__/security.test.js.map +1 -0
  81. package/dist/__tests__/session-bridge.test.d.ts +2 -0
  82. package/dist/__tests__/session-bridge.test.d.ts.map +1 -0
  83. package/dist/__tests__/session-bridge.test.js +158 -0
  84. package/dist/__tests__/session-bridge.test.js.map +1 -0
  85. package/dist/__tests__/session-memory-tables.test.d.ts +2 -0
  86. package/dist/__tests__/session-memory-tables.test.d.ts.map +1 -0
  87. package/dist/__tests__/session-memory-tables.test.js +169 -0
  88. package/dist/__tests__/session-memory-tables.test.js.map +1 -0
  89. package/dist/__tests__/staleness-detection.test.d.ts +2 -0
  90. package/dist/__tests__/staleness-detection.test.d.ts.map +1 -0
  91. package/dist/__tests__/staleness-detection.test.js +105 -0
  92. package/dist/__tests__/staleness-detection.test.js.map +1 -0
  93. package/dist/__tests__/team-collaboration.test.d.ts +2 -0
  94. package/dist/__tests__/team-collaboration.test.d.ts.map +1 -0
  95. package/dist/__tests__/team-collaboration.test.js +224 -0
  96. package/dist/__tests__/team-collaboration.test.js.map +1 -0
  97. package/dist/__tests__/tool-specific-format.test.d.ts +2 -0
  98. package/dist/__tests__/tool-specific-format.test.d.ts.map +1 -0
  99. package/dist/__tests__/tool-specific-format.test.js +132 -0
  100. package/dist/__tests__/tool-specific-format.test.js.map +1 -0
  101. package/dist/__tests__/usage-intelligence-store.test.d.ts +2 -0
  102. package/dist/__tests__/usage-intelligence-store.test.d.ts.map +1 -0
  103. package/dist/__tests__/usage-intelligence-store.test.js +266 -0
  104. package/dist/__tests__/usage-intelligence-store.test.js.map +1 -0
  105. package/dist/behavior-intelligence.d.ts.map +1 -1
  106. package/dist/behavior-intelligence.js +12 -1
  107. package/dist/behavior-intelligence.js.map +1 -1
  108. package/dist/cli.js +368 -1
  109. package/dist/cli.js.map +1 -1
  110. package/dist/code-scanner.d.ts.map +1 -1
  111. package/dist/code-scanner.js +301 -97
  112. package/dist/code-scanner.js.map +1 -1
  113. package/dist/core/community-store.d.ts +128 -0
  114. package/dist/core/community-store.d.ts.map +1 -0
  115. package/dist/core/community-store.js +329 -0
  116. package/dist/core/community-store.js.map +1 -0
  117. package/dist/core/database.d.ts +0 -3
  118. package/dist/core/database.d.ts.map +1 -1
  119. package/dist/core/database.js +287 -15
  120. package/dist/core/database.js.map +1 -1
  121. package/dist/core/enhanced-blind-spots.d.ts +27 -0
  122. package/dist/core/enhanced-blind-spots.d.ts.map +1 -0
  123. package/dist/core/enhanced-blind-spots.js +591 -0
  124. package/dist/core/enhanced-blind-spots.js.map +1 -0
  125. package/dist/core/knowledge-graph-store.d.ts +69 -0
  126. package/dist/core/knowledge-graph-store.d.ts.map +1 -0
  127. package/dist/core/knowledge-graph-store.js +269 -0
  128. package/dist/core/knowledge-graph-store.js.map +1 -0
  129. package/dist/core/live-watcher.d.ts +52 -0
  130. package/dist/core/live-watcher.d.ts.map +1 -0
  131. package/dist/core/live-watcher.js +369 -0
  132. package/dist/core/live-watcher.js.map +1 -0
  133. package/dist/core/project-registry.d.ts +24 -0
  134. package/dist/core/project-registry.d.ts.map +1 -0
  135. package/dist/core/project-registry.js +70 -0
  136. package/dist/core/project-registry.js.map +1 -0
  137. package/dist/core/prompt-builder.d.ts +49 -0
  138. package/dist/core/prompt-builder.d.ts.map +1 -1
  139. package/dist/core/prompt-builder.js +482 -67
  140. package/dist/core/prompt-builder.js.map +1 -1
  141. package/dist/core/security.d.ts +23 -0
  142. package/dist/core/security.d.ts.map +1 -0
  143. package/dist/core/security.js +117 -0
  144. package/dist/core/security.js.map +1 -0
  145. package/dist/core/session-memory.d.ts +64 -0
  146. package/dist/core/session-memory.d.ts.map +1 -1
  147. package/dist/core/session-memory.js +111 -0
  148. package/dist/core/session-memory.js.map +1 -1
  149. package/dist/core/usage-intelligence-store.d.ts +126 -0
  150. package/dist/core/usage-intelligence-store.d.ts.map +1 -0
  151. package/dist/core/usage-intelligence-store.js +405 -0
  152. package/dist/core/usage-intelligence-store.js.map +1 -0
  153. package/dist/daemon/server.d.ts.map +1 -1
  154. package/dist/daemon/server.js +936 -17
  155. package/dist/daemon/server.js.map +1 -1
  156. package/dist/knowledge-graph-builder.d.ts.map +1 -1
  157. package/dist/knowledge-graph-builder.js +18 -2
  158. package/dist/knowledge-graph-builder.js.map +1 -1
  159. package/dist/pc-scanner.d.ts +1 -0
  160. package/dist/pc-scanner.d.ts.map +1 -1
  161. package/dist/pc-scanner.js +58 -30
  162. package/dist/pc-scanner.js.map +1 -1
  163. package/package.json +1 -1
@@ -1,27 +1,35 @@
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
20
  const stackDNA = readStackDNA(db, projectPath);
18
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);
19
26
  const whoYouAre = buildWhoYouAre(profile, skills, collaborators, stackDNA, blindSpots);
20
- const rightNow = buildRightNow(recentActivity, profile);
27
+ const rightNow = buildRightNow(recentActivity, profile, lastSession);
21
28
  const yourStyle = buildYourStyle(topPatterns, profile, skills);
22
29
  const watchOut = buildWatchOut(blindSpots, profile);
23
30
  const predictions = buildPredictions(blindSpots, recentActivity, toolStats);
24
31
  const toolHint = toolName ? buildToolHint(toolName) : undefined;
32
+ const staleness = buildStalenessInfo(profile, recentActivity);
25
33
  return {
26
34
  whoYouAre,
27
35
  rightNow,
@@ -31,6 +39,11 @@ function buildContext(projectPath, toolName) {
31
39
  dbPredictions,
32
40
  injectedAt: new Date().toISOString(),
33
41
  toolHint,
42
+ lastSession,
43
+ triedApproaches,
44
+ mostTouchedFiles,
45
+ openQuestions,
46
+ staleness,
34
47
  };
35
48
  }
36
49
  function formatContextForInjection(ctx, compact = false) {
@@ -39,20 +52,77 @@ function formatContextForInjection(ctx, compact = false) {
39
52
  }
40
53
  return fullContext(ctx);
41
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
+ }
42
76
  function estimateTokens(text) {
43
77
  return Math.ceil(text.length / 4);
44
78
  }
45
79
  function fullContext(ctx) {
46
80
  let out = '';
47
- out += '═══ CELL CONTEXT ═══\n\n';
81
+ out += '━━━ CELL CONTEXT ━━━\n\n';
82
+ if (ctx.staleness?.warning) {
83
+ out += '⚠ ' + ctx.staleness.warning + '\n\n';
84
+ }
48
85
  out += '▸ WHO YOU ARE\n';
49
86
  out += ctx.whoYouAre + '\n\n';
50
87
  out += '▸ RIGHT NOW\n';
51
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
+ }
52
115
  out += '▸ YOUR STYLE\n';
53
116
  out += ctx.yourStyle + '\n\n';
54
117
  out += '▸ WATCH OUT\n';
55
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
+ }
56
126
  out += '▸ PREDICTIONS\n';
57
127
  out += ctx.predictions;
58
128
  if (ctx.toolHint) {
@@ -62,10 +132,21 @@ function fullContext(ctx) {
62
132
  }
63
133
  function compactContext(ctx) {
64
134
  let out = '';
135
+ if (ctx.staleness?.warning) {
136
+ out += '⚠ ' + ctx.staleness.warning + '\n\n';
137
+ }
65
138
  out += '## Developer Context\n';
66
139
  out += ctx.whoYouAre.replace(/\n/g, ' | ') + '\n\n';
67
140
  out += '### Current\n';
68
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
+ }
69
150
  out += '### Style\n';
70
151
  out += ctx.yourStyle.replace(/\n/g, ' | ') + '\n\n';
71
152
  out += '### Blind Spots\n';
@@ -77,16 +158,142 @@ function compactContext(ctx) {
77
158
  }
78
159
  return out;
79
160
  }
80
- function readProfile(db) {
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) {
81
271
  try {
82
- const row = db.prepare('SELECT * FROM user_profile WHERE id = 1').get();
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();
83
275
  if (row) {
84
276
  return {
85
- name: row.name || '',
86
- products: safeJson(row.products),
87
- stack: safeJson(row.stack),
88
- workStyle: safeJson(row.work_style),
89
- preferences: safeJson(row.preferences),
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 || '',
90
297
  };
91
298
  }
92
299
  }
@@ -95,17 +302,23 @@ function readProfile(db) {
95
302
  }
96
303
  return {};
97
304
  }
98
- function readBlindSpots(db) {
305
+ function readBlindSpots(db, projectPath) {
99
306
  try {
100
- return db.prepare("SELECT * FROM behavior_events WHERE event_type IN ('blind_spot','repeat_mistake') ORDER BY created_at DESC LIMIT 10").all();
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();
101
311
  }
102
312
  catch {
103
313
  return [];
104
314
  }
105
315
  }
106
- function readTopPatterns(db) {
316
+ function readTopPatterns(db, projectPath) {
107
317
  try {
108
- return db.prepare('SELECT category, rule, confidence, reuse_count FROM patterns ORDER BY confidence DESC, reuse_count DESC LIMIT 15').all();
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();
109
322
  }
110
323
  catch {
111
324
  return [];
@@ -114,9 +327,9 @@ function readTopPatterns(db) {
114
327
  function readRecentActivity(db, projectPath) {
115
328
  try {
116
329
  if (projectPath) {
117
- return db.prepare('SELECT * FROM signals WHERE project = ? ORDER BY created_at DESC LIMIT 10').all(projectPath);
330
+ return db.prepare('SELECT * FROM scans WHERE project = ? ORDER BY completed_at DESC LIMIT 5').all(projectPath);
118
331
  }
119
- return db.prepare('SELECT * FROM signals ORDER BY created_at DESC LIMIT 10').all();
332
+ return db.prepare('SELECT * FROM scans ORDER BY completed_at DESC LIMIT 5').all();
120
333
  }
121
334
  catch {
122
335
  return [];
@@ -170,9 +383,118 @@ function readPredictions(db, projectPath) {
170
383
  return [];
171
384
  }
172
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
+ }
173
491
  function buildWhoYouAre(profile, skills, collaborators, stackDNA, blindSpots) {
174
492
  const lines = [];
175
- // Stack fingerprint
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
+ }
176
498
  if (stackDNA && typeof stackDNA === 'object') {
177
499
  const s = stackDNA;
178
500
  const parts = [];
@@ -200,37 +522,76 @@ function buildWhoYouAre(profile, skills, collaborators, stackDNA, blindSpots) {
200
522
  const names = collaborators.slice(0, 3).map((c) => c.name).filter(Boolean);
201
523
  lines.push(`Team: ${names.join(', ')} (${collaborators.length} total)`);
202
524
  }
203
- // Blind spots summary
525
+ const strengths = profile.strengths || [];
526
+ if (strengths.length > 0) {
527
+ lines.push(`Strengths: ${strengths.slice(0, 3).join(' · ')}`);
528
+ }
204
529
  if (blindSpots && blindSpots.length > 0) {
205
- const top = blindSpots.slice(0, 3).map(b => b.pattern_value || b.description || '').filter(Boolean);
530
+ const top = blindSpots.slice(0, 3).map(b => `${b.pattern_value || b.description || 'unknown'} (${b.count || 0}x)`).filter(Boolean);
206
531
  if (top.length > 0)
207
- lines.push(`⚠ ${top.join(' | ')}`);
532
+ lines.push(`⚠ Blind spots: ${top.join(' | ')}`);
208
533
  }
209
534
  if (lines.length === 0) {
210
535
  lines.push('Developer profile — run `cell scan` to build profile');
211
536
  }
212
537
  return lines.join('\n');
213
538
  }
214
- function buildRightNow(activity, profile) {
539
+ function buildRightNow(activity, profile, lastSession) {
215
540
  const lines = [];
216
- if (activity.length > 0) {
217
- const lastSignal = activity[0];
218
- lines.push(`Last activity: ${lastSignal.signal_type || 'unknown'} on ${lastSignal.file_path || 'unknown file'}`);
219
- lines.push(`Last active: ${formatRelativeTime(lastSignal.created_at)}`);
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
+ }
220
563
  }
221
564
  else {
222
565
  lines.push('No recent activity detected');
223
566
  lines.push('Run `cell scan` to refresh');
224
567
  }
225
- const products = profile.products || [];
226
- if (products.length > 0) {
227
- const latest = products[products.length - 1];
228
- 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)}`);
229
570
  }
230
571
  return lines.join('\n');
231
572
  }
232
573
  function buildYourStyle(patterns, profile, skills) {
233
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
+ }
234
595
  const categories = new Map();
235
596
  for (const p of patterns) {
236
597
  const cat = String(p.category || '');
@@ -240,65 +601,65 @@ function buildYourStyle(patterns, profile, skills) {
240
601
  if (sortedCats.length > 0) {
241
602
  lines.push(`Top patterns: ${sortedCats.map(([c, n]) => `${c}(${n})`).join(', ')}`);
242
603
  }
243
- const topRules = patterns.slice(0, 5).map((p) => p.rule).filter(Boolean);
244
- if (topRules.length > 0) {
245
- lines.push('Style preferences:');
246
- for (const r of topRules) {
247
- lines.push(` - ${r}`);
248
- }
249
- }
250
604
  const doList = [];
251
- const dontList = [];
252
605
  for (const p of patterns) {
253
- const rule = String(p.rule || '');
606
+ const rule = String(p.pattern_value || '');
254
607
  const cat = String(p.category || '');
255
- if (cat === 'typescript_strict' || rule.includes('TypeScript') || rule.includes('type')) {
608
+ if (cat === 'typescript_strict' || rule.toLowerCase().includes('type')) {
256
609
  doList.push('DO: TypeScript strict mode');
257
610
  }
258
- if (cat === 'async_await' || rule.includes('async')) {
611
+ if (cat === 'async' || rule.toLowerCase().includes('async') || profile.async_style === 'uses-async') {
259
612
  doList.push('DO: Use async/await, not .then()');
260
613
  }
261
- if (cat === 'null_safety' || rule.includes('optional chaining')) {
614
+ if (cat === 'null_safety' || rule.toLowerCase().includes('optional')) {
262
615
  doList.push('DO: Use optional chaining');
263
616
  }
264
- if (cat === 'destructuring' || rule.includes('destructuring')) {
617
+ if (cat === 'destructuring' || rule.toLowerCase().includes('destructur')) {
265
618
  doList.push('DO: Use destructuring over index access');
266
619
  }
267
620
  }
268
- const unique = new Set(doList);
269
- if (unique.size > 0)
270
- lines.push([...unique].join('\n'));
271
- dontList.push('DON\'T: Suggest MongoDB (uses PostgreSQL)');
272
- dontList.push('DON\'T: Suggest large monolithic functions');
273
- dontList.push('DON\'T: Suggest var over const/let');
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');
274
632
  return lines.join('\n');
275
633
  }
276
634
  function buildWatchOut(blindSpots, profile) {
277
635
  const lines = [];
278
- const spots = blindSpots.filter((b) => b.severity === 'high' || b.severity === 'critical');
279
- if (spots.length === 0 && blindSpots.length === 0) {
280
- lines.push('Run `cell scan` to detect blind spots');
281
- 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');
282
639
  return lines.join('\n');
283
640
  }
284
- lines.push('Top blind spots:');
641
+ lines.push(`Top blind spots (${blindSpots.length} total):`);
285
642
  const top = blindSpots.slice(0, 5);
286
643
  for (const s of top) {
287
- 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;
288
647
  if (desc)
289
- lines.push(` - [${s.severity || 'unknown'}] ${desc}`);
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));
290
655
  }
291
- lines.push('Always flag if:');
292
- lines.push(' - async function missing try/catch');
293
- lines.push(' - API response used without null check');
294
- lines.push(' - Database operation without validation');
295
656
  return lines.join('\n');
296
657
  }
297
658
  function buildPredictions(blindSpots, activity, toolStats) {
298
659
  const lines = [];
299
- const highSeverity = blindSpots.filter((b) => b.severity === 'high' || b.severity === 'critical').length;
300
- if (highSeverity > 2) {
301
- lines.push(`⚠ ${highSeverity} high-severity blind spots detected`);
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`);
302
663
  }
303
664
  if (toolStats) {
304
665
  const acceptRate = toolStats.acceptance_rate;
@@ -310,9 +671,9 @@ function buildPredictions(blindSpots, activity, toolStats) {
310
671
  }
311
672
  }
312
673
  if (activity.length > 0) {
313
- const lastType = String(activity[0].signal_type || '');
314
- if (lastType === 'reject' || lastType === 'retry') {
315
- lines.push('⚠ Last action was rejected/retried — be more careful with suggestions');
674
+ const lastScan = activity[0];
675
+ if (lastScan.completed_at) {
676
+ lines.push(`Last scan: ${formatRelativeTime(lastScan.completed_at)}`);
316
677
  }
317
678
  }
318
679
  if (lines.length === 0) {
@@ -361,4 +722,58 @@ function safeJson(val) {
361
722
  return val;
362
723
  }
363
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
+ }
364
779
  //# sourceMappingURL=prompt-builder.js.map