@triedotdev/mcp 1.0.50 → 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.
- package/README.md +545 -406
- package/dist/agent-smith-BECRZH73.js +12 -0
- package/dist/{agent-smith-runner-3AWGEOZC.js → agent-smith-runner-LZRXM2Q2.js} +7 -7
- package/dist/agent-smith-runner-LZRXM2Q2.js.map +1 -0
- package/dist/{chunk-3SQK2RKF.js → chunk-A43476GB.js} +9 -9
- package/dist/chunk-A43476GB.js.map +1 -0
- package/dist/{chunk-IMFD4SJC.js → chunk-ASGSTVVF.js} +1 -1
- package/dist/chunk-ASGSTVVF.js.map +1 -0
- package/dist/chunk-C3AS5OXW.js +1177 -0
- package/dist/chunk-C3AS5OXW.js.map +1 -0
- package/dist/chunk-IEFAQFDQ.js +2061 -0
- package/dist/chunk-IEFAQFDQ.js.map +1 -0
- package/dist/{chunk-GLC62PGD.js → chunk-KB5ZN6K2.js} +2 -2
- package/dist/{chunk-37U65YW7.js → chunk-TOE75CFZ.js} +1855 -206
- package/dist/chunk-TOE75CFZ.js.map +1 -0
- package/dist/{chunk-GERAB55E.js → chunk-YKUCIKTU.js} +94 -1259
- package/dist/chunk-YKUCIKTU.js.map +1 -0
- package/dist/cli/create-agent.js +2 -2
- package/dist/cli/main.js +406 -68
- package/dist/cli/main.js.map +1 -1
- package/dist/cli/yolo-daemon.js +5 -5
- package/dist/comprehension-46F7ZNKL.js +821 -0
- package/dist/comprehension-46F7ZNKL.js.map +1 -0
- package/dist/index.js +448 -123
- package/dist/index.js.map +1 -1
- package/dist/workers/agent-worker.js +10 -11
- package/dist/workers/agent-worker.js.map +1 -1
- package/package.json +3 -1
- package/dist/agent-smith-RVXIMAL6.js +0 -11
- package/dist/agent-smith-runner-3AWGEOZC.js.map +0 -1
- package/dist/chunk-37U65YW7.js.map +0 -1
- package/dist/chunk-3SQK2RKF.js.map +0 -1
- package/dist/chunk-6T7S77U7.js +0 -852
- package/dist/chunk-6T7S77U7.js.map +0 -1
- package/dist/chunk-GERAB55E.js.map +0 -1
- package/dist/chunk-IMFD4SJC.js.map +0 -1
- package/dist/chunk-PZDQIFKO.js +0 -1598
- package/dist/chunk-PZDQIFKO.js.map +0 -1
- /package/dist/{agent-smith-RVXIMAL6.js.map → agent-smith-BECRZH73.js.map} +0 -0
- /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
|
-
|
|
13
|
-
|
|
7
|
+
AgentSmithSkill,
|
|
8
|
+
BaseSkill,
|
|
14
9
|
isAIAvailable,
|
|
15
10
|
runAIAnalysis
|
|
16
|
-
} from "./chunk-
|
|
11
|
+
} from "./chunk-A43476GB.js";
|
|
17
12
|
import {
|
|
18
13
|
getWorkingDirectory
|
|
19
|
-
} from "./chunk-
|
|
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
|
|
20
58
|
|
|
21
|
-
|
|
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
|
+
}
|
|
231
|
+
|
|
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,7 +286,7 @@ 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
|
|
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";
|
|
@@ -298,7 +509,7 @@ Output STRICT JSON:
|
|
|
298
509
|
}
|
|
299
510
|
};
|
|
300
511
|
|
|
301
|
-
// src/
|
|
512
|
+
// src/skills/built-in/privacy.ts
|
|
302
513
|
var PRIVACY_INDICATORS = {
|
|
303
514
|
high: [
|
|
304
515
|
{ pattern: /email|phone|ssn|social.*security|passport|driver.*license/i, reason: "PII fields" },
|
|
@@ -342,7 +553,7 @@ var CRITICAL_PRIVACY_PATTERNS = [
|
|
|
342
553
|
regulation: "PCI DSS"
|
|
343
554
|
}
|
|
344
555
|
];
|
|
345
|
-
var
|
|
556
|
+
var PrivacySkill = class extends BaseSkill {
|
|
346
557
|
name = "privacy";
|
|
347
558
|
description = "AI-powered privacy analysis: GDPR, CCPA, PCI-DSS compliance";
|
|
348
559
|
version = "2.0.0";
|
|
@@ -593,7 +804,7 @@ Output STRICT JSON:
|
|
|
593
804
|
}
|
|
594
805
|
};
|
|
595
806
|
|
|
596
|
-
// src/
|
|
807
|
+
// src/skills/built-in/typecheck.ts
|
|
597
808
|
import { extname } from "path";
|
|
598
809
|
var SKIP_FILES = [
|
|
599
810
|
/node_modules\//,
|
|
@@ -604,7 +815,7 @@ var SKIP_FILES = [
|
|
|
604
815
|
/\.test\.[jt]sx?$/,
|
|
605
816
|
/\.spec\.[jt]sx?$/
|
|
606
817
|
];
|
|
607
|
-
var
|
|
818
|
+
var TypeCheckSkill = class extends BaseSkill {
|
|
608
819
|
name = "typecheck";
|
|
609
820
|
description = "Catches type errors and ensures type safety";
|
|
610
821
|
version = "1.0.0";
|
|
@@ -679,8 +890,8 @@ var TypeCheckAgent = class extends BaseAgent {
|
|
|
679
890
|
}
|
|
680
891
|
};
|
|
681
892
|
|
|
682
|
-
// src/
|
|
683
|
-
var
|
|
893
|
+
// src/skills/built-in/comprehension.ts
|
|
894
|
+
var ComprehensionSkill = class extends BaseSkill {
|
|
684
895
|
name = "comprehension";
|
|
685
896
|
description = "Explains what code does in plain language for non-technical builders";
|
|
686
897
|
version = "1.0.0";
|
|
@@ -897,7 +1108,7 @@ var ComprehensionAgent = class extends BaseAgent {
|
|
|
897
1108
|
}
|
|
898
1109
|
};
|
|
899
1110
|
|
|
900
|
-
// src/
|
|
1111
|
+
// src/skills/built-in/accessibility.ts
|
|
901
1112
|
var WCAG_CRITERIA = {
|
|
902
1113
|
// Perceivable
|
|
903
1114
|
"1.1.1": { name: "Non-text Content", level: "A", description: "All non-text content has text alternatives" },
|
|
@@ -924,6 +1135,7 @@ var WCAG_CRITERIA = {
|
|
|
924
1135
|
// Understandable
|
|
925
1136
|
"3.2.1": { name: "On Focus", level: "A", description: "Focus does not trigger unexpected context changes" },
|
|
926
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" },
|
|
927
1139
|
"3.3.1": { name: "Error Identification", level: "A", description: "Errors are identified and described in text" },
|
|
928
1140
|
"3.3.2": { name: "Labels or Instructions", level: "A", description: "Labels or instructions are provided for user input" },
|
|
929
1141
|
// Robust
|
|
@@ -960,7 +1172,7 @@ var REQUIRED_ARIA_ATTRIBUTES = {
|
|
|
960
1172
|
"treegrid": [],
|
|
961
1173
|
"treeitem": []
|
|
962
1174
|
};
|
|
963
|
-
var
|
|
1175
|
+
var AccessibilitySkill = class extends BaseSkill {
|
|
964
1176
|
name = "accessibility";
|
|
965
1177
|
description = "WCAG 2.1 AA compliance: screen readers, keyboard nav, color contrast, touch targets, semantic HTML, ARIA patterns";
|
|
966
1178
|
version = "2.0.0";
|
|
@@ -1084,7 +1296,7 @@ var AccessibilityAgent = class extends BaseAgent {
|
|
|
1084
1296
|
}
|
|
1085
1297
|
}
|
|
1086
1298
|
if (/<svg\s/i.test(line)) {
|
|
1087
|
-
const svgContext = this.getMultiLineElement(lines, i, "svg");
|
|
1299
|
+
const svgContext = this.getMultiLineElement(lines, i, "svg") ?? line;
|
|
1088
1300
|
if (!/aria-label|aria-labelledby|<title>|role=["']img["']/i.test(svgContext) && !/aria-hidden=["']true["']/i.test(svgContext)) {
|
|
1089
1301
|
issues.push(this.createIssue(
|
|
1090
1302
|
this.generateIssueId(),
|
|
@@ -1112,7 +1324,7 @@ var AccessibilityAgent = class extends BaseAgent {
|
|
|
1112
1324
|
const line = lines[i];
|
|
1113
1325
|
const lineNumber = i + 1;
|
|
1114
1326
|
if (/<button/i.test(line) || /Button\s/i.test(line)) {
|
|
1115
|
-
const buttonContext = this.getMultiLineElement(lines, i, "button")
|
|
1327
|
+
const buttonContext = this.getMultiLineElement(lines, i, "button") ?? this.getMultiLineElement(lines, i, "Button") ?? line;
|
|
1116
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);
|
|
1117
1329
|
const hasAccessibleName = /aria-label|aria-labelledby|title=|sr-only|visually-hidden/i.test(buttonContext);
|
|
1118
1330
|
if (hasIconOnly && !hasAccessibleName) {
|
|
@@ -1163,7 +1375,7 @@ var AccessibilityAgent = class extends BaseAgent {
|
|
|
1163
1375
|
}
|
|
1164
1376
|
}
|
|
1165
1377
|
if (/<a\s/i.test(line) || /<Link\s/i.test(line)) {
|
|
1166
|
-
const linkContext = this.getMultiLineElement(lines, i, "a")
|
|
1378
|
+
const linkContext = this.getMultiLineElement(lines, i, "a") ?? this.getMultiLineElement(lines, i, "Link") ?? line;
|
|
1167
1379
|
if (!/href=|to=/i.test(linkContext)) {
|
|
1168
1380
|
issues.push(this.createIssue(
|
|
1169
1381
|
this.generateIssueId(),
|
|
@@ -1937,7 +2149,7 @@ Review code for comprehensive accessibility compliance.
|
|
|
1937
2149
|
}
|
|
1938
2150
|
};
|
|
1939
2151
|
|
|
1940
|
-
// src/
|
|
2152
|
+
// src/skills/built-in/design-engineer.ts
|
|
1941
2153
|
var DOMAIN_DESIGN_RULES = {
|
|
1942
2154
|
fitness: {
|
|
1943
2155
|
defaultMode: "dark",
|
|
@@ -2155,7 +2367,7 @@ var PROJECT_CONTEXTS = {
|
|
|
2155
2367
|
effects: ["image reveals", "cursor effects", "page transitions", "scroll-linked galleries"]
|
|
2156
2368
|
}
|
|
2157
2369
|
};
|
|
2158
|
-
var
|
|
2370
|
+
var DesignEngineerSkill = class extends BaseSkill {
|
|
2159
2371
|
name = "design-engineer";
|
|
2160
2372
|
description = "Award-winning frontend craft: design systems, motion design, creative CSS, modern color palettes, Awwwards-level polish";
|
|
2161
2373
|
version = "2.0.0";
|
|
@@ -3662,8 +3874,8 @@ Output STRICT JSON:
|
|
|
3662
3874
|
}
|
|
3663
3875
|
};
|
|
3664
3876
|
|
|
3665
|
-
// src/
|
|
3666
|
-
var
|
|
3877
|
+
// src/skills/built-in/legal.ts
|
|
3878
|
+
var LegalSkill = class extends BaseSkill {
|
|
3667
3879
|
name = "legal";
|
|
3668
3880
|
description = "Comprehensive legal compliance for app development: licensing, ToS, accessibility, IP, data protection, e-commerce, and regulatory requirements";
|
|
3669
3881
|
version = "2.0.0";
|
|
@@ -4655,10 +4867,10 @@ var LegalAgent = class extends BaseAgent {
|
|
|
4655
4867
|
}
|
|
4656
4868
|
};
|
|
4657
4869
|
|
|
4658
|
-
// src/
|
|
4870
|
+
// src/skills/built-in/test.ts
|
|
4659
4871
|
import { basename, dirname } from "path";
|
|
4660
|
-
import { existsSync } from "fs";
|
|
4661
|
-
var
|
|
4872
|
+
import { existsSync as existsSync2 } from "fs";
|
|
4873
|
+
var TestSkill = class extends BaseSkill {
|
|
4662
4874
|
name = "test";
|
|
4663
4875
|
description = "Test coverage analysis, test quality, and testing best practices";
|
|
4664
4876
|
version = "1.0.0";
|
|
@@ -4700,12 +4912,9 @@ var TestAgent = class extends BaseAgent {
|
|
|
4700
4912
|
`${fileDir}/__tests__/${fileName}`,
|
|
4701
4913
|
`${fileDir}/../__tests__/${fileName}`
|
|
4702
4914
|
];
|
|
4703
|
-
const hasTestFile = testPatterns.some((pattern) =>
|
|
4915
|
+
const hasTestFile = testPatterns.some((pattern) => existsSync2(pattern));
|
|
4704
4916
|
if (!hasTestFile) {
|
|
4705
4917
|
const severity = this.determineTestSeverity(content);
|
|
4706
|
-
if (severity === "low") {
|
|
4707
|
-
return issues;
|
|
4708
|
-
}
|
|
4709
4918
|
issues.push(this.createIssue(
|
|
4710
4919
|
this.generateIssueId(),
|
|
4711
4920
|
severity,
|
|
@@ -4751,8 +4960,8 @@ var TestAgent = class extends BaseAgent {
|
|
|
4751
4960
|
}
|
|
4752
4961
|
};
|
|
4753
4962
|
|
|
4754
|
-
// src/
|
|
4755
|
-
var
|
|
4963
|
+
// src/skills/built-in/software-architect.ts
|
|
4964
|
+
var SoftwareArchitectSkill = class extends BaseSkill {
|
|
4756
4965
|
name = "software-architect";
|
|
4757
4966
|
description = "Architecture patterns, code organization, SOLID principles, and scalability";
|
|
4758
4967
|
version = "1.0.0";
|
|
@@ -4981,8 +5190,8 @@ Output STRICT JSON:
|
|
|
4981
5190
|
}
|
|
4982
5191
|
};
|
|
4983
5192
|
|
|
4984
|
-
// src/
|
|
4985
|
-
var
|
|
5193
|
+
// src/skills/built-in/devops.ts
|
|
5194
|
+
var DevOpsSkill = class extends BaseSkill {
|
|
4986
5195
|
name = "devops";
|
|
4987
5196
|
description = "Infrastructure, deployment, configuration, and operational concerns";
|
|
4988
5197
|
version = "1.0.0";
|
|
@@ -5187,7 +5396,7 @@ Output STRICT JSON:
|
|
|
5187
5396
|
}
|
|
5188
5397
|
};
|
|
5189
5398
|
|
|
5190
|
-
// src/
|
|
5399
|
+
// src/skills/built-in/bug-finding.ts
|
|
5191
5400
|
var BUG_INDICATORS = {
|
|
5192
5401
|
high: [
|
|
5193
5402
|
{ pattern: /async|await|promise/i, reason: "async code" },
|
|
@@ -5223,7 +5432,7 @@ var CRITICAL_BUG_PATTERNS = [
|
|
|
5223
5432
|
fix: "Use === for comparison instead of ="
|
|
5224
5433
|
}
|
|
5225
5434
|
];
|
|
5226
|
-
var
|
|
5435
|
+
var BugFindingSkill = class extends BaseSkill {
|
|
5227
5436
|
name = "bug-finding";
|
|
5228
5437
|
description = "AI-powered bug detection: null safety, edge cases, async issues, runtime errors";
|
|
5229
5438
|
version = "2.0.0";
|
|
@@ -5418,8 +5627,8 @@ Output STRICT JSON:
|
|
|
5418
5627
|
}
|
|
5419
5628
|
};
|
|
5420
5629
|
|
|
5421
|
-
// src/
|
|
5422
|
-
var
|
|
5630
|
+
// src/skills/built-in/user-testing.ts
|
|
5631
|
+
var UserTestingSkill = class extends BaseSkill {
|
|
5423
5632
|
name = "user-testing";
|
|
5424
5633
|
description = "Simulates user personas (happy path, security tester, confused user) to find vulnerabilities";
|
|
5425
5634
|
version = "2.0.0";
|
|
@@ -5889,8 +6098,8 @@ var UserTestingAgent = class extends BaseAgent {
|
|
|
5889
6098
|
}
|
|
5890
6099
|
};
|
|
5891
6100
|
|
|
5892
|
-
// src/
|
|
5893
|
-
var
|
|
6101
|
+
// src/skills/built-in/trie-clean.ts
|
|
6102
|
+
var TrieCleanSkill = class extends BaseSkill {
|
|
5894
6103
|
name = "trie_clean";
|
|
5895
6104
|
description = "Reviews AI-generated code for common mistakes and best practices (for non-technical users)";
|
|
5896
6105
|
version = "1.0.0";
|
|
@@ -5974,7 +6183,7 @@ var TrieCleanAgent = class extends BaseAgent {
|
|
|
5974
6183
|
}
|
|
5975
6184
|
};
|
|
5976
6185
|
|
|
5977
|
-
// src/
|
|
6186
|
+
// src/skills/built-in/soc2.ts
|
|
5978
6187
|
var SOC2_PATTERNS = {
|
|
5979
6188
|
// CC6 - Logical Access Controls
|
|
5980
6189
|
hardcodedSecrets: [
|
|
@@ -6041,7 +6250,7 @@ var REGULATION_DESCRIPTIONS = {
|
|
|
6041
6250
|
"CC7.3": "Incident Detection - Proper error handling and alerting",
|
|
6042
6251
|
"CC8.1": "Change Management - Controlled changes with proper review"
|
|
6043
6252
|
};
|
|
6044
|
-
var
|
|
6253
|
+
var SOC2Skill = class extends BaseSkill {
|
|
6045
6254
|
name = "soc2";
|
|
6046
6255
|
description = "SOC 2 Type II compliance: access controls, encryption, logging, change management";
|
|
6047
6256
|
version = "1.0.0";
|
|
@@ -6189,8 +6398,8 @@ Output STRICT JSON:
|
|
|
6189
6398
|
}
|
|
6190
6399
|
};
|
|
6191
6400
|
|
|
6192
|
-
// src/
|
|
6193
|
-
var
|
|
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";
|
|
@@ -6340,8 +6549,8 @@ var CRITICAL_REVIEW_CHECKLIST = {
|
|
|
6340
6549
|
]
|
|
6341
6550
|
};
|
|
6342
6551
|
|
|
6343
|
-
// src/
|
|
6344
|
-
var
|
|
6552
|
+
// src/skills/built-in/performance.ts
|
|
6553
|
+
var PerformanceSkill = class extends BaseSkill {
|
|
6345
6554
|
name = "performance";
|
|
6346
6555
|
description = "Surfaces performance patterns for human review: memory, renders, bundles, queries";
|
|
6347
6556
|
version = "1.0.0";
|
|
@@ -6640,8 +6849,8 @@ var PerformanceAgent = class extends BaseAgent {
|
|
|
6640
6849
|
}
|
|
6641
6850
|
};
|
|
6642
6851
|
|
|
6643
|
-
// src/
|
|
6644
|
-
var
|
|
6852
|
+
// src/skills/built-in/e2e.ts
|
|
6853
|
+
var E2ESkill = class extends BaseSkill {
|
|
6645
6854
|
name = "e2e";
|
|
6646
6855
|
description = "Identifies E2E test gaps and flaky test patterns for human review";
|
|
6647
6856
|
version = "1.0.0";
|
|
@@ -6873,8 +7082,8 @@ var E2EAgent = class extends BaseAgent {
|
|
|
6873
7082
|
}
|
|
6874
7083
|
};
|
|
6875
7084
|
|
|
6876
|
-
// src/
|
|
6877
|
-
var
|
|
7085
|
+
// src/skills/built-in/visual-qa.ts
|
|
7086
|
+
var VisualQASkill = class extends BaseSkill {
|
|
6878
7087
|
name = "visual-qa";
|
|
6879
7088
|
description = "Surfaces potential visual/layout issues in CSS for human review";
|
|
6880
7089
|
version = "1.0.0";
|
|
@@ -7209,8 +7418,8 @@ var VisualQAAgent = class extends BaseAgent {
|
|
|
7209
7418
|
}
|
|
7210
7419
|
};
|
|
7211
7420
|
|
|
7212
|
-
// src/
|
|
7213
|
-
var
|
|
7421
|
+
// src/skills/built-in/data-flow.ts
|
|
7422
|
+
var DataFlowSkill = class extends BaseSkill {
|
|
7214
7423
|
name = "data-flow";
|
|
7215
7424
|
description = "Detects schema mismatches, placeholder data, and data integrity issues";
|
|
7216
7425
|
version = "1.0.0";
|
|
@@ -7420,6 +7629,20 @@ var DataFlowAgent = class extends BaseAgent {
|
|
|
7420
7629
|
for (let i = 0; i < lines.length; i++) {
|
|
7421
7630
|
const line = lines[i] || "";
|
|
7422
7631
|
const lineNumber = i + 1;
|
|
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
|
+
));
|
|
7645
|
+
}
|
|
7423
7646
|
if (/==\s*["']['"]/.test(line) || /==\s*0[^.]/.test(line)) {
|
|
7424
7647
|
issues.push(this.createIssue(
|
|
7425
7648
|
this.generateIssueId(),
|
|
@@ -7439,7 +7662,7 @@ var DataFlowAgent = class extends BaseAgent {
|
|
|
7439
7662
|
}
|
|
7440
7663
|
};
|
|
7441
7664
|
|
|
7442
|
-
// src/
|
|
7665
|
+
// src/skills/built-in/moneybags.ts
|
|
7443
7666
|
var MONEYBAGS_ASCII = `
|
|
7444
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
|
|
7445
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
|
|
@@ -7462,51 +7685,51 @@ var MONEYBAGS_QUOTES = [
|
|
|
7462
7685
|
"Floating-point for money? That's going to be an expensive lesson."
|
|
7463
7686
|
];
|
|
7464
7687
|
var BASE_COST_BY_SEVERITY = {
|
|
7465
|
-
critical:
|
|
7466
|
-
// Critical bugs found in dev -
|
|
7467
|
-
serious:
|
|
7468
|
-
// Serious issues need careful remediation
|
|
7469
|
-
moderate:
|
|
7470
|
-
// Moderate issues are quicker fixes
|
|
7471
|
-
low:
|
|
7472
|
-
// Low severity - mostly cleanup
|
|
7688
|
+
critical: 5e3,
|
|
7689
|
+
// Critical bugs found in dev - high impact, deep fixes
|
|
7690
|
+
serious: 2e3,
|
|
7691
|
+
// Serious issues need careful remediation
|
|
7692
|
+
moderate: 500,
|
|
7693
|
+
// Moderate issues are quicker fixes
|
|
7694
|
+
low: 150
|
|
7695
|
+
// Low severity - mostly cleanup
|
|
7473
7696
|
};
|
|
7474
7697
|
var PRODUCTION_MULTIPLIER = {
|
|
7475
|
-
critical:
|
|
7476
|
-
// Critical bugs can cause outages, breaches
|
|
7477
|
-
serious:
|
|
7478
|
-
// Serious bugs cause significant user impact
|
|
7479
|
-
moderate:
|
|
7480
|
-
// Moderate bugs require hotfixes, user support
|
|
7698
|
+
critical: 12,
|
|
7699
|
+
// Critical bugs can cause outages, breaches
|
|
7700
|
+
serious: 8,
|
|
7701
|
+
// Serious bugs cause significant user impact
|
|
7702
|
+
moderate: 4,
|
|
7703
|
+
// Moderate bugs require hotfixes, user support
|
|
7481
7704
|
low: 2
|
|
7482
|
-
// Low bugs accumulate tech debt
|
|
7705
|
+
// Low bugs accumulate tech debt
|
|
7483
7706
|
};
|
|
7484
7707
|
var CATEGORY_MULTIPLIERS = {
|
|
7485
7708
|
// Security categories - important but realistic
|
|
7486
|
-
"security": { multiplier:
|
|
7487
|
-
"authentication": { multiplier:
|
|
7488
|
-
"authorization": { multiplier:
|
|
7489
|
-
"injection": { multiplier:
|
|
7490
|
-
"xss": { multiplier:
|
|
7491
|
-
"secrets": { multiplier:
|
|
7492
|
-
"cryptography": { multiplier:
|
|
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" },
|
|
7493
7716
|
// Data integrity categories
|
|
7494
|
-
"data-loss": { multiplier:
|
|
7495
|
-
"data-corruption": { multiplier:
|
|
7496
|
-
"privacy": { multiplier:
|
|
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" },
|
|
7497
7720
|
// Financial categories
|
|
7498
|
-
"payment": { multiplier:
|
|
7499
|
-
"billing": { multiplier:
|
|
7500
|
-
"financial-calculation": { multiplier:
|
|
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" },
|
|
7501
7724
|
// Reliability categories
|
|
7502
|
-
"crash": { multiplier:
|
|
7503
|
-
"memory-leak": { multiplier:
|
|
7504
|
-
"deadlock": { multiplier:
|
|
7505
|
-
"race-condition": { multiplier:
|
|
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" },
|
|
7506
7729
|
// User experience
|
|
7507
|
-
"accessibility": { multiplier: 1.
|
|
7508
|
-
"performance": { multiplier:
|
|
7509
|
-
"ux": { multiplier: 1, reason: "UX bugs increase support costs" },
|
|
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" },
|
|
7510
7733
|
// Code quality
|
|
7511
7734
|
"bug": { multiplier: 1, reason: "General bugs require developer time" },
|
|
7512
7735
|
"type-error": { multiplier: 0.8, reason: "Type errors caught early save debugging time" },
|
|
@@ -7537,13 +7760,13 @@ var USER_COUNT_MULTIPLIERS = [
|
|
|
7537
7760
|
{ threshold: 50, multiplier: 0.5, label: "MVP (50 users)" },
|
|
7538
7761
|
{ threshold: 250, multiplier: 1, label: "Early stage (250 users)" },
|
|
7539
7762
|
// Baseline (default)
|
|
7540
|
-
{ threshold: 1e3, multiplier:
|
|
7541
|
-
{ threshold: 5e3, multiplier:
|
|
7542
|
-
{ threshold: 25e3, multiplier:
|
|
7543
|
-
{ threshold: 1e5, multiplier:
|
|
7544
|
-
{ threshold: 5e5, multiplier:
|
|
7545
|
-
{ threshold: 1e6, multiplier:
|
|
7546
|
-
// Capped
|
|
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)" },
|
|
7766
|
+
{ threshold: 1e5, multiplier: 15, label: "Growth (100K 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
|
|
7547
7770
|
];
|
|
7548
7771
|
var PER_USER_COSTS = {
|
|
7549
7772
|
"data-loss": 5,
|
|
@@ -7559,7 +7782,7 @@ var PER_USER_COSTS = {
|
|
|
7559
7782
|
"accessibility": 0.1
|
|
7560
7783
|
// $0.10 per user (support costs)
|
|
7561
7784
|
};
|
|
7562
|
-
var
|
|
7785
|
+
var MoneybagSkill = class extends BaseSkill {
|
|
7563
7786
|
name = "moneybags";
|
|
7564
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.";
|
|
7565
7788
|
version = "1.1.0";
|
|
@@ -7712,8 +7935,8 @@ var MoneybagAgent = class extends BaseAgent {
|
|
|
7712
7935
|
const fixHours = EFFORT_HOURS[effort] || 8;
|
|
7713
7936
|
const developerRate = this.config.developerRate ?? DEVELOPER_HOURLY_RATE;
|
|
7714
7937
|
const fixCost = fixHours * developerRate;
|
|
7715
|
-
const BASE_NOW_CAP =
|
|
7716
|
-
const BASE_PROD_CAP =
|
|
7938
|
+
const BASE_NOW_CAP = 25e3;
|
|
7939
|
+
const BASE_PROD_CAP = 25e4;
|
|
7717
7940
|
const maxNowCost = BASE_NOW_CAP * userScaleMultiplier;
|
|
7718
7941
|
const maxProdCost = BASE_PROD_CAP * userScaleMultiplier;
|
|
7719
7942
|
const rawNowCost = baseCost * categoryMultiplier * contextMultiplier + fixCost;
|
|
@@ -8040,7 +8263,7 @@ Default: 250 users. Scale with: trie scan --users 10000
|
|
|
8040
8263
|
}
|
|
8041
8264
|
};
|
|
8042
8265
|
|
|
8043
|
-
// src/
|
|
8266
|
+
// src/skills/built-in/production-ready.ts
|
|
8044
8267
|
var PRODUCTION_READY_ASCII = `
|
|
8045
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
|
|
8046
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
|
|
@@ -8202,7 +8425,7 @@ var PRODUCTION_CONFIG_FILES = [
|
|
|
8202
8425
|
/vercel\.json$/,
|
|
8203
8426
|
/netlify\.toml$/
|
|
8204
8427
|
];
|
|
8205
|
-
var
|
|
8428
|
+
var ProductionReadySkill = class extends BaseSkill {
|
|
8206
8429
|
name = "production-ready";
|
|
8207
8430
|
description = "Production readiness checker: health endpoints, graceful shutdown, connection pooling, security headers, monitoring, and deployment gates";
|
|
8208
8431
|
version = "1.0.0";
|
|
@@ -8466,10 +8689,1376 @@ Output STRICT JSON:
|
|
|
8466
8689
|
}
|
|
8467
8690
|
};
|
|
8468
8691
|
|
|
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
|
+
|
|
8469
10058
|
// src/skills/gating.ts
|
|
8470
|
-
import { existsSync as
|
|
8471
|
-
import { readFile } from "fs/promises";
|
|
8472
|
-
import { join } from "path";
|
|
10059
|
+
import { existsSync as existsSync7 } from "fs";
|
|
10060
|
+
import { readFile as readFile8 } from "fs/promises";
|
|
10061
|
+
import { join as join8 } from "path";
|
|
8473
10062
|
import { execSync } from "child_process";
|
|
8474
10063
|
async function checkSkillRequirements(frontmatter, projectDir) {
|
|
8475
10064
|
const result = { allowed: true };
|
|
@@ -8526,7 +10115,7 @@ async function checkSkillRequirements(frontmatter, projectDir) {
|
|
|
8526
10115
|
}
|
|
8527
10116
|
}
|
|
8528
10117
|
if (reqs.configFiles && reqs.configFiles.length > 0) {
|
|
8529
|
-
const missing = reqs.configFiles.filter((file) => !
|
|
10118
|
+
const missing = reqs.configFiles.filter((file) => !existsSync7(join8(projectDir, file)));
|
|
8530
10119
|
if (missing.length > 0) {
|
|
8531
10120
|
result.allowed = false;
|
|
8532
10121
|
result.missingConfigs = missing;
|
|
@@ -8538,11 +10127,11 @@ async function checkSkillRequirements(frontmatter, projectDir) {
|
|
|
8538
10127
|
}
|
|
8539
10128
|
async function getProjectDependencies(projectDir) {
|
|
8540
10129
|
try {
|
|
8541
|
-
const pkgPath =
|
|
8542
|
-
if (!
|
|
10130
|
+
const pkgPath = join8(projectDir, "package.json");
|
|
10131
|
+
if (!existsSync7(pkgPath)) {
|
|
8543
10132
|
return /* @__PURE__ */ new Set();
|
|
8544
10133
|
}
|
|
8545
|
-
const pkg = JSON.parse(await
|
|
10134
|
+
const pkg = JSON.parse(await readFile8(pkgPath, "utf-8"));
|
|
8546
10135
|
return /* @__PURE__ */ new Set([
|
|
8547
10136
|
...Object.keys(pkg.dependencies || {}),
|
|
8548
10137
|
...Object.keys(pkg.devDependencies || {})
|
|
@@ -8578,8 +10167,8 @@ function formatGatingReason(result) {
|
|
|
8578
10167
|
return `Missing: ${parts.join("; ")}`;
|
|
8579
10168
|
}
|
|
8580
10169
|
|
|
8581
|
-
// src/
|
|
8582
|
-
var
|
|
10170
|
+
// src/skills/built-in/skill-review.ts
|
|
10171
|
+
var SkillReviewSkill = class extends BaseSkill {
|
|
8583
10172
|
name = "skill-review";
|
|
8584
10173
|
description = "Applies installed skills from GitHub repositories to code review";
|
|
8585
10174
|
version = "1.0.0";
|
|
@@ -8786,13 +10375,13 @@ ${parsed.rawContent}`);
|
|
|
8786
10375
|
}
|
|
8787
10376
|
};
|
|
8788
10377
|
|
|
8789
|
-
// src/
|
|
8790
|
-
var CustomSkill = class extends
|
|
10378
|
+
// src/skills/built-in/custom-skill.ts
|
|
10379
|
+
var CustomSkill = class extends BaseSkill {
|
|
8791
10380
|
name;
|
|
8792
10381
|
description;
|
|
8793
10382
|
version;
|
|
8794
|
-
author;
|
|
8795
|
-
authorUrl;
|
|
10383
|
+
author = void 0;
|
|
10384
|
+
authorUrl = void 0;
|
|
8796
10385
|
config;
|
|
8797
10386
|
constructor(config) {
|
|
8798
10387
|
super();
|
|
@@ -8800,8 +10389,14 @@ var CustomSkill = class extends BaseAgent {
|
|
|
8800
10389
|
this.name = config.name;
|
|
8801
10390
|
this.description = config.description;
|
|
8802
10391
|
this.version = config.version;
|
|
8803
|
-
|
|
8804
|
-
|
|
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
|
+
}
|
|
8805
10400
|
}
|
|
8806
10401
|
get priority() {
|
|
8807
10402
|
return {
|
|
@@ -8997,75 +10592,75 @@ var CustomSkill = class extends BaseAgent {
|
|
|
8997
10592
|
}
|
|
8998
10593
|
};
|
|
8999
10594
|
|
|
9000
|
-
// src/
|
|
9001
|
-
import { readdir, readFile as
|
|
9002
|
-
import { join as
|
|
9003
|
-
var
|
|
9004
|
-
|
|
9005
|
-
|
|
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;
|
|
9006
10601
|
initialized = false;
|
|
9007
10602
|
constructor() {
|
|
9008
|
-
this.
|
|
10603
|
+
this.registerBuiltinSkills();
|
|
9009
10604
|
}
|
|
9010
|
-
|
|
10605
|
+
registerBuiltinSkills() {
|
|
9011
10606
|
if (this.initialized) return;
|
|
9012
10607
|
this.initialized = true;
|
|
9013
|
-
const
|
|
9014
|
-
// Core
|
|
9015
|
-
new
|
|
9016
|
-
new
|
|
9017
|
-
new
|
|
9018
|
-
new
|
|
9019
|
-
// Specialized
|
|
9020
|
-
new
|
|
9021
|
-
new
|
|
9022
|
-
new
|
|
9023
|
-
new
|
|
9024
|
-
new
|
|
9025
|
-
new
|
|
9026
|
-
new
|
|
9027
|
-
new
|
|
9028
|
-
new
|
|
9029
|
-
new
|
|
9030
|
-
new
|
|
9031
|
-
new
|
|
9032
|
-
// New
|
|
9033
|
-
new
|
|
9034
|
-
new
|
|
9035
|
-
new
|
|
9036
|
-
new
|
|
9037
|
-
// Cost analysis
|
|
9038
|
-
new
|
|
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(),
|
|
9039
10634
|
// Production readiness gate
|
|
9040
|
-
new
|
|
9041
|
-
// Skill review
|
|
9042
|
-
new
|
|
10635
|
+
new ProductionReadySkill(),
|
|
10636
|
+
// Skill review skill (applies external skills)
|
|
10637
|
+
new SkillReviewSkill()
|
|
9043
10638
|
];
|
|
9044
10639
|
const isWorker = typeof process !== "undefined" && (process.env.TRIE_WORKER === "true" || process.env.NODE_ENV === "test");
|
|
9045
10640
|
if (!isWorker && !process.env.TRIE_QUIET) {
|
|
9046
|
-
console.error(`Loaded config for ${
|
|
10641
|
+
console.error(`Loaded config for ${builtinSkills.length} built-in skills`);
|
|
9047
10642
|
}
|
|
9048
|
-
for (const
|
|
9049
|
-
this.
|
|
10643
|
+
for (const skill of builtinSkills) {
|
|
10644
|
+
this.skills.set(skill.name, skill);
|
|
9050
10645
|
}
|
|
9051
10646
|
}
|
|
9052
10647
|
/**
|
|
9053
10648
|
* Load custom skills from .trie/agents/ directory
|
|
9054
10649
|
*/
|
|
9055
10650
|
async loadCustomSkills() {
|
|
9056
|
-
if (this.
|
|
10651
|
+
if (this.customSkillsLoaded) return;
|
|
9057
10652
|
try {
|
|
9058
|
-
const skillsDir =
|
|
9059
|
-
const files = await
|
|
10653
|
+
const skillsDir = join9(getWorkingDirectory(void 0, true), ".trie", "agents");
|
|
10654
|
+
const files = await readdir4(skillsDir);
|
|
9060
10655
|
const jsonFiles = files.filter((f) => f.endsWith(".json"));
|
|
9061
10656
|
let loadedCount = 0;
|
|
9062
10657
|
for (const file of jsonFiles) {
|
|
9063
10658
|
try {
|
|
9064
|
-
const configPath =
|
|
9065
|
-
const content = await
|
|
10659
|
+
const configPath = join9(skillsDir, file);
|
|
10660
|
+
const content = await readFile9(configPath, "utf-8");
|
|
9066
10661
|
const config = JSON.parse(content);
|
|
9067
10662
|
const skill = new CustomSkill(config);
|
|
9068
|
-
this.
|
|
10663
|
+
this.skills.set(skill.name, skill);
|
|
9069
10664
|
loadedCount++;
|
|
9070
10665
|
} catch (error) {
|
|
9071
10666
|
console.error(`Failed to load custom skill from ${file}:`, error);
|
|
@@ -9074,22 +10669,22 @@ var AgentRegistryImpl = class {
|
|
|
9074
10669
|
if (loadedCount > 0) {
|
|
9075
10670
|
console.error(`Loaded ${loadedCount} custom skill(s) from .trie/agents/`);
|
|
9076
10671
|
}
|
|
9077
|
-
this.
|
|
10672
|
+
this.customSkillsLoaded = true;
|
|
9078
10673
|
} catch (error) {
|
|
9079
|
-
this.
|
|
10674
|
+
this.customSkillsLoaded = true;
|
|
9080
10675
|
}
|
|
9081
|
-
await this.
|
|
10676
|
+
await this.loadSkillsForSkill();
|
|
9082
10677
|
}
|
|
9083
10678
|
// Backward compatibility alias
|
|
9084
10679
|
async loadCustomAgents() {
|
|
9085
10680
|
return this.loadCustomSkills();
|
|
9086
10681
|
}
|
|
9087
10682
|
/**
|
|
9088
|
-
* Load installed skills for the
|
|
10683
|
+
* Load installed skills for the SkillReviewSkill
|
|
9089
10684
|
*/
|
|
9090
|
-
async
|
|
9091
|
-
const skillReviewAgent = this.
|
|
9092
|
-
if (skillReviewAgent && skillReviewAgent instanceof
|
|
10685
|
+
async loadSkillsForSkill() {
|
|
10686
|
+
const skillReviewAgent = this.skills.get("skill-review");
|
|
10687
|
+
if (skillReviewAgent && skillReviewAgent instanceof SkillReviewSkill) {
|
|
9093
10688
|
await skillReviewAgent.loadSkills();
|
|
9094
10689
|
if (skillReviewAgent.hasSkills()) {
|
|
9095
10690
|
console.error(`Loaded ${skillReviewAgent.getAppliedSkillNames().length} skill(s) for skill-review agent`);
|
|
@@ -9100,40 +10695,56 @@ var AgentRegistryImpl = class {
|
|
|
9100
10695
|
* Reload custom skills (useful after creating new ones)
|
|
9101
10696
|
*/
|
|
9102
10697
|
async reloadCustomSkills() {
|
|
9103
|
-
for (const [name, agent] of this.
|
|
10698
|
+
for (const [name, agent] of this.skills.entries()) {
|
|
9104
10699
|
if (agent instanceof CustomSkill) {
|
|
9105
|
-
this.
|
|
10700
|
+
this.skills.delete(name);
|
|
9106
10701
|
}
|
|
9107
10702
|
}
|
|
9108
|
-
this.
|
|
10703
|
+
this.customSkillsLoaded = false;
|
|
9109
10704
|
await this.loadCustomSkills();
|
|
9110
10705
|
}
|
|
9111
10706
|
// Backward compatibility alias
|
|
9112
10707
|
async reloadCustomAgents() {
|
|
9113
10708
|
return this.reloadCustomSkills();
|
|
9114
10709
|
}
|
|
10710
|
+
getSkill(name) {
|
|
10711
|
+
return this.skills.get(name);
|
|
10712
|
+
}
|
|
10713
|
+
// Backward compatibility alias
|
|
9115
10714
|
getAgent(name) {
|
|
9116
|
-
return this.
|
|
10715
|
+
return this.getSkill(name);
|
|
10716
|
+
}
|
|
10717
|
+
getSkillsByNames(names) {
|
|
10718
|
+
return names.map((name) => this.getSkill(name)).filter((skill) => skill !== void 0);
|
|
9117
10719
|
}
|
|
10720
|
+
// Backward compatibility alias
|
|
9118
10721
|
getAgentsByNames(names) {
|
|
9119
|
-
return
|
|
10722
|
+
return this.getSkillsByNames(names);
|
|
9120
10723
|
}
|
|
10724
|
+
getAllSkills() {
|
|
10725
|
+
return Array.from(this.skills.values());
|
|
10726
|
+
}
|
|
10727
|
+
// Backward compatibility alias
|
|
9121
10728
|
getAllAgents() {
|
|
9122
|
-
return
|
|
10729
|
+
return this.getAllSkills();
|
|
9123
10730
|
}
|
|
9124
10731
|
/**
|
|
9125
|
-
* Get only built-in
|
|
10732
|
+
* Get only built-in skills
|
|
9126
10733
|
*/
|
|
9127
|
-
|
|
9128
|
-
return Array.from(this.
|
|
9129
|
-
(
|
|
10734
|
+
getBuiltinSkills() {
|
|
10735
|
+
return Array.from(this.skills.values()).filter(
|
|
10736
|
+
(skill) => !(skill instanceof CustomSkill)
|
|
9130
10737
|
);
|
|
9131
10738
|
}
|
|
10739
|
+
// Backward compatibility alias
|
|
10740
|
+
getBuiltinAgents() {
|
|
10741
|
+
return this.getBuiltinSkills();
|
|
10742
|
+
}
|
|
9132
10743
|
/**
|
|
9133
10744
|
* Get only custom skills
|
|
9134
10745
|
*/
|
|
9135
10746
|
getCustomSkills() {
|
|
9136
|
-
return Array.from(this.
|
|
10747
|
+
return Array.from(this.skills.values()).filter(
|
|
9137
10748
|
(agent) => agent instanceof CustomSkill
|
|
9138
10749
|
);
|
|
9139
10750
|
}
|
|
@@ -9141,32 +10752,40 @@ var AgentRegistryImpl = class {
|
|
|
9141
10752
|
getCustomAgents() {
|
|
9142
10753
|
return this.getCustomSkills();
|
|
9143
10754
|
}
|
|
9144
|
-
|
|
9145
|
-
this.
|
|
9146
|
-
console.error(`Registered custom skill: ${
|
|
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);
|
|
9147
10762
|
}
|
|
9148
10763
|
/**
|
|
9149
|
-
* Unregister
|
|
10764
|
+
* Unregister a skill by name
|
|
9150
10765
|
*/
|
|
10766
|
+
unregisterSkill(name) {
|
|
10767
|
+
return this.skills.delete(name);
|
|
10768
|
+
}
|
|
10769
|
+
// Backward compatibility alias
|
|
9151
10770
|
unregisterAgent(name) {
|
|
9152
|
-
return this.
|
|
10771
|
+
return this.unregisterSkill(name);
|
|
9153
10772
|
}
|
|
9154
|
-
|
|
9155
|
-
return Array.from(this.
|
|
10773
|
+
getSkillNames() {
|
|
10774
|
+
return Array.from(this.skills.keys());
|
|
9156
10775
|
}
|
|
9157
|
-
|
|
9158
|
-
return Array.from(this.
|
|
9159
|
-
name:
|
|
9160
|
-
description:
|
|
9161
|
-
isCustom:
|
|
10776
|
+
getSkillDescriptions() {
|
|
10777
|
+
return Array.from(this.skills.values()).map((skill) => ({
|
|
10778
|
+
name: skill.name,
|
|
10779
|
+
description: skill.description,
|
|
10780
|
+
isCustom: skill instanceof CustomSkill
|
|
9162
10781
|
}));
|
|
9163
10782
|
}
|
|
9164
10783
|
/**
|
|
9165
|
-
* Check if
|
|
10784
|
+
* Check if a skill is custom
|
|
9166
10785
|
*/
|
|
9167
10786
|
isCustomSkill(name) {
|
|
9168
|
-
const
|
|
9169
|
-
return
|
|
10787
|
+
const skill = this.skills.get(name);
|
|
10788
|
+
return skill instanceof CustomSkill;
|
|
9170
10789
|
}
|
|
9171
10790
|
// Backward compatibility alias
|
|
9172
10791
|
isCustomAgent(name) {
|
|
@@ -9176,9 +10795,9 @@ var AgentRegistryImpl = class {
|
|
|
9176
10795
|
* Get custom skill metadata
|
|
9177
10796
|
*/
|
|
9178
10797
|
getCustomSkillMetadata(name) {
|
|
9179
|
-
const
|
|
9180
|
-
if (
|
|
9181
|
-
return
|
|
10798
|
+
const skill = this.skills.get(name);
|
|
10799
|
+
if (skill instanceof CustomSkill) {
|
|
10800
|
+
return skill.getMetadata();
|
|
9182
10801
|
}
|
|
9183
10802
|
return null;
|
|
9184
10803
|
}
|
|
@@ -9187,19 +10806,49 @@ var AgentRegistryImpl = class {
|
|
|
9187
10806
|
return this.getCustomSkillMetadata(name);
|
|
9188
10807
|
}
|
|
9189
10808
|
};
|
|
9190
|
-
var SINGLETON_KEY = "
|
|
9191
|
-
|
|
10809
|
+
var SINGLETON_KEY = "__TRIE_SKILL_REGISTRY__";
|
|
10810
|
+
var LEGACY_SINGLETON_KEY = "__TRIE_AGENT_REGISTRY__";
|
|
10811
|
+
function getSkillRegistry() {
|
|
9192
10812
|
const global = globalThis;
|
|
9193
10813
|
if (!global[SINGLETON_KEY]) {
|
|
9194
|
-
global[
|
|
10814
|
+
const existing = global[LEGACY_SINGLETON_KEY];
|
|
10815
|
+
global[SINGLETON_KEY] = existing ?? new SkillRegistryImpl();
|
|
10816
|
+
global[LEGACY_SINGLETON_KEY] = global[SINGLETON_KEY];
|
|
9195
10817
|
}
|
|
9196
10818
|
return global[SINGLETON_KEY];
|
|
9197
10819
|
}
|
|
9198
10820
|
|
|
9199
10821
|
export {
|
|
9200
|
-
|
|
10822
|
+
SuperReviewerSkill,
|
|
9201
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,
|
|
9202
10851
|
CustomSkill,
|
|
9203
|
-
|
|
10852
|
+
getSkillRegistry
|
|
9204
10853
|
};
|
|
9205
|
-
//# sourceMappingURL=chunk-
|
|
10854
|
+
//# sourceMappingURL=chunk-TOE75CFZ.js.map
|