@triedotdev/mcp 1.0.142 → 1.0.143

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 CHANGED
@@ -32,8 +32,10 @@ import {
32
32
  InteractiveDashboard,
33
33
  StreamingManager,
34
34
  TrieCheckTool,
35
+ TrieCloudFixTool,
35
36
  TrieExplainTool,
36
37
  TrieFeedbackTool,
38
+ TrieFixTool,
37
39
  TrieGetBlockersTool,
38
40
  TrieGetDecisionsTool,
39
41
  TrieGetGovernanceTool,
@@ -46,7 +48,7 @@ import {
46
48
  getPrompt,
47
49
  getSystemPrompt,
48
50
  handleCheckpointTool
49
- } from "./chunk-Y2LYDCJD.js";
51
+ } from "./chunk-AIJF67CF.js";
50
52
  import "./chunk-23RJT5WT.js";
51
53
  import "./chunk-N2EDZTKG.js";
52
54
  import {
@@ -91,9 +93,7 @@ import {
91
93
  getSkillRegistry
92
94
  } from "./chunk-G76DYVGX.js";
93
95
  import {
94
- getAutonomyConfig,
95
- loadAutonomyConfig,
96
- saveAutonomyConfig
96
+ getAutonomyConfig
97
97
  } from "./chunk-5KJ4UJOY.js";
98
98
  import {
99
99
  findSimilarIssues,
@@ -195,1151 +195,10 @@ function detectAITool() {
195
195
  };
196
196
  }
197
197
 
198
- // src/tools/fix.ts
198
+ // src/tools/test.ts
199
199
  import { readFile } from "fs/promises";
200
200
  import { existsSync } from "fs";
201
- import { extname, relative, resolve, isAbsolute } from "path";
202
-
203
- // src/tools/fix-triage.ts
204
- var EFFORT_SCORES = {
205
- trivial: -6,
206
- easy: -3,
207
- medium: 0,
208
- hard: 4
209
- };
210
- var SEVERITY_SCORES = {
211
- critical: 4,
212
- serious: 2,
213
- moderate: -1,
214
- low: -3
215
- };
216
- function triageIssue(issue, context, occurrence, config, pipeline) {
217
- const reasons = [];
218
- if (config?.level === "passive") {
219
- return {
220
- strategy: "local-ai",
221
- score: 0,
222
- confidence: 1,
223
- reasons: ["Autonomy level is passive \u2014 cloud dispatch disabled"],
224
- fallback: "local-ai"
225
- };
226
- }
227
- if (config?.cloudAgentEnabled === false) {
228
- return {
229
- strategy: "local-ai",
230
- score: 0,
231
- confidence: 1,
232
- reasons: ["Cloud agent not enabled (run trie_cloud_fix action:configure)"],
233
- fallback: "local-ai"
234
- };
235
- }
236
- let score = 0;
237
- const effort = issue.effort ?? "medium";
238
- const effortScore = EFFORT_SCORES[effort] ?? 0;
239
- if (effortScore !== 0) {
240
- score += effortScore;
241
- reasons.push(`effort:${effort}`);
242
- }
243
- const severityScore = SEVERITY_SCORES[issue.severity] ?? 0;
244
- if (severityScore !== 0) {
245
- score += severityScore;
246
- reasons.push(`severity:${issue.severity}`);
247
- }
248
- if (issue.autoFixable) {
249
- score -= 2;
250
- reasons.push("autoFixable");
251
- }
252
- if (issue.confidence < 0.7) {
253
- score -= 2;
254
- reasons.push(`low confidence (${(issue.confidence * 100).toFixed(0)}%)`);
255
- }
256
- if (issue.cwe) {
257
- score += 3;
258
- reasons.push(`cwe:${issue.cwe}`);
259
- }
260
- if (issue.owasp) {
261
- score += 2;
262
- reasons.push(`owasp:${issue.owasp}`);
263
- }
264
- if (issue.category === "security") {
265
- score += 2;
266
- reasons.push("category:security");
267
- }
268
- if (context) {
269
- if (context.hasTests) {
270
- score += 1;
271
- reasons.push("has tests");
272
- } else {
273
- score -= 2;
274
- reasons.push("no tests");
275
- }
276
- if (context.complexity === "high") {
277
- score += 1;
278
- reasons.push("high complexity");
279
- }
280
- if (context.touchesAuth || context.touchesCrypto || context.touchesPayments) {
281
- score += 2;
282
- reasons.push("touches auth/crypto/payments");
283
- }
284
- if (context.touchesDatabase) {
285
- score += 1;
286
- reasons.push("touches database");
287
- }
288
- }
289
- if (occurrence) {
290
- if (occurrence.count >= 5) {
291
- score += 3;
292
- reasons.push(`${occurrence.count}\xD7 seen`);
293
- } else if (occurrence.count >= 3) {
294
- score += 1;
295
- reasons.push(`${occurrence.count}\xD7 seen`);
296
- }
297
- if (occurrence.escalationLevel === "block") {
298
- score += 4;
299
- reasons.push("escalation:block");
300
- } else if (occurrence.escalationLevel === "escalate") {
301
- score += 2;
302
- reasons.push("escalation:escalate");
303
- }
304
- }
305
- if (config?.level === "aggressive") {
306
- score -= 1;
307
- reasons.push("aggressive mode (\u22121 threshold)");
308
- }
309
- if (pipeline) {
310
- if (pipeline.hasLinkedPR && pipeline.prState === "open") {
311
- score -= 2;
312
- reasons.push("has open PR");
313
- }
314
- if (pipeline.hasLinkedTicket && pipeline.ticketStatus?.toLowerCase().includes("started")) {
315
- score -= 1;
316
- reasons.push("ticket in active sprint");
317
- }
318
- if (pipeline.hasLinkedTicket && pipeline.ticketPriority === "urgent") {
319
- score += 1;
320
- reasons.push("ticket:urgent");
321
- }
322
- if (!pipeline.hasLinkedTicket && !pipeline.hasLinkedPR && issue.severity === "critical") {
323
- score += 2;
324
- reasons.push("critical, no ticket/PR (falling through cracks)");
325
- }
326
- }
327
- let strategy;
328
- if (score < 0 && issue.autoFixable) {
329
- strategy = "inline-auto";
330
- } else if (score < 4) {
331
- strategy = "local-ai";
332
- } else {
333
- strategy = "cloud-agent";
334
- }
335
- const confidence = Math.min(1, Math.abs(score) / 8);
336
- return { strategy, score, confidence, reasons, fallback: "local-ai" };
337
- }
338
- function triageIssues(issues, context, occurrences, config, pipelineContexts) {
339
- const results = /* @__PURE__ */ new Map();
340
- const summary = {
341
- inlineAuto: [],
342
- localAi: [],
343
- cloudAgent: [],
344
- cloudAgentScore: 0
345
- };
346
- for (const issue of issues) {
347
- const occurrence = occurrences?.get(issue.id);
348
- const pipeline = pipelineContexts?.get(issue.id);
349
- const result = triageIssue(issue, context, occurrence, config, pipeline);
350
- results.set(issue.id, result);
351
- switch (result.strategy) {
352
- case "inline-auto":
353
- summary.inlineAuto.push(issue);
354
- break;
355
- case "local-ai":
356
- summary.localAi.push(issue);
357
- break;
358
- case "cloud-agent":
359
- summary.cloudAgent.push(issue);
360
- summary.cloudAgentScore += result.score;
361
- break;
362
- }
363
- }
364
- return { results, summary };
365
- }
366
- function formatTriageTable(results, issues) {
367
- const LINE = "\u2500".repeat(68);
368
- const lines = [];
369
- lines.push("FIX ROUTING PLAN");
370
- lines.push(LINE);
371
- lines.push(
372
- padEnd("Issue", 32) + padEnd("Strategy", 14) + padEnd("Score", 7) + "Reason"
373
- );
374
- for (const issue of issues) {
375
- const r = results.get(issue.id);
376
- if (!r) continue;
377
- const loc = `${shortPath(issue.file)}:${issue.line ?? "?"}`;
378
- const scoreStr = r.score >= 0 ? `+${r.score}` : String(r.score);
379
- lines.push(
380
- padEnd(loc, 32) + padEnd(r.strategy, 14) + padEnd(scoreStr, 7) + r.reasons.join(", ")
381
- );
382
- }
383
- lines.push(LINE);
384
- const counts = [];
385
- const cloud = issues.filter((i) => results.get(i.id)?.strategy === "cloud-agent");
386
- const local = issues.filter((i) => results.get(i.id)?.strategy === "local-ai");
387
- const auto = issues.filter((i) => results.get(i.id)?.strategy === "inline-auto");
388
- if (cloud.length) counts.push(`${cloud.length} for cloud agent`);
389
- if (local.length) counts.push(`${local.length} for local AI`);
390
- if (auto.length) counts.push(`${auto.length} auto-fixable`);
391
- lines.push(counts.join(", "));
392
- if (cloud.length > 0) {
393
- const ids = cloud.map((i) => `"${i.id}"`).join(",");
394
- lines.push("");
395
- lines.push(`To dispatch cloud issues: trie_cloud_fix action:dispatch issueIds:[${ids}]`);
396
- }
397
- if (local.length > 0) {
398
- const ids = local.map((i) => `"${i.id}"`).join(",");
399
- lines.push(`To fix local issues: trie_fix issueIds:[${ids}]`);
400
- }
401
- return lines.join("\n");
402
- }
403
- function formatCloudRecommendation(results, issues) {
404
- const cloud = issues.filter((i) => {
405
- const r = results.get(i.id);
406
- return r && r.score >= 4;
407
- });
408
- if (cloud.length === 0) return null;
409
- const LINE = "\u2500".repeat(65);
410
- const lines = [];
411
- lines.push(LINE);
412
- lines.push(
413
- `${cloud.length} issue${cloud.length > 1 ? "s" : ""} qualify for cloud agent verification (test-verified fix + PR):`
414
- );
415
- for (const issue of cloud) {
416
- const r = results.get(issue.id);
417
- const loc = `${shortPath(issue.file)}:${issue.line ?? "?"}`;
418
- const scoreStr = r.score >= 0 ? `+${r.score}` : String(r.score);
419
- lines.push(` \u2022 ${padEnd(loc, 30)} \u2014 score ${scoreStr} (${r.reasons.join(", ")})`);
420
- }
421
- const ids = cloud.map((i) => `"${i.id}"`).join(",");
422
- lines.push("");
423
- lines.push(`Run: trie_cloud_fix action:dispatch issueIds:[${ids}]`);
424
- lines.push(LINE);
425
- return lines.join("\n");
426
- }
427
- function shortPath(file) {
428
- const parts = file.split("/");
429
- return parts.length > 2 ? parts.slice(-2).join("/") : file;
430
- }
431
- function padEnd(str, len) {
432
- if (str.length >= len) return str.slice(0, len);
433
- return str + " ".repeat(len - str.length);
434
- }
435
-
436
- // src/tools/fix.ts
437
- var pendingFixes = /* @__PURE__ */ new Map();
438
- var TrieFixTool = class {
439
- async execute(args) {
440
- const { issueIds, file, line, issue, fix, autoApprove = false, dryRun = false, action } = args || {};
441
- if (action === "route") {
442
- return this.routeIssues(issueIds);
443
- }
444
- if (issueIds && issueIds.length > 0) {
445
- return this.fixByIds(issueIds, autoApprove, dryRun);
446
- }
447
- if (file && fix) {
448
- return this.applyFix(file, line || 1, issue || "User-specified fix", fix, dryRun);
449
- }
450
- if (pendingFixes.size > 0) {
451
- return this.showPendingFixes();
452
- }
453
- if (file && issue) {
454
- return this.generateFixPrompt(file, line || 1, issue);
455
- }
456
- return {
457
- content: [{
458
- type: "text",
459
- text: this.getHelpText()
460
- }]
461
- };
462
- }
463
- async routeIssues(issueIds) {
464
- await loadPendingFixesFromMemory();
465
- const pending = getPendingFixes();
466
- if (pending.length === 0) {
467
- return {
468
- content: [{ type: "text", text: "No pending issues. Run trie_scan to detect new issues, or check memory with trie_memory action:recent." }]
469
- };
470
- }
471
- const issues = pending.map((p) => ({
472
- id: p.id,
473
- severity: p.severity ?? "moderate",
474
- effort: p.effort,
475
- issue: p.issue,
476
- fix: p.suggestedFix,
477
- file: p.file,
478
- line: p.line,
479
- confidence: p.confidence,
480
- autoFixable: p.autoFixable ?? false,
481
- agent: "trie_scan",
482
- cwe: p.cwe,
483
- owasp: p.owasp,
484
- category: p.category
485
- }));
486
- const filtered = issueIds && issueIds.length > 0 ? issues.filter((i) => issueIds.includes(i.id)) : issues;
487
- const workDir = getWorkingDirectory(void 0, true);
488
- const config = await loadAutonomyConfig(workDir);
489
- const { results } = triageIssues(filtered, void 0, void 0, config);
490
- const table = formatTriageTable(results, filtered);
491
- return { content: [{ type: "text", text: `
492
- ${table}
493
- ` }] };
494
- }
495
- async fixByIds(issueIds, autoApprove, dryRun) {
496
- const results = [];
497
- let fixed = 0;
498
- let failed = 0;
499
- for (const id of issueIds) {
500
- const pendingFix = pendingFixes.get(id);
501
- if (!pendingFix) {
502
- results.push(`\u274C Issue ${id}: Not found in pending fixes`);
503
- failed++;
504
- continue;
505
- }
506
- if (pendingFix.confidence < 0.8 && !autoApprove) {
507
- results.push(`[!] Issue ${id}: Confidence too low (${(pendingFix.confidence * 100).toFixed(0)}%) - use autoApprove:true to override`);
508
- continue;
509
- }
510
- if (dryRun) {
511
- results.push(`\u{1F50D} Issue ${id}: Would fix "${pendingFix.issue}" in ${pendingFix.file}:${pendingFix.line}`);
512
- continue;
513
- }
514
- try {
515
- results.push(`\u2705 Issue ${id}: Fix prepared for ${pendingFix.file}:${pendingFix.line}`);
516
- results.push(` Issue: ${pendingFix.issue}`);
517
- results.push(` Fix: ${pendingFix.suggestedFix}`);
518
- pendingFix.status = "applied";
519
- fixed++;
520
- } catch (error) {
521
- results.push(`\u274C Issue ${id}: Failed to apply - ${error}`);
522
- failed++;
523
- }
524
- }
525
- let output = `
526
- ${"\u2501".repeat(60)}
527
- `;
528
- output += `\u{1F527} FIX RESULTS
529
- `;
530
- output += `${"\u2501".repeat(60)}
531
-
532
- `;
533
- output += results.join("\n");
534
- output += `
535
-
536
- **Summary:** ${fixed} fixed, ${failed} failed, ${issueIds.length - fixed - failed} skipped
537
- `;
538
- output += await this.appendCloudRecommendation(issueIds);
539
- return { content: [{ type: "text", text: output }] };
540
- }
541
- async applyFix(file, line, issue, fix, dryRun) {
542
- const workDir = getWorkingDirectory(void 0, true);
543
- const filePath = isAbsolute(file) ? file : resolve(workDir, file);
544
- if (!existsSync(filePath)) {
545
- return {
546
- content: [{
547
- type: "text",
548
- text: `\u274C File not found: ${filePath}`
549
- }]
550
- };
551
- }
552
- const content = await readFile(filePath, "utf-8");
553
- const lines = content.split("\n");
554
- const language = this.detectLanguage(filePath);
555
- const contextStart = Math.max(0, line - 10);
556
- const contextEnd = Math.min(lines.length, line + 10);
557
- const contextLines = lines.slice(contextStart, contextEnd);
558
- const prompt = getPrompt("fix", "apply", {
559
- issue,
560
- fix,
561
- language,
562
- code: contextLines.join("\n"),
563
- filePath: relative(workDir, filePath),
564
- line: String(line)
565
- });
566
- const systemPrompt = getSystemPrompt("fix");
567
- let output = `
568
- ${"\u2501".repeat(60)}
569
- `;
570
- output += `\u{1F527} FIX APPLICATION REQUEST
571
- `;
572
- output += `${"\u2501".repeat(60)}
573
-
574
- `;
575
- output += `## \u{1F4CD} Target
576
-
577
- `;
578
- output += `- **File:** \`${relative(workDir, filePath)}\`
579
- `;
580
- output += `- **Line:** ${line}
581
- `;
582
- output += `- **Issue:** ${issue}
583
- `;
584
- output += `- **Requested Fix:** ${fix}
585
-
586
- `;
587
- output += `## \u{1F4C4} Current Code Context
588
-
589
- `;
590
- output += `\`\`\`${language}
591
- `;
592
- for (let i = 0; i < contextLines.length; i++) {
593
- const lineNum = contextStart + i + 1;
594
- const marker = lineNum === line ? "\u2192 " : " ";
595
- output += `${marker}${lineNum.toString().padStart(4)} | ${contextLines[i]}
596
- `;
597
- }
598
- output += `\`\`\`
599
-
600
- `;
601
- if (dryRun) {
602
- output += `## \u{1F50D} Dry Run Mode
603
-
604
- `;
605
- output += `No changes will be made. Review the fix below:
606
-
607
- `;
608
- }
609
- output += `${"\u2500".repeat(60)}
610
- `;
611
- output += `## \u{1F9E0} Fix Request for AI
612
-
613
- `;
614
- output += `**Role:** ${systemPrompt.split("\n")[0]}
615
-
616
- `;
617
- output += prompt;
618
- output += `
619
- ${"\u2500".repeat(60)}
620
- `;
621
- output += `
622
- ### After generating the fix, apply it with:
623
-
624
- `;
625
- output += `\`\`\`
626
- `;
627
- output += `Use the edit_file tool to apply the generated code changes
628
- `;
629
- output += `\`\`\`
630
- `;
631
- return { content: [{ type: "text", text: output }] };
632
- }
633
- async generateFixPrompt(file, line, issue) {
634
- const workDir = getWorkingDirectory(void 0, true);
635
- const filePath = isAbsolute(file) ? file : resolve(workDir, file);
636
- if (!existsSync(filePath)) {
637
- return {
638
- content: [{
639
- type: "text",
640
- text: `\u274C File not found: ${filePath}`
641
- }]
642
- };
643
- }
644
- const content = await readFile(filePath, "utf-8");
645
- const lines = content.split("\n");
646
- const language = this.detectLanguage(filePath);
647
- const contextStart = Math.max(0, line - 20);
648
- const contextEnd = Math.min(lines.length, line + 20);
649
- const contextLines = lines.slice(contextStart, contextEnd);
650
- let output = `
651
- ${"\u2501".repeat(60)}
652
- `;
653
- output += `\u{1F527} FIX GENERATION REQUEST
654
- `;
655
- output += `${"\u2501".repeat(60)}
656
-
657
- `;
658
- output += `## \u{1F4CD} Issue Details
659
-
660
- `;
661
- output += `- **File:** \`${relative(workDir, filePath)}\`
662
- `;
663
- output += `- **Line:** ${line}
664
- `;
665
- output += `- **Issue:** ${issue}
666
-
667
- `;
668
- output += `## \u{1F4C4} Code Context
669
-
670
- `;
671
- output += `\`\`\`${language}
672
- `;
673
- for (let i = 0; i < contextLines.length; i++) {
674
- const lineNum = contextStart + i + 1;
675
- const marker = lineNum === line ? "\u2192 " : " ";
676
- output += `${marker}${lineNum.toString().padStart(4)} | ${contextLines[i]}
677
- `;
678
- }
679
- output += `\`\`\`
680
-
681
- `;
682
- output += `## \u{1F9E0} Analysis Request
683
-
684
- `;
685
- output += `Please analyze this issue and provide:
686
-
687
- `;
688
- output += `1. **Root cause** - Why does this issue occur?
689
- `;
690
- output += `2. **Impact** - What could go wrong if unfixed?
691
- `;
692
- output += `3. **Fix** - The exact code change needed
693
- `;
694
- output += `4. **Verification** - How to test the fix works
695
-
696
- `;
697
- output += `After analysis, you can apply the fix using the edit_file tool.
698
- `;
699
- return { content: [{ type: "text", text: output }] };
700
- }
701
- showPendingFixes() {
702
- let output = `
703
- ${"\u2501".repeat(60)}
704
- `;
705
- output += `\u{1F527} PENDING FIXES
706
- `;
707
- output += `${"\u2501".repeat(60)}
708
-
709
- `;
710
- if (pendingFixes.size === 0) {
711
- output += `No pending fixes. Run \`trie_scan\` first to detect issues.
712
- `;
713
- return { content: [{ type: "text", text: output }] };
714
- }
715
- const fixes = Array.from(pendingFixes.values());
716
- const byStatus = {
717
- pending: fixes.filter((f) => f.status === "pending"),
718
- applied: fixes.filter((f) => f.status === "applied"),
719
- rejected: fixes.filter((f) => f.status === "rejected")
720
- };
721
- if (byStatus.pending.length > 0) {
722
- output += `## \u23F3 Pending (${byStatus.pending.length})
723
-
724
- `;
725
- output += `| ID | File | Line | Issue | Confidence |
726
- `;
727
- output += `|----|------|------|-------|------------|
728
- `;
729
- for (const fix of byStatus.pending) {
730
- const conf = `${(fix.confidence * 100).toFixed(0)}%`;
731
- const shortFile = fix.file.split("/").slice(-2).join("/");
732
- output += `| ${fix.id} | ${shortFile} | ${fix.line} | ${fix.issue.slice(0, 40)}... | ${conf} |
733
- `;
734
- }
735
- output += "\n";
736
- }
737
- output += `### Commands
738
-
739
- `;
740
- output += `- Fix all high-confidence: \`trie_fix autoApprove:true\`
741
- `;
742
- output += `- Fix specific: \`trie_fix issueIds:["id1", "id2"]\`
743
- `;
744
- output += `- Preview: \`trie_fix dryRun:true\`
745
- `;
746
- return { content: [{ type: "text", text: output }] };
747
- }
748
- getHelpText() {
749
- return `
750
- ${"\u2501".repeat(60)}
751
- \u{1F527} TRIE FIX - AI-POWERED CODE FIXING
752
- ${"\u2501".repeat(60)}
753
-
754
- ## Usage
755
-
756
- ### Fix issues from a scan:
757
- \`\`\`
758
- trie_fix issueIds:["issue-1", "issue-2"]
759
- \`\`\`
760
-
761
- ### Auto-fix all high-confidence issues:
762
- \`\`\`
763
- trie_fix autoApprove:true
764
- \`\`\`
765
-
766
- ### Fix specific file and line:
767
- \`\`\`
768
- trie_fix file:"src/app.ts" line:42 issue:"SQL injection" fix:"Use parameterized query"
769
- \`\`\`
770
-
771
- ### Preview fixes without applying:
772
- \`\`\`
773
- trie_fix dryRun:true
774
- \`\`\`
775
-
776
- ### View pending fixes:
777
- \`\`\`
778
- trie_fix
779
- \`\`\`
780
-
781
- ## Workflow
782
-
783
- 1. Run \`trie_scan\` to detect issues
784
- 2. Review the issues found
785
- 3. Run \`trie_fix\` to apply fixes
786
-
787
- The AI will analyze each issue, generate the fix, and you can review before applying.
788
- `;
789
- }
790
- async appendCloudRecommendation(handledIds) {
791
- try {
792
- const pending = getPendingFixes();
793
- const remaining = pending.filter((p) => !handledIds.includes(p.id) || pendingFixes.get(p.id)?.status === "pending");
794
- if (remaining.length === 0) return "";
795
- const issues = remaining.map((p) => ({
796
- id: p.id,
797
- severity: "moderate",
798
- issue: p.issue,
799
- fix: p.suggestedFix,
800
- file: p.file,
801
- line: p.line,
802
- confidence: p.confidence,
803
- autoFixable: false,
804
- agent: "trie_scan"
805
- }));
806
- const workDir = getWorkingDirectory(void 0, true);
807
- const config = await loadAutonomyConfig(workDir);
808
- const { results } = triageIssues(issues, void 0, void 0, config);
809
- const footer = formatCloudRecommendation(results, issues);
810
- return footer ? `
811
- ${footer}
812
- ` : "";
813
- } catch {
814
- return "";
815
- }
816
- }
817
- detectLanguage(filePath) {
818
- const ext = extname(filePath).toLowerCase();
819
- const langMap = {
820
- ".ts": "typescript",
821
- ".tsx": "tsx",
822
- ".js": "javascript",
823
- ".jsx": "jsx",
824
- ".py": "python",
825
- ".go": "go",
826
- ".rs": "rust"
827
- };
828
- return langMap[ext] || "plaintext";
829
- }
830
- };
831
- function getPendingFixes() {
832
- return Array.from(pendingFixes.values());
833
- }
834
- async function loadPendingFixesFromMemory() {
835
- try {
836
- const { getRecentIssues: getRecentIssues2 } = await import("./issue-store-LZWZIGM7.js");
837
- pendingFixes.clear();
838
- const recentIssues = await getRecentIssues2({ limit: 50, includeResolved: false });
839
- for (const storedIssue of recentIssues) {
840
- const fix = {
841
- id: storedIssue.id,
842
- file: storedIssue.file,
843
- line: storedIssue.line || 0,
844
- issue: storedIssue.issue,
845
- suggestedFix: storedIssue.fix,
846
- confidence: 0.8,
847
- // Default confidence for memory issues
848
- status: "pending",
849
- severity: storedIssue.severity,
850
- autoFixable: true,
851
- // Memory issues are generally auto-fixable
852
- category: storedIssue.category
853
- };
854
- pendingFixes.set(fix.id, fix);
855
- }
856
- } catch (error) {
857
- console.warn("Failed to load pending fixes from memory:", error);
858
- }
859
- }
860
-
861
- // src/tools/cloud-fix.ts
862
- import { readFile as readFile2, writeFile, mkdir } from "fs/promises";
863
- import { existsSync as existsSync2 } from "fs";
864
- import { join } from "path";
865
- import { execSync } from "child_process";
866
-
867
- // src/integrations/cursor-cloud-agent.ts
868
- var BASE_URL = "https://api.cursor.com/v1";
869
- var CursorCloudAgentClient = class {
870
- apiKey;
871
- constructor(apiKey) {
872
- this.apiKey = apiKey;
873
- }
874
- /**
875
- * Dispatch an issue to a cloud agent for fixing.
876
- */
877
- async dispatch(issue, triageResult, repoUrl, branch) {
878
- const prompt = this.buildPrompt(issue, triageResult);
879
- const body = {
880
- prompt,
881
- repo: repoUrl,
882
- branch,
883
- metadata: {
884
- issueId: issue.id,
885
- file: issue.file,
886
- line: issue.line,
887
- severity: issue.severity,
888
- agent: issue.agent
889
- }
890
- };
891
- const res = await this.request("POST", "/agents/tasks", body);
892
- return {
893
- jobId: res.id ?? res.taskId ?? res.jobId,
894
- status: "dispatched",
895
- artifactUrls: [],
896
- dispatchedAt: (/* @__PURE__ */ new Date()).toISOString()
897
- };
898
- }
899
- /**
900
- * Poll job status.
901
- */
902
- async poll(jobId) {
903
- const res = await this.request("GET", `/agents/tasks/${jobId}`);
904
- const status = mapStatus(res.status);
905
- const prUrl = extractPrUrl(res);
906
- const artifactUrls = this.extractArtifacts(res);
907
- return { status, prUrl, artifactUrls };
908
- }
909
- /**
910
- * Get artifact URLs for a completed job.
911
- */
912
- async getArtifacts(jobId) {
913
- const res = await this.request("GET", `/agents/tasks/${jobId}`);
914
- return this.extractArtifacts(res);
915
- }
916
- /**
917
- * Cancel a running job.
918
- */
919
- async cancelJob(jobId) {
920
- await this.request("DELETE", `/agents/tasks/${jobId}`);
921
- }
922
- // --------------------------------------------------------------------------
923
- // Internal
924
- // --------------------------------------------------------------------------
925
- buildPrompt(issue, triageResult) {
926
- const parts = [
927
- "You are fixing a verified issue in the codebase.",
928
- "",
929
- `Issue: ${issue.issue}`,
930
- `File: ${issue.file}${issue.line ? `:${issue.line}` : ""}`,
931
- `Severity: ${issue.severity} | Effort: ${issue.effort ?? "medium"}`,
932
- `Agent that found it: ${issue.agent}`,
933
- `Suggested fix: ${issue.fix}`
934
- ];
935
- if (issue.cwe) parts.push(`CWE: ${issue.cwe}`);
936
- if (issue.owasp) parts.push(`OWASP: ${issue.owasp}`);
937
- parts.push(`Triage confidence: ${triageResult.confidence.toFixed(2)}`);
938
- parts.push(`Why cloud agent: ${triageResult.reasons.join(", ")}`);
939
- parts.push("");
940
- parts.push("Steps:");
941
- parts.push(`1. Apply the minimal fix described above to ${issue.file}`);
942
- parts.push("2. Run the existing test suite (detect test runner from package.json scripts)");
943
- parts.push("3. Screenshot the passing test output \u2014 this is the verification artifact");
944
- parts.push("4. If tests fail, iterate on the fix until they pass (max 3 attempts)");
945
- parts.push("5. Open a PR with only this single change \u2014 do not bundle other fixes");
946
- parts.push("6. Include the screenshot in the PR description as evidence");
947
- return parts.join("\n");
948
- }
949
- async request(method, path2, body) {
950
- const url = `${BASE_URL}${path2}`;
951
- const headers = {
952
- "Authorization": `Bearer ${this.apiKey}`,
953
- "Content-Type": "application/json"
954
- };
955
- const init = { method, headers };
956
- if (body) init.body = JSON.stringify(body);
957
- const res = await fetch(url, init);
958
- if (res.status === 401) {
959
- throw new Error(
960
- 'Cursor API key is invalid or expired.\nUpdate it: trie_cloud_fix action:configure apiKey:"key-..."'
961
- );
962
- }
963
- if (res.status === 404) {
964
- throw new Error(`Job not found: ${path2}`);
965
- }
966
- if (res.status >= 500) {
967
- throw new Error(
968
- `Cursor API returned ${res.status}. The service may be temporarily unavailable \u2014 retry in a few minutes.`
969
- );
970
- }
971
- if (!res.ok) {
972
- const text = await res.text().catch(() => "");
973
- throw new Error(`Cursor API error ${res.status}: ${text}`);
974
- }
975
- return res.json();
976
- }
977
- extractArtifacts(res) {
978
- const urls = [];
979
- if (Array.isArray(res.messages)) {
980
- for (const msg of res.messages) {
981
- if (typeof msg.content === "string") {
982
- const matches = msg.content.match(/https:\/\/[^\s)]+\.(png|jpg|mp4|webm)/g);
983
- if (matches) urls.push(...matches);
984
- }
985
- }
986
- }
987
- if (Array.isArray(res.artifacts)) {
988
- for (const a of res.artifacts) {
989
- if (a.url) urls.push(a.url);
990
- }
991
- }
992
- return [...new Set(urls)];
993
- }
994
- };
995
- function mapStatus(raw) {
996
- switch (raw) {
997
- case "pending":
998
- case "queued":
999
- return "pending";
1000
- case "running":
1001
- case "in_progress":
1002
- return "running";
1003
- case "completed":
1004
- case "succeeded":
1005
- case "verified":
1006
- return "completed";
1007
- default:
1008
- return "failed";
1009
- }
1010
- }
1011
- function extractPrUrl(res) {
1012
- if (typeof res.prUrl === "string") return res.prUrl;
1013
- if (typeof res.pr_url === "string") return res.pr_url;
1014
- if (typeof res.pullRequestUrl === "string") return res.pullRequestUrl;
1015
- if (Array.isArray(res.messages)) {
1016
- for (const msg of res.messages) {
1017
- if (typeof msg.content === "string") {
1018
- const match = msg.content.match(/https:\/\/github\.com\/[^\s)]+\/pull\/\d+/);
1019
- if (match) return match[0];
1020
- }
1021
- }
1022
- }
1023
- return void 0;
1024
- }
1025
-
1026
- // src/tools/cloud-fix.ts
1027
- var TrieCloudFixTool = class {
1028
- async execute(args) {
1029
- const { action = "status" } = args || {};
1030
- switch (action) {
1031
- case "configure":
1032
- return this.configure(args);
1033
- case "dispatch":
1034
- return this.dispatch(args);
1035
- case "status":
1036
- return this.status();
1037
- case "artifacts":
1038
- return this.artifacts(args);
1039
- case "cancel":
1040
- return this.cancel(args);
1041
- default:
1042
- return this.text(`Unknown action "${action}". Use: configure | dispatch | status | artifacts | cancel`);
1043
- }
1044
- }
1045
- // --------------------------------------------------------------------------
1046
- // configure
1047
- // --------------------------------------------------------------------------
1048
- async configure(args) {
1049
- const apiKey = args?.apiKey || process.env.CURSOR_API_KEY;
1050
- if (!apiKey) {
1051
- return this.text(
1052
- 'Missing API key.\n\nUsage: trie_cloud_fix action:configure apiKey:"key-..."\nOr set: export CURSOR_API_KEY="key-..."'
1053
- );
1054
- }
1055
- const workDir = getWorkingDirectory(void 0, true);
1056
- await saveAutonomyConfig(workDir, { cloudAgentEnabled: true, cursorApiKey: apiKey });
1057
- return this.text("Cursor API key saved. Cloud agent dispatch enabled.");
1058
- }
1059
- // --------------------------------------------------------------------------
1060
- // dispatch
1061
- // --------------------------------------------------------------------------
1062
- async dispatch(args) {
1063
- console.log("Cloud dispatch starting...");
1064
- const workDir = getWorkingDirectory(void 0, true);
1065
- const apiKey = await this.resolveApiKey(workDir);
1066
- if (!apiKey) return this.setupGuard();
1067
- const config = await loadAutonomyConfig(workDir);
1068
- console.log("About to resolve issues...");
1069
- const allIssues = await this.resolveIssues(args?.issueIds);
1070
- console.log(`Resolved ${allIssues.length} issues`);
1071
- if (allIssues.length === 0) {
1072
- return this.text("No issues to dispatch. Run trie_scan to detect new issues, or check memory with trie_memory action:recent.");
1073
- }
1074
- const { results, summary } = triageIssues(allIssues, void 0, void 0, config);
1075
- const lines = [];
1076
- lines.push(formatTriageTable(results, allIssues));
1077
- lines.push("");
1078
- for (const issue of allIssues) {
1079
- const r = results.get(issue.id);
1080
- if (r && r.strategy !== "cloud-agent") {
1081
- lines.push(`Skipped ${issue.id}: routed to ${r.strategy} (score ${r.score >= 0 ? "+" : ""}${r.score} \u2014 ${r.reasons.join(", ")})`);
1082
- }
1083
- }
1084
- if (summary.cloudAgent.length === 0) {
1085
- lines.push("\nNo issues qualify for cloud dispatch. Use trie_fix for local fixes.");
1086
- return this.text(lines.join("\n"));
1087
- }
1088
- const client = new CursorCloudAgentClient(apiKey);
1089
- const repoUrl = this.getRepoUrl(workDir);
1090
- const branch = this.getBranch(workDir);
1091
- const store = await this.loadJobs(workDir);
1092
- lines.push("\nDISPATCHED");
1093
- for (const issue of summary.cloudAgent) {
1094
- const triageResult = results.get(issue.id);
1095
- try {
1096
- const job = await client.dispatch(issue, triageResult, repoUrl, branch);
1097
- store.jobs[issue.id] = {
1098
- issueId: issue.id,
1099
- jobId: job.jobId,
1100
- status: "dispatched",
1101
- score: triageResult.score,
1102
- strategy: "cloud-agent",
1103
- dispatchedAt: job.dispatchedAt,
1104
- artifactUrls: [],
1105
- prUrl: null
1106
- };
1107
- lines.push(` ${issue.id} ${shortPath2(issue.file)}:${issue.line ?? "?"} job:${job.jobId} (score +${triageResult.score})`);
1108
- } catch (err) {
1109
- lines.push(` ${issue.id} FAILED: ${err.message}`);
1110
- }
1111
- }
1112
- await this.saveJobs(workDir, store);
1113
- lines.push("");
1114
- lines.push("Cloud agents are running in isolated VMs. Check back with:");
1115
- lines.push("trie_cloud_fix action:status");
1116
- return this.text(lines.join("\n"));
1117
- }
1118
- // --------------------------------------------------------------------------
1119
- // status
1120
- // --------------------------------------------------------------------------
1121
- async status() {
1122
- const workDir = getWorkingDirectory(void 0, true);
1123
- const apiKey = await this.resolveApiKey(workDir);
1124
- if (!apiKey) return this.setupGuard();
1125
- const store = await this.loadJobs(workDir);
1126
- const entries = Object.values(store.jobs);
1127
- if (entries.length === 0) {
1128
- return this.text("No cloud jobs. Dispatch with: trie_cloud_fix action:dispatch");
1129
- }
1130
- const client = new CursorCloudAgentClient(apiKey);
1131
- const LINE = "\u2500".repeat(68);
1132
- const lines = ["JOB STATUS", LINE];
1133
- lines.push(padEnd2("Issue", 32) + padEnd2("Status", 12) + padEnd2("PR", 28) + "Age");
1134
- for (const job of entries) {
1135
- if (job.status === "dispatched" || job.status === "running") {
1136
- try {
1137
- const poll = await client.poll(job.jobId);
1138
- if (poll.status === "completed" && poll.prUrl) {
1139
- job.status = "verified";
1140
- job.prUrl = poll.prUrl;
1141
- } else if (poll.status === "running") {
1142
- job.status = "running";
1143
- } else if (poll.status === "failed") {
1144
- job.status = "failed";
1145
- }
1146
- if (poll.artifactUrls.length) {
1147
- job.artifactUrls = poll.artifactUrls;
1148
- }
1149
- } catch {
1150
- }
1151
- }
1152
- const age = formatAge(job.dispatchedAt);
1153
- const pr = job.prUrl ?? "\u2014";
1154
- lines.push(padEnd2(job.issueId, 32) + padEnd2(job.status, 12) + padEnd2(pr, 28) + age);
1155
- }
1156
- lines.push(LINE);
1157
- await this.saveJobs(workDir, store);
1158
- return this.text(lines.join("\n"));
1159
- }
1160
- // --------------------------------------------------------------------------
1161
- // artifacts
1162
- // --------------------------------------------------------------------------
1163
- async artifacts(args) {
1164
- const workDir = getWorkingDirectory(void 0, true);
1165
- const apiKey = await this.resolveApiKey(workDir);
1166
- if (!apiKey) return this.setupGuard();
1167
- const store = await this.loadJobs(workDir);
1168
- const jobId = args?.jobId;
1169
- const targets = jobId ? Object.values(store.jobs).filter((j) => j.jobId === jobId) : Object.values(store.jobs).filter((j) => j.status === "verified");
1170
- if (targets.length === 0) {
1171
- return this.text(jobId ? `No job found with id ${jobId}` : "No completed jobs with artifacts.");
1172
- }
1173
- const client = new CursorCloudAgentClient(apiKey);
1174
- const lines = [];
1175
- for (const job of targets) {
1176
- try {
1177
- const artifacts = await client.getArtifacts(job.jobId);
1178
- job.artifactUrls = artifacts;
1179
- } catch {
1180
- }
1181
- lines.push(`Issue: ${job.issueId}`);
1182
- lines.push(`PR: ${job.prUrl ?? "N/A"}`);
1183
- for (const url of job.artifactUrls) {
1184
- const ext = url.split(".").pop();
1185
- const label = ext === "mp4" || ext === "webm" ? "Video" : "Screenshot";
1186
- lines.push(`${label}: ${url}`);
1187
- }
1188
- if (job.status === "verified") {
1189
- lines.push("Agent verified: all tests pass with this fix applied.");
1190
- }
1191
- lines.push("");
1192
- }
1193
- await this.saveJobs(workDir, store);
1194
- return this.text(lines.join("\n"));
1195
- }
1196
- // --------------------------------------------------------------------------
1197
- // cancel
1198
- // --------------------------------------------------------------------------
1199
- async cancel(args) {
1200
- const workDir = getWorkingDirectory(void 0, true);
1201
- const apiKey = await this.resolveApiKey(workDir);
1202
- if (!apiKey) return this.setupGuard();
1203
- const jobId = args?.jobId;
1204
- if (!jobId) {
1205
- return this.text('Provide jobId to cancel. Example: trie_cloud_fix action:cancel jobId:"cursor-task-xyz"');
1206
- }
1207
- const store = await this.loadJobs(workDir);
1208
- const entry = Object.values(store.jobs).find((j) => j.jobId === jobId);
1209
- if (!entry) {
1210
- return this.text(`Job ${jobId} not found in cloud-jobs.json.`);
1211
- }
1212
- const client = new CursorCloudAgentClient(apiKey);
1213
- try {
1214
- await client.cancelJob(jobId);
1215
- } catch (err) {
1216
- return this.text(`Cancel failed: ${err.message}`);
1217
- }
1218
- delete store.jobs[entry.issueId];
1219
- await this.saveJobs(workDir, store);
1220
- return this.text(`Job ${jobId} cancelled and removed.`);
1221
- }
1222
- // --------------------------------------------------------------------------
1223
- // Helpers
1224
- // --------------------------------------------------------------------------
1225
- async resolveApiKey(workDir) {
1226
- if (process.env.CURSOR_API_KEY) return process.env.CURSOR_API_KEY;
1227
- const config = await loadAutonomyConfig(workDir);
1228
- return config.cursorApiKey ?? null;
1229
- }
1230
- setupGuard() {
1231
- return this.text(
1232
- 'Cloud Agent dispatch requires a Cursor API key.\n\nGet your key at: cursor.com/settings \u2192 API Keys\nThen run: trie_cloud_fix action:configure apiKey:"key-..."\n\nOr set the environment variable: export CURSOR_API_KEY="key-..."'
1233
- );
1234
- }
1235
- async resolveIssues(issueIds) {
1236
- let pending = getPendingFixes();
1237
- if (pending.length === 0) {
1238
- try {
1239
- console.log("Loading issues from memory...");
1240
- const { getRecentIssues: getRecentIssues2 } = await import("./issue-store-LZWZIGM7.js");
1241
- const recentIssues = await getRecentIssues2({ limit: 50, includeResolved: false });
1242
- console.log(`Found ${recentIssues.length} recent issues in memory`);
1243
- const memoryIssues = recentIssues.map((storedIssue) => ({
1244
- id: storedIssue.id,
1245
- severity: storedIssue.severity || "moderate",
1246
- issue: storedIssue.issue,
1247
- fix: storedIssue.fix,
1248
- file: storedIssue.file,
1249
- line: storedIssue.line,
1250
- confidence: 0.8,
1251
- // Default confidence for memory issues
1252
- autoFixable: true,
1253
- // Memory issues are generally auto-fixable
1254
- agent: storedIssue.agent,
1255
- category: storedIssue.category
1256
- }));
1257
- console.log(`Converted ${memoryIssues.length} memory issues for cloud dispatch`);
1258
- if (issueIds && issueIds.length > 0) {
1259
- return memoryIssues.filter((i) => issueIds.includes(i.id));
1260
- }
1261
- return memoryIssues;
1262
- } catch (error) {
1263
- console.warn("Failed to load issues from memory:", error);
1264
- console.warn("Error details:", error);
1265
- }
1266
- }
1267
- const issues = pending.map((p) => ({
1268
- id: p.id,
1269
- severity: p.severity ?? "moderate",
1270
- effort: p.effort,
1271
- issue: p.issue,
1272
- fix: p.suggestedFix,
1273
- file: p.file,
1274
- line: p.line,
1275
- confidence: p.confidence,
1276
- autoFixable: p.autoFixable ?? false,
1277
- agent: "trie_scan",
1278
- cwe: p.cwe,
1279
- owasp: p.owasp,
1280
- category: p.category
1281
- }));
1282
- if (issueIds && issueIds.length > 0) {
1283
- return issues.filter((i) => issueIds.includes(i.id));
1284
- }
1285
- return issues;
1286
- }
1287
- getRepoUrl(workDir) {
1288
- try {
1289
- return execSync("git remote get-url origin", { cwd: workDir, encoding: "utf-8" }).trim();
1290
- } catch {
1291
- return "unknown";
1292
- }
1293
- }
1294
- getBranch(workDir) {
1295
- try {
1296
- return execSync("git rev-parse --abbrev-ref HEAD", { cwd: workDir, encoding: "utf-8" }).trim();
1297
- } catch {
1298
- return "main";
1299
- }
1300
- }
1301
- async loadJobs(workDir) {
1302
- const path2 = join(getTrieDirectory(workDir), "cloud-jobs.json");
1303
- try {
1304
- if (existsSync2(path2)) {
1305
- const raw = await readFile2(path2, "utf-8");
1306
- return JSON.parse(raw);
1307
- }
1308
- } catch {
1309
- }
1310
- return { jobs: {} };
1311
- }
1312
- async saveJobs(workDir, store) {
1313
- const trieDir = getTrieDirectory(workDir);
1314
- if (!existsSync2(trieDir)) await mkdir(trieDir, { recursive: true });
1315
- const path2 = join(trieDir, "cloud-jobs.json");
1316
- await writeFile(path2, JSON.stringify(store, null, 2));
1317
- }
1318
- text(msg) {
1319
- return { content: [{ type: "text", text: msg }] };
1320
- }
1321
- };
1322
- function formatAge(isoDate) {
1323
- const ms = Date.now() - new Date(isoDate).getTime();
1324
- const mins = Math.floor(ms / 6e4);
1325
- if (mins < 60) return `${mins}m`;
1326
- const hrs = Math.floor(mins / 60);
1327
- if (hrs < 24) return `${hrs}h ${mins % 60}m`;
1328
- return `${Math.floor(hrs / 24)}d`;
1329
- }
1330
- function shortPath2(file) {
1331
- const parts = file.split("/");
1332
- return parts.length > 2 ? parts.slice(-2).join("/") : file;
1333
- }
1334
- function padEnd2(str, len) {
1335
- if (str.length >= len) return str.slice(0, len);
1336
- return str + " ".repeat(len - str.length);
1337
- }
1338
-
1339
- // src/tools/test.ts
1340
- import { readFile as readFile3 } from "fs/promises";
1341
- import { existsSync as existsSync3 } from "fs";
1342
- import { extname as extname2, relative as relative2, resolve as resolve2, isAbsolute as isAbsolute2, dirname, basename, join as join2 } from "path";
201
+ import { extname, relative, resolve, isAbsolute, dirname, basename, join } from "path";
1343
202
  var TrieTestTool = class {
1344
203
  async execute(args) {
1345
204
  const { action, files, framework, style = "unit" } = args || {};
@@ -1392,15 +251,15 @@ ${"\u2501".repeat(60)}
1392
251
  const workDir = getWorkingDirectory(void 0, true);
1393
252
  const allUnits = [];
1394
253
  for (const file of files) {
1395
- const resolvedPath = isAbsolute2(file) ? file : resolve2(workDir, file);
1396
- if (!existsSync3(resolvedPath)) {
254
+ const resolvedPath = isAbsolute(file) ? file : resolve(workDir, file);
255
+ if (!existsSync(resolvedPath)) {
1397
256
  output += `[!] File not found: ${file}
1398
257
  `;
1399
258
  continue;
1400
259
  }
1401
- const code = await readFile3(resolvedPath, "utf-8");
260
+ const code = await readFile(resolvedPath, "utf-8");
1402
261
  const language = this.detectLanguage(resolvedPath);
1403
- const relativePath = relative2(workDir, resolvedPath);
262
+ const relativePath = relative(workDir, resolvedPath);
1404
263
  const units = this.extractTestableUnits(code, language);
1405
264
  allUnits.push({ file: relativePath, units });
1406
265
  output += `### \u{1F4C4} ${relativePath}
@@ -1431,7 +290,7 @@ ${"\u2501".repeat(60)}
1431
290
  `;
1432
291
  for (const { file, units } of allUnits) {
1433
292
  if (units.length === 0) continue;
1434
- const code = await readFile3(resolve2(workDir, file), "utf-8");
293
+ const code = await readFile(resolve(workDir, file), "utf-8");
1435
294
  const language = this.detectLanguage(file);
1436
295
  const prompt = getPrompt("test", "generate", {
1437
296
  code,
@@ -1476,21 +335,21 @@ ${"\u2501".repeat(60)}
1476
335
  `;
1477
336
  const workDir = getWorkingDirectory(void 0, true);
1478
337
  for (const file of files) {
1479
- const resolvedPath = isAbsolute2(file) ? file : resolve2(workDir, file);
1480
- if (!existsSync3(resolvedPath)) {
338
+ const resolvedPath = isAbsolute(file) ? file : resolve(workDir, file);
339
+ if (!existsSync(resolvedPath)) {
1481
340
  output += `[!] File not found: ${file}
1482
341
  `;
1483
342
  continue;
1484
343
  }
1485
- const code = await readFile3(resolvedPath, "utf-8");
344
+ const code = await readFile(resolvedPath, "utf-8");
1486
345
  const language = this.detectLanguage(resolvedPath);
1487
- const relativePath = relative2(workDir, resolvedPath);
346
+ const relativePath = relative(workDir, resolvedPath);
1488
347
  const units = this.extractTestableUnits(code, language);
1489
348
  const testFile = await this.findTestFile(resolvedPath);
1490
349
  let testCode = "";
1491
350
  let testedUnits = [];
1492
351
  if (testFile) {
1493
- testCode = await readFile3(testFile, "utf-8");
352
+ testCode = await readFile(testFile, "utf-8");
1494
353
  testedUnits = this.findTestedUnits(testCode, units.map((u) => u.name));
1495
354
  }
1496
355
  const coverage = units.length > 0 ? Math.round(testedUnits.length / units.length * 100) : 0;
@@ -1501,7 +360,7 @@ ${"\u2501".repeat(60)}
1501
360
  output += `**Coverage:** ${coverageIcon} ${coverage}% (${testedUnits.length}/${units.length} units)
1502
361
  `;
1503
362
  if (testFile) {
1504
- output += `**Test file:** \`${relative2(workDir, testFile)}\`
363
+ output += `**Test file:** \`${relative(workDir, testFile)}\`
1505
364
  `;
1506
365
  } else {
1507
366
  output += `**Test file:** \u274C Not found
@@ -1558,14 +417,14 @@ ${"\u2501".repeat(60)}
1558
417
  `;
1559
418
  const workDir = getWorkingDirectory(void 0, true);
1560
419
  for (const file of files) {
1561
- const resolvedPath = isAbsolute2(file) ? file : resolve2(workDir, file);
1562
- if (!existsSync3(resolvedPath)) {
420
+ const resolvedPath = isAbsolute(file) ? file : resolve(workDir, file);
421
+ if (!existsSync(resolvedPath)) {
1563
422
  output += `[!] File not found: ${file}
1564
423
  `;
1565
424
  continue;
1566
425
  }
1567
- const code = await readFile3(resolvedPath, "utf-8");
1568
- const relativePath = relative2(workDir, resolvedPath);
426
+ const code = await readFile(resolvedPath, "utf-8");
427
+ const relativePath = relative(workDir, resolvedPath);
1569
428
  const patterns = this.detectTestablePatterns(code);
1570
429
  output += `### \u{1F4C4} ${relativePath}
1571
430
 
@@ -1801,8 +660,8 @@ ${"\u2501".repeat(60)}
1801
660
  }
1802
661
  async findTestFile(sourcePath) {
1803
662
  const dir = dirname(sourcePath);
1804
- const base = basename(sourcePath, extname2(sourcePath));
1805
- const ext = extname2(sourcePath);
663
+ const base = basename(sourcePath, extname(sourcePath));
664
+ const ext = extname(sourcePath);
1806
665
  const patterns = [
1807
666
  `${base}.test${ext}`,
1808
667
  `${base}.spec${ext}`,
@@ -1810,16 +669,16 @@ ${"\u2501".repeat(60)}
1810
669
  `test_${base}${ext}`
1811
670
  ];
1812
671
  for (const pattern of patterns) {
1813
- const testPath = join2(dir, pattern);
1814
- if (existsSync3(testPath)) {
672
+ const testPath = join(dir, pattern);
673
+ if (existsSync(testPath)) {
1815
674
  return testPath;
1816
675
  }
1817
676
  }
1818
- const testsDir = join2(dir, "__tests__");
1819
- if (existsSync3(testsDir)) {
677
+ const testsDir = join(dir, "__tests__");
678
+ if (existsSync(testsDir)) {
1820
679
  for (const pattern of patterns) {
1821
- const testPath = join2(testsDir, pattern);
1822
- if (existsSync3(testPath)) {
680
+ const testPath = join(testsDir, pattern);
681
+ if (existsSync(testPath)) {
1823
682
  return testPath;
1824
683
  }
1825
684
  }
@@ -1866,10 +725,10 @@ ${"\u2501".repeat(60)}
1866
725
  }
1867
726
  async detectTestFramework() {
1868
727
  const workDir = getWorkingDirectory(void 0, true);
1869
- const packagePath = resolve2(workDir, "package.json");
1870
- if (existsSync3(packagePath)) {
728
+ const packagePath = resolve(workDir, "package.json");
729
+ if (existsSync(packagePath)) {
1871
730
  try {
1872
- const pkg = JSON.parse(await readFile3(packagePath, "utf-8"));
731
+ const pkg = JSON.parse(await readFile(packagePath, "utf-8"));
1873
732
  const deps = { ...pkg.dependencies, ...pkg.devDependencies };
1874
733
  if (deps.vitest) return "vitest";
1875
734
  if (deps.jest) return "jest";
@@ -1877,13 +736,13 @@ ${"\u2501".repeat(60)}
1877
736
  } catch {
1878
737
  }
1879
738
  }
1880
- if (existsSync3(resolve2(workDir, "pytest.ini")) || existsSync3(resolve2(workDir, "pyproject.toml"))) {
739
+ if (existsSync(resolve(workDir, "pytest.ini")) || existsSync(resolve(workDir, "pyproject.toml"))) {
1881
740
  return "pytest";
1882
741
  }
1883
742
  return "jest";
1884
743
  }
1885
744
  detectLanguage(filePath) {
1886
- const ext = extname2(filePath).toLowerCase();
745
+ const ext = extname(filePath).toLowerCase();
1887
746
  const langMap = {
1888
747
  ".ts": "typescript",
1889
748
  ".tsx": "tsx",
@@ -1936,9 +795,9 @@ trie_test action:"run" files:["src/utils.test.ts"]
1936
795
  };
1937
796
 
1938
797
  // src/tools/watch.ts
1939
- import { watch, existsSync as existsSync4, readFileSync } from "fs";
1940
- import { stat, readFile as readFile4 } from "fs/promises";
1941
- import { join as join3, extname as extname3, basename as basename2 } from "path";
798
+ import { watch, existsSync as existsSync2, readFileSync } from "fs";
799
+ import { stat, readFile as readFile2 } from "fs/promises";
800
+ import { join as join2, extname as extname2, basename as basename2 } from "path";
1942
801
  import { createHash } from "crypto";
1943
802
  var WATCH_EXTENSIONS = /* @__PURE__ */ new Set([
1944
803
  ".ts",
@@ -2156,17 +1015,17 @@ Your Trie agent is now autonomously watching and learning from your codebase.
2156
1015
  return parts.some((p) => SKIP_DIRS.has(p) || p.startsWith(".") && p !== ".");
2157
1016
  }
2158
1017
  async watchDirectory(dir, debounceMs) {
2159
- if (!existsSync4(dir)) return;
1018
+ if (!existsSync2(dir)) return;
2160
1019
  try {
2161
1020
  const dirStat = await stat(dir);
2162
1021
  if (!dirStat.isDirectory()) return;
2163
1022
  const watcher = watch(dir, { persistent: true, recursive: true }, (_eventType, filename) => {
2164
1023
  if (!filename) return;
2165
1024
  if (this.shouldSkipPath(filename)) return;
2166
- const ext = extname3(filename).toLowerCase();
1025
+ const ext = extname2(filename).toLowerCase();
2167
1026
  if (!WATCH_EXTENSIONS.has(ext)) return;
2168
- const fullPath = join3(dir, filename);
2169
- if (!existsSync4(fullPath)) return;
1027
+ const fullPath = join2(dir, filename);
1028
+ if (!existsSync2(fullPath)) return;
2170
1029
  this.state.pendingFiles.add(fullPath);
2171
1030
  if (this.state.scanDebounceTimer) {
2172
1031
  clearTimeout(this.state.scanDebounceTimer);
@@ -2212,7 +1071,7 @@ Detected changes in ${files.length} file(s):`);
2212
1071
  const fileContents = await Promise.all(
2213
1072
  files.map(async (file) => {
2214
1073
  try {
2215
- const content = await readFile4(file, "utf-8");
1074
+ const content = await readFile2(file, "utf-8");
2216
1075
  return { file, content };
2217
1076
  } catch {
2218
1077
  return null;
@@ -2290,7 +1149,7 @@ ${f.content.slice(0, 1e3)}`
2290
1149
  }
2291
1150
  isQuiet() {
2292
1151
  const projectPath = this.watchedDirectory || getWorkingDirectory(void 0, true);
2293
- const quietPath = join3(getTrieDirectory(projectPath), "quiet.json");
1152
+ const quietPath = join2(getTrieDirectory(projectPath), "quiet.json");
2294
1153
  try {
2295
1154
  const raw = readFileSync(quietPath, "utf-8");
2296
1155
  const data = JSON.parse(raw);
@@ -2458,7 +1317,7 @@ ${f.content.slice(0, 1e3)}`
2458
1317
  if (lastClean && Date.now() - lastClean < this.cleanFileCooldownMs) {
2459
1318
  return 0;
2460
1319
  }
2461
- const fileNode = await graph.getNode("file", join3(projectPath, file));
1320
+ const fileNode = await graph.getNode("file", join2(projectPath, file));
2462
1321
  if (!fileNode) return score;
2463
1322
  const data = fileNode.data;
2464
1323
  const riskScores = { critical: 10, high: 6, medium: 2, low: 1 };
@@ -2546,7 +1405,7 @@ ${f.content.slice(0, 1e3)}`
2546
1405
  const fileContents = await Promise.all(
2547
1406
  filesToScan.map(async ({ file, relativePath }) => {
2548
1407
  try {
2549
- const content = await readFile4(file, "utf-8");
1408
+ const content = await readFile2(file, "utf-8");
2550
1409
  return { path: relativePath, content: content.slice(0, charLimit) };
2551
1410
  } catch {
2552
1411
  return null;
@@ -2711,7 +1570,7 @@ ${filesBlock}`,
2711
1570
  fixChangeId: null,
2712
1571
  reportedVia: "detected"
2713
1572
  });
2714
- const filePath = join3(projectPath, issue.file);
1573
+ const filePath = join2(projectPath, issue.file);
2715
1574
  const fileNode = await graph.getNode("file", filePath);
2716
1575
  if (fileNode) {
2717
1576
  await graph.addEdge(fileNode.id, incident.id, "affects");
@@ -2843,7 +1702,7 @@ ${filesBlock}`,
2843
1702
  const recentFiles = /* @__PURE__ */ new Set();
2844
1703
  const uncommittedFiles = await getGitChangedFiles(projectPath);
2845
1704
  if (uncommittedFiles) {
2846
- uncommittedFiles.forEach((f) => recentFiles.add(join3(projectPath, f)));
1705
+ uncommittedFiles.forEach((f) => recentFiles.add(join2(projectPath, f)));
2847
1706
  }
2848
1707
  const oneDayAgo = Date.now() - 24 * 60 * 60 * 1e3;
2849
1708
  const recentChanges = await getChangedFilesSinceTimestamp(projectPath, oneDayAgo);
@@ -2851,8 +1710,8 @@ ${filesBlock}`,
2851
1710
  recentChanges.forEach((f) => recentFiles.add(f));
2852
1711
  }
2853
1712
  const filesToCheck = Array.from(recentFiles).filter((file) => {
2854
- const ext = extname3(file).toLowerCase();
2855
- return WATCH_EXTENSIONS.has(ext) && existsSync4(file);
1713
+ const ext = extname2(file).toLowerCase();
1714
+ return WATCH_EXTENSIONS.has(ext) && existsSync2(file);
2856
1715
  });
2857
1716
  console.debug("[Initial Scan] Files discovered for initial scan:", {
2858
1717
  totalRecentFiles: recentFiles.size,
@@ -2874,7 +1733,7 @@ ${filesBlock}`,
2874
1733
  const fileContents = await Promise.all(
2875
1734
  filesToScan.map(async (file) => {
2876
1735
  try {
2877
- const content = await readFile4(file, "utf-8");
1736
+ const content = await readFile2(file, "utf-8");
2878
1737
  const relativePath = file.replace(projectPath + "/", "");
2879
1738
  return { path: relativePath, content: content.slice(0, maxCharsPerFile) };
2880
1739
  } catch {
@@ -3220,9 +2079,9 @@ To get a full report, run \`trie_scan\` on your codebase.`
3220
2079
  };
3221
2080
 
3222
2081
  // src/tools/pr-review.ts
3223
- import { readFile as readFile5 } from "fs/promises";
3224
- import { existsSync as existsSync5 } from "fs";
3225
- import { join as join4, basename as basename3, resolve as resolve3, isAbsolute as isAbsolute3 } from "path";
2082
+ import { readFile as readFile3 } from "fs/promises";
2083
+ import { existsSync as existsSync3 } from "fs";
2084
+ import { join as join3, basename as basename3, resolve as resolve2, isAbsolute as isAbsolute2 } from "path";
3226
2085
 
3227
2086
  // src/skills/built-in/super-reviewer.ts
3228
2087
  var CRITICAL_REVIEW_CHECKLIST = {
@@ -3335,8 +2194,8 @@ Usage:
3335
2194
  */
3336
2195
  async getPRInfo(pr, worktree) {
3337
2196
  if (worktree) {
3338
- const worktreePath = isAbsolute3(worktree) ? worktree : resolve3(getWorkingDirectory(void 0, true), worktree);
3339
- if (!existsSync5(worktreePath)) {
2197
+ const worktreePath = isAbsolute2(worktree) ? worktree : resolve2(getWorkingDirectory(void 0, true), worktree);
2198
+ if (!existsSync3(worktreePath)) {
3340
2199
  return { success: false, error: `Worktree not found: ${worktreePath}` };
3341
2200
  }
3342
2201
  return {
@@ -3469,8 +2328,8 @@ Usage:
3469
2328
  "rfcs"
3470
2329
  ];
3471
2330
  for (const docPath of designDocPaths) {
3472
- const fullPath = join4(cwd, docPath);
3473
- if (existsSync5(fullPath)) {
2331
+ const fullPath = join3(cwd, docPath);
2332
+ if (existsSync3(fullPath)) {
3474
2333
  }
3475
2334
  }
3476
2335
  return designDocs;
@@ -3483,9 +2342,9 @@ Usage:
3483
2342
  const cwd = getWorkingDirectory(void 0, true);
3484
2343
  await Promise.all(filePaths.map(async (filePath) => {
3485
2344
  try {
3486
- const fullPath = isAbsolute3(filePath) ? filePath : join4(cwd, filePath);
3487
- if (existsSync5(fullPath)) {
3488
- const content = await readFile5(fullPath, "utf-8");
2345
+ const fullPath = isAbsolute2(filePath) ? filePath : join3(cwd, filePath);
2346
+ if (existsSync3(fullPath)) {
2347
+ const content = await readFile3(fullPath, "utf-8");
3489
2348
  contents.set(filePath, content);
3490
2349
  }
3491
2350
  } catch {
@@ -5246,9 +4105,9 @@ var ToolRegistry = class {
5246
4105
  };
5247
4106
 
5248
4107
  // src/server/resource-manager.ts
5249
- import { readdir, readFile as readFile6 } from "fs/promises";
5250
- import { existsSync as existsSync6 } from "fs";
5251
- import { join as join5, dirname as dirname2 } from "path";
4108
+ import { readdir, readFile as readFile4 } from "fs/promises";
4109
+ import { existsSync as existsSync4 } from "fs";
4110
+ import { join as join4, dirname as dirname2 } from "path";
5252
4111
  import { fileURLToPath } from "url";
5253
4112
 
5254
4113
  // src/skills/installer.ts
@@ -5373,7 +4232,7 @@ var ResourceManager = class {
5373
4232
  }
5374
4233
  async getScanReportResources() {
5375
4234
  try {
5376
- const reportsDir = join5(getWorkingDirectory(void 0, true), "trie-reports");
4235
+ const reportsDir = join4(getWorkingDirectory(void 0, true), "trie-reports");
5377
4236
  const files = await readdir(reportsDir);
5378
4237
  const reportFiles = files.filter((f) => f.endsWith(".txt") || f.endsWith(".json"));
5379
4238
  return reportFiles.slice(0, 10).map((file) => ({
@@ -5473,10 +4332,10 @@ var ResourceManager = class {
5473
4332
  async getUIAppResource(uri, appId) {
5474
4333
  const currentFile = fileURLToPath(import.meta.url);
5475
4334
  const distDir = dirname2(dirname2(currentFile));
5476
- const uiDir = join5(distDir, "ui");
5477
- const htmlPath = join5(uiDir, `${appId}.html`);
4335
+ const uiDir = join4(distDir, "ui");
4336
+ const htmlPath = join4(uiDir, `${appId}.html`);
5478
4337
  try {
5479
- if (!existsSync6(htmlPath)) {
4338
+ if (!existsSync4(htmlPath)) {
5480
4339
  return {
5481
4340
  contents: [{
5482
4341
  uri,
@@ -5485,7 +4344,7 @@ var ResourceManager = class {
5485
4344
  }]
5486
4345
  };
5487
4346
  }
5488
- const content = await readFile6(htmlPath, "utf-8");
4347
+ const content = await readFile4(htmlPath, "utf-8");
5489
4348
  return {
5490
4349
  contents: [{
5491
4350
  uri,
@@ -5665,10 +4524,10 @@ var ResourceManager = class {
5665
4524
  } catch {
5666
4525
  }
5667
4526
  summary.push("---", "", "# Detailed Context", "");
5668
- const agentsMdPath = join5(getTrieDirectory(workDir), "AGENTS.md");
4527
+ const agentsMdPath = join4(getTrieDirectory(workDir), "AGENTS.md");
5669
4528
  try {
5670
- if (existsSync6(agentsMdPath)) {
5671
- const agentsContent = await readFile6(agentsMdPath, "utf-8");
4529
+ if (existsSync4(agentsMdPath)) {
4530
+ const agentsContent = await readFile4(agentsMdPath, "utf-8");
5672
4531
  summary.push(agentsContent);
5673
4532
  } else {
5674
4533
  const contextSummary = await getContextForAI();
@@ -5793,8 +4652,8 @@ This information is automatically available to Claude Code, Cursor, and other AI
5793
4652
  }
5794
4653
  async getCacheStatsResource(uri) {
5795
4654
  try {
5796
- const cachePath = join5(getTrieDirectory(getWorkingDirectory(void 0, true)), ".trie-cache.json");
5797
- const cacheContent = await readFile6(cachePath, "utf-8");
4655
+ const cachePath = join4(getTrieDirectory(getWorkingDirectory(void 0, true)), ".trie-cache.json");
4656
+ const cacheContent = await readFile4(cachePath, "utf-8");
5798
4657
  const cache = JSON.parse(cacheContent);
5799
4658
  const fileCount = Object.keys(cache.files || {}).length;
5800
4659
  const totalVulns = Object.values(cache.files || {}).reduce((acc, file) => {
@@ -5873,9 +4732,9 @@ This information is automatically available to Claude Code, Cursor, and other AI
5873
4732
  }
5874
4733
  async getScanReportResource(uri, parsedUri) {
5875
4734
  const fileName = parsedUri.replace("reports/", "");
5876
- const reportPath = join5(getWorkingDirectory(void 0, true), "trie-reports", fileName);
4735
+ const reportPath = join4(getWorkingDirectory(void 0, true), "trie-reports", fileName);
5877
4736
  try {
5878
- const content = await readFile6(reportPath, "utf-8");
4737
+ const content = await readFile4(reportPath, "utf-8");
5879
4738
  return {
5880
4739
  contents: [{
5881
4740
  uri,
@@ -6022,32 +4881,32 @@ async function findOpenPort() {
6022
4881
  return portChecks.find((port) => port !== null) || null;
6023
4882
  }
6024
4883
  async function checkPort(port) {
6025
- return new Promise((resolve4) => {
4884
+ return new Promise((resolve3) => {
6026
4885
  const testServer = createServer();
6027
4886
  let portInUse = false;
6028
4887
  testServer.once("error", (err) => {
6029
4888
  if (err.code === "EADDRINUSE") {
6030
4889
  portInUse = true;
6031
- testHttpPort(port).then(resolve4).catch(() => resolve4(false));
4890
+ testHttpPort(port).then(resolve3).catch(() => resolve3(false));
6032
4891
  } else {
6033
- resolve4(false);
4892
+ resolve3(false);
6034
4893
  }
6035
4894
  });
6036
4895
  testServer.once("listening", () => {
6037
4896
  testServer.close();
6038
- resolve4(false);
4897
+ resolve3(false);
6039
4898
  });
6040
4899
  setTimeout(() => {
6041
4900
  if (!portInUse) {
6042
4901
  testServer.close();
6043
- resolve4(false);
4902
+ resolve3(false);
6044
4903
  }
6045
4904
  }, 1e3);
6046
4905
  testServer.listen(port, "127.0.0.1");
6047
4906
  });
6048
4907
  }
6049
4908
  async function testHttpPort(port) {
6050
- return new Promise((resolve4) => {
4909
+ return new Promise((resolve3) => {
6051
4910
  const req = request({
6052
4911
  hostname: "localhost",
6053
4912
  port,
@@ -6055,18 +4914,18 @@ async function testHttpPort(port) {
6055
4914
  method: "GET",
6056
4915
  timeout: 2e3
6057
4916
  }, (res) => {
6058
- resolve4(res.statusCode !== void 0);
4917
+ resolve3(res.statusCode !== void 0);
6059
4918
  res.on("data", () => {
6060
4919
  });
6061
4920
  res.on("end", () => {
6062
4921
  });
6063
4922
  });
6064
4923
  req.on("error", () => {
6065
- resolve4(false);
4924
+ resolve3(false);
6066
4925
  });
6067
4926
  req.on("timeout", () => {
6068
4927
  req.destroy();
6069
- resolve4(false);
4928
+ resolve3(false);
6070
4929
  });
6071
4930
  req.end();
6072
4931
  });