@triedotdev/mcp 1.0.49 → 1.0.51

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 (41) hide show
  1. package/README.md +545 -406
  2. package/dist/agent-smith-BECRZH73.js +12 -0
  3. package/dist/{agent-smith-runner-ZTDCJJQG.js → agent-smith-runner-LZRXM2Q2.js} +7 -7
  4. package/dist/agent-smith-runner-LZRXM2Q2.js.map +1 -0
  5. package/dist/{chunk-KQOMSIVR.js → chunk-A43476GB.js} +13 -9
  6. package/dist/chunk-A43476GB.js.map +1 -0
  7. package/dist/{chunk-IMFD4SJC.js → chunk-ASGSTVVF.js} +1 -1
  8. package/dist/chunk-ASGSTVVF.js.map +1 -0
  9. package/dist/chunk-C3AS5OXW.js +1177 -0
  10. package/dist/chunk-C3AS5OXW.js.map +1 -0
  11. package/dist/chunk-IEFAQFDQ.js +2061 -0
  12. package/dist/chunk-IEFAQFDQ.js.map +1 -0
  13. package/dist/{chunk-GLC62PGD.js → chunk-KB5ZN6K2.js} +2 -2
  14. package/dist/{chunk-VZYCZXEQ.js → chunk-TOE75CFZ.js} +2034 -391
  15. package/dist/chunk-TOE75CFZ.js.map +1 -0
  16. package/dist/{chunk-JDICQHNT.js → chunk-YKUCIKTU.js} +171 -1245
  17. package/dist/chunk-YKUCIKTU.js.map +1 -0
  18. package/dist/cli/create-agent.js +2 -2
  19. package/dist/cli/main.js +428 -71
  20. package/dist/cli/main.js.map +1 -1
  21. package/dist/cli/yolo-daemon.js +32 -20
  22. package/dist/cli/yolo-daemon.js.map +1 -1
  23. package/dist/comprehension-46F7ZNKL.js +821 -0
  24. package/dist/comprehension-46F7ZNKL.js.map +1 -0
  25. package/dist/index.js +478 -122
  26. package/dist/index.js.map +1 -1
  27. package/dist/workers/agent-worker.js +11 -11
  28. package/dist/workers/agent-worker.js.map +1 -1
  29. package/package.json +3 -1
  30. package/dist/agent-smith-5QOZXLMV.js +0 -11
  31. package/dist/agent-smith-runner-ZTDCJJQG.js.map +0 -1
  32. package/dist/chunk-6T7S77U7.js +0 -852
  33. package/dist/chunk-6T7S77U7.js.map +0 -1
  34. package/dist/chunk-IMFD4SJC.js.map +0 -1
  35. package/dist/chunk-JDICQHNT.js.map +0 -1
  36. package/dist/chunk-KQOMSIVR.js.map +0 -1
  37. package/dist/chunk-PZDQIFKO.js +0 -1598
  38. package/dist/chunk-PZDQIFKO.js.map +0 -1
  39. package/dist/chunk-VZYCZXEQ.js.map +0 -1
  40. /package/dist/{agent-smith-5QOZXLMV.js.map → agent-smith-BECRZH73.js.map} +0 -0
  41. /package/dist/{chunk-GLC62PGD.js.map → chunk-KB5ZN6K2.js.map} +0 -0
@@ -0,0 +1,1177 @@
1
+ import {
2
+ CustomSkill,
3
+ getGlobalMemoryStats,
4
+ getHistoricalInsights,
5
+ getMemoryStats,
6
+ getRecentIssues,
7
+ getSkillRegistry,
8
+ loadContextState
9
+ } from "./chunk-TOE75CFZ.js";
10
+
11
+ // src/orchestrator/triager.ts
12
+ var Triager = class {
13
+ agentRegistry = getSkillRegistry();
14
+ config;
15
+ customSkillsLoaded = false;
16
+ contextState = null;
17
+ memoryInsights = null;
18
+ constructor(config) {
19
+ this.config = {
20
+ minConfidence: 0.15,
21
+ maxAgents: 11,
22
+ timeoutMs: 6e4,
23
+ enableCostAware: false,
24
+ enableDependencies: true,
25
+ ...config
26
+ };
27
+ }
28
+ /**
29
+ * Load previous context state for smart triaging
30
+ */
31
+ async loadPreviousContext() {
32
+ if (this.contextState === null) {
33
+ try {
34
+ this.contextState = await loadContextState();
35
+ } catch {
36
+ this.contextState = null;
37
+ }
38
+ }
39
+ }
40
+ /**
41
+ * Load memory insights for memory-influenced triaging
42
+ */
43
+ async loadMemoryInsights() {
44
+ if (this.memoryInsights !== null) return;
45
+ try {
46
+ const [stats, recent, historical, global] = await Promise.all([
47
+ getMemoryStats().catch(() => null),
48
+ getRecentIssues({ limit: 20 }).catch(() => []),
49
+ getHistoricalInsights(process.cwd()).catch(() => null),
50
+ getGlobalMemoryStats().catch(() => null)
51
+ ]);
52
+ const recentAgents = /* @__PURE__ */ new Set();
53
+ for (const issue of recent) {
54
+ recentAgents.add(issue.agent);
55
+ }
56
+ const recurringPatternAgents = /* @__PURE__ */ new Set();
57
+ if (historical?.recurringPatterns) {
58
+ for (const pattern of historical.recurringPatterns) {
59
+ recurringPatternAgents.add(pattern.agent);
60
+ }
61
+ }
62
+ const crossProjectAgents = /* @__PURE__ */ new Set();
63
+ if (global?.patternsByAgent) {
64
+ for (const [agent, count] of Object.entries(global.patternsByAgent)) {
65
+ if (count >= 2) {
66
+ crossProjectAgents.add(agent);
67
+ }
68
+ }
69
+ }
70
+ this.memoryInsights = {
71
+ issuesByAgent: stats?.issuesByAgent || {},
72
+ recentAgents,
73
+ recurringPatternAgents,
74
+ trend: historical?.improvementTrend || "unknown",
75
+ crossProjectAgents
76
+ };
77
+ } catch {
78
+ this.memoryInsights = {
79
+ issuesByAgent: {},
80
+ recentAgents: /* @__PURE__ */ new Set(),
81
+ recurringPatternAgents: /* @__PURE__ */ new Set(),
82
+ trend: "unknown",
83
+ crossProjectAgents: /* @__PURE__ */ new Set()
84
+ };
85
+ }
86
+ }
87
+ /**
88
+ * Ensure custom skills are loaded before triaging
89
+ */
90
+ async ensureCustomSkillsLoaded() {
91
+ if (!this.customSkillsLoaded) {
92
+ await this.agentRegistry.loadCustomSkills();
93
+ this.customSkillsLoaded = true;
94
+ }
95
+ }
96
+ async selectAgents(context, riskLevel) {
97
+ await this.ensureCustomSkillsLoaded();
98
+ await Promise.all([
99
+ this.loadPreviousContext(),
100
+ this.loadMemoryInsights()
101
+ ]);
102
+ let effectiveRiskLevel = riskLevel;
103
+ if (this.contextState?.healthScore !== void 0 && this.contextState.healthScore < 50) {
104
+ if (riskLevel === "low" || riskLevel === "medium") {
105
+ effectiveRiskLevel = "high";
106
+ console.error(` \u{1F4CA} Health score ${this.contextState.healthScore}% - escalating to ${effectiveRiskLevel.toUpperCase()} risk`);
107
+ }
108
+ }
109
+ if (effectiveRiskLevel === "critical" || effectiveRiskLevel === "high") {
110
+ console.error(` \u26A0\uFE0F ${effectiveRiskLevel.toUpperCase()} risk - activating all agents for comprehensive review`);
111
+ return this.getAllAgents().filter((agent) => agent.shouldActivate(context));
112
+ }
113
+ const scores = this.scoreAgents(context, effectiveRiskLevel);
114
+ this.boostAgentsWithHistory(scores);
115
+ this.boostAgentsWithMemory(scores);
116
+ this.logAgentScoring(scores);
117
+ const qualified = scores.filter((s) => s.confidence >= this.config.minConfidence);
118
+ qualified.sort((a, b) => {
119
+ if (a.tier !== b.tier) return a.tier - b.tier;
120
+ return b.confidence - a.confidence;
121
+ });
122
+ if (this.config.enableDependencies) {
123
+ return this.resolveDependencies(qualified.map((s) => s.agent));
124
+ }
125
+ return qualified.map((s) => s.agent);
126
+ }
127
+ /**
128
+ * Boost confidence for agents that found issues in previous scans
129
+ */
130
+ boostAgentsWithHistory(scores) {
131
+ if (!this.contextState?.agentStatus) return;
132
+ for (const score of scores) {
133
+ const previousRun = this.contextState.agentStatus[score.agent.name];
134
+ if (previousRun?.issuesFound && previousRun.issuesFound > 0) {
135
+ const boost = Math.min(0.3, previousRun.issuesFound * 0.05);
136
+ score.confidence = Math.min(1, score.confidence + boost);
137
+ score.reasons.push(`found ${previousRun.issuesFound} issues in last scan`);
138
+ }
139
+ }
140
+ }
141
+ /**
142
+ * Boost confidence for agents based on memory patterns
143
+ */
144
+ boostAgentsWithMemory(scores) {
145
+ if (!this.memoryInsights) return;
146
+ for (const score of scores) {
147
+ const agentName = score.agent.name;
148
+ const historicalCount = this.memoryInsights.issuesByAgent[agentName] || 0;
149
+ if (historicalCount >= 10) {
150
+ const boost = Math.min(0.2, historicalCount * 0.01);
151
+ score.confidence = Math.min(1, score.confidence + boost);
152
+ score.reasons.push(`${historicalCount} historical issues`);
153
+ }
154
+ if (this.memoryInsights.recentAgents.has(agentName)) {
155
+ score.confidence = Math.min(1, score.confidence + 0.1);
156
+ score.reasons.push("recent activity");
157
+ }
158
+ if (this.memoryInsights.recurringPatternAgents.has(agentName)) {
159
+ score.confidence = Math.min(1, score.confidence + 0.15);
160
+ score.reasons.push("recurring patterns");
161
+ }
162
+ if (this.memoryInsights.crossProjectAgents.has(agentName)) {
163
+ score.confidence = Math.min(1, score.confidence + 0.1);
164
+ score.reasons.push("cross-project pattern");
165
+ }
166
+ }
167
+ if (this.memoryInsights.trend === "declining") {
168
+ for (const score of scores) {
169
+ if (score.confidence > 0) {
170
+ score.confidence = Math.min(1, score.confidence + 0.05);
171
+ }
172
+ }
173
+ }
174
+ }
175
+ scoreAgents(context, riskLevel) {
176
+ const allAgents = this.getAllAgents();
177
+ const scores = [];
178
+ for (const agent of allAgents) {
179
+ const score = this.scoreAgent(agent, context, riskLevel);
180
+ scores.push(score);
181
+ }
182
+ return scores;
183
+ }
184
+ scoreAgent(agent, context, riskLevel) {
185
+ if (agent instanceof CustomSkill) {
186
+ return this.scoreCustomSkill(agent, context, riskLevel);
187
+ }
188
+ return this.scoreBuiltinAgent(agent, context, riskLevel);
189
+ }
190
+ /**
191
+ * Score custom skills using their activation rules
192
+ */
193
+ scoreCustomSkill(agent, context, riskLevel) {
194
+ const reasons = [];
195
+ let confidence = agent.getActivationConfidence(context);
196
+ if (confidence > 0) {
197
+ reasons.push(`custom skill: ${agent.getMetadata().category}`);
198
+ const meta = agent.getMetadata();
199
+ if (meta.patternCount > 0) {
200
+ reasons.push(`${meta.patternCount} detection patterns`);
201
+ }
202
+ }
203
+ if (riskLevel === "high" && confidence > 0) {
204
+ confidence = Math.min(1, confidence * 1.2);
205
+ }
206
+ return {
207
+ agent,
208
+ confidence,
209
+ reasons,
210
+ tier: agent.priority.tier,
211
+ isCustom: true
212
+ };
213
+ }
214
+ /**
215
+ * Score built-in agents
216
+ */
217
+ scoreBuiltinAgent(agent, context, riskLevel) {
218
+ const reasons = [];
219
+ let confidence = 0;
220
+ let tier = 3;
221
+ if (agent.name === "typecheck") {
222
+ tier = 1;
223
+ confidence = 1;
224
+ reasons.push("fundamental type safety");
225
+ }
226
+ if (agent.name === "comprehension") {
227
+ tier = 1;
228
+ confidence = 1;
229
+ reasons.push("stakeholder communication");
230
+ }
231
+ if (agent.name === "security") {
232
+ tier = 2;
233
+ if (context.touchesAuth) {
234
+ confidence += 0.4;
235
+ reasons.push("auth code");
236
+ }
237
+ if (context.touchesPayments) {
238
+ confidence += 0.4;
239
+ reasons.push("payment code");
240
+ }
241
+ if (context.touchesAPI) {
242
+ confidence += 0.3;
243
+ reasons.push("API endpoints");
244
+ }
245
+ if (context.touchesDatabase) {
246
+ confidence += 0.25;
247
+ reasons.push("database access");
248
+ }
249
+ if (context.touchesCrypto) {
250
+ confidence += 0.35;
251
+ reasons.push("cryptographic operations");
252
+ }
253
+ if (context.touchesUserData) {
254
+ confidence += 0.3;
255
+ reasons.push("user data");
256
+ }
257
+ if (context.touchesSecurityConfig) {
258
+ confidence += 0.4;
259
+ reasons.push("security config");
260
+ }
261
+ if (context.touchesThirdPartyAPI) {
262
+ confidence += 0.2;
263
+ reasons.push("third-party integration");
264
+ }
265
+ if (context.patterns?.hasFileUploads) {
266
+ confidence += 0.3;
267
+ reasons.push("file uploads");
268
+ }
269
+ if (riskLevel === "high") confidence *= 1.2;
270
+ }
271
+ if (agent.name === "privacy") {
272
+ tier = 2;
273
+ if (context.touchesUserData) {
274
+ confidence += 0.5;
275
+ reasons.push("PII handling");
276
+ }
277
+ if (context.touchesAuth) {
278
+ confidence += 0.3;
279
+ reasons.push("credentials");
280
+ }
281
+ if (context.touchesLogging) {
282
+ confidence += 0.25;
283
+ reasons.push("logging (may expose data)");
284
+ }
285
+ if (context.patterns?.hasEmailHandling) {
286
+ confidence += 0.3;
287
+ reasons.push("email handling");
288
+ }
289
+ if (context.patterns?.hasFormHandling) {
290
+ confidence += 0.2;
291
+ reasons.push("form data");
292
+ }
293
+ }
294
+ if (agent.name === "legal") {
295
+ tier = 2;
296
+ if (context.touchesUserData) {
297
+ confidence += 0.4;
298
+ reasons.push("GDPR/CCPA");
299
+ }
300
+ if (context.touchesPayments) {
301
+ confidence += 0.35;
302
+ reasons.push("PCI-DSS");
303
+ }
304
+ if (context.patterns?.hasEmailHandling) {
305
+ confidence += 0.25;
306
+ reasons.push("CAN-SPAM");
307
+ }
308
+ }
309
+ if (agent.name === "accessibility") {
310
+ tier = 2;
311
+ if (context.touchesUI) {
312
+ confidence += 0.6;
313
+ reasons.push("UI components");
314
+ }
315
+ if (context.framework === "react" || context.framework === "vue") {
316
+ confidence += 0.2;
317
+ reasons.push(`${context.framework} framework`);
318
+ }
319
+ if (context.patterns?.hasFormHandling) {
320
+ confidence += 0.2;
321
+ reasons.push("form UX");
322
+ }
323
+ }
324
+ if (agent.name === "test") {
325
+ tier = 2;
326
+ if (context.isNewFeature) {
327
+ confidence += 0.4;
328
+ reasons.push("new feature");
329
+ }
330
+ if (context.touchesAuth) {
331
+ confidence += 0.35;
332
+ reasons.push("auth needs tests");
333
+ }
334
+ if (context.touchesPayments) {
335
+ confidence += 0.4;
336
+ reasons.push("payments need tests");
337
+ }
338
+ if (context.touchesAPI) {
339
+ confidence += 0.3;
340
+ reasons.push("API testing");
341
+ }
342
+ if (!context.hasTests) {
343
+ confidence += 0.2;
344
+ reasons.push("no existing tests");
345
+ }
346
+ if (context.complexity === "high") {
347
+ confidence += 0.25;
348
+ reasons.push("complex code");
349
+ }
350
+ }
351
+ if (agent.name === "software-architect") {
352
+ tier = 2;
353
+ if (context.isNewFeature) {
354
+ confidence += 0.35;
355
+ reasons.push("architecture review");
356
+ }
357
+ if (context.touchesDatabase) {
358
+ confidence += 0.35;
359
+ reasons.push("data modeling");
360
+ }
361
+ if (context.linesChanged > 200) {
362
+ confidence += 0.3;
363
+ reasons.push("large change");
364
+ }
365
+ if (context.touchesAPI) {
366
+ confidence += 0.25;
367
+ reasons.push("API design");
368
+ }
369
+ if (context.patterns?.hasWebSockets) {
370
+ confidence += 0.3;
371
+ reasons.push("real-time architecture");
372
+ }
373
+ if (context.patterns?.hasQueue) {
374
+ confidence += 0.3;
375
+ reasons.push("async architecture");
376
+ }
377
+ }
378
+ if (agent.name === "devops") {
379
+ tier = 2;
380
+ if (context.touchesSecurityConfig) {
381
+ confidence += 0.4;
382
+ reasons.push("security config");
383
+ }
384
+ if (context.touchesFileSystem) {
385
+ confidence += 0.3;
386
+ reasons.push("file operations");
387
+ }
388
+ if (context.touchesLogging) {
389
+ confidence += 0.25;
390
+ reasons.push("logging");
391
+ }
392
+ if (context.touchesErrorHandling) {
393
+ confidence += 0.2;
394
+ reasons.push("error handling");
395
+ }
396
+ if (context.patterns?.hasCaching) {
397
+ confidence += 0.25;
398
+ reasons.push("caching");
399
+ }
400
+ if (context.patterns?.hasRateLimiting) {
401
+ confidence += 0.3;
402
+ reasons.push("rate limiting");
403
+ }
404
+ }
405
+ if (agent.name === "bug-finding") {
406
+ tier = 2;
407
+ if (context.touchesPayments) {
408
+ confidence += 0.5;
409
+ reasons.push("payments = zero bugs");
410
+ }
411
+ if (context.isNewFeature) {
412
+ confidence += 0.3;
413
+ reasons.push("new code");
414
+ }
415
+ if (context.patterns?.hasAsyncCode) {
416
+ confidence += 0.35;
417
+ reasons.push("async patterns");
418
+ }
419
+ if (context.complexity === "high") {
420
+ confidence += 0.3;
421
+ reasons.push("complex logic");
422
+ }
423
+ if (context.touchesDatabase) {
424
+ confidence += 0.25;
425
+ reasons.push("data mutations");
426
+ }
427
+ }
428
+ if (agent.name === "user-testing") {
429
+ tier = 3;
430
+ if (context.touchesUI) {
431
+ confidence += 0.5;
432
+ reasons.push("UI changes");
433
+ }
434
+ if (context.isNewFeature && context.touchesUI) {
435
+ confidence += 0.3;
436
+ reasons.push("new UI feature");
437
+ }
438
+ if (context.patterns?.hasFormHandling) {
439
+ confidence += 0.25;
440
+ reasons.push("form UX");
441
+ }
442
+ }
443
+ if (agent.name === "trie_clean") {
444
+ tier = 2;
445
+ if (context.touchesUI) {
446
+ confidence += 0.4;
447
+ reasons.push("UI code");
448
+ }
449
+ if (context.isNewFeature) {
450
+ confidence += 0.3;
451
+ reasons.push("new feature");
452
+ }
453
+ if (context.framework === "react") {
454
+ confidence += 0.2;
455
+ reasons.push("React code");
456
+ }
457
+ }
458
+ if (agent.name === "soc2") {
459
+ tier = 2;
460
+ if (context.touchesAuth) {
461
+ confidence += 0.4;
462
+ reasons.push("authentication");
463
+ }
464
+ if (context.touchesSecurityConfig) {
465
+ confidence += 0.4;
466
+ reasons.push("security config");
467
+ }
468
+ if (context.touchesLogging) {
469
+ confidence += 0.3;
470
+ reasons.push("logging");
471
+ }
472
+ if (context.touchesAPI) {
473
+ confidence += 0.25;
474
+ reasons.push("API endpoints");
475
+ }
476
+ if (context.touchesDatabase) {
477
+ confidence += 0.2;
478
+ reasons.push("data access");
479
+ }
480
+ }
481
+ if (agent.name === "moneybags") {
482
+ tier = 3;
483
+ if (context.touchesPayments) {
484
+ confidence += 0.6;
485
+ reasons.push("payment code = high cost risk");
486
+ }
487
+ if (context.touchesAuth) {
488
+ confidence += 0.4;
489
+ reasons.push("auth bugs are expensive");
490
+ }
491
+ if (context.touchesHealthData) {
492
+ confidence += 0.5;
493
+ reasons.push("HIPAA violations");
494
+ }
495
+ if (context.touchesUserData) {
496
+ confidence += 0.3;
497
+ reasons.push("PII exposure costs");
498
+ }
499
+ if (context.touchesDatabase) {
500
+ confidence += 0.25;
501
+ reasons.push("data loss risk");
502
+ }
503
+ if (context.isNewFeature) {
504
+ confidence += 0.2;
505
+ reasons.push("new code risk");
506
+ }
507
+ if (riskLevel === "high" || riskLevel === "critical") {
508
+ confidence *= 1.3;
509
+ reasons.push("high-stakes context");
510
+ }
511
+ }
512
+ if (agent.name === "production-ready") {
513
+ tier = 3;
514
+ if (context.touchesAPI) {
515
+ confidence += 0.4;
516
+ reasons.push("API deployment");
517
+ }
518
+ if (context.touchesDatabase) {
519
+ confidence += 0.35;
520
+ reasons.push("database operations");
521
+ }
522
+ if (context.touchesAuth) {
523
+ confidence += 0.35;
524
+ reasons.push("auth system");
525
+ }
526
+ if (context.touchesPayments) {
527
+ confidence += 0.5;
528
+ reasons.push("payment processing");
529
+ }
530
+ if (context.linesChanged > 200) {
531
+ confidence += 0.3;
532
+ reasons.push("significant changes");
533
+ }
534
+ if (riskLevel === "high" || riskLevel === "critical") {
535
+ confidence += 0.4;
536
+ reasons.push("production gate check");
537
+ }
538
+ }
539
+ confidence = Math.min(1, confidence);
540
+ return { agent, confidence, reasons, tier, isCustom: false };
541
+ }
542
+ logAgentScoring(scores) {
543
+ console.error("\n \u{1F4CA} Agent Confidence Scores:");
544
+ const sorted = [...scores].sort((a, b) => b.confidence - a.confidence);
545
+ for (const score of sorted) {
546
+ const bar = this.getConfidenceBar(score.confidence);
547
+ const status = score.confidence >= this.config.minConfidence ? "\u2713" : "\u2717";
548
+ const tierLabel = score.tier === 1 ? "[T1]" : score.tier === 2 ? "[T2]" : "[T3]";
549
+ const customLabel = score.isCustom ? " \u{1F4DA}" : "";
550
+ console.error(` ${status} ${score.agent.name.padEnd(18)} ${tierLabel} ${bar} ${(score.confidence * 100).toFixed(0)}%${customLabel}`);
551
+ if (score.reasons.length > 0 && score.confidence > 0) {
552
+ console.error(` \u2514\u2500 ${score.reasons.join(", ")}`);
553
+ }
554
+ }
555
+ console.error("");
556
+ }
557
+ getConfidenceBar(confidence) {
558
+ const filled = Math.round(confidence * 10);
559
+ const empty = 10 - filled;
560
+ return "\u2588".repeat(filled) + "\u2591".repeat(empty);
561
+ }
562
+ resolveDependencies(agents) {
563
+ const agentNames = new Set(agents.map((a) => a.name));
564
+ const resolved = [];
565
+ const added = /* @__PURE__ */ new Set();
566
+ const dependencies = {
567
+ "legal": ["privacy"],
568
+ // legal should see privacy issues first
569
+ "test": ["bug-finding"],
570
+ // find bugs before writing tests
571
+ "user-testing": ["accessibility"]
572
+ // accessibility before UX
573
+ };
574
+ for (const agent of agents) {
575
+ const deps = dependencies[agent.name] || [];
576
+ for (const depName of deps) {
577
+ if (!added.has(depName)) {
578
+ const depAgent = this.agentRegistry.getAgent(depName);
579
+ if (depAgent && agentNames.has(depName)) {
580
+ resolved.push(depAgent);
581
+ added.add(depName);
582
+ }
583
+ }
584
+ }
585
+ if (!added.has(agent.name)) {
586
+ resolved.push(agent);
587
+ added.add(agent.name);
588
+ }
589
+ }
590
+ return resolved;
591
+ }
592
+ getTriagingReason(context, riskLevel) {
593
+ if (riskLevel === "critical") {
594
+ return "Critical risk detected - activating all agents for comprehensive review";
595
+ }
596
+ const reasons = [];
597
+ if (context.touchesAuth) reasons.push("authentication");
598
+ if (context.touchesPayments) reasons.push("payments");
599
+ if (context.touchesDatabase) reasons.push("database");
600
+ if (context.touchesUserData) reasons.push("user data");
601
+ if (context.touchesUI) reasons.push("UI");
602
+ if (context.touchesAPI) reasons.push("API");
603
+ if (context.isNewFeature) reasons.push("new feature");
604
+ if (context.touchesCrypto) reasons.push("cryptography");
605
+ if (context.touchesThirdPartyAPI) reasons.push("3rd party API");
606
+ if (reasons.length === 0) {
607
+ return `${riskLevel} risk - general code changes`;
608
+ }
609
+ return `${riskLevel} risk: ${reasons.join(", ")}`;
610
+ }
611
+ async getSkippedAgents(context, riskLevel) {
612
+ await this.ensureCustomSkillsLoaded();
613
+ if (riskLevel === "critical") return [];
614
+ const scores = this.scoreAgents(context, riskLevel);
615
+ return scores.filter((s) => s.confidence < this.config.minConfidence).map((s) => s.agent.name);
616
+ }
617
+ async getTriagingConfidence(context, riskLevel) {
618
+ await this.ensureCustomSkillsLoaded();
619
+ const scores = this.scoreAgents(context, riskLevel);
620
+ const qualified = scores.filter((s) => s.confidence >= this.config.minConfidence);
621
+ if (qualified.length === 0) return 0.5;
622
+ const avgConfidence = qualified.reduce((sum, s) => sum + s.confidence, 0) / qualified.length;
623
+ const contextStrength = this.getContextStrength(context);
624
+ return Math.min(1, avgConfidence * 0.7 + contextStrength * 0.3);
625
+ }
626
+ getContextStrength(context) {
627
+ let signals = 0;
628
+ const checks = [
629
+ context.touchesAuth,
630
+ context.touchesPayments,
631
+ context.touchesDatabase,
632
+ context.touchesAPI,
633
+ context.touchesUI,
634
+ context.touchesUserData,
635
+ context.touchesHealthData,
636
+ context.touchesSecurityConfig,
637
+ context.touchesCrypto,
638
+ context.touchesFileSystem,
639
+ context.isNewFeature
640
+ ];
641
+ for (const check of checks) {
642
+ if (check) signals++;
643
+ }
644
+ return signals > 0 ? Math.min(1, signals / 3) : 0.3;
645
+ }
646
+ getAllAgents() {
647
+ return this.agentRegistry.getAllAgents();
648
+ }
649
+ /**
650
+ * Get custom skills count
651
+ */
652
+ getCustomSkillCount() {
653
+ return this.agentRegistry.getCustomSkills().length;
654
+ }
655
+ // Backward compatibility alias
656
+ getCustomAgentCount() {
657
+ return this.getCustomSkillCount();
658
+ }
659
+ /**
660
+ * Reload custom skills
661
+ */
662
+ async reloadCustomSkills() {
663
+ await this.agentRegistry.reloadCustomSkills();
664
+ }
665
+ // Backward compatibility alias
666
+ async reloadCustomAgents() {
667
+ return this.reloadCustomSkills();
668
+ }
669
+ };
670
+
671
+ // src/utils/parallel-executor.ts
672
+ import { Worker } from "worker_threads";
673
+ import { cpus } from "os";
674
+ var ParallelExecutor = class {
675
+ maxWorkers;
676
+ cache;
677
+ streaming;
678
+ activeWorkers = /* @__PURE__ */ new Set();
679
+ cacheEnabled = true;
680
+ useWorkerThreads = false;
681
+ constructor(cacheManager, maxWorkers = Math.max(2, Math.min(cpus().length - 1, 8)), options) {
682
+ this.maxWorkers = maxWorkers;
683
+ this.cache = cacheManager;
684
+ this.cacheEnabled = options?.cacheEnabled ?? true;
685
+ this.useWorkerThreads = options?.useWorkerThreads ?? false;
686
+ }
687
+ /**
688
+ * Set streaming manager for real-time updates
689
+ */
690
+ setStreaming(streaming) {
691
+ this.streaming = streaming;
692
+ }
693
+ /**
694
+ * Execute agents in parallel with intelligent scheduling
695
+ */
696
+ async executeAgents(agents, files, context) {
697
+ if (agents.length === 0) {
698
+ return /* @__PURE__ */ new Map();
699
+ }
700
+ if (this.streaming && this.streaming.getProgress().totalFiles === 0) {
701
+ this.streaming.startScan(files.length);
702
+ }
703
+ const cacheResults = /* @__PURE__ */ new Map();
704
+ const uncachedTasks = [];
705
+ for (const agent of agents) {
706
+ const cached = await this.checkAgentCache(agent, files);
707
+ if (cached) {
708
+ cacheResults.set(agent.name, cached);
709
+ this.streaming?.completeAgent(agent.name, cached.issues);
710
+ } else {
711
+ uncachedTasks.push({
712
+ agent,
713
+ files,
714
+ context,
715
+ priority: agent.priority?.tier || 2,
716
+ timeoutMs: context?.config?.timeoutMs || 12e4
717
+ });
718
+ }
719
+ }
720
+ uncachedTasks.sort((a, b) => a.priority - b.priority);
721
+ const parallelResults = await this.executeTasksParallel(uncachedTasks);
722
+ await this.cacheResults(parallelResults);
723
+ const allResults = /* @__PURE__ */ new Map();
724
+ for (const [agent, result] of cacheResults) {
725
+ allResults.set(agent, result);
726
+ }
727
+ for (const result of parallelResults) {
728
+ allResults.set(result.agent, result.result);
729
+ }
730
+ const allIssues = Array.from(allResults.values()).flatMap((r) => r.issues);
731
+ this.streaming?.completeScan(allIssues);
732
+ return allResults;
733
+ }
734
+ /**
735
+ * Check if agent has cached results for given files
736
+ */
737
+ async checkAgentCache(agent, files) {
738
+ if (!this.cacheEnabled || !this.cache) {
739
+ return null;
740
+ }
741
+ const cachedIssues = await this.cache.getCachedBatch(files, agent.name);
742
+ if (cachedIssues.size === files.length) {
743
+ const allIssues = Array.from(cachedIssues.values()).flat();
744
+ return {
745
+ agent: agent.name,
746
+ issues: allIssues,
747
+ executionTime: 0,
748
+ // Cached
749
+ success: true,
750
+ metadata: {
751
+ filesAnalyzed: files.length,
752
+ linesAnalyzed: 0
753
+ }
754
+ };
755
+ }
756
+ return null;
757
+ }
758
+ /**
759
+ * Execute tasks in parallel batches
760
+ */
761
+ async executeTasksParallel(tasks) {
762
+ if (tasks.length === 0) {
763
+ return [];
764
+ }
765
+ const results = [];
766
+ const batches = this.createBatches(tasks, this.maxWorkers);
767
+ for (const batch of batches) {
768
+ const batchResults = await Promise.all(
769
+ batch.map((task) => this.executeTask(task))
770
+ );
771
+ results.push(...batchResults);
772
+ }
773
+ return results;
774
+ }
775
+ /**
776
+ * Create batches for parallel execution
777
+ */
778
+ createBatches(tasks, batchSize) {
779
+ const batches = [];
780
+ for (let i = 0; i < tasks.length; i += batchSize) {
781
+ batches.push(tasks.slice(i, i + batchSize));
782
+ }
783
+ return batches;
784
+ }
785
+ /**
786
+ * Execute a single task
787
+ */
788
+ async executeTask(task) {
789
+ const startTime = Date.now();
790
+ this.streaming?.startAgent(task.agent.name);
791
+ try {
792
+ const result = this.useWorkerThreads ? await this.executeTaskInWorker(task) : await task.agent.scan(task.files, task.context);
793
+ const executionTime = Date.now() - startTime;
794
+ this.streaming?.completeAgent(task.agent.name, result.issues);
795
+ return {
796
+ agent: task.agent.name,
797
+ result,
798
+ fromCache: false,
799
+ executionTime
800
+ };
801
+ } catch (error) {
802
+ const executionTime = Date.now() - startTime;
803
+ const errorMessage = error instanceof Error ? error.message : String(error);
804
+ this.streaming?.reportError(new Error(errorMessage), `Agent: ${task.agent.name}`);
805
+ return {
806
+ agent: task.agent.name,
807
+ result: {
808
+ agent: task.agent.name,
809
+ issues: [],
810
+ executionTime,
811
+ success: false,
812
+ error: errorMessage
813
+ },
814
+ fromCache: false,
815
+ executionTime
816
+ };
817
+ }
818
+ }
819
+ async executeTaskInWorker(task) {
820
+ const distDir = new URL(".", import.meta.url);
821
+ const workerUrl = new URL("workers/agent-worker.js", distDir);
822
+ return new Promise((resolve, reject) => {
823
+ const worker = new Worker(workerUrl, {
824
+ workerData: {
825
+ agentName: task.agent.name,
826
+ files: task.files,
827
+ context: task.context
828
+ }
829
+ });
830
+ this.activeWorkers.add(worker);
831
+ const timeout = setTimeout(() => {
832
+ worker.terminate().catch(() => void 0);
833
+ reject(new Error(`Agent ${task.agent.name} timed out after ${task.timeoutMs}ms`));
834
+ }, task.timeoutMs);
835
+ worker.on("message", (message) => {
836
+ if (message?.type === "result") {
837
+ clearTimeout(timeout);
838
+ resolve(message.result);
839
+ } else if (message?.type === "error") {
840
+ clearTimeout(timeout);
841
+ reject(new Error(message.error));
842
+ }
843
+ });
844
+ worker.on("error", (error) => {
845
+ clearTimeout(timeout);
846
+ reject(error);
847
+ });
848
+ worker.on("exit", (code) => {
849
+ this.activeWorkers.delete(worker);
850
+ if (code !== 0) {
851
+ clearTimeout(timeout);
852
+ reject(new Error(`Worker stopped with exit code ${code}`));
853
+ }
854
+ });
855
+ });
856
+ }
857
+ /**
858
+ * Cache results for future use
859
+ */
860
+ async cacheResults(results) {
861
+ if (!this.cacheEnabled || !this.cache) {
862
+ return;
863
+ }
864
+ const cachePromises = results.filter((r) => r.result.success && !r.fromCache).map((r) => {
865
+ const issuesByFile = this.groupIssuesByFile(r.result.issues);
866
+ const perFilePromises = Object.entries(issuesByFile).map(
867
+ ([file, issues]) => this.cache.setCached(file, r.agent, issues, r.executionTime)
868
+ );
869
+ return Promise.all(perFilePromises);
870
+ });
871
+ await Promise.allSettled(cachePromises);
872
+ }
873
+ /**
874
+ * Cleanup resources
875
+ */
876
+ async cleanup() {
877
+ const terminationPromises = Array.from(this.activeWorkers).map(
878
+ (worker) => worker.terminate()
879
+ );
880
+ await Promise.allSettled(terminationPromises);
881
+ this.activeWorkers.clear();
882
+ }
883
+ groupIssuesByFile(issues) {
884
+ const grouped = {};
885
+ for (const issue of issues) {
886
+ if (!grouped[issue.file]) {
887
+ grouped[issue.file] = [];
888
+ }
889
+ grouped[issue.file].push(issue);
890
+ }
891
+ return grouped;
892
+ }
893
+ };
894
+ function calculateOptimalConcurrency() {
895
+ const numCPUs = cpus().length;
896
+ const availableMemoryGB = process.memoryUsage().rss / 1024 / 1024 / 1024;
897
+ let optimal = Math.max(2, Math.min(numCPUs - 1, 8));
898
+ if (availableMemoryGB < 2) {
899
+ optimal = Math.max(2, Math.floor(optimal / 2));
900
+ }
901
+ if (numCPUs > 8) {
902
+ optimal = Math.min(optimal + 2, 12);
903
+ }
904
+ return optimal;
905
+ }
906
+
907
+ // src/utils/cache-manager.ts
908
+ import { readFile, writeFile, mkdir, stat } from "fs/promises";
909
+ import { join } from "path";
910
+ import { createHash } from "crypto";
911
+ var CacheManager = class {
912
+ cacheDir;
913
+ indexPath;
914
+ VERSION = "1.0.0";
915
+ MAX_AGE_MS = 24 * 60 * 60 * 1e3;
916
+ // 24 hours
917
+ MAX_ENTRIES = 1e3;
918
+ constructor(baseDir) {
919
+ this.cacheDir = join(baseDir, ".trie", "cache");
920
+ this.indexPath = join(this.cacheDir, "index.json");
921
+ }
922
+ /**
923
+ * Generate cache key for a file and agent combination
924
+ */
925
+ generateCacheKey(filePath, agent, fileHash) {
926
+ const key = `${filePath}:${agent}:${fileHash}`;
927
+ return createHash("sha256").update(key).digest("hex").slice(0, 16);
928
+ }
929
+ /**
930
+ * Get file hash for cache validation
931
+ */
932
+ async getFileHash(filePath) {
933
+ try {
934
+ const content = await readFile(filePath, "utf-8");
935
+ const stats = await stat(filePath);
936
+ const hash = createHash("sha256").update(content).digest("hex").slice(0, 16);
937
+ return {
938
+ hash,
939
+ size: stats.size,
940
+ mtime: stats.mtime.getTime()
941
+ };
942
+ } catch {
943
+ return { hash: "", size: 0, mtime: 0 };
944
+ }
945
+ }
946
+ /**
947
+ * Load cache index
948
+ */
949
+ async loadIndex() {
950
+ try {
951
+ const content = await readFile(this.indexPath, "utf-8");
952
+ return JSON.parse(content);
953
+ } catch {
954
+ return {
955
+ version: this.VERSION,
956
+ created: Date.now(),
957
+ entries: {}
958
+ };
959
+ }
960
+ }
961
+ /**
962
+ * Save cache index
963
+ */
964
+ async saveIndex(index) {
965
+ try {
966
+ await mkdir(this.cacheDir, { recursive: true });
967
+ await writeFile(this.indexPath, JSON.stringify(index, null, 2));
968
+ } catch (error) {
969
+ console.warn("Failed to save cache index:", error);
970
+ }
971
+ }
972
+ /**
973
+ * Clean up expired entries
974
+ */
975
+ cleanupExpired(index) {
976
+ const now = Date.now();
977
+ const validEntries = {};
978
+ for (const [key, entry] of Object.entries(index.entries)) {
979
+ if (now - entry.timestamp < this.MAX_AGE_MS) {
980
+ validEntries[key] = entry;
981
+ }
982
+ }
983
+ const entries = Object.entries(validEntries);
984
+ if (entries.length > this.MAX_ENTRIES) {
985
+ entries.sort((a, b) => b[1].timestamp - a[1].timestamp);
986
+ const limited = entries.slice(0, this.MAX_ENTRIES);
987
+ return {
988
+ ...index,
989
+ entries: Object.fromEntries(limited)
990
+ };
991
+ }
992
+ return {
993
+ ...index,
994
+ entries: validEntries
995
+ };
996
+ }
997
+ /**
998
+ * Get cached result for a file and agent
999
+ */
1000
+ async getCached(filePath, agent) {
1001
+ try {
1002
+ const { hash, size: _size, mtime: _mtime } = await this.getFileHash(filePath);
1003
+ if (!hash) return null;
1004
+ const index = await this.loadIndex();
1005
+ const cacheKey = this.generateCacheKey(filePath, agent, hash);
1006
+ const entry = index.entries[cacheKey];
1007
+ if (!entry) return null;
1008
+ const isValid = entry.fileHash === hash && entry.version === this.VERSION && Date.now() - entry.timestamp < this.MAX_AGE_MS;
1009
+ if (!isValid) {
1010
+ delete index.entries[cacheKey];
1011
+ await this.saveIndex(index);
1012
+ return null;
1013
+ }
1014
+ return entry.issues;
1015
+ } catch {
1016
+ return null;
1017
+ }
1018
+ }
1019
+ /**
1020
+ * Cache result for a file and agent
1021
+ */
1022
+ async setCached(filePath, agent, issues, executionTime) {
1023
+ try {
1024
+ const { hash, size } = await this.getFileHash(filePath);
1025
+ if (!hash) return;
1026
+ const index = await this.loadIndex();
1027
+ const cacheKey = this.generateCacheKey(filePath, agent, hash);
1028
+ index.entries[cacheKey] = {
1029
+ version: this.VERSION,
1030
+ timestamp: Date.now(),
1031
+ fileHash: hash,
1032
+ fileSize: size,
1033
+ agent,
1034
+ issues,
1035
+ executionTime
1036
+ };
1037
+ const cleanedIndex = this.cleanupExpired(index);
1038
+ await this.saveIndex(cleanedIndex);
1039
+ } catch (error) {
1040
+ console.warn("Failed to cache result:", error);
1041
+ }
1042
+ }
1043
+ /**
1044
+ * Check if multiple files have cached results
1045
+ */
1046
+ async getCachedBatch(files, agent) {
1047
+ const results = /* @__PURE__ */ new Map();
1048
+ await Promise.all(
1049
+ files.map(async (file) => {
1050
+ const cached = await this.getCached(file, agent);
1051
+ if (cached) {
1052
+ results.set(file, cached);
1053
+ }
1054
+ })
1055
+ );
1056
+ return results;
1057
+ }
1058
+ /**
1059
+ * Get cache statistics
1060
+ */
1061
+ async getStats() {
1062
+ try {
1063
+ const index = await this.loadIndex();
1064
+ const entries = Object.values(index.entries);
1065
+ const totalSizeKB = entries.reduce((acc, entry) => acc + entry.fileSize, 0) / 1024;
1066
+ const timestamps = entries.map((e) => e.timestamp);
1067
+ const agents = [...new Set(entries.map((e) => e.agent))];
1068
+ return {
1069
+ totalEntries: entries.length,
1070
+ totalSizeKB: Math.round(totalSizeKB),
1071
+ oldestEntry: timestamps.length > 0 ? Math.min(...timestamps) : null,
1072
+ newestEntry: timestamps.length > 0 ? Math.max(...timestamps) : null,
1073
+ agents
1074
+ };
1075
+ } catch {
1076
+ return {
1077
+ totalEntries: 0,
1078
+ totalSizeKB: 0,
1079
+ oldestEntry: null,
1080
+ newestEntry: null,
1081
+ agents: []
1082
+ };
1083
+ }
1084
+ }
1085
+ /**
1086
+ * Clear all cache
1087
+ */
1088
+ async clear() {
1089
+ try {
1090
+ const emptyIndex = {
1091
+ version: this.VERSION,
1092
+ created: Date.now(),
1093
+ entries: {}
1094
+ };
1095
+ await this.saveIndex(emptyIndex);
1096
+ } catch (error) {
1097
+ console.warn("Failed to clear cache:", error);
1098
+ }
1099
+ }
1100
+ };
1101
+
1102
+ // src/orchestrator/executor.ts
1103
+ var Executor = class {
1104
+ async executeAgents(agents, files, context, options) {
1105
+ const parallel = options?.parallel ?? true;
1106
+ const cacheEnabled = options?.cacheEnabled ?? true;
1107
+ const maxConcurrency = options?.maxConcurrency ?? calculateOptimalConcurrency();
1108
+ const useWorkerThreads = options?.useWorkerThreads ?? false;
1109
+ console.error(`\u26A1 Executing ${agents.length} agents ${parallel ? "in parallel" : "sequentially"}...`);
1110
+ if (parallel) {
1111
+ const cacheManager = cacheEnabled ? new CacheManager(context.workingDir) : null;
1112
+ const executor = new ParallelExecutor(cacheManager, maxConcurrency, {
1113
+ cacheEnabled,
1114
+ useWorkerThreads
1115
+ });
1116
+ if (options?.streaming) {
1117
+ executor.setStreaming(options.streaming);
1118
+ }
1119
+ const results = await executor.executeAgents(agents, files, {
1120
+ ...context,
1121
+ config: { timeoutMs: options?.timeoutMs ?? 12e4 }
1122
+ });
1123
+ return agents.map((agent) => results.get(agent.name)).filter(Boolean);
1124
+ }
1125
+ const promises = agents.map(
1126
+ (agent) => this.executeAgentWithTimeout(agent, files, context, options?.timeoutMs ?? 3e4)
1127
+ );
1128
+ try {
1129
+ const results = await Promise.allSettled(promises);
1130
+ return results.map((result, index) => {
1131
+ if (result.status === "fulfilled") {
1132
+ console.error(`\u2705 ${agents[index].name} completed in ${result.value.executionTime}ms`);
1133
+ return result.value;
1134
+ } else {
1135
+ console.error(`\u274C ${agents[index].name} failed:`, result.reason);
1136
+ return {
1137
+ agent: agents[index].name,
1138
+ issues: [],
1139
+ executionTime: 0,
1140
+ success: false,
1141
+ error: result.reason instanceof Error ? result.reason.message : String(result.reason)
1142
+ };
1143
+ }
1144
+ });
1145
+ } catch (error) {
1146
+ console.error("Executor error:", error);
1147
+ return agents.map((agent) => ({
1148
+ agent: agent.name,
1149
+ issues: [],
1150
+ executionTime: 0,
1151
+ success: false,
1152
+ error: "Execution failed"
1153
+ }));
1154
+ }
1155
+ }
1156
+ async executeAgentWithTimeout(agent, files, context, timeoutMs = 3e4) {
1157
+ return new Promise(async (resolve, reject) => {
1158
+ const timeout = setTimeout(() => {
1159
+ reject(new Error(`Agent ${agent.name} timed out after ${timeoutMs}ms`));
1160
+ }, timeoutMs);
1161
+ try {
1162
+ const result = await agent.scan(files, context);
1163
+ clearTimeout(timeout);
1164
+ resolve(result);
1165
+ } catch (error) {
1166
+ clearTimeout(timeout);
1167
+ reject(error);
1168
+ }
1169
+ });
1170
+ }
1171
+ };
1172
+
1173
+ export {
1174
+ Triager,
1175
+ Executor
1176
+ };
1177
+ //# sourceMappingURL=chunk-C3AS5OXW.js.map