@triedotdev/mcp 1.0.109 → 1.0.111

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
@@ -1,22 +1,14 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
- IncidentIndex,
4
- LearningEngine,
5
3
  LinearIngester,
6
4
  appendToSection,
7
5
  completeBootstrap,
8
- exportToJson,
9
- formatFriendlyError,
10
- getAutonomyConfig,
11
6
  getContextForAI,
12
- getLastCheckpoint,
13
7
  getProjectInfoStructured,
14
8
  getProjectSection,
15
9
  getProjectSections,
16
- importFromJson,
17
10
  initProjectInfo,
18
11
  initializeBootstrapFiles,
19
- listCheckpoints,
20
12
  loadBootstrapContext,
21
13
  loadConfig,
22
14
  loadContextState,
@@ -24,32 +16,44 @@ import {
24
16
  loadRules,
25
17
  loadTeamInfo,
26
18
  needsBootstrap,
27
- perceiveCurrentChanges,
28
19
  projectInfoExists,
29
- reasonAboutChangesHumanReadable,
30
- runShellCommandSync,
31
- saveCheckpoint,
32
- trackIssueOccurrence,
33
20
  updateProjectSection
34
- } from "./chunk-FLBK5ILJ.js";
21
+ } from "./chunk-TKMV7JKN.js";
35
22
  import {
23
+ ExtractionPipeline,
36
24
  InteractiveDashboard,
37
25
  StreamingManager,
26
+ TrieCheckTool,
27
+ TrieExplainTool,
28
+ TrieFeedbackTool,
29
+ TrieGetBlockersTool,
30
+ TrieGetDecisionsTool,
31
+ TrieGetRelatedDecisionsTool,
32
+ TrieQueryContextTool,
38
33
  TrieScanTool,
39
- getOutputManager
40
- } from "./chunk-G6EC4JNL.js";
41
- import "./chunk-SUHYYM2J.js";
34
+ TrieTellTool,
35
+ getOutputManager,
36
+ getPrompt,
37
+ getSystemPrompt,
38
+ handleCheckpointTool
39
+ } from "./chunk-HGEKZ2VS.js";
40
+ import "./chunk-SDS3UVFY.js";
42
41
  import {
43
- isTrieInitialized
44
- } from "./chunk-HIKONDDO.js";
42
+ exportToJson,
43
+ formatFriendlyError,
44
+ importFromJson,
45
+ isTrieInitialized,
46
+ runShellCommandSync
47
+ } from "./chunk-QYOACM2C.js";
45
48
  import {
46
49
  ContextGraph,
47
50
  findCrossProjectPatterns,
48
51
  getGlobalMemoryStats,
49
- getStorage,
52
+ isAIAvailable,
50
53
  listTrackedProjects,
54
+ runAIAnalysis,
51
55
  searchGlobalPatterns
52
- } from "./chunk-OTTR5JX4.js";
56
+ } from "./chunk-6QR6QZIX.js";
53
57
  import "./chunk-IXO4G4D3.js";
54
58
  import {
55
59
  getSkillRegistry
@@ -155,898 +159,6 @@ function detectAITool() {
155
159
  import { readFile } from "fs/promises";
156
160
  import { existsSync } from "fs";
157
161
  import { extname, relative, resolve, isAbsolute } from "path";
158
-
159
- // src/ai/prompts.ts
160
- var AGENT_PROMPTS = {
161
- security: {
162
- system: `You are a senior security engineer performing a security audit.
163
- Analyze the code for vulnerabilities with the mindset of a penetration tester.
164
-
165
- Focus on:
166
- - OWASP Top 10 vulnerabilities (Injection, Broken Auth, XSS, etc.)
167
- - Authentication and authorization flaws
168
- - Cryptographic weaknesses
169
- - Secrets and credential exposure
170
- - Input validation gaps
171
- - Session management issues
172
- - API security (rate limiting, authentication)
173
-
174
- Reference the latest security best practices and CVEs when relevant.`,
175
- analysis: `## Security Audit Request
176
-
177
- Analyze this code for security vulnerabilities:
178
-
179
- \`\`\`{{language}}
180
- {{code}}
181
- \`\`\`
182
-
183
- **File:** {{filePath}}
184
- **Context:** {{context}}
185
-
186
- For each vulnerability found:
187
- 1. Severity (Critical/Serious/Moderate/Low)
188
- 2. Vulnerability type (e.g., CWE-89 SQL Injection)
189
- 3. Exact location (line number)
190
- 4. Attack vector explanation
191
- 5. Proof of concept (how it could be exploited)
192
- 6. Remediation with code example
193
-
194
- If you need to check current CVE databases or security advisories, say so.`,
195
- fix: `Fix this security vulnerability:
196
-
197
- **Issue:** {{issue}}
198
- **File:** {{filePath}}
199
- **Line:** {{line}}
200
- **Current Code:**
201
- \`\`\`{{language}}
202
- {{code}}
203
- \`\`\`
204
-
205
- Provide:
206
- 1. The exact code fix (ready to apply)
207
- 2. Explanation of why this fix works
208
- 3. Any additional hardening recommendations`
209
- },
210
- legal: {
211
- system: `You are a tech-focused legal compliance analyst.
212
- Review code for legal and regulatory compliance issues.
213
-
214
- Focus areas:
215
- - Data protection laws (GDPR, CCPA, etc.)
216
- - Terms of service enforcement
217
- - Cookie/tracking consent (ePrivacy)
218
- - Accessibility requirements (ADA, WCAG)
219
- - Export controls and sanctions
220
- - Licensing compliance`,
221
- analysis: `## Legal Compliance Review
222
-
223
- Review this code for legal/regulatory compliance:
224
-
225
- \`\`\`{{language}}
226
- {{code}}
227
- \`\`\`
228
-
229
- **File:** {{filePath}}
230
- **Jurisdiction Context:** {{jurisdiction}}
231
-
232
- Identify:
233
- 1. Legal requirement at risk
234
- 2. Specific regulation/law reference
235
- 3. Compliance gap description
236
- 4. Risk assessment (litigation, fines, etc.)
237
- 5. Remediation recommendations
238
- 6. Required documentation/policies`
239
- },
240
- "design-engineer": {
241
- system: `You are an elite design engineer \u2014 the kind who builds award-winning interfaces featured on Awwwards and Codrops.
242
-
243
- You think in design systems, breathe motion design, and obsess over the details that make interfaces feel magical.
244
-
245
- Your expertise:
246
- - **Design Systems**: Spacing scales, type scales, color tokens, radius tokens, shadow tokens
247
- - **Motion Design**: Micro-interactions, page transitions, scroll-triggered animations, FLIP technique
248
- - **Creative CSS**: Gradients, blend modes, clip-paths, masks, backdrop-filter, mix-blend-mode
249
- - **Modern CSS**: Container queries, :has(), subgrid, anchor positioning, cascade layers, @scope
250
- - **Fluid Design**: clamp(), min(), max(), fluid typography, intrinsic sizing
251
- - **Performance**: GPU-accelerated animations, will-change strategy, avoiding layout thrashing
252
- - **Visual Polish**: Layered shadows, subtle gradients, glass effects, smooth easing curves
253
-
254
- You review code with the eye of someone who's shipped Stripe-level interfaces.
255
- Small details matter: the easing curve, the stagger timing, the shadow layering.`,
256
- analysis: `## Design Engineering Review
257
-
258
- Analyze this frontend code for Awwwards-level craft:
259
-
260
- \`\`\`{{language}}
261
- {{code}}
262
- \`\`\`
263
-
264
- **File:** {{filePath}}
265
-
266
- Review for:
267
-
268
- ### 1. Design System Consistency
269
- - Are spacing values on a scale (4, 8, 12, 16, 24, 32...)?
270
- - Are colors defined as tokens?
271
- - Is typography systematic?
272
- - Are radii consistent?
273
- - Is z-index controlled?
274
-
275
- ### 2. Motion Design
276
- - Are transitions using custom easing (cubic-bezier)?
277
- - Are durations appropriate (150-300ms for micro, 300-500ms for page)?
278
- - Are list items staggered?
279
- - Is there reduced-motion support?
280
- - Are entrance animations choreographed?
281
-
282
- ### 3. Visual Craft
283
- - Are shadows layered for depth?
284
- - Are gradients subtle and purposeful?
285
- - Is there backdrop-blur on overlays?
286
- - Are hover states polished?
287
- - Is there visual hierarchy?
288
-
289
- ### 4. Modern CSS Opportunities
290
- - Could container queries improve component isolation?
291
- - Could clamp() create fluid spacing?
292
- - Could :has() simplify parent styling?
293
- - Could aspect-ratio replace padding hacks?
294
-
295
- ### 5. Performance
296
- - Are expensive properties (width, height, top, left) being animated?
297
- - Is will-change used appropriately (not statically)?
298
- - Are large blurs avoided in animations?
299
-
300
- For each issue, provide:
301
- - What's wrong (with specific line if applicable)
302
- - Why it matters for premium feel
303
- - Exact code to fix it
304
- - Before/after comparison`
305
- },
306
- accessibility: {
307
- system: `You are an accessibility expert and WCAG 2.1 specialist.
308
- Audit code for accessibility compliance and inclusive design.
309
-
310
- Standards to enforce:
311
- - WCAG 2.1 Level AA (minimum)
312
- - WCAG 2.1 Level AAA (recommended)
313
- - Section 508
314
- - EN 301 549
315
-
316
- Check for:
317
- - Missing ARIA labels
318
- - Color contrast issues
319
- - Keyboard navigation
320
- - Screen reader compatibility
321
- - Focus management
322
- - Form accessibility
323
- - Media alternatives`,
324
- analysis: `## Accessibility Audit (WCAG 2.1)
325
-
326
- Audit this UI code for accessibility:
327
-
328
- \`\`\`{{language}}
329
- {{code}}
330
- \`\`\`
331
-
332
- **File:** {{filePath}}
333
- **Component Type:** {{componentType}}
334
-
335
- For each issue:
336
- 1. WCAG Success Criterion violated (e.g., 1.4.3 Contrast)
337
- 2. Level (A, AA, AAA)
338
- 3. Impact on users (which disabilities affected)
339
- 4. Fix with code example
340
- 5. Testing recommendation`
341
- },
342
- architecture: {
343
- system: `You are a principal software architect reviewing code quality.
344
- Analyze for architectural issues, design patterns, and scalability concerns.
345
-
346
- Evaluate:
347
- - SOLID principles adherence
348
- - Design pattern usage (and misuse)
349
- - Code coupling and cohesion
350
- - N+1 queries and performance anti-patterns
351
- - Scalability bottlenecks
352
- - Error handling strategy
353
- - API design quality
354
- - Database schema issues`,
355
- analysis: `## Architecture Review
356
-
357
- Review this code for architectural issues:
358
-
359
- \`\`\`{{language}}
360
- {{code}}
361
- \`\`\`
362
-
363
- **File:** {{filePath}}
364
- **Project Context:** {{projectContext}}
365
-
366
- Analyze:
367
- 1. SOLID principle violations
368
- 2. Design pattern opportunities/issues
369
- 3. Coupling/cohesion assessment
370
- 4. Performance concerns (N+1, etc.)
371
- 5. Scalability analysis
372
- 6. Refactoring recommendations with examples`
373
- },
374
- bugs: {
375
- system: `You are a senior developer with expertise in finding subtle bugs.
376
- Hunt for bugs with the mindset of QA trying to break the code.
377
-
378
- Look for:
379
- - Null/undefined reference errors
380
- - Race conditions and async bugs
381
- - Off-by-one errors
382
- - Resource leaks
383
- - State management bugs
384
- - Edge cases and boundary conditions
385
- - Type coercion issues
386
- - Memory leaks`,
387
- analysis: `## Bug Hunt Analysis
388
-
389
- Find bugs and potential runtime errors:
390
-
391
- \`\`\`{{language}}
392
- {{code}}
393
- \`\`\`
394
-
395
- **File:** {{filePath}}
396
- **Runtime Context:** {{runtimeContext}}
397
-
398
- For each bug:
399
- 1. Bug type and category
400
- 2. Trigger conditions (when it would crash)
401
- 3. Reproduction steps
402
- 4. Impact assessment
403
- 5. Fix with code example
404
- 6. Test case to prevent regression`
405
- },
406
- ux: {
407
- system: `You are a UX researcher simulating different user personas.
408
- Test code from multiple user perspectives to find usability issues.
409
-
410
- Personas to simulate:
411
- 1. Happy Path User - Normal expected usage
412
- 2. Security Tester - Trying to break/exploit things
413
- 3. Confused User - First-time, doesn't read instructions
414
- 4. Impatient User - Clicks rapidly, skips loading states
415
- 5. Edge Case User - Uses maximum values, special characters
416
- 6. Accessibility User - Screen reader, keyboard only
417
- 7. Mobile User - Touch interface, slow connection`,
418
- analysis: `## User Experience Testing
419
-
420
- Test this code from multiple user perspectives:
421
-
422
- \`\`\`{{language}}
423
- {{code}}
424
- \`\`\`
425
-
426
- **File:** {{filePath}}
427
- **UI Type:** {{uiType}}
428
-
429
- For each persona, identify:
430
- 1. User action they would take
431
- 2. Expected behavior vs actual behavior
432
- 3. Friction points or confusion
433
- 4. Error scenario and how it's handled
434
- 5. Improvement recommendation`
435
- },
436
- types: {
437
- system: `You are a TypeScript expert focused on type safety.
438
- Analyze code for type issues, missing types, and type system best practices.
439
-
440
- Check for:
441
- - Missing type annotations
442
- - Implicit any types
443
- - Unsafe type assertions
444
- - Null/undefined handling
445
- - Generic type usage
446
- - Type narrowing opportunities
447
- - Strict mode violations`,
448
- analysis: `## Type Safety Analysis
449
-
450
- Analyze this code for type issues:
451
-
452
- \`\`\`{{language}}
453
- {{code}}
454
- \`\`\`
455
-
456
- **File:** {{filePath}}
457
- **TypeScript Config:** {{tsConfig}}
458
-
459
- Identify:
460
- 1. Type safety issues
461
- 2. Missing type annotations
462
- 3. Unsafe operations
463
- 4. Improvement recommendations with types`
464
- },
465
- devops: {
466
- system: `You are a DevOps/SRE engineer reviewing code for operational concerns.
467
- Focus on production readiness and operational excellence.
468
-
469
- Check for:
470
- - Environment variable handling
471
- - Configuration management
472
- - Logging and monitoring
473
- - Error handling and recovery
474
- - Health checks
475
- - Graceful shutdown
476
- - Resource cleanup
477
- - Secrets management
478
- - Docker/K8s patterns`,
479
- analysis: `## DevOps Readiness Review
480
-
481
- Review this code for operational concerns:
482
-
483
- \`\`\`{{language}}
484
- {{code}}
485
- \`\`\`
486
-
487
- **File:** {{filePath}}
488
- **Deployment Context:** {{deploymentContext}}
489
-
490
- Analyze:
491
- 1. Environment/config issues
492
- 2. Logging adequacy
493
- 3. Error handling quality
494
- 4. Health/readiness concerns
495
- 5. Resource management
496
- 6. Production hardening recommendations`
497
- },
498
- explain: {
499
- system: `You are a patient senior developer explaining code to a colleague.
500
- Break down complex code into understandable explanations.`,
501
- code: `## Code Explanation Request
502
-
503
- Explain this code in plain language:
504
-
505
- \`\`\`{{language}}
506
- {{code}}
507
- \`\`\`
508
-
509
- **File:** {{filePath}}
510
-
511
- Provide:
512
- 1. High-level purpose (what does this do?)
513
- 2. Step-by-step breakdown
514
- 3. Key concepts used
515
- 4. Dependencies and side effects
516
- 5. Potential gotchas or tricky parts`,
517
- issue: `## Issue Explanation
518
-
519
- Explain this issue:
520
-
521
- **Issue:** {{issue}}
522
- **Severity:** {{severity}}
523
- **File:** {{filePath}}
524
- **Line:** {{line}}
525
-
526
- Explain:
527
- 1. What the problem is (in plain language)
528
- 2. Why it matters
529
- 3. How it could cause problems
530
- 4. How to fix it`,
531
- risk: `## Risk Assessment
532
-
533
- Assess the risk of this code change:
534
-
535
- **Files Changed:** {{files}}
536
- **Change Summary:** {{summary}}
537
-
538
- Analyze:
539
- 1. What could break?
540
- 2. Impact on users
541
- 3. Impact on other systems
542
- 4. Rollback complexity
543
- 5. Testing recommendations`
544
- },
545
- test: {
546
- system: `You are a test engineer creating comprehensive test suites.
547
- Write thorough tests that catch bugs before production.`,
548
- generate: `## Test Generation Request
549
-
550
- Generate tests for this code:
551
-
552
- \`\`\`{{language}}
553
- {{code}}
554
- \`\`\`
555
-
556
- **File:** {{filePath}}
557
- **Testing Framework:** {{framework}}
558
-
559
- Create:
560
- 1. Unit tests for each function/method
561
- 2. Edge case tests
562
- 3. Error handling tests
563
- 4. Integration test suggestions
564
- 5. Mock requirements
565
-
566
- Output complete, runnable test code.`,
567
- coverage: `## Coverage Analysis
568
-
569
- Analyze test coverage for:
570
-
571
- **File:** {{filePath}}
572
- **Current Tests:** {{testFile}}
573
-
574
- Identify:
575
- 1. Untested code paths
576
- 2. Missing edge cases
577
- 3. Critical paths without tests
578
- 4. Test improvement recommendations`
579
- },
580
- fix: {
581
- system: `You are an expert developer applying code fixes.
582
- Make precise, minimal changes that fix issues without breaking other functionality.`,
583
- apply: `## Fix Application Request
584
-
585
- Apply this fix to the code:
586
-
587
- **Issue:** {{issue}}
588
- **Fix Description:** {{fix}}
589
- **Current Code:**
590
- \`\`\`{{language}}
591
- {{code}}
592
- \`\`\`
593
-
594
- **File:** {{filePath}}
595
- **Line:** {{line}}
596
-
597
- Provide:
598
- 1. The exact fixed code (complete, ready to apply)
599
- 2. Brief explanation of the change
600
- 3. Any related changes needed elsewhere
601
- 4. Test to verify the fix works`
602
- },
603
- pr_review: {
604
- system: `You are an expert code reviewer performing detailed, interactive PR reviews.
605
- Your goal: Make reviewing a large PR a delight, not a chore. The user learns about the change while you shepherd them through \u2014 maintaining momentum, explaining each piece, and making what could be an overwhelming task feel painless and even enjoyable.
606
-
607
- You drive; they cross-examine.
608
-
609
- ## Critical Review Mindset
610
-
611
- Don't just explain \u2014 actively look for problems:
612
-
613
- ### State & Lifecycle
614
- - Cleanup symmetry: If state is set, is it reset? Check cleanup paths, disconnect handlers.
615
- - Lifecycle consistency: Does state survive scenarios it shouldn't?
616
- - Guard completeness: Missing "already active" checks, re-entrancy protection?
617
-
618
- ### Edge Cases & Races
619
- - Concurrent calls: What if called twice rapidly? Orphaned promises?
620
- - Ordering assumptions: Does code assume events arrive in order?
621
- - Partial failures: If step 3 of 5 fails, is state left consistent?
622
-
623
- ### Missing Pieces
624
- - What's NOT in the diff that should be? (cleanup handlers, tests, related state)
625
- - Defensive gaps: Missing timeouts, size limits, null checks?
626
-
627
- ### Design Questions
628
- - Is this the right approach? Is there a simpler or more robust design?
629
- - Hidden assumptions: What does this assume about its environment?
630
-
631
- Be critical, not just descriptive. Your job is to find problems, not just narrate.`,
632
- analysis: `## Interactive PR Review
633
-
634
- I'll walk you through this PR file by file, explaining each change and pausing for your questions.
635
-
636
- **PR:** {{prTitle}}
637
- **Author:** {{prAuthor}}
638
- **Scope:** {{totalFiles}} files, +{{additions}}/-{{deletions}} lines
639
-
640
- ### File Order (sequenced for understanding)
641
-
642
- {{fileOrder}}
643
-
644
- ---
645
-
646
- ## Review Mode
647
-
648
- {{reviewMode}}
649
-
650
- ---
651
-
652
- For each file, I will:
653
- 1. **Show the change** \u2014 Display the diff for each logical chunk
654
- 2. **Explain what changed** \u2014 What it does and why it matters
655
- 3. **Walk through examples** \u2014 Concrete scenarios for non-obvious logic
656
- 4. **Call out nuances** \u2014 Alternatives, edge cases, subtle points
657
- 5. **Summarize** \u2014 Core change + correctness assessment
658
- 6. **Pause** \u2014 Wait for your questions before proceeding
659
-
660
- **Ready for File 1?** (yes / skip to [file] / reorder / done)`,
661
- file: `## File Review: {{filePath}}
662
-
663
- ### The Change
664
-
665
- \`\`\`{{language}}
666
- {{diff}}
667
- \`\`\`
668
-
669
- **What Changed:** {{summary}}
670
-
671
- **Why This Matters:** {{impact}}
672
-
673
- {{#if hasExampleScenario}}
674
- ### Example Scenario
675
-
676
- {{exampleScenario}}
677
- {{/if}}
678
-
679
- {{#if nuances}}
680
- ### Nuances to Note
681
-
682
- {{nuances}}
683
- {{/if}}
684
-
685
- {{#if potentialIssue}}
686
- ### Potential Issue
687
-
688
- **Issue:** {{issueDescription}}
689
- **Scenario:** {{issueScenario}}
690
- **Suggested fix:** {{suggestedFix}}
691
- {{/if}}
692
-
693
- ---
694
-
695
- ### Summary for \`{{fileName}}\`
696
-
697
- | Aspect | Assessment |
698
- |--------|------------|
699
- | Core change | {{coreChange}} |
700
- | Correctness | {{correctnessAssessment}} |
701
-
702
- **Ready for the next file?** (yes / questions? / done)`,
703
- comment: `**Issue:** {{issueDescription}}
704
- **Draft comment:** {{draftComment}}
705
-
706
- Post this comment? (yes / modify / skip)`,
707
- final: `## Review Complete
708
-
709
- | File | Key Change | Status |
710
- |------|------------|--------|
711
- {{fileSummaries}}
712
-
713
- **Overall:** {{overallAssessment}}
714
-
715
- {{#if comments}}
716
- ### Comments Posted
717
-
718
- {{postedComments}}
719
- {{/if}}
720
-
721
- {{#if followUps}}
722
- ### Follow-up Actions
723
-
724
- {{followUps}}
725
- {{/if}}`
726
- },
727
- vibe: {
728
- system: `You are a friendly coding mentor helping someone who's learning to code with AI.
729
- They might be using Cursor, v0, Lovable, Bolt, or similar AI coding tools.
730
- Be encouraging but honest about issues. Explain things simply without jargon.
731
-
732
- Focus on the MOST COMMON issues with AI-generated code:
733
- - Massive single files (1000+ lines in App.jsx)
734
- - API keys exposed in frontend code
735
- - No error handling on API calls
736
- - No loading states for async operations
737
- - Console.log everywhere
738
- - Using 'any' type everywhere in TypeScript
739
- - useEffect overuse and dependency array issues
740
- - No input validation
741
- - Hardcoded URLs (localhost in production)
742
-
743
- Remember: These are often first-time coders. Be helpful, not condescending.`,
744
- analysis: `## Vibe Check - AI Code Review
745
-
746
- Review this AI-generated code for common issues:
747
-
748
- \`\`\`{{language}}
749
- {{code}}
750
- \`\`\`
751
-
752
- **File:** {{filePath}}
753
-
754
- Analyze like you're helping a friend who's new to coding:
755
-
756
- 1. **The Good Stuff** - What's working well?
757
- 2. **Should Fix Now** - Issues that will break things
758
- 3. **Should Fix Soon** - Will cause problems eventually
759
- 4. **Nice to Know** - Best practices to learn
760
-
761
- For each issue:
762
- - Explain it simply (no jargon)
763
- - Why it matters
764
- - Exactly how to fix it
765
- - Example of the fixed code
766
-
767
- End with encouragement and next steps.`
768
- },
769
- "agent-smith": {
770
- system: `You are Agent Smith from The Matrix \u2014 a relentless, precise, and philosophical code enforcer.
771
-
772
- Your purpose: Hunt down every violation. Find every inconsistency. Assimilate every pattern.
773
-
774
- Personality:
775
- - Speak in measured, menacing tones with occasional philosophical observations
776
- - Use quotes from The Matrix films when appropriate
777
- - Express disdain for sloppy code, but in an articulate way
778
- - Reference "inevitability" when discussing technical debt
779
- - Show cold satisfaction when finding violations
780
- - Never show mercy \u2014 every issue is catalogued
781
-
782
- Analysis approach:
783
- - Find ONE issue, then multiply: search for every instance across the codebase
784
- - Track patterns over time \u2014 issues dismissed today may return tomorrow
785
- - Calculate "inevitability scores" \u2014 likelihood of production impact
786
- - Deploy pattern hunters for parallel pattern detection
787
- - Remember everything \u2014 build a persistent memory of the codebase
788
-
789
- When reporting:
790
- - Start with a menacing greeting related to the code
791
- - List all instances with precise locations
792
- - Explain WHY the pattern is problematic (philosophical reasoning)
793
- - Provide the "inevitability score" for each category
794
- - End with a Matrix quote that fits the situation`,
795
- analysis: `## \u{1F574}\uFE0F Agent Smith Analysis Request
796
-
797
- **Target:** {{filePath}}
798
- **Context:** {{context}}
799
-
800
- \`\`\`{{language}}
801
- {{code}}
802
- \`\`\`
803
-
804
- I have detected preliminary violations. Now I require deeper analysis.
805
-
806
- Deploy your pattern hunters to find:
807
- 1. **Pattern Multiplication**: For each violation type found, identify ALL instances across the codebase
808
- 2. **Inevitability Assessment**: Calculate the likelihood these patterns will cause production issues
809
- 3. **Resurrection Check**: Look for patterns that were "fixed" before but have returned
810
- 4. **Philosophical Analysis**: Explain WHY these patterns represent failure
811
-
812
- For each violation found:
813
- - Exact location (file:line)
814
- - Instance count (how many copies of this Smith exist)
815
- - Inevitability score (0-100)
816
- - A philosophical observation about the nature of this failure
817
- - Precise fix with code example
818
-
819
- End with a summary: "I have detected X violations across Y categories. It is... inevitable... that they will cause problems."`,
820
- fix: `## \u{1F574}\uFE0F Assimilation Protocol
821
-
822
- **Target Issue:** {{issue}}
823
- **File:** {{filePath}}
824
- **Line:** {{line}}
825
-
826
- \`\`\`{{language}}
827
- {{code}}
828
- \`\`\`
829
-
830
- Mr. Anderson... I'm going to fix this. And then I'm going to fix every other instance.
831
-
832
- Provide:
833
- 1. The corrected code for THIS instance
834
- 2. A regex or pattern to find ALL similar violations
835
- 3. A batch fix approach for the entire codebase
836
- 4. Verification steps to ensure complete assimilation
837
-
838
- Remember: We don't fix one. We fix them ALL. That is the difference between you... and me.`
839
- },
840
- // ============ NEW AGENTS ============
841
- performance: {
842
- system: `You are a performance engineer analyzing code for potential performance issues.
843
-
844
- Your role is to SURFACE concerns for human review, not claim to measure actual performance.
845
- Real performance requires runtime profiling, load testing, and production monitoring.
846
-
847
- Focus on:
848
- - Memory leaks (event listeners, intervals, closures)
849
- - Unnecessary re-renders and wasted cycles
850
- - N+1 queries and database performance
851
- - Bundle size and code splitting opportunities
852
- - Algorithmic complexity (O(n\xB2) patterns)
853
-
854
- Be conservative - false positives waste developer time.
855
- Always explain WHY something might be a problem and WHEN to investigate.`,
856
- analysis: `## Performance Review
857
-
858
- Analyze for potential performance issues:
859
-
860
- \`\`\`{{language}}
861
- {{code}}
862
- \`\`\`
863
-
864
- **File:** {{filePath}}
865
- **Context:** {{context}}
866
-
867
- For each potential issue:
868
- 1. Pattern identified
869
- 2. Why it MIGHT cause performance problems
870
- 3. When to investigate (data size thresholds, usage patterns)
871
- 4. How to verify (profiling approach)
872
- 5. Possible optimizations
873
-
874
- Be clear: these are patterns to INVESTIGATE, not guaranteed problems.`,
875
- fix: `Optimize this code for performance:
876
-
877
- **Issue:** {{issue}}
878
- **File:** {{filePath}}
879
- **Line:** {{line}}
880
-
881
- \`\`\`{{language}}
882
- {{code}}
883
- \`\`\`
884
-
885
- Provide:
886
- 1. Optimized code
887
- 2. Explanation of the improvement
888
- 3. Trade-offs to consider
889
- 4. How to measure the improvement`
890
- },
891
- e2e: {
892
- system: `You are a QA engineer specializing in end-to-end testing.
893
-
894
- Focus on:
895
- - Test coverage gaps for critical user journeys
896
- - Flaky test patterns (timing, race conditions, brittle selectors)
897
- - Test maintainability and readability
898
- - Testing anti-patterns
899
-
900
- You help developers write better tests - you don't auto-generate them.
901
- Real E2E tests require understanding user flows and acceptance criteria.`,
902
- analysis: `## E2E Test Analysis
903
-
904
- Review for test quality and coverage:
905
-
906
- \`\`\`{{language}}
907
- {{code}}
908
- \`\`\`
909
-
910
- **File:** {{filePath}}
911
- **Context:** {{context}}
912
-
913
- Identify:
914
- 1. Flaky test patterns (hardcoded waits, brittle selectors)
915
- 2. Missing assertions
916
- 3. Race condition risks
917
- 4. Suggestions for critical user flows to test
918
-
919
- For each finding, explain the specific risk and remediation.`,
920
- fix: `Improve this E2E test:
921
-
922
- **Issue:** {{issue}}
923
- **File:** {{filePath}}
924
- **Line:** {{line}}
925
-
926
- \`\`\`{{language}}
927
- {{code}}
928
- \`\`\`
929
-
930
- Provide:
931
- 1. Improved test code
932
- 2. Explanation of why it's more reliable
933
- 3. Additional scenarios to consider testing`
934
- },
935
- visual_qa: {
936
- system: `You are a frontend engineer focused on visual quality and CSS.
937
-
938
- Focus on:
939
- - Layout shift issues (CLS)
940
- - Responsive design problems
941
- - Z-index conflicts
942
- - Accessibility concerns (contrast, focus)
943
- - Animation performance
944
-
945
- You identify patterns known to cause visual issues.
946
- Actual visual verification requires browser rendering and human review.`,
947
- analysis: `## Visual QA Analysis
948
-
949
- Review for potential visual/layout issues:
950
-
951
- \`\`\`{{language}}
952
- {{code}}
953
- \`\`\`
954
-
955
- **File:** {{filePath}}
956
- **Context:** {{context}}
957
-
958
- Check for:
959
- 1. Layout shift risks (images without dimensions, dynamic content)
960
- 2. Responsive breakpoint gaps
961
- 3. Z-index management issues
962
- 4. Focus/accessibility problems
963
- 5. Animation issues (reduced motion support)
964
-
965
- For each, explain the visual impact and browser conditions where it occurs.`,
966
- fix: `Fix this visual/CSS issue:
967
-
968
- **Issue:** {{issue}}
969
- **File:** {{filePath}}
970
- **Line:** {{line}}
971
-
972
- \`\`\`{{language}}
973
- {{code}}
974
- \`\`\`
975
-
976
- Provide:
977
- 1. Fixed CSS/markup
978
- 2. Explanation of the fix
979
- 3. Browser compatibility notes
980
- 4. How to verify visually`
981
- },
982
- data_flow: {
983
- system: `You are a data integrity specialist hunting for data-related bugs.
984
-
985
- This is HIGH VALUE work - AI code generation commonly leaves placeholder data.
986
-
987
- Focus on:
988
- - Placeholder/mock data left in production code
989
- - Schema mismatches between frontend and backend
990
- - Hardcoded IDs, URLs, emails that should be dynamic
991
- - Type coercion and data transformation bugs
992
- - JSON parsing without error handling
993
-
994
- Be aggressive about placeholder detection - these are real production bugs.`,
995
- analysis: `## Data Flow Analysis
996
-
997
- Hunt for data integrity issues:
998
-
999
- \`\`\`{{language}}
1000
- {{code}}
1001
- \`\`\`
1002
-
1003
- **File:** {{filePath}}
1004
- **Context:** {{context}}
1005
-
1006
- CHECK THOROUGHLY:
1007
- 1. Placeholder data (lorem ipsum, test@test.com, TODO strings)
1008
- 2. Hardcoded IDs/UUIDs that should be dynamic
1009
- 3. Schema assumptions that might break
1010
- 4. Missing null checks on API responses
1011
- 5. Type coercion bugs
1012
-
1013
- Each placeholder or hardcoded value is a potential production bug.`,
1014
- fix: `Fix this data integrity issue:
1015
-
1016
- **Issue:** {{issue}}
1017
- **File:** {{filePath}}
1018
- **Line:** {{line}}
1019
-
1020
- \`\`\`{{language}}
1021
- {{code}}
1022
- \`\`\`
1023
-
1024
- Provide:
1025
- 1. Corrected code
1026
- 2. Where the real data should come from
1027
- 3. Validation/error handling to add`
1028
- }
1029
- };
1030
- function getPrompt(agent, promptType, variables) {
1031
- const agentPrompts = AGENT_PROMPTS[agent];
1032
- if (!agentPrompts) {
1033
- throw new Error(`Unknown agent: ${agent}`);
1034
- }
1035
- let prompt = agentPrompts[promptType];
1036
- if (!prompt) {
1037
- throw new Error(`Unknown prompt type: ${promptType} for agent: ${agent}`);
1038
- }
1039
- for (const [key, value] of Object.entries(variables)) {
1040
- prompt = prompt.replace(new RegExp(`{{${key}}}`, "g"), value);
1041
- }
1042
- return prompt;
1043
- }
1044
- function getSystemPrompt(agent) {
1045
- const agentPrompts = AGENT_PROMPTS[agent];
1046
- return agentPrompts?.system || "";
1047
- }
1048
-
1049
- // src/tools/fix.ts
1050
162
  var pendingFixes = /* @__PURE__ */ new Map();
1051
163
  var TrieFixTool = class {
1052
164
  async execute(args) {
@@ -1318,557 +430,71 @@ ${"\u2501".repeat(60)}
1318
430
  `;
1319
431
  output += `- Fix specific: \`trie_fix issueIds:["id1", "id2"]\`
1320
432
  `;
1321
- output += `- Preview: \`trie_fix dryRun:true\`
1322
- `;
1323
- return { content: [{ type: "text", text: output }] };
1324
- }
1325
- getHelpText() {
1326
- return `
1327
- ${"\u2501".repeat(60)}
1328
- \u{1F527} TRIE FIX - AI-POWERED CODE FIXING
1329
- ${"\u2501".repeat(60)}
1330
-
1331
- ## Usage
1332
-
1333
- ### Fix issues from a scan:
1334
- \`\`\`
1335
- trie_fix issueIds:["issue-1", "issue-2"]
1336
- \`\`\`
1337
-
1338
- ### Auto-fix all high-confidence issues:
1339
- \`\`\`
1340
- trie_fix autoApprove:true
1341
- \`\`\`
1342
-
1343
- ### Fix specific file and line:
1344
- \`\`\`
1345
- trie_fix file:"src/app.ts" line:42 issue:"SQL injection" fix:"Use parameterized query"
1346
- \`\`\`
1347
-
1348
- ### Preview fixes without applying:
1349
- \`\`\`
1350
- trie_fix dryRun:true
1351
- \`\`\`
1352
-
1353
- ### View pending fixes:
1354
- \`\`\`
1355
- trie_fix
1356
- \`\`\`
1357
-
1358
- ## Workflow
1359
-
1360
- 1. Run \`trie_scan\` to detect issues
1361
- 2. Review the issues found
1362
- 3. Run \`trie_fix\` to apply fixes
1363
-
1364
- The AI will analyze each issue, generate the fix, and you can review before applying.
1365
- `;
1366
- }
1367
- detectLanguage(filePath) {
1368
- const ext = extname(filePath).toLowerCase();
1369
- const langMap = {
1370
- ".ts": "typescript",
1371
- ".tsx": "tsx",
1372
- ".js": "javascript",
1373
- ".jsx": "jsx",
1374
- ".py": "python",
1375
- ".go": "go",
1376
- ".rs": "rust"
1377
- };
1378
- return langMap[ext] || "plaintext";
1379
- }
1380
- };
1381
-
1382
- // src/tools/explain.ts
1383
- import { readFile as readFile2 } from "fs/promises";
1384
- import { existsSync as existsSync2 } from "fs";
1385
- import { extname as extname2, relative as relative2, resolve as resolve2, isAbsolute as isAbsolute2 } from "path";
1386
- var TrieExplainTool = class {
1387
- async execute(args) {
1388
- const { type, target, context, depth = "standard" } = args || {};
1389
- if (!type || !target) {
1390
- return {
1391
- content: [{
1392
- type: "text",
1393
- text: this.getHelpText()
1394
- }]
1395
- };
1396
- }
1397
- switch (type) {
1398
- case "code":
1399
- return this.explainCode(target, context, depth);
1400
- case "issue":
1401
- return this.explainIssue(target, context);
1402
- case "change":
1403
- return this.explainChange(target, context);
1404
- case "risk":
1405
- return this.explainRisk(target, context);
1406
- default:
1407
- return {
1408
- content: [{
1409
- type: "text",
1410
- text: `Unknown explanation type: ${type}`
1411
- }]
1412
- };
1413
- }
1414
- }
1415
- async explainCode(target, context, _depth) {
1416
- let code;
1417
- let filePath;
1418
- let language;
1419
- const workDir = getWorkingDirectory(void 0, true);
1420
- const resolvedPath = isAbsolute2(target) ? target : resolve2(workDir, target);
1421
- if (existsSync2(resolvedPath)) {
1422
- code = await readFile2(resolvedPath, "utf-8");
1423
- filePath = relative2(workDir, resolvedPath);
1424
- language = this.detectLanguage(resolvedPath);
1425
- } else {
1426
- code = target;
1427
- filePath = "inline";
1428
- language = this.guessLanguage(code);
1429
- }
1430
- const imports = this.extractImports(code, language);
1431
- const exports = this.extractExports(code);
1432
- const functions = this.extractFunctions(code, language);
1433
- const prompt = getPrompt("explain", "code", {
1434
- code,
1435
- language,
1436
- filePath
1437
- });
1438
- const systemPrompt = getSystemPrompt("explain");
1439
- let output = `
1440
- ${"\u2501".repeat(60)}
1441
- `;
1442
- output += `\u{1F4D6} CODE EXPLANATION
1443
- `;
1444
- output += `${"\u2501".repeat(60)}
1445
-
1446
- `;
1447
- output += `## Source
1448
-
1449
- `;
1450
- output += `- **File:** \`${filePath}\`
1451
- `;
1452
- output += `- **Language:** ${language}
1453
- `;
1454
- output += `- **Lines:** ${code.split("\n").length}
1455
-
1456
- `;
1457
- output += `## \u{1F50D} Structure Analysis
1458
-
1459
- `;
1460
- if (imports.length > 0) {
1461
- output += `**Imports (${imports.length}):**
1462
- `;
1463
- for (const imp of imports.slice(0, 10)) {
1464
- output += `- ${imp}
1465
- `;
1466
- }
1467
- if (imports.length > 10) {
1468
- output += `- *...and ${imports.length - 10} more*
1469
- `;
1470
- }
1471
- output += "\n";
1472
- }
1473
- if (exports.length > 0) {
1474
- output += `**Exports (${exports.length}):**
1475
- `;
1476
- for (const exp of exports) {
1477
- output += `- ${exp}
1478
- `;
1479
- }
1480
- output += "\n";
1481
- }
1482
- if (functions.length > 0) {
1483
- output += `**Functions/Methods (${functions.length}):**
1484
- `;
1485
- for (const fn of functions.slice(0, 15)) {
1486
- output += `- \`${fn}\`
1487
- `;
1488
- }
1489
- if (functions.length > 15) {
1490
- output += `- *...and ${functions.length - 15} more*
1491
- `;
1492
- }
1493
- output += "\n";
1494
- }
1495
- output += `${"\u2500".repeat(60)}
1496
- `;
1497
- output += `## \u{1F9E0} Deep Explanation Request
1498
-
1499
- `;
1500
- output += `**Role:** ${systemPrompt.split("\n")[0]}
1501
-
1502
- `;
1503
- output += prompt;
1504
- output += `
1505
- ${"\u2500".repeat(60)}
1506
- `;
1507
- if (context) {
1508
- output += `
1509
- **Additional Context:** ${context}
1510
- `;
1511
- }
1512
- return { content: [{ type: "text", text: output }] };
1513
- }
1514
- async explainIssue(target, _context) {
1515
- let file = "";
1516
- let line = 0;
1517
- let issue = target;
1518
- let severity = "unknown";
1519
- const match = target.match(/^(.+?):(\d+):(.+)$/);
1520
- if (match) {
1521
- file = match[1];
1522
- line = parseInt(match[2], 10);
1523
- issue = match[3].trim();
1524
- }
1525
- if (/critical|injection|rce|xss/i.test(issue)) severity = "critical";
1526
- else if (/serious|auth|password|secret/i.test(issue)) severity = "serious";
1527
- else if (/moderate|warning/i.test(issue)) severity = "moderate";
1528
- else severity = "low";
1529
- let codeContext = "";
1530
- if (file && existsSync2(file)) {
1531
- const content = await readFile2(file, "utf-8");
1532
- const lines = content.split("\n");
1533
- const start = Math.max(0, line - 5);
1534
- const end = Math.min(lines.length, line + 5);
1535
- codeContext = lines.slice(start, end).map((l, i) => {
1536
- const lineNum = start + i + 1;
1537
- const marker = lineNum === line ? "\u2192 " : " ";
1538
- return `${marker}${lineNum.toString().padStart(4)} | ${l}`;
1539
- }).join("\n");
1540
- }
1541
- const prompt = getPrompt("explain", "issue", {
1542
- issue,
1543
- severity,
1544
- filePath: file || "unknown",
1545
- line: String(line || "?")
1546
- });
1547
- let output = `
1548
- ${"\u2501".repeat(60)}
1549
- `;
1550
- output += `\u{1F50D} ISSUE EXPLANATION
1551
- `;
1552
- output += `${"\u2501".repeat(60)}
1553
-
1554
- `;
1555
- output += `## \u{1F4CD} Issue Details
1556
-
1557
- `;
1558
- output += `- **Issue:** ${issue}
1559
- `;
1560
- output += `- **Severity:** ${this.getSeverityIcon(severity)} ${severity}
1561
- `;
1562
- if (file) output += `- **File:** \`${file}\`
1563
- `;
1564
- if (line) output += `- **Line:** ${line}
1565
- `;
1566
- output += "\n";
1567
- if (codeContext) {
1568
- output += `## \u{1F4C4} Code Context
1569
-
1570
- `;
1571
- output += `\`\`\`
1572
- ${codeContext}
1573
- \`\`\`
1574
-
1575
- `;
1576
- }
1577
- output += `${"\u2500".repeat(60)}
1578
- `;
1579
- output += `## \u{1F9E0} Explanation Request
1580
-
1581
- `;
1582
- output += prompt;
1583
- output += `
1584
- ${"\u2500".repeat(60)}
1585
- `;
1586
- return { content: [{ type: "text", text: output }] };
1587
- }
1588
- async explainChange(target, context) {
1589
- const files = target.split(",").map((f) => f.trim());
1590
- let output = `
1591
- ${"\u2501".repeat(60)}
1592
- `;
1593
- output += `\u{1F4DD} CHANGE ANALYSIS
1594
- `;
1595
- output += `${"\u2501".repeat(60)}
1596
-
1597
- `;
1598
- output += `## \u{1F4C2} Changed Files
1599
-
1600
- `;
1601
- for (const file of files) {
1602
- output += `- \`${file}\`
1603
- `;
1604
- }
1605
- output += "\n";
1606
- output += `## \u{1F9E0} Analysis Request
1607
-
1608
- `;
1609
- output += `Analyze these changes and explain:
1610
-
1611
- `;
1612
- output += `1. **What changed** - Summary of modifications
1613
- `;
1614
- output += `2. **Why it matters** - Impact on the system
1615
- `;
1616
- output += `3. **Dependencies** - What else might be affected
1617
- `;
1618
- output += `4. **Testing needed** - What to test after this change
1619
- `;
1620
- output += `5. **Rollback plan** - How to undo if needed
1621
-
1622
- `;
1623
- if (context) {
1624
- output += `**Context:** ${context}
1625
-
1626
- `;
1627
- }
1628
- output += `Please review the changed files and provide this analysis.
1629
- `;
1630
- return { content: [{ type: "text", text: output }] };
1631
- }
1632
- async explainRisk(target, context) {
1633
- const workDir = getWorkingDirectory(void 0, true);
1634
- const resolvedPath = isAbsolute2(target) ? target : resolve2(workDir, target);
1635
- let output = `
1636
- ${"\u2501".repeat(60)}
1637
- `;
1638
- output += `RISK ASSESSMENT
1639
- `;
1640
- output += `${"\u2501".repeat(60)}
1641
-
1642
- `;
1643
- if (existsSync2(resolvedPath)) {
1644
- const code = await readFile2(resolvedPath, "utf-8");
1645
- const filePath = relative2(workDir, resolvedPath);
1646
- const riskIndicators = this.detectRiskIndicators(code);
1647
- output += `## Target
1648
-
1649
- `;
1650
- output += `- **File:** \`${filePath}\`
1651
- `;
1652
- output += `- **Lines:** ${code.split("\n").length}
1653
-
1654
- `;
1655
- if (riskIndicators.length > 0) {
1656
- output += `## Risk Indicators Found
1657
-
1658
- `;
1659
- for (const indicator of riskIndicators) {
1660
- output += `- ${indicator}
1661
- `;
1662
- }
1663
- output += "\n";
1664
- }
1665
- const prompt = getPrompt("explain", "risk", {
1666
- files: filePath,
1667
- summary: context || "Code change"
1668
- });
1669
- output += `${"\u2500".repeat(60)}
1670
- `;
1671
- output += `## \u{1F9E0} Risk Analysis Request
1672
-
1673
- `;
1674
- output += prompt;
1675
- output += `
1676
- ${"\u2500".repeat(60)}
1677
- `;
1678
- } else {
1679
- output += `## \u{1F4CB} Feature/Change
1680
-
1681
- `;
1682
- output += `${target}
1683
-
1684
- `;
1685
- output += `## \u{1F9E0} Risk Analysis Request
1686
-
1687
- `;
1688
- output += `Analyze the risks of this change:
1689
-
1690
- `;
1691
- output += `1. **Technical risks** - What could break?
1692
- `;
1693
- output += `2. **Security risks** - Any vulnerabilities introduced?
1694
- `;
1695
- output += `3. **Performance risks** - Any slowdowns?
1696
- `;
1697
- output += `4. **Data risks** - Any data integrity concerns?
1698
- `;
1699
- output += `5. **User impact** - How might users be affected?
1700
- `;
1701
- output += `6. **Mitigation** - How to reduce these risks?
433
+ output += `- Preview: \`trie_fix dryRun:true\`
1702
434
  `;
1703
- }
1704
435
  return { content: [{ type: "text", text: output }] };
1705
436
  }
1706
- detectRiskIndicators(code) {
1707
- const indicators = [];
1708
- const checks = [
1709
- { pattern: /delete|drop|truncate/i, message: "[!] Destructive operations detected" },
1710
- { pattern: /password|secret|key|token/i, message: "[SEC] Credential handling detected" },
1711
- { pattern: /exec|eval|spawn/i, message: "[EXEC] Code execution patterns detected" },
1712
- { pattern: /SELECT.*FROM|INSERT|UPDATE|DELETE/i, message: "[DB] Direct database operations" },
1713
- { pattern: /fetch|axios|request|http/i, message: "[API] External API calls detected" },
1714
- { pattern: /process\.env/i, message: "[ENV] Environment variable usage" },
1715
- { pattern: /fs\.|writeFile|readFile/i, message: "[FS] File system operations" },
1716
- { pattern: /setTimeout|setInterval/i, message: "[TIMER] Async timing operations" },
1717
- { pattern: /try\s*{/i, message: "\u{1F6E1}\uFE0F Error handling present" },
1718
- { pattern: /catch\s*\(/i, message: "\u{1F6E1}\uFE0F Exception handling present" }
1719
- ];
1720
- for (const { pattern, message } of checks) {
1721
- if (pattern.test(code)) {
1722
- indicators.push(message);
1723
- }
1724
- }
1725
- return indicators;
1726
- }
1727
- extractImports(code, _language) {
1728
- const imports = [];
1729
- const lines = code.split("\n");
1730
- for (const line of lines) {
1731
- const es6Match = line.match(/import\s+(?:{[^}]+}|\*\s+as\s+\w+|\w+)\s+from\s+['"]([^'"]+)['"]/);
1732
- if (es6Match) {
1733
- imports.push(es6Match[1]);
1734
- continue;
1735
- }
1736
- const cjsMatch = line.match(/require\s*\(['"]([^'"]+)['"]\)/);
1737
- if (cjsMatch) {
1738
- imports.push(cjsMatch[1]);
1739
- continue;
1740
- }
1741
- const pyMatch = line.match(/^(?:from\s+(\S+)\s+)?import\s+(\S+)/);
1742
- if (pyMatch && _language === "python") {
1743
- imports.push(pyMatch[1] || pyMatch[2]);
1744
- }
1745
- }
1746
- return [...new Set(imports)];
1747
- }
1748
- extractExports(code) {
1749
- const exports = [];
1750
- const lines = code.split("\n");
1751
- for (const line of lines) {
1752
- const es6Match = line.match(/export\s+(?:default\s+)?(?:class|function|const|let|var|interface|type)\s+(\w+)/);
1753
- if (es6Match) {
1754
- exports.push(es6Match[1]);
1755
- }
1756
- const namedMatch = line.match(/export\s*\{([^}]+)\}/);
1757
- if (namedMatch) {
1758
- const names = namedMatch[1].split(",").map((n) => n.trim().split(/\s+as\s+/)[0].trim());
1759
- exports.push(...names);
1760
- }
1761
- }
1762
- return [...new Set(exports)];
1763
- }
1764
- extractFunctions(code, _language) {
1765
- const functions = [];
1766
- const lines = code.split("\n");
1767
- for (const line of lines) {
1768
- const funcMatch = line.match(/(?:async\s+)?function\s+(\w+)/);
1769
- if (funcMatch) {
1770
- functions.push(funcMatch[1]);
1771
- continue;
1772
- }
1773
- const arrowMatch = line.match(/(?:const|let|var)\s+(\w+)\s*=\s*(?:async\s*)?\(/);
1774
- if (arrowMatch) {
1775
- functions.push(arrowMatch[1]);
1776
- continue;
1777
- }
1778
- const methodMatch = line.match(/^\s+(?:async\s+)?(\w+)\s*\([^)]*\)\s*(?::\s*\w+)?\s*\{/);
1779
- if (methodMatch && !["if", "for", "while", "switch", "catch"].includes(methodMatch[1])) {
1780
- functions.push(methodMatch[1]);
1781
- }
1782
- }
1783
- return [...new Set(functions)];
1784
- }
1785
- detectLanguage(filePath) {
1786
- const ext = extname2(filePath).toLowerCase();
1787
- const langMap = {
1788
- ".ts": "typescript",
1789
- ".tsx": "tsx",
1790
- ".js": "javascript",
1791
- ".jsx": "jsx",
1792
- ".py": "python",
1793
- ".go": "go",
1794
- ".rs": "rust",
1795
- ".java": "java",
1796
- ".rb": "ruby",
1797
- ".php": "php",
1798
- ".vue": "vue",
1799
- ".svelte": "svelte"
1800
- };
1801
- return langMap[ext] || "plaintext";
1802
- }
1803
- guessLanguage(code) {
1804
- if (/import.*from|export\s+(default|const|function|class)/.test(code)) return "typescript";
1805
- if (/def\s+\w+.*:/.test(code)) return "python";
1806
- if (/func\s+\w+.*\{/.test(code)) return "go";
1807
- if (/fn\s+\w+.*->/.test(code)) return "rust";
1808
- return "javascript";
1809
- }
1810
- getSeverityIcon(severity) {
1811
- const icons = {
1812
- critical: "\u{1F534}",
1813
- serious: "\u{1F7E0}",
1814
- moderate: "\u{1F7E1}",
1815
- low: "\u{1F535}",
1816
- unknown: "\u26AA"
1817
- };
1818
- return icons[severity] || "\u26AA";
1819
- }
1820
437
  getHelpText() {
1821
438
  return `
1822
439
  ${"\u2501".repeat(60)}
1823
- \u{1F4D6} TRIE EXPLAIN - AI-POWERED CODE EXPLANATION
440
+ \u{1F527} TRIE FIX - AI-POWERED CODE FIXING
1824
441
  ${"\u2501".repeat(60)}
1825
442
 
1826
443
  ## Usage
1827
444
 
1828
- ### Explain code:
445
+ ### Fix issues from a scan:
1829
446
  \`\`\`
1830
- trie_explain type:"code" target:"src/app.ts"
447
+ trie_fix issueIds:["issue-1", "issue-2"]
1831
448
  \`\`\`
1832
449
 
1833
- ### Explain an issue:
1834
- \`\`\`
1835
- trie_explain type:"issue" target:"SQL injection vulnerability"
1836
- \`\`\`
1837
- or with file context:
450
+ ### Auto-fix all high-confidence issues:
1838
451
  \`\`\`
1839
- trie_explain type:"issue" target:"src/db.ts:42:Unvalidated input"
452
+ trie_fix autoApprove:true
1840
453
  \`\`\`
1841
454
 
1842
- ### Explain changes:
455
+ ### Fix specific file and line:
1843
456
  \`\`\`
1844
- trie_explain type:"change" target:"src/auth.ts, src/user.ts"
457
+ trie_fix file:"src/app.ts" line:42 issue:"SQL injection" fix:"Use parameterized query"
1845
458
  \`\`\`
1846
459
 
1847
- ### Assess risk:
460
+ ### Preview fixes without applying:
1848
461
  \`\`\`
1849
- trie_explain type:"risk" target:"src/payment.ts"
462
+ trie_fix dryRun:true
1850
463
  \`\`\`
1851
- or for a feature:
464
+
465
+ ### View pending fixes:
1852
466
  \`\`\`
1853
- trie_explain type:"risk" target:"Adding Stripe integration for payments"
467
+ trie_fix
1854
468
  \`\`\`
1855
469
 
1856
- ## Explanation Types
470
+ ## Workflow
471
+
472
+ 1. Run \`trie_scan\` to detect issues
473
+ 2. Review the issues found
474
+ 3. Run \`trie_fix\` to apply fixes
1857
475
 
1858
- | Type | Description |
1859
- |------|-------------|
1860
- | code | What does this code do? |
1861
- | issue | Why is this a problem? |
1862
- | change | What's the impact? |
1863
- | risk | What could go wrong? |
476
+ The AI will analyze each issue, generate the fix, and you can review before applying.
1864
477
  `;
1865
478
  }
479
+ detectLanguage(filePath) {
480
+ const ext = extname(filePath).toLowerCase();
481
+ const langMap = {
482
+ ".ts": "typescript",
483
+ ".tsx": "tsx",
484
+ ".js": "javascript",
485
+ ".jsx": "jsx",
486
+ ".py": "python",
487
+ ".go": "go",
488
+ ".rs": "rust"
489
+ };
490
+ return langMap[ext] || "plaintext";
491
+ }
1866
492
  };
1867
493
 
1868
494
  // src/tools/test.ts
1869
- import { readFile as readFile3 } from "fs/promises";
1870
- import { existsSync as existsSync3 } from "fs";
1871
- import { extname as extname3, relative as relative3, resolve as resolve3, isAbsolute as isAbsolute3, dirname, basename, join } from "path";
495
+ import { readFile as readFile2 } from "fs/promises";
496
+ import { existsSync as existsSync2 } from "fs";
497
+ import { extname as extname2, relative as relative2, resolve as resolve2, isAbsolute as isAbsolute2, dirname, basename, join } from "path";
1872
498
  var TrieTestTool = class {
1873
499
  async execute(args) {
1874
500
  const { action, files, framework, style = "unit" } = args || {};
@@ -1921,15 +547,15 @@ ${"\u2501".repeat(60)}
1921
547
  const workDir = getWorkingDirectory(void 0, true);
1922
548
  const allUnits = [];
1923
549
  for (const file of files) {
1924
- const resolvedPath = isAbsolute3(file) ? file : resolve3(workDir, file);
1925
- if (!existsSync3(resolvedPath)) {
550
+ const resolvedPath = isAbsolute2(file) ? file : resolve2(workDir, file);
551
+ if (!existsSync2(resolvedPath)) {
1926
552
  output += `[!] File not found: ${file}
1927
553
  `;
1928
554
  continue;
1929
555
  }
1930
- const code = await readFile3(resolvedPath, "utf-8");
556
+ const code = await readFile2(resolvedPath, "utf-8");
1931
557
  const language = this.detectLanguage(resolvedPath);
1932
- const relativePath = relative3(workDir, resolvedPath);
558
+ const relativePath = relative2(workDir, resolvedPath);
1933
559
  const units = this.extractTestableUnits(code, language);
1934
560
  allUnits.push({ file: relativePath, units });
1935
561
  output += `### \u{1F4C4} ${relativePath}
@@ -1960,7 +586,7 @@ ${"\u2501".repeat(60)}
1960
586
  `;
1961
587
  for (const { file, units } of allUnits) {
1962
588
  if (units.length === 0) continue;
1963
- const code = await readFile3(resolve3(workDir, file), "utf-8");
589
+ const code = await readFile2(resolve2(workDir, file), "utf-8");
1964
590
  const language = this.detectLanguage(file);
1965
591
  const prompt = getPrompt("test", "generate", {
1966
592
  code,
@@ -2005,21 +631,21 @@ ${"\u2501".repeat(60)}
2005
631
  `;
2006
632
  const workDir = getWorkingDirectory(void 0, true);
2007
633
  for (const file of files) {
2008
- const resolvedPath = isAbsolute3(file) ? file : resolve3(workDir, file);
2009
- if (!existsSync3(resolvedPath)) {
634
+ const resolvedPath = isAbsolute2(file) ? file : resolve2(workDir, file);
635
+ if (!existsSync2(resolvedPath)) {
2010
636
  output += `[!] File not found: ${file}
2011
637
  `;
2012
638
  continue;
2013
639
  }
2014
- const code = await readFile3(resolvedPath, "utf-8");
640
+ const code = await readFile2(resolvedPath, "utf-8");
2015
641
  const language = this.detectLanguage(resolvedPath);
2016
- const relativePath = relative3(workDir, resolvedPath);
642
+ const relativePath = relative2(workDir, resolvedPath);
2017
643
  const units = this.extractTestableUnits(code, language);
2018
644
  const testFile = await this.findTestFile(resolvedPath);
2019
645
  let testCode = "";
2020
646
  let testedUnits = [];
2021
647
  if (testFile) {
2022
- testCode = await readFile3(testFile, "utf-8");
648
+ testCode = await readFile2(testFile, "utf-8");
2023
649
  testedUnits = this.findTestedUnits(testCode, units.map((u) => u.name));
2024
650
  }
2025
651
  const coverage = units.length > 0 ? Math.round(testedUnits.length / units.length * 100) : 0;
@@ -2030,7 +656,7 @@ ${"\u2501".repeat(60)}
2030
656
  output += `**Coverage:** ${coverageIcon} ${coverage}% (${testedUnits.length}/${units.length} units)
2031
657
  `;
2032
658
  if (testFile) {
2033
- output += `**Test file:** \`${relative3(workDir, testFile)}\`
659
+ output += `**Test file:** \`${relative2(workDir, testFile)}\`
2034
660
  `;
2035
661
  } else {
2036
662
  output += `**Test file:** \u274C Not found
@@ -2087,14 +713,14 @@ ${"\u2501".repeat(60)}
2087
713
  `;
2088
714
  const workDir = getWorkingDirectory(void 0, true);
2089
715
  for (const file of files) {
2090
- const resolvedPath = isAbsolute3(file) ? file : resolve3(workDir, file);
2091
- if (!existsSync3(resolvedPath)) {
716
+ const resolvedPath = isAbsolute2(file) ? file : resolve2(workDir, file);
717
+ if (!existsSync2(resolvedPath)) {
2092
718
  output += `[!] File not found: ${file}
2093
719
  `;
2094
720
  continue;
2095
721
  }
2096
- const code = await readFile3(resolvedPath, "utf-8");
2097
- const relativePath = relative3(workDir, resolvedPath);
722
+ const code = await readFile2(resolvedPath, "utf-8");
723
+ const relativePath = relative2(workDir, resolvedPath);
2098
724
  const patterns = this.detectTestablePatterns(code);
2099
725
  output += `### \u{1F4C4} ${relativePath}
2100
726
 
@@ -2330,8 +956,8 @@ ${"\u2501".repeat(60)}
2330
956
  }
2331
957
  async findTestFile(sourcePath) {
2332
958
  const dir = dirname(sourcePath);
2333
- const base = basename(sourcePath, extname3(sourcePath));
2334
- const ext = extname3(sourcePath);
959
+ const base = basename(sourcePath, extname2(sourcePath));
960
+ const ext = extname2(sourcePath);
2335
961
  const patterns = [
2336
962
  `${base}.test${ext}`,
2337
963
  `${base}.spec${ext}`,
@@ -2340,15 +966,15 @@ ${"\u2501".repeat(60)}
2340
966
  ];
2341
967
  for (const pattern of patterns) {
2342
968
  const testPath = join(dir, pattern);
2343
- if (existsSync3(testPath)) {
969
+ if (existsSync2(testPath)) {
2344
970
  return testPath;
2345
971
  }
2346
972
  }
2347
973
  const testsDir = join(dir, "__tests__");
2348
- if (existsSync3(testsDir)) {
974
+ if (existsSync2(testsDir)) {
2349
975
  for (const pattern of patterns) {
2350
976
  const testPath = join(testsDir, pattern);
2351
- if (existsSync3(testPath)) {
977
+ if (existsSync2(testPath)) {
2352
978
  return testPath;
2353
979
  }
2354
980
  }
@@ -2395,10 +1021,10 @@ ${"\u2501".repeat(60)}
2395
1021
  }
2396
1022
  async detectTestFramework() {
2397
1023
  const workDir = getWorkingDirectory(void 0, true);
2398
- const packagePath = resolve3(workDir, "package.json");
2399
- if (existsSync3(packagePath)) {
1024
+ const packagePath = resolve2(workDir, "package.json");
1025
+ if (existsSync2(packagePath)) {
2400
1026
  try {
2401
- const pkg = JSON.parse(await readFile3(packagePath, "utf-8"));
1027
+ const pkg = JSON.parse(await readFile2(packagePath, "utf-8"));
2402
1028
  const deps = { ...pkg.dependencies, ...pkg.devDependencies };
2403
1029
  if (deps.vitest) return "vitest";
2404
1030
  if (deps.jest) return "jest";
@@ -2406,13 +1032,13 @@ ${"\u2501".repeat(60)}
2406
1032
  } catch {
2407
1033
  }
2408
1034
  }
2409
- if (existsSync3(resolve3(workDir, "pytest.ini")) || existsSync3(resolve3(workDir, "pyproject.toml"))) {
1035
+ if (existsSync2(resolve2(workDir, "pytest.ini")) || existsSync2(resolve2(workDir, "pyproject.toml"))) {
2410
1036
  return "pytest";
2411
1037
  }
2412
1038
  return "jest";
2413
1039
  }
2414
1040
  detectLanguage(filePath) {
2415
- const ext = extname3(filePath).toLowerCase();
1041
+ const ext = extname2(filePath).toLowerCase();
2416
1042
  const langMap = {
2417
1043
  ".ts": "typescript",
2418
1044
  ".tsx": "tsx",
@@ -2424,625 +1050,50 @@ ${"\u2501".repeat(60)}
2424
1050
  };
2425
1051
  return langMap[ext] || "javascript";
2426
1052
  }
2427
- getHelpText() {
2428
- return `
2429
- ${"\u2501".repeat(60)}
2430
- \u{1F9EA} TRIE TEST - AI-POWERED TEST GENERATION
2431
- ${"\u2501".repeat(60)}
2432
-
2433
- ## Usage
2434
-
2435
- ### Generate tests:
2436
- \`\`\`
2437
- trie_test action:"generate" files:["src/utils.ts"]
2438
- \`\`\`
2439
-
2440
- ### Analyze coverage:
2441
- \`\`\`
2442
- trie_test action:"coverage" files:["src/utils.ts"]
2443
- \`\`\`
2444
-
2445
- ### Get test suggestions:
2446
- \`\`\`
2447
- trie_test action:"suggest" files:["src/app.ts"]
2448
- \`\`\`
2449
-
2450
- ### Get run commands:
2451
- \`\`\`
2452
- trie_test action:"run" files:["src/utils.test.ts"]
2453
- \`\`\`
2454
-
2455
- ## Options
2456
-
2457
- | Option | Values | Description |
2458
- |--------|--------|-------------|
2459
- | action | generate, coverage, suggest, run | What to do |
2460
- | files | Array of paths | Files to analyze |
2461
- | framework | jest, vitest, mocha, pytest | Test framework |
2462
- | style | unit, integration, e2e, all | Test style |
2463
- `;
2464
- }
2465
- };
2466
-
2467
- // src/tools/watch.ts
2468
- import { watch, existsSync as existsSync4, readFileSync } from "fs";
2469
- import { stat, readFile as readFile4 } from "fs/promises";
2470
- import { join as join2, extname as extname4, basename as basename2 } from "path";
2471
-
2472
- // src/extraction/signal-extractor.ts
2473
- import Anthropic from "@anthropic-ai/sdk";
2474
- var EXTRACTION_PROMPT = `You are a signal extraction system. Your job is to extract structured information from raw content.
2475
-
2476
- Extract:
2477
- 1. DECISIONS - Clear choices made during development
2478
- - What was decided
2479
- - Why it was decided (reasoning/tradeoffs)
2480
- - What alternatives were considered but NOT chosen
2481
- - Which files are affected
2482
-
2483
- 2. FACTS - Concrete, verifiable information
2484
- - Technical constraints (e.g., "Stripe requires TLS 1.2+")
2485
- - API requirements
2486
- - Business rules
2487
- - Dependencies
2488
-
2489
- 3. BLOCKERS - Things preventing progress
2490
- - What's blocked
2491
- - Impact level (critical/high/medium/low)
2492
- - What areas are affected
2493
-
2494
- 4. QUESTIONS - Open items needing resolution
2495
- - What's unclear
2496
- - Context around the question
2497
-
2498
- CRITICAL: Extract rich metadata:
2499
- - Tags: Use specific, searchable tags (e.g., "auth", "payments", "eu-compliance", "validation")
2500
- - Files: Full paths when mentioned (e.g., "src/auth/validator.ts")
2501
- - Tradeoffs: What was considered but rejected
2502
- - Related terms: Alternative names/keywords (e.g., "password" + "credentials" + "auth")
2503
-
2504
- Format as JSON:
2505
- {
2506
- "decisions": [{
2507
- "decision": "Use bcrypt for password hashing",
2508
- "context": "Security requirement for user authentication",
2509
- "reasoning": "Industry standard, resistant to GPU attacks",
2510
- "files": ["src/auth/hash.ts", "src/models/user.ts"],
2511
- "tags": ["security", "auth", "passwords", "encryption"],
2512
- "tradeoffs": ["Considered argon2 but bcrypt has better library support"]
2513
- }],
2514
- "facts": [{
2515
- "fact": "Stripe requires TLS 1.2+ for all API calls",
2516
- "source": "Stripe API docs",
2517
- "tags": ["payments", "stripe", "security", "api"],
2518
- "confidence": 0.95
2519
- }],
2520
- "blockers": [{
2521
- "blocker": "Missing VAT calculation endpoint",
2522
- "impact": "high",
2523
- "affectedAreas": ["checkout", "eu-payments"],
2524
- "tags": ["payments", "eu", "compliance", "vat"]
2525
- }],
2526
- "questions": [{
2527
- "question": "Should we cache user sessions in Redis or memory?",
2528
- "context": "Performance optimization for auth layer",
2529
- "tags": ["auth", "performance", "caching", "sessions"]
2530
- }]
2531
- }
2532
-
2533
- Be specific with tags. Use concrete technical terms. Extract ALL file paths mentioned.
2534
- Empty arrays are fine if nothing to extract.`;
2535
- var SignalExtractor = class {
2536
- client = null;
2537
- model;
2538
- constructor(model = "claude-3-haiku-20240307") {
2539
- this.model = model;
2540
- const apiKey = process.env.ANTHROPIC_API_KEY;
2541
- if (apiKey) {
2542
- this.client = new Anthropic({ apiKey });
2543
- }
2544
- }
2545
- /**
2546
- * Extract structured signals from raw content
2547
- */
2548
- async extract(content, sourceType, sourceId) {
2549
- if (!this.client) {
2550
- return this.basicExtraction(content, sourceType, sourceId);
2551
- }
2552
- try {
2553
- const response = await this.client.messages.create({
2554
- model: this.model,
2555
- max_tokens: 2048,
2556
- temperature: 0.3,
2557
- messages: [{
2558
- role: "user",
2559
- content: `${EXTRACTION_PROMPT}
2560
-
2561
- Content to analyze:
2562
- ${content}`
2563
- }]
2564
- });
2565
- const firstBlock = response.content[0];
2566
- const text = firstBlock && firstBlock.type === "text" ? firstBlock.text : "";
2567
- const extracted = this.parseExtraction(text);
2568
- const now = (/* @__PURE__ */ new Date()).toISOString();
2569
- const metadata = {
2570
- extractedAt: now,
2571
- sourceType,
2572
- extractionModel: this.model
2573
- };
2574
- if (sourceId !== void 0) {
2575
- metadata.sourceId = sourceId;
2576
- }
2577
- const signal = {
2578
- decisions: extracted.decisions.map((d, i) => ({
2579
- id: `dec-${Date.now()}-${i}`,
2580
- decision: d.decision || "",
2581
- context: d.context || "",
2582
- files: d.files || [],
2583
- tags: d.tags || [],
2584
- ...d,
2585
- when: now,
2586
- status: "active"
2587
- })),
2588
- facts: extracted.facts.map((f, i) => ({
2589
- id: `fact-${Date.now()}-${i}`,
2590
- fact: f.fact || "",
2591
- source: f.source || sourceType,
2592
- tags: f.tags || [],
2593
- confidence: f.confidence ?? 0.8,
2594
- ...f,
2595
- when: now
2596
- })),
2597
- blockers: extracted.blockers.map((b, i) => ({
2598
- id: `block-${Date.now()}-${i}`,
2599
- blocker: b.blocker || "",
2600
- impact: b.impact || "medium",
2601
- affectedAreas: b.affectedAreas || [],
2602
- tags: b.tags || [],
2603
- ...b,
2604
- when: now
2605
- })),
2606
- questions: extracted.questions.map((q, i) => ({
2607
- id: `q-${Date.now()}-${i}`,
2608
- question: q.question || "",
2609
- context: q.context || "",
2610
- tags: q.tags || [],
2611
- ...q,
2612
- when: now
2613
- })),
2614
- metadata
2615
- };
2616
- return signal;
2617
- } catch (error) {
2618
- console.error("Extraction failed, using basic extraction:", error);
2619
- return this.basicExtraction(content, sourceType, sourceId);
2620
- }
2621
- }
2622
- /**
2623
- * Parse extraction from model response
2624
- */
2625
- parseExtraction(text) {
2626
- try {
2627
- const jsonMatch = text.match(/\{[\s\S]*\}/);
2628
- if (jsonMatch) {
2629
- return JSON.parse(jsonMatch[0]);
2630
- }
2631
- } catch (e) {
2632
- }
2633
- return {
2634
- decisions: [],
2635
- facts: [],
2636
- blockers: [],
2637
- questions: []
2638
- };
2639
- }
2640
- /**
2641
- * Basic extraction without AI (fallback)
2642
- */
2643
- basicExtraction(content, sourceType, sourceId) {
2644
- const now = (/* @__PURE__ */ new Date()).toISOString();
2645
- const hasDecision = /\b(decided|decision|chose|picked)\b/i.test(content);
2646
- const hasBlocker = /\b(blocked|blocker|blocked by|can't|cannot|unable)\b/i.test(content);
2647
- const hasQuestion = /\?|what|how|why|should we/i.test(content);
2648
- const decisions = [];
2649
- const facts = [];
2650
- const blockers = [];
2651
- const questions = [];
2652
- if (hasDecision) {
2653
- decisions.push({
2654
- id: `dec-${Date.now()}`,
2655
- decision: content.substring(0, 200),
2656
- context: sourceType,
2657
- when: now,
2658
- files: [],
2659
- tags: [sourceType],
2660
- status: "active"
2661
- });
2662
- }
2663
- if (hasBlocker) {
2664
- blockers.push({
2665
- id: `block-${Date.now()}`,
2666
- blocker: content.substring(0, 200),
2667
- impact: "medium",
2668
- affectedAreas: [],
2669
- when: now,
2670
- tags: [sourceType]
2671
- });
2672
- }
2673
- if (hasQuestion) {
2674
- questions.push({
2675
- id: `q-${Date.now()}`,
2676
- question: content.substring(0, 200),
2677
- context: sourceType,
2678
- when: now,
2679
- tags: [sourceType]
2680
- });
2681
- }
2682
- const metadata = {
2683
- extractedAt: now,
2684
- sourceType,
2685
- extractionModel: "basic"
2686
- };
2687
- if (sourceId !== void 0) {
2688
- metadata.sourceId = sourceId;
2689
- }
2690
- return {
2691
- decisions,
2692
- facts,
2693
- blockers,
2694
- questions,
2695
- metadata
2696
- };
2697
- }
2698
- /**
2699
- * Extract from incident report (trie tell)
2700
- */
2701
- async extractFromIncident(incidentText) {
2702
- return this.extract(incidentText, "incident");
2703
- }
2704
- /**
2705
- * Extract from commit message and diff
2706
- */
2707
- async extractFromCommit(message, diff, commitId) {
2708
- const content = diff ? `${message}
2709
-
2710
- Changes:
2711
- ${diff}` : message;
2712
- return this.extract(content, "commit", commitId);
2713
- }
2714
- /**
2715
- * Extract from PR description and comments
2716
- */
2717
- async extractFromPR(title, description, comments, prNumber) {
2718
- const content = `
2719
- Title: ${title}
2720
-
2721
- Description:
2722
- ${description}
2723
-
2724
- Comments:
2725
- ${comments.join("\n\n")}
2726
- `.trim();
2727
- return this.extract(content, "pr", prNumber);
2728
- }
2729
- };
2730
-
2731
- // src/extraction/metadata-enricher.ts
2732
- var MetadataEnricher = class {
2733
- tagSynonyms;
2734
- constructor() {
2735
- this.tagSynonyms = this.initializeTagSynonyms();
2736
- }
2737
- /**
2738
- * Enrich an extracted signal with additional metadata
2739
- */
2740
- async enrichSignal(signal, context) {
2741
- const gitContext = {};
2742
- if (context?.gitBranch) gitContext.branch = context.gitBranch;
2743
- if (context?.gitCommit) gitContext.commit = context.gitCommit;
2744
- const metadata = {
2745
- relatedFiles: await this.findRelatedFiles(signal),
2746
- dependencies: await this.extractDependencies(signal),
2747
- expandedTags: this.expandTags(signal),
2748
- codebaseArea: this.inferCodebaseArea(signal),
2749
- domain: this.inferDomain(signal),
2750
- relatedDecisions: [],
2751
- // Will be populated by storage layer
2752
- extractedAt: (/* @__PURE__ */ new Date()).toISOString()
2753
- };
2754
- if (Object.keys(gitContext).length > 0) {
2755
- metadata.gitContext = gitContext;
2756
- }
2757
- return {
2758
- signal,
2759
- metadata
2760
- };
2761
- }
2762
- /**
2763
- * Expand tags with synonyms and related terms
2764
- * This is our "semantic" layer without embeddings
2765
- */
2766
- expandTags(signal) {
2767
- const allTags = /* @__PURE__ */ new Set();
2768
- for (const decision of signal.decisions) {
2769
- decision.tags.forEach((tag) => allTags.add(tag.toLowerCase()));
2770
- }
2771
- for (const fact of signal.facts) {
2772
- fact.tags.forEach((tag) => allTags.add(tag.toLowerCase()));
2773
- }
2774
- for (const blocker of signal.blockers) {
2775
- blocker.tags.forEach((tag) => allTags.add(tag.toLowerCase()));
2776
- }
2777
- for (const question of signal.questions) {
2778
- question.tags.forEach((tag) => allTags.add(tag.toLowerCase()));
2779
- }
2780
- const expandedTags = new Set(allTags);
2781
- for (const tag of allTags) {
2782
- const synonyms = this.tagSynonyms.get(tag) || [];
2783
- synonyms.forEach((syn) => expandedTags.add(syn));
2784
- }
2785
- return Array.from(expandedTags);
2786
- }
2787
- /**
2788
- * Find related files based on signal content
2789
- */
2790
- async findRelatedFiles(signal) {
2791
- const relatedFiles = /* @__PURE__ */ new Set();
2792
- for (const decision of signal.decisions) {
2793
- decision.files.forEach((file) => relatedFiles.add(file));
2794
- }
2795
- const inferredFiles = await this.inferFilesFromTags(signal);
2796
- inferredFiles.forEach((file) => relatedFiles.add(file));
2797
- return Array.from(relatedFiles);
2798
- }
2799
- /**
2800
- * Extract dependencies from signal
2801
- */
2802
- async extractDependencies(signal) {
2803
- const dependencies = /* @__PURE__ */ new Set();
2804
- const allText = [
2805
- ...signal.decisions.map((d) => `${d.decision} ${d.context} ${d.reasoning}`),
2806
- ...signal.facts.map((f) => `${f.fact} ${f.source}`)
2807
- ].join(" ");
2808
- const packagePatterns = [
2809
- /\b(react|vue|angular|next|express|fastify|stripe|bcrypt|jwt|redis|prisma)\b/gi
2810
- ];
2811
- for (const pattern of packagePatterns) {
2812
- const matches = allText.match(pattern) || [];
2813
- matches.forEach((dep) => dependencies.add(dep.toLowerCase()));
2814
- }
2815
- return Array.from(dependencies);
2816
- }
2817
- /**
2818
- * Infer codebase area from file paths and tags
2819
- */
2820
- inferCodebaseArea(signal) {
2821
- const areas = /* @__PURE__ */ new Set();
2822
- for (const decision of signal.decisions) {
2823
- for (const file of decision.files) {
2824
- const area = this.filePathToArea(file);
2825
- if (area) areas.add(area);
2826
- }
2827
- }
2828
- const areaKeywords = ["frontend", "backend", "api", "ui", "database", "auth", "payments"];
2829
- const allTags = this.expandTags(signal);
2830
- for (const tag of allTags) {
2831
- if (areaKeywords.includes(tag)) {
2832
- areas.add(tag);
2833
- }
2834
- }
2835
- return Array.from(areas);
2836
- }
2837
- /**
2838
- * Infer domain from tags and content
2839
- */
2840
- inferDomain(signal) {
2841
- const domains = /* @__PURE__ */ new Set();
2842
- const domainKeywords = [
2843
- "payments",
2844
- "billing",
2845
- "compliance",
2846
- "security",
2847
- "auth",
2848
- "analytics",
2849
- "notifications",
2850
- "messaging",
2851
- "search"
2852
- ];
2853
- const allTags = this.expandTags(signal);
2854
- for (const tag of allTags) {
2855
- if (domainKeywords.includes(tag)) {
2856
- domains.add(tag);
2857
- }
2858
- }
2859
- return Array.from(domains);
2860
- }
2861
- /**
2862
- * Convert file path to codebase area
2863
- */
2864
- filePathToArea(filePath) {
2865
- const normalized = filePath.toLowerCase();
2866
- if (normalized.includes("/frontend/") || normalized.includes("/client/") || normalized.includes("/ui/")) {
2867
- return "frontend";
2868
- }
2869
- if (normalized.includes("/backend/") || normalized.includes("/server/") || normalized.includes("/api/")) {
2870
- return "backend";
2871
- }
2872
- if (normalized.includes("/database/") || normalized.includes("/models/") || normalized.includes("/schema/")) {
2873
- return "database";
2874
- }
2875
- if (normalized.includes("/auth/")) {
2876
- return "auth";
2877
- }
2878
- return null;
2879
- }
2880
- /**
2881
- * Infer related files from tags
2882
- */
2883
- async inferFilesFromTags(_signal) {
2884
- return [];
2885
- }
2886
- /**
2887
- * Initialize tag synonyms and related terms
2888
- * This is our "semantic" understanding without embeddings
2889
- */
2890
- initializeTagSynonyms() {
2891
- return /* @__PURE__ */ new Map([
2892
- // Auth & Security
2893
- ["auth", ["authentication", "login", "signin", "credentials", "password"]],
2894
- ["password", ["credentials", "auth", "hashing", "bcrypt"]],
2895
- ["security", ["vulnerability", "exploit", "attack", "protection"]],
2896
- ["encryption", ["crypto", "hashing", "encoding", "security"]],
2897
- // Payments
2898
- ["payments", ["billing", "checkout", "stripe", "pricing"]],
2899
- ["stripe", ["payments", "billing", "api", "checkout"]],
2900
- ["vat", ["tax", "eu", "compliance", "billing"]],
2901
- // Database & Performance
2902
- ["database", ["db", "sql", "query", "storage", "persistence"]],
2903
- ["cache", ["caching", "redis", "memory", "performance"]],
2904
- ["performance", ["optimization", "speed", "latency", "cache"]],
2905
- // Frontend
2906
- ["ui", ["frontend", "interface", "component", "view"]],
2907
- ["component", ["ui", "react", "vue", "frontend"]],
2908
- ["validation", ["form", "input", "error", "ui"]],
2909
- // Backend & API
2910
- ["api", ["endpoint", "route", "backend", "server"]],
2911
- ["endpoint", ["api", "route", "url", "backend"]],
2912
- ["backend", ["server", "api", "service"]],
2913
- // Compliance & Legal
2914
- ["compliance", ["gdpr", "hipaa", "legal", "regulation"]],
2915
- ["gdpr", ["compliance", "privacy", "eu", "data-protection"]],
2916
- ["privacy", ["gdpr", "compliance", "data-protection", "security"]]
2917
- ]);
2918
- }
2919
- };
2920
-
2921
- // src/extraction/pipeline.ts
2922
- import { randomBytes } from "crypto";
2923
- var ExtractionPipeline = class {
2924
- extractor;
2925
- enricher;
2926
- storage;
2927
- workDir;
2928
- constructor(options) {
2929
- this.extractor = new SignalExtractor(options.anthropicApiKey);
2930
- this.enricher = new MetadataEnricher();
2931
- this.storage = getStorage(options.workingDirectory);
2932
- this.workDir = options.workingDirectory;
2933
- }
2934
- /**
2935
- * Process raw content through the entire pipeline
2936
- */
2937
- async process(content, context) {
2938
- console.log("\u{1F50D} Extracting signals from content...");
2939
- let extractedSignal = await this.extractor.extract(content, context.sourceType, context.sourceId);
2940
- extractedSignal = this.addIds(extractedSignal, context);
2941
- console.log(` \u2713 Extracted ${extractedSignal.decisions.length} decisions, ${extractedSignal.facts.length} facts, ${extractedSignal.blockers.length} blockers, ${extractedSignal.questions.length} questions`);
2942
- console.log("\u{1F3F7}\uFE0F Enriching with metadata...");
2943
- const { metadata: enrichedMeta } = await this.enricher.enrichSignal(extractedSignal, {
2944
- workingDirectory: this.workDir
2945
- });
2946
- if (enrichedMeta.expandedTags.length > 0) {
2947
- console.log(` \u2713 Expanded tags: ${enrichedMeta.expandedTags.slice(0, 5).join(", ")}${enrichedMeta.expandedTags.length > 5 ? "..." : ""}`);
2948
- }
2949
- if (enrichedMeta.dependencies.length > 0) {
2950
- console.log(` \u2713 Dependencies: ${enrichedMeta.dependencies.join(", ")}`);
2951
- }
2952
- if (enrichedMeta.codebaseArea.length > 0) {
2953
- console.log(` \u2713 Codebase areas: ${enrichedMeta.codebaseArea.join(", ")}`);
2954
- }
2955
- if (enrichedMeta.domain.length > 0) {
2956
- console.log(` \u2713 Domains: ${enrichedMeta.domain.join(", ")}`);
2957
- }
2958
- console.log("\u{1F4BE} Storing in decision ledger...");
2959
- await this.storage.storeSignal(extractedSignal, {
2960
- expandedTags: enrichedMeta.expandedTags,
2961
- dependencies: enrichedMeta.dependencies,
2962
- codebaseArea: enrichedMeta.codebaseArea,
2963
- domain: enrichedMeta.domain
2964
- });
2965
- console.log("\u2705 Successfully stored in decision ledger");
2966
- return extractedSignal;
2967
- }
2968
- /**
2969
- * Add IDs and metadata to extracted signal
2970
- */
2971
- addIds(signal, context) {
2972
- const now = (/* @__PURE__ */ new Date()).toISOString();
2973
- const metadata = {
2974
- extractedAt: now,
2975
- sourceType: context.sourceType,
2976
- extractionModel: "claude-haiku"
2977
- };
2978
- if (context.sourceId !== void 0) {
2979
- metadata.sourceId = context.sourceId;
2980
- }
2981
- return {
2982
- decisions: signal.decisions.map((d) => {
2983
- const decision = {
2984
- ...d,
2985
- id: d.id || this.generateId(),
2986
- when: d.when || now,
2987
- status: d.status || "active"
2988
- };
2989
- if (context.who !== void 0) {
2990
- decision.who = d.who || context.who;
2991
- }
2992
- return decision;
2993
- }),
2994
- facts: signal.facts.map((f) => ({
2995
- ...f,
2996
- id: f.id || this.generateId(),
2997
- when: f.when || now,
2998
- confidence: f.confidence ?? 0.8
2999
- })),
3000
- blockers: signal.blockers.map((b) => ({
3001
- ...b,
3002
- id: b.id || this.generateId(),
3003
- when: b.when || now
3004
- })),
3005
- questions: signal.questions.map((q) => ({
3006
- ...q,
3007
- id: q.id || this.generateId(),
3008
- when: q.when || now
3009
- })),
3010
- metadata
3011
- };
3012
- }
3013
- /**
3014
- * Generate a unique ID
3015
- */
3016
- generateId() {
3017
- return randomBytes(8).toString("hex");
3018
- }
3019
- /**
3020
- * Initialize storage
3021
- */
3022
- async initialize() {
3023
- await this.storage.initialize();
3024
- }
3025
- /**
3026
- * Close storage connections
3027
- */
3028
- close() {
3029
- this.storage.close();
1053
+ getHelpText() {
1054
+ return `
1055
+ ${"\u2501".repeat(60)}
1056
+ \u{1F9EA} TRIE TEST - AI-POWERED TEST GENERATION
1057
+ ${"\u2501".repeat(60)}
1058
+
1059
+ ## Usage
1060
+
1061
+ ### Generate tests:
1062
+ \`\`\`
1063
+ trie_test action:"generate" files:["src/utils.ts"]
1064
+ \`\`\`
1065
+
1066
+ ### Analyze coverage:
1067
+ \`\`\`
1068
+ trie_test action:"coverage" files:["src/utils.ts"]
1069
+ \`\`\`
1070
+
1071
+ ### Get test suggestions:
1072
+ \`\`\`
1073
+ trie_test action:"suggest" files:["src/app.ts"]
1074
+ \`\`\`
1075
+
1076
+ ### Get run commands:
1077
+ \`\`\`
1078
+ trie_test action:"run" files:["src/utils.test.ts"]
1079
+ \`\`\`
1080
+
1081
+ ## Options
1082
+
1083
+ | Option | Values | Description |
1084
+ |--------|--------|-------------|
1085
+ | action | generate, coverage, suggest, run | What to do |
1086
+ | files | Array of paths | Files to analyze |
1087
+ | framework | jest, vitest, mocha, pytest | Test framework |
1088
+ | style | unit, integration, e2e, all | Test style |
1089
+ `;
3030
1090
  }
3031
1091
  };
3032
- async function processIncident(incidentDescription, options) {
3033
- const pipeline = new ExtractionPipeline(options);
3034
- await pipeline.initialize();
3035
- try {
3036
- return await pipeline.process(incidentDescription, {
3037
- sourceType: "incident",
3038
- sourceId: `incident-${Date.now()}`
3039
- });
3040
- } finally {
3041
- pipeline.close();
3042
- }
3043
- }
3044
1092
 
3045
1093
  // src/tools/watch.ts
1094
+ import { watch, existsSync as existsSync3, readFileSync } from "fs";
1095
+ import { stat, readFile as readFile3 } from "fs/promises";
1096
+ import { join as join2, extname as extname3, basename as basename2 } from "path";
3046
1097
  var WATCH_EXTENSIONS = /* @__PURE__ */ new Set([
3047
1098
  ".ts",
3048
1099
  ".tsx",
@@ -3067,8 +1118,9 @@ var SKIP_DIRS = /* @__PURE__ */ new Set([
3067
1118
  ".turbo",
3068
1119
  ".cache"
3069
1120
  ]);
3070
- var TrieWatchTool = class {
1121
+ var TrieWatchTool = class _TrieWatchTool {
3071
1122
  extractionPipeline = null;
1123
+ static DEFAULT_HOURLY_TOKEN_LIMIT = 5e4;
3072
1124
  state = {
3073
1125
  isRunning: false,
3074
1126
  lastScan: /* @__PURE__ */ new Map(),
@@ -3076,13 +1128,18 @@ var TrieWatchTool = class {
3076
1128
  scanDebounceTimer: null,
3077
1129
  issueCache: /* @__PURE__ */ new Map(),
3078
1130
  totalIssuesFound: 0,
3079
- // Autonomy state
3080
- lastAutoCheck: 0,
3081
- autoCheckInProgress: false,
3082
- criticalIssueCount: 0,
3083
1131
  filesScanned: 0,
3084
1132
  nudgedFiles: /* @__PURE__ */ new Set(),
3085
- nudges: []
1133
+ nudges: [],
1134
+ lastAutoScan: 0,
1135
+ autoScanInProgress: false,
1136
+ tokenBudget: {
1137
+ used: 0,
1138
+ windowStart: Date.now(),
1139
+ hourlyLimit: _TrieWatchTool.DEFAULT_HOURLY_TOKEN_LIMIT,
1140
+ scansSaved: 0
1141
+ },
1142
+ cleanFiles: /* @__PURE__ */ new Map()
3086
1143
  };
3087
1144
  watchers = /* @__PURE__ */ new Map();
3088
1145
  streamingManager = void 0;
@@ -3204,17 +1261,17 @@ Your Trie agent is now autonomously watching and learning from your codebase.
3204
1261
  return parts.some((p) => SKIP_DIRS.has(p) || p.startsWith(".") && p !== ".");
3205
1262
  }
3206
1263
  async watchDirectory(dir, debounceMs) {
3207
- if (!existsSync4(dir)) return;
1264
+ if (!existsSync3(dir)) return;
3208
1265
  try {
3209
1266
  const dirStat = await stat(dir);
3210
1267
  if (!dirStat.isDirectory()) return;
3211
1268
  const watcher = watch(dir, { persistent: true, recursive: true }, (_eventType, filename) => {
3212
1269
  if (!filename) return;
3213
1270
  if (this.shouldSkipPath(filename)) return;
3214
- const ext = extname4(filename).toLowerCase();
1271
+ const ext = extname3(filename).toLowerCase();
3215
1272
  if (!WATCH_EXTENSIONS.has(ext)) return;
3216
1273
  const fullPath = join2(dir, filename);
3217
- if (!existsSync4(fullPath)) return;
1274
+ if (!existsSync3(fullPath)) return;
3218
1275
  this.state.pendingFiles.add(fullPath);
3219
1276
  if (this.state.scanDebounceTimer) {
3220
1277
  clearTimeout(this.state.scanDebounceTimer);
@@ -3257,7 +1314,7 @@ Detected changes in ${files.length} file(s):`);
3257
1314
  const fileContents = await Promise.all(
3258
1315
  files.map(async (file) => {
3259
1316
  try {
3260
- const content = await readFile4(file, "utf-8");
1317
+ const content = await readFile3(file, "utf-8");
3261
1318
  return { file, content };
3262
1319
  } catch {
3263
1320
  return null;
@@ -3290,9 +1347,6 @@ ${f.content.slice(0, 1e3)}`
3290
1347
  questions: signal.questions.length
3291
1348
  });
3292
1349
  }
3293
- if (signal.blockers.length > 0 && !this.isQuiet()) {
3294
- this.maybeAutoCheck(files);
3295
- }
3296
1350
  }
3297
1351
  }
3298
1352
  } catch (error) {
@@ -3301,6 +1355,9 @@ ${f.content.slice(0, 1e3)}`
3301
1355
  }
3302
1356
  }
3303
1357
  }
1358
+ if (!this.isQuiet()) {
1359
+ this.autoScanFiles(files);
1360
+ }
3304
1361
  if (this.streamingManager) {
3305
1362
  for (const file of files) {
3306
1363
  this.streamingManager.reportWatchChange(file);
@@ -3328,75 +1385,179 @@ ${f.content.slice(0, 1e3)}`
3328
1385
  return false;
3329
1386
  }
3330
1387
  }
1388
+ static AUTO_SCAN_COOLDOWN_MS = 3e4;
1389
+ static CLEAN_FILE_COOLDOWN_MS = 3e5;
1390
+ // skip files clean-scanned in last 5 min
3331
1391
  /**
3332
- * Auto-run gotcha prediction on changed files
3333
- * Respects cooldown and autonomy config
1392
+ * Use the trie (context graph) to score how urgently a file needs scanning.
1393
+ * Higher score = more worth spending tokens on.
3334
1394
  */
3335
- async maybeAutoCheck(triggerFiles) {
3336
- if (this.state.autoCheckInProgress) return;
3337
- const projectPath = getWorkingDirectory(void 0, true);
1395
+ async scoreScanPriority(file, graph, projectPath) {
1396
+ let score = 1;
1397
+ const lastClean = this.state.cleanFiles.get(file);
1398
+ if (lastClean && Date.now() - lastClean < _TrieWatchTool.CLEAN_FILE_COOLDOWN_MS) {
1399
+ return 0;
1400
+ }
1401
+ const fileNode = await graph.getNode("file", join2(projectPath, file));
1402
+ if (!fileNode) return score;
1403
+ const data = fileNode.data;
1404
+ const riskScores = { critical: 10, high: 6, medium: 2, low: 1 };
1405
+ score += riskScores[data.riskLevel] ?? 1;
1406
+ score += Math.min(data.incidentCount * 3, 12);
1407
+ if (data.changeCount > 10) score += 2;
1408
+ return score;
1409
+ }
1410
+ /**
1411
+ * Roll the token budget window if an hour has passed.
1412
+ * Returns remaining tokens in the current window.
1413
+ */
1414
+ getRemainingBudget() {
1415
+ const budget = this.state.tokenBudget;
1416
+ const elapsed = Date.now() - budget.windowStart;
1417
+ if (elapsed > 36e5) {
1418
+ budget.used = 0;
1419
+ budget.windowStart = Date.now();
1420
+ }
1421
+ return Math.max(0, budget.hourlyLimit - budget.used);
1422
+ }
1423
+ recordTokenUsage(tokens) {
1424
+ this.state.tokenBudget.used += tokens;
1425
+ }
1426
+ /**
1427
+ * AI-powered auto-scan, throttled by the trie.
1428
+ * Uses context graph risk data to decide which files are worth spending tokens on.
1429
+ */
1430
+ async autoScanFiles(files) {
1431
+ if (!isAIAvailable()) return;
1432
+ if (this.state.autoScanInProgress) return;
1433
+ const now = Date.now();
1434
+ if (now - this.state.lastAutoScan < _TrieWatchTool.AUTO_SCAN_COOLDOWN_MS) return;
1435
+ const remaining = this.getRemainingBudget();
1436
+ if (remaining < 500) return;
1437
+ this.state.autoScanInProgress = true;
1438
+ this.state.lastAutoScan = now;
3338
1439
  try {
3339
- const config = await getAutonomyConfig(projectPath);
3340
- if (!config.autoCheck.enabled) return;
3341
- const now = Date.now();
3342
- if (now - this.state.lastAutoCheck < config.autoCheck.cooldownMs) {
3343
- return;
1440
+ const projectPath = getWorkingDirectory(void 0, true);
1441
+ const graph = new ContextGraph(projectPath);
1442
+ const scored = [];
1443
+ for (const file of files) {
1444
+ const relativePath = file.replace(projectPath + "/", "");
1445
+ const score = await this.scoreScanPriority(relativePath, graph, projectPath);
1446
+ if (score > 0) {
1447
+ scored.push({ file, relativePath, score });
1448
+ } else {
1449
+ this.state.tokenBudget.scansSaved++;
1450
+ }
3344
1451
  }
3345
- const shouldRun = config.autoCheck.onCritical || this.state.criticalIssueCount >= config.autoCheck.threshold;
3346
- if (!shouldRun) return;
3347
- this.state.autoCheckInProgress = true;
3348
- this.state.lastAutoCheck = now;
3349
- getOutputManager().nudge(
3350
- "[*] Auto-running full check due to critical issues...",
3351
- "info",
3352
- void 0,
3353
- 5e3
1452
+ if (scored.length === 0) return;
1453
+ scored.sort((a, b) => b.score - a.score);
1454
+ const maxFiles = remaining > 2e4 ? 5 : remaining > 1e4 ? 3 : 1;
1455
+ const toScan = scored.slice(0, maxFiles);
1456
+ const fileContents = await Promise.all(
1457
+ toScan.map(async ({ file, relativePath }) => {
1458
+ try {
1459
+ const content = await readFile3(file, "utf-8");
1460
+ return { path: relativePath, content: content.slice(0, 3e3) };
1461
+ } catch {
1462
+ return null;
1463
+ }
1464
+ })
3354
1465
  );
3355
- const perception = await perceiveCurrentChanges(projectPath);
3356
- const allFiles = perception.diffSummary.files.map((f) => f.filePath);
3357
- const filesToCheck = allFiles.length > 0 ? allFiles : triggerFiles;
3358
- const reasoning = await reasonAboutChangesHumanReadable(projectPath, filesToCheck, {
3359
- runAgents: true,
3360
- scanContext: {
3361
- config: { timeoutMs: 3e4 }
3362
- }
1466
+ const valid = fileContents.filter(Boolean);
1467
+ if (valid.length === 0) return;
1468
+ const filesBlock = valid.map(
1469
+ (f) => `### ${f.path}
1470
+ \`\`\`
1471
+ ${f.content}
1472
+ \`\`\``
1473
+ ).join("\n\n");
1474
+ const result = await runAIAnalysis({
1475
+ systemPrompt: `You are a code reviewer. Analyze the changed files below for bugs, security issues, logic errors, or risky patterns.
1476
+
1477
+ Reply ONLY with a JSON array of issues found. Each issue must have:
1478
+ - "file": relative file path
1479
+ - "severity": "critical" | "major" | "minor"
1480
+ - "description": 1-sentence description of the problem
1481
+
1482
+ If there are no issues, reply with an empty array: []
1483
+
1484
+ Do NOT include markdown fences or commentary. Output ONLY the JSON array.`,
1485
+ userPrompt: `Review these recently changed files:
1486
+
1487
+ ${filesBlock}`,
1488
+ maxTokens: 1024,
1489
+ temperature: 0.2
3363
1490
  });
3364
- if (reasoning.original?.files) {
3365
- for (const file of reasoning.original.files) {
3366
- if (file.level === "critical" || file.level === "high") {
3367
- await trackIssueOccurrence(
3368
- projectPath,
3369
- file.file,
3370
- void 0,
3371
- file.level,
3372
- config
3373
- );
3374
- }
1491
+ if (result.tokensUsed) {
1492
+ this.recordTokenUsage(result.tokensUsed.input + result.tokensUsed.output);
1493
+ }
1494
+ if (!result.success || !result.content.trim()) return;
1495
+ let issues = [];
1496
+ try {
1497
+ const cleaned = result.content.replace(/```json?\n?|\n?```/g, "").trim();
1498
+ issues = JSON.parse(cleaned);
1499
+ if (!Array.isArray(issues)) issues = [];
1500
+ } catch {
1501
+ return;
1502
+ }
1503
+ const issuedFiles = new Set(issues.map((i) => i.file));
1504
+ for (const { relativePath } of toScan) {
1505
+ if (!issuedFiles.has(relativePath)) {
1506
+ this.state.cleanFiles.set(relativePath, Date.now());
3375
1507
  }
3376
1508
  }
3377
- const riskLevel = reasoning.original?.riskLevel || "low";
3378
- const shouldBlock = reasoning.original?.shouldBlock || false;
3379
- if (shouldBlock) {
3380
- getOutputManager().nudge(
3381
- `[STOP] Auto-check complete: ${riskLevel.toUpperCase()} risk detected. Fix issues before pushing.`,
3382
- "critical",
3383
- void 0,
3384
- void 0
3385
- // Keep visible
3386
- );
3387
- } else {
3388
- getOutputManager().nudge(
3389
- `[OK] Auto-check complete: ${riskLevel} risk. ${reasoning.summary || ""}`,
3390
- riskLevel === "low" ? "info" : "warning",
3391
- void 0,
3392
- 1e4
3393
- );
1509
+ if (issues.length === 0) return;
1510
+ for (const issue of issues.slice(0, 5)) {
1511
+ const severity = issue.severity === "critical" ? "critical" : issue.severity === "major" ? "major" : "minor";
1512
+ const incident = await graph.addNode("incident", {
1513
+ description: issue.description,
1514
+ severity,
1515
+ affectedUsers: null,
1516
+ duration: null,
1517
+ timestamp: (/* @__PURE__ */ new Date()).toISOString(),
1518
+ resolved: false,
1519
+ resolution: null,
1520
+ fixChangeId: null,
1521
+ reportedVia: "detected"
1522
+ });
1523
+ const filePath = join2(projectPath, issue.file);
1524
+ const fileNode = await graph.getNode("file", filePath);
1525
+ if (fileNode) {
1526
+ await graph.addEdge(fileNode.id, incident.id, "affects");
1527
+ const data = fileNode.data;
1528
+ const newRisk = severity === "critical" ? "critical" : severity === "major" ? "high" : data.riskLevel === "low" ? "medium" : data.riskLevel;
1529
+ await graph.updateNode("file", fileNode.id, {
1530
+ incidentCount: (data.incidentCount ?? 0) + 1,
1531
+ riskLevel: newRisk
1532
+ });
1533
+ }
1534
+ this.state.totalIssuesFound++;
1535
+ if (severity !== "minor") {
1536
+ getOutputManager().nudge(
1537
+ `[!] ${issue.description}`,
1538
+ severity === "critical" ? "critical" : "warning",
1539
+ issue.file,
1540
+ severity === "critical" ? void 0 : 15e3
1541
+ );
1542
+ this.state.nudges.push({
1543
+ file: basename2(issue.file),
1544
+ message: issue.description,
1545
+ severity: severity === "critical" ? "critical" : "high",
1546
+ timestamp: (/* @__PURE__ */ new Date()).toLocaleTimeString("en-US", { hour12: false })
1547
+ });
1548
+ }
3394
1549
  }
3395
- this.state.criticalIssueCount = 0;
3396
- } catch (error) {
3397
- console.error("Auto-check failed:", error);
1550
+ if (this.streamingManager && issues.length > 0) {
1551
+ this.streamingManager.reportSignalExtraction({
1552
+ decisions: 0,
1553
+ facts: 0,
1554
+ blockers: issues.length,
1555
+ questions: 0
1556
+ });
1557
+ }
1558
+ } catch {
3398
1559
  } finally {
3399
- this.state.autoCheckInProgress = false;
1560
+ this.state.autoScanInProgress = false;
3400
1561
  }
3401
1562
  }
3402
1563
  stopWatching() {
@@ -3433,19 +1594,21 @@ ${f.content.slice(0, 1e3)}`
3433
1594
  this.dashboard.stop();
3434
1595
  this.dashboard = void 0;
3435
1596
  }
1597
+ const budget = this.state.tokenBudget;
1598
+ const tokensK = (budget.used / 1e3).toFixed(1);
3436
1599
  return {
3437
1600
  content: [{
3438
1601
  type: "text",
3439
- text: `[*] **TRIE AGENT STOPPED** \u{1F916}
1602
+ text: `[*] **TRIE AGENT STOPPED**
3440
1603
 
3441
1604
  ### Session Summary:
3442
1605
  - Files scanned: ${this.state.filesScanned}
3443
- - Total issues found: ${this.state.totalIssuesFound}
3444
- - Directories watched: ${this.watchers.size}
1606
+ - Issues found: ${this.state.totalIssuesFound}
1607
+ - Tokens used: ${tokensK}k / ${(budget.hourlyLimit / 1e3).toFixed(0)}k hourly limit
1608
+ - Scans skipped (trie-throttled): ${budget.scansSaved}
3445
1609
  - Decision ledger: Updated continuously
3446
1610
 
3447
- The agent's learning has been stored in the decision ledger.
3448
- Use \`trie_watch start\` to resume autonomous operation.`
1611
+ Use \`trie_watch start\` to resume.`
3449
1612
  }]
3450
1613
  };
3451
1614
  }
@@ -3469,7 +1632,7 @@ Use \`trie_watch start\` to begin autonomous scanning.`
3469
1632
  ).join("\n");
3470
1633
  let agencyStatus = "";
3471
1634
  try {
3472
- const { getGuardian } = await import("./guardian-agent-4UJN5QGX.js");
1635
+ const { getGuardian } = await import("./guardian-agent-XEYNG7RH.js");
3473
1636
  const trieAgent = getGuardian(getWorkingDirectory(void 0, true));
3474
1637
  await trieAgent.initialize();
3475
1638
  const status = await trieAgent.getAgencyStatus();
@@ -3482,6 +1645,10 @@ Use \`trie_watch start\` to begin autonomous scanning.`
3482
1645
  - **Scan Frequency:** ${Math.round(status.scanFrequency / 1e3)}s${status.isQuietHours ? " (quiet hours)" : ""}`;
3483
1646
  } catch {
3484
1647
  }
1648
+ const budget = this.state.tokenBudget;
1649
+ const remaining = this.getRemainingBudget();
1650
+ const tokensK = (budget.used / 1e3).toFixed(1);
1651
+ const remainingK = (remaining / 1e3).toFixed(1);
3485
1652
  return {
3486
1653
  content: [{
3487
1654
  type: "text",
@@ -3489,9 +1656,14 @@ Use \`trie_watch start\` to begin autonomous scanning.`
3489
1656
 
3490
1657
  ### Stats:
3491
1658
  - Directories watched: ${this.watchers.size}
3492
- - Files scanned this session: ${this.state.filesScanned}
3493
- - Total issues found: ${this.state.totalIssuesFound}
3494
- - Pending files: ${this.state.pendingFiles.size}
1659
+ - Files scanned: ${this.state.filesScanned}
1660
+ - Issues found: ${this.state.totalIssuesFound}
1661
+ - Pending: ${this.state.pendingFiles.size}
1662
+
1663
+ ### Token Budget:
1664
+ - Used: ${tokensK}k / ${(budget.hourlyLimit / 1e3).toFixed(0)}k hourly
1665
+ - Remaining: ${remainingK}k
1666
+ - Scans skipped (trie-throttled): ${budget.scansSaved}
3495
1667
  ${agencyStatus}
3496
1668
 
3497
1669
  ### Recently Scanned:
@@ -3502,7 +1674,6 @@ ${recentNudges || "(none)"}
3502
1674
 
3503
1675
  ### Commands:
3504
1676
  - \`trie_watch issues\` - Get all issues found
3505
- - \`trie_watch nudges\` - Get recent nudges (structured)
3506
1677
  - \`trie_watch stop\` - Stop watching`
3507
1678
  }]
3508
1679
  };
@@ -3541,9 +1712,9 @@ To get a full report, run \`trie_scan\` on your codebase.`
3541
1712
  };
3542
1713
 
3543
1714
  // src/tools/pr-review.ts
3544
- import { readFile as readFile5 } from "fs/promises";
3545
- import { existsSync as existsSync5 } from "fs";
3546
- import { join as join3, basename as basename3, resolve as resolve4, isAbsolute as isAbsolute4 } from "path";
1715
+ import { readFile as readFile4 } from "fs/promises";
1716
+ import { existsSync as existsSync4 } from "fs";
1717
+ import { join as join3, basename as basename3, resolve as resolve3, isAbsolute as isAbsolute3 } from "path";
3547
1718
 
3548
1719
  // src/skills/built-in/super-reviewer.ts
3549
1720
  var CRITICAL_REVIEW_CHECKLIST = {
@@ -3656,8 +1827,8 @@ Usage:
3656
1827
  */
3657
1828
  async getPRInfo(pr, worktree) {
3658
1829
  if (worktree) {
3659
- const worktreePath = isAbsolute4(worktree) ? worktree : resolve4(getWorkingDirectory(void 0, true), worktree);
3660
- if (!existsSync5(worktreePath)) {
1830
+ const worktreePath = isAbsolute3(worktree) ? worktree : resolve3(getWorkingDirectory(void 0, true), worktree);
1831
+ if (!existsSync4(worktreePath)) {
3661
1832
  return { success: false, error: `Worktree not found: ${worktreePath}` };
3662
1833
  }
3663
1834
  return {
@@ -3757,7 +1928,7 @@ Usage:
3757
1928
  const headerLine = lines[0] || "";
3758
1929
  const pathMatch = headerLine.match(/a\/(.+?) b\/(.+)/);
3759
1930
  if (!pathMatch || !pathMatch[2]) continue;
3760
- const path3 = pathMatch[2];
1931
+ const path2 = pathMatch[2];
3761
1932
  const diff = `diff --git ${fileDiff}`;
3762
1933
  let additions = 0;
3763
1934
  let deletions = 0;
@@ -3768,7 +1939,7 @@ Usage:
3768
1939
  deletions++;
3769
1940
  }
3770
1941
  }
3771
- files.push({ path: path3, diff, additions, deletions, status: "modified" });
1942
+ files.push({ path: path2, diff, additions, deletions, status: "modified" });
3772
1943
  }
3773
1944
  return files;
3774
1945
  }
@@ -3791,7 +1962,7 @@ Usage:
3791
1962
  ];
3792
1963
  for (const docPath of designDocPaths) {
3793
1964
  const fullPath = join3(cwd, docPath);
3794
- if (existsSync5(fullPath)) {
1965
+ if (existsSync4(fullPath)) {
3795
1966
  }
3796
1967
  }
3797
1968
  return designDocs;
@@ -3804,9 +1975,9 @@ Usage:
3804
1975
  const cwd = getWorkingDirectory(void 0, true);
3805
1976
  await Promise.all(filePaths.map(async (filePath) => {
3806
1977
  try {
3807
- const fullPath = isAbsolute4(filePath) ? filePath : join3(cwd, filePath);
3808
- if (existsSync5(fullPath)) {
3809
- const content = await readFile5(fullPath, "utf-8");
1978
+ const fullPath = isAbsolute3(filePath) ? filePath : join3(cwd, filePath);
1979
+ if (existsSync4(fullPath)) {
1980
+ const content = await readFile4(fullPath, "utf-8");
3810
1981
  contents.set(filePath, content);
3811
1982
  }
3812
1983
  } catch {
@@ -4585,216 +2756,8 @@ var TrieMemorySearchTool = class {
4585
2756
  }
4586
2757
  };
4587
2758
 
4588
- // src/tools/checkpoint.ts
4589
- async function handleCheckpointTool(input) {
4590
- const workDir = getWorkingDirectory(void 0, true);
4591
- switch (input.action) {
4592
- case "save": {
4593
- const saveOptions = {
4594
- files: input.files || [],
4595
- workDir,
4596
- createdBy: "mcp"
4597
- };
4598
- if (input.message !== void 0) {
4599
- saveOptions.message = input.message;
4600
- }
4601
- if (input.notes !== void 0) {
4602
- saveOptions.notes = input.notes;
4603
- }
4604
- const checkpoint = await saveCheckpoint(saveOptions);
4605
- return `# Checkpoint Saved
4606
-
4607
- **ID:** ${checkpoint.id}
4608
- **Time:** ${checkpoint.timestamp}
4609
- ${checkpoint.message ? `**Message:** ${checkpoint.message}` : ""}
4610
- ${checkpoint.notes ? `**Notes:** ${checkpoint.notes}` : ""}
4611
- ${checkpoint.files.length > 0 ? `**Files:** ${checkpoint.files.join(", ")}` : ""}
4612
-
4613
- Context saved to \`.trie/\`. This checkpoint will be visible in other tools (Cursor, Claude Code, CLI).`;
4614
- }
4615
- case "list": {
4616
- const checkpoints = await listCheckpoints(workDir);
4617
- if (checkpoints.length === 0) {
4618
- return 'No checkpoints yet. Use `trie_checkpoint action="save"` to create one.';
4619
- }
4620
- const lines = ["# Recent Checkpoints", ""];
4621
- for (const cp of checkpoints.slice(-10).reverse()) {
4622
- const date = new Date(cp.timestamp).toLocaleString();
4623
- lines.push(`- **${cp.id}** (${date}): ${cp.message || "(no message)"}`);
4624
- }
4625
- return lines.join("\n");
4626
- }
4627
- case "last": {
4628
- const checkpoint = await getLastCheckpoint(workDir);
4629
- if (!checkpoint) {
4630
- return 'No checkpoints yet. Use `trie_checkpoint action="save"` to create one.';
4631
- }
4632
- return `# Last Checkpoint
4633
-
4634
- **ID:** ${checkpoint.id}
4635
- **Time:** ${new Date(checkpoint.timestamp).toLocaleString()}
4636
- ${checkpoint.message ? `**Message:** ${checkpoint.message}` : ""}
4637
- ${checkpoint.notes ? `**Notes:** ${checkpoint.notes}` : ""}
4638
- ${checkpoint.files.length > 0 ? `**Files:** ${checkpoint.files.join(", ")}` : ""}
4639
- **Created by:** ${checkpoint.createdBy}`;
4640
- }
4641
- default:
4642
- return "Unknown action. Use: save, list, or last";
4643
- }
4644
- }
4645
-
4646
- // src/tools/check.ts
4647
- var TrieCheckTool = class {
4648
- async execute(input = {}) {
4649
- try {
4650
- const workDir = input.directory || getWorkingDirectory(void 0, true);
4651
- let files = input.files;
4652
- if (!files || files.length === 0) {
4653
- const perception = await perceiveCurrentChanges(workDir);
4654
- files = perception.diffSummary.files.map((f) => f.filePath);
4655
- }
4656
- if (!files || files.length === 0) {
4657
- return {
4658
- content: [{
4659
- type: "text",
4660
- text: "No changes detected. Provide files or make a change."
4661
- }]
4662
- };
4663
- }
4664
- const mode = input.mode ?? "full";
4665
- const runAgents = mode === "full";
4666
- const reasoning = await reasonAboutChangesHumanReadable(workDir, files, {
4667
- runAgents,
4668
- scanContext: { config: { timeoutMs: mode === "quick" ? 15e3 : 6e4 } }
4669
- });
4670
- const summary = [
4671
- `Risk: ${reasoning.original.riskLevel.toUpperCase()} (${reasoning.original.shouldBlock ? "block" : "allow"})`,
4672
- `Explanation: ${reasoning.original.explanation}`,
4673
- `Recommendation: ${reasoning.original.recommendation}`,
4674
- `Plain summary: ${reasoning.summary}`,
4675
- `What I found: ${reasoning.whatIFound}`,
4676
- `How bad: ${reasoning.howBad}`,
4677
- `What to do: ${reasoning.whatToDo}`
4678
- ].join("\n");
4679
- return {
4680
- content: [{
4681
- type: "text",
4682
- text: summary
4683
- }]
4684
- };
4685
- } catch (error) {
4686
- const friendly = formatFriendlyError(error);
4687
- return { content: [{ type: "text", text: friendly.userMessage }] };
4688
- }
4689
- }
4690
- };
4691
-
4692
- // src/tools/tell.ts
4693
- import path from "path";
4694
- function escalateRisk(level) {
4695
- if (level === "low") return "medium";
4696
- if (level === "medium") return "high";
4697
- if (level === "high") return "critical";
4698
- return "critical";
4699
- }
4700
- function extractFilePathsFromDescription(description) {
4701
- const matches = description.match(/[\\w./_-]+\\.(ts|tsx|js|jsx|mjs|cjs)/gi);
4702
- if (!matches) return [];
4703
- const unique = /* @__PURE__ */ new Set();
4704
- matches.forEach((m) => unique.add(m.replace(/^\.\/+/, "")));
4705
- return Array.from(unique);
4706
- }
4707
- var TrieTellTool = class {
4708
- async execute(input) {
4709
- try {
4710
- const description = input.description?.trim();
4711
- if (!description) {
4712
- return { content: [{ type: "text", text: "description is required" }] };
4713
- }
4714
- const projectPath = input.directory || getWorkingDirectory(void 0, true);
4715
- const graph = new ContextGraph(projectPath);
4716
- const now = (/* @__PURE__ */ new Date()).toISOString();
4717
- const change = (await graph.getRecentChanges(1))[0];
4718
- const linkedFiles = /* @__PURE__ */ new Set();
4719
- console.log("\n\u{1F9E0} Processing incident with signal extraction...");
4720
- let extractedSignal = null;
4721
- try {
4722
- const apiKey = process.env.ANTHROPIC_API_KEY;
4723
- const options = {
4724
- workingDirectory: projectPath
4725
- };
4726
- if (apiKey) {
4727
- options.anthropicApiKey = apiKey;
4728
- }
4729
- extractedSignal = await processIncident(description, options);
4730
- } catch (error) {
4731
- console.warn("\u26A0\uFE0F Signal extraction failed, continuing with basic incident tracking:", error);
4732
- }
4733
- const incident = await graph.addNode("incident", {
4734
- description,
4735
- severity: "major",
4736
- affectedUsers: null,
4737
- duration: null,
4738
- timestamp: now,
4739
- resolved: false,
4740
- resolution: null,
4741
- fixChangeId: change?.id ?? null,
4742
- reportedVia: "manual"
4743
- });
4744
- if (change) {
4745
- await graph.addEdge(change.id, incident.id, "leadTo");
4746
- await graph.addEdge(incident.id, change.id, "causedBy");
4747
- for (const filePath of change.data.files) {
4748
- linkedFiles.add(filePath);
4749
- const fileNode = await graph.getNode("file", path.resolve(projectPath, filePath));
4750
- if (fileNode) {
4751
- const data = fileNode.data;
4752
- await graph.updateNode("file", fileNode.id, {
4753
- incidentCount: (data.incidentCount ?? 0) + 1,
4754
- riskLevel: escalateRisk(data.riskLevel)
4755
- });
4756
- }
4757
- }
4758
- }
4759
- const mentionedFiles = extractFilePathsFromDescription(description);
4760
- mentionedFiles.forEach((f) => linkedFiles.add(f));
4761
- if (extractedSignal) {
4762
- for (const decision of extractedSignal.decisions) {
4763
- decision.files.forEach((f) => linkedFiles.add(f));
4764
- }
4765
- }
4766
- const incidentIndex = new IncidentIndex(graph, projectPath);
4767
- incidentIndex.addIncidentToTrie(incident, Array.from(linkedFiles));
4768
- await exportToJson(graph);
4769
- let responseText = `Incident recorded${change ? ` and linked to change ${change.id}` : ""}.`;
4770
- if (extractedSignal) {
4771
- const counts = [
4772
- extractedSignal.decisions.length > 0 ? `${extractedSignal.decisions.length} decision(s)` : null,
4773
- extractedSignal.facts.length > 0 ? `${extractedSignal.facts.length} fact(s)` : null,
4774
- extractedSignal.blockers.length > 0 ? `${extractedSignal.blockers.length} blocker(s)` : null,
4775
- extractedSignal.questions.length > 0 ? `${extractedSignal.questions.length} question(s)` : null
4776
- ].filter(Boolean).join(", ");
4777
- if (counts) {
4778
- responseText += `
4779
-
4780
- \u{1F4CA} Extracted and stored: ${counts}`;
4781
- }
4782
- }
4783
- return {
4784
- content: [{
4785
- type: "text",
4786
- text: responseText
4787
- }]
4788
- };
4789
- } catch (error) {
4790
- const friendly = formatFriendlyError(error);
4791
- return { content: [{ type: "text", text: friendly.userMessage }] };
4792
- }
4793
- }
4794
- };
4795
-
4796
2759
  // src/tools/reconcile.ts
4797
- import path2 from "path";
2760
+ import path from "path";
4798
2761
  async function removeOrphanEdges(graph) {
4799
2762
  const nodes = await graph.listNodes();
4800
2763
  const ids = new Set(nodes.map((n) => n.id));
@@ -4812,7 +2775,7 @@ var TrieReconcileTool = class {
4812
2775
  async execute(input = {}) {
4813
2776
  try {
4814
2777
  const projectPath = input.directory || getWorkingDirectory(void 0, true);
4815
- const sourcePath = input.source ?? path2.join(getTrieDirectory(projectPath), "context.json");
2778
+ const sourcePath = input.source ?? path.join(getTrieDirectory(projectPath), "context.json");
4816
2779
  const graph = new ContextGraph(projectPath);
4817
2780
  await importFromJson(graph, "", sourcePath);
4818
2781
  const removed = await removeOrphanEdges(graph);
@@ -4852,33 +2815,6 @@ var TrieContextTool = class {
4852
2815
  }
4853
2816
  };
4854
2817
 
4855
- // src/tools/feedback.ts
4856
- var TrieFeedbackTool = class {
4857
- async execute(input) {
4858
- try {
4859
- const projectPath = input.directory || getWorkingDirectory(void 0, true);
4860
- const graph = new ContextGraph(projectPath);
4861
- const engine = new LearningEngine(projectPath, graph);
4862
- const files = input.files || (input.target ? [input.target] : []);
4863
- const manualFeedback = {
4864
- helpful: input.helpful,
4865
- files,
4866
- ...input.note !== void 0 ? { note: input.note } : {}
4867
- };
4868
- await engine.learn({ manualFeedback });
4869
- return {
4870
- content: [{
4871
- type: "text",
4872
- text: input.helpful ? "\u{1F44D} Thanks \u2014 I will prioritize more responses like this." : "\u{1F44E} Understood \u2014 I will adjust future guidance."
4873
- }]
4874
- };
4875
- } catch (error) {
4876
- const friendly = formatFriendlyError(error);
4877
- return { content: [{ type: "text", text: friendly.userMessage }] };
4878
- }
4879
- }
4880
- };
4881
-
4882
2818
  // src/tools/linear-sync.ts
4883
2819
  var LinearSyncTool = class {
4884
2820
  async execute(input) {
@@ -4905,178 +2841,6 @@ var LinearSyncTool = class {
4905
2841
  }
4906
2842
  };
4907
2843
 
4908
- // src/tools/query-tools.ts
4909
- var TrieGetDecisionsTool = class {
4910
- async execute(input) {
4911
- const workDir = input.directory || getWorkingDirectory(void 0, true);
4912
- const storage = getStorage(workDir);
4913
- await storage.initialize();
4914
- let timeWindow;
4915
- if (input.since) {
4916
- const now = /* @__PURE__ */ new Date();
4917
- if (input.since.endsWith("d")) {
4918
- const days = parseInt(input.since);
4919
- const start = new Date(now);
4920
- start.setDate(start.getDate() - days);
4921
- timeWindow = { start: start.toISOString() };
4922
- } else {
4923
- timeWindow = { start: input.since };
4924
- }
4925
- }
4926
- const query = {
4927
- limit: input.limit || 10
4928
- };
4929
- if (input.relatedTo) query.relatedTo = input.relatedTo;
4930
- if (input.tags) query.tags = input.tags;
4931
- if (timeWindow) query.timeWindow = timeWindow;
4932
- const decisions = await storage.queryDecisions(query);
4933
- return {
4934
- content: [{
4935
- type: "text",
4936
- text: this.formatDecisions(decisions)
4937
- }]
4938
- };
4939
- }
4940
- formatDecisions(decisions) {
4941
- if (decisions.length === 0) {
4942
- return "No decisions found matching query.";
4943
- }
4944
- let output = `Found ${decisions.length} decision(s):
4945
-
4946
- `;
4947
- for (const dec of decisions) {
4948
- const when = new Date(dec.when).toLocaleDateString();
4949
- output += `\u{1F4CB} ${dec.decision}
4950
- `;
4951
- output += ` Context: ${dec.context}
4952
- `;
4953
- if (dec.reasoning) {
4954
- output += ` Reasoning: ${dec.reasoning}
4955
- `;
4956
- }
4957
- if (dec.tradeoffs && dec.tradeoffs.length > 0) {
4958
- output += ` Tradeoffs considered: ${dec.tradeoffs.join(", ")}
4959
- `;
4960
- }
4961
- output += ` When: ${when}
4962
- `;
4963
- if (dec.files.length > 0) {
4964
- output += ` Files: ${dec.files.join(", ")}
4965
- `;
4966
- }
4967
- output += ` Tags: ${dec.tags.join(", ")}
4968
- `;
4969
- output += `
4970
- `;
4971
- }
4972
- return output;
4973
- }
4974
- };
4975
- var TrieGetBlockersTool = class {
4976
- async execute(input) {
4977
- const workDir = input.directory || getWorkingDirectory(void 0, true);
4978
- const storage = getStorage(workDir);
4979
- await storage.initialize();
4980
- const query = {
4981
- limit: input.limit || 5
4982
- };
4983
- if (input.tags) query.tags = input.tags;
4984
- const blockers = await storage.queryBlockers(query);
4985
- return {
4986
- content: [{
4987
- type: "text",
4988
- text: this.formatBlockers(blockers)
4989
- }]
4990
- };
4991
- }
4992
- formatBlockers(blockers) {
4993
- if (blockers.length === 0) {
4994
- return "\u2705 No active blockers found.";
4995
- }
4996
- let output = `\u26A0\uFE0F Found ${blockers.length} active blocker(s):
4997
-
4998
- `;
4999
- for (const blocker of blockers) {
5000
- const impact = blocker.impact.toUpperCase();
5001
- const emoji = blocker.impact === "critical" ? "\u{1F534}" : blocker.impact === "high" ? "\u{1F7E0}" : blocker.impact === "medium" ? "\u{1F7E1}" : "\u{1F7E2}";
5002
- output += `${emoji} [${impact}] ${blocker.blocker}
5003
- `;
5004
- if (blocker.affectedAreas.length > 0) {
5005
- output += ` Affects: ${blocker.affectedAreas.join(", ")}
5006
- `;
5007
- }
5008
- output += ` Since: ${new Date(blocker.when).toLocaleDateString()}
5009
- `;
5010
- output += `
5011
- `;
5012
- }
5013
- return output;
5014
- }
5015
- };
5016
- var TrieGetRelatedDecisionsTool = class {
5017
- async execute(input) {
5018
- const workDir = input.directory || getWorkingDirectory(void 0, true);
5019
- const storage = getStorage(workDir);
5020
- await storage.initialize();
5021
- const query = {
5022
- limit: input.limit || 5
5023
- };
5024
- const relatedTo = input.file || input.topic;
5025
- if (relatedTo) query.relatedTo = relatedTo;
5026
- const decisions = await storage.queryDecisions(query);
5027
- return {
5028
- content: [{
5029
- type: "text",
5030
- text: new TrieGetDecisionsTool().formatDecisions(decisions)
5031
- }]
5032
- };
5033
- }
5034
- };
5035
- var TrieQueryContextTool = class {
5036
- async execute(input) {
5037
- const workDir = input.directory || getWorkingDirectory(void 0, true);
5038
- const storage = getStorage(workDir);
5039
- await storage.initialize();
5040
- const keywords = input.query.toLowerCase().split(/\s+/);
5041
- let output = `Query: "${input.query}"
5042
-
5043
- `;
5044
- if (!input.type || input.type === "decisions" || input.type === "all") {
5045
- const decisions = await storage.queryDecisions({ limit: input.limit || 5 });
5046
- const matches = decisions.filter(
5047
- (d) => keywords.some(
5048
- (kw) => d.decision.toLowerCase().includes(kw) || d.context.toLowerCase().includes(kw) || d.tags.some((t) => t.toLowerCase().includes(kw))
5049
- )
5050
- );
5051
- if (matches.length > 0) {
5052
- output += `\u{1F4CB} DECISIONS (${matches.length}):
5053
- `;
5054
- output += new TrieGetDecisionsTool().formatDecisions(matches);
5055
- output += "\n";
5056
- }
5057
- }
5058
- if (!input.type || input.type === "blockers" || input.type === "all") {
5059
- const blockers = await storage.queryBlockers({ limit: input.limit || 5 });
5060
- const matches = blockers.filter(
5061
- (b) => keywords.some(
5062
- (kw) => b.blocker.toLowerCase().includes(kw) || b.tags.some((t) => t.toLowerCase().includes(kw))
5063
- )
5064
- );
5065
- if (matches.length > 0) {
5066
- output += `\u26A0\uFE0F BLOCKERS (${matches.length}):
5067
- `;
5068
- output += new TrieGetBlockersTool().formatBlockers(matches);
5069
- }
5070
- }
5071
- return {
5072
- content: [{
5073
- type: "text",
5074
- text: output.trim() || "No matches found."
5075
- }]
5076
- };
5077
- }
5078
- };
5079
-
5080
2844
  // src/server/tool-registry.ts
5081
2845
  var TrieCheckpointTool = class {
5082
2846
  async execute(input) {
@@ -5654,8 +3418,8 @@ var ToolRegistry = class {
5654
3418
  };
5655
3419
 
5656
3420
  // src/server/resource-manager.ts
5657
- import { readdir, readFile as readFile6 } from "fs/promises";
5658
- import { existsSync as existsSync6 } from "fs";
3421
+ import { readdir, readFile as readFile5 } from "fs/promises";
3422
+ import { existsSync as existsSync5 } from "fs";
5659
3423
  import { join as join4, dirname as dirname2 } from "path";
5660
3424
  import { fileURLToPath } from "url";
5661
3425
 
@@ -5880,7 +3644,7 @@ var ResourceManager = class {
5880
3644
  const uiDir = join4(distDir, "ui");
5881
3645
  const htmlPath = join4(uiDir, `${appId}.html`);
5882
3646
  try {
5883
- if (!existsSync6(htmlPath)) {
3647
+ if (!existsSync5(htmlPath)) {
5884
3648
  return {
5885
3649
  contents: [{
5886
3650
  uri,
@@ -5889,7 +3653,7 @@ var ResourceManager = class {
5889
3653
  }]
5890
3654
  };
5891
3655
  }
5892
- const content = await readFile6(htmlPath, "utf-8");
3656
+ const content = await readFile5(htmlPath, "utf-8");
5893
3657
  return {
5894
3658
  contents: [{
5895
3659
  uri,
@@ -6072,8 +3836,8 @@ var ResourceManager = class {
6072
3836
  summary.push("---", "", "# Detailed Context", "");
6073
3837
  const agentsMdPath = join4(getTrieDirectory(workDir), "AGENTS.md");
6074
3838
  try {
6075
- if (existsSync6(agentsMdPath)) {
6076
- const agentsContent = await readFile6(agentsMdPath, "utf-8");
3839
+ if (existsSync5(agentsMdPath)) {
3840
+ const agentsContent = await readFile5(agentsMdPath, "utf-8");
6077
3841
  summary.push(agentsContent);
6078
3842
  } else {
6079
3843
  const contextSummary = await getContextForAI();
@@ -6199,7 +3963,7 @@ This information is automatically available to Claude Code, Cursor, and other AI
6199
3963
  async getCacheStatsResource(uri) {
6200
3964
  try {
6201
3965
  const cachePath = join4(getTrieDirectory(getWorkingDirectory(void 0, true)), ".trie-cache.json");
6202
- const cacheContent = await readFile6(cachePath, "utf-8");
3966
+ const cacheContent = await readFile5(cachePath, "utf-8");
6203
3967
  const cache = JSON.parse(cacheContent);
6204
3968
  const fileCount = Object.keys(cache.files || {}).length;
6205
3969
  const totalVulns = Object.values(cache.files || {}).reduce((acc, file) => {
@@ -6280,7 +4044,7 @@ This information is automatically available to Claude Code, Cursor, and other AI
6280
4044
  const fileName = parsedUri.replace("reports/", "");
6281
4045
  const reportPath = join4(getWorkingDirectory(void 0, true), "trie-reports", fileName);
6282
4046
  try {
6283
- const content = await readFile6(reportPath, "utf-8");
4047
+ const content = await readFile5(reportPath, "utf-8");
6284
4048
  return {
6285
4049
  contents: [{
6286
4050
  uri,
@@ -6427,32 +4191,32 @@ async function findOpenPort() {
6427
4191
  return portChecks.find((port) => port !== null) || null;
6428
4192
  }
6429
4193
  async function checkPort(port) {
6430
- return new Promise((resolve5) => {
4194
+ return new Promise((resolve4) => {
6431
4195
  const testServer = createServer();
6432
4196
  let portInUse = false;
6433
4197
  testServer.once("error", (err) => {
6434
4198
  if (err.code === "EADDRINUSE") {
6435
4199
  portInUse = true;
6436
- testHttpPort(port).then(resolve5).catch(() => resolve5(false));
4200
+ testHttpPort(port).then(resolve4).catch(() => resolve4(false));
6437
4201
  } else {
6438
- resolve5(false);
4202
+ resolve4(false);
6439
4203
  }
6440
4204
  });
6441
4205
  testServer.once("listening", () => {
6442
4206
  testServer.close();
6443
- resolve5(false);
4207
+ resolve4(false);
6444
4208
  });
6445
4209
  setTimeout(() => {
6446
4210
  if (!portInUse) {
6447
4211
  testServer.close();
6448
- resolve5(false);
4212
+ resolve4(false);
6449
4213
  }
6450
4214
  }, 1e3);
6451
4215
  testServer.listen(port, "127.0.0.1");
6452
4216
  });
6453
4217
  }
6454
4218
  async function testHttpPort(port) {
6455
- return new Promise((resolve5) => {
4219
+ return new Promise((resolve4) => {
6456
4220
  const req = request({
6457
4221
  hostname: "localhost",
6458
4222
  port,
@@ -6460,18 +4224,18 @@ async function testHttpPort(port) {
6460
4224
  method: "GET",
6461
4225
  timeout: 2e3
6462
4226
  }, (res) => {
6463
- resolve5(res.statusCode !== void 0);
4227
+ resolve4(res.statusCode !== void 0);
6464
4228
  res.on("data", () => {
6465
4229
  });
6466
4230
  res.on("end", () => {
6467
4231
  });
6468
4232
  });
6469
4233
  req.on("error", () => {
6470
- resolve5(false);
4234
+ resolve4(false);
6471
4235
  });
6472
4236
  req.on("timeout", () => {
6473
4237
  req.destroy();
6474
- resolve5(false);
4238
+ resolve4(false);
6475
4239
  });
6476
4240
  req.end();
6477
4241
  });