@triedotdev/mcp 1.0.49 → 1.0.51

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (41) hide show
  1. package/README.md +545 -406
  2. package/dist/agent-smith-BECRZH73.js +12 -0
  3. package/dist/{agent-smith-runner-ZTDCJJQG.js → agent-smith-runner-LZRXM2Q2.js} +7 -7
  4. package/dist/agent-smith-runner-LZRXM2Q2.js.map +1 -0
  5. package/dist/{chunk-KQOMSIVR.js → chunk-A43476GB.js} +13 -9
  6. package/dist/chunk-A43476GB.js.map +1 -0
  7. package/dist/{chunk-IMFD4SJC.js → chunk-ASGSTVVF.js} +1 -1
  8. package/dist/chunk-ASGSTVVF.js.map +1 -0
  9. package/dist/chunk-C3AS5OXW.js +1177 -0
  10. package/dist/chunk-C3AS5OXW.js.map +1 -0
  11. package/dist/chunk-IEFAQFDQ.js +2061 -0
  12. package/dist/chunk-IEFAQFDQ.js.map +1 -0
  13. package/dist/{chunk-GLC62PGD.js → chunk-KB5ZN6K2.js} +2 -2
  14. package/dist/{chunk-VZYCZXEQ.js → chunk-TOE75CFZ.js} +2034 -391
  15. package/dist/chunk-TOE75CFZ.js.map +1 -0
  16. package/dist/{chunk-JDICQHNT.js → chunk-YKUCIKTU.js} +171 -1245
  17. package/dist/chunk-YKUCIKTU.js.map +1 -0
  18. package/dist/cli/create-agent.js +2 -2
  19. package/dist/cli/main.js +428 -71
  20. package/dist/cli/main.js.map +1 -1
  21. package/dist/cli/yolo-daemon.js +32 -20
  22. package/dist/cli/yolo-daemon.js.map +1 -1
  23. package/dist/comprehension-46F7ZNKL.js +821 -0
  24. package/dist/comprehension-46F7ZNKL.js.map +1 -0
  25. package/dist/index.js +478 -122
  26. package/dist/index.js.map +1 -1
  27. package/dist/workers/agent-worker.js +11 -11
  28. package/dist/workers/agent-worker.js.map +1 -1
  29. package/package.json +3 -1
  30. package/dist/agent-smith-5QOZXLMV.js +0 -11
  31. package/dist/agent-smith-runner-ZTDCJJQG.js.map +0 -1
  32. package/dist/chunk-6T7S77U7.js +0 -852
  33. package/dist/chunk-6T7S77U7.js.map +0 -1
  34. package/dist/chunk-IMFD4SJC.js.map +0 -1
  35. package/dist/chunk-JDICQHNT.js.map +0 -1
  36. package/dist/chunk-KQOMSIVR.js.map +0 -1
  37. package/dist/chunk-PZDQIFKO.js +0 -1598
  38. package/dist/chunk-PZDQIFKO.js.map +0 -1
  39. package/dist/chunk-VZYCZXEQ.js.map +0 -1
  40. /package/dist/{agent-smith-5QOZXLMV.js.map → agent-smith-BECRZH73.js.map} +0 -0
  41. /package/dist/{chunk-GLC62PGD.js.map → chunk-KB5ZN6K2.js.map} +0 -0
@@ -1,24 +1,235 @@
1
- import {
2
- listInstalledSkills,
3
- parseSkillMd,
4
- recordSkillUsage
5
- } from "./chunk-PZDQIFKO.js";
6
1
  import {
7
2
  checkFileLevelIssues,
8
3
  getVibeCodeTrie,
9
4
  scanForVibeCodeIssues
10
5
  } from "./chunk-3CS6Z2SL.js";
11
6
  import {
12
- AgentSmithAgent,
13
- BaseAgent,
7
+ AgentSmithSkill,
8
+ BaseSkill,
14
9
  isAIAvailable,
15
10
  runAIAnalysis
16
- } from "./chunk-KQOMSIVR.js";
11
+ } from "./chunk-A43476GB.js";
17
12
  import {
18
13
  getWorkingDirectory
19
- } from "./chunk-IMFD4SJC.js";
14
+ } from "./chunk-ASGSTVVF.js";
15
+
16
+ // src/utils/project-info.ts
17
+ import { readFile, writeFile, mkdir } from "fs/promises";
18
+ import { existsSync } from "fs";
19
+ import { join } from "path";
20
+ var PROJECT_MD_PATH = ".trie/PROJECT.md";
21
+ function getProjectTemplate() {
22
+ return `# Project Information
23
+
24
+ > This file stores important project context for AI assistants.
25
+ > Edit freely - this file is yours, not auto-generated.
26
+ > Available via MCP resource: \`trie://project\`
27
+
28
+ ---
29
+
30
+ ## Project Overview
31
+
32
+ <!-- Describe your project's purpose and goals -->
33
+
34
+ [Add project description here]
35
+
36
+ ---
37
+
38
+ ## Technology Stack
39
+
40
+ <!-- List frameworks, languages, databases, cloud services, etc. -->
41
+
42
+ - **Language:**
43
+ - **Framework:**
44
+ - **Database:**
45
+ - **Hosting:**
46
+
47
+ ---
48
+
49
+ ## Architecture
50
+
51
+ <!-- Key patterns, architectural decisions, and system design -->
52
+
53
+ [Describe your architecture here]
54
+
55
+ ---
56
+
57
+ ## Coding Conventions
58
+
59
+ <!-- Style guidelines, naming conventions, patterns to follow -->
60
+
61
+ -
62
+ -
63
+ -
64
+
65
+ ---
66
+
67
+ ## Environment
68
+
69
+ <!-- URLs, API endpoints, deployment info -->
70
+
71
+ | Environment | URL | Notes |
72
+ |-------------|-----|-------|
73
+ | Development | | |
74
+ | Staging | | |
75
+ | Production | | |
76
+
77
+ ---
78
+
79
+ ## Team
80
+
81
+ <!-- Ownership, contacts, responsibilities -->
82
+
83
+ - **Owner:**
84
+ - **Team:**
85
+
86
+ ---
87
+
88
+ ## Compliance
89
+
90
+ <!-- HIPAA, SOC2, GDPR, PCI-DSS requirements if applicable -->
91
+
92
+ - [ ] GDPR
93
+ - [ ] SOC2
94
+ - [ ] HIPAA
95
+ - [ ] PCI-DSS
96
+
97
+ ---
98
+
99
+ ## AI Instructions
100
+
101
+ <!-- Special instructions for AI assistants working on this project -->
102
+
103
+ When working on this project, AI assistants should:
104
+
105
+ 1.
106
+ 2.
107
+ 3.
108
+
109
+ ---
110
+
111
+ *This file is read by Trie agents and exposed via \`trie://project\` MCP resource.*
112
+ *Edit this file to provide context to Claude Code, Cursor, GitHub Actions, and other AI tools.*
113
+ `;
114
+ }
115
+ function projectInfoExists(workDir) {
116
+ const dir = workDir || getWorkingDirectory(void 0, true);
117
+ const projectPath = join(dir, PROJECT_MD_PATH);
118
+ return existsSync(projectPath);
119
+ }
120
+ async function loadProjectInfo(workDir) {
121
+ const dir = workDir || getWorkingDirectory(void 0, true);
122
+ const projectPath = join(dir, PROJECT_MD_PATH);
123
+ try {
124
+ if (!existsSync(projectPath)) {
125
+ return null;
126
+ }
127
+ return await readFile(projectPath, "utf-8");
128
+ } catch {
129
+ return null;
130
+ }
131
+ }
132
+ async function saveProjectInfo(content, workDir) {
133
+ const dir = workDir || getWorkingDirectory(void 0, true);
134
+ const trieDir = join(dir, ".trie");
135
+ const projectPath = join(dir, PROJECT_MD_PATH);
136
+ await mkdir(trieDir, { recursive: true });
137
+ await writeFile(projectPath, content, "utf-8");
138
+ }
139
+ async function initProjectInfo(workDir) {
140
+ const dir = workDir || getWorkingDirectory(void 0, true);
141
+ const projectPath = join(dir, PROJECT_MD_PATH);
142
+ if (existsSync(projectPath)) {
143
+ return { created: false, path: projectPath };
144
+ }
145
+ await saveProjectInfo(getProjectTemplate(), dir);
146
+ return { created: true, path: projectPath };
147
+ }
148
+ async function getProjectSection(sectionName, workDir) {
149
+ const content = await loadProjectInfo(workDir);
150
+ if (!content) return null;
151
+ const sectionRegex = new RegExp(
152
+ `## ${escapeRegex(sectionName)}\\s*\\n([\\s\\S]*?)(?=\\n## |\\n---\\s*$|$)`,
153
+ "i"
154
+ );
155
+ const match = content.match(sectionRegex);
156
+ if (match?.[1]) {
157
+ return match[1].trim();
158
+ }
159
+ return null;
160
+ }
161
+ async function updateProjectSection(sectionName, newContent, workDir) {
162
+ let content = await loadProjectInfo(workDir);
163
+ if (!content) {
164
+ await initProjectInfo(workDir);
165
+ content = await loadProjectInfo(workDir);
166
+ if (!content) return false;
167
+ }
168
+ const sectionRegex = new RegExp(
169
+ `(## ${escapeRegex(sectionName)}\\s*\\n)([\\s\\S]*?)((?=\\n## )|(?=\\n---\\s*$)|$)`,
170
+ "i"
171
+ );
172
+ if (content.match(sectionRegex)) {
173
+ const updatedContent = content.replace(sectionRegex, `$1
174
+ ${newContent}
175
+
176
+ $3`);
177
+ await saveProjectInfo(updatedContent, workDir);
178
+ return true;
179
+ }
180
+ return false;
181
+ }
182
+ async function appendToSection(sectionName, contentToAdd, workDir) {
183
+ const currentContent = await getProjectSection(sectionName, workDir);
184
+ if (currentContent === null) return false;
185
+ const newContent = currentContent + "\n" + contentToAdd;
186
+ return updateProjectSection(sectionName, newContent, workDir);
187
+ }
188
+ async function getProjectSections(workDir) {
189
+ const content = await loadProjectInfo(workDir);
190
+ if (!content) return [];
191
+ const sectionRegex = /^## (.+)$/gm;
192
+ const sections = [];
193
+ let match;
194
+ while ((match = sectionRegex.exec(content)) !== null) {
195
+ if (match[1]) {
196
+ sections.push(match[1].trim());
197
+ }
198
+ }
199
+ return sections;
200
+ }
201
+ async function getProjectInfoStructured(workDir) {
202
+ const dir = workDir || getWorkingDirectory(void 0, true);
203
+ const projectPath = join(dir, PROJECT_MD_PATH);
204
+ const content = await loadProjectInfo(dir);
205
+ if (!content) {
206
+ return {
207
+ exists: false,
208
+ path: projectPath,
209
+ sections: {},
210
+ raw: null
211
+ };
212
+ }
213
+ const sectionNames = await getProjectSections(dir);
214
+ const sections = {};
215
+ for (const name of sectionNames) {
216
+ const sectionContent = await getProjectSection(name, dir);
217
+ if (sectionContent) {
218
+ sections[name] = sectionContent;
219
+ }
220
+ }
221
+ return {
222
+ exists: true,
223
+ path: projectPath,
224
+ sections,
225
+ raw: content
226
+ };
227
+ }
228
+ function escapeRegex(str) {
229
+ return str.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
230
+ }
20
231
 
21
- // src/agents/security.ts
232
+ // src/skills/built-in/security.ts
22
233
  var ALWAYS_SKIP_FILES = [
23
234
  /vulnerability-signatures\.[jt]s$/,
24
235
  /vibe-code-signatures\.[jt]s$/,
@@ -75,10 +286,11 @@ var CRITICAL_PATTERNS = [
75
286
  { pattern: /sk_live_[A-Za-z0-9]{24,}/, severity: "critical", issue: "Stripe live API key exposed", fix: "Rotate Stripe key immediately. Use environment variables." },
76
287
  { pattern: /xox[baprs]-[A-Za-z0-9-]{10,}/, severity: "critical", issue: "Slack token exposed", fix: "Revoke Slack token and use environment variables." }
77
288
  ];
78
- var SecurityAgent = class extends BaseAgent {
289
+ var SecuritySkill = class extends BaseSkill {
79
290
  name = "security";
80
291
  description = "AI-powered security analysis: vulnerabilities, injection risks, authentication issues";
81
292
  version = "2.0.0";
293
+ author = "Trie Agent";
82
294
  shouldActivate(context) {
83
295
  return context.touchesAuth || context.touchesDatabase || context.touchesAPI || context.touchesUserData || context.touchesPayments || context.touchesSecurityConfig;
84
296
  }
@@ -297,7 +509,7 @@ Output STRICT JSON:
297
509
  }
298
510
  };
299
511
 
300
- // src/agents/privacy.ts
512
+ // src/skills/built-in/privacy.ts
301
513
  var PRIVACY_INDICATORS = {
302
514
  high: [
303
515
  { pattern: /email|phone|ssn|social.*security|passport|driver.*license/i, reason: "PII fields" },
@@ -341,10 +553,11 @@ var CRITICAL_PRIVACY_PATTERNS = [
341
553
  regulation: "PCI DSS"
342
554
  }
343
555
  ];
344
- var PrivacyAgent = class extends BaseAgent {
556
+ var PrivacySkill = class extends BaseSkill {
345
557
  name = "privacy";
346
558
  description = "AI-powered privacy analysis: GDPR, CCPA, PCI-DSS compliance";
347
559
  version = "2.0.0";
560
+ author = "Trie Agent";
348
561
  shouldActivate(context) {
349
562
  const hasUserDataSignals = context.touchesUserData && (context.touchesDatabase || context.touchesAuth || context.patterns?.hasFormHandling || context.patterns?.hasEmailHandling || context.touchesThirdPartyAPI);
350
563
  const fileNameSignals = context.filePatterns.some(
@@ -591,7 +804,7 @@ Output STRICT JSON:
591
804
  }
592
805
  };
593
806
 
594
- // src/agents/typecheck.ts
807
+ // src/skills/built-in/typecheck.ts
595
808
  import { extname } from "path";
596
809
  var SKIP_FILES = [
597
810
  /node_modules\//,
@@ -602,10 +815,11 @@ var SKIP_FILES = [
602
815
  /\.test\.[jt]sx?$/,
603
816
  /\.spec\.[jt]sx?$/
604
817
  ];
605
- var TypeCheckAgent = class extends BaseAgent {
818
+ var TypeCheckSkill = class extends BaseSkill {
606
819
  name = "typecheck";
607
820
  description = "Catches type errors and ensures type safety";
608
821
  version = "1.0.0";
822
+ author = "Trie Agent";
609
823
  shouldActivate(_context) {
610
824
  return true;
611
825
  }
@@ -676,11 +890,12 @@ var TypeCheckAgent = class extends BaseAgent {
676
890
  }
677
891
  };
678
892
 
679
- // src/agents/comprehension.ts
680
- var ComprehensionAgent = class extends BaseAgent {
893
+ // src/skills/built-in/comprehension.ts
894
+ var ComprehensionSkill = class extends BaseSkill {
681
895
  name = "comprehension";
682
896
  description = "Explains what code does in plain language for non-technical builders";
683
897
  version = "1.0.0";
898
+ author = "Trie Agent";
684
899
  shouldActivate(_context) {
685
900
  return true;
686
901
  }
@@ -893,7 +1108,7 @@ var ComprehensionAgent = class extends BaseAgent {
893
1108
  }
894
1109
  };
895
1110
 
896
- // src/agents/accessibility.ts
1111
+ // src/skills/built-in/accessibility.ts
897
1112
  var WCAG_CRITERIA = {
898
1113
  // Perceivable
899
1114
  "1.1.1": { name: "Non-text Content", level: "A", description: "All non-text content has text alternatives" },
@@ -920,6 +1135,7 @@ var WCAG_CRITERIA = {
920
1135
  // Understandable
921
1136
  "3.2.1": { name: "On Focus", level: "A", description: "Focus does not trigger unexpected context changes" },
922
1137
  "3.2.2": { name: "On Input", level: "A", description: "Input does not trigger unexpected context changes" },
1138
+ "3.2.5": { name: "Change on Request", level: "AAA", description: "Changes of context are initiated only by user request" },
923
1139
  "3.3.1": { name: "Error Identification", level: "A", description: "Errors are identified and described in text" },
924
1140
  "3.3.2": { name: "Labels or Instructions", level: "A", description: "Labels or instructions are provided for user input" },
925
1141
  // Robust
@@ -956,10 +1172,11 @@ var REQUIRED_ARIA_ATTRIBUTES = {
956
1172
  "treegrid": [],
957
1173
  "treeitem": []
958
1174
  };
959
- var AccessibilityAgent = class extends BaseAgent {
1175
+ var AccessibilitySkill = class extends BaseSkill {
960
1176
  name = "accessibility";
961
1177
  description = "WCAG 2.1 AA compliance: screen readers, keyboard nav, color contrast, touch targets, semantic HTML, ARIA patterns";
962
1178
  version = "2.0.0";
1179
+ author = "Trie Agent";
963
1180
  shouldActivate(context) {
964
1181
  return context.touchesUI;
965
1182
  }
@@ -990,12 +1207,13 @@ var AccessibilityAgent = class extends BaseAgent {
990
1207
  const score = this.calculateAccessibilityScore(issues);
991
1208
  issues.push(this.createIssue(
992
1209
  this.generateIssueId(),
993
- criticalCount > 0 ? "critical" : "serious",
1210
+ "low",
1211
+ // Summary is informational, not a blocker
994
1212
  `Accessibility Score: ${score}/100 \u2014 ${criticalCount} critical, ${seriousCount} serious issues`,
995
1213
  `Review and fix accessibility issues starting with critical problems. Use axe-core or Lighthouse for additional validation.`,
996
1214
  files[0] || "project",
997
1215
  void 0,
998
- 0.95,
1216
+ 0.6,
999
1217
  void 0,
1000
1218
  false
1001
1219
  ));
@@ -1078,7 +1296,7 @@ var AccessibilityAgent = class extends BaseAgent {
1078
1296
  }
1079
1297
  }
1080
1298
  if (/<svg\s/i.test(line)) {
1081
- const svgContext = this.getMultiLineElement(lines, i, "svg");
1299
+ const svgContext = this.getMultiLineElement(lines, i, "svg") ?? line;
1082
1300
  if (!/aria-label|aria-labelledby|<title>|role=["']img["']/i.test(svgContext) && !/aria-hidden=["']true["']/i.test(svgContext)) {
1083
1301
  issues.push(this.createIssue(
1084
1302
  this.generateIssueId(),
@@ -1106,7 +1324,7 @@ var AccessibilityAgent = class extends BaseAgent {
1106
1324
  const line = lines[i];
1107
1325
  const lineNumber = i + 1;
1108
1326
  if (/<button/i.test(line) || /Button\s/i.test(line)) {
1109
- const buttonContext = this.getMultiLineElement(lines, i, "button") || this.getMultiLineElement(lines, i, "Button");
1327
+ const buttonContext = this.getMultiLineElement(lines, i, "button") ?? this.getMultiLineElement(lines, i, "Button") ?? line;
1110
1328
  const hasIconOnly = />\s*<(Icon|svg|i\s|img)[^>]*>\s*<\/(button|Button)/i.test(buttonContext) || />\s*<[A-Z][a-zA-Z]*Icon[^>]*\s*\/>\s*<\/(button|Button)/i.test(buttonContext) || /<(Icon|svg)[^>]*\/>\s*<\/(button|Button)/i.test(buttonContext);
1111
1329
  const hasAccessibleName = /aria-label|aria-labelledby|title=|sr-only|visually-hidden/i.test(buttonContext);
1112
1330
  if (hasIconOnly && !hasAccessibleName) {
@@ -1157,7 +1375,7 @@ var AccessibilityAgent = class extends BaseAgent {
1157
1375
  }
1158
1376
  }
1159
1377
  if (/<a\s/i.test(line) || /<Link\s/i.test(line)) {
1160
- const linkContext = this.getMultiLineElement(lines, i, "a") || this.getMultiLineElement(lines, i, "Link");
1378
+ const linkContext = this.getMultiLineElement(lines, i, "a") ?? this.getMultiLineElement(lines, i, "Link") ?? line;
1161
1379
  if (!/href=|to=/i.test(linkContext)) {
1162
1380
  issues.push(this.createIssue(
1163
1381
  this.generateIssueId(),
@@ -1931,7 +2149,7 @@ Review code for comprehensive accessibility compliance.
1931
2149
  }
1932
2150
  };
1933
2151
 
1934
- // src/agents/design-engineer.ts
2152
+ // src/skills/built-in/design-engineer.ts
1935
2153
  var DOMAIN_DESIGN_RULES = {
1936
2154
  fitness: {
1937
2155
  defaultMode: "dark",
@@ -2149,10 +2367,11 @@ var PROJECT_CONTEXTS = {
2149
2367
  effects: ["image reveals", "cursor effects", "page transitions", "scroll-linked galleries"]
2150
2368
  }
2151
2369
  };
2152
- var DesignEngineerAgent = class extends BaseAgent {
2370
+ var DesignEngineerSkill = class extends BaseSkill {
2153
2371
  name = "design-engineer";
2154
2372
  description = "Award-winning frontend craft: design systems, motion design, creative CSS, modern color palettes, Awwwards-level polish";
2155
2373
  version = "2.0.0";
2374
+ author = "Trie Agent";
2156
2375
  shouldActivate(context) {
2157
2376
  return context.touchesUI;
2158
2377
  }
@@ -2187,12 +2406,14 @@ var DesignEngineerAgent = class extends BaseAgent {
2187
2406
  const domainRecommendation = this.getDomainRecommendations(designContext);
2188
2407
  issues.push(this.createIssue(
2189
2408
  this.generateIssueId(),
2190
- healthScore.score < 50 ? "serious" : "moderate",
2409
+ "low",
2410
+ // Design scores are informational, not blockers
2191
2411
  `Design Health Score: ${healthScore.score}/100 | Slop Score: ${healthScore.slopScore}/100`,
2192
2412
  `Breakdown: Token adoption ${healthScore.breakdown.tokenAdoption}%, Contrast ${healthScore.breakdown.contrastCompliance}%, Spacing ${healthScore.breakdown.spacingConsistency}%, Typography ${healthScore.breakdown.typographySystem}%, Surface hierarchy ${healthScore.breakdown.surfaceHierarchy}%. ${domainRecommendation}`,
2193
2413
  files[0] || "project",
2194
2414
  void 0,
2195
- 0.95,
2415
+ 0.6,
2416
+ // Lower confidence for aggregate scores
2196
2417
  void 0,
2197
2418
  false
2198
2419
  ));
@@ -2921,12 +3142,13 @@ var DesignEngineerAgent = class extends BaseAgent {
2921
3142
  const suggestedFix = this.suggestLighterSurface(bgColors[0], 10);
2922
3143
  issues.push(this.createIssue(
2923
3144
  this.generateIssueId(),
2924
- "critical",
3145
+ "moderate",
3146
+ // Design issues should not be critical - reserved for security/data loss
2925
3147
  `AI SLOP: Surfaces too similar (${minDelta.toFixed(1)}% lightness delta). Min 8% required.`,
2926
3148
  `Change surface color to create visible hierarchy. Suggestion: use ${suggestedFix} for elevated surfaces. Reference: zinc scale at tailwindcss.com/docs/customizing-colors`,
2927
3149
  file,
2928
3150
  void 0,
2929
- 0.95,
3151
+ 0.75,
2930
3152
  void 0,
2931
3153
  true
2932
3154
  ));
@@ -2937,12 +3159,13 @@ var DesignEngineerAgent = class extends BaseAgent {
2937
3159
  if (accentHues.length > AI_SLOP_BLOCKERS.accents.maxAccentHues + 1) {
2938
3160
  issues.push(this.createIssue(
2939
3161
  this.generateIssueId(),
2940
- "serious",
3162
+ "low",
3163
+ // Design preference, not a real issue
2941
3164
  `AI SLOP: ${accentHues.length} accent color families detected. Use ONE primary accent.`,
2942
3165
  `Standardize on a single accent hue family. Semantic colors (success/warning/error) are exempt. Reference: radix-ui.com/colors for cohesive scales`,
2943
3166
  file,
2944
3167
  void 0,
2945
- 0.9,
3168
+ 0.65,
2946
3169
  void 0,
2947
3170
  true
2948
3171
  ));
@@ -2972,12 +3195,14 @@ var DesignEngineerAgent = class extends BaseAgent {
2972
3195
  const desaturated = this.desaturateColor(color, 60);
2973
3196
  issues.push(this.createIssue(
2974
3197
  this.generateIssueId(),
2975
- "serious",
3198
+ "low",
3199
+ // Design suggestions should be low severity, not serious
2976
3200
  `AI SLOP: Neon color detected (${color}, ${saturation.toFixed(0)}% saturation)`,
2977
3201
  `Desaturate to ${desaturated}. Max recommended saturation: 75%. Source colors from radix-ui.com/colors for contrast-safe alternatives.`,
2978
3202
  file,
2979
3203
  void 0,
2980
- 0.9,
3204
+ 0.7,
3205
+ // Lower confidence for design opinions
2981
3206
  void 0,
2982
3207
  true
2983
3208
  ));
@@ -3649,11 +3874,12 @@ Output STRICT JSON:
3649
3874
  }
3650
3875
  };
3651
3876
 
3652
- // src/agents/legal.ts
3653
- var LegalAgent = class extends BaseAgent {
3877
+ // src/skills/built-in/legal.ts
3878
+ var LegalSkill = class extends BaseSkill {
3654
3879
  name = "legal";
3655
3880
  description = "Comprehensive legal compliance for app development: licensing, ToS, accessibility, IP, data protection, e-commerce, and regulatory requirements";
3656
3881
  version = "2.0.0";
3882
+ author = "Trie Agent";
3657
3883
  shouldActivate(context) {
3658
3884
  return context.touchesUserData || context.touchesPayments || context.touchesAuth || context.touchesUI || context.touchesAPI || context.touchesThirdPartyAPI || context.touchesHealthData;
3659
3885
  }
@@ -4347,18 +4573,23 @@ var LegalAgent = class extends BaseAgent {
4347
4573
  checkAgeRestrictions(content, file) {
4348
4574
  const issues = [];
4349
4575
  const lines = content.split("\n");
4576
+ const isReactChildrenUsage = /children\s*[:\?})]|React\.ReactNode|PropsWithChildren|\.children/i.test(content);
4350
4577
  for (let i = 0; i < lines.length; i++) {
4351
4578
  const line = lines[i];
4352
- if (/kids|children|child|minor|under.*13|age.*13/i.test(line)) {
4579
+ const childPattern = /\b(kids|minor|under.*13|age.*13)\b/i;
4580
+ const childrenPropPattern = /children\s*[:\?})\]=]|\.children|ReactNode/i;
4581
+ if (childPattern.test(line) && !childrenPropPattern.test(line) && !isReactChildrenUsage) {
4353
4582
  if (!/coppa|parentalConsent|verifiableConsent/i.test(content)) {
4354
4583
  issues.push(this.createIssue(
4355
4584
  this.generateIssueId(),
4356
- "critical",
4357
- "Child-directed content without COPPA compliance",
4358
- "COPPA requires verifiable parental consent before collecting data from children under 13",
4585
+ "serious",
4586
+ // Downgraded from critical - needs human review
4587
+ "Potential child-directed content without COPPA compliance",
4588
+ "COPPA requires verifiable parental consent before collecting data from children under 13. Review if this applies to your app.",
4359
4589
  file,
4360
4590
  i + 1,
4361
- 0.95,
4591
+ 0.7,
4592
+ // Lower confidence - needs human verification
4362
4593
  "COPPA - Children's Online Privacy Protection Act",
4363
4594
  false
4364
4595
  ));
@@ -4636,13 +4867,14 @@ var LegalAgent = class extends BaseAgent {
4636
4867
  }
4637
4868
  };
4638
4869
 
4639
- // src/agents/test.ts
4870
+ // src/skills/built-in/test.ts
4640
4871
  import { basename, dirname } from "path";
4641
- import { existsSync } from "fs";
4642
- var TestAgent = class extends BaseAgent {
4872
+ import { existsSync as existsSync2 } from "fs";
4873
+ var TestSkill = class extends BaseSkill {
4643
4874
  name = "test";
4644
4875
  description = "Test coverage analysis, test quality, and testing best practices";
4645
4876
  version = "1.0.0";
4877
+ author = "Trie Agent";
4646
4878
  shouldActivate(context) {
4647
4879
  return context.isNewFeature || context.touchesAuth || context.touchesPayments || context.touchesAPI;
4648
4880
  }
@@ -4666,13 +4898,21 @@ var TestAgent = class extends BaseAgent {
4666
4898
  const issues = [];
4667
4899
  const fileName = basename(file);
4668
4900
  const fileDir = dirname(file);
4901
+ if (/index\.[jt]sx?$|types?\.[jt]s$|constants?\.[jt]s$|config\.[jt]s$/.test(fileName)) {
4902
+ return issues;
4903
+ }
4904
+ if (/\.(tsx|jsx)$/.test(fileName) && !/\.test\.|\.spec\./.test(fileName)) {
4905
+ if (!/auth|login|payment|checkout|form/i.test(content)) {
4906
+ return issues;
4907
+ }
4908
+ }
4669
4909
  const testPatterns = [
4670
4910
  file.replace(/\.(ts|js|tsx|jsx)$/, ".test.$1"),
4671
4911
  file.replace(/\.(ts|js|tsx|jsx)$/, ".spec.$1"),
4672
4912
  `${fileDir}/__tests__/${fileName}`,
4673
4913
  `${fileDir}/../__tests__/${fileName}`
4674
4914
  ];
4675
- const hasTestFile = testPatterns.some((pattern) => existsSync(pattern));
4915
+ const hasTestFile = testPatterns.some((pattern) => existsSync2(pattern));
4676
4916
  if (!hasTestFile) {
4677
4917
  const severity = this.determineTestSeverity(content);
4678
4918
  issues.push(this.createIssue(
@@ -4682,7 +4922,8 @@ var TestAgent = class extends BaseAgent {
4682
4922
  `Create test file: ${fileName.replace(/\.(ts|js|tsx|jsx)$/, ".test.$1")}`,
4683
4923
  file,
4684
4924
  void 0,
4685
- 0.85,
4925
+ 0.7,
4926
+ // Lower confidence - we can't know if tests exist elsewhere
4686
4927
  void 0,
4687
4928
  false
4688
4929
  ));
@@ -4700,52 +4941,8 @@ var TestAgent = class extends BaseAgent {
4700
4941
  }
4701
4942
  checkTestablePatterns(content, file) {
4702
4943
  const issues = [];
4703
- const lines = content.split("\n");
4704
4944
  const exports = content.match(/export\s+(function|class|const|async function)/g);
4705
4945
  const exportCount = exports?.length || 0;
4706
- for (let i = 0; i < lines.length; i++) {
4707
- const line = lines[i];
4708
- const lineNumber = i + 1;
4709
- if ((line.match(/if|else|switch|\?.*:/g) || []).length >= 3) {
4710
- issues.push(this.createIssue(
4711
- this.generateIssueId(),
4712
- "low",
4713
- "Complex conditional logic should have unit tests",
4714
- "Write tests covering different branches of this logic",
4715
- file,
4716
- lineNumber,
4717
- 0.7,
4718
- void 0,
4719
- false
4720
- ));
4721
- }
4722
- if (/catch\s*\(|\.catch\(/.test(line)) {
4723
- issues.push(this.createIssue(
4724
- this.generateIssueId(),
4725
- "low",
4726
- "Error handling path should be tested",
4727
- "Write tests that trigger and verify error handling behavior",
4728
- file,
4729
- lineNumber,
4730
- 0.65,
4731
- void 0,
4732
- false
4733
- ));
4734
- }
4735
- if (/async\s+function|await\s+/.test(line) && /fetch|axios|database|query/i.test(line)) {
4736
- issues.push(this.createIssue(
4737
- this.generateIssueId(),
4738
- "moderate",
4739
- "Async operation should have integration tests",
4740
- "Mock external dependencies and test async behavior",
4741
- file,
4742
- lineNumber,
4743
- 0.75,
4744
- void 0,
4745
- false
4746
- ));
4747
- }
4748
- }
4749
4946
  if (exportCount > 5) {
4750
4947
  issues.push(this.createIssue(
4751
4948
  this.generateIssueId(),
@@ -4763,11 +4960,12 @@ var TestAgent = class extends BaseAgent {
4763
4960
  }
4764
4961
  };
4765
4962
 
4766
- // src/agents/software-architect.ts
4767
- var SoftwareArchitectAgent = class extends BaseAgent {
4963
+ // src/skills/built-in/software-architect.ts
4964
+ var SoftwareArchitectSkill = class extends BaseSkill {
4768
4965
  name = "software-architect";
4769
4966
  description = "Architecture patterns, code organization, SOLID principles, and scalability";
4770
4967
  version = "1.0.0";
4968
+ author = "Trie Agent";
4771
4969
  shouldActivate(context) {
4772
4970
  return context.isNewFeature || context.touchesDatabase || context.touchesAPI || context.linesChanged > 200;
4773
4971
  }
@@ -4791,18 +4989,23 @@ var SoftwareArchitectAgent = class extends BaseAgent {
4791
4989
  for (let i = 0; i < lines.length; i++) {
4792
4990
  const line = lines[i];
4793
4991
  const lineNumber = i + 1;
4794
- if (/\.(tsx|jsx)$/.test(file) && /prisma|mongoose|sequelize|typeorm|query|SELECT/i.test(line)) {
4795
- issues.push(this.createIssue(
4796
- this.generateIssueId(),
4797
- "serious",
4798
- "Direct database access in UI component",
4799
- "Move database logic to API layer or server action",
4800
- file,
4801
- lineNumber,
4802
- 0.9,
4803
- void 0,
4804
- false
4805
- ));
4992
+ if (/\.(tsx|jsx)$/.test(file)) {
4993
+ const hasOrmImport = /from\s+['"]prisma|from\s+['"]mongoose|from\s+['"]sequelize|from\s+['"]typeorm|from\s+['"]@prisma/i.test(line);
4994
+ const hasDirectQuery = /\.query\s*\(|\.execute\s*\(|\.raw\s*\(/.test(line);
4995
+ if (hasOrmImport || hasDirectQuery) {
4996
+ issues.push(this.createIssue(
4997
+ this.generateIssueId(),
4998
+ "moderate",
4999
+ // Downgraded - sometimes this is intentional (Next.js server components)
5000
+ "Direct database access in UI component",
5001
+ "Move database logic to API layer or server action",
5002
+ file,
5003
+ lineNumber,
5004
+ 0.75,
5005
+ void 0,
5006
+ false
5007
+ ));
5008
+ }
4806
5009
  }
4807
5010
  if (/controller|handler|route/i.test(file) && lines.slice(i, i + 20).join("\n").split("if").length > 5) {
4808
5011
  issues.push(this.createIssue(
@@ -4852,18 +5055,19 @@ var SoftwareArchitectAgent = class extends BaseAgent {
4852
5055
  checkCodeOrganization(content, file) {
4853
5056
  const issues = [];
4854
5057
  const hasUI = /jsx|tsx|render|component|React|useState/i.test(content);
4855
- const hasAPI = /fetch|axios|api|endpoint|route/i.test(content);
4856
- const hasDB = /prisma|mongoose|query|INSERT|SELECT/i.test(content);
5058
+ const hasAPI = /fetch\(|axios\.|api\/|endpoint|route/i.test(content);
5059
+ const hasDB = /from\s+['"]prisma|from\s+['"]mongoose|from\s+['"]sequelize|\.query\s*\(/i.test(content);
4857
5060
  const concernCount = [hasUI, hasAPI, hasDB].filter(Boolean).length;
4858
- if (concernCount >= 2) {
5061
+ if (concernCount >= 3) {
4859
5062
  issues.push(this.createIssue(
4860
5063
  this.generateIssueId(),
4861
- "moderate",
5064
+ "low",
5065
+ // Downgraded - this is more of a suggestion
4862
5066
  "Multiple concerns mixed in single file",
4863
- "Separate UI, API, and data access layers",
5067
+ "Consider separating UI, API, and data access layers",
4864
5068
  file,
4865
5069
  void 0,
4866
- 0.75,
5070
+ 0.6,
4867
5071
  void 0,
4868
5072
  false
4869
5073
  ));
@@ -4986,11 +5190,12 @@ Output STRICT JSON:
4986
5190
  }
4987
5191
  };
4988
5192
 
4989
- // src/agents/devops.ts
4990
- var DevOpsAgent = class extends BaseAgent {
5193
+ // src/skills/built-in/devops.ts
5194
+ var DevOpsSkill = class extends BaseSkill {
4991
5195
  name = "devops";
4992
5196
  description = "Infrastructure, deployment, configuration, and operational concerns";
4993
5197
  version = "1.0.0";
5198
+ author = "Trie Agent";
4994
5199
  shouldActivate(context) {
4995
5200
  return context.touchesSecurityConfig || context.touchesDatabase || context.touchesPayments || context.touchesHealthData;
4996
5201
  }
@@ -5191,7 +5396,7 @@ Output STRICT JSON:
5191
5396
  }
5192
5397
  };
5193
5398
 
5194
- // src/agents/bug-finding.ts
5399
+ // src/skills/built-in/bug-finding.ts
5195
5400
  var BUG_INDICATORS = {
5196
5401
  high: [
5197
5402
  { pattern: /async|await|promise/i, reason: "async code" },
@@ -5227,10 +5432,11 @@ var CRITICAL_BUG_PATTERNS = [
5227
5432
  fix: "Use === for comparison instead of ="
5228
5433
  }
5229
5434
  ];
5230
- var BugFindingAgent = class extends BaseAgent {
5435
+ var BugFindingSkill = class extends BaseSkill {
5231
5436
  name = "bug-finding";
5232
5437
  description = "AI-powered bug detection: null safety, edge cases, async issues, runtime errors";
5233
5438
  version = "2.0.0";
5439
+ author = "Trie Agent";
5234
5440
  shouldActivate(context) {
5235
5441
  return context.touchesPayments || context.isNewFeature || context.touchesDatabase || context.touchesAPI;
5236
5442
  }
@@ -5421,11 +5627,12 @@ Output STRICT JSON:
5421
5627
  }
5422
5628
  };
5423
5629
 
5424
- // src/agents/user-testing.ts
5425
- var UserTestingAgent = class extends BaseAgent {
5630
+ // src/skills/built-in/user-testing.ts
5631
+ var UserTestingSkill = class extends BaseSkill {
5426
5632
  name = "user-testing";
5427
5633
  description = "Simulates user personas (happy path, security tester, confused user) to find vulnerabilities";
5428
5634
  version = "2.0.0";
5635
+ author = "Trie Agent";
5429
5636
  get priority() {
5430
5637
  return {
5431
5638
  name: this.name,
@@ -5891,11 +6098,12 @@ var UserTestingAgent = class extends BaseAgent {
5891
6098
  }
5892
6099
  };
5893
6100
 
5894
- // src/agents/trie-clean.ts
5895
- var TrieCleanAgent = class extends BaseAgent {
6101
+ // src/skills/built-in/trie-clean.ts
6102
+ var TrieCleanSkill = class extends BaseSkill {
5896
6103
  name = "trie_clean";
5897
6104
  description = "Reviews AI-generated code for common mistakes and best practices (for non-technical users)";
5898
6105
  version = "1.0.0";
6106
+ author = "Trie Agent";
5899
6107
  get priority() {
5900
6108
  return {
5901
6109
  name: this.name,
@@ -5975,7 +6183,7 @@ var TrieCleanAgent = class extends BaseAgent {
5975
6183
  }
5976
6184
  };
5977
6185
 
5978
- // src/agents/soc2.ts
6186
+ // src/skills/built-in/soc2.ts
5979
6187
  var SOC2_PATTERNS = {
5980
6188
  // CC6 - Logical Access Controls
5981
6189
  hardcodedSecrets: [
@@ -6042,10 +6250,11 @@ var REGULATION_DESCRIPTIONS = {
6042
6250
  "CC7.3": "Incident Detection - Proper error handling and alerting",
6043
6251
  "CC8.1": "Change Management - Controlled changes with proper review"
6044
6252
  };
6045
- var SOC2Agent = class extends BaseAgent {
6253
+ var SOC2Skill = class extends BaseSkill {
6046
6254
  name = "soc2";
6047
6255
  description = "SOC 2 Type II compliance: access controls, encryption, logging, change management";
6048
6256
  version = "1.0.0";
6257
+ author = "Trie Agent";
6049
6258
  shouldActivate(context) {
6050
6259
  return context.touchesAuth || context.touchesAPI || context.touchesDatabase || context.touchesUserData || context.touchesSecurityConfig || context.touchesLogging;
6051
6260
  }
@@ -6189,11 +6398,12 @@ Output STRICT JSON:
6189
6398
  }
6190
6399
  };
6191
6400
 
6192
- // src/agents/super-reviewer.ts
6193
- var SuperReviewerAgent = class extends BaseAgent {
6401
+ // src/skills/built-in/super-reviewer.ts
6402
+ var SuperReviewerSkill = class extends BaseSkill {
6194
6403
  name = "super-reviewer";
6195
6404
  description = "Interactive PR review: walks through changes file-by-file, explains each chunk, waits for cross-examination";
6196
6405
  version = "1.0.0";
6406
+ author = "Trie Agent";
6197
6407
  shouldActivate(_context) {
6198
6408
  return false;
6199
6409
  }
@@ -6339,11 +6549,12 @@ var CRITICAL_REVIEW_CHECKLIST = {
6339
6549
  ]
6340
6550
  };
6341
6551
 
6342
- // src/agents/performance.ts
6343
- var PerformanceAgent = class extends BaseAgent {
6552
+ // src/skills/built-in/performance.ts
6553
+ var PerformanceSkill = class extends BaseSkill {
6344
6554
  name = "performance";
6345
6555
  description = "Surfaces performance patterns for human review: memory, renders, bundles, queries";
6346
6556
  version = "1.0.0";
6557
+ author = "Trie Agent";
6347
6558
  shouldActivate(context) {
6348
6559
  return context.touchesUI || context.touchesDatabase || context.touchesAPI || context.patterns.hasAsyncCode || context.linesChanged > 100;
6349
6560
  }
@@ -6638,11 +6849,12 @@ var PerformanceAgent = class extends BaseAgent {
6638
6849
  }
6639
6850
  };
6640
6851
 
6641
- // src/agents/e2e.ts
6642
- var E2EAgent = class extends BaseAgent {
6852
+ // src/skills/built-in/e2e.ts
6853
+ var E2ESkill = class extends BaseSkill {
6643
6854
  name = "e2e";
6644
6855
  description = "Identifies E2E test gaps and flaky test patterns for human review";
6645
6856
  version = "1.0.0";
6857
+ author = "Trie Agent";
6646
6858
  shouldActivate(context) {
6647
6859
  return context.touchesUI || context.isNewFeature || context.patterns.hasFormHandling;
6648
6860
  }
@@ -6870,11 +7082,12 @@ var E2EAgent = class extends BaseAgent {
6870
7082
  }
6871
7083
  };
6872
7084
 
6873
- // src/agents/visual-qa.ts
6874
- var VisualQAAgent = class extends BaseAgent {
7085
+ // src/skills/built-in/visual-qa.ts
7086
+ var VisualQASkill = class extends BaseSkill {
6875
7087
  name = "visual-qa";
6876
7088
  description = "Surfaces potential visual/layout issues in CSS for human review";
6877
7089
  version = "1.0.0";
7090
+ author = "Trie Agent";
6878
7091
  shouldActivate(context) {
6879
7092
  return context.touchesUI || context.filePatterns.some((f) => /\.(css|scss|sass|less|styled)/.test(f));
6880
7093
  }
@@ -7205,11 +7418,12 @@ var VisualQAAgent = class extends BaseAgent {
7205
7418
  }
7206
7419
  };
7207
7420
 
7208
- // src/agents/data-flow.ts
7209
- var DataFlowAgent = class extends BaseAgent {
7421
+ // src/skills/built-in/data-flow.ts
7422
+ var DataFlowSkill = class extends BaseSkill {
7210
7423
  name = "data-flow";
7211
7424
  description = "Detects schema mismatches, placeholder data, and data integrity issues";
7212
7425
  version = "1.0.0";
7426
+ author = "Trie Agent";
7213
7427
  shouldActivate(context) {
7214
7428
  return context.touchesAPI || context.touchesDatabase || context.isNewFeature || context.patterns.hasFormHandling;
7215
7429
  }
@@ -7240,13 +7454,9 @@ var DataFlowAgent = class extends BaseAgent {
7240
7454
  const placeholderPatterns = [
7241
7455
  { pattern: /["']lorem ipsum/i, desc: "Lorem ipsum placeholder text" },
7242
7456
  { pattern: /["']test@(test|example)\.com["']/i, desc: "Test email address" },
7243
- { pattern: /["']TODO["']|["']FIXME["']|["']PLACEHOLDER["']/i, desc: "TODO/PLACEHOLDER string value" },
7244
- { pattern: /["']xxx["']|["']yyy["']|["']zzz["']/i, desc: "Placeholder string (xxx/yyy/zzz)" },
7245
- { pattern: /["']foo["']|["']bar["']|["']baz["']/, desc: "Common placeholder names" },
7246
- { pattern: /["']asdf["']|["']qwerty["']/i, desc: "Keyboard mash placeholder" },
7457
+ { pattern: /["']PLACEHOLDER["']/i, desc: "PLACEHOLDER string value" },
7247
7458
  { pattern: /["']changeme["']|["']replace[-_]?me["']/i, desc: "Replace-me placeholder" },
7248
- { pattern: /["']your[-_]?.*[-_]?here["']/i, desc: "Your-X-here placeholder" },
7249
- { pattern: /price:\s*0[,\s]|amount:\s*0[,\s]|total:\s*0[,\s]/i, desc: "Zero price/amount (placeholder?)" }
7459
+ { pattern: /["']your[-_]?(api[-_]?key|token|password)[-_]?here["']/i, desc: "Your-X-here placeholder" }
7250
7460
  ];
7251
7461
  for (let i = 0; i < lines.length; i++) {
7252
7462
  const line = lines[i] || "";
@@ -7351,45 +7561,17 @@ var DataFlowAgent = class extends BaseAgent {
7351
7561
  for (let i = 0; i < lines.length; i++) {
7352
7562
  const line = lines[i] || "";
7353
7563
  const lineNumber = i + 1;
7354
- const optionalChainCount = (line.match(/\?\./g) || []).length;
7355
- if (optionalChainCount >= 3) {
7356
- issues.push(this.createIssue(
7357
- this.generateIssueId(),
7358
- "low",
7359
- "Heavy optional chaining may indicate schema uncertainty",
7360
- "Review: if data structure is well-defined, some ?. may be unnecessary",
7361
- file,
7362
- lineNumber,
7363
- 0.5,
7364
- void 0,
7365
- false,
7366
- { category: "schema", effort: "medium" }
7367
- ));
7368
- }
7369
- if (/as\s+\w+(\[\])?[,;\s)]/.test(line) && !/as\s+const/.test(line)) {
7370
- issues.push(this.createIssue(
7371
- this.generateIssueId(),
7372
- "low",
7373
- "Type assertion may hide actual type mismatch",
7374
- "Prefer type guards or validation for runtime safety",
7375
- file,
7376
- lineNumber,
7377
- 0.45,
7378
- void 0,
7379
- false,
7380
- { category: "type-assertion", effort: "medium" }
7381
- ));
7382
- }
7383
7564
  if (/response\.(data|body)\.(\w+)\.(\w+)\.(\w+)/.test(line)) {
7384
7565
  if (!/\?\./.test(line)) {
7385
7566
  issues.push(this.createIssue(
7386
7567
  this.generateIssueId(),
7387
- "moderate",
7568
+ "low",
7569
+ // Downgraded - optional chaining is good but not critical
7388
7570
  "Deep property access on API response without null checks",
7389
7571
  "Add optional chaining or validate response structure",
7390
7572
  file,
7391
7573
  lineNumber,
7392
- 0.75,
7574
+ 0.6,
7393
7575
  void 0,
7394
7576
  false,
7395
7577
  { category: "null-access", effort: "easy" }
@@ -7438,23 +7620,6 @@ var DataFlowAgent = class extends BaseAgent {
7438
7620
  ));
7439
7621
  }
7440
7622
  }
7441
- if (/Number\(|parseFloat\(|\+\s*\w+/.test(line)) {
7442
- const context = lines.slice(i, Math.min(i + 3, lines.length)).join("\n");
7443
- if (!/isNaN|Number\.isFinite|isFinite|\|\|\s*0/.test(context)) {
7444
- issues.push(this.createIssue(
7445
- this.generateIssueId(),
7446
- "low",
7447
- "Number conversion without NaN check",
7448
- "Check for NaN: isNaN(result) or provide fallback: value || 0",
7449
- file,
7450
- lineNumber,
7451
- 0.55,
7452
- void 0,
7453
- false,
7454
- { category: "nan", effort: "easy" }
7455
- ));
7456
- }
7457
- }
7458
7623
  }
7459
7624
  return issues;
7460
7625
  }
@@ -7464,45 +7629,40 @@ var DataFlowAgent = class extends BaseAgent {
7464
7629
  for (let i = 0; i < lines.length; i++) {
7465
7630
  const line = lines[i] || "";
7466
7631
  const lineNumber = i + 1;
7467
- if (/[^!=]==[^=]/.test(line) && !/===/.test(line)) {
7468
- if (/null|undefined|""|\d+|true|false/.test(line)) {
7469
- issues.push(this.createIssue(
7470
- this.generateIssueId(),
7471
- "moderate",
7472
- "Loose equality (==) may cause unexpected type coercion",
7473
- "Use strict equality (===) for predictable comparisons",
7474
- file,
7475
- lineNumber,
7476
- 0.8,
7477
- void 0,
7478
- true,
7479
- { category: "equality", effort: "trivial" }
7480
- ));
7481
- }
7632
+ if (/==\s*null/.test(line) || /==\s*undefined/.test(line)) {
7633
+ issues.push(this.createIssue(
7634
+ this.generateIssueId(),
7635
+ "moderate",
7636
+ "Loose equality check against null/undefined",
7637
+ "Use strict equality (===) to avoid accidental truthiness",
7638
+ file,
7639
+ lineNumber,
7640
+ 0.75,
7641
+ void 0,
7642
+ true,
7643
+ { category: "equality", effort: "trivial" }
7644
+ ));
7482
7645
  }
7483
- if (/if\s*\(\s*\w+\s*\)/.test(line)) {
7484
- const varName = line.match(/if\s*\(\s*(\w+)\s*\)/)?.[1];
7485
- if (varName && /count|total|length|index|num|amount|price/i.test(varName)) {
7486
- issues.push(this.createIssue(
7487
- this.generateIssueId(),
7488
- "low",
7489
- "Truthy check on number variable - 0 is falsy but might be valid",
7490
- "Consider explicit: if (count !== undefined) or if (count > 0)",
7491
- file,
7492
- lineNumber,
7493
- 0.6,
7494
- void 0,
7495
- false,
7496
- { category: "falsy", effort: "easy" }
7497
- ));
7498
- }
7646
+ if (/==\s*["']['"]/.test(line) || /==\s*0[^.]/.test(line)) {
7647
+ issues.push(this.createIssue(
7648
+ this.generateIssueId(),
7649
+ "low",
7650
+ "Loose equality with empty string or zero - type coercion risk",
7651
+ "Use strict equality (===) to avoid unexpected behavior",
7652
+ file,
7653
+ lineNumber,
7654
+ 0.65,
7655
+ void 0,
7656
+ true,
7657
+ { category: "equality", effort: "trivial" }
7658
+ ));
7499
7659
  }
7500
7660
  }
7501
7661
  return issues;
7502
7662
  }
7503
7663
  };
7504
7664
 
7505
- // src/agents/moneybags.ts
7665
+ // src/skills/built-in/moneybags.ts
7506
7666
  var MONEYBAGS_ASCII = `
7507
7667
  \u2588\u2588\u2588\u2557 \u2588\u2588\u2588\u2557 \u2588\u2588\u2588\u2588\u2588\u2588\u2557 \u2588\u2588\u2588\u2557 \u2588\u2588\u2557\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2557\u2588\u2588\u2557 \u2588\u2588\u2557
7508
7668
  \u2588\u2588\u2588\u2588\u2557 \u2588\u2588\u2588\u2588\u2551\u2588\u2588\u2554\u2550\u2550\u2550\u2588\u2588\u2557\u2588\u2588\u2588\u2588\u2557 \u2588\u2588\u2551\u2588\u2588\u2554\u2550\u2550\u2550\u2550\u255D\u255A\u2588\u2588\u2557 \u2588\u2588\u2554\u255D
@@ -7526,66 +7686,66 @@ var MONEYBAGS_QUOTES = [
7526
7686
  ];
7527
7687
  var BASE_COST_BY_SEVERITY = {
7528
7688
  critical: 5e3,
7529
- // Critical bugs found in dev - still expensive to fix properly
7689
+ // Critical bugs found in dev - high impact, deep fixes
7530
7690
  serious: 2e3,
7531
7691
  // Serious issues need careful remediation
7532
7692
  moderate: 500,
7533
7693
  // Moderate issues are quicker fixes
7534
- low: 100
7694
+ low: 150
7535
7695
  // Low severity - mostly cleanup
7536
7696
  };
7537
7697
  var PRODUCTION_MULTIPLIER = {
7538
- critical: 30,
7698
+ critical: 12,
7539
7699
  // Critical bugs can cause outages, breaches
7540
- serious: 20,
7700
+ serious: 8,
7541
7701
  // Serious bugs cause significant user impact
7542
- moderate: 10,
7702
+ moderate: 4,
7543
7703
  // Moderate bugs require hotfixes, user support
7544
- low: 5
7704
+ low: 2
7545
7705
  // Low bugs accumulate tech debt
7546
7706
  };
7547
7707
  var CATEGORY_MULTIPLIERS = {
7548
- // Security categories - based on breach cost data
7549
- "security": { multiplier: 8, reason: "Security vulnerabilities can lead to data breaches (avg $4.45M)" },
7550
- "authentication": { multiplier: 10, reason: "Auth bypass leads to complete system compromise" },
7551
- "authorization": { multiplier: 8, reason: "Authorization flaws expose sensitive data" },
7552
- "injection": { multiplier: 12, reason: "SQL/Command injection enables full system takeover" },
7553
- "xss": { multiplier: 5, reason: "XSS enables session hijacking and data theft" },
7554
- "secrets": { multiplier: 15, reason: "Exposed secrets require immediate rotation and audit" },
7555
- "cryptography": { multiplier: 6, reason: "Weak crypto undermines entire security model" },
7708
+ // Security categories - important but realistic
7709
+ "security": { multiplier: 6, reason: "Security vulnerabilities require careful remediation" },
7710
+ "authentication": { multiplier: 8, reason: "Auth bypass is serious but fixable" },
7711
+ "authorization": { multiplier: 6, reason: "Authorization flaws expose sensitive data" },
7712
+ "injection": { multiplier: 12, reason: "SQL/Command injection is severe - prioritize fix" },
7713
+ "xss": { multiplier: 4, reason: "XSS needs fixing but React mitigates most cases" },
7714
+ "secrets": { multiplier: 8, reason: "Exposed secrets require rotation" },
7715
+ "cryptography": { multiplier: 4, reason: "Weak crypto should be updated" },
7556
7716
  // Data integrity categories
7557
- "data-loss": { multiplier: 20, reason: "Data loss can be irrecoverable and legally actionable" },
7558
- "data-corruption": { multiplier: 15, reason: "Data corruption requires manual recovery and validation" },
7559
- "privacy": { multiplier: 10, reason: "Privacy violations carry regulatory fines (GDPR: 4% revenue)" },
7717
+ "data-loss": { multiplier: 10, reason: "Data loss is serious - ensure backups exist" },
7718
+ "data-corruption": { multiplier: 6, reason: "Data corruption requires recovery work" },
7719
+ "privacy": { multiplier: 8, reason: "Privacy violations carry compliance risk" },
7560
7720
  // Financial categories
7561
- "payment": { multiplier: 25, reason: "Payment bugs can cause direct financial loss or fraud" },
7562
- "billing": { multiplier: 20, reason: "Billing errors require refunds and erode trust" },
7563
- "financial-calculation": { multiplier: 15, reason: "Incorrect calculations compound over time" },
7721
+ "payment": { multiplier: 25, reason: "Payment bugs need immediate attention" },
7722
+ "billing": { multiplier: 8, reason: "Billing errors erode trust" },
7723
+ "financial-calculation": { multiplier: 6, reason: "Incorrect calculations compound over time" },
7564
7724
  // Reliability categories
7565
- "crash": { multiplier: 8, reason: "Crashes cause downtime (avg $5,600/minute)" },
7566
- "memory-leak": { multiplier: 5, reason: "Memory leaks cause gradual degradation and outages" },
7567
- "deadlock": { multiplier: 10, reason: "Deadlocks require restarts and cause data inconsistency" },
7568
- "race-condition": { multiplier: 8, reason: "Race conditions cause intermittent, hard-to-debug failures" },
7725
+ "crash": { multiplier: 4, reason: "Crashes hurt user experience" },
7726
+ "memory-leak": { multiplier: 3, reason: "Memory leaks cause gradual degradation" },
7727
+ "deadlock": { multiplier: 4, reason: "Deadlocks require restarts" },
7728
+ "race-condition": { multiplier: 4, reason: "Race conditions are hard to debug" },
7569
7729
  // User experience
7570
- "accessibility": { multiplier: 3, reason: "Accessibility issues can lead to lawsuits (ADA compliance)" },
7571
- "performance": { multiplier: 2, reason: "Performance issues hurt conversion rates (~7% per 1s delay)" },
7572
- "ux": { multiplier: 1.5, reason: "UX bugs increase support costs and churn" },
7730
+ "accessibility": { multiplier: 1.5, reason: "Accessibility issues should be addressed" },
7731
+ "performance": { multiplier: 2, reason: "Performance issues hurt conversion rates" },
7732
+ "ux": { multiplier: 1.2, reason: "UX bugs increase support costs" },
7573
7733
  // Code quality
7574
- "bug": { multiplier: 2, reason: "General bugs require developer time and QA cycles" },
7575
- "type-error": { multiplier: 1.5, reason: "Type errors caught early save debugging time" },
7576
- "logic-error": { multiplier: 3, reason: "Logic errors produce incorrect business outcomes" },
7734
+ "bug": { multiplier: 1, reason: "General bugs require developer time" },
7735
+ "type-error": { multiplier: 0.8, reason: "Type errors caught early save debugging time" },
7736
+ "logic-error": { multiplier: 1.5, reason: "Logic errors produce incorrect outcomes" },
7577
7737
  // Default
7578
- "default": { multiplier: 2, reason: "General code issues" }
7738
+ "default": { multiplier: 1, reason: "General code issues" }
7579
7739
  };
7580
7740
  var CONTEXT_MULTIPLIERS = {
7581
- touchesPayments: { multiplier: 5, description: "Payment processing code" },
7582
- touchesAuth: { multiplier: 4, description: "Authentication/authorization code" },
7583
- touchesUserData: { multiplier: 3, description: "User PII handling" },
7584
- touchesHealthData: { multiplier: 6, description: "Health data (HIPAA liability)" },
7585
- touchesDatabase: { multiplier: 2.5, description: "Database operations" },
7586
- touchesAPI: { multiplier: 2, description: "External API integrations" },
7587
- touchesCrypto: { multiplier: 3, description: "Cryptographic operations" },
7588
- touchesFileSystem: { multiplier: 2, description: "File system operations" }
7741
+ touchesPayments: { multiplier: 1.3, description: "Payment processing code" },
7742
+ touchesAuth: { multiplier: 1.2, description: "Authentication/authorization code" },
7743
+ touchesUserData: { multiplier: 1.15, description: "User PII handling" },
7744
+ touchesHealthData: { multiplier: 1.3, description: "Health data (HIPAA liability)" },
7745
+ touchesDatabase: { multiplier: 1.1, description: "Database operations" },
7746
+ touchesAPI: { multiplier: 1.1, description: "External API integrations" },
7747
+ touchesCrypto: { multiplier: 1.15, description: "Cryptographic operations" },
7748
+ touchesFileSystem: { multiplier: 1.05, description: "File system operations" }
7589
7749
  };
7590
7750
  var EFFORT_HOURS = {
7591
7751
  trivial: 0.5,
@@ -7596,16 +7756,17 @@ var EFFORT_HOURS = {
7596
7756
  var DEVELOPER_HOURLY_RATE = 150;
7597
7757
  var DEFAULT_USER_COUNT = 250;
7598
7758
  var USER_COUNT_MULTIPLIERS = [
7599
- { threshold: 0, multiplier: 0.1, label: "Pre-launch (0 users)" },
7600
- { threshold: 50, multiplier: 0.3, label: "MVP (50 users)" },
7759
+ { threshold: 0, multiplier: 0.2, label: "Pre-launch (0 users)" },
7760
+ { threshold: 50, multiplier: 0.5, label: "MVP (50 users)" },
7601
7761
  { threshold: 250, multiplier: 1, label: "Early stage (250 users)" },
7602
7762
  // Baseline (default)
7603
- { threshold: 1e3, multiplier: 2, label: "Growing (1K users)" },
7604
- { threshold: 5e3, multiplier: 4, label: "Traction (5K users)" },
7605
- { threshold: 25e3, multiplier: 8, label: "Scale-up (25K users)" },
7763
+ { threshold: 1e3, multiplier: 3, label: "Growing (1K users)" },
7764
+ { threshold: 5e3, multiplier: 6, label: "Traction (5K users)" },
7765
+ { threshold: 25e3, multiplier: 10, label: "Scale-up (25K users)" },
7606
7766
  { threshold: 1e5, multiplier: 15, label: "Growth (100K users)" },
7607
- { threshold: 5e5, multiplier: 25, label: "Large (500K users)" },
7608
- { threshold: 1e6, multiplier: 40, label: "Enterprise (1M+ users)" }
7767
+ { threshold: 5e5, multiplier: 18, label: "Large (500K users)" },
7768
+ { threshold: 1e6, multiplier: 20, label: "Enterprise (1M+ users)" }
7769
+ // Capped to avoid runaway estimates
7609
7770
  ];
7610
7771
  var PER_USER_COSTS = {
7611
7772
  "data-loss": 5,
@@ -7621,10 +7782,11 @@ var PER_USER_COSTS = {
7621
7782
  "accessibility": 0.1
7622
7783
  // $0.10 per user (support costs)
7623
7784
  };
7624
- var MoneybagAgent = class extends BaseAgent {
7785
+ var MoneybagSkill = class extends BaseSkill {
7625
7786
  name = "moneybags";
7626
7787
  description = "Estimates the dollar cost of bugs based on severity, category, and user scale. Uses industry research (IBM, NIST, Ponemon) with configurable user count scaling.";
7627
7788
  version = "1.1.0";
7789
+ author = "Trie Agent";
7628
7790
  bannerShown = false;
7629
7791
  config = {
7630
7792
  userCount: DEFAULT_USER_COUNT,
@@ -7751,7 +7913,7 @@ var MoneybagAgent = class extends BaseAgent {
7751
7913
  contextFactors.push(data.description);
7752
7914
  }
7753
7915
  }
7754
- contextMultiplier = Math.min(contextMultiplier, 10);
7916
+ contextMultiplier = Math.min(contextMultiplier, 2);
7755
7917
  const userScale = this.getUserScaleMultiplier();
7756
7918
  const userScaleMultiplier = userScale.multiplier;
7757
7919
  const userScaleLabel = userScale.label;
@@ -7773,14 +7935,15 @@ var MoneybagAgent = class extends BaseAgent {
7773
7935
  const fixHours = EFFORT_HOURS[effort] || 8;
7774
7936
  const developerRate = this.config.developerRate ?? DEVELOPER_HOURLY_RATE;
7775
7937
  const fixCost = fixHours * developerRate;
7776
- const totalNowCost = Math.round(
7777
- baseCost * categoryMultiplier * contextMultiplier * userScaleMultiplier + fixCost
7778
- );
7779
- const totalProductionCost = Math.round(
7780
- baseCost * productionMultiplier * categoryMultiplier * contextMultiplier * userScaleMultiplier + perUserCost + // Add per-user costs for production impact
7781
- fixCost * 3
7782
- // Production fixes take 3x longer (debugging, deployment, rollback, post-mortem)
7783
- );
7938
+ const BASE_NOW_CAP = 25e3;
7939
+ const BASE_PROD_CAP = 25e4;
7940
+ const maxNowCost = BASE_NOW_CAP * userScaleMultiplier;
7941
+ const maxProdCost = BASE_PROD_CAP * userScaleMultiplier;
7942
+ const rawNowCost = baseCost * categoryMultiplier * contextMultiplier + fixCost;
7943
+ const totalNowCost = Math.round(Math.min(rawNowCost, maxNowCost));
7944
+ const rawProductionCost = baseCost * productionMultiplier * categoryMultiplier * contextMultiplier + perUserCost + // Add per-user costs for production impact
7945
+ fixCost * 2;
7946
+ const totalProductionCost = Math.round(Math.min(rawProductionCost, maxProdCost));
7784
7947
  const savings = totalProductionCost - totalNowCost;
7785
7948
  const summary = this.generateCostSummary(
7786
7949
  issue,
@@ -8100,7 +8263,7 @@ Default: 250 users. Scale with: trie scan --users 10000
8100
8263
  }
8101
8264
  };
8102
8265
 
8103
- // src/agents/production-ready.ts
8266
+ // src/skills/built-in/production-ready.ts
8104
8267
  var PRODUCTION_READY_ASCII = `
8105
8268
  \u2588\u2588\u2588\u2588\u2588\u2588\u2557 \u2588\u2588\u2588\u2588\u2588\u2588\u2557 \u2588\u2588\u2588\u2588\u2588\u2588\u2557 \u2588\u2588\u2588\u2588\u2588\u2588\u2557
8106
8269
  \u2588\u2588\u2554\u2550\u2550\u2588\u2588\u2557\u2588\u2588\u2554\u2550\u2550\u2588\u2588\u2557\u2588\u2588\u2554\u2550\u2550\u2550\u2588\u2588\u2557\u2588\u2588\u2554\u2550\u2550\u2588\u2588\u2557
@@ -8123,66 +8286,76 @@ var PRODUCTION_QUOTES = [
8123
8286
  "Production is where your code meets reality. Is yours ready?"
8124
8287
  ];
8125
8288
  var PRODUCTION_PATTERNS = {
8126
- // Health & Reliability
8289
+ // Health & Reliability - BACKEND ONLY
8127
8290
  healthEndpoint: {
8128
8291
  pattern: /\/health|healthcheck|health-check|readiness|liveness/i,
8129
8292
  category: "reliability",
8130
8293
  requirement: "Health check endpoint",
8131
- severity: "serious"
8294
+ severity: "moderate",
8295
+ // Downgraded - not critical for all apps
8296
+ backendOnly: true
8132
8297
  },
8133
8298
  gracefulShutdown: {
8134
8299
  pattern: /SIGTERM|SIGINT|process\.on\s*\(\s*['"]SIG/i,
8135
8300
  category: "reliability",
8136
8301
  requirement: "Graceful shutdown handling",
8137
- severity: "moderate"
8302
+ severity: "low",
8303
+ backendOnly: true
8138
8304
  },
8139
- // Scalability
8305
+ // Scalability - BACKEND ONLY
8140
8306
  connectionPooling: {
8141
8307
  pattern: /connectionLimit|pool|poolSize|max_connections|maxConnections/i,
8142
8308
  category: "scalability",
8143
8309
  requirement: "Database connection pooling",
8144
- severity: "serious"
8310
+ severity: "moderate",
8311
+ backendOnly: true
8145
8312
  },
8146
8313
  inMemorySession: {
8147
8314
  pattern: /express-session.*(?!redis|memcached|mongo)|session\s*=\s*\{\}/i,
8148
8315
  category: "scalability",
8149
8316
  requirement: "External session store (not in-memory)",
8150
- severity: "serious"
8317
+ severity: "moderate",
8318
+ backendOnly: true
8151
8319
  },
8152
- // Error Handling
8320
+ // Error Handling - BACKEND ONLY
8153
8321
  globalErrorHandler: {
8154
8322
  pattern: /app\.use\s*\(\s*\(?err|errorHandler|process\.on\s*\(\s*['"]uncaughtException/i,
8155
8323
  category: "reliability",
8156
8324
  requirement: "Global error handler",
8157
- severity: "serious"
8325
+ severity: "moderate",
8326
+ backendOnly: true
8158
8327
  },
8159
- // Security Headers
8328
+ // Security Headers - BACKEND ONLY (frontend relies on hosting platform)
8160
8329
  securityHeaders: {
8161
8330
  pattern: /helmet|contentSecurityPolicy|X-Frame-Options|X-Content-Type|Strict-Transport/i,
8162
8331
  category: "security",
8163
8332
  requirement: "Security headers (CSP, HSTS, etc.)",
8164
- severity: "serious"
8333
+ severity: "moderate",
8334
+ backendOnly: true
8165
8335
  },
8166
- // Rate Limiting
8336
+ // Rate Limiting - BACKEND ONLY
8167
8337
  rateLimiting: {
8168
8338
  pattern: /rateLimit|rate-limit|throttle|express-rate-limit|slowDown/i,
8169
8339
  category: "security",
8170
8340
  requirement: "API rate limiting",
8171
- severity: "moderate"
8341
+ severity: "low",
8342
+ backendOnly: true
8172
8343
  },
8173
- // Logging
8344
+ // Logging - applies to both but less critical for frontend
8174
8345
  structuredLogging: {
8175
8346
  pattern: /pino|winston|bunyan|structured.*log|log.*json/i,
8176
8347
  category: "observability",
8177
8348
  requirement: "Structured logging",
8178
- severity: "moderate"
8349
+ severity: "low",
8350
+ backendOnly: false
8179
8351
  },
8180
- // Monitoring
8352
+ // Monitoring - applies to both
8181
8353
  monitoring: {
8182
8354
  pattern: /prometheus|datadog|newrelic|sentry|bugsnag|opentelemetry|@sentry/i,
8183
8355
  category: "observability",
8184
8356
  requirement: "Error/performance monitoring",
8185
- severity: "moderate"
8357
+ severity: "low",
8358
+ backendOnly: false
8186
8359
  }
8187
8360
  };
8188
8361
  var PRODUCTION_ANTIPATTERNS = [
@@ -8252,10 +8425,11 @@ var PRODUCTION_CONFIG_FILES = [
8252
8425
  /vercel\.json$/,
8253
8426
  /netlify\.toml$/
8254
8427
  ];
8255
- var ProductionReadyAgent = class extends BaseAgent {
8428
+ var ProductionReadySkill = class extends BaseSkill {
8256
8429
  name = "production-ready";
8257
8430
  description = "Production readiness checker: health endpoints, graceful shutdown, connection pooling, security headers, monitoring, and deployment gates";
8258
8431
  version = "1.0.0";
8432
+ author = "Trie Agent";
8259
8433
  bannerShown = false;
8260
8434
  foundRequirements = /* @__PURE__ */ new Set();
8261
8435
  get priority() {
@@ -8363,7 +8537,12 @@ var ProductionReadyAgent = class extends BaseAgent {
8363
8537
  }
8364
8538
  }
8365
8539
  const combinedContent = allContent.join("\n");
8540
+ const isFrontendOnly = this.detectFrontendOnlyApp(combinedContent, files);
8366
8541
  for (const [key, config] of Object.entries(PRODUCTION_PATTERNS)) {
8542
+ const patternConfig = config;
8543
+ if (isFrontendOnly && patternConfig.backendOnly) {
8544
+ continue;
8545
+ }
8367
8546
  if (!this.foundRequirements.has(key)) {
8368
8547
  if (!config.pattern.test(combinedContent)) {
8369
8548
  this.progress?.found(config.severity, `Missing: ${config.requirement}`);
@@ -8374,7 +8553,8 @@ var ProductionReadyAgent = class extends BaseAgent {
8374
8553
  this.getRequirementFix(key),
8375
8554
  "project",
8376
8555
  void 0,
8377
- 0.8,
8556
+ 0.6,
8557
+ // Lower confidence for missing checks
8378
8558
  void 0,
8379
8559
  false,
8380
8560
  { category: config.category }
@@ -8385,6 +8565,35 @@ var ProductionReadyAgent = class extends BaseAgent {
8385
8565
  this.logReadinessSummary(issues);
8386
8566
  return issues;
8387
8567
  }
8568
+ /**
8569
+ * Detect if this is a frontend-only app (React, Vue, Svelte, etc.) without a backend
8570
+ * Frontend apps don't need health endpoints, database pooling, session stores, etc.
8571
+ */
8572
+ detectFrontendOnlyApp(content, files) {
8573
+ const frontendContentPatterns = [
8574
+ /vite\.config|next\.config|nuxt\.config|svelte\.config/i,
8575
+ /from ['"]react['"]|from ['"]vue['"]|from ['"]svelte['"]/i,
8576
+ /createRoot|ReactDOM|createApp/i
8577
+ ];
8578
+ const frontendFilePatterns = [
8579
+ /\.tsx$/,
8580
+ /\.jsx$/,
8581
+ /\.vue$/,
8582
+ /\.svelte$/
8583
+ ];
8584
+ const backendIndicators = [
8585
+ /express|fastify|koa|hapi|nest|@nestjs/i,
8586
+ /createServer|http\.Server|https\.Server/i,
8587
+ /app\.listen\s*\(|server\.listen\s*\(/i,
8588
+ /middleware|router\.get|router\.post|app\.get\s*\(/i,
8589
+ /prisma|sequelize|mongoose|knex|typeorm/i
8590
+ ];
8591
+ const hasFrontendContent = frontendContentPatterns.some((p) => p.test(content));
8592
+ const hasFrontendFiles = files.some((f) => frontendFilePatterns.some((p) => p.test(f)));
8593
+ const hasFrontendSignals = hasFrontendContent || hasFrontendFiles;
8594
+ const hasBackendSignals = backendIndicators.some((p) => p.test(content));
8595
+ return hasFrontendSignals && !hasBackendSignals;
8596
+ }
8388
8597
  getRequirementFix(key) {
8389
8598
  const fixes = {
8390
8599
  healthEndpoint: 'Add health check endpoint: app.get("/health", (req, res) => res.json({ status: "ok" }))',
@@ -8480,10 +8689,1376 @@ Output STRICT JSON:
8480
8689
  }
8481
8690
  };
8482
8691
 
8483
- // src/skills/gating.ts
8484
- import { existsSync as existsSync2 } from "fs";
8485
- import { readFile } from "fs/promises";
8486
- import { join } from "path";
8692
+ // src/skills/installer.ts
8693
+ import { mkdir as mkdir2, rm, writeFile as writeFile2, readdir, readFile as readFile3, access, cp } from "fs/promises";
8694
+ import { join as join3 } from "path";
8695
+ import { exec } from "child_process";
8696
+ import { promisify } from "util";
8697
+
8698
+ // src/skills/parser.ts
8699
+ import { readFile as readFile2 } from "fs/promises";
8700
+ import { join as join2 } from "path";
8701
+ async function parseSkillMd(skillPath) {
8702
+ const skillMdPath = join2(skillPath, "SKILL.md");
8703
+ const rawContent = await readFile2(skillMdPath, "utf-8");
8704
+ const frontmatterMatch = rawContent.match(/^---\n([\s\S]*?)\n---/);
8705
+ if (!frontmatterMatch || !frontmatterMatch[1]) {
8706
+ throw new Error("Invalid SKILL.md: missing YAML frontmatter");
8707
+ }
8708
+ const frontmatter = parseYamlFrontmatter(frontmatterMatch[1]);
8709
+ if (!frontmatter.name || !frontmatter.description) {
8710
+ throw new Error("Invalid SKILL.md: missing required name or description in frontmatter");
8711
+ }
8712
+ const content = rawContent.slice(frontmatterMatch[0].length).trim();
8713
+ return {
8714
+ frontmatter,
8715
+ content,
8716
+ rawContent
8717
+ };
8718
+ }
8719
+ function parseYamlFrontmatter(yaml) {
8720
+ const result = {};
8721
+ const lines = yaml.split("\n");
8722
+ for (const line of lines) {
8723
+ const trimmed = line.trim();
8724
+ if (!trimmed || trimmed.startsWith("#")) continue;
8725
+ const colonIndex = trimmed.indexOf(":");
8726
+ if (colonIndex === -1) continue;
8727
+ const key = trimmed.slice(0, colonIndex).trim();
8728
+ let value = trimmed.slice(colonIndex + 1).trim();
8729
+ if (value === "") continue;
8730
+ if (typeof value === "string") {
8731
+ if (value.startsWith('"') && value.endsWith('"') || value.startsWith("'") && value.endsWith("'")) {
8732
+ value = value.slice(1, -1);
8733
+ }
8734
+ if (typeof value === "string" && value.startsWith("[") && value.endsWith("]")) {
8735
+ value = value.slice(1, -1).split(",").map((s) => s.trim().replace(/^["']|["']$/g, ""));
8736
+ }
8737
+ }
8738
+ result[key] = value;
8739
+ }
8740
+ return result;
8741
+ }
8742
+
8743
+ // src/skills/installer.ts
8744
+ var execAsync = promisify(exec);
8745
+ async function installSkill(source, skillName) {
8746
+ const parts = source.split("/");
8747
+ if (parts.length < 2) {
8748
+ return { success: false, name: "unknown", error: "Invalid source format. Use owner/repo or owner/repo/skill-name" };
8749
+ }
8750
+ const owner = parts[0];
8751
+ const repo = parts[1];
8752
+ const specifiedSkill = skillName || parts[2];
8753
+ const skillsDir = join3(getWorkingDirectory(void 0, true), ".trie", "skills");
8754
+ const tempDir = join3(skillsDir, `.temp-${Date.now()}`);
8755
+ try {
8756
+ await mkdir2(skillsDir, { recursive: true });
8757
+ const repoUrl = `https://github.com/${owner}/${repo}.git`;
8758
+ await execAsync(`git clone --depth 1 "${repoUrl}" "${tempDir}"`, { timeout: 6e4 });
8759
+ const sourcePath = await findSkillPath(tempDir, specifiedSkill);
8760
+ if (!sourcePath) {
8761
+ throw new Error(`SKILL.md not found in repository. Searched in: root, skills/, ${specifiedSkill || "subdirectories"}`);
8762
+ }
8763
+ const parsed = await parseSkillMd(sourcePath);
8764
+ const name = parsed.frontmatter.name;
8765
+ const targetPath = join3(skillsDir, name);
8766
+ await rm(targetPath, { recursive: true, force: true });
8767
+ await cp(sourcePath, targetPath, { recursive: true });
8768
+ await writeFile2(join3(targetPath, ".installed.json"), JSON.stringify({
8769
+ installedFrom: source,
8770
+ installedAt: (/* @__PURE__ */ new Date()).toISOString(),
8771
+ repository: `${owner}/${repo}`
8772
+ }, null, 2));
8773
+ return { success: true, name, path: targetPath };
8774
+ } catch (error) {
8775
+ const message = error instanceof Error ? error.message : String(error);
8776
+ return { success: false, name: skillName || "unknown", error: message };
8777
+ } finally {
8778
+ await rm(tempDir, { recursive: true, force: true }).catch(() => {
8779
+ });
8780
+ }
8781
+ }
8782
+ async function findSkillPath(repoPath, skillName) {
8783
+ const searchPaths = [];
8784
+ if (skillName) {
8785
+ searchPaths.push(
8786
+ join3(repoPath, "skills", skillName),
8787
+ join3(repoPath, skillName)
8788
+ );
8789
+ }
8790
+ searchPaths.push(
8791
+ repoPath,
8792
+ join3(repoPath, "skill")
8793
+ );
8794
+ if (!skillName) {
8795
+ try {
8796
+ const skillsSubdir = join3(repoPath, "skills");
8797
+ await access(skillsSubdir);
8798
+ const entries = await readdir(skillsSubdir, { withFileTypes: true });
8799
+ for (const entry of entries) {
8800
+ if (entry.isDirectory() && !entry.name.startsWith(".")) {
8801
+ searchPaths.push(join3(skillsSubdir, entry.name));
8802
+ }
8803
+ }
8804
+ } catch {
8805
+ }
8806
+ }
8807
+ for (const searchPath of searchPaths) {
8808
+ try {
8809
+ await parseSkillMd(searchPath);
8810
+ return searchPath;
8811
+ } catch {
8812
+ }
8813
+ }
8814
+ return null;
8815
+ }
8816
+ async function listInstalledSkills() {
8817
+ const skillsDir = join3(getWorkingDirectory(void 0, true), ".trie", "skills");
8818
+ const skills = [];
8819
+ try {
8820
+ const entries = await readdir(skillsDir, { withFileTypes: true });
8821
+ for (const entry of entries) {
8822
+ if (!entry.isDirectory() || entry.name.startsWith(".")) continue;
8823
+ const skillPath = join3(skillsDir, entry.name);
8824
+ try {
8825
+ const parsed = await parseSkillMd(skillPath);
8826
+ const metaPath = join3(skillPath, ".installed.json");
8827
+ let meta = { installedFrom: "unknown", installedAt: (/* @__PURE__ */ new Date()).toISOString() };
8828
+ try {
8829
+ meta = JSON.parse(await readFile3(metaPath, "utf-8"));
8830
+ } catch {
8831
+ }
8832
+ skills.push({
8833
+ name: parsed.frontmatter.name,
8834
+ description: parsed.frontmatter.description,
8835
+ path: skillPath,
8836
+ installedFrom: meta.installedFrom,
8837
+ installedAt: meta.installedAt
8838
+ });
8839
+ } catch {
8840
+ }
8841
+ }
8842
+ } catch {
8843
+ }
8844
+ return skills;
8845
+ }
8846
+ async function removeSkill(skillName) {
8847
+ const skillsDir = join3(getWorkingDirectory(void 0, true), ".trie", "skills");
8848
+ const skillPath = join3(skillsDir, skillName);
8849
+ try {
8850
+ await rm(skillPath, { recursive: true });
8851
+ return true;
8852
+ } catch {
8853
+ return false;
8854
+ }
8855
+ }
8856
+
8857
+ // src/utils/context-state.ts
8858
+ import { readFile as readFile7, writeFile as writeFile6, mkdir as mkdir6 } from "fs/promises";
8859
+ import { existsSync as existsSync6 } from "fs";
8860
+ import { join as join7, basename as basename2 } from "path";
8861
+
8862
+ // src/memory/issue-store.ts
8863
+ import { mkdir as mkdir4, writeFile as writeFile4, readFile as readFile5, readdir as readdir2 } from "fs/promises";
8864
+ import { existsSync as existsSync4 } from "fs";
8865
+ import { join as join5 } from "path";
8866
+
8867
+ // src/memory/bm25.ts
8868
+ var BM25Index = class _BM25Index {
8869
+ documents = /* @__PURE__ */ new Map();
8870
+ termFrequencies = /* @__PURE__ */ new Map();
8871
+ documentFrequencies = /* @__PURE__ */ new Map();
8872
+ documentLengths = /* @__PURE__ */ new Map();
8873
+ avgDocLength = 0;
8874
+ k1 = 1.5;
8875
+ b = 0.75;
8876
+ /**
8877
+ * Add a document to the index
8878
+ */
8879
+ addDocument(doc) {
8880
+ const tokens = this.tokenize(doc.text);
8881
+ this.documents.set(doc.id, doc);
8882
+ this.documentLengths.set(doc.id, tokens.length);
8883
+ const termFreq = /* @__PURE__ */ new Map();
8884
+ const seenTerms = /* @__PURE__ */ new Set();
8885
+ for (const token of tokens) {
8886
+ termFreq.set(token, (termFreq.get(token) || 0) + 1);
8887
+ if (!seenTerms.has(token)) {
8888
+ seenTerms.add(token);
8889
+ this.documentFrequencies.set(token, (this.documentFrequencies.get(token) || 0) + 1);
8890
+ }
8891
+ }
8892
+ this.termFrequencies.set(doc.id, termFreq);
8893
+ this.updateAvgDocLength();
8894
+ }
8895
+ /**
8896
+ * Add multiple documents
8897
+ */
8898
+ addDocuments(docs) {
8899
+ for (const doc of docs) {
8900
+ this.addDocument(doc);
8901
+ }
8902
+ }
8903
+ /**
8904
+ * Search the index
8905
+ */
8906
+ search(query, limit = 10) {
8907
+ const queryTokens = this.tokenize(query);
8908
+ const scores = /* @__PURE__ */ new Map();
8909
+ const N = this.documents.size;
8910
+ for (const [docId] of this.documents) {
8911
+ let score = 0;
8912
+ const docLength = this.documentLengths.get(docId) || 0;
8913
+ const termFreqs = this.termFrequencies.get(docId);
8914
+ if (!termFreqs) continue;
8915
+ for (const term of queryTokens) {
8916
+ const tf = termFreqs.get(term) || 0;
8917
+ if (tf === 0) continue;
8918
+ const df = this.documentFrequencies.get(term) || 0;
8919
+ const idf = Math.log((N - df + 0.5) / (df + 0.5) + 1);
8920
+ const numerator = tf * (this.k1 + 1);
8921
+ const denominator = tf + this.k1 * (1 - this.b + this.b * (docLength / this.avgDocLength));
8922
+ score += idf * (numerator / denominator);
8923
+ }
8924
+ if (score > 0) {
8925
+ scores.set(docId, score);
8926
+ }
8927
+ }
8928
+ return Array.from(scores.entries()).sort((a, b) => b[1] - a[1]).slice(0, limit).map(([id, score]) => {
8929
+ const metadata = this.documents.get(id)?.metadata;
8930
+ const result = { id, score };
8931
+ if (metadata !== void 0) {
8932
+ result.metadata = metadata;
8933
+ }
8934
+ return result;
8935
+ });
8936
+ }
8937
+ /**
8938
+ * Get document count
8939
+ */
8940
+ get size() {
8941
+ return this.documents.size;
8942
+ }
8943
+ /**
8944
+ * Clear the index
8945
+ */
8946
+ clear() {
8947
+ this.documents.clear();
8948
+ this.termFrequencies.clear();
8949
+ this.documentFrequencies.clear();
8950
+ this.documentLengths.clear();
8951
+ this.avgDocLength = 0;
8952
+ }
8953
+ /**
8954
+ * Serialize the index to JSON
8955
+ */
8956
+ serialize() {
8957
+ return JSON.stringify({
8958
+ documents: Array.from(this.documents.entries()),
8959
+ termFrequencies: Array.from(this.termFrequencies.entries()).map(([k, v]) => [k, Array.from(v.entries())]),
8960
+ documentFrequencies: Array.from(this.documentFrequencies.entries()),
8961
+ documentLengths: Array.from(this.documentLengths.entries()),
8962
+ avgDocLength: this.avgDocLength
8963
+ });
8964
+ }
8965
+ /**
8966
+ * Load from serialized JSON
8967
+ */
8968
+ static deserialize(json) {
8969
+ const data = JSON.parse(json);
8970
+ const index = new _BM25Index();
8971
+ index.documents = new Map(data.documents);
8972
+ index.termFrequencies = new Map(data.termFrequencies.map(([k, v]) => [k, new Map(v)]));
8973
+ index.documentFrequencies = new Map(data.documentFrequencies);
8974
+ index.documentLengths = new Map(data.documentLengths);
8975
+ index.avgDocLength = data.avgDocLength;
8976
+ return index;
8977
+ }
8978
+ tokenize(text) {
8979
+ return text.toLowerCase().replace(/[^\w\s]/g, " ").split(/\s+/).filter((token) => token.length > 2 && !this.isStopWord(token));
8980
+ }
8981
+ isStopWord(word) {
8982
+ const stopWords = /* @__PURE__ */ new Set([
8983
+ "the",
8984
+ "be",
8985
+ "to",
8986
+ "of",
8987
+ "and",
8988
+ "a",
8989
+ "in",
8990
+ "that",
8991
+ "have",
8992
+ "i",
8993
+ "it",
8994
+ "for",
8995
+ "not",
8996
+ "on",
8997
+ "with",
8998
+ "he",
8999
+ "as",
9000
+ "you",
9001
+ "do",
9002
+ "at",
9003
+ "this",
9004
+ "but",
9005
+ "his",
9006
+ "by",
9007
+ "from",
9008
+ "they",
9009
+ "we",
9010
+ "say",
9011
+ "her",
9012
+ "she",
9013
+ "or",
9014
+ "an",
9015
+ "will",
9016
+ "my",
9017
+ "one",
9018
+ "all",
9019
+ "would",
9020
+ "there",
9021
+ "their",
9022
+ "what",
9023
+ "so",
9024
+ "up",
9025
+ "out",
9026
+ "if",
9027
+ "about",
9028
+ "who",
9029
+ "get",
9030
+ "which",
9031
+ "go",
9032
+ "me",
9033
+ "when",
9034
+ "make",
9035
+ "can",
9036
+ "like",
9037
+ "time",
9038
+ "no",
9039
+ "just",
9040
+ "him",
9041
+ "know",
9042
+ "take",
9043
+ "into",
9044
+ "year",
9045
+ "your",
9046
+ "some",
9047
+ "could",
9048
+ "them",
9049
+ "see",
9050
+ "other",
9051
+ "than",
9052
+ "then",
9053
+ "now",
9054
+ "look",
9055
+ "only",
9056
+ "come",
9057
+ "its",
9058
+ "over",
9059
+ "also",
9060
+ "back",
9061
+ "after",
9062
+ "use",
9063
+ "two",
9064
+ "how",
9065
+ "our",
9066
+ "first",
9067
+ "way",
9068
+ "even",
9069
+ "new",
9070
+ "want",
9071
+ "because",
9072
+ "any",
9073
+ "these",
9074
+ "give",
9075
+ "day",
9076
+ "most",
9077
+ "us",
9078
+ "should",
9079
+ "been",
9080
+ "has",
9081
+ "was",
9082
+ "are"
9083
+ ]);
9084
+ return stopWords.has(word);
9085
+ }
9086
+ updateAvgDocLength() {
9087
+ if (this.documentLengths.size === 0) {
9088
+ this.avgDocLength = 0;
9089
+ return;
9090
+ }
9091
+ const total = Array.from(this.documentLengths.values()).reduce((a, b) => a + b, 0);
9092
+ this.avgDocLength = total / this.documentLengths.size;
9093
+ }
9094
+ };
9095
+
9096
+ // src/memory/compactor.ts
9097
+ import { mkdir as mkdir3, writeFile as writeFile3, readFile as readFile4 } from "fs/promises";
9098
+ import { existsSync as existsSync3 } from "fs";
9099
+ import { join as join4 } from "path";
9100
+ async function compactOldIssues(issues, options = {}) {
9101
+ const keepDays = options.keepDays ?? 30;
9102
+ const minIssues = options.minIssuesToCompact ?? 100;
9103
+ const cutoffDate = /* @__PURE__ */ new Date();
9104
+ cutoffDate.setDate(cutoffDate.getDate() - keepDays);
9105
+ const oldIssues = issues.filter((i) => new Date(i.timestamp) < cutoffDate);
9106
+ const recentIssues = issues.filter((i) => new Date(i.timestamp) >= cutoffDate);
9107
+ if (oldIssues.length < minIssues) {
9108
+ return { summary: null, remaining: issues };
9109
+ }
9110
+ const summary = buildSummary(oldIssues);
9111
+ return { summary, remaining: recentIssues };
9112
+ }
9113
+ function buildSummary(issues) {
9114
+ const sorted = issues.sort(
9115
+ (a, b) => new Date(a.timestamp).getTime() - new Date(b.timestamp).getTime()
9116
+ );
9117
+ const bySeverity = {};
9118
+ const byAgent = {};
9119
+ const patternMap = /* @__PURE__ */ new Map();
9120
+ const fileCount = /* @__PURE__ */ new Map();
9121
+ for (const issue of issues) {
9122
+ bySeverity[issue.severity] = (bySeverity[issue.severity] || 0) + 1;
9123
+ byAgent[issue.agent] = (byAgent[issue.agent] || 0) + 1;
9124
+ const patternKey = normalizePattern(issue.issue);
9125
+ const existing = patternMap.get(patternKey);
9126
+ if (existing) {
9127
+ existing.count++;
9128
+ } else {
9129
+ patternMap.set(patternKey, { count: 1, issue });
9130
+ }
9131
+ const fileName = issue.file.split("/").pop() || issue.file;
9132
+ fileCount.set(fileName, (fileCount.get(fileName) || 0) + 1);
9133
+ }
9134
+ const topPatterns = Array.from(patternMap.entries()).sort((a, b) => b[1].count - a[1].count).slice(0, 10).map(([pattern, data]) => ({
9135
+ pattern: pattern.slice(0, 100),
9136
+ count: data.count,
9137
+ severity: data.issue.severity,
9138
+ agent: data.issue.agent,
9139
+ exampleFix: data.issue.fix.slice(0, 200)
9140
+ }));
9141
+ const hotFiles = Array.from(fileCount.entries()).sort((a, b) => b[1] - a[1]).slice(0, 10).map(([file, count]) => ({ file, count }));
9142
+ return {
9143
+ period: `${sorted[0]?.timestamp.split("T")[0]} to ${sorted[sorted.length - 1]?.timestamp.split("T")[0]}`,
9144
+ startDate: sorted[0]?.timestamp || "",
9145
+ endDate: sorted[sorted.length - 1]?.timestamp || "",
9146
+ totalIssues: issues.length,
9147
+ resolvedCount: issues.filter((i) => i.resolved).length,
9148
+ bySeverity,
9149
+ byAgent,
9150
+ topPatterns,
9151
+ hotFiles,
9152
+ compactedAt: (/* @__PURE__ */ new Date()).toISOString()
9153
+ };
9154
+ }
9155
+ function normalizePattern(text) {
9156
+ return text.toLowerCase().replace(/`[^`]+`/g, "CODE").replace(/\b\d+\b/g, "N").replace(/["']/g, "").replace(/\s+/g, " ").trim().slice(0, 150);
9157
+ }
9158
+ async function saveCompactedSummary(summary, projectDir) {
9159
+ const memoryDir = join4(projectDir, ".trie", "memory");
9160
+ await mkdir3(memoryDir, { recursive: true });
9161
+ const summaryPath = join4(memoryDir, "compacted-summaries.json");
9162
+ let summaries = [];
9163
+ try {
9164
+ if (existsSync3(summaryPath)) {
9165
+ summaries = JSON.parse(await readFile4(summaryPath, "utf-8"));
9166
+ }
9167
+ } catch {
9168
+ summaries = [];
9169
+ }
9170
+ summaries.push(summary);
9171
+ if (summaries.length > 12) {
9172
+ summaries = summaries.slice(-12);
9173
+ }
9174
+ await writeFile3(summaryPath, JSON.stringify(summaries, null, 2));
9175
+ }
9176
+ async function loadCompactedSummaries(projectDir) {
9177
+ const summaryPath = join4(projectDir, ".trie", "memory", "compacted-summaries.json");
9178
+ try {
9179
+ if (existsSync3(summaryPath)) {
9180
+ return JSON.parse(await readFile4(summaryPath, "utf-8"));
9181
+ }
9182
+ } catch {
9183
+ }
9184
+ return [];
9185
+ }
9186
+ async function getHistoricalInsights(projectDir) {
9187
+ const summaries = await loadCompactedSummaries(projectDir);
9188
+ if (summaries.length === 0) {
9189
+ return {
9190
+ totalHistoricalIssues: 0,
9191
+ recurringPatterns: [],
9192
+ improvementTrend: "unknown"
9193
+ };
9194
+ }
9195
+ const totalHistoricalIssues = summaries.reduce((sum, s) => sum + s.totalIssues, 0);
9196
+ const patternCounts = /* @__PURE__ */ new Map();
9197
+ for (const summary of summaries) {
9198
+ for (const pattern of summary.topPatterns) {
9199
+ const key = pattern.pattern;
9200
+ const existing = patternCounts.get(key);
9201
+ if (existing) {
9202
+ existing.count += pattern.count;
9203
+ existing.appearances++;
9204
+ } else {
9205
+ patternCounts.set(key, { ...pattern, appearances: 1 });
9206
+ }
9207
+ }
9208
+ }
9209
+ const recurringPatterns = Array.from(patternCounts.values()).filter((p) => p.appearances >= 2).sort((a, b) => b.count - a.count).slice(0, 5);
9210
+ let improvementTrend = "unknown";
9211
+ if (summaries.length >= 2) {
9212
+ const recent = summaries.slice(-2);
9213
+ const olderCount = recent[0]?.totalIssues || 0;
9214
+ const newerCount = recent[1]?.totalIssues || 0;
9215
+ if (newerCount < olderCount * 0.8) {
9216
+ improvementTrend = "improving";
9217
+ } else if (newerCount > olderCount * 1.2) {
9218
+ improvementTrend = "declining";
9219
+ } else {
9220
+ improvementTrend = "stable";
9221
+ }
9222
+ }
9223
+ return {
9224
+ totalHistoricalIssues,
9225
+ recurringPatterns,
9226
+ improvementTrend
9227
+ };
9228
+ }
9229
+
9230
+ // src/memory/issue-store.ts
9231
+ async function storeIssues(issues, project, workDir) {
9232
+ const projectDir = workDir || getWorkingDirectory(void 0, true);
9233
+ const memoryDir = join5(projectDir, ".trie", "memory");
9234
+ await mkdir4(memoryDir, { recursive: true });
9235
+ const stored = [];
9236
+ const now = (/* @__PURE__ */ new Date()).toISOString();
9237
+ for (const issue of issues) {
9238
+ const hash = hashIssue(issue);
9239
+ const storedIssue = {
9240
+ id: issue.id,
9241
+ hash,
9242
+ severity: issue.severity,
9243
+ issue: issue.issue,
9244
+ fix: issue.fix,
9245
+ file: issue.file,
9246
+ agent: issue.agent,
9247
+ timestamp: now,
9248
+ project,
9249
+ resolved: false
9250
+ };
9251
+ if (issue.line !== void 0) {
9252
+ storedIssue.line = issue.line;
9253
+ }
9254
+ if (issue.category !== void 0) {
9255
+ storedIssue.category = issue.category;
9256
+ }
9257
+ stored.push(storedIssue);
9258
+ }
9259
+ await appendToDailyLog(stored, projectDir);
9260
+ await updateIssueIndex(stored, projectDir);
9261
+ return stored.length;
9262
+ }
9263
+ async function searchIssues(query, options = {}) {
9264
+ const projectDir = options.workDir || getWorkingDirectory(void 0, true);
9265
+ const limit = options.limit || 10;
9266
+ const allIssues = await loadIssueIndex(projectDir);
9267
+ if (allIssues.length === 0) {
9268
+ return [];
9269
+ }
9270
+ const filteredIssues = allIssues.filter((issue) => {
9271
+ if (options.project && issue.project !== options.project) return false;
9272
+ if (options.severity && !options.severity.includes(issue.severity)) return false;
9273
+ if (options.agent && issue.agent !== options.agent) return false;
9274
+ if (!options.includeResolved && issue.resolved) return false;
9275
+ return true;
9276
+ });
9277
+ if (filteredIssues.length === 0) {
9278
+ return [];
9279
+ }
9280
+ const bm25 = new BM25Index();
9281
+ const issueMap = /* @__PURE__ */ new Map();
9282
+ for (const issue of filteredIssues) {
9283
+ const searchText = `${issue.issue} ${issue.fix} ${issue.file} ${issue.agent} ${issue.category || ""} ${issue.severity}`;
9284
+ bm25.addDocument({
9285
+ id: issue.id,
9286
+ text: searchText
9287
+ });
9288
+ issueMap.set(issue.id, issue);
9289
+ }
9290
+ const bm25Results = bm25.search(query, limit);
9291
+ return bm25Results.map((result) => ({
9292
+ issue: issueMap.get(result.id),
9293
+ score: result.score,
9294
+ matchType: "bm25"
9295
+ }));
9296
+ }
9297
+ async function findSimilarIssues(issue, options = {}) {
9298
+ const query = `${issue.issue} ${issue.fix} ${issue.agent}`;
9299
+ const searchOptions = {
9300
+ limit: (options.limit || 5) + 5,
9301
+ // Get extra to account for filtering
9302
+ includeResolved: true
9303
+ };
9304
+ if (options.workDir !== void 0) {
9305
+ searchOptions.workDir = options.workDir;
9306
+ }
9307
+ const results = await searchIssues(query, searchOptions);
9308
+ let filtered = results.filter((r) => r.issue.id !== issue.id);
9309
+ if (options.excludeSameFile) {
9310
+ filtered = filtered.filter((r) => r.issue.file !== issue.file);
9311
+ }
9312
+ return filtered.slice(0, options.limit || 5);
9313
+ }
9314
+ async function markIssueResolved(issueId, workDir) {
9315
+ const projectDir = workDir || getWorkingDirectory(void 0, true);
9316
+ const index = await loadIssueIndex(projectDir);
9317
+ const issue = index.find((i) => i.id === issueId);
9318
+ if (!issue) return false;
9319
+ issue.resolved = true;
9320
+ issue.resolvedAt = (/* @__PURE__ */ new Date()).toISOString();
9321
+ await saveIssueIndex(index, projectDir);
9322
+ return true;
9323
+ }
9324
+ async function getMemoryStats(workDir) {
9325
+ const projectDir = workDir || getWorkingDirectory(void 0, true);
9326
+ const index = await loadIssueIndex(projectDir);
9327
+ const historical = await getHistoricalInsights(projectDir);
9328
+ const stats = {
9329
+ totalIssues: index.length,
9330
+ issuesByAgent: {},
9331
+ issuesBySeverity: {},
9332
+ resolvedCount: 0,
9333
+ historicalIssues: historical.totalHistoricalIssues,
9334
+ improvementTrend: historical.improvementTrend
9335
+ };
9336
+ for (const issue of index) {
9337
+ stats.issuesByAgent[issue.agent] = (stats.issuesByAgent[issue.agent] || 0) + 1;
9338
+ stats.issuesBySeverity[issue.severity] = (stats.issuesBySeverity[issue.severity] || 0) + 1;
9339
+ if (issue.resolved) stats.resolvedCount++;
9340
+ }
9341
+ if (index.length > 0) {
9342
+ const sorted = [...index].sort(
9343
+ (a, b) => new Date(a.timestamp).getTime() - new Date(b.timestamp).getTime()
9344
+ );
9345
+ const oldest = sorted[0]?.timestamp;
9346
+ const newest = sorted[sorted.length - 1]?.timestamp;
9347
+ if (oldest !== void 0) {
9348
+ stats.oldestIssue = oldest;
9349
+ }
9350
+ if (newest !== void 0) {
9351
+ stats.newestIssue = newest;
9352
+ }
9353
+ }
9354
+ return stats;
9355
+ }
9356
+ async function getRecentIssues(options = {}) {
9357
+ const projectDir = options.workDir || getWorkingDirectory(void 0, true);
9358
+ const index = await loadIssueIndex(projectDir);
9359
+ const limit = options.limit || 20;
9360
+ const daysBack = options.daysBack || 7;
9361
+ const cutoff = /* @__PURE__ */ new Date();
9362
+ cutoff.setDate(cutoff.getDate() - daysBack);
9363
+ return index.filter((i) => new Date(i.timestamp) >= cutoff).sort((a, b) => new Date(b.timestamp).getTime() - new Date(a.timestamp).getTime()).slice(0, limit);
9364
+ }
9365
+ async function getDailyLogs(workDir) {
9366
+ const projectDir = workDir || getWorkingDirectory(void 0, true);
9367
+ const memoryDir = join5(projectDir, ".trie", "memory");
9368
+ try {
9369
+ if (!existsSync4(memoryDir)) return [];
9370
+ const files = await readdir2(memoryDir);
9371
+ return files.filter((f) => /^\d{4}-\d{2}-\d{2}\.md$/.test(f)).sort().reverse();
9372
+ } catch {
9373
+ return [];
9374
+ }
9375
+ }
9376
+ async function appendToDailyLog(issues, projectDir) {
9377
+ const memoryDir = join5(projectDir, ".trie", "memory");
9378
+ const today = (/* @__PURE__ */ new Date()).toISOString().split("T")[0];
9379
+ const logPath = join5(memoryDir, `${today}.md`);
9380
+ let content = "";
9381
+ try {
9382
+ if (existsSync4(logPath)) {
9383
+ content = await readFile5(logPath, "utf-8");
9384
+ } else {
9385
+ content = `# Issue Log: ${today}
9386
+
9387
+ `;
9388
+ }
9389
+ } catch {
9390
+ content = `# Issue Log: ${today}
9391
+
9392
+ `;
9393
+ }
9394
+ const time = (/* @__PURE__ */ new Date()).toTimeString().split(" ")[0];
9395
+ const newEntries = issues.map(
9396
+ (i) => `## [${time}] ${i.severity.toUpperCase()}: ${i.issue.slice(0, 80)}${i.issue.length > 80 ? "..." : ""}
9397
+ - **File:** \`${i.file}\`${i.line ? `:${i.line}` : ""}
9398
+ - **Agent:** ${i.agent}
9399
+ - **Fix:** ${i.fix.slice(0, 200)}${i.fix.length > 200 ? "..." : ""}
9400
+ `
9401
+ ).join("\n");
9402
+ content += newEntries + "\n";
9403
+ await writeFile4(logPath, content);
9404
+ }
9405
+ async function loadIssueIndex(projectDir) {
9406
+ const indexPath = join5(projectDir, ".trie", "memory", "issues.json");
9407
+ try {
9408
+ if (existsSync4(indexPath)) {
9409
+ const content = await readFile5(indexPath, "utf-8");
9410
+ return JSON.parse(content);
9411
+ }
9412
+ } catch {
9413
+ }
9414
+ return [];
9415
+ }
9416
+ async function updateIssueIndex(newIssues, projectDir) {
9417
+ const memoryDir = join5(projectDir, ".trie", "memory");
9418
+ await mkdir4(memoryDir, { recursive: true });
9419
+ let existing = await loadIssueIndex(projectDir);
9420
+ const hashSet = new Set(existing.map((i) => i.hash));
9421
+ const toAdd = newIssues.filter((i) => !hashSet.has(i.hash));
9422
+ existing = [...existing, ...toAdd];
9423
+ if (existing.length > 500) {
9424
+ const { summary, remaining } = await compactOldIssues(existing, {
9425
+ keepDays: 30,
9426
+ minIssuesToCompact: 100
9427
+ });
9428
+ if (summary) {
9429
+ await saveCompactedSummary(summary, projectDir);
9430
+ existing = remaining;
9431
+ }
9432
+ }
9433
+ if (existing.length > 1e3) {
9434
+ existing = existing.sort((a, b) => new Date(b.timestamp).getTime() - new Date(a.timestamp).getTime()).slice(0, 1e3);
9435
+ }
9436
+ await saveIssueIndex(existing, projectDir);
9437
+ }
9438
+ async function saveIssueIndex(issues, projectDir) {
9439
+ const indexPath = join5(projectDir, ".trie", "memory", "issues.json");
9440
+ await writeFile4(indexPath, JSON.stringify(issues, null, 2));
9441
+ }
9442
+ function hashIssue(issue) {
9443
+ const content = `${issue.issue}|${issue.file}|${issue.severity}|${issue.agent}`;
9444
+ let hash = 0;
9445
+ for (let i = 0; i < content.length; i++) {
9446
+ const char = content.charCodeAt(i);
9447
+ hash = (hash << 5) - hash + char;
9448
+ hash = hash & hash;
9449
+ }
9450
+ return Math.abs(hash).toString(36);
9451
+ }
9452
+
9453
+ // src/memory/global-memory.ts
9454
+ import { mkdir as mkdir5, writeFile as writeFile5, readFile as readFile6, readdir as readdir3 } from "fs/promises";
9455
+ import { existsSync as existsSync5 } from "fs";
9456
+ import { join as join6 } from "path";
9457
+ import { homedir } from "os";
9458
+ var GLOBAL_TRIE_DIR = join6(homedir(), ".trie");
9459
+ var GLOBAL_MEMORY_DIR = join6(GLOBAL_TRIE_DIR, "memory");
9460
+ async function recordToGlobalMemory(issues, projectName, projectPath, healthScore = 0) {
9461
+ await mkdir5(GLOBAL_MEMORY_DIR, { recursive: true });
9462
+ await mkdir5(join6(GLOBAL_MEMORY_DIR, "projects"), { recursive: true });
9463
+ const patterns = await loadGlobalPatterns();
9464
+ const now = (/* @__PURE__ */ new Date()).toISOString();
9465
+ for (const issue of issues) {
9466
+ const patternId = extractPatternId(issue);
9467
+ const existing = patterns.find((p) => p.id === patternId);
9468
+ if (existing) {
9469
+ existing.occurrences++;
9470
+ existing.lastSeen = now;
9471
+ if (!existing.projects.includes(projectName)) {
9472
+ existing.projects.push(projectName);
9473
+ }
9474
+ } else {
9475
+ patterns.push({
9476
+ id: patternId,
9477
+ pattern: issue.issue.slice(0, 200),
9478
+ description: issue.fix.slice(0, 200),
9479
+ severity: issue.severity,
9480
+ agent: issue.agent,
9481
+ occurrences: 1,
9482
+ projects: [projectName],
9483
+ firstSeen: now,
9484
+ lastSeen: now
9485
+ });
9486
+ }
9487
+ }
9488
+ await saveGlobalPatterns(patterns);
9489
+ const summaryPath = join6(GLOBAL_MEMORY_DIR, "projects", `${sanitizeName(projectName)}.json`);
9490
+ const summary = {
9491
+ name: projectName,
9492
+ path: projectPath,
9493
+ lastScan: now,
9494
+ healthScore,
9495
+ totalIssues: issues.length,
9496
+ patterns: [...new Set(issues.map((i) => extractPatternId(i)))]
9497
+ };
9498
+ await writeFile5(summaryPath, JSON.stringify(summary, null, 2));
9499
+ }
9500
+ async function findCrossProjectPatterns(minOccurrences = 2) {
9501
+ const patterns = await loadGlobalPatterns();
9502
+ return patterns.filter((p) => p.projects.length >= minOccurrences).sort((a, b) => b.occurrences - a.occurrences);
9503
+ }
9504
+ async function listTrackedProjects() {
9505
+ const projectsDir = join6(GLOBAL_MEMORY_DIR, "projects");
9506
+ try {
9507
+ if (!existsSync5(projectsDir)) return [];
9508
+ const files = await readdir3(projectsDir);
9509
+ const summaries = [];
9510
+ for (const file of files) {
9511
+ if (!file.endsWith(".json")) continue;
9512
+ try {
9513
+ const content = await readFile6(join6(projectsDir, file), "utf-8");
9514
+ summaries.push(JSON.parse(content));
9515
+ } catch {
9516
+ }
9517
+ }
9518
+ return summaries.sort(
9519
+ (a, b) => new Date(b.lastScan).getTime() - new Date(a.lastScan).getTime()
9520
+ );
9521
+ } catch {
9522
+ return [];
9523
+ }
9524
+ }
9525
+ async function getGlobalMemoryStats() {
9526
+ const patterns = await loadGlobalPatterns();
9527
+ const projects = await listTrackedProjects();
9528
+ const patternsByAgent = {};
9529
+ for (const pattern of patterns) {
9530
+ patternsByAgent[pattern.agent] = (patternsByAgent[pattern.agent] || 0) + 1;
9531
+ }
9532
+ return {
9533
+ totalPatterns: patterns.length,
9534
+ crossProjectPatterns: patterns.filter((p) => p.projects.length >= 2).length,
9535
+ trackedProjects: projects.length,
9536
+ totalOccurrences: patterns.reduce((sum, p) => sum + p.occurrences, 0),
9537
+ fixedPatterns: patterns.filter((p) => p.fixApplied).length,
9538
+ patternsByAgent
9539
+ };
9540
+ }
9541
+ async function updateGlobalMemoryMd() {
9542
+ const patterns = await loadGlobalPatterns();
9543
+ const crossProject = patterns.filter((p) => p.projects.length >= 2);
9544
+ const projects = await listTrackedProjects();
9545
+ const lines = [
9546
+ "# Global Trie Memory",
9547
+ "",
9548
+ "> Auto-generated file tracking patterns across all your projects.",
9549
+ `> Last updated: ${(/* @__PURE__ */ new Date()).toISOString()}`,
9550
+ "",
9551
+ "## Summary",
9552
+ "",
9553
+ `- **Projects tracked:** ${projects.length}`,
9554
+ `- **Total patterns:** ${patterns.length}`,
9555
+ `- **Cross-project patterns:** ${crossProject.length}`,
9556
+ "",
9557
+ "## Cross-Project Patterns",
9558
+ "",
9559
+ "These issues appear in multiple projects:",
9560
+ ""
9561
+ ];
9562
+ for (const p of crossProject.slice(0, 20)) {
9563
+ lines.push(
9564
+ `### ${p.pattern.slice(0, 60)}${p.pattern.length > 60 ? "..." : ""}`,
9565
+ "",
9566
+ `- **Severity:** ${p.severity}`,
9567
+ `- **Agent:** ${p.agent}`,
9568
+ `- **Occurrences:** ${p.occurrences} across ${p.projects.length} projects`,
9569
+ `- **Projects:** ${p.projects.slice(0, 5).join(", ")}${p.projects.length > 5 ? "..." : ""}`
9570
+ );
9571
+ if (p.fixApplied) {
9572
+ lines.push(`- **Fixed in:** ${p.fixApplied.project} on ${p.fixApplied.timestamp.split("T")[0]}`);
9573
+ } else {
9574
+ lines.push("- **Status:** Not fixed");
9575
+ }
9576
+ lines.push("");
9577
+ }
9578
+ lines.push(
9579
+ "## Tracked Projects",
9580
+ "",
9581
+ "| Project | Last Scan | Health | Issues |",
9582
+ "|---------|-----------|--------|--------|"
9583
+ );
9584
+ for (const p of projects.slice(0, 20)) {
9585
+ lines.push(`| ${p.name} | ${p.lastScan.split("T")[0]} | ${p.healthScore}% | ${p.totalIssues} |`);
9586
+ }
9587
+ lines.push("", "---", "", "*This file is auto-generated by Trie. Do not edit manually.*");
9588
+ await mkdir5(GLOBAL_MEMORY_DIR, { recursive: true });
9589
+ await writeFile5(join6(GLOBAL_MEMORY_DIR, "GLOBAL_MEMORY.md"), lines.join("\n"));
9590
+ }
9591
+ async function searchGlobalPatterns(query, options = {}) {
9592
+ const patterns = await loadGlobalPatterns();
9593
+ const limit = options.limit || 10;
9594
+ const queryTerms = query.toLowerCase().split(/\s+/).filter((t) => t.length > 2);
9595
+ const scored = patterns.filter((p) => {
9596
+ if (options.severity && !options.severity.includes(p.severity)) return false;
9597
+ if (options.agent && p.agent !== options.agent) return false;
9598
+ return true;
9599
+ }).map((p) => {
9600
+ const text = `${p.pattern} ${p.description} ${p.agent}`.toLowerCase();
9601
+ let score = 0;
9602
+ for (const term of queryTerms) {
9603
+ if (text.includes(term)) score++;
9604
+ }
9605
+ return { pattern: p, score };
9606
+ }).filter((s) => s.score > 0).sort((a, b) => b.score - a.score).slice(0, limit);
9607
+ return scored.map((s) => s.pattern);
9608
+ }
9609
+ async function loadGlobalPatterns() {
9610
+ const patternsPath = join6(GLOBAL_MEMORY_DIR, "global-patterns.json");
9611
+ try {
9612
+ if (existsSync5(patternsPath)) {
9613
+ const content = await readFile6(patternsPath, "utf-8");
9614
+ return JSON.parse(content);
9615
+ }
9616
+ } catch {
9617
+ }
9618
+ return [];
9619
+ }
9620
+ async function saveGlobalPatterns(patterns) {
9621
+ await mkdir5(GLOBAL_MEMORY_DIR, { recursive: true });
9622
+ const patternsPath = join6(GLOBAL_MEMORY_DIR, "global-patterns.json");
9623
+ const pruned = patterns.sort((a, b) => new Date(b.lastSeen).getTime() - new Date(a.lastSeen).getTime()).slice(0, 500);
9624
+ await writeFile5(patternsPath, JSON.stringify(pruned, null, 2));
9625
+ }
9626
+ function extractPatternId(issue) {
9627
+ const normalized = issue.issue.toLowerCase().replace(/`[^`]+`/g, "CODE").replace(/\b\d+\b/g, "N").replace(/['"]/g, "").slice(0, 100);
9628
+ let hash = 0;
9629
+ for (let i = 0; i < normalized.length; i++) {
9630
+ const char = normalized.charCodeAt(i);
9631
+ hash = (hash << 5) - hash + char;
9632
+ hash = hash & hash;
9633
+ }
9634
+ return `${issue.agent}-${issue.severity}-${Math.abs(hash).toString(36)}`;
9635
+ }
9636
+ function sanitizeName(name) {
9637
+ return name.replace(/[^a-zA-Z0-9-_]/g, "-").toLowerCase();
9638
+ }
9639
+
9640
+ // src/utils/context-state.ts
9641
+ var AGENTS_MD_PATH = ".trie/AGENTS.md";
9642
+ var STATE_JSON_PATH = ".trie/state.json";
9643
+ async function loadContextState() {
9644
+ const workDir = getWorkingDirectory(void 0, true);
9645
+ const statePath = join7(workDir, STATE_JSON_PATH);
9646
+ const defaults = getDefaultState();
9647
+ try {
9648
+ if (existsSync6(statePath)) {
9649
+ const content = await readFile7(statePath, "utf-8");
9650
+ const loaded = JSON.parse(content);
9651
+ return {
9652
+ ...defaults,
9653
+ ...loaded,
9654
+ skills: loaded.skills || defaults.skills
9655
+ };
9656
+ }
9657
+ } catch {
9658
+ }
9659
+ return defaults;
9660
+ }
9661
+ async function saveContextState(state) {
9662
+ const workDir = getWorkingDirectory(void 0, true);
9663
+ const trieDir = join7(workDir, ".trie");
9664
+ const statePath = join7(workDir, STATE_JSON_PATH);
9665
+ await mkdir6(trieDir, { recursive: true });
9666
+ await writeFile6(statePath, JSON.stringify(state, null, 2));
9667
+ }
9668
+ async function updateContextAfterScan(results, filesScanned, contextSignals, duration) {
9669
+ const state = await loadContextState();
9670
+ const workDir = getWorkingDirectory(void 0, true);
9671
+ const now = (/* @__PURE__ */ new Date()).toISOString();
9672
+ const allIssues = results.flatMap((r) => r.issues);
9673
+ const issueCounts = {
9674
+ critical: allIssues.filter((i) => i.severity === "critical").length,
9675
+ serious: allIssues.filter((i) => i.severity === "serious").length,
9676
+ moderate: allIssues.filter((i) => i.severity === "moderate").length,
9677
+ low: allIssues.filter((i) => i.severity === "low").length,
9678
+ total: allIssues.length
9679
+ };
9680
+ const fileIssueMap = /* @__PURE__ */ new Map();
9681
+ for (const issue of allIssues) {
9682
+ const count = fileIssueMap.get(issue.file) || 0;
9683
+ fileIssueMap.set(issue.file, count + 1);
9684
+ }
9685
+ const hotFiles = Array.from(fileIssueMap.entries()).sort((a, b) => b[1] - a[1]).slice(0, 10).map(([file, issueCount]) => ({ file, issueCount }));
9686
+ const scanSummary = {
9687
+ timestamp: now,
9688
+ agents: results.map((r) => r.agent),
9689
+ filesScanned,
9690
+ issues: issueCounts,
9691
+ duration,
9692
+ hotFiles
9693
+ };
9694
+ for (const result of results) {
9695
+ state.agentStatus[result.agent] = {
9696
+ lastRun: now,
9697
+ issuesFound: result.issues.length
9698
+ };
9699
+ }
9700
+ const criticalPenalty = issueCounts.critical * 25;
9701
+ const seriousPenalty = issueCounts.serious * 10;
9702
+ const moderatePenalty = issueCounts.moderate * 3;
9703
+ const lowPenalty = issueCounts.low * 1;
9704
+ const totalPenalty = Math.min(100, criticalPenalty + seriousPenalty + moderatePenalty + lowPenalty);
9705
+ state.healthScore = Math.max(0, 100 - totalPenalty);
9706
+ state.activePriorities = generatePriorities(issueCounts, contextSignals);
9707
+ state.contextSignals = { ...state.contextSignals, ...contextSignals };
9708
+ state.scanHistory = [scanSummary, ...state.scanHistory.slice(0, 19)];
9709
+ state.lastScan = scanSummary;
9710
+ await saveContextState(state);
9711
+ await updateAgentsMd(state);
9712
+ if (allIssues.length > 0) {
9713
+ const projectName = basename2(workDir);
9714
+ try {
9715
+ await storeIssues(allIssues, projectName, workDir);
9716
+ await recordToGlobalMemory(allIssues, projectName, workDir, state.healthScore);
9717
+ await updateGlobalMemoryMd();
9718
+ } catch {
9719
+ }
9720
+ }
9721
+ }
9722
+ async function updateAgentsMd(state) {
9723
+ const workDir = getWorkingDirectory(void 0, true);
9724
+ const mdPath = join7(workDir, AGENTS_MD_PATH);
9725
+ let content;
9726
+ try {
9727
+ content = await readFile7(mdPath, "utf-8");
9728
+ } catch {
9729
+ content = getAgentsMdTemplate();
9730
+ }
9731
+ content = updateSection(content, "Project State", generateProjectStateTable(state));
9732
+ content = updateSection(content, "Active Priorities", generatePrioritiesList(state));
9733
+ content = updateSection(content, "Agent Status", generateAgentStatusTable(state));
9734
+ content = updateSection(content, "Recent Scan History", generateScanHistoryTable(state));
9735
+ content = updateSection(content, "Context Signals Detected", generateContextSignals(state));
9736
+ content = updateSection(content, "Risk Assessment", generateRiskAssessment(state));
9737
+ content = updateSection(content, "Hot Files", generateHotFilesSection(state));
9738
+ content = content.replace(
9739
+ /Last updated:.*$/m,
9740
+ `Last updated: ${(/* @__PURE__ */ new Date()).toISOString()}`
9741
+ );
9742
+ await writeFile6(mdPath, content);
9743
+ }
9744
+ function updateSection(content, sectionName, newContent) {
9745
+ const sectionRegex = new RegExp(
9746
+ `(### ${sectionName}[\\s\\S]*?)(?=###|---|
9747
+ ## |$)`,
9748
+ "g"
9749
+ );
9750
+ const replacement = `### ${sectionName}
9751
+ ${newContent}
9752
+
9753
+ `;
9754
+ if (content.match(sectionRegex)) {
9755
+ return content.replace(sectionRegex, replacement);
9756
+ }
9757
+ return content;
9758
+ }
9759
+ function generateProjectStateTable(state) {
9760
+ const lastScan = state.lastScan;
9761
+ const lastScanDate = lastScan ? new Date(lastScan.timestamp).toLocaleString() : "Never";
9762
+ const criticalCount = lastScan?.issues.critical ?? 0;
9763
+ const totalTasks = lastScan?.issues.total ?? 0;
9764
+ return `| Metric | Value | Updated |
9765
+ |--------|-------|---------|
9766
+ | Last Scan | ${lastScanDate} | ${lastScan ? "Auto" : "-"} |
9767
+ | Critical Issues | ${criticalCount} | ${lastScan ? "Auto" : "-"} |
9768
+ | Open Tasks | ${totalTasks} | ${lastScan ? "Auto" : "-"} |
9769
+ | Health Score | ${state.healthScore}% | ${lastScan ? "Auto" : "-"} |`;
9770
+ }
9771
+ function generatePrioritiesList(state) {
9772
+ if (state.activePriorities.length === 0) {
9773
+ return "_No active priorities. Run a scan to identify issues._";
9774
+ }
9775
+ return state.activePriorities.map((p, i) => `${i + 1}. ${p}`).join("\n");
9776
+ }
9777
+ function generatePriorities(issues, contextSignals) {
9778
+ const priorities = [];
9779
+ if (issues.critical > 0) {
9780
+ priorities.push(`\u{1F6A8} Fix ${issues.critical} critical security issue${issues.critical > 1 ? "s" : ""} immediately`);
9781
+ }
9782
+ if (issues.serious > 0) {
9783
+ priorities.push(`\u26A0\uFE0F Address ${issues.serious} serious issue${issues.serious > 1 ? "s" : ""} before deployment`);
9784
+ }
9785
+ if (contextSignals.touchesAuth && issues.critical === 0) {
9786
+ priorities.push("\u2705 Auth code reviewed - continue monitoring");
9787
+ }
9788
+ if (contextSignals.touchesPayments) {
9789
+ priorities.push("\u{1F4B3} Payment code detected - ensure PCI compliance");
9790
+ }
9791
+ if (contextSignals.touchesUserData) {
9792
+ priorities.push("\u{1F510} User data handling detected - verify privacy compliance");
9793
+ }
9794
+ if (issues.moderate > 5) {
9795
+ priorities.push(`\u{1F4CB} Schedule time to address ${issues.moderate} moderate issues`);
9796
+ }
9797
+ if (priorities.length === 0) {
9798
+ priorities.push("\u2728 No critical issues - focus on feature development");
9799
+ }
9800
+ return priorities.slice(0, 5);
9801
+ }
9802
+ function generateAgentStatusTable(state) {
9803
+ const builtInAgents = [
9804
+ "security",
9805
+ "privacy",
9806
+ "legal",
9807
+ "accessibility",
9808
+ "bugs",
9809
+ "design",
9810
+ "architecture",
9811
+ "performance",
9812
+ "devops",
9813
+ "soc2",
9814
+ "e2e",
9815
+ "typecheck",
9816
+ "visual-qa",
9817
+ "data-flow"
9818
+ ];
9819
+ let table = `| Agent | Status | Last Run | Issues Found |
9820
+ |-------|--------|----------|--------------|`;
9821
+ for (const agent of builtInAgents) {
9822
+ const status = state.agentStatus[agent];
9823
+ const lastRun = status?.lastRun ? new Date(status.lastRun).toLocaleDateString() : "Never";
9824
+ const issues = status?.issuesFound ?? "-";
9825
+ const statusEmoji = status ? "\u2705" : "\u23F8\uFE0F";
9826
+ table += `
9827
+ | ${agent} | ${statusEmoji} Ready | ${lastRun} | ${issues} |`;
9828
+ }
9829
+ return table;
9830
+ }
9831
+ function generateScanHistoryTable(state) {
9832
+ if (state.scanHistory.length === 0) {
9833
+ return `| Date | Agents | Files | Issues | Duration |
9834
+ |------|--------|-------|--------|----------|
9835
+ | - | - | - | - | - |`;
9836
+ }
9837
+ let table = `| Date | Agents | Files | Issues | Duration |
9838
+ |------|--------|-------|--------|----------|`;
9839
+ for (const scan of state.scanHistory.slice(0, 10)) {
9840
+ const date = new Date(scan.timestamp).toLocaleDateString();
9841
+ const agents = scan.agents.slice(0, 3).join(", ") + (scan.agents.length > 3 ? "..." : "");
9842
+ const duration = `${(scan.duration / 1e3).toFixed(1)}s`;
9843
+ table += `
9844
+ | ${date} | ${agents} | ${scan.filesScanned} | ${scan.issues.total} | ${duration} |`;
9845
+ }
9846
+ return table;
9847
+ }
9848
+ function generateContextSignals(state) {
9849
+ const signals = [
9850
+ "touchesAuth",
9851
+ "touchesPayments",
9852
+ "touchesUserData",
9853
+ "touchesAPI",
9854
+ "touchesDatabase",
9855
+ "touchesCrypto"
9856
+ ];
9857
+ return signals.map((s) => {
9858
+ const value = state.contextSignals[s];
9859
+ const emoji = value === true ? "\u2705" : value === false ? "\u274C" : "\u2753";
9860
+ return `- \`${s}\`: ${emoji} ${value === void 0 ? "Unknown" : value ? "Yes" : "No"}`;
9861
+ }).join("\n");
9862
+ }
9863
+ function generateRiskAssessment(state) {
9864
+ const score = state.healthScore;
9865
+ let riskLevel;
9866
+ let confidence;
9867
+ if (state.lastScan === null) {
9868
+ return `- Overall Risk: Unknown
9869
+ - Confidence: 0%`;
9870
+ }
9871
+ if (score >= 90) {
9872
+ riskLevel = "\u{1F7E2} Low";
9873
+ confidence = 95;
9874
+ } else if (score >= 70) {
9875
+ riskLevel = "\u{1F7E1} Medium";
9876
+ confidence = 85;
9877
+ } else if (score >= 50) {
9878
+ riskLevel = "\u{1F7E0} High";
9879
+ confidence = 80;
9880
+ } else {
9881
+ riskLevel = "\u{1F534} Critical";
9882
+ confidence = 90;
9883
+ }
9884
+ return `- Overall Risk: ${riskLevel}
9885
+ - Health Score: ${score}%
9886
+ - Confidence: ${confidence}%`;
9887
+ }
9888
+ function generateHotFilesSection(state) {
9889
+ if (!state.lastScan || state.lastScan.hotFiles.length === 0) {
9890
+ return "_Run a scan to identify hot files._";
9891
+ }
9892
+ return state.lastScan.hotFiles.map((f) => `- \`${f.file}\` - ${f.issueCount} issue${f.issueCount > 1 ? "s" : ""}`).join("\n");
9893
+ }
9894
+ function getDefaultState() {
9895
+ return {
9896
+ lastScan: null,
9897
+ healthScore: 0,
9898
+ activePriorities: [
9899
+ "Initial setup required - run first scan with `trie scan`",
9900
+ "Configure agents in `.trie/config.json`",
9901
+ "Set up CI/CD integration"
9902
+ ],
9903
+ contextSignals: {},
9904
+ agentStatus: {},
9905
+ scanHistory: [],
9906
+ customAgents: [],
9907
+ skills: {},
9908
+ environment: detectEnvironment()
9909
+ };
9910
+ }
9911
+ function detectEnvironment() {
9912
+ if (process.env.GITHUB_ACTIONS) return "github-actions";
9913
+ if (process.env.GITLAB_CI) return "gitlab-ci";
9914
+ if (process.env.CI) return "ci";
9915
+ const parent = process.env._ || "";
9916
+ if (parent.includes("cursor")) return "cursor";
9917
+ if (parent.includes("claude")) return "claude-code";
9918
+ return "cli";
9919
+ }
9920
+ async function recordSkillInstalled(params) {
9921
+ const state = await loadContextState();
9922
+ state.skills[params.name] = {
9923
+ source: params.source,
9924
+ installedAt: (/* @__PURE__ */ new Date()).toISOString(),
9925
+ timesApplied: 0,
9926
+ appliedBy: []
9927
+ };
9928
+ await saveContextState(state);
9929
+ }
9930
+ async function recordSkillUsage(params) {
9931
+ const state = await loadContextState();
9932
+ const now = (/* @__PURE__ */ new Date()).toISOString();
9933
+ for (const skillName of params.skillNames) {
9934
+ const skillRecord = state.skills[skillName];
9935
+ if (skillRecord) {
9936
+ skillRecord.timesApplied++;
9937
+ skillRecord.lastApplied = now;
9938
+ if (!skillRecord.appliedBy.includes(params.agentName)) {
9939
+ skillRecord.appliedBy.push(params.agentName);
9940
+ }
9941
+ }
9942
+ }
9943
+ const agentStatus = state.agentStatus[params.agentName];
9944
+ if (agentStatus) {
9945
+ agentStatus.skillsApplied = params.skillNames;
9946
+ }
9947
+ await saveContextState(state);
9948
+ }
9949
+ function getAgentsMdTemplate() {
9950
+ return `# Trie Agent Context
9951
+
9952
+ > **Auto-generated file** - Updated automatically when agents run.
9953
+ > Last updated: Never (initial state)
9954
+
9955
+ This file provides prioritized context for all AI coding assistants working with this codebase.
9956
+ Agents should read this file first and update it after completing scans.
9957
+
9958
+ ---
9959
+
9960
+ ## Quick Context (Read First)
9961
+
9962
+ ### Project State
9963
+ | Metric | Value | Updated |
9964
+ |--------|-------|---------|
9965
+ | Last Scan | Never | - |
9966
+ | Critical Issues | 0 | - |
9967
+ | Open Tasks | 0 | - |
9968
+ | Health Score | Unknown | - |
9969
+
9970
+ ### Active Priorities
9971
+ 1. Initial setup required - run first scan with \`trie scan\`
9972
+ 2. Configure agents in \`.trie/config.json\`
9973
+ 3. Set up CI/CD integration
9974
+
9975
+ ### Hot Files
9976
+ _Run a scan to identify hot files._
9977
+
9978
+ ---
9979
+
9980
+ ## Agent Status
9981
+
9982
+ ### Agent Status
9983
+ | Agent | Status | Last Run | Issues Found |
9984
+ |-------|--------|----------|--------------|
9985
+ | security | Ready | Never | - |
9986
+ | privacy | Ready | Never | - |
9987
+ | bugs | Ready | Never | - |
9988
+
9989
+ ### Recent Scan History
9990
+ | Date | Agents | Files | Issues | Duration |
9991
+ |------|--------|-------|--------|----------|
9992
+ | - | - | - | - | - |
9993
+
9994
+ ---
9995
+
9996
+ ## Context Analysis
9997
+
9998
+ ### Context Signals Detected
9999
+ - \`touchesAuth\`: Unknown
10000
+ - \`touchesPayments\`: Unknown
10001
+ - \`touchesUserData\`: Unknown
10002
+ - \`touchesAPI\`: Unknown
10003
+ - \`touchesDatabase\`: Unknown
10004
+ - \`touchesCrypto\`: Unknown
10005
+
10006
+ ### Risk Assessment
10007
+ - Overall Risk: Unknown
10008
+ - Confidence: 0%
10009
+
10010
+ ---
10011
+
10012
+ *This file is maintained by Trie agents. Manual edits will be preserved in non-auto sections.*
10013
+ `;
10014
+ }
10015
+ async function getContextForAI() {
10016
+ const state = await loadContextState();
10017
+ const workDir = getWorkingDirectory(void 0, true);
10018
+ const lines = [];
10019
+ if (projectInfoExists(workDir)) {
10020
+ const projectInfo = await loadProjectInfo(workDir);
10021
+ if (projectInfo) {
10022
+ lines.push(projectInfo);
10023
+ lines.push("");
10024
+ lines.push("---");
10025
+ lines.push("");
10026
+ }
10027
+ }
10028
+ lines.push(
10029
+ "## Trie Scan Context",
10030
+ "",
10031
+ `**Health Score:** ${state.healthScore}%`,
10032
+ `**Last Scan:** ${state.lastScan ? new Date(state.lastScan.timestamp).toLocaleString() : "Never"}`,
10033
+ "",
10034
+ "**Active Priorities:**",
10035
+ ...state.activePriorities.map((p) => `- ${p}`),
10036
+ ""
10037
+ );
10038
+ if (state.lastScan) {
10039
+ lines.push(
10040
+ "**Recent Issues:**",
10041
+ `- Critical: ${state.lastScan.issues.critical}`,
10042
+ `- Serious: ${state.lastScan.issues.serious}`,
10043
+ `- Moderate: ${state.lastScan.issues.moderate}`,
10044
+ `- Low: ${state.lastScan.issues.low}`,
10045
+ ""
10046
+ );
10047
+ if (state.lastScan.hotFiles.length > 0) {
10048
+ lines.push(
10049
+ "**Hot Files (most issues):**",
10050
+ ...state.lastScan.hotFiles.slice(0, 5).map((f) => `- ${f.file}: ${f.issueCount} issues`),
10051
+ ""
10052
+ );
10053
+ }
10054
+ }
10055
+ return lines.join("\n");
10056
+ }
10057
+
10058
+ // src/skills/gating.ts
10059
+ import { existsSync as existsSync7 } from "fs";
10060
+ import { readFile as readFile8 } from "fs/promises";
10061
+ import { join as join8 } from "path";
8487
10062
  import { execSync } from "child_process";
8488
10063
  async function checkSkillRequirements(frontmatter, projectDir) {
8489
10064
  const result = { allowed: true };
@@ -8540,7 +10115,7 @@ async function checkSkillRequirements(frontmatter, projectDir) {
8540
10115
  }
8541
10116
  }
8542
10117
  if (reqs.configFiles && reqs.configFiles.length > 0) {
8543
- const missing = reqs.configFiles.filter((file) => !existsSync2(join(projectDir, file)));
10118
+ const missing = reqs.configFiles.filter((file) => !existsSync7(join8(projectDir, file)));
8544
10119
  if (missing.length > 0) {
8545
10120
  result.allowed = false;
8546
10121
  result.missingConfigs = missing;
@@ -8552,11 +10127,11 @@ async function checkSkillRequirements(frontmatter, projectDir) {
8552
10127
  }
8553
10128
  async function getProjectDependencies(projectDir) {
8554
10129
  try {
8555
- const pkgPath = join(projectDir, "package.json");
8556
- if (!existsSync2(pkgPath)) {
10130
+ const pkgPath = join8(projectDir, "package.json");
10131
+ if (!existsSync7(pkgPath)) {
8557
10132
  return /* @__PURE__ */ new Set();
8558
10133
  }
8559
- const pkg = JSON.parse(await readFile(pkgPath, "utf-8"));
10134
+ const pkg = JSON.parse(await readFile8(pkgPath, "utf-8"));
8560
10135
  return /* @__PURE__ */ new Set([
8561
10136
  ...Object.keys(pkg.dependencies || {}),
8562
10137
  ...Object.keys(pkg.devDependencies || {})
@@ -8592,11 +10167,12 @@ function formatGatingReason(result) {
8592
10167
  return `Missing: ${parts.join("; ")}`;
8593
10168
  }
8594
10169
 
8595
- // src/agents/skill-review.ts
8596
- var SkillReviewAgent = class extends BaseAgent {
10170
+ // src/skills/built-in/skill-review.ts
10171
+ var SkillReviewSkill = class extends BaseSkill {
8597
10172
  name = "skill-review";
8598
10173
  description = "Applies installed skills from GitHub repositories to code review";
8599
10174
  version = "1.0.0";
10175
+ author = "Trie Agent";
8600
10176
  skills = [];
8601
10177
  loadedSkillContent = /* @__PURE__ */ new Map();
8602
10178
  filteredSkills = /* @__PURE__ */ new Map();
@@ -8799,11 +10375,13 @@ ${parsed.rawContent}`);
8799
10375
  }
8800
10376
  };
8801
10377
 
8802
- // src/agents/custom-skill.ts
8803
- var CustomSkill = class extends BaseAgent {
10378
+ // src/skills/built-in/custom-skill.ts
10379
+ var CustomSkill = class extends BaseSkill {
8804
10380
  name;
8805
10381
  description;
8806
10382
  version;
10383
+ author = void 0;
10384
+ authorUrl = void 0;
8807
10385
  config;
8808
10386
  constructor(config) {
8809
10387
  super();
@@ -8811,6 +10389,14 @@ var CustomSkill = class extends BaseAgent {
8811
10389
  this.name = config.name;
8812
10390
  this.description = config.description;
8813
10391
  this.version = config.version;
10392
+ const authorAttr = config.author;
10393
+ if (authorAttr !== void 0) {
10394
+ this.author = authorAttr;
10395
+ }
10396
+ const authorUrlAttr = config.authorUrl;
10397
+ if (authorUrlAttr !== void 0) {
10398
+ this.authorUrl = authorUrlAttr;
10399
+ }
8814
10400
  }
8815
10401
  get priority() {
8816
10402
  return {
@@ -9006,72 +10592,75 @@ var CustomSkill = class extends BaseAgent {
9006
10592
  }
9007
10593
  };
9008
10594
 
9009
- // src/agents/registry.ts
9010
- import { readdir, readFile as readFile2 } from "fs/promises";
9011
- import { join as join2 } from "path";
9012
- var AgentRegistryImpl = class {
9013
- agents = /* @__PURE__ */ new Map();
9014
- customAgentsLoaded = false;
10595
+ // src/skills/built-in/registry.ts
10596
+ import { readdir as readdir4, readFile as readFile9 } from "fs/promises";
10597
+ import { join as join9 } from "path";
10598
+ var SkillRegistryImpl = class {
10599
+ skills = /* @__PURE__ */ new Map();
10600
+ customSkillsLoaded = false;
9015
10601
  initialized = false;
9016
10602
  constructor() {
9017
- this.registerBuiltinAgents();
10603
+ this.registerBuiltinSkills();
9018
10604
  }
9019
- registerBuiltinAgents() {
10605
+ registerBuiltinSkills() {
9020
10606
  if (this.initialized) return;
9021
10607
  this.initialized = true;
9022
- const builtinAgents = [
9023
- // Core agents (always available)
9024
- new SecurityAgent(),
9025
- new PrivacyAgent(),
9026
- new TypeCheckAgent(),
9027
- new ComprehensionAgent(),
9028
- // Specialized agents
9029
- new AccessibilityAgent(),
9030
- new DesignEngineerAgent(),
9031
- new LegalAgent(),
9032
- new TestAgent(),
9033
- new SoftwareArchitectAgent(),
9034
- new DevOpsAgent(),
9035
- new BugFindingAgent(),
9036
- new UserTestingAgent(),
9037
- new TrieCleanAgent(),
9038
- new SOC2Agent(),
9039
- new SuperReviewerAgent(),
9040
- new AgentSmithAgent(),
9041
- // New agents (inspired by Turkey Build)
9042
- new PerformanceAgent(),
9043
- new E2EAgent(),
9044
- new VisualQAAgent(),
9045
- new DataFlowAgent(),
9046
- // Cost analysis agent
9047
- new MoneybagAgent(),
10608
+ const builtinSkills = [
10609
+ // Core skills (always available)
10610
+ new SecuritySkill(),
10611
+ new PrivacySkill(),
10612
+ new TypeCheckSkill(),
10613
+ new ComprehensionSkill(),
10614
+ // Specialized skills
10615
+ new AccessibilitySkill(),
10616
+ new DesignEngineerSkill(),
10617
+ new LegalSkill(),
10618
+ new TestSkill(),
10619
+ new SoftwareArchitectSkill(),
10620
+ new DevOpsSkill(),
10621
+ new BugFindingSkill(),
10622
+ new UserTestingSkill(),
10623
+ new TrieCleanSkill(),
10624
+ new SOC2Skill(),
10625
+ new SuperReviewerSkill(),
10626
+ new AgentSmithSkill(),
10627
+ // New skills (inspired by Turkey Build)
10628
+ new PerformanceSkill(),
10629
+ new E2ESkill(),
10630
+ new VisualQASkill(),
10631
+ new DataFlowSkill(),
10632
+ // Cost analysis skill
10633
+ new MoneybagSkill(),
9048
10634
  // Production readiness gate
9049
- new ProductionReadyAgent(),
9050
- // Skill review agent (applies external skills)
9051
- new SkillReviewAgent()
10635
+ new ProductionReadySkill(),
10636
+ // Skill review skill (applies external skills)
10637
+ new SkillReviewSkill()
9052
10638
  ];
9053
- console.error(`Loaded config for ${builtinAgents.length} built-in agents`);
9054
- for (const agent of builtinAgents) {
9055
- this.agents.set(agent.name, agent);
10639
+ const isWorker = typeof process !== "undefined" && (process.env.TRIE_WORKER === "true" || process.env.NODE_ENV === "test");
10640
+ if (!isWorker && !process.env.TRIE_QUIET) {
10641
+ console.error(`Loaded config for ${builtinSkills.length} built-in skills`);
10642
+ }
10643
+ for (const skill of builtinSkills) {
10644
+ this.skills.set(skill.name, skill);
9056
10645
  }
9057
10646
  }
9058
10647
  /**
9059
10648
  * Load custom skills from .trie/agents/ directory
9060
10649
  */
9061
10650
  async loadCustomSkills() {
9062
- if (this.customAgentsLoaded) return;
10651
+ if (this.customSkillsLoaded) return;
9063
10652
  try {
9064
- const skillsDir = join2(getWorkingDirectory(void 0, true), ".trie", "agents");
9065
- const files = await readdir(skillsDir);
10653
+ const skillsDir = join9(getWorkingDirectory(void 0, true), ".trie", "agents");
10654
+ const files = await readdir4(skillsDir);
9066
10655
  const jsonFiles = files.filter((f) => f.endsWith(".json"));
9067
10656
  let loadedCount = 0;
9068
10657
  for (const file of jsonFiles) {
9069
10658
  try {
9070
- const configPath = join2(skillsDir, file);
9071
- const content = await readFile2(configPath, "utf-8");
10659
+ const configPath = join9(skillsDir, file);
10660
+ const content = await readFile9(configPath, "utf-8");
9072
10661
  const config = JSON.parse(content);
9073
10662
  const skill = new CustomSkill(config);
9074
- this.agents.set(skill.name, skill);
10663
+ this.skills.set(skill.name, skill);
9075
10664
  loadedCount++;
9076
10665
  } catch (error) {
9077
10666
  console.error(`Failed to load custom skill from ${file}:`, error);
@@ -9080,22 +10669,22 @@ var AgentRegistryImpl = class {
9080
10669
  if (loadedCount > 0) {
9081
10670
  console.error(`Loaded ${loadedCount} custom skill(s) from .trie/agents/`);
9082
10671
  }
9083
- this.customAgentsLoaded = true;
10672
+ this.customSkillsLoaded = true;
9084
10673
  } catch (error) {
9085
- this.customAgentsLoaded = true;
10674
+ this.customSkillsLoaded = true;
9086
10675
  }
9087
- await this.loadSkillsForAgent();
10676
+ await this.loadSkillsForSkill();
9088
10677
  }
9089
10678
  // Backward compatibility alias
9090
10679
  async loadCustomAgents() {
9091
10680
  return this.loadCustomSkills();
9092
10681
  }
9093
10682
  /**
9094
- * Load installed skills for the SkillReviewAgent
10683
+ * Load installed skills for the SkillReviewSkill
9095
10684
  */
9096
- async loadSkillsForAgent() {
9097
- const skillReviewAgent = this.agents.get("skill-review");
9098
- if (skillReviewAgent && skillReviewAgent instanceof SkillReviewAgent) {
10685
+ async loadSkillsForSkill() {
10686
+ const skillReviewAgent = this.skills.get("skill-review");
10687
+ if (skillReviewAgent && skillReviewAgent instanceof SkillReviewSkill) {
9099
10688
  await skillReviewAgent.loadSkills();
9100
10689
  if (skillReviewAgent.hasSkills()) {
9101
10690
  console.error(`Loaded ${skillReviewAgent.getAppliedSkillNames().length} skill(s) for skill-review agent`);
@@ -9106,40 +10695,56 @@ var AgentRegistryImpl = class {
9106
10695
  * Reload custom skills (useful after creating new ones)
9107
10696
  */
9108
10697
  async reloadCustomSkills() {
9109
- for (const [name, agent] of this.agents.entries()) {
10698
+ for (const [name, agent] of this.skills.entries()) {
9110
10699
  if (agent instanceof CustomSkill) {
9111
- this.agents.delete(name);
10700
+ this.skills.delete(name);
9112
10701
  }
9113
10702
  }
9114
- this.customAgentsLoaded = false;
10703
+ this.customSkillsLoaded = false;
9115
10704
  await this.loadCustomSkills();
9116
10705
  }
9117
10706
  // Backward compatibility alias
9118
10707
  async reloadCustomAgents() {
9119
10708
  return this.reloadCustomSkills();
9120
10709
  }
10710
+ getSkill(name) {
10711
+ return this.skills.get(name);
10712
+ }
10713
+ // Backward compatibility alias
9121
10714
  getAgent(name) {
9122
- return this.agents.get(name);
10715
+ return this.getSkill(name);
9123
10716
  }
10717
+ getSkillsByNames(names) {
10718
+ return names.map((name) => this.getSkill(name)).filter((skill) => skill !== void 0);
10719
+ }
10720
+ // Backward compatibility alias
9124
10721
  getAgentsByNames(names) {
9125
- return names.map((name) => this.getAgent(name)).filter((agent) => agent !== void 0);
10722
+ return this.getSkillsByNames(names);
9126
10723
  }
10724
+ getAllSkills() {
10725
+ return Array.from(this.skills.values());
10726
+ }
10727
+ // Backward compatibility alias
9127
10728
  getAllAgents() {
9128
- return Array.from(this.agents.values());
10729
+ return this.getAllSkills();
9129
10730
  }
9130
10731
  /**
9131
- * Get only built-in agents
10732
+ * Get only built-in skills
9132
10733
  */
9133
- getBuiltinAgents() {
9134
- return Array.from(this.agents.values()).filter(
9135
- (agent) => !(agent instanceof CustomSkill)
10734
+ getBuiltinSkills() {
10735
+ return Array.from(this.skills.values()).filter(
10736
+ (skill) => !(skill instanceof CustomSkill)
9136
10737
  );
9137
10738
  }
10739
+ // Backward compatibility alias
10740
+ getBuiltinAgents() {
10741
+ return this.getBuiltinSkills();
10742
+ }
9138
10743
  /**
9139
10744
  * Get only custom skills
9140
10745
  */
9141
10746
  getCustomSkills() {
9142
- return Array.from(this.agents.values()).filter(
10747
+ return Array.from(this.skills.values()).filter(
9143
10748
  (agent) => agent instanceof CustomSkill
9144
10749
  );
9145
10750
  }
@@ -9147,32 +10752,40 @@ var AgentRegistryImpl = class {
9147
10752
  getCustomAgents() {
9148
10753
  return this.getCustomSkills();
9149
10754
  }
9150
- registerAgent(agent) {
9151
- this.agents.set(agent.name, agent);
9152
- console.error(`Registered custom skill: ${agent.name}`);
10755
+ registerSkill(skill) {
10756
+ this.skills.set(skill.name, skill);
10757
+ console.error(`Registered custom skill: ${skill.name}`);
10758
+ }
10759
+ // Backward compatibility alias
10760
+ registerAgent(skill) {
10761
+ this.registerSkill(skill);
9153
10762
  }
9154
10763
  /**
9155
- * Unregister an agent by name
10764
+ * Unregister a skill by name
9156
10765
  */
10766
+ unregisterSkill(name) {
10767
+ return this.skills.delete(name);
10768
+ }
10769
+ // Backward compatibility alias
9157
10770
  unregisterAgent(name) {
9158
- return this.agents.delete(name);
10771
+ return this.unregisterSkill(name);
9159
10772
  }
9160
- getAgentNames() {
9161
- return Array.from(this.agents.keys());
10773
+ getSkillNames() {
10774
+ return Array.from(this.skills.keys());
9162
10775
  }
9163
- getAgentDescriptions() {
9164
- return Array.from(this.agents.values()).map((agent) => ({
9165
- name: agent.name,
9166
- description: agent.description,
9167
- isCustom: agent instanceof CustomSkill
10776
+ getSkillDescriptions() {
10777
+ return Array.from(this.skills.values()).map((skill) => ({
10778
+ name: skill.name,
10779
+ description: skill.description,
10780
+ isCustom: skill instanceof CustomSkill
9168
10781
  }));
9169
10782
  }
9170
10783
  /**
9171
- * Check if an agent is a custom skill
10784
+ * Check if a skill is custom
9172
10785
  */
9173
10786
  isCustomSkill(name) {
9174
- const agent = this.agents.get(name);
9175
- return agent instanceof CustomSkill;
10787
+ const skill = this.skills.get(name);
10788
+ return skill instanceof CustomSkill;
9176
10789
  }
9177
10790
  // Backward compatibility alias
9178
10791
  isCustomAgent(name) {
@@ -9182,9 +10795,9 @@ var AgentRegistryImpl = class {
9182
10795
  * Get custom skill metadata
9183
10796
  */
9184
10797
  getCustomSkillMetadata(name) {
9185
- const agent = this.agents.get(name);
9186
- if (agent instanceof CustomSkill) {
9187
- return agent.getMetadata();
10798
+ const skill = this.skills.get(name);
10799
+ if (skill instanceof CustomSkill) {
10800
+ return skill.getMetadata();
9188
10801
  }
9189
10802
  return null;
9190
10803
  }
@@ -9193,19 +10806,49 @@ var AgentRegistryImpl = class {
9193
10806
  return this.getCustomSkillMetadata(name);
9194
10807
  }
9195
10808
  };
9196
- var SINGLETON_KEY = "__TRIE_AGENT_REGISTRY__";
9197
- function getAgentRegistry() {
10809
+ var SINGLETON_KEY = "__TRIE_SKILL_REGISTRY__";
10810
+ var LEGACY_SINGLETON_KEY = "__TRIE_AGENT_REGISTRY__";
10811
+ function getSkillRegistry() {
9198
10812
  const global = globalThis;
9199
10813
  if (!global[SINGLETON_KEY]) {
9200
- global[SINGLETON_KEY] = new AgentRegistryImpl();
10814
+ const existing = global[LEGACY_SINGLETON_KEY];
10815
+ global[SINGLETON_KEY] = existing ?? new SkillRegistryImpl();
10816
+ global[LEGACY_SINGLETON_KEY] = global[SINGLETON_KEY];
9201
10817
  }
9202
10818
  return global[SINGLETON_KEY];
9203
10819
  }
9204
10820
 
9205
10821
  export {
9206
- SuperReviewerAgent,
10822
+ SuperReviewerSkill,
9207
10823
  CRITICAL_REVIEW_CHECKLIST,
10824
+ installSkill,
10825
+ listInstalledSkills,
10826
+ removeSkill,
10827
+ projectInfoExists,
10828
+ loadProjectInfo,
10829
+ initProjectInfo,
10830
+ getProjectSection,
10831
+ updateProjectSection,
10832
+ appendToSection,
10833
+ getProjectSections,
10834
+ getProjectInfoStructured,
10835
+ getHistoricalInsights,
10836
+ searchIssues,
10837
+ findSimilarIssues,
10838
+ markIssueResolved,
10839
+ getMemoryStats,
10840
+ getRecentIssues,
10841
+ getDailyLogs,
10842
+ findCrossProjectPatterns,
10843
+ listTrackedProjects,
10844
+ getGlobalMemoryStats,
10845
+ updateGlobalMemoryMd,
10846
+ searchGlobalPatterns,
10847
+ loadContextState,
10848
+ updateContextAfterScan,
10849
+ recordSkillInstalled,
10850
+ getContextForAI,
9208
10851
  CustomSkill,
9209
- getAgentRegistry
10852
+ getSkillRegistry
9210
10853
  };
9211
- //# sourceMappingURL=chunk-VZYCZXEQ.js.map
10854
+ //# sourceMappingURL=chunk-TOE75CFZ.js.map