@triedotdev/mcp 1.0.61 → 1.0.63

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 (56) hide show
  1. package/README.md +591 -52
  2. package/dist/agent-smith-W4HUCFGC.js +14 -0
  3. package/dist/{agent-smith-runner-ZU4R3I2Z.js → agent-smith-runner-QRVOEOBE.js} +13 -7
  4. package/dist/agent-smith-runner-QRVOEOBE.js.map +1 -0
  5. package/dist/chunk-4YSLDGBL.js +674 -0
  6. package/dist/chunk-4YSLDGBL.js.map +1 -0
  7. package/dist/chunk-7KHT2NKR.js +212 -0
  8. package/dist/chunk-7KHT2NKR.js.map +1 -0
  9. package/dist/{chunk-XSPS463E.js → chunk-ALA6733H.js} +492 -14
  10. package/dist/chunk-ALA6733H.js.map +1 -0
  11. package/dist/chunk-AQCAMIQQ.js +139 -0
  12. package/dist/chunk-AQCAMIQQ.js.map +1 -0
  13. package/dist/chunk-D3DMONAJ.js +904 -0
  14. package/dist/chunk-D3DMONAJ.js.map +1 -0
  15. package/dist/{chunk-KB5ZN6K2.js → chunk-GWSNINKX.js} +2 -2
  16. package/dist/{chunk-32WLOG6E.js → chunk-K6BQBKIR.js} +662 -633
  17. package/dist/chunk-K6BQBKIR.js.map +1 -0
  18. package/dist/{chunk-ASGSTVVF.js → chunk-KOFQ47YW.js} +10 -6
  19. package/dist/chunk-KOFQ47YW.js.map +1 -0
  20. package/dist/{chunk-XVGHO2Z5.js → chunk-N2AZH3EQ.js} +7683 -4777
  21. package/dist/chunk-N2AZH3EQ.js.map +1 -0
  22. package/dist/chunk-PBOVCPKE.js +2566 -0
  23. package/dist/chunk-PBOVCPKE.js.map +1 -0
  24. package/dist/{chunk-NUT4G5AY.js → chunk-R7Z7OHTJ.js} +493 -650
  25. package/dist/chunk-R7Z7OHTJ.js.map +1 -0
  26. package/dist/chunk-TSHZQKCM.js +933 -0
  27. package/dist/chunk-TSHZQKCM.js.map +1 -0
  28. package/dist/{chunk-S4VGGLXF.js → chunk-X2PABPBH.js} +461 -892
  29. package/dist/chunk-X2PABPBH.js.map +1 -0
  30. package/dist/cli/create-agent.js +3 -2
  31. package/dist/cli/create-agent.js.map +1 -1
  32. package/dist/cli/main.js +1120 -70
  33. package/dist/cli/main.js.map +1 -1
  34. package/dist/cli/yolo-daemon.js +151 -41
  35. package/dist/cli/yolo-daemon.js.map +1 -1
  36. package/dist/goal-manager-KFBOAP4X.js +20 -0
  37. package/dist/goal-manager-KFBOAP4X.js.map +1 -0
  38. package/dist/guardian-agent-PULK546O.js +17 -0
  39. package/dist/guardian-agent-PULK546O.js.map +1 -0
  40. package/dist/index.js +173 -39
  41. package/dist/index.js.map +1 -1
  42. package/dist/issue-store-QRDF3X55.js +22 -0
  43. package/dist/issue-store-QRDF3X55.js.map +1 -0
  44. package/dist/workers/agent-worker.js +6 -3
  45. package/dist/workers/agent-worker.js.map +1 -1
  46. package/package.json +1 -1
  47. package/dist/agent-smith-57MKX5QC.js +0 -13
  48. package/dist/agent-smith-runner-ZU4R3I2Z.js.map +0 -1
  49. package/dist/chunk-32WLOG6E.js.map +0 -1
  50. package/dist/chunk-ASGSTVVF.js.map +0 -1
  51. package/dist/chunk-NUT4G5AY.js.map +0 -1
  52. package/dist/chunk-S4VGGLXF.js.map +0 -1
  53. package/dist/chunk-XSPS463E.js.map +0 -1
  54. package/dist/chunk-XVGHO2Z5.js.map +0 -1
  55. /package/dist/{agent-smith-57MKX5QC.js.map → agent-smith-W4HUCFGC.js.map} +0 -0
  56. /package/dist/{chunk-KB5ZN6K2.js.map → chunk-GWSNINKX.js.map} +0 -0
@@ -0,0 +1,904 @@
1
+ import {
2
+ getGuardianState
3
+ } from "./chunk-4YSLDGBL.js";
4
+ import {
5
+ BackupManager,
6
+ atomicWriteJSON,
7
+ getMemoryStats,
8
+ safeParseAndValidate,
9
+ searchIssues
10
+ } from "./chunk-TSHZQKCM.js";
11
+
12
+ // src/guardian/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
+ });
24
+ var GuardianInsightSchema = z.object({
25
+ id: z.string(),
26
+ type: z.enum(["observation", "warning", "suggestion", "celebration", "question"]),
27
+ message: z.string(),
28
+ context: z.string().optional(),
29
+ suggestedAction: z.string().optional(),
30
+ actionCommand: z.string().optional(),
31
+ relatedIssues: z.array(z.string()),
32
+ priority: z.number().min(1).max(10),
33
+ timestamp: z.number(),
34
+ dismissed: z.boolean(),
35
+ category: z.enum(["security", "quality", "performance", "pattern", "progress", "general"]),
36
+ details: InsightDetailsSchema.optional()
37
+ });
38
+ var InsightStoreDataSchema = z.object({
39
+ version: z.literal(1),
40
+ insights: z.array(GuardianInsightSchema),
41
+ cooldowns: z.record(z.string(), z.number()),
42
+ // insightKey -> timestamp
43
+ dismissedIds: z.array(z.string()),
44
+ // Track dismissed insight IDs permanently
45
+ lastUpdated: z.string()
46
+ });
47
+ var InsightStore = class _InsightStore {
48
+ projectPath;
49
+ data;
50
+ loaded = false;
51
+ dirty = false;
52
+ // Default cooldown periods (in ms)
53
+ static COOLDOWNS = {
54
+ "pre-push-warning": 6e4,
55
+ // 1 min between pre-push warnings
56
+ "security-warning": 3e4,
57
+ // 30s between security warnings
58
+ "new-issues": 3e4,
59
+ // 30s between new issue observations
60
+ "celebration": 6e4,
61
+ // 1 min between celebrations
62
+ "pattern-suggestion": 12e4,
63
+ // 2 min between pattern suggestions
64
+ "accessibility-visual-qa": 3e5,
65
+ // 5 min between visual QA suggestions
66
+ "goal-suggestion": 3e5,
67
+ // 5 min between goal suggestions
68
+ "risk-prediction": 18e4,
69
+ // 3 min between risk predictions
70
+ "hypothesis-update": 6e5,
71
+ // 10 min between hypothesis updates
72
+ "auto-escalation": 3e5
73
+ // 5 min between auto-escalations
74
+ };
75
+ constructor(projectPath) {
76
+ this.projectPath = projectPath;
77
+ this.data = this.createEmptyData();
78
+ }
79
+ /**
80
+ * Get the storage file path
81
+ */
82
+ getStorePath() {
83
+ return join(this.projectPath, ".trie", "memory", "guardian-insights.json");
84
+ }
85
+ /**
86
+ * Create empty data structure
87
+ */
88
+ createEmptyData() {
89
+ return {
90
+ version: 1,
91
+ insights: [],
92
+ cooldowns: {},
93
+ dismissedIds: [],
94
+ lastUpdated: (/* @__PURE__ */ new Date()).toISOString()
95
+ };
96
+ }
97
+ /**
98
+ * Load insights from disk
99
+ *
100
+ * If the file is corrupted, attempts recovery from backup.
101
+ * Returns empty data if no valid file/backup exists.
102
+ */
103
+ async load() {
104
+ if (this.loaded) {
105
+ return this.data;
106
+ }
107
+ const storePath = this.getStorePath();
108
+ try {
109
+ if (existsSync(storePath)) {
110
+ const content = await readFile(storePath, "utf-8");
111
+ const result = safeParseAndValidate(content, InsightStoreDataSchema);
112
+ if (result.success) {
113
+ this.data = result.data;
114
+ this.loaded = true;
115
+ this.deduplicateInsights();
116
+ return this.data;
117
+ }
118
+ console.error(` \u26A0\uFE0F Insight store corrupted: ${result.error}`);
119
+ const backupManager = new BackupManager(storePath);
120
+ if (await backupManager.recoverFromBackup()) {
121
+ console.error(" \u2705 Recovered from backup");
122
+ const recovered = await readFile(storePath, "utf-8");
123
+ const recoveredResult = safeParseAndValidate(recovered, InsightStoreDataSchema);
124
+ if (recoveredResult.success) {
125
+ this.data = recoveredResult.data;
126
+ this.loaded = true;
127
+ this.deduplicateInsights();
128
+ return this.data;
129
+ }
130
+ }
131
+ console.error(" \u274C No valid backup found, starting fresh");
132
+ }
133
+ } catch (error) {
134
+ console.error(` \u26A0\uFE0F Could not load insight store: ${error}`);
135
+ }
136
+ this.data = this.createEmptyData();
137
+ this.loaded = true;
138
+ return this.data;
139
+ }
140
+ /**
141
+ * Deduplicate existing insights on load
142
+ * Keeps the most recent instance of each unique insight
143
+ */
144
+ deduplicateInsights() {
145
+ const seen = /* @__PURE__ */ new Map();
146
+ const toRemove = [];
147
+ for (let i = 0; i < this.data.insights.length; i++) {
148
+ const insight = this.data.insights[i];
149
+ if (!insight) continue;
150
+ const contentKey = this.getContentKey(insight);
151
+ if (seen.has(contentKey)) {
152
+ toRemove.push(i);
153
+ } else {
154
+ seen.set(contentKey, i);
155
+ }
156
+ }
157
+ if (toRemove.length > 0) {
158
+ for (let i = toRemove.length - 1; i >= 0; i--) {
159
+ const idx = toRemove[i];
160
+ if (idx !== void 0) {
161
+ this.data.insights.splice(idx, 1);
162
+ }
163
+ }
164
+ this.dirty = true;
165
+ }
166
+ }
167
+ /**
168
+ * Save insights to disk
169
+ *
170
+ * Creates backup before writing, uses atomic write.
171
+ */
172
+ async save() {
173
+ if (!this.dirty && this.loaded) {
174
+ return;
175
+ }
176
+ const storePath = this.getStorePath();
177
+ const memoryDir = join(this.projectPath, ".trie", "memory");
178
+ await mkdir(memoryDir, { recursive: true });
179
+ const backupManager = new BackupManager(storePath);
180
+ await backupManager.createBackup();
181
+ this.data.lastUpdated = (/* @__PURE__ */ new Date()).toISOString();
182
+ await atomicWriteJSON(storePath, this.data);
183
+ this.dirty = false;
184
+ }
185
+ /**
186
+ * Generate a content-based key for deduplication
187
+ * Insights with the same content key are considered duplicates
188
+ */
189
+ getContentKey(insight) {
190
+ const normalizedMessage = insight.message.replace(/\d+/g, "N").toLowerCase().trim();
191
+ return `${insight.type}:${insight.category}:${normalizedMessage}`;
192
+ }
193
+ /**
194
+ * Add an insight to the store
195
+ *
196
+ * Checks for duplicates using both insight ID and content similarity.
197
+ * If a similar insight already exists (same type, category, and normalized message),
198
+ * updates its timestamp instead of creating a duplicate.
199
+ * Respects cooldowns to prevent insight spam.
200
+ */
201
+ async addInsight(insight) {
202
+ await this.load();
203
+ if (this.data.insights.some((i) => i.id === insight.id)) {
204
+ return false;
205
+ }
206
+ if (this.data.dismissedIds.includes(insight.id)) {
207
+ return false;
208
+ }
209
+ const contentKey = this.getContentKey(insight);
210
+ const existingIndex = this.data.insights.findIndex(
211
+ (i) => !i.dismissed && this.getContentKey(i) === contentKey
212
+ );
213
+ if (existingIndex >= 0) {
214
+ const existing = this.data.insights[existingIndex];
215
+ if (existing) {
216
+ existing.timestamp = insight.timestamp;
217
+ existing.message = insight.message;
218
+ existing.details = insight.details;
219
+ existing.relatedIssues = insight.relatedIssues;
220
+ existing.suggestedAction = insight.suggestedAction;
221
+ this.data.insights.splice(existingIndex, 1);
222
+ this.data.insights.unshift(existing);
223
+ this.dirty = true;
224
+ await this.save();
225
+ }
226
+ return false;
227
+ }
228
+ this.data.insights.unshift(insight);
229
+ if (this.data.insights.length > 100) {
230
+ this.data.insights = this.data.insights.slice(0, 100);
231
+ }
232
+ this.dirty = true;
233
+ await this.save();
234
+ return true;
235
+ }
236
+ /**
237
+ * Check if a cooldown has expired for an insight type
238
+ */
239
+ canCreateInsight(insightKey) {
240
+ const lastTime = this.data.cooldowns[insightKey];
241
+ const cooldown = _InsightStore.COOLDOWNS[insightKey] || 3e4;
242
+ if (!lastTime) return true;
243
+ return Date.now() - lastTime > cooldown;
244
+ }
245
+ /**
246
+ * Mark that an insight type was created (set cooldown)
247
+ */
248
+ async markInsightCreated(insightKey) {
249
+ await this.load();
250
+ this.data.cooldowns[insightKey] = Date.now();
251
+ this.dirty = true;
252
+ await this.save();
253
+ }
254
+ /**
255
+ * Get active (non-dismissed) insights
256
+ *
257
+ * Returns insights sorted by priority (highest first),
258
+ * limited to the specified count.
259
+ */
260
+ getActiveInsights(limit = 5) {
261
+ return this.data.insights.filter((i) => !i.dismissed).sort((a, b) => b.priority - a.priority).slice(0, limit);
262
+ }
263
+ /**
264
+ * Get all insights (including dismissed)
265
+ */
266
+ getAllInsights() {
267
+ return [...this.data.insights];
268
+ }
269
+ /**
270
+ * Dismiss an insight by ID
271
+ */
272
+ async dismissInsight(insightId) {
273
+ await this.load();
274
+ const insight = this.data.insights.find((i) => i.id === insightId);
275
+ if (!insight) {
276
+ return false;
277
+ }
278
+ insight.dismissed = true;
279
+ if (!this.data.dismissedIds.includes(insightId)) {
280
+ this.data.dismissedIds.push(insightId);
281
+ if (this.data.dismissedIds.length > 500) {
282
+ this.data.dismissedIds = this.data.dismissedIds.slice(-500);
283
+ }
284
+ }
285
+ this.dirty = true;
286
+ await this.save();
287
+ return true;
288
+ }
289
+ /**
290
+ * Remove an insight entirely
291
+ */
292
+ async removeInsight(insightId) {
293
+ await this.load();
294
+ const index = this.data.insights.findIndex((i) => i.id === insightId);
295
+ if (index === -1) {
296
+ return false;
297
+ }
298
+ this.data.insights.splice(index, 1);
299
+ this.dirty = true;
300
+ await this.save();
301
+ return true;
302
+ }
303
+ /**
304
+ * Clear all cooldowns
305
+ */
306
+ async clearCooldowns() {
307
+ await this.load();
308
+ this.data.cooldowns = {};
309
+ this.dirty = true;
310
+ await this.save();
311
+ }
312
+ /**
313
+ * Get insight by ID
314
+ */
315
+ getInsight(insightId) {
316
+ return this.data.insights.find((i) => i.id === insightId);
317
+ }
318
+ /**
319
+ * Update an existing insight
320
+ */
321
+ async updateInsight(insightId, updates) {
322
+ await this.load();
323
+ const insight = this.data.insights.find((i) => i.id === insightId);
324
+ if (!insight) {
325
+ return false;
326
+ }
327
+ Object.assign(insight, updates);
328
+ this.dirty = true;
329
+ await this.save();
330
+ return true;
331
+ }
332
+ /**
333
+ * Get insights by category
334
+ */
335
+ getInsightsByCategory(category) {
336
+ return this.data.insights.filter((i) => i.category === category && !i.dismissed);
337
+ }
338
+ /**
339
+ * Get insights by type
340
+ */
341
+ getInsightsByType(type) {
342
+ return this.data.insights.filter((i) => i.type === type && !i.dismissed);
343
+ }
344
+ /**
345
+ * Get insights from the last N hours
346
+ */
347
+ getRecentInsights(hours = 24) {
348
+ const cutoff = Date.now() - hours * 60 * 60 * 1e3;
349
+ return this.data.insights.filter((i) => i.timestamp >= cutoff);
350
+ }
351
+ /**
352
+ * Get statistics about insights
353
+ */
354
+ getStats() {
355
+ const stats = {
356
+ total: this.data.insights.length,
357
+ active: 0,
358
+ dismissed: 0,
359
+ byCategory: {},
360
+ byType: {}
361
+ };
362
+ for (const insight of this.data.insights) {
363
+ if (insight.dismissed) {
364
+ stats.dismissed++;
365
+ } else {
366
+ stats.active++;
367
+ }
368
+ stats.byCategory[insight.category] = (stats.byCategory[insight.category] || 0) + 1;
369
+ stats.byType[insight.type] = (stats.byType[insight.type] || 0) + 1;
370
+ }
371
+ return stats;
372
+ }
373
+ /**
374
+ * Prune old insights (older than N days)
375
+ */
376
+ async pruneOldInsights(daysToKeep = 30) {
377
+ await this.load();
378
+ const cutoff = Date.now() - daysToKeep * 24 * 60 * 60 * 1e3;
379
+ const originalCount = this.data.insights.length;
380
+ this.data.insights = this.data.insights.filter((i) => i.timestamp >= cutoff);
381
+ const pruned = originalCount - this.data.insights.length;
382
+ if (pruned > 0) {
383
+ this.dirty = true;
384
+ await this.save();
385
+ }
386
+ return pruned;
387
+ }
388
+ /**
389
+ * Check if the store has been loaded
390
+ */
391
+ isLoaded() {
392
+ return this.loaded;
393
+ }
394
+ /**
395
+ * Force reload from disk
396
+ */
397
+ async reload() {
398
+ this.loaded = false;
399
+ this.dirty = false;
400
+ return this.load();
401
+ }
402
+ };
403
+ var insightStores = /* @__PURE__ */ new Map();
404
+ function getInsightStore(projectPath) {
405
+ let store = insightStores.get(projectPath);
406
+ if (!store) {
407
+ store = new InsightStore(projectPath);
408
+ insightStores.set(projectPath, store);
409
+ }
410
+ return store;
411
+ }
412
+
413
+ // src/guardian/goal-manager.ts
414
+ import { basename } from "path";
415
+ var DEFAULT_CONFIG = {
416
+ minConfidence: 0.6,
417
+ maxActiveGoals: 3,
418
+ goalDurationDays: 14,
419
+ reductionTargetPercent: 50
420
+ };
421
+ var GoalManager = class {
422
+ projectPath;
423
+ config;
424
+ guardianState;
425
+ insightStore;
426
+ constructor(projectPath, config = {}) {
427
+ this.projectPath = projectPath;
428
+ this.config = { ...DEFAULT_CONFIG, ...config };
429
+ this.guardianState = getGuardianState(projectPath);
430
+ this.insightStore = getInsightStore(projectPath);
431
+ }
432
+ /**
433
+ * Analyze incident patterns from memory
434
+ */
435
+ async analyzeIncidentPatterns() {
436
+ const patterns = [];
437
+ try {
438
+ const stats = await getMemoryStats(this.projectPath);
439
+ const recentIssues = await searchIssues("", {
440
+ workDir: this.projectPath,
441
+ limit: 500,
442
+ includeResolved: true
443
+ });
444
+ if (recentIssues.length < 5) {
445
+ return patterns;
446
+ }
447
+ const fileIssueCount = /* @__PURE__ */ new Map();
448
+ for (const { issue } of recentIssues) {
449
+ const file = issue.file;
450
+ fileIssueCount.set(file, (fileIssueCount.get(file) || 0) + 1);
451
+ }
452
+ const sortedFiles = [...fileIssueCount.entries()].sort((a, b) => b[1] - a[1]);
453
+ const dirIssueCount = /* @__PURE__ */ new Map();
454
+ for (const [file, count] of sortedFiles) {
455
+ const parts = file.split("/");
456
+ if (parts.length > 1) {
457
+ const dir = parts.slice(0, -1).join("/");
458
+ dirIssueCount.set(dir, (dirIssueCount.get(dir) || 0) + count);
459
+ }
460
+ }
461
+ const sortedDirs = [...dirIssueCount.entries()].sort((a, b) => b[1] - a[1]);
462
+ if (sortedDirs.length > 0) {
463
+ const [topDir, topDirCount] = sortedDirs[0];
464
+ const totalIssues = recentIssues.length;
465
+ const percentage = topDirCount / totalIssues * 100;
466
+ if (percentage >= 30) {
467
+ patterns.push({
468
+ type: "file-cluster",
469
+ description: `${basename(topDir)}/ has ${percentage.toFixed(0)}% of issues`,
470
+ metric: `${topDir}_issues`,
471
+ currentValue: topDirCount,
472
+ suggestedTarget: Math.floor(topDirCount * (1 - this.config.reductionTargetPercent / 100)),
473
+ confidence: Math.min(0.9, percentage / 100 + 0.3),
474
+ evidence: [
475
+ `${topDirCount} issues in ${topDir}/`,
476
+ `${percentage.toFixed(0)}% of total issues`,
477
+ `Top files: ${sortedFiles.filter(([f]) => f.startsWith(topDir)).slice(0, 3).map(([f]) => basename(f)).join(", ")}`
478
+ ],
479
+ category: "quality"
480
+ });
481
+ }
482
+ }
483
+ const criticalCount = recentIssues.filter((r) => r.issue.severity === "critical").length;
484
+ const seriousCount = recentIssues.filter((r) => r.issue.severity === "serious").length;
485
+ if (criticalCount >= 3) {
486
+ patterns.push({
487
+ type: "severity-trend",
488
+ description: `${criticalCount} critical issues need attention`,
489
+ metric: "critical_issues",
490
+ currentValue: criticalCount,
491
+ suggestedTarget: 0,
492
+ confidence: Math.min(0.95, 0.5 + criticalCount * 0.1),
493
+ evidence: [
494
+ `${criticalCount} critical severity issues`,
495
+ `${seriousCount} serious severity issues`,
496
+ "Critical issues should be zero for production safety"
497
+ ],
498
+ category: "security"
499
+ });
500
+ }
501
+ const agentIssueCount = /* @__PURE__ */ new Map();
502
+ for (const { issue } of recentIssues) {
503
+ agentIssueCount.set(issue.agent, (agentIssueCount.get(issue.agent) || 0) + 1);
504
+ }
505
+ const sortedAgents = [...agentIssueCount.entries()].sort((a, b) => b[1] - a[1]);
506
+ if (sortedAgents.length > 0) {
507
+ const [topAgent, topAgentCount] = sortedAgents[0];
508
+ const percentage = topAgentCount / recentIssues.length * 100;
509
+ if (percentage >= 40 && topAgentCount >= 5) {
510
+ const category = this.agentToCategory(topAgent);
511
+ patterns.push({
512
+ type: "agent-concentration",
513
+ description: `${topAgent} skill finds ${percentage.toFixed(0)}% of issues`,
514
+ metric: `${topAgent}_issues`,
515
+ currentValue: topAgentCount,
516
+ suggestedTarget: Math.floor(topAgentCount * 0.5),
517
+ confidence: Math.min(0.85, percentage / 100 + 0.2),
518
+ evidence: [
519
+ `${topAgentCount} issues from ${topAgent}`,
520
+ `${percentage.toFixed(0)}% of all issues`,
521
+ `Suggests focused improvement in ${category} area`
522
+ ],
523
+ category
524
+ });
525
+ }
526
+ }
527
+ if (stats.improvementTrend === "improving") {
528
+ patterns.push({
529
+ type: "time-pattern",
530
+ description: "Quality is improving - maintain the streak",
531
+ metric: "clean_scans",
532
+ currentValue: 0,
533
+ suggestedTarget: 5,
534
+ confidence: 0.7,
535
+ evidence: [
536
+ "Historical trend shows improvement",
537
+ "Momentum is positive",
538
+ "Streak goal can maintain motivation"
539
+ ],
540
+ category: "quality"
541
+ });
542
+ }
543
+ } catch (error) {
544
+ console.error("Failed to analyze incident patterns:", error);
545
+ }
546
+ return patterns;
547
+ }
548
+ /**
549
+ * Convert agent name to category
550
+ */
551
+ agentToCategory(agent) {
552
+ const categoryMap = {
553
+ "security": "security",
554
+ "privacy": "security",
555
+ "soc2": "security",
556
+ "performance": "performance",
557
+ "accessibility": "quality",
558
+ "test": "coverage",
559
+ "typecheck": "quality",
560
+ "bug-finding": "quality"
561
+ };
562
+ return categoryMap[agent] || "general";
563
+ }
564
+ /**
565
+ * Generate goal opportunities from patterns
566
+ */
567
+ async generateGoalOpportunities() {
568
+ const patterns = await this.analyzeIncidentPatterns();
569
+ const opportunities = [];
570
+ const validPatterns = patterns.filter((p) => p.confidence >= this.config.minConfidence);
571
+ await this.guardianState.load();
572
+ const activeGoals = this.guardianState.getActiveGoals();
573
+ const slotsAvailable = this.config.maxActiveGoals - activeGoals.length;
574
+ if (slotsAvailable <= 0) {
575
+ return opportunities;
576
+ }
577
+ for (const pattern of validPatterns.slice(0, slotsAvailable)) {
578
+ const goalType = pattern.type === "time-pattern" ? "streak" : "reduction";
579
+ const deadline = /* @__PURE__ */ new Date();
580
+ deadline.setDate(deadline.getDate() + this.config.goalDurationDays);
581
+ opportunities.push({
582
+ pattern,
583
+ goal: {
584
+ description: this.generateGoalDescription(pattern),
585
+ type: goalType,
586
+ metric: pattern.metric,
587
+ target: pattern.suggestedTarget,
588
+ currentValue: pattern.currentValue,
589
+ startValue: pattern.currentValue,
590
+ status: "active",
591
+ autoGenerated: true,
592
+ confidence: pattern.confidence,
593
+ deadline: deadline.toISOString(),
594
+ category: pattern.category,
595
+ evidence: pattern.evidence
596
+ },
597
+ reasoning: this.generateGoalReasoning(pattern)
598
+ });
599
+ }
600
+ return opportunities;
601
+ }
602
+ /**
603
+ * Generate a human-readable goal description
604
+ */
605
+ generateGoalDescription(pattern) {
606
+ switch (pattern.type) {
607
+ case "file-cluster":
608
+ return `Reduce issues in ${pattern.description.split(" ")[0]} by ${this.config.reductionTargetPercent}%`;
609
+ case "severity-trend":
610
+ return "Eliminate all critical issues";
611
+ case "agent-concentration":
612
+ return `Reduce ${pattern.description.split(" ")[0]} issues by 50%`;
613
+ case "time-pattern":
614
+ return "Achieve 5 consecutive clean scans";
615
+ default:
616
+ return pattern.description;
617
+ }
618
+ }
619
+ /**
620
+ * Generate reasoning for why this goal was suggested
621
+ */
622
+ generateGoalReasoning(pattern) {
623
+ const evidence = pattern.evidence.join(". ");
624
+ return `Based on analysis: ${evidence}. Confidence: ${(pattern.confidence * 100).toFixed(0)}%`;
625
+ }
626
+ /**
627
+ * Auto-generate goals and create them (with auto-generated status)
628
+ *
629
+ * Returns goals that need user acceptance.
630
+ */
631
+ async autoGenerateGoals() {
632
+ const opportunities = await this.generateGoalOpportunities();
633
+ const createdGoals = [];
634
+ for (const opportunity of opportunities) {
635
+ const goal = {
636
+ id: `goal-${Date.now()}-${Math.random().toString(36).slice(2, 8)}`,
637
+ ...opportunity.goal,
638
+ createdAt: (/* @__PURE__ */ new Date()).toISOString(),
639
+ updatedAt: (/* @__PURE__ */ new Date()).toISOString()
640
+ };
641
+ await this.guardianState.addGoal(goal);
642
+ createdGoals.push(goal);
643
+ if (this.insightStore.canCreateInsight("goal-suggestion")) {
644
+ const insight = {
645
+ id: `insight-goal-${goal.id}`,
646
+ type: "suggestion",
647
+ message: `\u{1F3AF} New goal suggested: ${goal.description}`,
648
+ context: opportunity.reasoning,
649
+ suggestedAction: "Review and accept/reject this goal",
650
+ relatedIssues: [],
651
+ priority: 6,
652
+ timestamp: Date.now(),
653
+ dismissed: false,
654
+ category: "progress",
655
+ details: {
656
+ examples: opportunity.pattern.evidence
657
+ }
658
+ };
659
+ await this.insightStore.addInsight(insight);
660
+ await this.insightStore.markInsightCreated("goal-suggestion");
661
+ }
662
+ }
663
+ return createdGoals;
664
+ }
665
+ /**
666
+ * Update goal progress based on current state
667
+ */
668
+ async updateGoalProgress() {
669
+ await this.guardianState.load();
670
+ const activeGoals = this.guardianState.getActiveGoals();
671
+ for (const goal of activeGoals) {
672
+ const currentValue = await this.measureGoalMetric(goal);
673
+ await this.guardianState.updateGoal(goal.id, { currentValue });
674
+ if (this.isGoalAchieved(goal, currentValue)) {
675
+ await this.guardianState.updateGoal(goal.id, {
676
+ status: "achieved",
677
+ achievedAt: (/* @__PURE__ */ new Date()).toISOString(),
678
+ currentValue
679
+ });
680
+ await this.celebrateGoalAchievement(goal);
681
+ }
682
+ if (goal.deadline) {
683
+ const deadline = new Date(goal.deadline);
684
+ if (Date.now() > deadline.getTime() && !this.isGoalAchieved(goal, currentValue)) {
685
+ await this.guardianState.updateGoal(goal.id, {
686
+ status: "failed",
687
+ currentValue
688
+ });
689
+ }
690
+ }
691
+ }
692
+ }
693
+ /**
694
+ * Measure the current value of a goal's metric
695
+ *
696
+ * Supports both structured metrics and semantic/natural language goals
697
+ */
698
+ async measureGoalMetric(goal) {
699
+ try {
700
+ const issues = await searchIssues("", {
701
+ workDir: this.projectPath,
702
+ limit: 1e3,
703
+ includeResolved: false
704
+ });
705
+ if (goal.metric.endsWith("_issues")) {
706
+ const prefix = goal.metric.replace("_issues", "");
707
+ if (prefix.includes("/")) {
708
+ return issues.filter((r) => r.issue.file.startsWith(prefix)).length;
709
+ }
710
+ return issues.filter((r) => r.issue.agent === prefix).length;
711
+ }
712
+ if (goal.metric === "critical_issues") {
713
+ return issues.filter((r) => r.issue.severity === "critical").length;
714
+ }
715
+ const desc = goal.description.toLowerCase();
716
+ if (desc.includes("dead code") || desc.includes("unused") || desc.includes("remove unused")) {
717
+ const deadCodeIssues = issues.filter((r) => {
718
+ const msg = r.issue.issue.toLowerCase();
719
+ return msg.includes("unused") || msg.includes("dead code") || msg.includes("never used") || msg.includes("unreachable") || msg.includes("no-unused") || msg.includes("defined but never");
720
+ });
721
+ return deadCodeIssues.length;
722
+ }
723
+ if (desc.includes("security") || desc.includes("vulnerab") || desc.includes("fix security")) {
724
+ const securityIssues = issues.filter(
725
+ (r) => r.issue.agent === "security" || r.issue.agent === "privacy" || r.issue.severity === "critical"
726
+ );
727
+ return securityIssues.length;
728
+ }
729
+ if (desc.includes("type") || desc.includes("typescript") || desc.includes("any type")) {
730
+ const typeIssues = issues.filter(
731
+ (r) => r.issue.agent === "typecheck" || r.issue.issue.toLowerCase().includes("type") || r.issue.issue.toLowerCase().includes("any")
732
+ );
733
+ return typeIssues.length;
734
+ }
735
+ if (desc.includes("test") || desc.includes("coverage")) {
736
+ const testIssues = issues.filter(
737
+ (r) => r.issue.agent === "test" || r.issue.issue.toLowerCase().includes("test") || r.issue.issue.toLowerCase().includes("coverage")
738
+ );
739
+ return testIssues.length;
740
+ }
741
+ if (desc.includes("performance") || desc.includes("slow") || desc.includes("optimize")) {
742
+ const perfIssues = issues.filter(
743
+ (r) => r.issue.agent === "performance" || r.issue.issue.toLowerCase().includes("performance") || r.issue.issue.toLowerCase().includes("slow")
744
+ );
745
+ return perfIssues.length;
746
+ }
747
+ if (desc.includes("accessibility") || desc.includes("a11y") || desc.includes("accessible")) {
748
+ const a11yIssues = issues.filter(
749
+ (r) => r.issue.agent === "accessibility" || r.issue.issue.toLowerCase().includes("accessibility")
750
+ );
751
+ return a11yIssues.length;
752
+ }
753
+ if (desc.includes("bug") || desc.includes("fix") || desc.includes("error")) {
754
+ const bugIssues = issues.filter(
755
+ (r) => r.issue.agent === "bug-finding" || r.issue.severity === "critical" || r.issue.severity === "serious"
756
+ );
757
+ return bugIssues.length;
758
+ }
759
+ if (desc.includes("quality") || desc.includes("clean") || desc.includes("improve")) {
760
+ return issues.length;
761
+ }
762
+ return issues.length;
763
+ } catch {
764
+ return goal.currentValue;
765
+ }
766
+ }
767
+ /**
768
+ * Check if a goal has been achieved
769
+ */
770
+ isGoalAchieved(goal, currentValue) {
771
+ switch (goal.type) {
772
+ case "reduction":
773
+ return currentValue <= goal.target;
774
+ case "score":
775
+ return currentValue >= goal.target;
776
+ case "streak":
777
+ return currentValue >= goal.target;
778
+ default:
779
+ return currentValue <= goal.target;
780
+ }
781
+ }
782
+ /**
783
+ * Create a celebration insight for goal achievement
784
+ */
785
+ async celebrateGoalAchievement(goal) {
786
+ const insight = {
787
+ id: `insight-achieved-${goal.id}`,
788
+ type: "celebration",
789
+ message: `\u{1F389} Goal achieved: ${goal.description}!`,
790
+ context: `Started at ${goal.startValue}, now at ${goal.currentValue}. Target was ${goal.target}.`,
791
+ relatedIssues: [],
792
+ priority: 8,
793
+ timestamp: Date.now(),
794
+ dismissed: false,
795
+ category: "progress"
796
+ };
797
+ await this.insightStore.addInsight(insight);
798
+ }
799
+ /**
800
+ * Accept an auto-generated goal
801
+ */
802
+ async acceptGoal(goalId) {
803
+ return this.guardianState.respondToGoal(goalId, true);
804
+ }
805
+ /**
806
+ * Reject an auto-generated goal
807
+ */
808
+ async rejectGoal(goalId) {
809
+ return this.guardianState.respondToGoal(goalId, false);
810
+ }
811
+ /**
812
+ * Get pending auto-generated goals (awaiting acceptance)
813
+ */
814
+ getPendingGoals() {
815
+ return this.guardianState.getAutoGeneratedGoals().filter((g) => g.status === "active");
816
+ }
817
+ /**
818
+ * Get goal progress summary
819
+ */
820
+ getGoalProgressSummary() {
821
+ const goals = this.guardianState.getAllGoals();
822
+ return {
823
+ active: goals.filter((g) => g.status === "active").length,
824
+ achieved: goals.filter((g) => g.status === "achieved").length,
825
+ failed: goals.filter((g) => g.status === "failed").length,
826
+ pending: goals.filter((g) => g.autoGenerated && g.status === "active").length
827
+ };
828
+ }
829
+ };
830
+ async function calculateAdaptiveScanFrequency(projectPath) {
831
+ const guardianState = getGuardianState(projectPath);
832
+ await guardianState.load();
833
+ try {
834
+ const stats = await getMemoryStats(projectPath);
835
+ const issues = await searchIssues("", {
836
+ workDir: projectPath,
837
+ limit: 100,
838
+ includeResolved: false
839
+ });
840
+ const criticalCount = issues.filter((r) => r.issue.severity === "critical").length;
841
+ const seriousCount = issues.filter((r) => r.issue.severity === "serious").length;
842
+ if (criticalCount >= 3) {
843
+ return {
844
+ frequencyMs: 6e4,
845
+ reason: `${criticalCount} critical issues detected - scanning frequently`
846
+ };
847
+ }
848
+ if (criticalCount > 0 || seriousCount >= 5) {
849
+ return {
850
+ frequencyMs: 12e4,
851
+ reason: `Critical or many serious issues - elevated scan frequency`
852
+ };
853
+ }
854
+ if (seriousCount > 0) {
855
+ return {
856
+ frequencyMs: 18e4,
857
+ reason: `${seriousCount} serious issues - moderate scan frequency`
858
+ };
859
+ }
860
+ if (stats.totalIssues > 10) {
861
+ return {
862
+ frequencyMs: 3e5,
863
+ reason: "Some issues present - standard scan frequency"
864
+ };
865
+ }
866
+ return {
867
+ frequencyMs: 6e5,
868
+ reason: "Code looks good - relaxed scan frequency"
869
+ };
870
+ } catch {
871
+ return {
872
+ frequencyMs: 3e5,
873
+ reason: "Default scan frequency (5 min)"
874
+ };
875
+ }
876
+ }
877
+ async function adaptScanFrequency(projectPath) {
878
+ const guardianState = getGuardianState(projectPath);
879
+ const { frequencyMs } = await calculateAdaptiveScanFrequency(projectPath);
880
+ await guardianState.setScanFrequency(frequencyMs);
881
+ return frequencyMs;
882
+ }
883
+ var goalManagers = /* @__PURE__ */ new Map();
884
+ function getGoalManager(projectPath) {
885
+ let manager = goalManagers.get(projectPath);
886
+ if (!manager) {
887
+ manager = new GoalManager(projectPath);
888
+ goalManagers.set(projectPath, manager);
889
+ }
890
+ return manager;
891
+ }
892
+ function clearGoalManagers() {
893
+ goalManagers.clear();
894
+ }
895
+
896
+ export {
897
+ getInsightStore,
898
+ GoalManager,
899
+ calculateAdaptiveScanFrequency,
900
+ adaptScanFrequency,
901
+ getGoalManager,
902
+ clearGoalManagers
903
+ };
904
+ //# sourceMappingURL=chunk-D3DMONAJ.js.map