@triedotdev/mcp 1.0.169 → 1.0.171

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 (145) hide show
  1. package/README.md +62 -540
  2. package/dist/chunk-2YXOBNKW.js +619 -0
  3. package/dist/chunk-2YXOBNKW.js.map +1 -0
  4. package/dist/chunk-QR64Y5TI.js +363 -0
  5. package/dist/chunk-QR64Y5TI.js.map +1 -0
  6. package/dist/cli/main.d.ts +0 -15
  7. package/dist/cli/main.js +356 -3098
  8. package/dist/cli/main.js.map +1 -1
  9. package/dist/index.js +2 -34
  10. package/dist/index.js.map +1 -1
  11. package/dist/server/mcp-server.js +2 -34
  12. package/package.json +8 -31
  13. package/dist/autonomy-config-FSERX3O3.js +0 -30
  14. package/dist/autonomy-config-FSERX3O3.js.map +0 -1
  15. package/dist/chat-store-JNGNTDSN.js +0 -15
  16. package/dist/chat-store-JNGNTDSN.js.map +0 -1
  17. package/dist/chunk-2HF65EHQ.js +0 -311
  18. package/dist/chunk-2HF65EHQ.js.map +0 -1
  19. package/dist/chunk-3XR6WVAW.js +0 -4011
  20. package/dist/chunk-3XR6WVAW.js.map +0 -1
  21. package/dist/chunk-43X6JBEM.js +0 -36
  22. package/dist/chunk-43X6JBEM.js.map +0 -1
  23. package/dist/chunk-6NLHFIYA.js +0 -344
  24. package/dist/chunk-6NLHFIYA.js.map +0 -1
  25. package/dist/chunk-7IO4YUI3.js +0 -1827
  26. package/dist/chunk-7IO4YUI3.js.map +0 -1
  27. package/dist/chunk-AHD2CBQ7.js +0 -846
  28. package/dist/chunk-AHD2CBQ7.js.map +0 -1
  29. package/dist/chunk-BUTOP5EB.js +0 -931
  30. package/dist/chunk-BUTOP5EB.js.map +0 -1
  31. package/dist/chunk-DGUM43GV.js +0 -11
  32. package/dist/chunk-DGUM43GV.js.map +0 -1
  33. package/dist/chunk-EFWVF6TI.js +0 -267
  34. package/dist/chunk-EFWVF6TI.js.map +0 -1
  35. package/dist/chunk-F6WFNUAY.js +0 -216
  36. package/dist/chunk-F6WFNUAY.js.map +0 -1
  37. package/dist/chunk-FBNURWRY.js +0 -662
  38. package/dist/chunk-FBNURWRY.js.map +0 -1
  39. package/dist/chunk-FQ45QP5A.js +0 -361
  40. package/dist/chunk-FQ45QP5A.js.map +0 -1
  41. package/dist/chunk-FVRO5RN3.js +0 -1306
  42. package/dist/chunk-FVRO5RN3.js.map +0 -1
  43. package/dist/chunk-G2TGF6TR.js +0 -573
  44. package/dist/chunk-G2TGF6TR.js.map +0 -1
  45. package/dist/chunk-G3I7SZLW.js +0 -354
  46. package/dist/chunk-G3I7SZLW.js.map +0 -1
  47. package/dist/chunk-GTKYBOXL.js +0 -700
  48. package/dist/chunk-GTKYBOXL.js.map +0 -1
  49. package/dist/chunk-HVCDY3AK.js +0 -850
  50. package/dist/chunk-HVCDY3AK.js.map +0 -1
  51. package/dist/chunk-I2O5OYQT.js +0 -727
  52. package/dist/chunk-I2O5OYQT.js.map +0 -1
  53. package/dist/chunk-JVMBCWKS.js +0 -348
  54. package/dist/chunk-JVMBCWKS.js.map +0 -1
  55. package/dist/chunk-KCUOWRPX.js +0 -816
  56. package/dist/chunk-KCUOWRPX.js.map +0 -1
  57. package/dist/chunk-KDHN2ZQE.js +0 -313
  58. package/dist/chunk-KDHN2ZQE.js.map +0 -1
  59. package/dist/chunk-ME2OERF5.js +0 -345
  60. package/dist/chunk-ME2OERF5.js.map +0 -1
  61. package/dist/chunk-OBQ74FOU.js +0 -27
  62. package/dist/chunk-OBQ74FOU.js.map +0 -1
  63. package/dist/chunk-Q5EKA5YA.js +0 -254
  64. package/dist/chunk-Q5EKA5YA.js.map +0 -1
  65. package/dist/chunk-Q63FFI6D.js +0 -132
  66. package/dist/chunk-Q63FFI6D.js.map +0 -1
  67. package/dist/chunk-SASNMSB5.js +0 -12597
  68. package/dist/chunk-SASNMSB5.js.map +0 -1
  69. package/dist/chunk-T63OHG4Q.js +0 -440
  70. package/dist/chunk-T63OHG4Q.js.map +0 -1
  71. package/dist/chunk-TN5WEKWI.js +0 -173
  72. package/dist/chunk-TN5WEKWI.js.map +0 -1
  73. package/dist/chunk-VUL52BQL.js +0 -402
  74. package/dist/chunk-VUL52BQL.js.map +0 -1
  75. package/dist/chunk-VVITXIHN.js +0 -189
  76. package/dist/chunk-VVITXIHN.js.map +0 -1
  77. package/dist/chunk-WCN7S3EI.js +0 -14
  78. package/dist/chunk-WCN7S3EI.js.map +0 -1
  79. package/dist/chunk-XPZZFPBZ.js +0 -491
  80. package/dist/chunk-XPZZFPBZ.js.map +0 -1
  81. package/dist/chunk-ZJF5FTBX.js +0 -1396
  82. package/dist/chunk-ZJF5FTBX.js.map +0 -1
  83. package/dist/chunk-ZV2K6M7T.js +0 -74
  84. package/dist/chunk-ZV2K6M7T.js.map +0 -1
  85. package/dist/cli/create-agent.d.ts +0 -1
  86. package/dist/cli/create-agent.js +0 -1050
  87. package/dist/cli/create-agent.js.map +0 -1
  88. package/dist/cli/yolo-daemon.d.ts +0 -1
  89. package/dist/cli/yolo-daemon.js +0 -421
  90. package/dist/cli/yolo-daemon.js.map +0 -1
  91. package/dist/client-NJPZE5JT.js +0 -28
  92. package/dist/client-NJPZE5JT.js.map +0 -1
  93. package/dist/codebase-index-VAPF32XX.js +0 -12
  94. package/dist/codebase-index-VAPF32XX.js.map +0 -1
  95. package/dist/fast-analyzer-3GCCZMLK.js +0 -216
  96. package/dist/fast-analyzer-3GCCZMLK.js.map +0 -1
  97. package/dist/git-EO5SRFMN.js +0 -28
  98. package/dist/git-EO5SRFMN.js.map +0 -1
  99. package/dist/github-ingester-ZOKK6GRS.js +0 -11
  100. package/dist/github-ingester-ZOKK6GRS.js.map +0 -1
  101. package/dist/goal-manager-QUKX2W6C.js +0 -25
  102. package/dist/goal-manager-QUKX2W6C.js.map +0 -1
  103. package/dist/goal-validator-2SFSKKVU.js +0 -24
  104. package/dist/goal-validator-2SFSKKVU.js.map +0 -1
  105. package/dist/graph-B3NA4S7I.js +0 -10
  106. package/dist/graph-B3NA4S7I.js.map +0 -1
  107. package/dist/hypothesis-KCPBR652.js +0 -23
  108. package/dist/hypothesis-KCPBR652.js.map +0 -1
  109. package/dist/incident-index-EFNUSGWL.js +0 -11
  110. package/dist/incident-index-EFNUSGWL.js.map +0 -1
  111. package/dist/insight-store-EC4PLSAW.js +0 -22
  112. package/dist/insight-store-EC4PLSAW.js.map +0 -1
  113. package/dist/issue-store-YAXTNRRY.js +0 -36
  114. package/dist/issue-store-YAXTNRRY.js.map +0 -1
  115. package/dist/ledger-TWZTGDFA.js +0 -58
  116. package/dist/ledger-TWZTGDFA.js.map +0 -1
  117. package/dist/linear-ingester-XXPAZZRW.js +0 -11
  118. package/dist/linear-ingester-XXPAZZRW.js.map +0 -1
  119. package/dist/output-manager-RVJ37XKA.js +0 -13
  120. package/dist/output-manager-RVJ37XKA.js.map +0 -1
  121. package/dist/parse-goal-violation-SACGFG3C.js +0 -8
  122. package/dist/parse-goal-violation-SACGFG3C.js.map +0 -1
  123. package/dist/pattern-discovery-F7LU5K6E.js +0 -8
  124. package/dist/pattern-discovery-F7LU5K6E.js.map +0 -1
  125. package/dist/progress-SRQ2V3BP.js +0 -18
  126. package/dist/progress-SRQ2V3BP.js.map +0 -1
  127. package/dist/project-state-AHPA77SM.js +0 -28
  128. package/dist/project-state-AHPA77SM.js.map +0 -1
  129. package/dist/sync-M2FSWPBC.js +0 -12
  130. package/dist/sync-M2FSWPBC.js.map +0 -1
  131. package/dist/terminal-spawn-5YXDMUCF.js +0 -157
  132. package/dist/terminal-spawn-5YXDMUCF.js.map +0 -1
  133. package/dist/tiered-storage-DYNC5CQ6.js +0 -13
  134. package/dist/tiered-storage-DYNC5CQ6.js.map +0 -1
  135. package/dist/trie-agent-I3HAHY2G.js +0 -26
  136. package/dist/trie-agent-I3HAHY2G.js.map +0 -1
  137. package/dist/ui/chat.html +0 -1014
  138. package/dist/ui/goals.html +0 -967
  139. package/dist/ui/hypotheses.html +0 -1011
  140. package/dist/ui/ledger.html +0 -954
  141. package/dist/ui/nudges.html +0 -995
  142. package/dist/vibe-code-signatures-5ZULYP3D.js +0 -987
  143. package/dist/vibe-code-signatures-5ZULYP3D.js.map +0 -1
  144. package/dist/vulnerability-signatures-2URZSXAQ.js +0 -983
  145. package/dist/vulnerability-signatures-2URZSXAQ.js.map +0 -1
@@ -1,440 +0,0 @@
1
- import {
2
- BackupManager,
3
- safeParseAndValidate
4
- } from "./chunk-EFWVF6TI.js";
5
- import {
6
- atomicWriteJSON
7
- } from "./chunk-43X6JBEM.js";
8
- import {
9
- getTrieDirectory
10
- } from "./chunk-VVITXIHN.js";
11
-
12
- // src/agent/insight-store.ts
13
- import { mkdir, readFile } from "fs/promises";
14
- import { existsSync } from "fs";
15
- import { join } from "path";
16
- import { z } from "zod";
17
- var InsightDetailsSchema = z.object({
18
- affectedFiles: z.array(z.string()).optional(),
19
- issueBreakdown: z.record(z.string(), z.number()).optional(),
20
- examples: z.array(z.string()).optional(),
21
- trend: z.enum(["improving", "stable", "worsening"]).optional(),
22
- comparison: z.string().optional(),
23
- resolvedCount: z.number().optional(),
24
- resolvedIssues: z.array(z.object({
25
- file: z.string(),
26
- line: z.number().optional(),
27
- issue: z.string(),
28
- agent: z.string(),
29
- resolvedAt: z.string().optional()
30
- })).optional(),
31
- summary: z.string().optional(),
32
- // Hypothesis-related fields
33
- hypothesis: z.string().optional(),
34
- testCriteria: z.string().optional(),
35
- confidence: z.number().optional(),
36
- // Pattern-related fields
37
- patternsCount: z.number().optional(),
38
- topPattern: z.string().optional()
39
- });
40
- var InsightSchema = z.object({
41
- id: z.string(),
42
- type: z.enum(["observation", "warning", "suggestion", "celebration", "question"]),
43
- message: z.string(),
44
- context: z.string().optional(),
45
- suggestedAction: z.string().optional(),
46
- actionCommand: z.string().optional(),
47
- relatedIssues: z.array(z.string()),
48
- priority: z.number().min(1).max(10),
49
- timestamp: z.number(),
50
- dismissed: z.boolean(),
51
- category: z.enum(["security", "quality", "performance", "pattern", "progress", "general"]),
52
- details: InsightDetailsSchema.optional()
53
- });
54
- var InsightStoreDataSchema = z.object({
55
- version: z.literal(1),
56
- insights: z.array(InsightSchema),
57
- cooldowns: z.record(z.string(), z.number()),
58
- // insightKey -> timestamp
59
- dismissedIds: z.array(z.string()),
60
- // Track dismissed insight IDs permanently
61
- lastUpdated: z.string()
62
- });
63
- var InsightStore = class _InsightStore {
64
- projectPath;
65
- data;
66
- loaded = false;
67
- dirty = false;
68
- // Default cooldown periods (in ms)
69
- static COOLDOWNS = {
70
- "pre-push-warning": 6e4,
71
- // 1 min between pre-push warnings
72
- "security-warning": 3e4,
73
- // 30s between security warnings
74
- "new-issues": 3e4,
75
- // 30s between new issue observations
76
- "celebration": 6e4,
77
- // 1 min between celebrations
78
- "pattern-suggestion": 12e4,
79
- // 2 min between pattern suggestions
80
- "accessibility-visual-qa": 3e5,
81
- // 5 min between visual QA suggestions
82
- "goal-suggestion": 3e5,
83
- // 5 min between goal suggestions
84
- "risk-prediction": 18e4,
85
- // 3 min between risk predictions
86
- "hypothesis-update": 6e5,
87
- // 10 min between hypothesis updates
88
- "auto-escalation": 3e5
89
- // 5 min between auto-escalations
90
- };
91
- constructor(projectPath) {
92
- this.projectPath = projectPath;
93
- this.data = this.createEmptyData();
94
- }
95
- /**
96
- * Get the storage file path
97
- */
98
- getStorePath() {
99
- return join(getTrieDirectory(this.projectPath), "memory", "insights.json");
100
- }
101
- /**
102
- * Create empty data structure
103
- */
104
- createEmptyData() {
105
- return {
106
- version: 1,
107
- insights: [],
108
- cooldowns: {},
109
- dismissedIds: [],
110
- lastUpdated: (/* @__PURE__ */ new Date()).toISOString()
111
- };
112
- }
113
- /**
114
- * Load insights from disk
115
- *
116
- * If the file is corrupted, attempts recovery from backup.
117
- * Returns empty data if no valid file/backup exists.
118
- */
119
- async load() {
120
- if (this.loaded) {
121
- return this.data;
122
- }
123
- const storePath = this.getStorePath();
124
- try {
125
- if (existsSync(storePath)) {
126
- const content = await readFile(storePath, "utf-8");
127
- const result = safeParseAndValidate(content, InsightStoreDataSchema);
128
- if (result.success) {
129
- this.data = result.data;
130
- this.loaded = true;
131
- this.deduplicateInsights();
132
- return this.data;
133
- }
134
- console.error(` Insight store corrupted: ${result.error}`);
135
- const backupManager = new BackupManager(storePath);
136
- if (await backupManager.recoverFromBackup()) {
137
- console.error(" Recovered from backup");
138
- const recovered = await readFile(storePath, "utf-8");
139
- const recoveredResult = safeParseAndValidate(recovered, InsightStoreDataSchema);
140
- if (recoveredResult.success) {
141
- this.data = recoveredResult.data;
142
- this.loaded = true;
143
- this.deduplicateInsights();
144
- return this.data;
145
- }
146
- }
147
- console.error(" No valid backup found, starting fresh");
148
- }
149
- } catch (error) {
150
- console.error(` Could not load insight store: ${error}`);
151
- }
152
- this.data = this.createEmptyData();
153
- this.loaded = true;
154
- return this.data;
155
- }
156
- /**
157
- * Deduplicate existing insights on load
158
- * Keeps the most recent instance of each unique insight
159
- */
160
- deduplicateInsights() {
161
- const seen = /* @__PURE__ */ new Map();
162
- const toRemove = [];
163
- for (let i = 0; i < this.data.insights.length; i++) {
164
- const insight = this.data.insights[i];
165
- if (!insight) continue;
166
- const contentKey = this.getContentKey(insight);
167
- if (seen.has(contentKey)) {
168
- toRemove.push(i);
169
- } else {
170
- seen.set(contentKey, i);
171
- }
172
- }
173
- if (toRemove.length > 0) {
174
- for (let i = toRemove.length - 1; i >= 0; i--) {
175
- const idx = toRemove[i];
176
- if (idx !== void 0) {
177
- this.data.insights.splice(idx, 1);
178
- }
179
- }
180
- this.dirty = true;
181
- }
182
- }
183
- /**
184
- * Save insights to disk
185
- *
186
- * Creates backup before writing, uses atomic write.
187
- */
188
- async save() {
189
- if (!this.dirty && this.loaded) {
190
- return;
191
- }
192
- const storePath = this.getStorePath();
193
- const memoryDir = join(getTrieDirectory(this.projectPath), "memory");
194
- await mkdir(memoryDir, { recursive: true });
195
- const backupManager = new BackupManager(storePath);
196
- await backupManager.createBackup();
197
- this.data.lastUpdated = (/* @__PURE__ */ new Date()).toISOString();
198
- await atomicWriteJSON(storePath, this.data);
199
- this.dirty = false;
200
- }
201
- /**
202
- * Generate a content-based key for deduplication
203
- * Insights with the same content key are considered duplicates
204
- */
205
- getContentKey(insight) {
206
- const normalizedMessage = insight.message.replace(/\d+/g, "N").toLowerCase().trim();
207
- return `${insight.type}:${insight.category}:${normalizedMessage}`;
208
- }
209
- /**
210
- * Add an insight to the store
211
- *
212
- * Checks for duplicates using both insight ID and content similarity.
213
- * If a similar insight already exists (same type, category, and normalized message),
214
- * updates its timestamp instead of creating a duplicate.
215
- * Respects cooldowns to prevent insight spam.
216
- */
217
- async addInsight(insight) {
218
- await this.load();
219
- if (this.data.insights.some((i) => i.id === insight.id)) {
220
- return false;
221
- }
222
- if (this.data.dismissedIds.includes(insight.id)) {
223
- return false;
224
- }
225
- const contentKey = this.getContentKey(insight);
226
- const existingIndex = this.data.insights.findIndex(
227
- (i) => !i.dismissed && this.getContentKey(i) === contentKey
228
- );
229
- if (existingIndex >= 0) {
230
- const existing = this.data.insights[existingIndex];
231
- if (existing) {
232
- existing.timestamp = insight.timestamp;
233
- existing.message = insight.message;
234
- existing.details = insight.details;
235
- existing.relatedIssues = insight.relatedIssues;
236
- existing.suggestedAction = insight.suggestedAction;
237
- this.data.insights.splice(existingIndex, 1);
238
- this.data.insights.unshift(existing);
239
- this.dirty = true;
240
- await this.save();
241
- }
242
- return false;
243
- }
244
- this.data.insights.unshift(insight);
245
- if (this.data.insights.length > 100) {
246
- this.data.insights = this.data.insights.slice(0, 100);
247
- }
248
- this.dirty = true;
249
- await this.save();
250
- return true;
251
- }
252
- /**
253
- * Check if a cooldown has expired for an insight type
254
- */
255
- canCreateInsight(insightKey) {
256
- const lastTime = this.data.cooldowns[insightKey];
257
- const cooldown = _InsightStore.COOLDOWNS[insightKey] || 3e4;
258
- if (!lastTime) return true;
259
- return Date.now() - lastTime > cooldown;
260
- }
261
- /**
262
- * Mark that an insight type was created (set cooldown)
263
- */
264
- async markInsightCreated(insightKey) {
265
- await this.load();
266
- this.data.cooldowns[insightKey] = Date.now();
267
- this.dirty = true;
268
- await this.save();
269
- }
270
- /**
271
- * Get active (non-dismissed) insights
272
- *
273
- * Returns insights sorted by priority (highest first),
274
- * limited to the specified count.
275
- */
276
- getActiveInsights(limit = 5) {
277
- return this.data.insights.filter((i) => !i.dismissed).sort((a, b) => b.priority - a.priority).slice(0, limit);
278
- }
279
- /**
280
- * Get all insights (including dismissed)
281
- */
282
- getAllInsights() {
283
- return [...this.data.insights];
284
- }
285
- /**
286
- * Dismiss an insight by ID
287
- */
288
- async dismissInsight(insightId) {
289
- await this.load();
290
- const insight = this.data.insights.find((i) => i.id === insightId);
291
- if (!insight) {
292
- return false;
293
- }
294
- insight.dismissed = true;
295
- if (!this.data.dismissedIds.includes(insightId)) {
296
- this.data.dismissedIds.push(insightId);
297
- if (this.data.dismissedIds.length > 500) {
298
- this.data.dismissedIds = this.data.dismissedIds.slice(-500);
299
- }
300
- }
301
- this.dirty = true;
302
- await this.save();
303
- return true;
304
- }
305
- /**
306
- * Remove an insight entirely
307
- */
308
- async removeInsight(insightId) {
309
- await this.load();
310
- const index = this.data.insights.findIndex((i) => i.id === insightId);
311
- if (index === -1) {
312
- return false;
313
- }
314
- this.data.insights.splice(index, 1);
315
- this.dirty = true;
316
- await this.save();
317
- return true;
318
- }
319
- /**
320
- * Clear all cooldowns
321
- */
322
- async clearCooldowns() {
323
- await this.load();
324
- this.data.cooldowns = {};
325
- this.dirty = true;
326
- await this.save();
327
- }
328
- /**
329
- * Get insight by ID
330
- */
331
- getInsight(insightId) {
332
- return this.data.insights.find((i) => i.id === insightId);
333
- }
334
- /**
335
- * Update an existing insight
336
- */
337
- async updateInsight(insightId, updates) {
338
- await this.load();
339
- const insight = this.data.insights.find((i) => i.id === insightId);
340
- if (!insight) {
341
- return false;
342
- }
343
- Object.assign(insight, updates);
344
- this.dirty = true;
345
- await this.save();
346
- return true;
347
- }
348
- /**
349
- * Get insights by category
350
- */
351
- getInsightsByCategory(category) {
352
- return this.data.insights.filter((i) => i.category === category && !i.dismissed);
353
- }
354
- /**
355
- * Get insights by type
356
- */
357
- getInsightsByType(type) {
358
- return this.data.insights.filter((i) => i.type === type && !i.dismissed);
359
- }
360
- /**
361
- * Get insights from the last N hours
362
- */
363
- getRecentInsights(hours = 24) {
364
- const cutoff = Date.now() - hours * 60 * 60 * 1e3;
365
- return this.data.insights.filter((i) => i.timestamp >= cutoff);
366
- }
367
- /**
368
- * Get statistics about insights
369
- */
370
- getStats() {
371
- const stats = {
372
- total: this.data.insights.length,
373
- active: 0,
374
- dismissed: 0,
375
- byCategory: {},
376
- byType: {}
377
- };
378
- for (const insight of this.data.insights) {
379
- if (insight.dismissed) {
380
- stats.dismissed++;
381
- } else {
382
- stats.active++;
383
- }
384
- stats.byCategory[insight.category] = (stats.byCategory[insight.category] || 0) + 1;
385
- stats.byType[insight.type] = (stats.byType[insight.type] || 0) + 1;
386
- }
387
- return stats;
388
- }
389
- /**
390
- * Prune old insights (older than N days)
391
- */
392
- async pruneOldInsights(daysToKeep = 30) {
393
- await this.load();
394
- const cutoff = Date.now() - daysToKeep * 24 * 60 * 60 * 1e3;
395
- const originalCount = this.data.insights.length;
396
- this.data.insights = this.data.insights.filter((i) => i.timestamp >= cutoff);
397
- const pruned = originalCount - this.data.insights.length;
398
- if (pruned > 0) {
399
- this.dirty = true;
400
- await this.save();
401
- }
402
- return pruned;
403
- }
404
- /**
405
- * Check if the store has been loaded
406
- */
407
- isLoaded() {
408
- return this.loaded;
409
- }
410
- /**
411
- * Force reload from disk
412
- */
413
- async reload() {
414
- this.loaded = false;
415
- this.dirty = false;
416
- return this.load();
417
- }
418
- };
419
- var insightStores = /* @__PURE__ */ new Map();
420
- function getInsightStore(projectPath) {
421
- let store = insightStores.get(projectPath);
422
- if (!store) {
423
- store = new InsightStore(projectPath);
424
- insightStores.set(projectPath, store);
425
- }
426
- return store;
427
- }
428
- function clearInsightStores() {
429
- insightStores.clear();
430
- }
431
-
432
- export {
433
- InsightDetailsSchema,
434
- InsightSchema,
435
- InsightStoreDataSchema,
436
- InsightStore,
437
- getInsightStore,
438
- clearInsightStores
439
- };
440
- //# sourceMappingURL=chunk-T63OHG4Q.js.map
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/agent/insight-store.ts"],"sourcesContent":["/**\n * Insight Store - Persistent storage for insights\n * \n * Persists to: .trie/memory/insights.json\n * \n * Features:\n * - Insight persistence across restarts\n * - Cooldown state persistence (prevents duplicate insights)\n * - Dismissed insight tracking\n * - Atomic writes with backup rotation\n * - Zod validation for data integrity\n */\n\nimport { mkdir, readFile } from 'fs/promises';\nimport { existsSync } from 'fs';\nimport { join } from 'path';\nimport { getTrieDirectory } from '../utils/workspace.js';\nimport { z } from 'zod';\nimport { atomicWriteJSON } from '../utils/atomic-write.js';\nimport { BackupManager } from '../utils/backup-manager.js';\nimport { safeParseAndValidate } from '../memory/validation.js';\n\n// ============================================================================\n// Schemas\n// ============================================================================\n\n/**\n * Schema for insight details\n */\nexport const InsightDetailsSchema = z.object({\n affectedFiles: z.array(z.string()).optional(),\n issueBreakdown: z.record(z.string(), z.number()).optional(),\n examples: z.array(z.string()).optional(),\n trend: z.enum(['improving', 'stable', 'worsening']).optional(),\n comparison: z.string().optional(),\n resolvedCount: z.number().optional(),\n resolvedIssues: z.array(z.object({\n file: z.string(),\n line: z.number().optional(),\n issue: z.string(),\n agent: z.string(),\n resolvedAt: z.string().optional(),\n })).optional(),\n summary: z.string().optional(),\n // Hypothesis-related fields\n hypothesis: z.string().optional(),\n testCriteria: z.string().optional(),\n confidence: z.number().optional(),\n // Pattern-related fields\n patternsCount: z.number().optional(),\n topPattern: z.string().optional(),\n});\n\n/**\n * Schema for an insight\n */\nexport const InsightSchema = z.object({\n id: z.string(),\n type: z.enum(['observation', 'warning', 'suggestion', 'celebration', 'question']),\n message: z.string(),\n context: z.string().optional(),\n suggestedAction: z.string().optional(),\n actionCommand: z.string().optional(),\n relatedIssues: z.array(z.string()),\n priority: z.number().min(1).max(10),\n timestamp: z.number(),\n dismissed: z.boolean(),\n category: z.enum(['security', 'quality', 'performance', 'pattern', 'progress', 'general']),\n details: InsightDetailsSchema.optional(),\n});\n\nexport type Insight = z.infer<typeof InsightSchema>;\n\n/**\n * Schema for the entire insight store file\n */\nexport const InsightStoreDataSchema = z.object({\n version: z.literal(1),\n insights: z.array(InsightSchema),\n cooldowns: z.record(z.string(), z.number()), // insightKey -> timestamp\n dismissedIds: z.array(z.string()), // Track dismissed insight IDs permanently\n lastUpdated: z.string(),\n});\n\nexport type InsightStoreData = z.infer<typeof InsightStoreDataSchema>;\n\n// ============================================================================\n// InsightStore Class\n// ============================================================================\n\n/**\n * Persistent store for insights\n * \n * Usage:\n * ```typescript\n * const store = new InsightStore(projectPath);\n * await store.load();\n * \n * await store.addInsight(insight);\n * const active = store.getActiveInsights();\n * await store.dismissInsight(insightId);\n * ```\n */\nexport class InsightStore {\n private projectPath: string;\n private data: InsightStoreData;\n private loaded: boolean = false;\n private dirty: boolean = false;\n \n // Default cooldown periods (in ms)\n static readonly COOLDOWNS: Record<string, number> = {\n 'pre-push-warning': 60000, // 1 min between pre-push warnings\n 'security-warning': 30000, // 30s between security warnings\n 'new-issues': 30000, // 30s between new issue observations\n 'celebration': 60000, // 1 min between celebrations\n 'pattern-suggestion': 120000, // 2 min between pattern suggestions\n 'accessibility-visual-qa': 300000, // 5 min between visual QA suggestions\n 'goal-suggestion': 300000, // 5 min between goal suggestions\n 'risk-prediction': 180000, // 3 min between risk predictions\n 'hypothesis-update': 600000, // 10 min between hypothesis updates\n 'auto-escalation': 300000, // 5 min between auto-escalations\n };\n \n constructor(projectPath: string) {\n this.projectPath = projectPath;\n this.data = this.createEmptyData();\n }\n \n /**\n * Get the storage file path\n */\n private getStorePath(): string {\n return join(getTrieDirectory(this.projectPath), 'memory', 'insights.json');\n }\n \n /**\n * Create empty data structure\n */\n private createEmptyData(): InsightStoreData {\n return {\n version: 1,\n insights: [],\n cooldowns: {},\n dismissedIds: [],\n lastUpdated: new Date().toISOString(),\n };\n }\n \n /**\n * Load insights from disk\n * \n * If the file is corrupted, attempts recovery from backup.\n * Returns empty data if no valid file/backup exists.\n */\n async load(): Promise<InsightStoreData> {\n if (this.loaded) {\n return this.data;\n }\n \n const storePath = this.getStorePath();\n \n try {\n if (existsSync(storePath)) {\n const content = await readFile(storePath, 'utf-8');\n const result = safeParseAndValidate(content, InsightStoreDataSchema);\n \n if (result.success) {\n this.data = result.data;\n this.loaded = true;\n // Deduplicate any existing duplicate insights\n this.deduplicateInsights();\n return this.data;\n }\n \n // Validation failed - attempt recovery from backup\n console.error(` Insight store corrupted: ${result.error}`);\n const backupManager = new BackupManager(storePath);\n \n if (await backupManager.recoverFromBackup()) {\n console.error(' Recovered from backup');\n const recovered = await readFile(storePath, 'utf-8');\n const recoveredResult = safeParseAndValidate(recovered, InsightStoreDataSchema);\n if (recoveredResult.success) {\n this.data = recoveredResult.data;\n this.loaded = true;\n // Deduplicate any existing duplicate insights\n this.deduplicateInsights();\n return this.data;\n }\n }\n \n console.error(' No valid backup found, starting fresh');\n }\n } catch (error) {\n // File doesn't exist or recovery failed - start fresh\n console.error(` Could not load insight store: ${error}`);\n }\n \n this.data = this.createEmptyData();\n this.loaded = true;\n return this.data;\n }\n \n /**\n * Deduplicate existing insights on load\n * Keeps the most recent instance of each unique insight\n */\n private deduplicateInsights(): void {\n const seen = new Map<string, number>(); // contentKey -> index of first occurrence\n const toRemove: number[] = [];\n \n // Process from newest to oldest (insights are sorted by recency)\n for (let i = 0; i < this.data.insights.length; i++) {\n const insight = this.data.insights[i];\n if (!insight) continue;\n \n const contentKey = this.getContentKey(insight);\n \n if (seen.has(contentKey)) {\n // This is a duplicate - mark for removal\n toRemove.push(i);\n } else {\n seen.set(contentKey, i);\n }\n }\n \n // Remove duplicates (reverse order to preserve indices)\n if (toRemove.length > 0) {\n for (let i = toRemove.length - 1; i >= 0; i--) {\n const idx = toRemove[i];\n if (idx !== undefined) {\n this.data.insights.splice(idx, 1);\n }\n }\n this.dirty = true;\n }\n }\n \n /**\n * Save insights to disk\n * \n * Creates backup before writing, uses atomic write.\n */\n async save(): Promise<void> {\n if (!this.dirty && this.loaded) {\n return; // No changes to save\n }\n \n const storePath = this.getStorePath();\n const memoryDir = join(getTrieDirectory(this.projectPath), 'memory');\n \n // Ensure directory exists\n await mkdir(memoryDir, { recursive: true });\n \n // Create backup before writing\n const backupManager = new BackupManager(storePath);\n await backupManager.createBackup();\n \n // Update timestamp\n this.data.lastUpdated = new Date().toISOString();\n \n // Atomic write\n await atomicWriteJSON(storePath, this.data);\n \n this.dirty = false;\n }\n \n /**\n * Generate a content-based key for deduplication\n * Insights with the same content key are considered duplicates\n */\n private getContentKey(insight: Insight): string {\n // Normalize the message by removing specific numbers/counts that might vary slightly\n // e.g., \"Found 30 security issues\" and \"Found 31 security issues\" are the same insight\n const normalizedMessage = insight.message\n .replace(/\\d+/g, 'N') // Replace all numbers with N\n .toLowerCase()\n .trim();\n \n return `${insight.type}:${insight.category}:${normalizedMessage}`;\n }\n \n /**\n * Add an insight to the store\n * \n * Checks for duplicates using both insight ID and content similarity.\n * If a similar insight already exists (same type, category, and normalized message),\n * updates its timestamp instead of creating a duplicate.\n * Respects cooldowns to prevent insight spam.\n */\n async addInsight(insight: Insight): Promise<boolean> {\n await this.load();\n \n // Check if already exists by ID\n if (this.data.insights.some(i => i.id === insight.id)) {\n return false;\n }\n \n // Check if ID was previously dismissed (don't re-add)\n if (this.data.dismissedIds.includes(insight.id)) {\n return false;\n }\n \n // Check for content-based duplicates (same type, category, similar message)\n const contentKey = this.getContentKey(insight);\n const existingIndex = this.data.insights.findIndex(i => \n !i.dismissed && this.getContentKey(i) === contentKey\n );\n \n if (existingIndex >= 0) {\n // Update existing insight instead of adding duplicate\n const existing = this.data.insights[existingIndex];\n if (existing) {\n // Update with new data but keep the original ID\n existing.timestamp = insight.timestamp;\n existing.message = insight.message; // Update with current counts\n existing.details = insight.details; // Update details\n existing.relatedIssues = insight.relatedIssues;\n existing.suggestedAction = insight.suggestedAction;\n \n // Move to front of list\n this.data.insights.splice(existingIndex, 1);\n this.data.insights.unshift(existing);\n \n this.dirty = true;\n await this.save();\n }\n return false; // Return false to indicate no new insight was created\n }\n \n // Add to front of list\n this.data.insights.unshift(insight);\n \n // Keep only last 100 insights\n if (this.data.insights.length > 100) {\n this.data.insights = this.data.insights.slice(0, 100);\n }\n \n this.dirty = true;\n await this.save();\n \n return true;\n }\n \n /**\n * Check if a cooldown has expired for an insight type\n */\n canCreateInsight(insightKey: string): boolean {\n const lastTime = this.data.cooldowns[insightKey];\n const cooldown = InsightStore.COOLDOWNS[insightKey] || 30000;\n \n if (!lastTime) return true;\n return Date.now() - lastTime > cooldown;\n }\n \n /**\n * Mark that an insight type was created (set cooldown)\n */\n async markInsightCreated(insightKey: string): Promise<void> {\n await this.load();\n this.data.cooldowns[insightKey] = Date.now();\n this.dirty = true;\n await this.save();\n }\n \n /**\n * Get active (non-dismissed) insights\n * \n * Returns insights sorted by priority (highest first),\n * limited to the specified count.\n */\n getActiveInsights(limit: number = 5): Insight[] {\n return this.data.insights\n .filter(i => !i.dismissed)\n .sort((a, b) => b.priority - a.priority)\n .slice(0, limit);\n }\n \n /**\n * Get all insights (including dismissed)\n */\n getAllInsights(): Insight[] {\n return [...this.data.insights];\n }\n \n /**\n * Dismiss an insight by ID\n */\n async dismissInsight(insightId: string): Promise<boolean> {\n await this.load();\n \n const insight = this.data.insights.find(i => i.id === insightId);\n if (!insight) {\n return false;\n }\n \n insight.dismissed = true;\n \n // Track permanently dismissed IDs\n if (!this.data.dismissedIds.includes(insightId)) {\n this.data.dismissedIds.push(insightId);\n \n // Keep only last 500 dismissed IDs\n if (this.data.dismissedIds.length > 500) {\n this.data.dismissedIds = this.data.dismissedIds.slice(-500);\n }\n }\n \n this.dirty = true;\n await this.save();\n \n return true;\n }\n \n /**\n * Remove an insight entirely\n */\n async removeInsight(insightId: string): Promise<boolean> {\n await this.load();\n \n const index = this.data.insights.findIndex(i => i.id === insightId);\n if (index === -1) {\n return false;\n }\n \n this.data.insights.splice(index, 1);\n this.dirty = true;\n await this.save();\n \n return true;\n }\n \n /**\n * Clear all cooldowns\n */\n async clearCooldowns(): Promise<void> {\n await this.load();\n this.data.cooldowns = {};\n this.dirty = true;\n await this.save();\n }\n \n /**\n * Get insight by ID\n */\n getInsight(insightId: string): Insight | undefined {\n return this.data.insights.find(i => i.id === insightId);\n }\n \n /**\n * Update an existing insight\n */\n async updateInsight(insightId: string, updates: Partial<Insight>): Promise<boolean> {\n await this.load();\n \n const insight = this.data.insights.find(i => i.id === insightId);\n if (!insight) {\n return false;\n }\n \n Object.assign(insight, updates);\n this.dirty = true;\n await this.save();\n \n return true;\n }\n \n /**\n * Get insights by category\n */\n getInsightsByCategory(category: Insight['category']): Insight[] {\n return this.data.insights.filter(i => i.category === category && !i.dismissed);\n }\n \n /**\n * Get insights by type\n */\n getInsightsByType(type: Insight['type']): Insight[] {\n return this.data.insights.filter(i => i.type === type && !i.dismissed);\n }\n \n /**\n * Get insights from the last N hours\n */\n getRecentInsights(hours: number = 24): Insight[] {\n const cutoff = Date.now() - (hours * 60 * 60 * 1000);\n return this.data.insights.filter(i => i.timestamp >= cutoff);\n }\n \n /**\n * Get statistics about insights\n */\n getStats(): {\n total: number;\n active: number;\n dismissed: number;\n byCategory: Record<string, number>;\n byType: Record<string, number>;\n } {\n const stats = {\n total: this.data.insights.length,\n active: 0,\n dismissed: 0,\n byCategory: {} as Record<string, number>,\n byType: {} as Record<string, number>,\n };\n \n for (const insight of this.data.insights) {\n if (insight.dismissed) {\n stats.dismissed++;\n } else {\n stats.active++;\n }\n \n stats.byCategory[insight.category] = (stats.byCategory[insight.category] || 0) + 1;\n stats.byType[insight.type] = (stats.byType[insight.type] || 0) + 1;\n }\n \n return stats;\n }\n \n /**\n * Prune old insights (older than N days)\n */\n async pruneOldInsights(daysToKeep: number = 30): Promise<number> {\n await this.load();\n \n const cutoff = Date.now() - (daysToKeep * 24 * 60 * 60 * 1000);\n const originalCount = this.data.insights.length;\n \n this.data.insights = this.data.insights.filter(i => i.timestamp >= cutoff);\n \n const pruned = originalCount - this.data.insights.length;\n if (pruned > 0) {\n this.dirty = true;\n await this.save();\n }\n \n return pruned;\n }\n \n /**\n * Check if the store has been loaded\n */\n isLoaded(): boolean {\n return this.loaded;\n }\n \n /**\n * Force reload from disk\n */\n async reload(): Promise<InsightStoreData> {\n this.loaded = false;\n this.dirty = false;\n return this.load();\n }\n}\n\n// ============================================================================\n// Singleton Management\n// ============================================================================\n\nconst insightStores: Map<string, InsightStore> = new Map();\n\n/**\n * Get the InsightStore for a project (singleton per project)\n */\nexport function getInsightStore(projectPath: string): InsightStore {\n let store = insightStores.get(projectPath);\n if (!store) {\n store = new InsightStore(projectPath);\n insightStores.set(projectPath, store);\n }\n return store;\n}\n\n/**\n * Clear all InsightStore instances (for testing)\n */\nexport function clearInsightStores(): void {\n insightStores.clear();\n}\n"],"mappings":"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","names":[]}
@@ -1,173 +0,0 @@
1
- import {
2
- Trie
3
- } from "./chunk-6NLHFIYA.js";
4
- import {
5
- getTrieDirectory
6
- } from "./chunk-VVITXIHN.js";
7
-
8
- // src/context/incident-index.ts
9
- import path2 from "path";
10
-
11
- // src/context/file-trie.ts
12
- import fs from "fs";
13
- import path from "path";
14
- import { performance } from "perf_hooks";
15
- function normalizePath(filePath) {
16
- const normalized = filePath.replace(/\\/g, "/");
17
- return normalized.startsWith("./") ? normalized.slice(2) : normalized;
18
- }
19
- var FilePathTrie = class {
20
- trie = new Trie();
21
- persistPath;
22
- constructor(persistPath) {
23
- if (persistPath) this.persistPath = persistPath;
24
- if (persistPath && fs.existsSync(persistPath)) {
25
- try {
26
- const raw = fs.readFileSync(persistPath, "utf-8");
27
- if (raw.trim().length > 0) {
28
- const json = JSON.parse(raw);
29
- this.trie = Trie.fromJSON(json);
30
- }
31
- } catch {
32
- this.trie = new Trie();
33
- }
34
- }
35
- }
36
- addIncident(filePath, incident) {
37
- const key = normalizePath(filePath);
38
- const existing = this.trie.search(key);
39
- const incidents = existing.found && Array.isArray(existing.value) ? existing.value : [];
40
- incidents.push(incident);
41
- this.trie.insert(key, incidents);
42
- this.persist();
43
- }
44
- getIncidents(filePath) {
45
- const key = normalizePath(filePath);
46
- const result = this.trie.search(key);
47
- return result.found && Array.isArray(result.value) ? result.value : [];
48
- }
49
- getDirectoryIncidents(prefix) {
50
- const normalizedPrefix = normalizePath(prefix);
51
- const matches = this.trie.getWithPrefix(normalizedPrefix);
52
- return matches.flatMap((m) => Array.isArray(m.value) ? m.value : []).filter(Boolean);
53
- }
54
- getHotZones(threshold) {
55
- const matches = this.trie.getWithPrefix("");
56
- const zones = [];
57
- for (const match of matches) {
58
- const incidents = Array.isArray(match.value) ? match.value : [];
59
- if (incidents.length >= threshold) {
60
- zones.push({
61
- path: match.pattern,
62
- incidentCount: incidents.length,
63
- confidence: this.calculateConfidence(incidents.length)
64
- });
65
- }
66
- }
67
- return zones.sort((a, b) => b.incidentCount - a.incidentCount);
68
- }
69
- suggestPaths(partial, limit = 5) {
70
- const normalized = normalizePath(partial);
71
- const results = this.trie.getWithPrefix(normalized);
72
- return results.map((r) => ({
73
- path: r.pattern,
74
- incidentCount: Array.isArray(r.value) ? r.value.length : 0
75
- })).sort((a, b) => b.incidentCount - a.incidentCount).slice(0, limit);
76
- }
77
- timeLookup(path3) {
78
- const start = performance.now();
79
- this.getIncidents(path3);
80
- return performance.now() - start;
81
- }
82
- toJSON() {
83
- return this.trie.toJSON();
84
- }
85
- calculateConfidence(count) {
86
- const capped = Math.min(count, 10);
87
- return Math.round(capped / 10 * 100) / 100;
88
- }
89
- persist() {
90
- if (!this.persistPath) return;
91
- try {
92
- const dir = path.dirname(this.persistPath);
93
- if (!fs.existsSync(dir)) {
94
- fs.mkdirSync(dir, { recursive: true });
95
- }
96
- fs.writeFileSync(this.persistPath, JSON.stringify(this.trie.toJSON()), "utf-8");
97
- } catch {
98
- }
99
- }
100
- };
101
-
102
- // src/context/incident-index.ts
103
- var IncidentIndex = class _IncidentIndex {
104
- graph;
105
- trie;
106
- projectRoot;
107
- constructor(graph, projectRoot, options) {
108
- this.graph = graph;
109
- this.projectRoot = projectRoot;
110
- this.trie = new FilePathTrie(
111
- options?.persistPath ?? path2.join(getTrieDirectory(projectRoot), "incident-trie.json")
112
- );
113
- }
114
- static async build(graph, projectRoot, options) {
115
- const index = new _IncidentIndex(graph, projectRoot, options);
116
- await index.rebuild();
117
- return index;
118
- }
119
- async rebuild() {
120
- const nodes = await this.graph.listNodes();
121
- const incidents = nodes.filter((n) => n.type === "incident");
122
- for (const incident of incidents) {
123
- const files = await this.getFilesForIncident(incident.id);
124
- this.addIncidentToTrie(incident, files);
125
- }
126
- }
127
- addIncidentToTrie(incident, files) {
128
- const meta = {
129
- id: incident.id,
130
- file: "",
131
- description: incident.data.description,
132
- severity: incident.data.severity,
133
- timestamp: incident.data.timestamp
134
- };
135
- for (const file of files) {
136
- const normalized = this.normalizePath(file);
137
- this.trie.addIncident(normalized, { ...meta, file: normalized });
138
- }
139
- }
140
- getFileTrie() {
141
- return this.trie;
142
- }
143
- async getFilesForIncident(incidentId) {
144
- const files = /* @__PURE__ */ new Set();
145
- const edges = await this.graph.getEdges(incidentId, "both");
146
- for (const edge of edges) {
147
- if (edge.type === "causedBy" || edge.type === "leadTo") {
148
- const changeId = edge.type === "causedBy" ? edge.to_id : edge.from_id;
149
- const change = await this.graph.getNode("change", changeId);
150
- if (change?.data && "files" in change.data && Array.isArray(change.data.files)) {
151
- change.data.files.forEach((f) => files.add(f));
152
- }
153
- }
154
- if (edge.type === "affects") {
155
- const fileNode = await this.graph.getNode("file", edge.to_id) || await this.graph.getNode("file", edge.from_id);
156
- if (fileNode && typeof fileNode.data?.path === "string") {
157
- files.add(fileNode.data.path);
158
- }
159
- }
160
- }
161
- return Array.from(files);
162
- }
163
- normalizePath(filePath) {
164
- const absolute = path2.isAbsolute(filePath) ? filePath : path2.join(this.projectRoot, filePath);
165
- const relative = path2.relative(this.projectRoot, absolute);
166
- return relative.replace(/\\/g, "/");
167
- }
168
- };
169
-
170
- export {
171
- IncidentIndex
172
- };
173
- //# sourceMappingURL=chunk-TN5WEKWI.js.map