@triedotdev/mcp 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js ADDED
@@ -0,0 +1,3882 @@
1
+ #!/usr/bin/env node
2
+ import {
3
+ listCustomAgents,
4
+ loadAgentConfig,
5
+ parseDocument
6
+ } from "./chunk-EYNAGEQK.js";
7
+ import {
8
+ AgentRegistry,
9
+ TrieFixTool,
10
+ TrieScanTool,
11
+ getPrompt,
12
+ getSystemPrompt
13
+ } from "./chunk-E7CKHS3R.js";
14
+ import "./chunk-3CS6Z2SL.js";
15
+ import "./chunk-MR755QGT.js";
16
+ import "./chunk-6NLHFIYA.js";
17
+ import "./chunk-DGUM43GV.js";
18
+
19
+ // src/index.ts
20
+ import { Server } from "@modelcontextprotocol/sdk/server/index.js";
21
+ import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
22
+ import {
23
+ CallToolRequestSchema,
24
+ ListToolsRequestSchema,
25
+ ListResourcesRequestSchema,
26
+ ReadResourceRequestSchema
27
+ } from "@modelcontextprotocol/sdk/types.js";
28
+ import { readdir as readdir2, readFile as readFile6 } from "fs/promises";
29
+ import { join as join6 } from "path";
30
+
31
+ // src/tools/explain.ts
32
+ import { readFile } from "fs/promises";
33
+ import { existsSync } from "fs";
34
+ import { extname, relative, resolve, isAbsolute } from "path";
35
+ var TrieExplainTool = class {
36
+ async execute(args) {
37
+ const { type, target, context, depth = "standard" } = args || {};
38
+ if (!type || !target) {
39
+ return {
40
+ content: [{
41
+ type: "text",
42
+ text: this.getHelpText()
43
+ }]
44
+ };
45
+ }
46
+ switch (type) {
47
+ case "code":
48
+ return this.explainCode(target, context, depth);
49
+ case "issue":
50
+ return this.explainIssue(target, context);
51
+ case "change":
52
+ return this.explainChange(target, context);
53
+ case "risk":
54
+ return this.explainRisk(target, context);
55
+ default:
56
+ return {
57
+ content: [{
58
+ type: "text",
59
+ text: `Unknown explanation type: ${type}`
60
+ }]
61
+ };
62
+ }
63
+ }
64
+ async explainCode(target, context, _depth) {
65
+ let code;
66
+ let filePath;
67
+ let language;
68
+ const resolvedPath = isAbsolute(target) ? target : resolve(process.cwd(), target);
69
+ if (existsSync(resolvedPath)) {
70
+ code = await readFile(resolvedPath, "utf-8");
71
+ filePath = relative(process.cwd(), resolvedPath);
72
+ language = this.detectLanguage(resolvedPath);
73
+ } else {
74
+ code = target;
75
+ filePath = "inline";
76
+ language = this.guessLanguage(code);
77
+ }
78
+ const imports = this.extractImports(code, language);
79
+ const exports = this.extractExports(code);
80
+ const functions = this.extractFunctions(code, language);
81
+ const prompt = getPrompt("explain", "code", {
82
+ code,
83
+ language,
84
+ filePath
85
+ });
86
+ const systemPrompt = getSystemPrompt("explain");
87
+ let output = `
88
+ ${"\u2501".repeat(60)}
89
+ `;
90
+ output += `\u{1F4D6} CODE EXPLANATION
91
+ `;
92
+ output += `${"\u2501".repeat(60)}
93
+
94
+ `;
95
+ output += `## \u{1F4C2} Source
96
+
97
+ `;
98
+ output += `- **File:** \`${filePath}\`
99
+ `;
100
+ output += `- **Language:** ${language}
101
+ `;
102
+ output += `- **Lines:** ${code.split("\n").length}
103
+
104
+ `;
105
+ output += `## \u{1F50D} Structure Analysis
106
+
107
+ `;
108
+ if (imports.length > 0) {
109
+ output += `**Imports (${imports.length}):**
110
+ `;
111
+ for (const imp of imports.slice(0, 10)) {
112
+ output += `- ${imp}
113
+ `;
114
+ }
115
+ if (imports.length > 10) {
116
+ output += `- *...and ${imports.length - 10} more*
117
+ `;
118
+ }
119
+ output += "\n";
120
+ }
121
+ if (exports.length > 0) {
122
+ output += `**Exports (${exports.length}):**
123
+ `;
124
+ for (const exp of exports) {
125
+ output += `- ${exp}
126
+ `;
127
+ }
128
+ output += "\n";
129
+ }
130
+ if (functions.length > 0) {
131
+ output += `**Functions/Methods (${functions.length}):**
132
+ `;
133
+ for (const fn of functions.slice(0, 15)) {
134
+ output += `- \`${fn}\`
135
+ `;
136
+ }
137
+ if (functions.length > 15) {
138
+ output += `- *...and ${functions.length - 15} more*
139
+ `;
140
+ }
141
+ output += "\n";
142
+ }
143
+ output += `${"\u2500".repeat(60)}
144
+ `;
145
+ output += `## \u{1F9E0} Deep Explanation Request
146
+
147
+ `;
148
+ output += `**Role:** ${systemPrompt.split("\n")[0]}
149
+
150
+ `;
151
+ output += prompt;
152
+ output += `
153
+ ${"\u2500".repeat(60)}
154
+ `;
155
+ if (context) {
156
+ output += `
157
+ **Additional Context:** ${context}
158
+ `;
159
+ }
160
+ return { content: [{ type: "text", text: output }] };
161
+ }
162
+ async explainIssue(target, _context) {
163
+ let file = "";
164
+ let line = 0;
165
+ let issue = target;
166
+ let severity = "unknown";
167
+ const match = target.match(/^(.+?):(\d+):(.+)$/);
168
+ if (match) {
169
+ file = match[1];
170
+ line = parseInt(match[2], 10);
171
+ issue = match[3].trim();
172
+ }
173
+ if (/critical|injection|rce|xss/i.test(issue)) severity = "critical";
174
+ else if (/serious|auth|password|secret/i.test(issue)) severity = "serious";
175
+ else if (/moderate|warning/i.test(issue)) severity = "moderate";
176
+ else severity = "low";
177
+ let codeContext = "";
178
+ if (file && existsSync(file)) {
179
+ const content = await readFile(file, "utf-8");
180
+ const lines = content.split("\n");
181
+ const start = Math.max(0, line - 5);
182
+ const end = Math.min(lines.length, line + 5);
183
+ codeContext = lines.slice(start, end).map((l, i) => {
184
+ const lineNum = start + i + 1;
185
+ const marker = lineNum === line ? "\u2192 " : " ";
186
+ return `${marker}${lineNum.toString().padStart(4)} | ${l}`;
187
+ }).join("\n");
188
+ }
189
+ const prompt = getPrompt("explain", "issue", {
190
+ issue,
191
+ severity,
192
+ filePath: file || "unknown",
193
+ line: String(line || "?")
194
+ });
195
+ let output = `
196
+ ${"\u2501".repeat(60)}
197
+ `;
198
+ output += `\u{1F50D} ISSUE EXPLANATION
199
+ `;
200
+ output += `${"\u2501".repeat(60)}
201
+
202
+ `;
203
+ output += `## \u{1F4CD} Issue Details
204
+
205
+ `;
206
+ output += `- **Issue:** ${issue}
207
+ `;
208
+ output += `- **Severity:** ${this.getSeverityIcon(severity)} ${severity}
209
+ `;
210
+ if (file) output += `- **File:** \`${file}\`
211
+ `;
212
+ if (line) output += `- **Line:** ${line}
213
+ `;
214
+ output += "\n";
215
+ if (codeContext) {
216
+ output += `## \u{1F4C4} Code Context
217
+
218
+ `;
219
+ output += `\`\`\`
220
+ ${codeContext}
221
+ \`\`\`
222
+
223
+ `;
224
+ }
225
+ output += `${"\u2500".repeat(60)}
226
+ `;
227
+ output += `## \u{1F9E0} Explanation Request
228
+
229
+ `;
230
+ output += prompt;
231
+ output += `
232
+ ${"\u2500".repeat(60)}
233
+ `;
234
+ return { content: [{ type: "text", text: output }] };
235
+ }
236
+ async explainChange(target, context) {
237
+ const files = target.split(",").map((f) => f.trim());
238
+ let output = `
239
+ ${"\u2501".repeat(60)}
240
+ `;
241
+ output += `\u{1F4DD} CHANGE ANALYSIS
242
+ `;
243
+ output += `${"\u2501".repeat(60)}
244
+
245
+ `;
246
+ output += `## \u{1F4C2} Changed Files
247
+
248
+ `;
249
+ for (const file of files) {
250
+ output += `- \`${file}\`
251
+ `;
252
+ }
253
+ output += "\n";
254
+ output += `## \u{1F9E0} Analysis Request
255
+
256
+ `;
257
+ output += `Analyze these changes and explain:
258
+
259
+ `;
260
+ output += `1. **What changed** - Summary of modifications
261
+ `;
262
+ output += `2. **Why it matters** - Impact on the system
263
+ `;
264
+ output += `3. **Dependencies** - What else might be affected
265
+ `;
266
+ output += `4. **Testing needed** - What to test after this change
267
+ `;
268
+ output += `5. **Rollback plan** - How to undo if needed
269
+
270
+ `;
271
+ if (context) {
272
+ output += `**Context:** ${context}
273
+
274
+ `;
275
+ }
276
+ output += `Please review the changed files and provide this analysis.
277
+ `;
278
+ return { content: [{ type: "text", text: output }] };
279
+ }
280
+ async explainRisk(target, context) {
281
+ const resolvedPath = isAbsolute(target) ? target : resolve(process.cwd(), target);
282
+ let output = `
283
+ ${"\u2501".repeat(60)}
284
+ `;
285
+ output += `\u26A0\uFE0F RISK ASSESSMENT
286
+ `;
287
+ output += `${"\u2501".repeat(60)}
288
+
289
+ `;
290
+ if (existsSync(resolvedPath)) {
291
+ const code = await readFile(resolvedPath, "utf-8");
292
+ const filePath = relative(process.cwd(), resolvedPath);
293
+ const riskIndicators = this.detectRiskIndicators(code);
294
+ output += `## \u{1F4C2} Target
295
+
296
+ `;
297
+ output += `- **File:** \`${filePath}\`
298
+ `;
299
+ output += `- **Lines:** ${code.split("\n").length}
300
+
301
+ `;
302
+ if (riskIndicators.length > 0) {
303
+ output += `## \u{1F6A8} Risk Indicators Found
304
+
305
+ `;
306
+ for (const indicator of riskIndicators) {
307
+ output += `- ${indicator}
308
+ `;
309
+ }
310
+ output += "\n";
311
+ }
312
+ const prompt = getPrompt("explain", "risk", {
313
+ files: filePath,
314
+ summary: context || "Code change"
315
+ });
316
+ output += `${"\u2500".repeat(60)}
317
+ `;
318
+ output += `## \u{1F9E0} Risk Analysis Request
319
+
320
+ `;
321
+ output += prompt;
322
+ output += `
323
+ ${"\u2500".repeat(60)}
324
+ `;
325
+ } else {
326
+ output += `## \u{1F4CB} Feature/Change
327
+
328
+ `;
329
+ output += `${target}
330
+
331
+ `;
332
+ output += `## \u{1F9E0} Risk Analysis Request
333
+
334
+ `;
335
+ output += `Analyze the risks of this change:
336
+
337
+ `;
338
+ output += `1. **Technical risks** - What could break?
339
+ `;
340
+ output += `2. **Security risks** - Any vulnerabilities introduced?
341
+ `;
342
+ output += `3. **Performance risks** - Any slowdowns?
343
+ `;
344
+ output += `4. **Data risks** - Any data integrity concerns?
345
+ `;
346
+ output += `5. **User impact** - How might users be affected?
347
+ `;
348
+ output += `6. **Mitigation** - How to reduce these risks?
349
+ `;
350
+ }
351
+ return { content: [{ type: "text", text: output }] };
352
+ }
353
+ detectRiskIndicators(code) {
354
+ const indicators = [];
355
+ const checks = [
356
+ { pattern: /delete|drop|truncate/i, message: "\u26A0\uFE0F Destructive operations detected" },
357
+ { pattern: /password|secret|key|token/i, message: "\u{1F510} Credential handling detected" },
358
+ { pattern: /exec|eval|spawn/i, message: "\u{1F489} Code execution patterns detected" },
359
+ { pattern: /SELECT.*FROM|INSERT|UPDATE|DELETE/i, message: "\u{1F5C4}\uFE0F Direct database operations" },
360
+ { pattern: /fetch|axios|request|http/i, message: "\u{1F310} External API calls detected" },
361
+ { pattern: /process\.env/i, message: "\u2699\uFE0F Environment variable usage" },
362
+ { pattern: /fs\.|writeFile|readFile/i, message: "\u{1F4C1} File system operations" },
363
+ { pattern: /setTimeout|setInterval/i, message: "\u23F0 Async timing operations" },
364
+ { pattern: /try\s*{/i, message: "\u{1F6E1}\uFE0F Error handling present" },
365
+ { pattern: /catch\s*\(/i, message: "\u{1F6E1}\uFE0F Exception handling present" }
366
+ ];
367
+ for (const { pattern, message } of checks) {
368
+ if (pattern.test(code)) {
369
+ indicators.push(message);
370
+ }
371
+ }
372
+ return indicators;
373
+ }
374
+ extractImports(code, _language) {
375
+ const imports = [];
376
+ const lines = code.split("\n");
377
+ for (const line of lines) {
378
+ const es6Match = line.match(/import\s+(?:{[^}]+}|\*\s+as\s+\w+|\w+)\s+from\s+['"]([^'"]+)['"]/);
379
+ if (es6Match) {
380
+ imports.push(es6Match[1]);
381
+ continue;
382
+ }
383
+ const cjsMatch = line.match(/require\s*\(['"]([^'"]+)['"]\)/);
384
+ if (cjsMatch) {
385
+ imports.push(cjsMatch[1]);
386
+ continue;
387
+ }
388
+ const pyMatch = line.match(/^(?:from\s+(\S+)\s+)?import\s+(\S+)/);
389
+ if (pyMatch && _language === "python") {
390
+ imports.push(pyMatch[1] || pyMatch[2]);
391
+ }
392
+ }
393
+ return [...new Set(imports)];
394
+ }
395
+ extractExports(code) {
396
+ const exports = [];
397
+ const lines = code.split("\n");
398
+ for (const line of lines) {
399
+ const es6Match = line.match(/export\s+(?:default\s+)?(?:class|function|const|let|var|interface|type)\s+(\w+)/);
400
+ if (es6Match) {
401
+ exports.push(es6Match[1]);
402
+ }
403
+ const namedMatch = line.match(/export\s*\{([^}]+)\}/);
404
+ if (namedMatch) {
405
+ const names = namedMatch[1].split(",").map((n) => n.trim().split(/\s+as\s+/)[0].trim());
406
+ exports.push(...names);
407
+ }
408
+ }
409
+ return [...new Set(exports)];
410
+ }
411
+ extractFunctions(code, _language) {
412
+ const functions = [];
413
+ const lines = code.split("\n");
414
+ for (const line of lines) {
415
+ const funcMatch = line.match(/(?:async\s+)?function\s+(\w+)/);
416
+ if (funcMatch) {
417
+ functions.push(funcMatch[1]);
418
+ continue;
419
+ }
420
+ const arrowMatch = line.match(/(?:const|let|var)\s+(\w+)\s*=\s*(?:async\s*)?\(/);
421
+ if (arrowMatch) {
422
+ functions.push(arrowMatch[1]);
423
+ continue;
424
+ }
425
+ const methodMatch = line.match(/^\s+(?:async\s+)?(\w+)\s*\([^)]*\)\s*(?::\s*\w+)?\s*\{/);
426
+ if (methodMatch && !["if", "for", "while", "switch", "catch"].includes(methodMatch[1])) {
427
+ functions.push(methodMatch[1]);
428
+ }
429
+ }
430
+ return [...new Set(functions)];
431
+ }
432
+ detectLanguage(filePath) {
433
+ const ext = extname(filePath).toLowerCase();
434
+ const langMap = {
435
+ ".ts": "typescript",
436
+ ".tsx": "tsx",
437
+ ".js": "javascript",
438
+ ".jsx": "jsx",
439
+ ".py": "python",
440
+ ".go": "go",
441
+ ".rs": "rust",
442
+ ".java": "java",
443
+ ".rb": "ruby",
444
+ ".php": "php",
445
+ ".vue": "vue",
446
+ ".svelte": "svelte"
447
+ };
448
+ return langMap[ext] || "plaintext";
449
+ }
450
+ guessLanguage(code) {
451
+ if (/import.*from|export\s+(default|const|function|class)/.test(code)) return "typescript";
452
+ if (/def\s+\w+.*:/.test(code)) return "python";
453
+ if (/func\s+\w+.*\{/.test(code)) return "go";
454
+ if (/fn\s+\w+.*->/.test(code)) return "rust";
455
+ return "javascript";
456
+ }
457
+ getSeverityIcon(severity) {
458
+ const icons = {
459
+ critical: "\u{1F534}",
460
+ serious: "\u{1F7E0}",
461
+ moderate: "\u{1F7E1}",
462
+ low: "\u{1F535}",
463
+ unknown: "\u26AA"
464
+ };
465
+ return icons[severity] || "\u26AA";
466
+ }
467
+ getHelpText() {
468
+ return `
469
+ ${"\u2501".repeat(60)}
470
+ \u{1F4D6} TRIE EXPLAIN - AI-POWERED CODE EXPLANATION
471
+ ${"\u2501".repeat(60)}
472
+
473
+ ## Usage
474
+
475
+ ### Explain code:
476
+ \`\`\`
477
+ trie_explain type:"code" target:"src/app.ts"
478
+ \`\`\`
479
+
480
+ ### Explain an issue:
481
+ \`\`\`
482
+ trie_explain type:"issue" target:"SQL injection vulnerability"
483
+ \`\`\`
484
+ or with file context:
485
+ \`\`\`
486
+ trie_explain type:"issue" target:"src/db.ts:42:Unvalidated input"
487
+ \`\`\`
488
+
489
+ ### Explain changes:
490
+ \`\`\`
491
+ trie_explain type:"change" target:"src/auth.ts, src/user.ts"
492
+ \`\`\`
493
+
494
+ ### Assess risk:
495
+ \`\`\`
496
+ trie_explain type:"risk" target:"src/payment.ts"
497
+ \`\`\`
498
+ or for a feature:
499
+ \`\`\`
500
+ trie_explain type:"risk" target:"Adding Stripe integration for payments"
501
+ \`\`\`
502
+
503
+ ## Explanation Types
504
+
505
+ | Type | Description |
506
+ |------|-------------|
507
+ | code | What does this code do? |
508
+ | issue | Why is this a problem? |
509
+ | change | What's the impact? |
510
+ | risk | What could go wrong? |
511
+ `;
512
+ }
513
+ };
514
+
515
+ // src/tools/test.ts
516
+ import { readFile as readFile2 } from "fs/promises";
517
+ import { existsSync as existsSync2 } from "fs";
518
+ import { extname as extname2, relative as relative2, resolve as resolve2, isAbsolute as isAbsolute2, dirname, basename, join } from "path";
519
+ var TrieTestTool = class {
520
+ async execute(args) {
521
+ const { action, files, framework, style = "unit" } = args || {};
522
+ if (!action || !files || files.length === 0) {
523
+ return {
524
+ content: [{
525
+ type: "text",
526
+ text: this.getHelpText()
527
+ }]
528
+ };
529
+ }
530
+ switch (action) {
531
+ case "generate":
532
+ return this.generateTests(files, framework, style);
533
+ case "coverage":
534
+ return this.analyzeCoverage(files);
535
+ case "suggest":
536
+ return this.suggestTests(files);
537
+ case "run":
538
+ return this.runTestsInfo(files);
539
+ default:
540
+ return {
541
+ content: [{
542
+ type: "text",
543
+ text: `Unknown action: ${action}`
544
+ }]
545
+ };
546
+ }
547
+ }
548
+ async generateTests(files, framework, style) {
549
+ const detectedFramework = framework || await this.detectTestFramework();
550
+ let output = `
551
+ ${"\u2501".repeat(60)}
552
+ `;
553
+ output += `\u{1F9EA} TEST GENERATION
554
+ `;
555
+ output += `${"\u2501".repeat(60)}
556
+
557
+ `;
558
+ output += `## \u2699\uFE0F Configuration
559
+
560
+ `;
561
+ output += `- **Framework:** ${detectedFramework}
562
+ `;
563
+ output += `- **Style:** ${style}
564
+ `;
565
+ output += `- **Files:** ${files.length}
566
+
567
+ `;
568
+ const allUnits = [];
569
+ for (const file of files) {
570
+ const resolvedPath = isAbsolute2(file) ? file : resolve2(process.cwd(), file);
571
+ if (!existsSync2(resolvedPath)) {
572
+ output += `\u26A0\uFE0F File not found: ${file}
573
+ `;
574
+ continue;
575
+ }
576
+ const code = await readFile2(resolvedPath, "utf-8");
577
+ const language = this.detectLanguage(resolvedPath);
578
+ const relativePath = relative2(process.cwd(), resolvedPath);
579
+ const units = this.extractTestableUnits(code, language);
580
+ allUnits.push({ file: relativePath, units });
581
+ output += `### \u{1F4C4} ${relativePath}
582
+
583
+ `;
584
+ output += `Found **${units.length}** testable units:
585
+
586
+ `;
587
+ for (const unit of units) {
588
+ const complexityIcon = unit.complexity > 10 ? "\u{1F534}" : unit.complexity > 5 ? "\u{1F7E1}" : "\u{1F7E2}";
589
+ output += `- ${complexityIcon} \`${unit.name}\` (${unit.type}, complexity: ${unit.complexity})
590
+ `;
591
+ if (unit.dependencies.length > 0) {
592
+ output += ` - Dependencies: ${unit.dependencies.join(", ")}
593
+ `;
594
+ }
595
+ }
596
+ output += "\n";
597
+ }
598
+ output += `${"\u2500".repeat(60)}
599
+ `;
600
+ output += `## \u{1F9E0} Test Generation Request
601
+
602
+ `;
603
+ const systemPrompt = getSystemPrompt("test");
604
+ output += `**Role:** ${systemPrompt.split("\n")[0]}
605
+
606
+ `;
607
+ for (const { file, units } of allUnits) {
608
+ if (units.length === 0) continue;
609
+ const code = await readFile2(resolve2(process.cwd(), file), "utf-8");
610
+ const language = this.detectLanguage(file);
611
+ const prompt = getPrompt("test", "generate", {
612
+ code,
613
+ language,
614
+ filePath: file,
615
+ framework: detectedFramework
616
+ });
617
+ output += `### Tests for ${file}
618
+
619
+ `;
620
+ output += prompt;
621
+ output += "\n\n";
622
+ }
623
+ output += `${"\u2500".repeat(60)}
624
+ `;
625
+ output += `
626
+ ## \u{1F4DD} Expected Test Output
627
+
628
+ `;
629
+ output += `Generate complete test files with:
630
+ `;
631
+ output += `- All imports and setup
632
+ `;
633
+ output += `- Tests for each function/method
634
+ `;
635
+ output += `- Edge cases and error scenarios
636
+ `;
637
+ output += `- Mock requirements clearly stated
638
+ `;
639
+ output += `- Ready to copy and run
640
+ `;
641
+ return { content: [{ type: "text", text: output }] };
642
+ }
643
+ async analyzeCoverage(files) {
644
+ let output = `
645
+ ${"\u2501".repeat(60)}
646
+ `;
647
+ output += `\u{1F4CA} COVERAGE ANALYSIS
648
+ `;
649
+ output += `${"\u2501".repeat(60)}
650
+
651
+ `;
652
+ for (const file of files) {
653
+ const resolvedPath = isAbsolute2(file) ? file : resolve2(process.cwd(), file);
654
+ if (!existsSync2(resolvedPath)) {
655
+ output += `\u26A0\uFE0F File not found: ${file}
656
+ `;
657
+ continue;
658
+ }
659
+ const code = await readFile2(resolvedPath, "utf-8");
660
+ const language = this.detectLanguage(resolvedPath);
661
+ const relativePath = relative2(process.cwd(), resolvedPath);
662
+ const units = this.extractTestableUnits(code, language);
663
+ const testFile = await this.findTestFile(resolvedPath);
664
+ let testCode = "";
665
+ let testedUnits = [];
666
+ if (testFile) {
667
+ testCode = await readFile2(testFile, "utf-8");
668
+ testedUnits = this.findTestedUnits(testCode, units.map((u) => u.name));
669
+ }
670
+ const coverage = units.length > 0 ? Math.round(testedUnits.length / units.length * 100) : 0;
671
+ const coverageIcon = coverage >= 80 ? "\u{1F7E2}" : coverage >= 50 ? "\u{1F7E1}" : "\u{1F534}";
672
+ output += `### \u{1F4C4} ${relativePath}
673
+
674
+ `;
675
+ output += `**Coverage:** ${coverageIcon} ${coverage}% (${testedUnits.length}/${units.length} units)
676
+ `;
677
+ if (testFile) {
678
+ output += `**Test file:** \`${relative2(process.cwd(), testFile)}\`
679
+ `;
680
+ } else {
681
+ output += `**Test file:** \u274C Not found
682
+ `;
683
+ }
684
+ output += "\n";
685
+ const untested = units.filter((u) => !testedUnits.includes(u.name));
686
+ if (untested.length > 0) {
687
+ output += `**Missing Tests:**
688
+ `;
689
+ for (const unit of untested) {
690
+ const priority = unit.complexity > 5 ? "\u{1F534} HIGH" : "\u{1F7E1} MEDIUM";
691
+ output += `- ${priority}: \`${unit.name}\` (${unit.type})
692
+ `;
693
+ }
694
+ output += "\n";
695
+ }
696
+ if (testedUnits.length > 0) {
697
+ output += `**Tested:**
698
+ `;
699
+ for (const name of testedUnits) {
700
+ output += `- \u2705 \`${name}\`
701
+ `;
702
+ }
703
+ output += "\n";
704
+ }
705
+ }
706
+ output += `${"\u2500".repeat(60)}
707
+ `;
708
+ output += `## \u{1F4CB} Recommendations
709
+
710
+ `;
711
+ output += `To improve coverage:
712
+ `;
713
+ output += `1. Focus on high-complexity untested functions first
714
+ `;
715
+ output += `2. Add edge case tests for existing coverage
716
+ `;
717
+ output += `3. Consider integration tests for complex interactions
718
+ `;
719
+ output += `
720
+ Run \`trie_test action:generate files:["file.ts"]\` to generate missing tests.
721
+ `;
722
+ return { content: [{ type: "text", text: output }] };
723
+ }
724
+ async suggestTests(files) {
725
+ let output = `
726
+ ${"\u2501".repeat(60)}
727
+ `;
728
+ output += `\u{1F4A1} TEST SUGGESTIONS
729
+ `;
730
+ output += `${"\u2501".repeat(60)}
731
+
732
+ `;
733
+ for (const file of files) {
734
+ const resolvedPath = isAbsolute2(file) ? file : resolve2(process.cwd(), file);
735
+ if (!existsSync2(resolvedPath)) {
736
+ output += `\u26A0\uFE0F File not found: ${file}
737
+ `;
738
+ continue;
739
+ }
740
+ const code = await readFile2(resolvedPath, "utf-8");
741
+ const relativePath = relative2(process.cwd(), resolvedPath);
742
+ const patterns = this.detectTestablePatterns(code);
743
+ output += `### \u{1F4C4} ${relativePath}
744
+
745
+ `;
746
+ if (patterns.length === 0) {
747
+ output += `No specific test suggestions for this file.
748
+
749
+ `;
750
+ continue;
751
+ }
752
+ output += `| Priority | Pattern | Suggested Test |
753
+ `;
754
+ output += `|----------|---------|----------------|
755
+ `;
756
+ for (const pattern of patterns) {
757
+ output += `| ${pattern.priority} | ${pattern.name} | ${pattern.suggestion} |
758
+ `;
759
+ }
760
+ output += "\n";
761
+ }
762
+ return { content: [{ type: "text", text: output }] };
763
+ }
764
+ async runTestsInfo(files) {
765
+ const framework = await this.detectTestFramework();
766
+ let output = `
767
+ ${"\u2501".repeat(60)}
768
+ `;
769
+ output += `\u{1F3C3} RUN TESTS
770
+ `;
771
+ output += `${"\u2501".repeat(60)}
772
+
773
+ `;
774
+ output += `## Detected Configuration
775
+
776
+ `;
777
+ output += `- **Framework:** ${framework}
778
+ `;
779
+ output += `- **Files:** ${files.join(", ")}
780
+
781
+ `;
782
+ output += `## Commands
783
+
784
+ `;
785
+ switch (framework) {
786
+ case "jest":
787
+ output += `\`\`\`bash
788
+ `;
789
+ output += `# Run all tests
790
+ `;
791
+ output += `npx jest
792
+
793
+ `;
794
+ output += `# Run specific files
795
+ `;
796
+ output += `npx jest ${files.join(" ")}
797
+
798
+ `;
799
+ output += `# Run with coverage
800
+ `;
801
+ output += `npx jest --coverage
802
+ `;
803
+ output += `\`\`\`
804
+ `;
805
+ break;
806
+ case "vitest":
807
+ output += `\`\`\`bash
808
+ `;
809
+ output += `# Run all tests
810
+ `;
811
+ output += `npx vitest run
812
+
813
+ `;
814
+ output += `# Run specific files
815
+ `;
816
+ output += `npx vitest run ${files.join(" ")}
817
+
818
+ `;
819
+ output += `# Run with coverage
820
+ `;
821
+ output += `npx vitest run --coverage
822
+ `;
823
+ output += `\`\`\`
824
+ `;
825
+ break;
826
+ case "pytest":
827
+ output += `\`\`\`bash
828
+ `;
829
+ output += `# Run all tests
830
+ `;
831
+ output += `pytest
832
+
833
+ `;
834
+ output += `# Run specific files
835
+ `;
836
+ output += `pytest ${files.join(" ")}
837
+
838
+ `;
839
+ output += `# Run with coverage
840
+ `;
841
+ output += `pytest --cov
842
+ `;
843
+ output += `\`\`\`
844
+ `;
845
+ break;
846
+ default:
847
+ output += `Run your test framework with the specified files.
848
+ `;
849
+ }
850
+ output += `
851
+ *Note: This tool provides test commands but doesn't execute them directly.*
852
+ `;
853
+ return { content: [{ type: "text", text: output }] };
854
+ }
855
+ extractTestableUnits(code, language) {
856
+ const units = [];
857
+ const lines = code.split("\n");
858
+ for (let i = 0; i < lines.length; i++) {
859
+ const line = lines[i] || "";
860
+ const funcMatch = line.match(/(?:export\s+)?(?:async\s+)?function\s+(\w+)\s*\(([^)]*)\)/);
861
+ if (funcMatch) {
862
+ const endLine = this.findBlockEnd(lines, i);
863
+ const body = lines.slice(i, endLine + 1).join("\n");
864
+ units.push({
865
+ name: funcMatch[1],
866
+ type: "function",
867
+ startLine: i + 1,
868
+ endLine: endLine + 1,
869
+ signature: `${funcMatch[1]}(${funcMatch[2]})`,
870
+ complexity: this.calculateComplexity(body),
871
+ dependencies: this.extractDependencies(body)
872
+ });
873
+ }
874
+ const arrowMatch = line.match(/(?:export\s+)?(?:const|let)\s+(\w+)\s*=\s*(?:async\s*)?\([^)]*\)\s*(?:=>|:)/);
875
+ if (arrowMatch) {
876
+ const endLine = this.findBlockEnd(lines, i);
877
+ const body = lines.slice(i, endLine + 1).join("\n");
878
+ units.push({
879
+ name: arrowMatch[1],
880
+ type: "function",
881
+ startLine: i + 1,
882
+ endLine: endLine + 1,
883
+ signature: arrowMatch[1],
884
+ complexity: this.calculateComplexity(body),
885
+ dependencies: this.extractDependencies(body)
886
+ });
887
+ }
888
+ const classMatch = line.match(/(?:export\s+)?class\s+(\w+)/);
889
+ if (classMatch) {
890
+ const endLine = this.findBlockEnd(lines, i);
891
+ units.push({
892
+ name: classMatch[1],
893
+ type: "class",
894
+ startLine: i + 1,
895
+ endLine: endLine + 1,
896
+ signature: `class ${classMatch[1]}`,
897
+ complexity: this.calculateComplexity(lines.slice(i, endLine + 1).join("\n")),
898
+ dependencies: []
899
+ });
900
+ }
901
+ const componentMatch = line.match(/(?:export\s+)?(?:const|function)\s+([A-Z]\w+)\s*[=:]/);
902
+ if (componentMatch && /jsx|tsx/.test(language)) {
903
+ const endLine = this.findBlockEnd(lines, i);
904
+ units.push({
905
+ name: componentMatch[1],
906
+ type: "component",
907
+ startLine: i + 1,
908
+ endLine: endLine + 1,
909
+ signature: componentMatch[1],
910
+ complexity: this.calculateComplexity(lines.slice(i, endLine + 1).join("\n")),
911
+ dependencies: this.extractDependencies(lines.slice(i, endLine + 1).join("\n"))
912
+ });
913
+ }
914
+ }
915
+ return units;
916
+ }
917
+ findBlockEnd(lines, startLine) {
918
+ let braceCount = 0;
919
+ let started = false;
920
+ for (let i = startLine; i < lines.length; i++) {
921
+ const line = lines[i] || "";
922
+ for (const char of line) {
923
+ if (char === "{") {
924
+ braceCount++;
925
+ started = true;
926
+ } else if (char === "}") {
927
+ braceCount--;
928
+ }
929
+ }
930
+ if (started && braceCount === 0) {
931
+ return i;
932
+ }
933
+ }
934
+ return lines.length - 1;
935
+ }
936
+ calculateComplexity(code) {
937
+ let complexity = 1;
938
+ const patterns = [
939
+ /if\s*\(/g,
940
+ /else\s+if/g,
941
+ /\?\s*[^:]/g,
942
+ // Conditionals
943
+ /for\s*\(/g,
944
+ /while\s*\(/g,
945
+ /do\s*\{/g,
946
+ // Loops
947
+ /catch\s*\(/g,
948
+ // Error handling
949
+ /&&/g,
950
+ /\|\|/g,
951
+ // Logical operators
952
+ /case\s+/g
953
+ // Switch cases
954
+ ];
955
+ for (const pattern of patterns) {
956
+ const matches = code.match(pattern);
957
+ if (matches) {
958
+ complexity += matches.length;
959
+ }
960
+ }
961
+ return complexity;
962
+ }
963
+ extractDependencies(code) {
964
+ const deps = [];
965
+ const calls = code.match(/\b([a-z]\w+)\s*\(/gi) || [];
966
+ const builtins = ["if", "for", "while", "switch", "catch", "function", "return", "throw", "new", "await", "async"];
967
+ for (const call of calls) {
968
+ const name = call.replace(/\s*\($/, "");
969
+ if (!builtins.includes(name.toLowerCase()) && !deps.includes(name)) {
970
+ deps.push(name);
971
+ }
972
+ }
973
+ return deps.slice(0, 10);
974
+ }
975
+ async findTestFile(sourcePath) {
976
+ const dir = dirname(sourcePath);
977
+ const base = basename(sourcePath, extname2(sourcePath));
978
+ const ext = extname2(sourcePath);
979
+ const patterns = [
980
+ `${base}.test${ext}`,
981
+ `${base}.spec${ext}`,
982
+ `${base}_test${ext}`,
983
+ `test_${base}${ext}`
984
+ ];
985
+ for (const pattern of patterns) {
986
+ const testPath = join(dir, pattern);
987
+ if (existsSync2(testPath)) {
988
+ return testPath;
989
+ }
990
+ }
991
+ const testsDir = join(dir, "__tests__");
992
+ if (existsSync2(testsDir)) {
993
+ for (const pattern of patterns) {
994
+ const testPath = join(testsDir, pattern);
995
+ if (existsSync2(testPath)) {
996
+ return testPath;
997
+ }
998
+ }
999
+ }
1000
+ return null;
1001
+ }
1002
+ findTestedUnits(testCode, unitNames) {
1003
+ const tested = [];
1004
+ for (const name of unitNames) {
1005
+ const patterns = [
1006
+ new RegExp(`describe\\s*\\([^)]*${name}`, "i"),
1007
+ new RegExp(`it\\s*\\([^)]*${name}`, "i"),
1008
+ new RegExp(`test\\s*\\([^)]*${name}`, "i"),
1009
+ new RegExp(`expect\\s*\\([^)]*${name}`, "i")
1010
+ ];
1011
+ for (const pattern of patterns) {
1012
+ if (pattern.test(testCode)) {
1013
+ tested.push(name);
1014
+ break;
1015
+ }
1016
+ }
1017
+ }
1018
+ return tested;
1019
+ }
1020
+ detectTestablePatterns(code) {
1021
+ const patterns = [];
1022
+ const checks = [
1023
+ { pattern: /async\s+function|await\s+/i, priority: "\u{1F534} HIGH", name: "Async code", suggestion: "Test async flows and error handling" },
1024
+ { pattern: /try\s*{[^}]*catch/i, priority: "\u{1F534} HIGH", name: "Error handling", suggestion: "Test both success and error paths" },
1025
+ { pattern: /if\s*\([^)]*&&[^)]*\)/i, priority: "\u{1F7E1} MED", name: "Complex conditionals", suggestion: "Test all condition branches" },
1026
+ { pattern: /\.map\(|\.filter\(|\.reduce\(/i, priority: "\u{1F7E1} MED", name: "Array operations", suggestion: "Test with empty, single, multiple items" },
1027
+ { pattern: /fetch\(|axios\.|request\(/i, priority: "\u{1F534} HIGH", name: "HTTP requests", suggestion: "Mock API calls, test error responses" },
1028
+ { pattern: /localStorage|sessionStorage/i, priority: "\u{1F7E1} MED", name: "Storage usage", suggestion: "Mock storage, test read/write" },
1029
+ { pattern: /setTimeout|setInterval/i, priority: "\u{1F7E1} MED", name: "Timers", suggestion: "Use fake timers in tests" },
1030
+ { pattern: /useState|useEffect|useCallback/i, priority: "\u{1F534} HIGH", name: "React hooks", suggestion: "Test hook behavior and updates" },
1031
+ { pattern: /form|input|submit/i, priority: "\u{1F7E1} MED", name: "Form handling", suggestion: "Test validation and submission" }
1032
+ ];
1033
+ for (const { pattern, priority, name, suggestion } of checks) {
1034
+ if (pattern.test(code)) {
1035
+ patterns.push({ priority, name, suggestion });
1036
+ }
1037
+ }
1038
+ return patterns;
1039
+ }
1040
+ async detectTestFramework() {
1041
+ const packagePath = resolve2(process.cwd(), "package.json");
1042
+ if (existsSync2(packagePath)) {
1043
+ try {
1044
+ const pkg = JSON.parse(await readFile2(packagePath, "utf-8"));
1045
+ const deps = { ...pkg.dependencies, ...pkg.devDependencies };
1046
+ if (deps.vitest) return "vitest";
1047
+ if (deps.jest) return "jest";
1048
+ if (deps.mocha) return "mocha";
1049
+ } catch {
1050
+ }
1051
+ }
1052
+ if (existsSync2(resolve2(process.cwd(), "pytest.ini")) || existsSync2(resolve2(process.cwd(), "pyproject.toml"))) {
1053
+ return "pytest";
1054
+ }
1055
+ return "jest";
1056
+ }
1057
+ detectLanguage(filePath) {
1058
+ const ext = extname2(filePath).toLowerCase();
1059
+ const langMap = {
1060
+ ".ts": "typescript",
1061
+ ".tsx": "tsx",
1062
+ ".js": "javascript",
1063
+ ".jsx": "jsx",
1064
+ ".py": "python",
1065
+ ".go": "go",
1066
+ ".rs": "rust"
1067
+ };
1068
+ return langMap[ext] || "javascript";
1069
+ }
1070
+ getHelpText() {
1071
+ return `
1072
+ ${"\u2501".repeat(60)}
1073
+ \u{1F9EA} TRIE TEST - AI-POWERED TEST GENERATION
1074
+ ${"\u2501".repeat(60)}
1075
+
1076
+ ## Usage
1077
+
1078
+ ### Generate tests:
1079
+ \`\`\`
1080
+ trie_test action:"generate" files:["src/utils.ts"]
1081
+ \`\`\`
1082
+
1083
+ ### Analyze coverage:
1084
+ \`\`\`
1085
+ trie_test action:"coverage" files:["src/utils.ts"]
1086
+ \`\`\`
1087
+
1088
+ ### Get test suggestions:
1089
+ \`\`\`
1090
+ trie_test action:"suggest" files:["src/app.ts"]
1091
+ \`\`\`
1092
+
1093
+ ### Get run commands:
1094
+ \`\`\`
1095
+ trie_test action:"run" files:["src/utils.test.ts"]
1096
+ \`\`\`
1097
+
1098
+ ## Options
1099
+
1100
+ | Option | Values | Description |
1101
+ |--------|--------|-------------|
1102
+ | action | generate, coverage, suggest, run | What to do |
1103
+ | files | Array of paths | Files to analyze |
1104
+ | framework | jest, vitest, mocha, pytest | Test framework |
1105
+ | style | unit, integration, e2e, all | Test style |
1106
+ `;
1107
+ }
1108
+ };
1109
+
1110
+ // src/tools/register-agent.ts
1111
+ var TrieRegisterAgentTool = class {
1112
+ async execute(args) {
1113
+ const { name, path } = args;
1114
+ return {
1115
+ content: [
1116
+ {
1117
+ type: "text",
1118
+ text: `\u{1F916} Register agent tool called with name: ${name}, path: ${path}
1119
+
1120
+ TODO: Implement register agent functionality`
1121
+ }
1122
+ ]
1123
+ };
1124
+ }
1125
+ };
1126
+
1127
+ // src/tools/watch.ts
1128
+ import { watch } from "fs";
1129
+ import { stat } from "fs/promises";
1130
+ import { join as join2, extname as extname3, basename as basename2 } from "path";
1131
+ import { existsSync as existsSync3 } from "fs";
1132
+ var WATCH_EXTENSIONS = /* @__PURE__ */ new Set([
1133
+ ".ts",
1134
+ ".tsx",
1135
+ ".js",
1136
+ ".jsx",
1137
+ ".mjs",
1138
+ ".vue",
1139
+ ".svelte",
1140
+ ".astro",
1141
+ ".py",
1142
+ ".go",
1143
+ ".rs"
1144
+ ]);
1145
+ var SKIP_DIRS = /* @__PURE__ */ new Set([
1146
+ "node_modules",
1147
+ ".git",
1148
+ "dist",
1149
+ "build",
1150
+ ".next",
1151
+ ".nuxt",
1152
+ "coverage",
1153
+ ".turbo",
1154
+ ".cache"
1155
+ ]);
1156
+ var TrieWatchTool = class {
1157
+ scanTool = new TrieScanTool();
1158
+ fixTool = new TrieFixTool();
1159
+ state = {
1160
+ isRunning: false,
1161
+ yoloMode: false,
1162
+ lastScan: /* @__PURE__ */ new Map(),
1163
+ pendingFiles: /* @__PURE__ */ new Set(),
1164
+ scanDebounceTimer: null,
1165
+ issueCache: /* @__PURE__ */ new Map(),
1166
+ totalIssuesFound: 0,
1167
+ totalIssuesFixed: 0,
1168
+ filesScanned: 0
1169
+ };
1170
+ watchers = /* @__PURE__ */ new Map();
1171
+ async execute(args) {
1172
+ const { action, directory, debounceMs = 1e3, yolo = false } = args;
1173
+ switch (action) {
1174
+ case "start":
1175
+ return this.startWatching(directory || process.cwd(), debounceMs, yolo);
1176
+ case "stop":
1177
+ return this.stopWatching();
1178
+ case "status":
1179
+ return this.getStatus();
1180
+ case "issues":
1181
+ return this.getCurrentIssues();
1182
+ case "yolo":
1183
+ return this.toggleYoloMode();
1184
+ default:
1185
+ return {
1186
+ content: [{
1187
+ type: "text",
1188
+ text: `Unknown action: ${action}. Use 'start', 'stop', 'status', 'issues', or 'yolo'.`
1189
+ }]
1190
+ };
1191
+ }
1192
+ }
1193
+ async startWatching(directory, debounceMs, yoloMode) {
1194
+ if (this.state.isRunning) {
1195
+ return {
1196
+ content: [{
1197
+ type: "text",
1198
+ text: "\u26A0\uFE0F Watch mode is already running. Use `trie_watch stop` to stop it first."
1199
+ }]
1200
+ };
1201
+ }
1202
+ this.state.isRunning = true;
1203
+ this.state.yoloMode = yoloMode;
1204
+ this.state.issueCache.clear();
1205
+ this.state.totalIssuesFound = 0;
1206
+ this.state.totalIssuesFixed = 0;
1207
+ this.state.filesScanned = 0;
1208
+ const modeEmoji = yoloMode ? "\u{1F525}" : "\u{1F441}\uFE0F";
1209
+ const modeName = yoloMode ? "YOLO MODE" : "WATCH MODE";
1210
+ console.error("\n\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501");
1211
+ console.error(`${modeEmoji} TRIE AGENT - AUTONOMOUS ${modeName}`);
1212
+ console.error("\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\n");
1213
+ console.error(`\u{1F4C2} Watching: ${directory}`);
1214
+ console.error(`\u23F1\uFE0F Debounce: ${debounceMs}ms`);
1215
+ if (yoloMode) {
1216
+ console.error("\u{1F525} YOLO MODE: Auto-fixing issues as they occur!");
1217
+ }
1218
+ console.error("");
1219
+ await this.watchDirectory(directory, debounceMs);
1220
+ console.error("\u{1F50D} Running initial scan...\n");
1221
+ const initialResult = await this.scanTool.execute({ directory });
1222
+ const yoloMessage = yoloMode ? `
1223
+ ### \u{1F525} YOLO MODE ENABLED
1224
+ Issues will be **automatically fixed** as they're detected!
1225
+ - High-confidence fixes applied immediately
1226
+ - No confirmation needed
1227
+ - Living on the edge \u{1F680}
1228
+
1229
+ ` : `
1230
+ ### \u{1F4A1} Want auto-fixes?
1231
+ Run \`trie_watch yolo\` to enable YOLO mode and auto-fix issues as they occur!
1232
+
1233
+ `;
1234
+ return {
1235
+ content: [{
1236
+ type: "text",
1237
+ text: `${modeEmoji} **AUTONOMOUS ${modeName} ACTIVATED**
1238
+
1239
+ Trie Agent is now watching for file changes and will automatically scan them.
1240
+
1241
+ **Watching:** \`${directory}\`
1242
+ **Debounce:** ${debounceMs}ms (waits for you to stop typing)
1243
+ **YOLO Mode:** ${yoloMode ? "\u{1F525} ON - Auto-fixing!" : "\u274C OFF"}
1244
+
1245
+ ### How it works:
1246
+ 1. \u{1F4DD} You write/edit code
1247
+ 2. \u{1F441}\uFE0F Trie detects the change
1248
+ 3. \u{1F50D} Automatically scans the modified file
1249
+ 4. ${yoloMode ? "\u{1F527} Auto-fixes issues immediately!" : "\u{1F6A8} Reports issues immediately"}
1250
+ ${yoloMessage}
1251
+ ### Commands:
1252
+ - \`trie_watch status\` - See current watch status
1253
+ - \`trie_watch yolo\` - Toggle YOLO mode (auto-fix)
1254
+ - \`trie_watch issues\` - Get all issues found so far
1255
+ - \`trie_watch stop\` - Stop autonomous mode
1256
+
1257
+ ---
1258
+
1259
+ ${initialResult.content?.[0]?.text || "Initial scan complete."}`
1260
+ }]
1261
+ };
1262
+ }
1263
+ toggleYoloMode() {
1264
+ if (!this.state.isRunning) {
1265
+ return {
1266
+ content: [{
1267
+ type: "text",
1268
+ text: `\u26A0\uFE0F Watch mode is not running. Start it first with:
1269
+
1270
+ \`trie_watch start\` - Normal mode
1271
+ \`trie_watch start yolo:true\` - YOLO mode from the start`
1272
+ }]
1273
+ };
1274
+ }
1275
+ this.state.yoloMode = !this.state.yoloMode;
1276
+ if (this.state.yoloMode) {
1277
+ console.error("\n\u{1F525} YOLO MODE ACTIVATED! Auto-fixing issues as they occur...\n");
1278
+ return {
1279
+ content: [{
1280
+ type: "text",
1281
+ text: `\u{1F525} **YOLO MODE ACTIVATED**
1282
+
1283
+ Issues will now be **automatically fixed** as they're detected!
1284
+
1285
+ \u26A0\uFE0F **Warning:** This will modify your files without confirmation.
1286
+ - High-confidence fixes only
1287
+ - Backs up original code in memory
1288
+ - You can always undo with git
1289
+
1290
+ Run \`trie_watch yolo\` again to disable.`
1291
+ }]
1292
+ };
1293
+ } else {
1294
+ console.error("\n\u{1F441}\uFE0F YOLO mode disabled. Back to watch-only mode.\n");
1295
+ return {
1296
+ content: [{
1297
+ type: "text",
1298
+ text: `\u{1F441}\uFE0F **YOLO MODE DISABLED**
1299
+
1300
+ Back to normal watch mode. Issues will be reported but not auto-fixed.
1301
+
1302
+ Run \`trie_watch yolo\` to re-enable.`
1303
+ }]
1304
+ };
1305
+ }
1306
+ }
1307
+ async watchDirectory(dir, debounceMs) {
1308
+ if (!existsSync3(dir)) return;
1309
+ try {
1310
+ const dirStat = await stat(dir);
1311
+ if (!dirStat.isDirectory()) return;
1312
+ const dirName = basename2(dir);
1313
+ if (SKIP_DIRS.has(dirName) || dirName.startsWith(".")) return;
1314
+ const watcher = watch(dir, { persistent: true }, async (_eventType, filename) => {
1315
+ if (!filename) return;
1316
+ const fullPath = join2(dir, filename);
1317
+ const ext = extname3(filename).toLowerCase();
1318
+ if (!WATCH_EXTENSIONS.has(ext)) return;
1319
+ if (!existsSync3(fullPath)) return;
1320
+ this.state.pendingFiles.add(fullPath);
1321
+ if (this.state.scanDebounceTimer) {
1322
+ clearTimeout(this.state.scanDebounceTimer);
1323
+ }
1324
+ this.state.scanDebounceTimer = setTimeout(() => {
1325
+ this.processPendingFiles();
1326
+ }, debounceMs);
1327
+ });
1328
+ this.watchers.set(dir, watcher);
1329
+ const { readdir: readdir3 } = await import("fs/promises");
1330
+ const entries = await readdir3(dir, { withFileTypes: true });
1331
+ for (const entry of entries) {
1332
+ if (entry.isDirectory()) {
1333
+ await this.watchDirectory(join2(dir, entry.name), debounceMs);
1334
+ }
1335
+ }
1336
+ } catch (error) {
1337
+ }
1338
+ }
1339
+ async processPendingFiles() {
1340
+ if (this.state.pendingFiles.size === 0) return;
1341
+ const files = Array.from(this.state.pendingFiles);
1342
+ this.state.pendingFiles.clear();
1343
+ const modeEmoji = this.state.yoloMode ? "\u{1F525}" : "\u{1F441}\uFE0F";
1344
+ console.error(`
1345
+ ${modeEmoji} Detected changes in ${files.length} file(s):`);
1346
+ for (const file of files) {
1347
+ console.error(` \u2022 ${basename2(file)}`);
1348
+ }
1349
+ console.error("");
1350
+ try {
1351
+ const result = await this.scanTool.execute({ files });
1352
+ const resultText = result.content?.[0]?.text || "";
1353
+ this.state.filesScanned += files.length;
1354
+ const issueMatch = resultText.match(/(\d+) total/);
1355
+ if (issueMatch?.[1] !== void 0) {
1356
+ const newIssues = parseInt(issueMatch[1], 10);
1357
+ this.state.totalIssuesFound += newIssues;
1358
+ if (newIssues > 0) {
1359
+ console.error(`
1360
+ \u{1F6A8} Found ${newIssues} issues in changed files!`);
1361
+ const criticalMatch = resultText.match(/(\d+) CRITICAL/);
1362
+ const seriousMatch = resultText.match(/(\d+) SERIOUS/);
1363
+ const moderateMatch = resultText.match(/(\d+) MODERATE/);
1364
+ if (criticalMatch) {
1365
+ console.error(` \u{1F534} ${criticalMatch[1]} critical issues`);
1366
+ }
1367
+ if (seriousMatch) {
1368
+ console.error(` \u{1F7E0} ${seriousMatch[1]} serious issues`);
1369
+ }
1370
+ if (moderateMatch) {
1371
+ console.error(` \u{1F7E1} ${moderateMatch[1]} moderate issues`);
1372
+ }
1373
+ if (this.state.yoloMode) {
1374
+ console.error("\n\u{1F525} YOLO MODE: Attempting auto-fix...");
1375
+ await this.autoFixIssues(files);
1376
+ } else {
1377
+ console.error("\n\u{1F4A1} Run `trie_watch yolo` to auto-fix issues");
1378
+ }
1379
+ } else {
1380
+ console.error(" \u2705 No issues found - code looks good!");
1381
+ }
1382
+ }
1383
+ for (const file of files) {
1384
+ this.state.lastScan.set(file, Date.now());
1385
+ }
1386
+ } catch (error) {
1387
+ console.error(`\u274C Scan error: ${error}`);
1388
+ }
1389
+ }
1390
+ async autoFixIssues(files) {
1391
+ try {
1392
+ const fixResult = await this.fixTool.execute({
1393
+ files,
1394
+ autoApprove: true,
1395
+ minConfidence: 0.8
1396
+ // Only fix high-confidence issues
1397
+ });
1398
+ const fixText = fixResult.content?.[0]?.text || "";
1399
+ const fixedMatch = fixText.match(/(\d+) issues? fixed/i);
1400
+ if (fixedMatch?.[1] !== void 0) {
1401
+ const fixed = parseInt(fixedMatch[1], 10);
1402
+ this.state.totalIssuesFixed += fixed;
1403
+ console.error(` \u2705 Auto-fixed ${fixed} issues!`);
1404
+ } else if (fixText.includes("No issues")) {
1405
+ console.error(" \u2139\uFE0F No auto-fixable issues found");
1406
+ } else {
1407
+ const firstLine = fixText.split("\n")[0];
1408
+ console.error(` \u{1F527} ${firstLine}`);
1409
+ }
1410
+ } catch (error) {
1411
+ console.error(` \u26A0\uFE0F Auto-fix error: ${error}`);
1412
+ }
1413
+ }
1414
+ stopWatching() {
1415
+ if (!this.state.isRunning) {
1416
+ return {
1417
+ content: [{
1418
+ type: "text",
1419
+ text: "\u26A0\uFE0F Watch mode is not running."
1420
+ }]
1421
+ };
1422
+ }
1423
+ for (const [_dir, watcher] of this.watchers) {
1424
+ watcher.close();
1425
+ }
1426
+ this.watchers.clear();
1427
+ if (this.state.scanDebounceTimer) {
1428
+ clearTimeout(this.state.scanDebounceTimer);
1429
+ }
1430
+ const wasYolo = this.state.yoloMode;
1431
+ this.state.isRunning = false;
1432
+ this.state.yoloMode = false;
1433
+ const modeEmoji = wasYolo ? "\u{1F525}" : "\u{1F441}\uFE0F";
1434
+ console.error(`
1435
+ ${modeEmoji} Watch mode stopped.
1436
+ `);
1437
+ const yoloStats = wasYolo ? `
1438
+ - \u{1F525} **Issues auto-fixed: ${this.state.totalIssuesFixed}**` : "";
1439
+ return {
1440
+ content: [{
1441
+ type: "text",
1442
+ text: `${modeEmoji} **AUTONOMOUS MODE STOPPED**
1443
+
1444
+ ### Session Summary:
1445
+ - Files scanned: ${this.state.filesScanned}
1446
+ - Total issues found: ${this.state.totalIssuesFound}${yoloStats}
1447
+ - Directories watched: ${this.watchers.size}
1448
+ ${wasYolo ? `
1449
+ \u{1F525} YOLO mode was ON - issues were auto-fixed as they occurred!` : ""}
1450
+
1451
+ Use \`trie_watch start\` to start watching again.
1452
+ Use \`trie_watch start yolo:true\` for YOLO mode.`
1453
+ }]
1454
+ };
1455
+ }
1456
+ getStatus() {
1457
+ if (!this.state.isRunning) {
1458
+ return {
1459
+ content: [{
1460
+ type: "text",
1461
+ text: `\u{1F441}\uFE0F **Watch Mode Status: STOPPED**
1462
+
1463
+ Use \`trie_watch start\` to begin autonomous scanning.
1464
+ Use \`trie_watch start yolo:true\` for YOLO mode (auto-fix).`
1465
+ }]
1466
+ };
1467
+ }
1468
+ const modeEmoji = this.state.yoloMode ? "\u{1F525}" : "\u{1F441}\uFE0F";
1469
+ const modeName = this.state.yoloMode ? "YOLO MODE" : "WATCH MODE";
1470
+ const recentScans = Array.from(this.state.lastScan.entries()).sort((a, b) => b[1] - a[1]).slice(0, 5).map(([file, time]) => {
1471
+ const ago = Math.round((Date.now() - time) / 1e3);
1472
+ return `- \`${basename2(file)}\` (${ago}s ago)`;
1473
+ }).join("\n");
1474
+ const yoloStats = this.state.yoloMode ? `
1475
+ - \u{1F525} Issues auto-fixed: ${this.state.totalIssuesFixed}` : "";
1476
+ return {
1477
+ content: [{
1478
+ type: "text",
1479
+ text: `${modeEmoji} **${modeName} Status: RUNNING**
1480
+
1481
+ ### Stats:
1482
+ - Directories watched: ${this.watchers.size}
1483
+ - Files scanned this session: ${this.state.filesScanned}
1484
+ - Total issues found: ${this.state.totalIssuesFound}${yoloStats}
1485
+ - Pending files: ${this.state.pendingFiles.size}
1486
+ - YOLO Mode: ${this.state.yoloMode ? "\u{1F525} ON" : "\u274C OFF"}
1487
+
1488
+ ### Recently Scanned:
1489
+ ${recentScans || "(none yet)"}
1490
+
1491
+ ### Commands:
1492
+ - \`trie_watch yolo\` - ${this.state.yoloMode ? "Disable" : "Enable"} YOLO mode
1493
+ - \`trie_watch issues\` - Get all issues found
1494
+ - \`trie_watch stop\` - Stop watching`
1495
+ }]
1496
+ };
1497
+ }
1498
+ getCurrentIssues() {
1499
+ return {
1500
+ content: [{
1501
+ type: "text",
1502
+ text: `\u{1F4CB} **Issues Found This Session**
1503
+
1504
+ Total issues: ${this.state.totalIssuesFound}
1505
+ Files scanned: ${this.state.filesScanned}
1506
+
1507
+ To get a full report, run \`trie_scan\` on your codebase.`
1508
+ }]
1509
+ };
1510
+ }
1511
+ };
1512
+
1513
+ // src/tools/agent.ts
1514
+ import { readdir, readFile as readFile4 } from "fs/promises";
1515
+ import { existsSync as existsSync4 } from "fs";
1516
+ import { join as join3, extname as extname5, isAbsolute as isAbsolute3, resolve as resolve3, basename as basename4 } from "path";
1517
+
1518
+ // src/ai/engine.ts
1519
+ import { readFile as readFile3 } from "fs/promises";
1520
+ import { extname as extname4, relative as relative3, basename as basename3 } from "path";
1521
+ function detectLanguage(filePath) {
1522
+ const ext = extname4(filePath).toLowerCase();
1523
+ const langMap = {
1524
+ ".ts": "typescript",
1525
+ ".tsx": "tsx",
1526
+ ".js": "javascript",
1527
+ ".jsx": "jsx",
1528
+ ".py": "python",
1529
+ ".go": "go",
1530
+ ".rs": "rust",
1531
+ ".java": "java",
1532
+ ".rb": "ruby",
1533
+ ".php": "php",
1534
+ ".vue": "vue",
1535
+ ".svelte": "svelte",
1536
+ ".sql": "sql",
1537
+ ".json": "json",
1538
+ ".yaml": "yaml",
1539
+ ".yml": "yaml",
1540
+ ".md": "markdown",
1541
+ ".html": "html",
1542
+ ".css": "css",
1543
+ ".scss": "scss"
1544
+ };
1545
+ return langMap[ext] || "plaintext";
1546
+ }
1547
+ function analyzeFileContext(content, _filePath) {
1548
+ const summary = {
1549
+ hasAuth: false,
1550
+ hasDatabase: false,
1551
+ hasUserInput: false,
1552
+ hasFileOps: false,
1553
+ hasCrypto: false,
1554
+ hasExternalAPIs: false,
1555
+ exports: [],
1556
+ imports: []
1557
+ };
1558
+ if (/auth|login|session|jwt|token|password|credential|oauth/i.test(content)) {
1559
+ summary.hasAuth = true;
1560
+ }
1561
+ if (/prisma|sequelize|knex|mongodb|sql|query|database|postgres|mysql|sqlite/i.test(content)) {
1562
+ summary.hasDatabase = true;
1563
+ }
1564
+ if (/req\.body|req\.params|req\.query|formData|input|textarea|userinput/i.test(content)) {
1565
+ summary.hasUserInput = true;
1566
+ }
1567
+ if (/readFile|writeFile|createReadStream|createWriteStream|fs\.|multer|upload/i.test(content)) {
1568
+ summary.hasFileOps = true;
1569
+ }
1570
+ if (/crypto|bcrypt|argon|scrypt|encrypt|decrypt|hash|sign|verify/i.test(content)) {
1571
+ summary.hasCrypto = true;
1572
+ }
1573
+ if (/fetch\(|axios|http\.|https\.|request\(|got\(|api\//i.test(content)) {
1574
+ summary.hasExternalAPIs = true;
1575
+ }
1576
+ if (/from\s+['"]react['"]|import\s+React/i.test(content)) {
1577
+ summary.framework = "React";
1578
+ } else if (/from\s+['"]next|NextRequest|getServerSideProps/i.test(content)) {
1579
+ summary.framework = "Next.js";
1580
+ } else if (/from\s+['"]express['"]|express\(\)/i.test(content)) {
1581
+ summary.framework = "Express";
1582
+ } else if (/from\s+['"]fastify['"]|fastify\(\)/i.test(content)) {
1583
+ summary.framework = "Fastify";
1584
+ } else if (/from\s+['"]vue['"]|defineComponent/i.test(content)) {
1585
+ summary.framework = "Vue";
1586
+ }
1587
+ const exportMatches = content.match(/export\s+(const|function|class|interface|type)\s+(\w+)/g) || [];
1588
+ summary.exports = exportMatches.map((m) => m.split(/\s+/).pop() || "").filter(Boolean).slice(0, 10);
1589
+ const importMatches = content.match(/import\s+.*from\s+['"]([^'"]+)['"]/g) || [];
1590
+ summary.imports = importMatches.map((m) => {
1591
+ const match = m.match(/from\s+['"]([^'"]+)['"]/);
1592
+ return match ? match[1] : "";
1593
+ }).filter((s) => Boolean(s)).slice(0, 10);
1594
+ return summary;
1595
+ }
1596
+ function buildPromptContext(contexts, agent) {
1597
+ let contextSummary = "";
1598
+ const hasAuth = contexts.some((c) => c.summary?.hasAuth);
1599
+ const hasDatabase = contexts.some((c) => c.summary?.hasDatabase);
1600
+ const hasUserInput = contexts.some((c) => c.summary?.hasUserInput);
1601
+ const hasFileOps = contexts.some((c) => c.summary?.hasFileOps);
1602
+ const hasCrypto = contexts.some((c) => c.summary?.hasCrypto);
1603
+ const hasExternalAPIs = contexts.some((c) => c.summary?.hasExternalAPIs);
1604
+ const frameworks = [...new Set(contexts.map((c) => c.summary?.framework).filter(Boolean))];
1605
+ contextSummary += "## Code Context Summary\n\n";
1606
+ contextSummary += `**Files analyzed:** ${contexts.length}
1607
+ `;
1608
+ contextSummary += `**Total lines:** ${contexts.reduce((sum, c) => sum + c.lineCount, 0)}
1609
+ `;
1610
+ if (frameworks.length > 0) {
1611
+ contextSummary += `**Frameworks detected:** ${frameworks.join(", ")}
1612
+ `;
1613
+ }
1614
+ const features = [];
1615
+ if (hasAuth) features.push("Authentication/Authorization");
1616
+ if (hasDatabase) features.push("Database operations");
1617
+ if (hasUserInput) features.push("User input handling");
1618
+ if (hasFileOps) features.push("File operations");
1619
+ if (hasCrypto) features.push("Cryptography");
1620
+ if (hasExternalAPIs) features.push("External API calls");
1621
+ if (features.length > 0) {
1622
+ contextSummary += `**Key features:** ${features.join(", ")}
1623
+ `;
1624
+ }
1625
+ contextSummary += "\n";
1626
+ if (agent === "security") {
1627
+ if (hasAuth) contextSummary += "\u26A0\uFE0F **Auth code detected** - Review authentication flows carefully\n";
1628
+ if (hasDatabase) contextSummary += "\u26A0\uFE0F **Database ops detected** - Check for injection vulnerabilities\n";
1629
+ if (hasUserInput) contextSummary += "\u26A0\uFE0F **User input detected** - Verify input validation\n";
1630
+ } else if (agent === "privacy") {
1631
+ if (hasAuth) contextSummary += "\u26A0\uFE0F **Auth code detected** - Review credential handling\n";
1632
+ if (hasDatabase) contextSummary += "\u26A0\uFE0F **Database ops detected** - Check PII storage\n";
1633
+ } else if (agent === "bugs") {
1634
+ if (hasExternalAPIs) contextSummary += "\u26A0\uFE0F **External APIs detected** - Check error handling\n";
1635
+ if (hasFileOps) contextSummary += "\u26A0\uFE0F **File ops detected** - Verify error handling and cleanup\n";
1636
+ }
1637
+ return contextSummary;
1638
+ }
1639
+ async function buildAnalysis(request) {
1640
+ const { agent, files, context = {}, depth = "standard" } = request;
1641
+ const codeContexts = [];
1642
+ console.error(`\u{1F52C} AI Engine: Preparing ${agent} analysis for ${files.length} files...`);
1643
+ for (const filePath of files) {
1644
+ try {
1645
+ const content = await readFile3(filePath, "utf-8");
1646
+ const language = detectLanguage(filePath);
1647
+ const summary = analyzeFileContext(content, filePath);
1648
+ console.error(` \u{1F4C4} ${basename3(filePath)} - ${content.split("\n").length} lines`);
1649
+ codeContexts.push({
1650
+ filePath,
1651
+ relativePath: relative3(process.cwd(), filePath),
1652
+ language,
1653
+ content: depth === "quick" && content.length > 5e3 ? content.substring(0, 5e3) + "\n\n... (truncated for quick analysis)" : content,
1654
+ lineCount: content.split("\n").length,
1655
+ summary
1656
+ });
1657
+ } catch (error) {
1658
+ console.error(` \u26A0\uFE0F Error reading ${filePath}:`, error);
1659
+ }
1660
+ }
1661
+ const codeBlocks = codeContexts.map(
1662
+ (ctx) => `### File: ${ctx.relativePath}
1663
+ \`\`\`${ctx.language}
1664
+ ${ctx.content}
1665
+ \`\`\``
1666
+ ).join("\n\n");
1667
+ const promptContext = buildPromptContext(codeContexts, agent);
1668
+ const variables = {
1669
+ ...context,
1670
+ code: codeBlocks,
1671
+ language: codeContexts[0]?.language || "unknown",
1672
+ filePath: codeContexts.map((c) => c.relativePath).join(", ")
1673
+ };
1674
+ const analysisPrompt = getPrompt(agent, "analysis", variables);
1675
+ const systemPrompt = getSystemPrompt(agent);
1676
+ const suggestedFollowUps = [];
1677
+ if (codeContexts.some((c) => c.summary?.hasAuth)) {
1678
+ suggestedFollowUps.push("\u{1F510} Review authentication implementation");
1679
+ }
1680
+ if (codeContexts.some((c) => c.summary?.hasDatabase)) {
1681
+ suggestedFollowUps.push("\u{1F5C4}\uFE0F Check database query security");
1682
+ }
1683
+ if (codeContexts.some((c) => c.summary?.hasUserInput)) {
1684
+ suggestedFollowUps.push("\u{1F4DD} Verify input validation");
1685
+ }
1686
+ const filesSummary = codeContexts.map((c) => {
1687
+ const features = [];
1688
+ if (c.summary?.hasAuth) features.push("auth");
1689
+ if (c.summary?.hasDatabase) features.push("db");
1690
+ if (c.summary?.hasUserInput) features.push("input");
1691
+ if (c.summary?.framework) features.push(c.summary.framework);
1692
+ const featureStr = features.length > 0 ? ` [${features.join(", ")}]` : "";
1693
+ return `\`${c.relativePath}\` (${c.lineCount} lines)${featureStr}`;
1694
+ }).join("\n");
1695
+ console.error(`\u{1F9E0} AI Engine: Analysis prepared - ready for Claude`);
1696
+ return {
1697
+ agent,
1698
+ systemPrompt,
1699
+ prompt: promptContext + "\n" + analysisPrompt,
1700
+ codeContext: codeContexts,
1701
+ suggestedFollowUps,
1702
+ filesSummary
1703
+ };
1704
+ }
1705
+ function formatAnalysisResponse(result, options = {}) {
1706
+ const { agent, systemPrompt, prompt, codeContext, suggestedFollowUps, filesSummary } = result;
1707
+ const includePrompt = options.includePrompt ?? true;
1708
+ let output = "";
1709
+ output += `
1710
+ ${"\u2501".repeat(60)}
1711
+ `;
1712
+ output += `\u{1F9E0} ${agent.toUpperCase()} AGENT - AI ANALYSIS
1713
+ `;
1714
+ output += `${"\u2501".repeat(60)}
1715
+
1716
+ `;
1717
+ output += `## \u{1F4C2} Files for Analysis
1718
+
1719
+ `;
1720
+ output += filesSummary + "\n\n";
1721
+ if (suggestedFollowUps.length > 0) {
1722
+ output += `## \u{1F3AF} Focus Areas
1723
+
1724
+ `;
1725
+ for (const followUp of suggestedFollowUps) {
1726
+ output += `- ${followUp}
1727
+ `;
1728
+ }
1729
+ output += "\n";
1730
+ }
1731
+ output += `${"\u2500".repeat(60)}
1732
+ `;
1733
+ output += `## \u{1F9E0} Analysis Request for Claude
1734
+
1735
+ `;
1736
+ if (includePrompt) {
1737
+ output += `**Role:** ${systemPrompt.split("\n")[0]}
1738
+
1739
+ `;
1740
+ output += `---
1741
+
1742
+ `;
1743
+ output += prompt;
1744
+ output += `
1745
+
1746
+ ${"\u2500".repeat(60)}
1747
+ `;
1748
+ } else {
1749
+ output += `*Run with \`output: "full"\` to see the complete analysis prompt.*
1750
+
1751
+ `;
1752
+ output += `**Summary:** ${codeContext.length} files ready for ${agent} analysis
1753
+ `;
1754
+ }
1755
+ output += `
1756
+ **Claude:** Please analyze the code above according to the ${agent} analysis instructions and provide your findings.
1757
+ `;
1758
+ return output;
1759
+ }
1760
+
1761
+ // src/knowledge/index.ts
1762
+ var SECURITY_SOURCES = [
1763
+ {
1764
+ name: "OWASP Top 10",
1765
+ url: "https://owasp.org/Top10/",
1766
+ description: "Most critical web application security risks"
1767
+ },
1768
+ {
1769
+ name: "NIST NVD",
1770
+ url: "https://nvd.nist.gov/",
1771
+ description: "National Vulnerability Database"
1772
+ },
1773
+ {
1774
+ name: "CVE Database",
1775
+ url: "https://cve.mitre.org/",
1776
+ description: "Common Vulnerabilities and Exposures"
1777
+ },
1778
+ {
1779
+ name: "Snyk Vulnerability DB",
1780
+ url: "https://security.snyk.io/",
1781
+ description: "Open source vulnerability database"
1782
+ },
1783
+ {
1784
+ name: "GitHub Advisory Database",
1785
+ url: "https://github.com/advisories",
1786
+ description: "Security advisories from GitHub"
1787
+ }
1788
+ ];
1789
+ var DOCS_SOURCES = {
1790
+ react: [
1791
+ { name: "React Docs", url: "https://react.dev/", description: "Official React documentation" },
1792
+ { name: "React Security", url: "https://react.dev/reference/react-dom/components/common#dangerously-setting-the-inner-html", description: "React security guidance" }
1793
+ ],
1794
+ nextjs: [
1795
+ { name: "Next.js Docs", url: "https://nextjs.org/docs", description: "Official Next.js documentation" },
1796
+ { name: "Next.js Security", url: "https://nextjs.org/docs/advanced-features/security-headers", description: "Next.js security headers" }
1797
+ ],
1798
+ express: [
1799
+ { name: "Express Docs", url: "https://expressjs.com/", description: "Official Express.js documentation" },
1800
+ { name: "Express Security", url: "https://expressjs.com/en/advanced/best-practice-security.html", description: "Express security best practices" }
1801
+ ],
1802
+ node: [
1803
+ { name: "Node.js Docs", url: "https://nodejs.org/docs/", description: "Official Node.js documentation" },
1804
+ { name: "Node.js Security", url: "https://nodejs.org/en/docs/guides/security/", description: "Node.js security guidance" }
1805
+ ],
1806
+ typescript: [
1807
+ { name: "TypeScript Docs", url: "https://www.typescriptlang.org/docs/", description: "Official TypeScript documentation" }
1808
+ ]
1809
+ };
1810
+ var COMPLIANCE_SOURCES = {
1811
+ gdpr: [
1812
+ { name: "GDPR Official Text", url: "https://gdpr.eu/", description: "Complete GDPR regulation text" },
1813
+ { name: "GDPR Checklist", url: "https://gdpr.eu/checklist/", description: "GDPR compliance checklist" }
1814
+ ],
1815
+ hipaa: [
1816
+ { name: "HIPAA Guidelines", url: "https://www.hhs.gov/hipaa/", description: "Official HIPAA guidance" }
1817
+ ],
1818
+ wcag: [
1819
+ { name: "WCAG 2.1", url: "https://www.w3.org/WAI/WCAG21/quickref/", description: "WCAG 2.1 quick reference" }
1820
+ ],
1821
+ pci: [
1822
+ { name: "PCI DSS", url: "https://www.pcisecuritystandards.org/", description: "Payment Card Industry standards" }
1823
+ ]
1824
+ };
1825
+ function generateCVELookup(library, version) {
1826
+ let prompt = `## \u{1F512} Security Vulnerability Lookup
1827
+
1828
+ `;
1829
+ prompt += `**Library:** ${library}
1830
+ `;
1831
+ if (version) prompt += `**Version:** ${version}
1832
+ `;
1833
+ prompt += `
1834
+ `;
1835
+ prompt += `### Action Required
1836
+
1837
+ `;
1838
+ prompt += `Please check for known vulnerabilities:
1839
+
1840
+ `;
1841
+ prompt += `1. Search the **NIST NVD** (https://nvd.nist.gov/) for CVEs affecting \`${library}\`
1842
+ `;
1843
+ prompt += `2. Check **Snyk** (https://security.snyk.io/) for vulnerability reports
1844
+ `;
1845
+ prompt += `3. Review **GitHub Advisory Database** for any security advisories
1846
+ `;
1847
+ prompt += `4. Check npm audit / yarn audit if it's an npm package
1848
+
1849
+ `;
1850
+ prompt += `### Report Format
1851
+
1852
+ `;
1853
+ prompt += `For each vulnerability found, provide:
1854
+ `;
1855
+ prompt += `- CVE ID (if applicable)
1856
+ `;
1857
+ prompt += `- Severity (Critical/High/Medium/Low)
1858
+ `;
1859
+ prompt += `- Affected versions
1860
+ `;
1861
+ prompt += `- Description of the vulnerability
1862
+ `;
1863
+ prompt += `- Remediation (upgrade version, patches, mitigations)
1864
+ `;
1865
+ return prompt;
1866
+ }
1867
+ function generateDocsLookup(topic, framework) {
1868
+ let prompt = `## \u{1F4DA} Documentation Lookup
1869
+
1870
+ `;
1871
+ prompt += `**Topic:** ${topic}
1872
+ `;
1873
+ if (framework) prompt += `**Framework:** ${framework}
1874
+ `;
1875
+ prompt += `
1876
+ `;
1877
+ const sources = framework ? DOCS_SOURCES[framework.toLowerCase()] : [];
1878
+ if (sources && sources.length > 0) {
1879
+ prompt += `### Recommended Sources
1880
+
1881
+ `;
1882
+ for (const source of sources) {
1883
+ prompt += `- [${source.name}](${source.url}) - ${source.description}
1884
+ `;
1885
+ }
1886
+ prompt += `
1887
+ `;
1888
+ }
1889
+ prompt += `### Information Needed
1890
+
1891
+ `;
1892
+ prompt += `Please look up the latest documentation and provide:
1893
+
1894
+ `;
1895
+ prompt += `1. Current best practices for "${topic}"
1896
+ `;
1897
+ prompt += `2. Common pitfalls to avoid
1898
+ `;
1899
+ prompt += `3. Code examples demonstrating correct usage
1900
+ `;
1901
+ prompt += `4. Any recent changes or deprecations
1902
+ `;
1903
+ return prompt;
1904
+ }
1905
+ function generateSecurityLookup(pattern, context) {
1906
+ let prompt = `## \u{1F6E1}\uFE0F Security Best Practices Lookup
1907
+
1908
+ `;
1909
+ prompt += `**Pattern:** ${pattern}
1910
+ `;
1911
+ if (context) prompt += `**Context:** ${context}
1912
+ `;
1913
+ prompt += `
1914
+ `;
1915
+ prompt += `### Reference Sources
1916
+
1917
+ `;
1918
+ for (const source of SECURITY_SOURCES.slice(0, 3)) {
1919
+ prompt += `- [${source.name}](${source.url})
1920
+ `;
1921
+ }
1922
+ prompt += `
1923
+ `;
1924
+ prompt += `### Analysis Requested
1925
+
1926
+ `;
1927
+ prompt += `Please research and provide:
1928
+
1929
+ `;
1930
+ prompt += `1. **OWASP guidance** for this security pattern
1931
+ `;
1932
+ prompt += `2. **Attack vectors** - how this could be exploited
1933
+ `;
1934
+ prompt += `3. **Defense strategies** - recommended mitigations
1935
+ `;
1936
+ prompt += `4. **Code examples** - secure implementation patterns
1937
+ `;
1938
+ prompt += `5. **Testing approaches** - how to verify security
1939
+ `;
1940
+ return prompt;
1941
+ }
1942
+ function generateComplianceLookup(regulation, requirement) {
1943
+ let prompt = `## \u2696\uFE0F Compliance Requirement Lookup
1944
+
1945
+ `;
1946
+ prompt += `**Regulation:** ${regulation}
1947
+ `;
1948
+ if (requirement) prompt += `**Specific Requirement:** ${requirement}
1949
+ `;
1950
+ prompt += `
1951
+ `;
1952
+ const sources = COMPLIANCE_SOURCES[regulation.toLowerCase()];
1953
+ if (sources && sources.length > 0) {
1954
+ prompt += `### Official Sources
1955
+
1956
+ `;
1957
+ for (const source of sources) {
1958
+ prompt += `- [${source.name}](${source.url})
1959
+ `;
1960
+ }
1961
+ prompt += `
1962
+ `;
1963
+ }
1964
+ prompt += `### Compliance Information Needed
1965
+
1966
+ `;
1967
+ prompt += `Please research and provide:
1968
+
1969
+ `;
1970
+ prompt += `1. **Specific requirement text** from the regulation
1971
+ `;
1972
+ prompt += `2. **Technical requirements** for compliance
1973
+ `;
1974
+ prompt += `3. **Implementation guidance** with code examples
1975
+ `;
1976
+ prompt += `4. **Documentation requirements** - what records to keep
1977
+ `;
1978
+ prompt += `5. **Penalties** for non-compliance
1979
+ `;
1980
+ return prompt;
1981
+ }
1982
+ function generateChangelogLookup(library, fromVersion, toVersion) {
1983
+ let prompt = `## \u{1F4CB} Changelog Lookup
1984
+
1985
+ `;
1986
+ prompt += `**Library:** ${library}
1987
+ `;
1988
+ prompt += `**Current Version:** ${fromVersion}
1989
+ `;
1990
+ if (toVersion) prompt += `**Target Version:** ${toVersion}
1991
+ `;
1992
+ prompt += `
1993
+ `;
1994
+ prompt += `### Information Needed
1995
+
1996
+ `;
1997
+ prompt += `Please find the changelog/release notes and provide:
1998
+
1999
+ `;
2000
+ prompt += `1. **Breaking changes** between versions
2001
+ `;
2002
+ prompt += `2. **New features** added
2003
+ `;
2004
+ prompt += `3. **Deprecations** to be aware of
2005
+ `;
2006
+ prompt += `4. **Security fixes** included
2007
+ `;
2008
+ prompt += `5. **Migration guide** if available
2009
+ `;
2010
+ prompt += `6. **Known issues** with the upgrade
2011
+ `;
2012
+ return prompt;
2013
+ }
2014
+ function lookupKnowledge(request) {
2015
+ const { type, query, context = {} } = request;
2016
+ switch (type) {
2017
+ case "cve":
2018
+ return generateCVELookup(query, context.version);
2019
+ case "docs":
2020
+ return generateDocsLookup(query, context.framework);
2021
+ case "security":
2022
+ return generateSecurityLookup(query, context.context);
2023
+ case "best-practices":
2024
+ return generateComplianceLookup(query, context.requirement);
2025
+ case "changelog":
2026
+ return generateChangelogLookup(query, context.fromVersion || "current", context.toVersion);
2027
+ default:
2028
+ return `Unknown knowledge request type: ${type}`;
2029
+ }
2030
+ }
2031
+
2032
+ // src/tools/agent.ts
2033
+ var SCANNABLE_EXTENSIONS = /* @__PURE__ */ new Set([
2034
+ ".ts",
2035
+ ".tsx",
2036
+ ".js",
2037
+ ".jsx",
2038
+ ".mjs",
2039
+ ".cjs",
2040
+ ".vue",
2041
+ ".svelte",
2042
+ ".astro",
2043
+ ".py",
2044
+ ".go",
2045
+ ".rs"
2046
+ ]);
2047
+ var SKIP_DIRS2 = /* @__PURE__ */ new Set([
2048
+ "node_modules",
2049
+ ".git",
2050
+ "dist",
2051
+ "build",
2052
+ ".next",
2053
+ ".nuxt",
2054
+ "coverage",
2055
+ ".nyc_output",
2056
+ "__pycache__",
2057
+ ".pytest_cache",
2058
+ "vendor",
2059
+ ".venv",
2060
+ "venv",
2061
+ "target",
2062
+ ".turbo",
2063
+ ".cache"
2064
+ ]);
2065
+ var AGENT_TO_AI_TYPE = {
2066
+ "security": "security",
2067
+ "privacy": "privacy",
2068
+ "legal": "legal",
2069
+ "design-engineer": "accessibility",
2070
+ "software-architect": "architecture",
2071
+ "bug-finding": "bugs",
2072
+ "user-testing": "ux",
2073
+ "typecheck": "types",
2074
+ "devops": "devops",
2075
+ "comprehension": "explain",
2076
+ "test": "test",
2077
+ "trie_clean": "vibe"
2078
+ };
2079
+ var TrieAgentTool = class {
2080
+ agentRegistry = new AgentRegistry();
2081
+ async execute(args) {
2082
+ const { agent, files, directory, depth = "standard", lookup, output = "full" } = args;
2083
+ if (lookup) {
2084
+ return this.handleKnowledgeLookup(lookup);
2085
+ }
2086
+ if (!agent) {
2087
+ return this.listAgents();
2088
+ }
2089
+ const agentInstance = this.agentRegistry.getAgent(agent);
2090
+ if (!agentInstance) {
2091
+ return {
2092
+ content: [{
2093
+ type: "text",
2094
+ text: `\u274C Agent not found: ${agent}
2095
+
2096
+ Available agents:
2097
+ ${this.agentRegistry.getAgentNames().map((n) => `- ${n}`).join("\n")}`
2098
+ }]
2099
+ };
2100
+ }
2101
+ let filesToScan = files || [];
2102
+ if (!filesToScan.length) {
2103
+ const scanDir = directory || process.cwd();
2104
+ console.error(`
2105
+ \u{1F50D} Discovering files in: ${scanDir}`);
2106
+ filesToScan = await this.discoverFiles(scanDir);
2107
+ console.error(` Found ${filesToScan.length} files
2108
+ `);
2109
+ } else {
2110
+ filesToScan = filesToScan.map(
2111
+ (f) => isAbsolute3(f) ? f : resolve3(process.cwd(), f)
2112
+ );
2113
+ }
2114
+ const validFiles = filesToScan.filter((f) => existsSync4(f));
2115
+ if (validFiles.length === 0) {
2116
+ return {
2117
+ content: [{
2118
+ type: "text",
2119
+ text: `\u274C No valid files found to scan.`
2120
+ }]
2121
+ };
2122
+ }
2123
+ const startTime = Date.now();
2124
+ const aiAgentType = AGENT_TO_AI_TYPE[agent];
2125
+ if (aiAgentType) {
2126
+ return this.runAIAnalysis(
2127
+ aiAgentType,
2128
+ validFiles,
2129
+ agentInstance.name,
2130
+ agentInstance.description,
2131
+ depth,
2132
+ output
2133
+ );
2134
+ } else {
2135
+ return this.runStaticAnalysis(agentInstance, validFiles, startTime);
2136
+ }
2137
+ }
2138
+ async runAIAnalysis(agentType, files, agentName, agentDescription, depth, outputMode) {
2139
+ const startTime = Date.now();
2140
+ console.error(`
2141
+ \u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501`);
2142
+ console.error(`\u{1F9E0} Running AI-POWERED ${agentName.toUpperCase()} analysis`);
2143
+ console.error(`\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501
2144
+ `);
2145
+ console.error(`\u{1F4C4} ${agentDescription}`);
2146
+ console.error(`\u{1F4C2} Analyzing ${files.length} files (${depth} depth)...
2147
+ `);
2148
+ try {
2149
+ const analysis = await buildAnalysis({
2150
+ agent: agentType,
2151
+ files,
2152
+ depth
2153
+ });
2154
+ const executionTime = Date.now() - startTime;
2155
+ const includePrompt = outputMode === "full";
2156
+ let output = formatAnalysisResponse(analysis, { includePrompt });
2157
+ if (analysis.suggestedFollowUps.length > 0) {
2158
+ output += this.generateKnowledgeSuggestions(analysis.suggestedFollowUps, agentType);
2159
+ }
2160
+ output += `
2161
+ *Analysis completed in ${(executionTime / 1e3).toFixed(2)}s*
2162
+ `;
2163
+ return {
2164
+ content: [{
2165
+ type: "text",
2166
+ text: output
2167
+ }]
2168
+ };
2169
+ } catch (error) {
2170
+ return {
2171
+ content: [{
2172
+ type: "text",
2173
+ text: `\u274C Analysis error: ${error instanceof Error ? error.message : String(error)}`
2174
+ }]
2175
+ };
2176
+ }
2177
+ }
2178
+ async runStaticAnalysis(agentInstance, files, startTime) {
2179
+ console.error(`
2180
+ \u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501`);
2181
+ console.error(`\u{1F50D} Running ${agentInstance.name.toUpperCase()} static analysis`);
2182
+ console.error(`\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501
2183
+ `);
2184
+ console.error(`\u{1F4C4} ${agentInstance.description}`);
2185
+ console.error(`\u{1F4C2} Scanning ${files.length} files...
2186
+ `);
2187
+ try {
2188
+ const result = await agentInstance.scan(files, { workingDir: process.cwd() });
2189
+ const executionTime = Date.now() - startTime;
2190
+ return {
2191
+ content: [{
2192
+ type: "text",
2193
+ text: await this.formatStaticResult(agentInstance.name, result.issues, files, executionTime)
2194
+ }]
2195
+ };
2196
+ } catch (error) {
2197
+ return {
2198
+ content: [{
2199
+ type: "text",
2200
+ text: `\u274C Agent error: ${error instanceof Error ? error.message : String(error)}`
2201
+ }]
2202
+ };
2203
+ }
2204
+ }
2205
+ generateKnowledgeSuggestions(followUps, agentType) {
2206
+ if (followUps.length === 0) {
2207
+ return "";
2208
+ }
2209
+ let output = `
2210
+ ## \u{1F517} Suggested Follow-ups
2211
+
2212
+ `;
2213
+ for (const followUp of followUps) {
2214
+ output += `- ${followUp}
2215
+ `;
2216
+ }
2217
+ if (agentType === "security") {
2218
+ output += `- **CVE Check**: Run \`trie_security lookup:"cve" query:"[library-name]"\` to check for vulnerabilities
2219
+ `;
2220
+ }
2221
+ return output;
2222
+ }
2223
+ handleKnowledgeLookup(lookup) {
2224
+ const result = lookupKnowledge({
2225
+ type: lookup.type,
2226
+ query: lookup.query,
2227
+ context: lookup.context ?? {}
2228
+ });
2229
+ return {
2230
+ content: [{
2231
+ type: "text",
2232
+ text: result
2233
+ }]
2234
+ };
2235
+ }
2236
+ listAgents() {
2237
+ const agents = this.agentRegistry.getAgentDescriptions();
2238
+ const agentList = agents.map((a) => {
2239
+ const command = this.getAgentCommand(a.name);
2240
+ const aiPowered = AGENT_TO_AI_TYPE[a.name] ? "\u{1F9E0}" : "\u{1F50D}";
2241
+ return `| \`${command}\` | ${aiPowered} ${a.name} | ${a.description} |`;
2242
+ }).join("\n");
2243
+ return {
2244
+ content: [{
2245
+ type: "text",
2246
+ text: `# \u{1F916} Available Agents
2247
+
2248
+ | Command | Agent | Description |
2249
+ |---------|-------|-------------|
2250
+ ${agentList}
2251
+
2252
+ **Legend:** \u{1F9E0} = AI-powered deep analysis, \u{1F50D} = Static pattern matching
2253
+
2254
+ ## Usage
2255
+
2256
+ ### Run a specific agent:
2257
+ \`\`\`
2258
+ trie_security # Security vulnerabilities
2259
+ trie_privacy # Privacy/GDPR compliance
2260
+ trie_accessibility # WCAG accessibility audit
2261
+ trie_bugs # Bug detection
2262
+ trie_ux # User experience testing
2263
+ trie_types # Type safety analysis
2264
+ trie_architecture # Architecture review
2265
+ trie_devops # DevOps readiness
2266
+ trie_legal # Legal compliance
2267
+ \`\`\`
2268
+
2269
+ ### With options:
2270
+ \`\`\`
2271
+ trie_security files:["src/auth.ts"] depth:"deep"
2272
+ \`\`\`
2273
+
2274
+ ### Knowledge lookup:
2275
+ \`\`\`
2276
+ trie_security lookup:{type:"cve", query:"lodash"}
2277
+ trie_security lookup:{type:"docs", query:"XSS prevention", context:{framework:"react"}}
2278
+ \`\`\`
2279
+
2280
+ ### Run all agents:
2281
+ \`\`\`
2282
+ trie_scan # Full scan with smart triaging
2283
+ \`\`\``
2284
+ }]
2285
+ };
2286
+ }
2287
+ getAgentCommand(agentName) {
2288
+ const commandMap = {
2289
+ "security": "trie_security",
2290
+ "privacy": "trie_privacy",
2291
+ "legal": "trie_legal",
2292
+ "design-engineer": "trie_accessibility",
2293
+ "software-architect": "trie_architecture",
2294
+ "bug-finding": "trie_bugs",
2295
+ "user-testing": "trie_ux",
2296
+ "typecheck": "trie_types",
2297
+ "devops": "trie_devops",
2298
+ "comprehension": "trie_explain",
2299
+ "test": "trie_test"
2300
+ };
2301
+ return commandMap[agentName] || `trie_scan --agent ${agentName}`;
2302
+ }
2303
+ async formatStaticResult(agentName, issues, files, executionTime) {
2304
+ const critical = issues.filter((i) => i.severity === "critical").length;
2305
+ const serious = issues.filter((i) => i.severity === "serious").length;
2306
+ const moderate = issues.filter((i) => i.severity === "moderate").length;
2307
+ const low = issues.filter((i) => i.severity === "low").length;
2308
+ const agentEmoji = this.getAgentEmoji(agentName);
2309
+ let output = `
2310
+ `;
2311
+ output += `# ${agentEmoji} ${agentName.toUpperCase()} SCAN
2312
+
2313
+ `;
2314
+ output += `**Files:** ${files.length} | **Time:** ${(executionTime / 1e3).toFixed(2)}s
2315
+
2316
+ `;
2317
+ if (issues.length === 0) {
2318
+ output += `## \u2705 No Issues Found
2319
+
2320
+ `;
2321
+ output += `Your code passed all ${agentName} checks.
2322
+
2323
+ `;
2324
+ return output;
2325
+ }
2326
+ output += `## \u{1F3AF} ${issues.length} Issues Found
2327
+
2328
+ `;
2329
+ if (critical > 0) output += `\u{1F534} ${critical} Critical `;
2330
+ if (serious > 0) output += `\u{1F7E0} ${serious} Serious `;
2331
+ if (moderate > 0) output += `\u{1F7E1} ${moderate} Moderate `;
2332
+ if (low > 0) output += `\u{1F535} ${low} Low`;
2333
+ output += `
2334
+
2335
+ `;
2336
+ const sorted = [...issues].sort((a, b) => {
2337
+ const severityOrder = { critical: 0, serious: 1, moderate: 2, low: 3 };
2338
+ if (severityOrder[a.severity] !== severityOrder[b.severity]) {
2339
+ return severityOrder[a.severity] - severityOrder[b.severity];
2340
+ }
2341
+ return (a.line || 0) - (b.line || 0);
2342
+ });
2343
+ for (const issue of sorted) {
2344
+ const icon = { critical: "\u{1F534}", serious: "\u{1F7E0}", moderate: "\u{1F7E1}", low: "\u{1F535}" }[issue.severity];
2345
+ output += `---
2346
+
2347
+ `;
2348
+ output += `${icon} **${issue.issue}**
2349
+
2350
+ `;
2351
+ output += `\u{1F4CD} \`${issue.file}:${issue.line || "?"}\`
2352
+
2353
+ `;
2354
+ const snippet = await this.getCodeSnippet(issue.file, issue.line);
2355
+ if (snippet) {
2356
+ output += `\`\`\`
2357
+ ${snippet}
2358
+ \`\`\`
2359
+
2360
+ `;
2361
+ }
2362
+ output += `**Fix:** ${issue.fix}
2363
+
2364
+ `;
2365
+ if (issue.cwe) output += `CWE: ${issue.cwe}
2366
+ `;
2367
+ if (issue.regulation) output += `Regulation: ${issue.regulation}
2368
+ `;
2369
+ output += `<details>
2370
+ <summary>\u{1F4AC} Prompt to fix this</summary>
2371
+
2372
+ `;
2373
+ output += `\`\`\`
2374
+ Fix the ${issue.issue.toLowerCase()} in ${basename4(issue.file)}${issue.line ? ` at line ${issue.line}` : ""}.
2375
+
2376
+ ${issue.fix}
2377
+ \`\`\`
2378
+
2379
+ `;
2380
+ output += `</details>
2381
+
2382
+ `;
2383
+ }
2384
+ output += `---
2385
+ `;
2386
+ output += `*${agentName} scan completed in ${(executionTime / 1e3).toFixed(2)}s*
2387
+ `;
2388
+ return output;
2389
+ }
2390
+ /**
2391
+ * Get a code snippet around a specific line
2392
+ */
2393
+ async getCodeSnippet(filePath, line) {
2394
+ if (!line || !existsSync4(filePath)) return null;
2395
+ try {
2396
+ const content = await readFile4(filePath, "utf-8");
2397
+ const lines = content.split("\n");
2398
+ const start = Math.max(0, line - 3);
2399
+ const end = Math.min(lines.length, line + 2);
2400
+ return lines.slice(start, end).map((l, idx) => {
2401
+ const lineNum = start + idx + 1;
2402
+ const marker = lineNum === line ? "\u2192" : " ";
2403
+ return `${marker} ${lineNum.toString().padStart(4)} | ${l}`;
2404
+ }).join("\n");
2405
+ } catch {
2406
+ return null;
2407
+ }
2408
+ }
2409
+ getAgentEmoji(agentName) {
2410
+ const emojis = {
2411
+ "security": "\u{1F512}",
2412
+ "privacy": "\u{1F464}",
2413
+ "legal": "\u2696\uFE0F",
2414
+ "design-engineer": "\u267F",
2415
+ "software-architect": "\u{1F3D7}\uFE0F",
2416
+ "bug-finding": "\u{1F41B}",
2417
+ "user-testing": "\u{1F3AF}",
2418
+ "typecheck": "\u{1F4DD}",
2419
+ "devops": "\u2699\uFE0F",
2420
+ "comprehension": "\u{1F4D6}",
2421
+ "test": "\u{1F9EA}"
2422
+ };
2423
+ return emojis[agentName] || "\u{1F916}";
2424
+ }
2425
+ async discoverFiles(dir, maxFiles = 200) {
2426
+ const files = [];
2427
+ async function walk(currentDir) {
2428
+ if (files.length >= maxFiles) return;
2429
+ try {
2430
+ const entries = await readdir(currentDir, { withFileTypes: true });
2431
+ for (const entry of entries) {
2432
+ if (files.length >= maxFiles) break;
2433
+ const fullPath = join3(currentDir, entry.name);
2434
+ if (entry.isDirectory()) {
2435
+ if (!SKIP_DIRS2.has(entry.name) && !entry.name.startsWith(".")) {
2436
+ await walk(fullPath);
2437
+ }
2438
+ } else if (entry.isFile()) {
2439
+ const ext = extname5(entry.name).toLowerCase();
2440
+ if (SCANNABLE_EXTENSIONS.has(ext)) {
2441
+ files.push(fullPath);
2442
+ }
2443
+ }
2444
+ }
2445
+ } catch (error) {
2446
+ }
2447
+ }
2448
+ await walk(dir);
2449
+ return files;
2450
+ }
2451
+ };
2452
+
2453
+ // src/tools/create-agent.ts
2454
+ import { existsSync as existsSync5 } from "fs";
2455
+ import { mkdir, writeFile } from "fs/promises";
2456
+ import { join as join4, basename as basename5, extname as extname6 } from "path";
2457
+ var TrieCreateAgentTool = class {
2458
+ async execute(args) {
2459
+ const { filePath, documentContent, agentName, displayName, description, category } = args;
2460
+ if (!agentName) {
2461
+ return this.errorResponse("Missing required parameter: agentName");
2462
+ }
2463
+ if (!filePath && !documentContent) {
2464
+ return this.errorResponse(
2465
+ "Provide either filePath (path to PDF/TXT/MD file) or documentContent (raw text from drag-and-drop)"
2466
+ );
2467
+ }
2468
+ try {
2469
+ let rawText;
2470
+ let title = agentName;
2471
+ let wordCount = 0;
2472
+ if (filePath) {
2473
+ if (!existsSync5(filePath)) {
2474
+ return this.errorResponse(`File not found: ${filePath}`);
2475
+ }
2476
+ const ext = filePath.toLowerCase().split(".").pop();
2477
+ if (!["pdf", "txt", "md", "markdown", "rtf"].includes(ext || "")) {
2478
+ return this.errorResponse(
2479
+ `Unsupported file type: .${ext}
2480
+ Supported types: .pdf, .txt, .md, .rtf`
2481
+ );
2482
+ }
2483
+ const document = await parseDocument(filePath);
2484
+ rawText = document.rawText;
2485
+ title = document.metadata.title || basename5(filePath, extname6(filePath));
2486
+ wordCount = document.metadata.wordCount;
2487
+ } else {
2488
+ rawText = documentContent;
2489
+ wordCount = rawText.split(/\s+/).filter((w) => w.length > 0).length;
2490
+ const firstLine = rawText.split("\n")[0]?.trim();
2491
+ if (firstLine && firstLine.length < 100) {
2492
+ title = firstLine;
2493
+ }
2494
+ }
2495
+ const chunks = this.chunkText(rawText, 6e3);
2496
+ const extractionPrompt = this.buildExtractionPrompt(
2497
+ chunks,
2498
+ title,
2499
+ agentName,
2500
+ category,
2501
+ displayName,
2502
+ description
2503
+ );
2504
+ return {
2505
+ content: [
2506
+ {
2507
+ type: "text",
2508
+ text: this.formatExtractionRequest(
2509
+ agentName,
2510
+ title,
2511
+ wordCount,
2512
+ chunks.length,
2513
+ extractionPrompt
2514
+ )
2515
+ }
2516
+ ]
2517
+ };
2518
+ } catch (error) {
2519
+ const errorMessage = error instanceof Error ? error.message : String(error);
2520
+ return this.errorResponse(`Failed to parse document: ${errorMessage}`);
2521
+ }
2522
+ }
2523
+ /**
2524
+ * Chunk text into manageable pieces
2525
+ */
2526
+ chunkText(text, maxChunkSize) {
2527
+ if (text.length <= maxChunkSize) {
2528
+ return [text];
2529
+ }
2530
+ const chunks = [];
2531
+ const paragraphs = text.split(/\n\s*\n/);
2532
+ let currentChunk = "";
2533
+ for (const para of paragraphs) {
2534
+ if (currentChunk.length + para.length + 2 > maxChunkSize) {
2535
+ if (currentChunk) chunks.push(currentChunk.trim());
2536
+ currentChunk = para;
2537
+ } else {
2538
+ currentChunk += (currentChunk ? "\n\n" : "") + para;
2539
+ }
2540
+ }
2541
+ if (currentChunk) chunks.push(currentChunk.trim());
2542
+ return chunks;
2543
+ }
2544
+ /**
2545
+ * Build the extraction prompt for Claude
2546
+ */
2547
+ buildExtractionPrompt(chunks, title, agentName, category, displayName, description) {
2548
+ const prefix = agentName.toUpperCase().replace(/[^A-Z]/g, "").slice(0, 4) || "CUST";
2549
+ const documentContent = chunks.length === 1 ? chunks[0] : chunks.map((c, i) => `--- SECTION ${i + 1}/${chunks.length} ---
2550
+ ${c}`).join("\n\n");
2551
+ return `# Create Code Review Agent: "${displayName || this.formatDisplayName(agentName)}"
2552
+
2553
+ ## Your Task
2554
+ Analyze the following document and extract structured knowledge to create a code review agent.
2555
+
2556
+ ## Document Information
2557
+ - **Title**: ${title}
2558
+ - **Agent Name**: ${agentName}
2559
+ - **Category**: ${category || "auto-detect"}
2560
+ ${description ? `- **Description**: ${description}` : ""}
2561
+
2562
+ ## Document Content
2563
+ ${documentContent}
2564
+
2565
+ ---
2566
+
2567
+ ## Instructions
2568
+
2569
+ Please analyze this document and produce a **single JSON object** with the following structure. This will be used to create a custom code review agent.
2570
+
2571
+ **IMPORTANT**: Your response should be ONLY the JSON object, no other text.
2572
+
2573
+ \`\`\`json
2574
+ {
2575
+ "agentConfig": {
2576
+ "name": "${this.sanitizeAgentName(agentName)}",
2577
+ "displayName": "${displayName || this.formatDisplayName(agentName)}",
2578
+ "description": "${description || `Code review agent based on ${title}`}",
2579
+ "version": "1.0.0",
2580
+ "category": "string (technical | legal | policy | security | architecture | general)"
2581
+ },
2582
+ "knowledge": {
2583
+ "domain": "string (technical | legal | policy | security | architecture | general)",
2584
+ "summary": "2-3 paragraph summary of the document's key insights for code review",
2585
+ "coreConcepts": [
2586
+ {
2587
+ "name": "string",
2588
+ "description": "string",
2589
+ "importance": "critical | important | supplementary",
2590
+ "keywords": ["string"]
2591
+ }
2592
+ ],
2593
+ "bestPractices": [
2594
+ {
2595
+ "name": "string",
2596
+ "description": "string",
2597
+ "rationale": "why this is important",
2598
+ "codeExample": "optional code example or null"
2599
+ }
2600
+ ],
2601
+ "antiPatterns": [
2602
+ {
2603
+ "name": "string",
2604
+ "description": "string",
2605
+ "whyBad": "why to avoid",
2606
+ "betterAlternative": "what to do instead"
2607
+ }
2608
+ ],
2609
+ "glossary": {
2610
+ "term": "definition"
2611
+ }
2612
+ },
2613
+ "detectionRules": [
2614
+ {
2615
+ "id": "${prefix}-001",
2616
+ "name": "Rule Name",
2617
+ "description": "What this rule detects",
2618
+ "severity": "critical | serious | moderate | low | info",
2619
+ "patterns": {
2620
+ "regex": ["JavaScript regex patterns"],
2621
+ "keywords": ["words that indicate this issue"],
2622
+ "semantic": "Natural language description for AI detection"
2623
+ },
2624
+ "fix": {
2625
+ "description": "How to fix this issue",
2626
+ "example": "Code example or null",
2627
+ "autoFixable": false
2628
+ },
2629
+ "category": "string"
2630
+ }
2631
+ ],
2632
+ "prompts": {
2633
+ "systemPrompt": "You are an expert code reviewer specializing in [topic]. Your role is to...",
2634
+ "analysisPrompt": "Review this code for issues related to [topic]. Look for: ...\\n\\nCode:\\n\\\`\\\`\\\`{{language}}\\n{{code}}\\n\\\`\\\`\\\`\\n\\nFile: {{filePath}}",
2635
+ "fixPrompt": "Fix this issue: {{issue}}\\n\\nCode:\\n\\\`\\\`\\\`{{language}}\\n{{code}}\\n\\\`\\\`\\\`"
2636
+ }
2637
+ }
2638
+ \`\`\`
2639
+
2640
+ ## Guidelines
2641
+
2642
+ 1. **Core Concepts**: Extract 10-20 key concepts that are fundamental to the material
2643
+ 2. **Best Practices**: Extract 10-15 recommended approaches with rationale
2644
+ 3. **Anti-Patterns**: Extract 10-15 things to avoid with explanations
2645
+ 4. **Detection Rules**: Generate 15-30 rules with regex patterns that could detect issues in code
2646
+ 5. **Prompts**: Create prompts that embody the expertise from this document
2647
+
2648
+ Focus on extracting actionable, code-reviewable knowledge. The agent should be able to find violations of the principles in this document.
2649
+
2650
+ **Output ONLY the JSON object, starting with \`{\` and ending with \`}\`.**`;
2651
+ }
2652
+ /**
2653
+ * Format the extraction request output
2654
+ */
2655
+ formatExtractionRequest(agentName, title, wordCount, chunkCount, prompt) {
2656
+ return `
2657
+ \u{1F4DA} **Document Parsed Successfully!**
2658
+
2659
+ ${"\u2501".repeat(50)}
2660
+
2661
+ **Creating Agent:** \`${agentName}\`
2662
+ **Source Document:** ${title}
2663
+ **Word Count:** ${wordCount.toLocaleString()}
2664
+ **Processing Chunks:** ${chunkCount}
2665
+
2666
+ ${"\u2501".repeat(50)}
2667
+
2668
+ ## Next Step
2669
+
2670
+ I've prepared the document for analysis. Please process the following prompt to extract the knowledge, then pass the result to \`trie_save_agent\` to save the agent.
2671
+
2672
+ ${"\u2500".repeat(50)}
2673
+
2674
+ ${prompt}
2675
+ `;
2676
+ }
2677
+ sanitizeAgentName(name) {
2678
+ return name.toLowerCase().replace(/[^a-z0-9-]/g, "-").replace(/-+/g, "-").replace(/^-|-$/g, "");
2679
+ }
2680
+ formatDisplayName(name) {
2681
+ return name.split(/[-_]/).map((word) => word.charAt(0).toUpperCase() + word.slice(1)).join(" ");
2682
+ }
2683
+ errorResponse(message) {
2684
+ return {
2685
+ content: [
2686
+ {
2687
+ type: "text",
2688
+ text: `\u274C **Error:** ${message}`
2689
+ }
2690
+ ],
2691
+ isError: true
2692
+ };
2693
+ }
2694
+ };
2695
+ var TrieSaveAgentTool = class {
2696
+ async execute(args) {
2697
+ const { agentConfig, knowledge, detectionRules, prompts, sourceFile } = args;
2698
+ if (!agentConfig?.name) {
2699
+ return this.errorResponse("Missing agentConfig.name");
2700
+ }
2701
+ if (!knowledge?.summary) {
2702
+ return this.errorResponse("Missing knowledge.summary");
2703
+ }
2704
+ if (!prompts?.systemPrompt) {
2705
+ return this.errorResponse("Missing prompts.systemPrompt");
2706
+ }
2707
+ try {
2708
+ const fullConfig = {
2709
+ name: this.sanitizeAgentName(agentConfig.name),
2710
+ displayName: agentConfig.displayName || this.formatDisplayName(agentConfig.name),
2711
+ description: agentConfig.description,
2712
+ version: agentConfig.version || "1.0.0",
2713
+ category: agentConfig.category || knowledge.domain || "general",
2714
+ source: {
2715
+ type: "document",
2716
+ originalFile: sourceFile || "user-provided",
2717
+ fileType: "txt",
2718
+ compressedAt: (/* @__PURE__ */ new Date()).toISOString()
2719
+ },
2720
+ systemPrompt: prompts.systemPrompt,
2721
+ analysisPrompt: prompts.analysisPrompt,
2722
+ fixPrompt: prompts.fixPrompt,
2723
+ activationRules: this.buildActivationRules(knowledge, detectionRules),
2724
+ patterns: detectionRules.map((rule, i) => {
2725
+ const fixObj = {
2726
+ description: rule.fix?.description || "Review and fix manually",
2727
+ autoFixable: rule.fix?.autoFixable || false
2728
+ };
2729
+ if (rule.fix?.example) {
2730
+ fixObj.example = rule.fix.example;
2731
+ }
2732
+ return {
2733
+ id: rule.id || `CUST-${String(i + 1).padStart(3, "0")}`,
2734
+ name: rule.name,
2735
+ description: rule.description,
2736
+ severity: rule.severity || "moderate",
2737
+ patterns: {
2738
+ regex: rule.patterns?.regex || [],
2739
+ keywords: rule.patterns?.keywords || [],
2740
+ semantic: rule.patterns?.semantic || ""
2741
+ },
2742
+ fix: fixObj,
2743
+ category: rule.category || agentConfig.category
2744
+ };
2745
+ }),
2746
+ knowledge: {
2747
+ domain: knowledge.domain || "general",
2748
+ summary: knowledge.summary,
2749
+ coreConcepts: knowledge.coreConcepts.map((c) => ({
2750
+ name: c.name,
2751
+ description: c.description,
2752
+ importance: c.importance || "important",
2753
+ relatedPatterns: c.relatedPatterns || [],
2754
+ keywords: c.keywords || []
2755
+ })),
2756
+ bestPractices: knowledge.bestPractices.map((bp) => {
2757
+ const practice = {
2758
+ name: bp.name,
2759
+ description: bp.description,
2760
+ rationale: bp.rationale,
2761
+ category: bp.category || agentConfig.category
2762
+ };
2763
+ if (bp.codeExample) {
2764
+ practice.codeExample = bp.codeExample;
2765
+ }
2766
+ return practice;
2767
+ }),
2768
+ antiPatterns: knowledge.antiPatterns.map((ap) => ({
2769
+ name: ap.name,
2770
+ description: ap.description,
2771
+ whyBad: ap.whyBad,
2772
+ betterAlternative: ap.betterAlternative
2773
+ })),
2774
+ detectionRules: [],
2775
+ glossary: knowledge.glossary || {},
2776
+ sourceDocument: {
2777
+ title: agentConfig.displayName || agentConfig.name,
2778
+ wordCount: 0,
2779
+ compressionRatio: 0
2780
+ }
2781
+ }
2782
+ };
2783
+ const configPath = await this.saveAgentConfig(fullConfig);
2784
+ return {
2785
+ content: [
2786
+ {
2787
+ type: "text",
2788
+ text: this.formatSuccessResponse(fullConfig, configPath)
2789
+ }
2790
+ ]
2791
+ };
2792
+ } catch (error) {
2793
+ const errorMessage = error instanceof Error ? error.message : String(error);
2794
+ return this.errorResponse(`Failed to save agent: ${errorMessage}`);
2795
+ }
2796
+ }
2797
+ buildActivationRules(knowledge, detectionRules) {
2798
+ const domainRules = {
2799
+ technical: {
2800
+ filePatterns: ["*.ts", "*.tsx", "*.js", "*.jsx", "*.py", "*.go", "*.rs"],
2801
+ contextSignals: ["touchesUI", "touchesAPI"],
2802
+ priority: 2
2803
+ },
2804
+ legal: {
2805
+ filePatterns: ["*"],
2806
+ contextSignals: ["touchesUserData", "touchesAuth", "touchesPayments"],
2807
+ priority: 2
2808
+ },
2809
+ policy: {
2810
+ filePatterns: ["*"],
2811
+ contextSignals: ["touchesAuth", "touchesAPI", "touchesDatabase"],
2812
+ priority: 3
2813
+ },
2814
+ security: {
2815
+ filePatterns: ["*"],
2816
+ contextSignals: ["touchesAuth", "touchesCrypto", "touchesAPI", "touchesDatabase"],
2817
+ priority: 1
2818
+ },
2819
+ architecture: {
2820
+ filePatterns: ["*.ts", "*.tsx", "*.js", "*.jsx", "*.py", "*.go"],
2821
+ contextSignals: ["touchesAPI", "touchesDatabase"],
2822
+ priority: 2
2823
+ },
2824
+ general: {
2825
+ filePatterns: ["*"],
2826
+ contextSignals: [],
2827
+ priority: 3
2828
+ }
2829
+ };
2830
+ const defaults = domainRules[knowledge.domain] || domainRules.general;
2831
+ const contentPatterns = [];
2832
+ for (const rule of detectionRules) {
2833
+ if (rule.patterns?.keywords) {
2834
+ contentPatterns.push(...rule.patterns.keywords.slice(0, 3));
2835
+ }
2836
+ }
2837
+ for (const concept of knowledge.coreConcepts.slice(0, 5)) {
2838
+ if (concept.keywords) {
2839
+ contentPatterns.push(...concept.keywords.slice(0, 2));
2840
+ }
2841
+ }
2842
+ return {
2843
+ filePatterns: defaults.filePatterns || ["*"],
2844
+ contentPatterns: [...new Set(contentPatterns)].slice(0, 20),
2845
+ contextSignals: defaults.contextSignals || [],
2846
+ minConfidence: 0.3,
2847
+ priority: defaults.priority || 2
2848
+ };
2849
+ }
2850
+ async saveAgentConfig(config) {
2851
+ const trieDir = join4(process.cwd(), ".trie", "agents");
2852
+ await mkdir(trieDir, { recursive: true });
2853
+ const configPath = join4(trieDir, `${config.name}.json`);
2854
+ await writeFile(configPath, JSON.stringify(config, null, 2));
2855
+ return configPath;
2856
+ }
2857
+ formatSuccessResponse(config, configPath) {
2858
+ return `
2859
+ \u2705 **Agent Created Successfully!**
2860
+
2861
+ ${"\u2501".repeat(50)}
2862
+
2863
+ **Agent Name:** \`${config.name}\`
2864
+ **Display Name:** ${config.displayName}
2865
+ **Category:** ${config.category}
2866
+ **Config Saved To:** \`${configPath}\`
2867
+
2868
+ \u{1F4CA} **Statistics:**
2869
+ \u2022 Core concepts: ${config.knowledge.coreConcepts.length}
2870
+ \u2022 Best practices: ${config.knowledge.bestPractices.length}
2871
+ \u2022 Anti-patterns: ${config.knowledge.antiPatterns.length}
2872
+ \u2022 Detection rules: ${config.patterns.length}
2873
+
2874
+ \u{1F680} **Next Steps:**
2875
+ 1. The agent is now registered and will activate during scans
2876
+ 2. Run \`trie_scan\` to test the new agent
2877
+ 3. Edit \`${configPath}\` to customize detection rules
2878
+
2879
+ \u{1F4A1} **Usage:**
2880
+ The agent will automatically activate when scanning code that matches its patterns.
2881
+ Use \`trie_list_agents\` to see all registered agents.
2882
+ `.trim();
2883
+ }
2884
+ sanitizeAgentName(name) {
2885
+ return name.toLowerCase().replace(/[^a-z0-9-]/g, "-").replace(/-+/g, "-").replace(/^-|-$/g, "");
2886
+ }
2887
+ formatDisplayName(name) {
2888
+ return name.split(/[-_]/).map((word) => word.charAt(0).toUpperCase() + word.slice(1)).join(" ");
2889
+ }
2890
+ errorResponse(message) {
2891
+ return {
2892
+ content: [
2893
+ {
2894
+ type: "text",
2895
+ text: `\u274C **Error:** ${message}`
2896
+ }
2897
+ ],
2898
+ isError: true
2899
+ };
2900
+ }
2901
+ };
2902
+ var TrieListAgentsTool = class {
2903
+ async execute(args) {
2904
+ const { includeBuiltin = true } = args;
2905
+ try {
2906
+ const customAgentNames = await listCustomAgents();
2907
+ const customAgents = await Promise.all(
2908
+ customAgentNames.map(async (name) => {
2909
+ const config = await loadAgentConfig(name);
2910
+ return config ? {
2911
+ name: config.name,
2912
+ displayName: config.displayName,
2913
+ category: config.category,
2914
+ source: config.source.originalFile,
2915
+ patterns: config.patterns.length,
2916
+ isCustom: true
2917
+ } : null;
2918
+ })
2919
+ );
2920
+ const validCustomAgents = customAgents.filter(Boolean);
2921
+ const builtinAgents = includeBuiltin ? [
2922
+ { name: "security", displayName: "Security Agent", category: "security", isCustom: false },
2923
+ { name: "privacy", displayName: "Privacy Agent", category: "privacy", isCustom: false },
2924
+ { name: "legal", displayName: "Legal Agent", category: "compliance", isCustom: false },
2925
+ { name: "typecheck", displayName: "TypeCheck Agent", category: "quality", isCustom: false },
2926
+ { name: "comprehension", displayName: "Comprehension Agent", category: "communication", isCustom: false },
2927
+ { name: "design-engineer", displayName: "Design Engineer Agent", category: "accessibility", isCustom: false },
2928
+ { name: "test", displayName: "Test Agent", category: "testing", isCustom: false },
2929
+ { name: "software-architect", displayName: "Software Architect Agent", category: "architecture", isCustom: false },
2930
+ { name: "devops", displayName: "DevOps Agent", category: "devops", isCustom: false },
2931
+ { name: "bug-finding", displayName: "Bug Finding Agent", category: "quality", isCustom: false },
2932
+ { name: "user-testing", displayName: "User Testing Agent", category: "ux", isCustom: false },
2933
+ { name: "trie_clean", displayName: "Trie Clean Agent", category: "ai-code", isCustom: false }
2934
+ ] : [];
2935
+ let response = `# \u{1F916} Registered Agents
2936
+
2937
+ `;
2938
+ if (builtinAgents.length > 0) {
2939
+ response += `## Built-in Agents (${builtinAgents.length})
2940
+
2941
+ `;
2942
+ for (const agent of builtinAgents) {
2943
+ response += `- **${agent.displayName}** (\`${agent.name}\`) - ${agent.category}
2944
+ `;
2945
+ }
2946
+ response += "\n";
2947
+ }
2948
+ response += `## Custom Agents (${validCustomAgents.length})
2949
+
2950
+ `;
2951
+ if (validCustomAgents.length === 0) {
2952
+ response += `_No custom agents created yet._
2953
+
2954
+ `;
2955
+ response += `\u{1F4A1} Create one with: \`trie_create_agent\`
2956
+ `;
2957
+ response += ` - Provide a PDF, TXT, or MD file path
2958
+ `;
2959
+ response += ` - Or paste/drag document content directly
2960
+ `;
2961
+ } else {
2962
+ for (const agent of validCustomAgents) {
2963
+ if (agent) {
2964
+ response += `- **${agent.displayName}** (\`${agent.name}\`)
2965
+ `;
2966
+ response += ` - Category: ${agent.category}
2967
+ `;
2968
+ response += ` - Patterns: ${agent.patterns}
2969
+ `;
2970
+ response += ` - Source: ${agent.source}
2971
+
2972
+ `;
2973
+ }
2974
+ }
2975
+ }
2976
+ return {
2977
+ content: [
2978
+ {
2979
+ type: "text",
2980
+ text: response
2981
+ }
2982
+ ]
2983
+ };
2984
+ } catch (error) {
2985
+ const errorMessage = error instanceof Error ? error.message : String(error);
2986
+ return {
2987
+ content: [
2988
+ {
2989
+ type: "text",
2990
+ text: `\u274C Error listing agents: ${errorMessage}`
2991
+ }
2992
+ ],
2993
+ isError: true
2994
+ };
2995
+ }
2996
+ }
2997
+ };
2998
+
2999
+ // src/utils/ai-tool-detector.ts
3000
+ function detectAITool() {
3001
+ if (process.env.CLAUDE_CODE_VERSION) {
3002
+ return {
3003
+ name: "claude-code",
3004
+ preferredOutputFormat: "markdown",
3005
+ supportsDiffs: true,
3006
+ supportsInlineActions: true
3007
+ };
3008
+ }
3009
+ if (process.env.CURSOR_IDE) {
3010
+ return {
3011
+ name: "cursor",
3012
+ preferredOutputFormat: "rich-text",
3013
+ supportsDiffs: true,
3014
+ supportsInlineActions: false
3015
+ };
3016
+ }
3017
+ if (process.env.OPENCODE_INSTANCE) {
3018
+ return {
3019
+ name: "opencode",
3020
+ preferredOutputFormat: "plain-text",
3021
+ supportsDiffs: false,
3022
+ supportsInlineActions: false
3023
+ };
3024
+ }
3025
+ const parentProcess = process.env.PARENT_PROCESS_NAME;
3026
+ if (parentProcess?.toLowerCase().includes("claude")) {
3027
+ return {
3028
+ name: "claude-code",
3029
+ preferredOutputFormat: "markdown",
3030
+ supportsDiffs: true,
3031
+ supportsInlineActions: true
3032
+ };
3033
+ }
3034
+ if (parentProcess?.toLowerCase().includes("cursor")) {
3035
+ return {
3036
+ name: "cursor",
3037
+ preferredOutputFormat: "rich-text",
3038
+ supportsDiffs: true,
3039
+ supportsInlineActions: false
3040
+ };
3041
+ }
3042
+ if (parentProcess?.toLowerCase().includes("opencode")) {
3043
+ return {
3044
+ name: "opencode",
3045
+ preferredOutputFormat: "plain-text",
3046
+ supportsDiffs: false,
3047
+ supportsInlineActions: false
3048
+ };
3049
+ }
3050
+ return {
3051
+ name: "unknown",
3052
+ preferredOutputFormat: "markdown",
3053
+ supportsDiffs: true,
3054
+ supportsInlineActions: false
3055
+ };
3056
+ }
3057
+
3058
+ // src/config/loader.ts
3059
+ import { readFile as readFile5 } from "fs/promises";
3060
+ import { join as join5 } from "path";
3061
+
3062
+ // src/config/defaults.ts
3063
+ var DEFAULT_CONFIG = {
3064
+ version: "1.0",
3065
+ triaging: {
3066
+ enabled: true,
3067
+ riskThresholds: {
3068
+ critical: 70,
3069
+ high: 40,
3070
+ medium: 20
3071
+ },
3072
+ autoFixConfidence: 0.95
3073
+ },
3074
+ agents: {
3075
+ builtin: {
3076
+ security: { enabled: true },
3077
+ privacy: { enabled: true },
3078
+ legal: { enabled: true },
3079
+ "design-engineer": { enabled: true },
3080
+ "software-architect": { enabled: true },
3081
+ comprehension: { enabled: true },
3082
+ devops: { enabled: true },
3083
+ git: { enabled: true },
3084
+ typecheck: { enabled: true },
3085
+ test: { enabled: true },
3086
+ "user-testing": { enabled: true },
3087
+ "bug-finding": { enabled: true }
3088
+ },
3089
+ custom: []
3090
+ },
3091
+ ai: {
3092
+ provider: "hybrid",
3093
+ cloudModel: "claude-sonnet-4-20250514",
3094
+ localModel: "codellama:13b",
3095
+ useLocalFor: ["privacy-sensitive", "quick-checks"]
3096
+ },
3097
+ output: {
3098
+ format: "markdown",
3099
+ verbosity: "detailed",
3100
+ showConfidenceScores: true,
3101
+ includeAgentReasonings: false
3102
+ },
3103
+ compliance: {
3104
+ standards: ["GDPR", "HIPAA", "SOC2"],
3105
+ generateDocumentation: true,
3106
+ auditTrail: true
3107
+ }
3108
+ };
3109
+
3110
+ // src/config/loader.ts
3111
+ async function loadConfig() {
3112
+ try {
3113
+ const configPath = join5(process.cwd(), ".trie", "config.json");
3114
+ const configFile = await readFile5(configPath, "utf-8");
3115
+ const userConfig = JSON.parse(configFile);
3116
+ return mergeConfig(DEFAULT_CONFIG, userConfig);
3117
+ } catch (error) {
3118
+ console.error("No config found, using defaults");
3119
+ return DEFAULT_CONFIG;
3120
+ }
3121
+ }
3122
+ function mergeConfig(defaults, user) {
3123
+ if (typeof user !== "object" || user === null) {
3124
+ return defaults;
3125
+ }
3126
+ const result = { ...defaults };
3127
+ for (const [key, value] of Object.entries(user)) {
3128
+ if (typeof value === "object" && value !== null && !Array.isArray(value)) {
3129
+ result[key] = mergeConfig(defaults[key] || {}, value);
3130
+ } else {
3131
+ result[key] = value;
3132
+ }
3133
+ }
3134
+ return result;
3135
+ }
3136
+
3137
+ // src/index.ts
3138
+ var server = new Server(
3139
+ {
3140
+ name: "trie",
3141
+ version: "1.0.0",
3142
+ description: "Intelligent Agent Orchestration for AI Coding Tools"
3143
+ },
3144
+ {
3145
+ capabilities: {
3146
+ tools: {},
3147
+ resources: {}
3148
+ }
3149
+ }
3150
+ );
3151
+ var scanTool = new TrieScanTool();
3152
+ var fixTool = new TrieFixTool();
3153
+ var explainTool = new TrieExplainTool();
3154
+ var testTool = new TrieTestTool();
3155
+ var registerAgentTool = new TrieRegisterAgentTool();
3156
+ var watchTool = new TrieWatchTool();
3157
+ var agentTool = new TrieAgentTool();
3158
+ var createAgentTool = new TrieCreateAgentTool();
3159
+ var saveAgentTool = new TrieSaveAgentTool();
3160
+ var listAgentsTool = new TrieListAgentsTool();
3161
+ var tools = [
3162
+ {
3163
+ name: "scan",
3164
+ description: "Scan code with intelligent agent selection. Scans entire codebase if no files specified.",
3165
+ inputSchema: {
3166
+ type: "object",
3167
+ properties: {
3168
+ files: {
3169
+ type: "array",
3170
+ items: { type: "string" },
3171
+ description: "Files to scan (absolute paths). If empty, scans entire codebase."
3172
+ },
3173
+ directory: {
3174
+ type: "string",
3175
+ description: "Directory to scan (if files not specified). Defaults to current working directory."
3176
+ },
3177
+ context: {
3178
+ type: "object",
3179
+ properties: {
3180
+ changeType: {
3181
+ type: "string",
3182
+ enum: ["ui", "api", "database", "auth", "payment", "general"]
3183
+ },
3184
+ isNewFeature: { type: "boolean" },
3185
+ touchesUserData: { type: "boolean" }
3186
+ }
3187
+ },
3188
+ forceAgents: {
3189
+ type: "array",
3190
+ items: { type: "string" },
3191
+ description: "Manually specify agents to run (overrides triaging)"
3192
+ }
3193
+ }
3194
+ }
3195
+ },
3196
+ {
3197
+ name: "trie",
3198
+ description: "Quick menu of available Trie commands and aliases.",
3199
+ inputSchema: {
3200
+ type: "object",
3201
+ properties: {}
3202
+ }
3203
+ },
3204
+ // Alias so users can call `trie_scan` directly (no server prefix needed)
3205
+ {
3206
+ name: "trie_scan",
3207
+ description: "Alias for scan (same behavior as scan).",
3208
+ inputSchema: {
3209
+ type: "object",
3210
+ properties: {
3211
+ files: {
3212
+ type: "array",
3213
+ items: { type: "string" },
3214
+ description: "Files to scan (absolute paths). If empty, scans entire codebase."
3215
+ },
3216
+ directory: {
3217
+ type: "string",
3218
+ description: "Directory to scan (if files not specified). Defaults to current working directory."
3219
+ },
3220
+ context: {
3221
+ type: "object",
3222
+ properties: {
3223
+ changeType: {
3224
+ type: "string",
3225
+ enum: ["ui", "api", "database", "auth", "payment", "general"]
3226
+ },
3227
+ isNewFeature: { type: "boolean" },
3228
+ touchesUserData: { type: "boolean" }
3229
+ }
3230
+ },
3231
+ forceAgents: {
3232
+ type: "array",
3233
+ items: { type: "string" },
3234
+ description: "Manually specify agents to run (overrides triaging)"
3235
+ }
3236
+ }
3237
+ }
3238
+ },
3239
+ {
3240
+ name: "fix",
3241
+ description: "Apply high-confidence fixes to code",
3242
+ inputSchema: {
3243
+ type: "object",
3244
+ properties: {
3245
+ issueIds: {
3246
+ type: "array",
3247
+ items: { type: "string" },
3248
+ description: "Specific issues to fix (empty = all high-confidence)"
3249
+ },
3250
+ autoApprove: {
3251
+ type: "boolean",
3252
+ description: "Skip human review for high-confidence fixes"
3253
+ }
3254
+ }
3255
+ }
3256
+ },
3257
+ {
3258
+ name: "explain",
3259
+ description: "Explain code, issues, or changes in plain language",
3260
+ inputSchema: {
3261
+ type: "object",
3262
+ properties: {
3263
+ type: {
3264
+ type: "string",
3265
+ enum: ["code", "issue", "change", "risk"]
3266
+ },
3267
+ target: {
3268
+ type: "string",
3269
+ description: "What to explain (file path, issue ID, etc.)"
3270
+ }
3271
+ },
3272
+ required: ["type", "target"]
3273
+ }
3274
+ },
3275
+ {
3276
+ name: "test",
3277
+ description: "Generate tests or check test coverage",
3278
+ inputSchema: {
3279
+ type: "object",
3280
+ properties: {
3281
+ action: {
3282
+ type: "string",
3283
+ enum: ["generate", "coverage", "run"]
3284
+ },
3285
+ files: {
3286
+ type: "array",
3287
+ items: { type: "string" }
3288
+ }
3289
+ },
3290
+ required: ["action", "files"]
3291
+ }
3292
+ },
3293
+ {
3294
+ name: "register_agent",
3295
+ description: "Register a custom agent for your project",
3296
+ inputSchema: {
3297
+ type: "object",
3298
+ properties: {
3299
+ name: { type: "string" },
3300
+ path: {
3301
+ type: "string",
3302
+ description: "Path to agent implementation"
3303
+ },
3304
+ activationRules: {
3305
+ type: "object",
3306
+ description: "When to activate this agent"
3307
+ }
3308
+ },
3309
+ required: ["name", "path"]
3310
+ }
3311
+ },
3312
+ {
3313
+ name: "watch",
3314
+ description: "Autonomous mode: watch for file changes and scan/fix automatically. Use yolo:true for auto-fix!",
3315
+ inputSchema: {
3316
+ type: "object",
3317
+ properties: {
3318
+ action: {
3319
+ type: "string",
3320
+ enum: ["start", "stop", "status", "issues", "yolo"],
3321
+ description: "start = begin watching, stop = end, status = check, issues = list, yolo = toggle auto-fix"
3322
+ },
3323
+ directory: {
3324
+ type: "string",
3325
+ description: "Directory to watch (defaults to current working directory)"
3326
+ },
3327
+ yolo: {
3328
+ type: "boolean",
3329
+ description: "\u{1F525} YOLO MODE: Auto-fix issues as they occur! (default: false)"
3330
+ },
3331
+ debounceMs: {
3332
+ type: "number",
3333
+ description: "Milliseconds to wait after file change before scanning (default: 1000)"
3334
+ }
3335
+ },
3336
+ required: ["action"]
3337
+ }
3338
+ },
3339
+ // Individual agent commands
3340
+ {
3341
+ name: "security",
3342
+ description: "Run security agent: detect vulnerabilities, injection risks, auth issues, hardcoded secrets",
3343
+ inputSchema: {
3344
+ type: "object",
3345
+ properties: {
3346
+ files: { type: "array", items: { type: "string" }, description: "Files to scan (or scans codebase)" },
3347
+ directory: { type: "string", description: "Directory to scan" },
3348
+ output: {
3349
+ type: "string",
3350
+ enum: ["summary", "full"],
3351
+ description: "summary = concise (default), full = includes AI prompt/code (large output)"
3352
+ }
3353
+ }
3354
+ }
3355
+ },
3356
+ {
3357
+ name: "privacy",
3358
+ description: "Run privacy agent: PII handling, GDPR/HIPAA compliance, data encryption",
3359
+ inputSchema: {
3360
+ type: "object",
3361
+ properties: {
3362
+ files: { type: "array", items: { type: "string" }, description: "Files to scan" },
3363
+ directory: { type: "string", description: "Directory to scan" },
3364
+ output: {
3365
+ type: "string",
3366
+ enum: ["summary", "full"],
3367
+ description: "summary = concise (default), full = includes AI prompt/code (large output)"
3368
+ }
3369
+ }
3370
+ }
3371
+ },
3372
+ {
3373
+ name: "legal",
3374
+ description: "Run legal agent: GDPR, CCPA, consent patterns, data retention compliance",
3375
+ inputSchema: {
3376
+ type: "object",
3377
+ properties: {
3378
+ files: { type: "array", items: { type: "string" }, description: "Files to scan" },
3379
+ directory: { type: "string", description: "Directory to scan" },
3380
+ output: {
3381
+ type: "string",
3382
+ enum: ["summary", "full"],
3383
+ description: "summary = concise (default), full = includes AI prompt/code (large output)"
3384
+ }
3385
+ }
3386
+ }
3387
+ },
3388
+ {
3389
+ name: "accessibility",
3390
+ description: "Run accessibility agent: WCAG 2.1 compliance, keyboard nav, screen readers, color contrast",
3391
+ inputSchema: {
3392
+ type: "object",
3393
+ properties: {
3394
+ files: { type: "array", items: { type: "string" }, description: "Files to scan" },
3395
+ directory: { type: "string", description: "Directory to scan" },
3396
+ output: {
3397
+ type: "string",
3398
+ enum: ["summary", "full"],
3399
+ description: "summary = concise (default), full = includes AI prompt/code (large output)"
3400
+ }
3401
+ }
3402
+ }
3403
+ },
3404
+ {
3405
+ name: "architecture",
3406
+ description: "Run architecture agent: code organization, SOLID principles, N+1 queries, scalability",
3407
+ inputSchema: {
3408
+ type: "object",
3409
+ properties: {
3410
+ files: { type: "array", items: { type: "string" }, description: "Files to scan" },
3411
+ directory: { type: "string", description: "Directory to scan" },
3412
+ output: {
3413
+ type: "string",
3414
+ enum: ["summary", "full"],
3415
+ description: "summary = concise (default), full = includes AI prompt/code (large output)"
3416
+ }
3417
+ }
3418
+ }
3419
+ },
3420
+ {
3421
+ name: "bugs",
3422
+ description: "Run bug-finding agent: null safety, edge cases, common bugs, async issues",
3423
+ inputSchema: {
3424
+ type: "object",
3425
+ properties: {
3426
+ files: { type: "array", items: { type: "string" }, description: "Files to scan" },
3427
+ directory: { type: "string", description: "Directory to scan" },
3428
+ output: {
3429
+ type: "string",
3430
+ enum: ["summary", "full"],
3431
+ description: "summary = concise (default), full = includes AI prompt/code (large output)"
3432
+ }
3433
+ }
3434
+ }
3435
+ },
3436
+ {
3437
+ name: "ux",
3438
+ description: "Run UX testing agent: simulate happy path, security tester, confused user, impatient user",
3439
+ inputSchema: {
3440
+ type: "object",
3441
+ properties: {
3442
+ files: { type: "array", items: { type: "string" }, description: "Files to scan" },
3443
+ directory: { type: "string", description: "Directory to scan" },
3444
+ output: {
3445
+ type: "string",
3446
+ enum: ["summary", "full"],
3447
+ description: "summary = concise (default), full = includes AI prompt/code (large output)"
3448
+ }
3449
+ }
3450
+ }
3451
+ },
3452
+ {
3453
+ name: "types",
3454
+ description: "Run type safety agent: type errors, missing annotations, null checks",
3455
+ inputSchema: {
3456
+ type: "object",
3457
+ properties: {
3458
+ files: { type: "array", items: { type: "string" }, description: "Files to scan" },
3459
+ directory: { type: "string", description: "Directory to scan" },
3460
+ output: {
3461
+ type: "string",
3462
+ enum: ["summary", "full"],
3463
+ description: "summary = concise (default), full = includes AI prompt/code (large output)"
3464
+ }
3465
+ }
3466
+ }
3467
+ },
3468
+ {
3469
+ name: "devops",
3470
+ description: "Run devops agent: config issues, logging, environment variables, deployment patterns",
3471
+ inputSchema: {
3472
+ type: "object",
3473
+ properties: {
3474
+ files: { type: "array", items: { type: "string" }, description: "Files to scan" },
3475
+ directory: { type: "string", description: "Directory to scan" },
3476
+ output: {
3477
+ type: "string",
3478
+ enum: ["summary", "full"],
3479
+ description: "summary = concise (default), full = includes AI prompt/code (large output)"
3480
+ }
3481
+ }
3482
+ }
3483
+ },
3484
+ {
3485
+ name: "clean",
3486
+ description: "\u{1F9F9} Clean up AI-generated code: find common mistakes, bad patterns, and quick fixes",
3487
+ inputSchema: {
3488
+ type: "object",
3489
+ properties: {
3490
+ files: { type: "array", items: { type: "string" }, description: "Files to scan" },
3491
+ directory: { type: "string", description: "Directory to scan" },
3492
+ output: {
3493
+ type: "string",
3494
+ enum: ["summary", "full"],
3495
+ description: "summary = concise (default), full = includes AI prompt/code (large output)"
3496
+ }
3497
+ }
3498
+ }
3499
+ },
3500
+ // Custom agent creation tools (two-step process - no API key needed!)
3501
+ {
3502
+ name: "create_agent",
3503
+ description: "\u{1F4DA} Step 1: Parse a document to create a custom agent. Supports file path OR drag-and-drop content. Returns extraction prompt for Claude to process.",
3504
+ inputSchema: {
3505
+ type: "object",
3506
+ properties: {
3507
+ filePath: {
3508
+ type: "string",
3509
+ description: "Path to the document file (PDF, TXT, MD, or RTF)"
3510
+ },
3511
+ documentContent: {
3512
+ type: "string",
3513
+ description: "Raw document text (for drag-and-drop or pasted content). Use this OR filePath."
3514
+ },
3515
+ agentName: {
3516
+ type: "string",
3517
+ description: 'Name for the new agent (e.g., "react-fundamentals", "gdpr-compliance")'
3518
+ },
3519
+ displayName: {
3520
+ type: "string",
3521
+ description: 'Optional display name (e.g., "React Fundamentals Expert")'
3522
+ },
3523
+ description: {
3524
+ type: "string",
3525
+ description: "Optional description of what the agent does"
3526
+ },
3527
+ category: {
3528
+ type: "string",
3529
+ description: 'Optional category (e.g., "react", "security", "compliance", "architecture")'
3530
+ }
3531
+ },
3532
+ required: ["agentName"]
3533
+ }
3534
+ },
3535
+ {
3536
+ name: "save_agent",
3537
+ description: "\u{1F4E6} Step 2: Save the agent config after Claude extracts knowledge from the document. Pass the JSON output from trie_create_agent.",
3538
+ inputSchema: {
3539
+ type: "object",
3540
+ properties: {
3541
+ agentConfig: {
3542
+ type: "object",
3543
+ description: "Agent configuration (name, displayName, description, category)",
3544
+ properties: {
3545
+ name: { type: "string" },
3546
+ displayName: { type: "string" },
3547
+ description: { type: "string" },
3548
+ version: { type: "string" },
3549
+ category: { type: "string" }
3550
+ },
3551
+ required: ["name", "category"]
3552
+ },
3553
+ knowledge: {
3554
+ type: "object",
3555
+ description: "Extracted knowledge (domain, summary, coreConcepts, bestPractices, antiPatterns, glossary)"
3556
+ },
3557
+ detectionRules: {
3558
+ type: "array",
3559
+ description: "Array of detection rules with patterns and fixes"
3560
+ },
3561
+ prompts: {
3562
+ type: "object",
3563
+ description: "Agent prompts (systemPrompt, analysisPrompt, fixPrompt)",
3564
+ properties: {
3565
+ systemPrompt: { type: "string" },
3566
+ analysisPrompt: { type: "string" },
3567
+ fixPrompt: { type: "string" }
3568
+ },
3569
+ required: ["systemPrompt", "analysisPrompt", "fixPrompt"]
3570
+ },
3571
+ sourceFile: {
3572
+ type: "string",
3573
+ description: "Original source file path (optional)"
3574
+ }
3575
+ },
3576
+ required: ["agentConfig", "knowledge", "detectionRules", "prompts"]
3577
+ }
3578
+ },
3579
+ {
3580
+ name: "list_agents",
3581
+ description: "\u{1F4CB} List all registered agents including custom agents created from documents",
3582
+ inputSchema: {
3583
+ type: "object",
3584
+ properties: {
3585
+ includeBuiltin: {
3586
+ type: "boolean",
3587
+ description: "Include built-in agents in the list (default: true)"
3588
+ }
3589
+ }
3590
+ }
3591
+ }
3592
+ ];
3593
+ server.setRequestHandler(ListToolsRequestSchema, async () => {
3594
+ return {
3595
+ tools
3596
+ };
3597
+ });
3598
+ server.setRequestHandler(CallToolRequestSchema, async (request) => {
3599
+ const { name, arguments: args } = request.params;
3600
+ const stripNamespace = (n) => {
3601
+ const parts = n.split(":");
3602
+ const base = parts[0] || n;
3603
+ const slashParts = base.split("/");
3604
+ return slashParts[slashParts.length - 1] || base;
3605
+ };
3606
+ const rawName = stripNamespace(name);
3607
+ const normalizedName = rawName.startsWith("trie_") ? rawName.slice("trie_".length) : rawName;
3608
+ try {
3609
+ switch (normalizedName) {
3610
+ case "trie":
3611
+ return {
3612
+ content: [
3613
+ {
3614
+ type: "text",
3615
+ text: [
3616
+ "## Trie Menu",
3617
+ "",
3618
+ "- `trie_scan` or `scan`: Full intelligent scan (auto triage agents)",
3619
+ "- `fix`: Apply high-confidence fixes",
3620
+ "- `explain`: Explain code/issues/risks",
3621
+ "- `watch`: Watch mode (scan on change)",
3622
+ "- `security`, `privacy`, `legal`, `bugs`, `types`, `devops`, `architecture`, `ux`, `clean`: Run a specific agent",
3623
+ "- `test`: Generate/check tests",
3624
+ "- `register_agent`, `create_agent`, `save_agent`, `list_agents`: Custom agent lifecycle",
3625
+ "",
3626
+ "You can call these without any namespace; `trie_` aliases also work."
3627
+ ].join("\n")
3628
+ }
3629
+ ]
3630
+ };
3631
+ case "scan":
3632
+ return await scanTool.execute(args);
3633
+ case "fix":
3634
+ return await fixTool.execute(args);
3635
+ case "explain":
3636
+ return await explainTool.execute(args);
3637
+ case "test":
3638
+ return await testTool.execute(args);
3639
+ case "register_agent":
3640
+ return await registerAgentTool.execute(args);
3641
+ case "watch":
3642
+ return await watchTool.execute(args);
3643
+ // Individual agent commands
3644
+ case "security":
3645
+ return await agentTool.execute({ ...args, agent: "security" });
3646
+ case "privacy":
3647
+ return await agentTool.execute({ ...args, agent: "privacy" });
3648
+ case "legal":
3649
+ return await agentTool.execute({ ...args, agent: "legal" });
3650
+ case "accessibility":
3651
+ return await agentTool.execute({ ...args, agent: "design-engineer" });
3652
+ case "architecture":
3653
+ return await agentTool.execute({ ...args, agent: "software-architect" });
3654
+ case "bugs":
3655
+ return await agentTool.execute({ ...args, agent: "bug-finding" });
3656
+ case "ux":
3657
+ return await agentTool.execute({ ...args, agent: "user-testing" });
3658
+ case "types":
3659
+ return await agentTool.execute({ ...args, agent: "typecheck" });
3660
+ case "devops":
3661
+ return await agentTool.execute({ ...args, agent: "devops" });
3662
+ case "clean":
3663
+ return await agentTool.execute({ ...args, agent: "trie_clean" });
3664
+ // Custom agent creation tools (two-step process)
3665
+ case "create_agent":
3666
+ return await createAgentTool.execute(args);
3667
+ case "save_agent":
3668
+ return await saveAgentTool.execute(args);
3669
+ case "list_agents":
3670
+ return await listAgentsTool.execute(args);
3671
+ default:
3672
+ throw new Error(`Unknown tool: ${name}`);
3673
+ }
3674
+ } catch (error) {
3675
+ return {
3676
+ content: [
3677
+ {
3678
+ type: "text",
3679
+ text: `Error: ${error instanceof Error ? error.message : String(error)}`
3680
+ }
3681
+ ]
3682
+ };
3683
+ }
3684
+ });
3685
+ var agentRegistry = new AgentRegistry();
3686
+ async function getAvailableResources() {
3687
+ const resources = [];
3688
+ resources.push({
3689
+ uri: "trie://agents",
3690
+ name: "Available Agents",
3691
+ description: "List of all available Trie agents (built-in and custom)",
3692
+ mimeType: "application/json"
3693
+ });
3694
+ resources.push({
3695
+ uri: "trie://config",
3696
+ name: "Trie Configuration",
3697
+ description: "Current Trie configuration settings",
3698
+ mimeType: "application/json"
3699
+ });
3700
+ resources.push({
3701
+ uri: "trie://cache/stats",
3702
+ name: "Cache Statistics",
3703
+ description: "Trie scan cache statistics and performance metrics",
3704
+ mimeType: "application/json"
3705
+ });
3706
+ resources.push({
3707
+ uri: "trie://signatures",
3708
+ name: "Vulnerability Signatures",
3709
+ description: "Summary of loaded vulnerability detection signatures",
3710
+ mimeType: "application/json"
3711
+ });
3712
+ try {
3713
+ const reportsDir = join6(process.cwd(), "trie-reports");
3714
+ const files = await readdir2(reportsDir);
3715
+ const reportFiles = files.filter((f) => f.endsWith(".txt") || f.endsWith(".json"));
3716
+ for (const file of reportFiles.slice(0, 10)) {
3717
+ resources.push({
3718
+ uri: `trie://reports/${file}`,
3719
+ name: `Scan Report: ${file}`,
3720
+ description: `Trie scan report from ${file}`,
3721
+ mimeType: file.endsWith(".json") ? "application/json" : "text/plain"
3722
+ });
3723
+ }
3724
+ } catch {
3725
+ }
3726
+ try {
3727
+ await agentRegistry.loadCustomAgents();
3728
+ const customAgents = agentRegistry.getCustomAgents();
3729
+ for (const agent of customAgents) {
3730
+ resources.push({
3731
+ uri: `trie://agents/custom/${agent.name}`,
3732
+ name: `Custom Agent: ${agent.name}`,
3733
+ description: agent.description,
3734
+ mimeType: "application/json"
3735
+ });
3736
+ }
3737
+ } catch {
3738
+ }
3739
+ return resources;
3740
+ }
3741
+ async function readResourceContent(uri) {
3742
+ const parsedUri = uri.replace("trie://", "");
3743
+ if (parsedUri === "agents") {
3744
+ await agentRegistry.loadCustomAgents();
3745
+ const agents = agentRegistry.getAgentDescriptions();
3746
+ return {
3747
+ contents: [{
3748
+ uri,
3749
+ mimeType: "application/json",
3750
+ text: JSON.stringify({
3751
+ totalAgents: agents.length,
3752
+ builtinCount: agents.filter((a) => !a.isCustom).length,
3753
+ customCount: agents.filter((a) => a.isCustom).length,
3754
+ agents: agents.map((a) => ({
3755
+ name: a.name,
3756
+ description: a.description,
3757
+ type: a.isCustom ? "custom" : "builtin"
3758
+ }))
3759
+ }, null, 2)
3760
+ }]
3761
+ };
3762
+ }
3763
+ if (parsedUri.startsWith("agents/custom/")) {
3764
+ const agentName = parsedUri.replace("agents/custom/", "");
3765
+ await agentRegistry.loadCustomAgents();
3766
+ const metadata = agentRegistry.getCustomAgentMetadata(agentName);
3767
+ if (!metadata) {
3768
+ throw new Error(`Custom agent not found: ${agentName}`);
3769
+ }
3770
+ return {
3771
+ contents: [{
3772
+ uri,
3773
+ mimeType: "application/json",
3774
+ text: JSON.stringify(metadata, null, 2)
3775
+ }]
3776
+ };
3777
+ }
3778
+ if (parsedUri === "config") {
3779
+ const config = await loadConfig();
3780
+ return {
3781
+ contents: [{
3782
+ uri,
3783
+ mimeType: "application/json",
3784
+ text: JSON.stringify(config, null, 2)
3785
+ }]
3786
+ };
3787
+ }
3788
+ if (parsedUri === "cache/stats") {
3789
+ try {
3790
+ const cachePath = join6(process.cwd(), ".trie", ".trie-cache.json");
3791
+ const cacheContent = await readFile6(cachePath, "utf-8");
3792
+ const cache = JSON.parse(cacheContent);
3793
+ const fileCount = Object.keys(cache.files || {}).length;
3794
+ const totalVulns = Object.values(cache.files || {}).reduce((acc, file) => {
3795
+ return acc + (file.vulnerabilities?.length || 0);
3796
+ }, 0);
3797
+ return {
3798
+ contents: [{
3799
+ uri,
3800
+ mimeType: "application/json",
3801
+ text: JSON.stringify({
3802
+ version: cache.version,
3803
+ created: new Date(cache.created).toISOString(),
3804
+ lastUpdated: new Date(cache.lastUpdated).toISOString(),
3805
+ cachedFiles: fileCount,
3806
+ totalVulnerabilitiesFound: totalVulns,
3807
+ cacheAgeMinutes: Math.round((Date.now() - cache.lastUpdated) / 6e4)
3808
+ }, null, 2)
3809
+ }]
3810
+ };
3811
+ } catch {
3812
+ return {
3813
+ contents: [{
3814
+ uri,
3815
+ mimeType: "application/json",
3816
+ text: JSON.stringify({
3817
+ error: "No cache found. Run a scan first to build the cache.",
3818
+ hint: "Use trie_scan to scan your codebase"
3819
+ }, null, 2)
3820
+ }]
3821
+ };
3822
+ }
3823
+ }
3824
+ if (parsedUri === "signatures") {
3825
+ const { getVulnerabilityStats } = await import("./vulnerability-signatures-J3CUQ7VR.js");
3826
+ const { getVibeCodeStats } = await import("./vibe-code-signatures-4CBHUSI7.js");
3827
+ const vulnStats = getVulnerabilityStats();
3828
+ const vibeStats = getVibeCodeStats();
3829
+ return {
3830
+ contents: [{
3831
+ uri,
3832
+ mimeType: "application/json",
3833
+ text: JSON.stringify({
3834
+ vulnerabilitySignatures: vulnStats,
3835
+ vibeCodeSignatures: vibeStats,
3836
+ totalSignatures: vulnStats.total + vibeStats.total
3837
+ }, null, 2)
3838
+ }]
3839
+ };
3840
+ }
3841
+ if (parsedUri.startsWith("reports/")) {
3842
+ const fileName = parsedUri.replace("reports/", "");
3843
+ const reportPath = join6(process.cwd(), "trie-reports", fileName);
3844
+ try {
3845
+ const content = await readFile6(reportPath, "utf-8");
3846
+ return {
3847
+ contents: [{
3848
+ uri,
3849
+ mimeType: fileName.endsWith(".json") ? "application/json" : "text/plain",
3850
+ text: content
3851
+ }]
3852
+ };
3853
+ } catch {
3854
+ throw new Error(`Report not found: ${fileName}`);
3855
+ }
3856
+ }
3857
+ throw new Error(`Unknown resource: ${uri}`);
3858
+ }
3859
+ server.setRequestHandler(ListResourcesRequestSchema, async () => {
3860
+ const resources = await getAvailableResources();
3861
+ return { resources };
3862
+ });
3863
+ server.setRequestHandler(ReadResourceRequestSchema, async (request) => {
3864
+ const { uri } = request.params;
3865
+ return await readResourceContent(uri);
3866
+ });
3867
+ async function main() {
3868
+ const aiTool = detectAITool();
3869
+ console.error(`Detected AI Tool: ${aiTool.name}`);
3870
+ const config = await loadConfig();
3871
+ console.error(`Loaded config for ${config.agents.builtin ? Object.keys(config.agents.builtin).length : 0} built-in agents`);
3872
+ const transport = new StdioServerTransport();
3873
+ await server.connect(transport);
3874
+ console.error("Trie Agent MCP Server running...");
3875
+ }
3876
+ if (import.meta.url === `file://${process.argv[1]}`) {
3877
+ main().catch((error) => {
3878
+ console.error("Fatal error:", error);
3879
+ process.exit(1);
3880
+ });
3881
+ }
3882
+ //# sourceMappingURL=index.js.map