@triedotdev/mcp 1.0.93 → 1.0.97
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 +145 -137
- package/dist/chunk-APMV77PU.js +313 -0
- package/dist/chunk-APMV77PU.js.map +1 -0
- package/dist/{chunk-MZI46HQT.js → chunk-B3MNN3XB.js} +13 -18
- package/dist/{chunk-MZI46HQT.js.map → chunk-B3MNN3XB.js.map} +1 -1
- package/dist/{chunk-5Z7O66DE.js → chunk-F4NJ4CBP.js} +2 -2
- package/dist/{chunk-YTJXD664.js → chunk-FNCCZ3XB.js} +1222 -75
- package/dist/chunk-FNCCZ3XB.js.map +1 -0
- package/dist/chunk-G76DYVGX.js +136 -0
- package/dist/chunk-G76DYVGX.js.map +1 -0
- package/dist/chunk-HSNE46VE.js +956 -0
- package/dist/chunk-HSNE46VE.js.map +1 -0
- package/dist/{chunk-LVVG2DMW.js → chunk-IXO4G4D3.js} +2 -2
- package/dist/{chunk-LP4MVJDW.js → chunk-JDHR5BDR.js} +2 -3
- package/dist/chunk-NIASHOAB.js +1304 -0
- package/dist/chunk-NIASHOAB.js.map +1 -0
- package/dist/{chunk-NMGINYYX.js → chunk-OVRG5RP3.js} +6 -7
- package/dist/chunk-OVRG5RP3.js.map +1 -0
- package/dist/{chunk-T5UOH56R.js → chunk-R3I2GCZC.js} +3 -3
- package/dist/{chunk-RDOJCRKJ.js → chunk-R4AAPFXC.js} +2 -2
- package/dist/{chunk-R6AUYN3R.js → chunk-SLL2MDJD.js} +786 -4668
- package/dist/chunk-SLL2MDJD.js.map +1 -0
- package/dist/cli/create-agent.js +931 -7
- package/dist/cli/create-agent.js.map +1 -1
- package/dist/cli/main.js +151 -383
- package/dist/cli/main.js.map +1 -1
- package/dist/cli/yolo-daemon.js +13 -20
- package/dist/cli/yolo-daemon.js.map +1 -1
- package/dist/{goal-manager-ESJCJXFS.js → goal-manager-LAOT4QQX.js} +6 -6
- package/dist/guardian-agent-M352CBE5.js +19 -0
- package/dist/index.js +1025 -1550
- package/dist/index.js.map +1 -1
- package/dist/{issue-store-JZ2LCQEG.js → issue-store-W2X33X2X.js} +4 -4
- package/dist/{progress-PH6NNWZM.js → progress-PQVEM7BR.js} +2 -2
- package/dist/{vibe-code-signatures-K4UIWKJZ.js → vibe-code-signatures-ELEWJFGZ.js} +3 -3
- package/dist/{vulnerability-signatures-ZKVLMBRG.js → vulnerability-signatures-EIJQX2TS.js} +3 -3
- package/dist/workers/agent-worker.js +2 -11
- package/dist/workers/agent-worker.js.map +1 -1
- package/package.json +2 -2
- package/dist/agent-smith-QYDXPFPJ.js +0 -14
- package/dist/agent-smith-runner-GXGDJTSR.js +0 -573
- package/dist/agent-smith-runner-GXGDJTSR.js.map +0 -1
- package/dist/cache-manager-7SKX3IGO.js +0 -10
- package/dist/chunk-74NPKTZV.js +0 -141
- package/dist/chunk-74NPKTZV.js.map +0 -1
- package/dist/chunk-BG2BHWCC.js +0 -10879
- package/dist/chunk-BG2BHWCC.js.map +0 -1
- package/dist/chunk-CUXXRM3T.js +0 -2124
- package/dist/chunk-CUXXRM3T.js.map +0 -1
- package/dist/chunk-D25EIBPO.js +0 -183
- package/dist/chunk-D25EIBPO.js.map +0 -1
- package/dist/chunk-F55XBLIA.js +0 -536
- package/dist/chunk-F55XBLIA.js.map +0 -1
- package/dist/chunk-HFQ5ORON.js +0 -279
- package/dist/chunk-HFQ5ORON.js.map +0 -1
- package/dist/chunk-IOUOVBJZ.js +0 -175
- package/dist/chunk-IOUOVBJZ.js.map +0 -1
- package/dist/chunk-KWDNYWOR.js +0 -2270
- package/dist/chunk-KWDNYWOR.js.map +0 -1
- package/dist/chunk-LT7MKIXU.js +0 -266
- package/dist/chunk-LT7MKIXU.js.map +0 -1
- package/dist/chunk-MURGTWG4.js +0 -279
- package/dist/chunk-MURGTWG4.js.map +0 -1
- package/dist/chunk-NMGINYYX.js.map +0 -1
- package/dist/chunk-R6AUYN3R.js.map +0 -1
- package/dist/chunk-SJFJ6GLR.js +0 -955
- package/dist/chunk-SJFJ6GLR.js.map +0 -1
- package/dist/chunk-YTJXD664.js.map +0 -1
- package/dist/git-PZV3BBYI.js +0 -29
- package/dist/guardian-agent-ZHJXLBOU.js +0 -21
- package/dist/progress-PH6NNWZM.js.map +0 -1
- package/dist/vibe-code-signatures-K4UIWKJZ.js.map +0 -1
- package/dist/vulnerability-signatures-ZKVLMBRG.js.map +0 -1
- /package/dist/{chunk-5Z7O66DE.js.map → chunk-F4NJ4CBP.js.map} +0 -0
- /package/dist/{chunk-LVVG2DMW.js.map → chunk-IXO4G4D3.js.map} +0 -0
- /package/dist/{chunk-LP4MVJDW.js.map → chunk-JDHR5BDR.js.map} +0 -0
- /package/dist/{chunk-T5UOH56R.js.map → chunk-R3I2GCZC.js.map} +0 -0
- /package/dist/{chunk-RDOJCRKJ.js.map → chunk-R4AAPFXC.js.map} +0 -0
- /package/dist/{agent-smith-QYDXPFPJ.js.map → goal-manager-LAOT4QQX.js.map} +0 -0
- /package/dist/{cache-manager-7SKX3IGO.js.map → guardian-agent-M352CBE5.js.map} +0 -0
- /package/dist/{git-PZV3BBYI.js.map → issue-store-W2X33X2X.js.map} +0 -0
- /package/dist/{goal-manager-ESJCJXFS.js.map → progress-PQVEM7BR.js.map} +0 -0
- /package/dist/{guardian-agent-ZHJXLBOU.js.map → vibe-code-signatures-ELEWJFGZ.js.map} +0 -0
- /package/dist/{issue-store-JZ2LCQEG.js.map → vulnerability-signatures-EIJQX2TS.js.map} +0 -0
package/dist/chunk-CUXXRM3T.js
DELETED
|
@@ -1,2124 +0,0 @@
|
|
|
1
|
-
import {
|
|
2
|
-
CacheManager
|
|
3
|
-
} from "./chunk-HFQ5ORON.js";
|
|
4
|
-
import {
|
|
5
|
-
CustomSkill,
|
|
6
|
-
getSkillRegistry,
|
|
7
|
-
loadContextState
|
|
8
|
-
} from "./chunk-BG2BHWCC.js";
|
|
9
|
-
import {
|
|
10
|
-
getGlobalMemoryStats
|
|
11
|
-
} from "./chunk-LT7MKIXU.js";
|
|
12
|
-
import {
|
|
13
|
-
getHistoricalInsights,
|
|
14
|
-
getMemoryStats,
|
|
15
|
-
getRecentIssues,
|
|
16
|
-
searchIssues
|
|
17
|
-
} from "./chunk-LP4MVJDW.js";
|
|
18
|
-
import {
|
|
19
|
-
getTrieDirectory,
|
|
20
|
-
getWorkingDirectory
|
|
21
|
-
} from "./chunk-RDOJCRKJ.js";
|
|
22
|
-
import {
|
|
23
|
-
isInteractiveMode
|
|
24
|
-
} from "./chunk-D25EIBPO.js";
|
|
25
|
-
import {
|
|
26
|
-
__require
|
|
27
|
-
} from "./chunk-DGUM43GV.js";
|
|
28
|
-
|
|
29
|
-
// src/utils/trie-init.ts
|
|
30
|
-
import { existsSync } from "fs";
|
|
31
|
-
import { join } from "path";
|
|
32
|
-
var INIT_MARKERS = [
|
|
33
|
-
"PROJECT.md",
|
|
34
|
-
"RULES.md",
|
|
35
|
-
"TEAM.md",
|
|
36
|
-
"BOOTSTRAP.md",
|
|
37
|
-
"AGENTS.md",
|
|
38
|
-
"config.json"
|
|
39
|
-
];
|
|
40
|
-
function isTrieInitialized(workDir) {
|
|
41
|
-
const dir = workDir || getWorkingDirectory(void 0, true);
|
|
42
|
-
const trieDir = getTrieDirectory(dir);
|
|
43
|
-
return INIT_MARKERS.some((marker) => existsSync(join(trieDir, marker)));
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
// src/config/loader.ts
|
|
47
|
-
import { readFile, writeFile, mkdir } from "fs/promises";
|
|
48
|
-
import { existsSync as existsSync3 } from "fs";
|
|
49
|
-
import { join as join3, dirname } from "path";
|
|
50
|
-
|
|
51
|
-
// src/config/validation.ts
|
|
52
|
-
import { z } from "zod";
|
|
53
|
-
import { existsSync as existsSync2, readFileSync } from "fs";
|
|
54
|
-
import { resolve, join as join2 } from "path";
|
|
55
|
-
var API_KEY_PATTERNS = {
|
|
56
|
-
anthropic: /^sk-ant-api\d{2}-[\w-]{95}$/,
|
|
57
|
-
openai: /^sk-[\w]{48}$/,
|
|
58
|
-
github: /^ghp_[\w]{36}$/,
|
|
59
|
-
vercel: /^[\w]{24}$/,
|
|
60
|
-
linear: /^lin_api_[\w]{40,60}$/
|
|
61
|
-
};
|
|
62
|
-
var ApiKeysSchema = z.object({
|
|
63
|
-
anthropic: z.string().regex(API_KEY_PATTERNS.anthropic, "Invalid Anthropic API key format").optional(),
|
|
64
|
-
openai: z.string().regex(API_KEY_PATTERNS.openai, "Invalid OpenAI API key format").optional(),
|
|
65
|
-
github: z.string().regex(API_KEY_PATTERNS.github, "Invalid GitHub token format").optional(),
|
|
66
|
-
vercel: z.string().regex(API_KEY_PATTERNS.vercel, "Invalid Vercel token format").optional(),
|
|
67
|
-
linear: z.string().optional()
|
|
68
|
-
// Linear keys can vary, so we'll be flexible but allow storage
|
|
69
|
-
});
|
|
70
|
-
var AgentConfigSchema = z.object({
|
|
71
|
-
enabled: z.array(z.string()).optional().default([]),
|
|
72
|
-
disabled: z.array(z.string()).optional().default([]),
|
|
73
|
-
parallel: z.boolean().optional().default(true),
|
|
74
|
-
maxConcurrency: z.number().int().min(1).max(20).optional().default(4),
|
|
75
|
-
timeout: z.number().int().min(1e3).max(3e5).optional().default(12e4),
|
|
76
|
-
// 2 minutes
|
|
77
|
-
cache: z.boolean().optional().default(true)
|
|
78
|
-
});
|
|
79
|
-
var ComplianceSchema = z.object({
|
|
80
|
-
standards: z.array(z.enum(["SOC2", "GDPR", "HIPAA", "CCPA", "PCI-DSS"])).optional().default(["SOC2"]),
|
|
81
|
-
enforceCompliance: z.boolean().optional().default(false),
|
|
82
|
-
reportFormat: z.enum(["json", "sarif", "csv", "html"]).optional().default("json")
|
|
83
|
-
});
|
|
84
|
-
var OutputSchema = z.object({
|
|
85
|
-
format: z.enum(["console", "json", "sarif", "junit"]).optional().default("console"),
|
|
86
|
-
level: z.enum(["critical", "serious", "moderate", "low", "all"]).optional().default("all"),
|
|
87
|
-
interactive: z.boolean().optional().default(false),
|
|
88
|
-
streaming: z.boolean().optional().default(true),
|
|
89
|
-
colors: z.boolean().optional().default(true)
|
|
90
|
-
});
|
|
91
|
-
var PathsSchema = z.object({
|
|
92
|
-
include: z.array(z.string()).optional().default([]),
|
|
93
|
-
exclude: z.array(z.string()).optional().default(["node_modules", "dist", "build", ".git"]),
|
|
94
|
-
configDir: z.string().optional().default(".trie"),
|
|
95
|
-
outputDir: z.string().optional().default("trie-reports")
|
|
96
|
-
});
|
|
97
|
-
var IntegrationsSchema = z.object({
|
|
98
|
-
github: z.object({
|
|
99
|
-
enabled: z.boolean().optional().default(false),
|
|
100
|
-
token: z.string().optional(),
|
|
101
|
-
webhook: z.string().url().optional()
|
|
102
|
-
}).optional(),
|
|
103
|
-
slack: z.object({
|
|
104
|
-
enabled: z.boolean().optional().default(false),
|
|
105
|
-
webhook: z.string().url().optional(),
|
|
106
|
-
channel: z.string().optional()
|
|
107
|
-
}).optional(),
|
|
108
|
-
jira: z.object({
|
|
109
|
-
enabled: z.boolean().optional().default(false),
|
|
110
|
-
url: z.string().url().optional(),
|
|
111
|
-
token: z.string().optional(),
|
|
112
|
-
project: z.string().optional()
|
|
113
|
-
}).optional()
|
|
114
|
-
});
|
|
115
|
-
var UserSchema = z.object({
|
|
116
|
-
name: z.string().min(1).optional(),
|
|
117
|
-
email: z.string().email().optional(),
|
|
118
|
-
role: z.enum([
|
|
119
|
-
"developer",
|
|
120
|
-
"designer",
|
|
121
|
-
"qa",
|
|
122
|
-
"devops",
|
|
123
|
-
"security",
|
|
124
|
-
"architect",
|
|
125
|
-
"manager",
|
|
126
|
-
"contributor"
|
|
127
|
-
]).optional().default("developer"),
|
|
128
|
-
github: z.string().optional(),
|
|
129
|
-
// GitHub username
|
|
130
|
-
url: z.string().url().optional()
|
|
131
|
-
// Personal/portfolio URL
|
|
132
|
-
});
|
|
133
|
-
var TrieConfigSchema = z.object({
|
|
134
|
-
version: z.string().optional().default("1.0.0"),
|
|
135
|
-
apiKeys: ApiKeysSchema.optional(),
|
|
136
|
-
agents: AgentConfigSchema.optional(),
|
|
137
|
-
compliance: ComplianceSchema.optional(),
|
|
138
|
-
output: OutputSchema.optional(),
|
|
139
|
-
paths: PathsSchema.optional(),
|
|
140
|
-
integrations: IntegrationsSchema.optional(),
|
|
141
|
-
user: UserSchema.optional()
|
|
142
|
-
// User identity for attribution
|
|
143
|
-
});
|
|
144
|
-
var ConfigValidator = class {
|
|
145
|
-
/**
|
|
146
|
-
* Validate configuration object
|
|
147
|
-
*/
|
|
148
|
-
validateConfig(config) {
|
|
149
|
-
try {
|
|
150
|
-
const validated = TrieConfigSchema.parse(config);
|
|
151
|
-
const businessErrors = this.validateBusinessLogic(validated);
|
|
152
|
-
if (businessErrors.length > 0) {
|
|
153
|
-
return { success: false, errors: businessErrors };
|
|
154
|
-
}
|
|
155
|
-
return { success: true, data: validated };
|
|
156
|
-
} catch (error) {
|
|
157
|
-
if (error instanceof z.ZodError) {
|
|
158
|
-
const errors = error.errors.map(
|
|
159
|
-
(err) => `${err.path.join(".")}: ${err.message}`
|
|
160
|
-
);
|
|
161
|
-
return { success: false, errors };
|
|
162
|
-
}
|
|
163
|
-
return {
|
|
164
|
-
success: false,
|
|
165
|
-
errors: [`Configuration validation failed: ${error instanceof Error ? error.message : "Unknown error"}`]
|
|
166
|
-
};
|
|
167
|
-
}
|
|
168
|
-
}
|
|
169
|
-
/**
|
|
170
|
-
* Validate environment variables for API keys
|
|
171
|
-
*/
|
|
172
|
-
validateEnvironment() {
|
|
173
|
-
const warnings = [];
|
|
174
|
-
const errors = [];
|
|
175
|
-
const exposedPatterns = [
|
|
176
|
-
"NEXT_PUBLIC_ANTHROPIC",
|
|
177
|
-
"REACT_APP_ANTHROPIC",
|
|
178
|
-
"VITE_ANTHROPIC",
|
|
179
|
-
"PUBLIC_ANTHROPIC"
|
|
180
|
-
];
|
|
181
|
-
for (const pattern of exposedPatterns) {
|
|
182
|
-
const envVars = Object.keys(process.env).filter((key) => key.includes(pattern));
|
|
183
|
-
for (const envVar of envVars) {
|
|
184
|
-
errors.push(`[!] Security risk: API key in client-side environment variable: ${envVar}`);
|
|
185
|
-
}
|
|
186
|
-
}
|
|
187
|
-
let anthropicKey = process.env.ANTHROPIC_API_KEY;
|
|
188
|
-
if (!anthropicKey) {
|
|
189
|
-
try {
|
|
190
|
-
const configPath = join2(getTrieDirectory(getWorkingDirectory(void 0, true)), "config.json");
|
|
191
|
-
if (existsSync2(configPath)) {
|
|
192
|
-
const config = JSON.parse(readFileSync(configPath, "utf-8"));
|
|
193
|
-
anthropicKey = config.apiKeys?.anthropic;
|
|
194
|
-
}
|
|
195
|
-
} catch {
|
|
196
|
-
}
|
|
197
|
-
}
|
|
198
|
-
if (anthropicKey && !API_KEY_PATTERNS.anthropic.test(anthropicKey)) {
|
|
199
|
-
errors.push("ANTHROPIC_API_KEY does not match expected format");
|
|
200
|
-
}
|
|
201
|
-
if (!anthropicKey) {
|
|
202
|
-
warnings.push("ANTHROPIC_API_KEY not set - AI features will be disabled. Set in environment, .trie/config.json, or .env file");
|
|
203
|
-
}
|
|
204
|
-
if (!process.env.GITHUB_TOKEN && process.env.CI) {
|
|
205
|
-
warnings.push("GITHUB_TOKEN not set - GitHub integration disabled");
|
|
206
|
-
}
|
|
207
|
-
return {
|
|
208
|
-
valid: errors.length === 0,
|
|
209
|
-
warnings,
|
|
210
|
-
errors
|
|
211
|
-
};
|
|
212
|
-
}
|
|
213
|
-
/**
|
|
214
|
-
* Validate file paths in configuration
|
|
215
|
-
*/
|
|
216
|
-
validatePaths(paths) {
|
|
217
|
-
const errors = [];
|
|
218
|
-
if (paths?.include) {
|
|
219
|
-
for (const path of paths.include) {
|
|
220
|
-
const resolvedPath = resolve(path);
|
|
221
|
-
if (!existsSync2(resolvedPath)) {
|
|
222
|
-
errors.push(`Include path does not exist: ${path}`);
|
|
223
|
-
}
|
|
224
|
-
}
|
|
225
|
-
}
|
|
226
|
-
if (paths?.configDir) {
|
|
227
|
-
const configPath = resolve(paths.configDir);
|
|
228
|
-
if (!existsSync2(configPath)) {
|
|
229
|
-
try {
|
|
230
|
-
__require("fs").mkdirSync(configPath, { recursive: true });
|
|
231
|
-
} catch {
|
|
232
|
-
errors.push(`Cannot create config directory: ${paths.configDir}`);
|
|
233
|
-
}
|
|
234
|
-
}
|
|
235
|
-
}
|
|
236
|
-
return {
|
|
237
|
-
valid: errors.length === 0,
|
|
238
|
-
errors
|
|
239
|
-
};
|
|
240
|
-
}
|
|
241
|
-
/**
|
|
242
|
-
* Validate integration configurations
|
|
243
|
-
*/
|
|
244
|
-
validateIntegrations(integrations) {
|
|
245
|
-
const errors = [];
|
|
246
|
-
if (integrations?.github?.enabled) {
|
|
247
|
-
if (!integrations.github.token) {
|
|
248
|
-
errors.push("GitHub integration enabled but no token provided");
|
|
249
|
-
}
|
|
250
|
-
}
|
|
251
|
-
if (integrations?.slack?.enabled) {
|
|
252
|
-
if (!integrations.slack.webhook) {
|
|
253
|
-
errors.push("Slack integration enabled but no webhook URL provided");
|
|
254
|
-
}
|
|
255
|
-
}
|
|
256
|
-
if (integrations?.jira?.enabled) {
|
|
257
|
-
if (!integrations.jira.url || !integrations.jira.token || !integrations.jira.project) {
|
|
258
|
-
errors.push("JIRA integration enabled but missing required fields (url, token, project)");
|
|
259
|
-
}
|
|
260
|
-
}
|
|
261
|
-
return {
|
|
262
|
-
valid: errors.length === 0,
|
|
263
|
-
errors
|
|
264
|
-
};
|
|
265
|
-
}
|
|
266
|
-
/**
|
|
267
|
-
* Business logic validation
|
|
268
|
-
*/
|
|
269
|
-
validateBusinessLogic(config) {
|
|
270
|
-
const errors = [];
|
|
271
|
-
if (config.agents?.enabled && config.agents?.disabled) {
|
|
272
|
-
const overlap = config.agents.enabled.filter(
|
|
273
|
-
(agent) => config.agents?.disabled?.includes(agent)
|
|
274
|
-
);
|
|
275
|
-
if (overlap.length > 0) {
|
|
276
|
-
errors.push(`Agents cannot be both enabled and disabled: ${overlap.join(", ")}`);
|
|
277
|
-
}
|
|
278
|
-
}
|
|
279
|
-
if (config.agents?.maxConcurrency && config.agents.maxConcurrency > 10) {
|
|
280
|
-
errors.push("maxConcurrency should not exceed 10 for optimal performance");
|
|
281
|
-
}
|
|
282
|
-
if (config.compliance?.standards) {
|
|
283
|
-
const invalidStandards = config.compliance.standards.filter(
|
|
284
|
-
(standard) => !["SOC2", "GDPR", "HIPAA", "CCPA", "PCI-DSS"].includes(standard)
|
|
285
|
-
);
|
|
286
|
-
if (invalidStandards.length > 0) {
|
|
287
|
-
errors.push(`Invalid compliance standards: ${invalidStandards.join(", ")}`);
|
|
288
|
-
}
|
|
289
|
-
}
|
|
290
|
-
if (config.paths) {
|
|
291
|
-
const pathValidation = this.validatePaths(config.paths);
|
|
292
|
-
errors.push(...pathValidation.errors);
|
|
293
|
-
}
|
|
294
|
-
if (config.integrations) {
|
|
295
|
-
const integrationValidation = this.validateIntegrations(config.integrations);
|
|
296
|
-
errors.push(...integrationValidation.errors);
|
|
297
|
-
}
|
|
298
|
-
return errors;
|
|
299
|
-
}
|
|
300
|
-
/**
|
|
301
|
-
* Generate configuration template
|
|
302
|
-
*/
|
|
303
|
-
generateTemplate() {
|
|
304
|
-
return {
|
|
305
|
-
version: "1.0.0",
|
|
306
|
-
agents: {
|
|
307
|
-
enabled: ["security", "bugs", "types"],
|
|
308
|
-
disabled: [],
|
|
309
|
-
parallel: true,
|
|
310
|
-
maxConcurrency: 4,
|
|
311
|
-
timeout: 12e4,
|
|
312
|
-
cache: true
|
|
313
|
-
},
|
|
314
|
-
compliance: {
|
|
315
|
-
standards: ["SOC2"],
|
|
316
|
-
enforceCompliance: false,
|
|
317
|
-
reportFormat: "json"
|
|
318
|
-
},
|
|
319
|
-
output: {
|
|
320
|
-
format: "console",
|
|
321
|
-
level: "all",
|
|
322
|
-
interactive: false,
|
|
323
|
-
streaming: true,
|
|
324
|
-
colors: true
|
|
325
|
-
},
|
|
326
|
-
paths: {
|
|
327
|
-
include: [],
|
|
328
|
-
exclude: ["node_modules", "dist", "build", ".git"],
|
|
329
|
-
configDir: ".trie",
|
|
330
|
-
outputDir: "trie-reports"
|
|
331
|
-
}
|
|
332
|
-
};
|
|
333
|
-
}
|
|
334
|
-
/**
|
|
335
|
-
* Validate and provide suggestions for improvement
|
|
336
|
-
*/
|
|
337
|
-
analyze(config) {
|
|
338
|
-
const suggestions = [];
|
|
339
|
-
const securityIssues = [];
|
|
340
|
-
const optimizations = [];
|
|
341
|
-
let score = 100;
|
|
342
|
-
let hasApiKey = Boolean(config.apiKeys?.anthropic || process.env.ANTHROPIC_API_KEY);
|
|
343
|
-
if (!hasApiKey) {
|
|
344
|
-
try {
|
|
345
|
-
const workDir = getWorkingDirectory(void 0, true);
|
|
346
|
-
const envFiles = [".env", ".env.local", ".env.production"];
|
|
347
|
-
for (const envFile of envFiles) {
|
|
348
|
-
const envPath = join2(workDir, envFile);
|
|
349
|
-
if (existsSync2(envPath)) {
|
|
350
|
-
const envContent = readFileSync(envPath, "utf-8");
|
|
351
|
-
if (envContent.includes("ANTHROPIC_API_KEY=")) {
|
|
352
|
-
hasApiKey = true;
|
|
353
|
-
break;
|
|
354
|
-
}
|
|
355
|
-
}
|
|
356
|
-
}
|
|
357
|
-
} catch {
|
|
358
|
-
}
|
|
359
|
-
}
|
|
360
|
-
if (!hasApiKey) {
|
|
361
|
-
suggestions.push("Add ANTHROPIC_API_KEY to enable AI-powered analysis for better issue detection. Set in environment, .trie/config.json, or .env file");
|
|
362
|
-
score -= 10;
|
|
363
|
-
}
|
|
364
|
-
if (config.agents?.parallel === false) {
|
|
365
|
-
optimizations.push("Enable parallel agent execution for 3-5x faster scans");
|
|
366
|
-
score -= 15;
|
|
367
|
-
}
|
|
368
|
-
if (config.agents?.cache === false) {
|
|
369
|
-
optimizations.push("Enable result caching to speed up repeated scans");
|
|
370
|
-
score -= 10;
|
|
371
|
-
}
|
|
372
|
-
if (!config.compliance?.standards || config.compliance.standards.length === 0) {
|
|
373
|
-
suggestions.push("Configure compliance standards (SOC2, GDPR, etc.) for regulatory requirements");
|
|
374
|
-
score -= 5;
|
|
375
|
-
}
|
|
376
|
-
const hasIntegrations = config.integrations && (config.integrations.github?.enabled || config.integrations.slack?.enabled || config.integrations.jira?.enabled);
|
|
377
|
-
if (!hasIntegrations) {
|
|
378
|
-
suggestions.push("Consider enabling GitHub/Slack/JIRA integrations for better team collaboration");
|
|
379
|
-
score -= 5;
|
|
380
|
-
}
|
|
381
|
-
if (config.apiKeys) {
|
|
382
|
-
securityIssues.push("API keys in config file - consider using environment variables instead");
|
|
383
|
-
score -= 20;
|
|
384
|
-
}
|
|
385
|
-
return {
|
|
386
|
-
score: Math.max(0, score),
|
|
387
|
-
suggestions,
|
|
388
|
-
securityIssues,
|
|
389
|
-
optimizations
|
|
390
|
-
};
|
|
391
|
-
}
|
|
392
|
-
};
|
|
393
|
-
var DEFAULT_CONFIG = {
|
|
394
|
-
version: "1.0.0",
|
|
395
|
-
agents: {
|
|
396
|
-
enabled: [],
|
|
397
|
-
disabled: [],
|
|
398
|
-
parallel: true,
|
|
399
|
-
maxConcurrency: 4,
|
|
400
|
-
timeout: 12e4,
|
|
401
|
-
cache: true
|
|
402
|
-
},
|
|
403
|
-
compliance: {
|
|
404
|
-
standards: ["SOC2"],
|
|
405
|
-
enforceCompliance: false,
|
|
406
|
-
reportFormat: "json"
|
|
407
|
-
},
|
|
408
|
-
output: {
|
|
409
|
-
format: "console",
|
|
410
|
-
level: "all",
|
|
411
|
-
interactive: false,
|
|
412
|
-
streaming: true,
|
|
413
|
-
colors: true
|
|
414
|
-
},
|
|
415
|
-
paths: {
|
|
416
|
-
include: [],
|
|
417
|
-
exclude: ["node_modules", "dist", "build", ".git", ".next", ".nuxt", "coverage"],
|
|
418
|
-
configDir: ".trie",
|
|
419
|
-
outputDir: "trie-reports"
|
|
420
|
-
}
|
|
421
|
-
};
|
|
422
|
-
|
|
423
|
-
// src/config/loader.ts
|
|
424
|
-
async function loadConfig() {
|
|
425
|
-
const validator = new ConfigValidator();
|
|
426
|
-
const configPath = join3(getTrieDirectory(getWorkingDirectory(void 0, true)), "config.json");
|
|
427
|
-
try {
|
|
428
|
-
if (!existsSync3(configPath)) {
|
|
429
|
-
return DEFAULT_CONFIG;
|
|
430
|
-
}
|
|
431
|
-
const configFile = await readFile(configPath, "utf-8");
|
|
432
|
-
const userConfig = JSON.parse(configFile);
|
|
433
|
-
const merged = mergeConfig(DEFAULT_CONFIG, userConfig);
|
|
434
|
-
const result = validator.validateConfig(merged);
|
|
435
|
-
if (!result.success) {
|
|
436
|
-
if (!isInteractiveMode()) {
|
|
437
|
-
console.error("Configuration validation failed:");
|
|
438
|
-
for (const error of result.errors) {
|
|
439
|
-
console.error(` - ${error}`);
|
|
440
|
-
}
|
|
441
|
-
}
|
|
442
|
-
return DEFAULT_CONFIG;
|
|
443
|
-
}
|
|
444
|
-
if (!isInteractiveMode()) {
|
|
445
|
-
const envValidation = validator.validateEnvironment();
|
|
446
|
-
for (const warning of envValidation.warnings) {
|
|
447
|
-
console.warn(warning);
|
|
448
|
-
}
|
|
449
|
-
for (const error of envValidation.errors) {
|
|
450
|
-
console.error(error);
|
|
451
|
-
}
|
|
452
|
-
}
|
|
453
|
-
return result.data;
|
|
454
|
-
} catch (error) {
|
|
455
|
-
if (!isInteractiveMode()) {
|
|
456
|
-
console.error("Failed to load config, using defaults:", error);
|
|
457
|
-
}
|
|
458
|
-
return DEFAULT_CONFIG;
|
|
459
|
-
}
|
|
460
|
-
}
|
|
461
|
-
async function saveConfig(config) {
|
|
462
|
-
const configPath = join3(getTrieDirectory(getWorkingDirectory(void 0, true)), "config.json");
|
|
463
|
-
const dir = dirname(configPath);
|
|
464
|
-
if (!existsSync3(dir)) {
|
|
465
|
-
await mkdir(dir, { recursive: true });
|
|
466
|
-
}
|
|
467
|
-
await writeFile(configPath, JSON.stringify(config, null, 2), "utf-8");
|
|
468
|
-
}
|
|
469
|
-
function mergeConfig(defaults, user) {
|
|
470
|
-
if (typeof user !== "object" || user === null || Array.isArray(user)) {
|
|
471
|
-
return { ...defaults };
|
|
472
|
-
}
|
|
473
|
-
const result = { ...defaults };
|
|
474
|
-
for (const [key, value] of Object.entries(user)) {
|
|
475
|
-
const defaultValue = defaults[key];
|
|
476
|
-
if (typeof value === "object" && value !== null && !Array.isArray(value) && typeof defaultValue === "object" && defaultValue !== null) {
|
|
477
|
-
result[key] = mergeConfig(defaultValue, value);
|
|
478
|
-
} else {
|
|
479
|
-
result[key] = value;
|
|
480
|
-
}
|
|
481
|
-
}
|
|
482
|
-
return result;
|
|
483
|
-
}
|
|
484
|
-
|
|
485
|
-
// src/orchestrator/triager.ts
|
|
486
|
-
var Triager = class {
|
|
487
|
-
agentRegistry = getSkillRegistry();
|
|
488
|
-
config;
|
|
489
|
-
customSkillsLoaded = false;
|
|
490
|
-
contextState = null;
|
|
491
|
-
memoryInsights = null;
|
|
492
|
-
constructor(config) {
|
|
493
|
-
this.config = {
|
|
494
|
-
minConfidence: 0.15,
|
|
495
|
-
maxAgents: 11,
|
|
496
|
-
timeoutMs: 6e4,
|
|
497
|
-
enableCostAware: false,
|
|
498
|
-
enableDependencies: true,
|
|
499
|
-
...config
|
|
500
|
-
};
|
|
501
|
-
}
|
|
502
|
-
/**
|
|
503
|
-
* Load previous context state for smart triaging
|
|
504
|
-
*/
|
|
505
|
-
async loadPreviousContext() {
|
|
506
|
-
if (this.contextState === null) {
|
|
507
|
-
try {
|
|
508
|
-
this.contextState = await loadContextState();
|
|
509
|
-
} catch {
|
|
510
|
-
this.contextState = null;
|
|
511
|
-
}
|
|
512
|
-
}
|
|
513
|
-
}
|
|
514
|
-
/**
|
|
515
|
-
* Load memory insights for memory-influenced triaging
|
|
516
|
-
*/
|
|
517
|
-
async loadMemoryInsights() {
|
|
518
|
-
if (this.memoryInsights !== null) return;
|
|
519
|
-
try {
|
|
520
|
-
const [stats, recent, historical, global] = await Promise.all([
|
|
521
|
-
getMemoryStats().catch(() => null),
|
|
522
|
-
getRecentIssues({ limit: 20 }).catch(() => []),
|
|
523
|
-
getHistoricalInsights(process.cwd()).catch(() => null),
|
|
524
|
-
getGlobalMemoryStats().catch(() => null)
|
|
525
|
-
]);
|
|
526
|
-
const recentAgents = /* @__PURE__ */ new Set();
|
|
527
|
-
for (const issue of recent) {
|
|
528
|
-
recentAgents.add(issue.agent);
|
|
529
|
-
}
|
|
530
|
-
const recurringPatternAgents = /* @__PURE__ */ new Set();
|
|
531
|
-
if (historical?.recurringPatterns) {
|
|
532
|
-
for (const pattern of historical.recurringPatterns) {
|
|
533
|
-
recurringPatternAgents.add(pattern.agent);
|
|
534
|
-
}
|
|
535
|
-
}
|
|
536
|
-
const crossProjectAgents = /* @__PURE__ */ new Set();
|
|
537
|
-
if (global?.patternsByAgent) {
|
|
538
|
-
for (const [agent, count] of Object.entries(global.patternsByAgent)) {
|
|
539
|
-
if (count >= 2) {
|
|
540
|
-
crossProjectAgents.add(agent);
|
|
541
|
-
}
|
|
542
|
-
}
|
|
543
|
-
}
|
|
544
|
-
this.memoryInsights = {
|
|
545
|
-
issuesByAgent: stats?.issuesByAgent || {},
|
|
546
|
-
recentAgents,
|
|
547
|
-
recurringPatternAgents,
|
|
548
|
-
trend: historical?.improvementTrend || "unknown",
|
|
549
|
-
crossProjectAgents
|
|
550
|
-
};
|
|
551
|
-
} catch {
|
|
552
|
-
this.memoryInsights = {
|
|
553
|
-
issuesByAgent: {},
|
|
554
|
-
recentAgents: /* @__PURE__ */ new Set(),
|
|
555
|
-
recurringPatternAgents: /* @__PURE__ */ new Set(),
|
|
556
|
-
trend: "unknown",
|
|
557
|
-
crossProjectAgents: /* @__PURE__ */ new Set()
|
|
558
|
-
};
|
|
559
|
-
}
|
|
560
|
-
}
|
|
561
|
-
/**
|
|
562
|
-
* Ensure custom skills are loaded before triaging
|
|
563
|
-
*/
|
|
564
|
-
async ensureCustomSkillsLoaded() {
|
|
565
|
-
if (!this.customSkillsLoaded) {
|
|
566
|
-
await this.agentRegistry.loadCustomSkills();
|
|
567
|
-
this.customSkillsLoaded = true;
|
|
568
|
-
}
|
|
569
|
-
}
|
|
570
|
-
async selectAgents(context, riskLevel) {
|
|
571
|
-
await this.ensureCustomSkillsLoaded();
|
|
572
|
-
await Promise.all([
|
|
573
|
-
this.loadPreviousContext(),
|
|
574
|
-
this.loadMemoryInsights()
|
|
575
|
-
]);
|
|
576
|
-
let effectiveRiskLevel = riskLevel;
|
|
577
|
-
if (this.contextState?.healthScore !== void 0 && this.contextState.healthScore < 50) {
|
|
578
|
-
if (riskLevel === "low" || riskLevel === "medium") {
|
|
579
|
-
effectiveRiskLevel = "high";
|
|
580
|
-
if (!isInteractiveMode()) {
|
|
581
|
-
console.error(` Health score ${this.contextState.healthScore}% - escalating to ${effectiveRiskLevel.toUpperCase()} risk`);
|
|
582
|
-
}
|
|
583
|
-
}
|
|
584
|
-
}
|
|
585
|
-
if (effectiveRiskLevel === "critical" || effectiveRiskLevel === "high") {
|
|
586
|
-
if (!isInteractiveMode()) {
|
|
587
|
-
console.error(` ${effectiveRiskLevel.toUpperCase()} risk - activating all scouts for comprehensive review`);
|
|
588
|
-
}
|
|
589
|
-
return this.getAllAgents().filter((agent) => agent.shouldActivate(context));
|
|
590
|
-
}
|
|
591
|
-
const scores = this.scoreAgents(context, effectiveRiskLevel);
|
|
592
|
-
this.boostAgentsWithHistory(scores);
|
|
593
|
-
this.boostAgentsWithMemory(scores);
|
|
594
|
-
this.logAgentScoring(scores);
|
|
595
|
-
const qualified = scores.filter((s) => s.confidence >= this.config.minConfidence);
|
|
596
|
-
qualified.sort((a, b) => {
|
|
597
|
-
if (a.tier !== b.tier) return a.tier - b.tier;
|
|
598
|
-
return b.confidence - a.confidence;
|
|
599
|
-
});
|
|
600
|
-
if (this.config.enableDependencies) {
|
|
601
|
-
return this.resolveDependencies(qualified.map((s) => s.agent));
|
|
602
|
-
}
|
|
603
|
-
return qualified.map((s) => s.agent);
|
|
604
|
-
}
|
|
605
|
-
/**
|
|
606
|
-
* Boost confidence for agents that found issues in previous scans
|
|
607
|
-
*/
|
|
608
|
-
boostAgentsWithHistory(scores) {
|
|
609
|
-
if (!this.contextState?.agentStatus) return;
|
|
610
|
-
for (const score of scores) {
|
|
611
|
-
const previousRun = this.contextState.agentStatus[score.agent.name];
|
|
612
|
-
if (previousRun?.issuesFound && previousRun.issuesFound > 0) {
|
|
613
|
-
const boost = Math.min(0.3, previousRun.issuesFound * 0.05);
|
|
614
|
-
score.confidence = Math.min(1, score.confidence + boost);
|
|
615
|
-
score.reasons.push(`found ${previousRun.issuesFound} issues in last scan`);
|
|
616
|
-
}
|
|
617
|
-
}
|
|
618
|
-
}
|
|
619
|
-
/**
|
|
620
|
-
* Boost confidence for agents based on memory patterns
|
|
621
|
-
*/
|
|
622
|
-
boostAgentsWithMemory(scores) {
|
|
623
|
-
if (!this.memoryInsights) return;
|
|
624
|
-
for (const score of scores) {
|
|
625
|
-
const agentName = score.agent.name;
|
|
626
|
-
const historicalCount = this.memoryInsights.issuesByAgent[agentName] || 0;
|
|
627
|
-
if (historicalCount >= 10) {
|
|
628
|
-
const boost = Math.min(0.2, historicalCount * 0.01);
|
|
629
|
-
score.confidence = Math.min(1, score.confidence + boost);
|
|
630
|
-
score.reasons.push(`${historicalCount} historical issues`);
|
|
631
|
-
}
|
|
632
|
-
if (this.memoryInsights.recentAgents.has(agentName)) {
|
|
633
|
-
score.confidence = Math.min(1, score.confidence + 0.1);
|
|
634
|
-
score.reasons.push("recent activity");
|
|
635
|
-
}
|
|
636
|
-
if (this.memoryInsights.recurringPatternAgents.has(agentName)) {
|
|
637
|
-
score.confidence = Math.min(1, score.confidence + 0.15);
|
|
638
|
-
score.reasons.push("recurring patterns");
|
|
639
|
-
}
|
|
640
|
-
if (this.memoryInsights.crossProjectAgents.has(agentName)) {
|
|
641
|
-
score.confidence = Math.min(1, score.confidence + 0.1);
|
|
642
|
-
score.reasons.push("cross-project pattern");
|
|
643
|
-
}
|
|
644
|
-
}
|
|
645
|
-
if (this.memoryInsights.trend === "declining") {
|
|
646
|
-
for (const score of scores) {
|
|
647
|
-
if (score.confidence > 0) {
|
|
648
|
-
score.confidence = Math.min(1, score.confidence + 0.05);
|
|
649
|
-
}
|
|
650
|
-
}
|
|
651
|
-
}
|
|
652
|
-
}
|
|
653
|
-
scoreAgents(context, riskLevel) {
|
|
654
|
-
const allAgents = this.getAllAgents();
|
|
655
|
-
const scores = [];
|
|
656
|
-
for (const agent of allAgents) {
|
|
657
|
-
const score = this.scoreAgent(agent, context, riskLevel);
|
|
658
|
-
scores.push(score);
|
|
659
|
-
}
|
|
660
|
-
return scores;
|
|
661
|
-
}
|
|
662
|
-
scoreAgent(agent, context, riskLevel) {
|
|
663
|
-
if (agent instanceof CustomSkill) {
|
|
664
|
-
return this.scoreCustomSkill(agent, context, riskLevel);
|
|
665
|
-
}
|
|
666
|
-
return this.scoreBuiltinAgent(agent, context, riskLevel);
|
|
667
|
-
}
|
|
668
|
-
/**
|
|
669
|
-
* Score custom skills using their activation rules
|
|
670
|
-
*/
|
|
671
|
-
scoreCustomSkill(agent, context, riskLevel) {
|
|
672
|
-
const reasons = [];
|
|
673
|
-
let confidence = agent.getActivationConfidence(context);
|
|
674
|
-
if (confidence > 0) {
|
|
675
|
-
reasons.push(`custom skill: ${agent.getMetadata().category}`);
|
|
676
|
-
const meta = agent.getMetadata();
|
|
677
|
-
if (meta.patternCount > 0) {
|
|
678
|
-
reasons.push(`${meta.patternCount} detection patterns`);
|
|
679
|
-
}
|
|
680
|
-
}
|
|
681
|
-
if (riskLevel === "high" && confidence > 0) {
|
|
682
|
-
confidence = Math.min(1, confidence * 1.2);
|
|
683
|
-
}
|
|
684
|
-
return {
|
|
685
|
-
agent,
|
|
686
|
-
confidence,
|
|
687
|
-
reasons,
|
|
688
|
-
tier: agent.priority.tier,
|
|
689
|
-
isCustom: true
|
|
690
|
-
};
|
|
691
|
-
}
|
|
692
|
-
/**
|
|
693
|
-
* Score built-in agents
|
|
694
|
-
*/
|
|
695
|
-
scoreBuiltinAgent(agent, context, riskLevel) {
|
|
696
|
-
const reasons = [];
|
|
697
|
-
let confidence = 0;
|
|
698
|
-
let tier = 3;
|
|
699
|
-
if (agent.name === "typecheck") {
|
|
700
|
-
tier = 1;
|
|
701
|
-
confidence = 1;
|
|
702
|
-
reasons.push("fundamental type safety");
|
|
703
|
-
}
|
|
704
|
-
if (agent.name === "comprehension") {
|
|
705
|
-
tier = 1;
|
|
706
|
-
confidence = 1;
|
|
707
|
-
reasons.push("stakeholder communication");
|
|
708
|
-
}
|
|
709
|
-
if (agent.name === "security") {
|
|
710
|
-
tier = 2;
|
|
711
|
-
if (context.touchesAuth) {
|
|
712
|
-
confidence += 0.4;
|
|
713
|
-
reasons.push("auth code");
|
|
714
|
-
}
|
|
715
|
-
if (context.touchesPayments) {
|
|
716
|
-
confidence += 0.4;
|
|
717
|
-
reasons.push("payment code");
|
|
718
|
-
}
|
|
719
|
-
if (context.touchesAPI) {
|
|
720
|
-
confidence += 0.3;
|
|
721
|
-
reasons.push("API endpoints");
|
|
722
|
-
}
|
|
723
|
-
if (context.touchesDatabase) {
|
|
724
|
-
confidence += 0.25;
|
|
725
|
-
reasons.push("database access");
|
|
726
|
-
}
|
|
727
|
-
if (context.touchesCrypto) {
|
|
728
|
-
confidence += 0.35;
|
|
729
|
-
reasons.push("cryptographic operations");
|
|
730
|
-
}
|
|
731
|
-
if (context.touchesUserData) {
|
|
732
|
-
confidence += 0.3;
|
|
733
|
-
reasons.push("user data");
|
|
734
|
-
}
|
|
735
|
-
if (context.touchesSecurityConfig) {
|
|
736
|
-
confidence += 0.4;
|
|
737
|
-
reasons.push("security config");
|
|
738
|
-
}
|
|
739
|
-
if (context.touchesThirdPartyAPI) {
|
|
740
|
-
confidence += 0.2;
|
|
741
|
-
reasons.push("third-party integration");
|
|
742
|
-
}
|
|
743
|
-
if (context.patterns?.hasFileUploads) {
|
|
744
|
-
confidence += 0.3;
|
|
745
|
-
reasons.push("file uploads");
|
|
746
|
-
}
|
|
747
|
-
if (riskLevel === "high") confidence *= 1.2;
|
|
748
|
-
}
|
|
749
|
-
if (agent.name === "privacy") {
|
|
750
|
-
tier = 2;
|
|
751
|
-
if (context.touchesUserData) {
|
|
752
|
-
confidence += 0.5;
|
|
753
|
-
reasons.push("PII handling");
|
|
754
|
-
}
|
|
755
|
-
if (context.touchesAuth) {
|
|
756
|
-
confidence += 0.3;
|
|
757
|
-
reasons.push("credentials");
|
|
758
|
-
}
|
|
759
|
-
if (context.touchesLogging) {
|
|
760
|
-
confidence += 0.25;
|
|
761
|
-
reasons.push("logging (may expose data)");
|
|
762
|
-
}
|
|
763
|
-
if (context.patterns?.hasEmailHandling) {
|
|
764
|
-
confidence += 0.3;
|
|
765
|
-
reasons.push("email handling");
|
|
766
|
-
}
|
|
767
|
-
if (context.patterns?.hasFormHandling) {
|
|
768
|
-
confidence += 0.2;
|
|
769
|
-
reasons.push("form data");
|
|
770
|
-
}
|
|
771
|
-
}
|
|
772
|
-
if (agent.name === "legal") {
|
|
773
|
-
tier = 2;
|
|
774
|
-
if (context.touchesUserData) {
|
|
775
|
-
confidence += 0.4;
|
|
776
|
-
reasons.push("GDPR/CCPA");
|
|
777
|
-
}
|
|
778
|
-
if (context.touchesPayments) {
|
|
779
|
-
confidence += 0.35;
|
|
780
|
-
reasons.push("PCI-DSS");
|
|
781
|
-
}
|
|
782
|
-
if (context.patterns?.hasEmailHandling) {
|
|
783
|
-
confidence += 0.25;
|
|
784
|
-
reasons.push("CAN-SPAM");
|
|
785
|
-
}
|
|
786
|
-
}
|
|
787
|
-
if (agent.name === "accessibility") {
|
|
788
|
-
tier = 2;
|
|
789
|
-
if (context.touchesUI) {
|
|
790
|
-
confidence += 0.6;
|
|
791
|
-
reasons.push("UI components");
|
|
792
|
-
}
|
|
793
|
-
if (context.framework === "react" || context.framework === "vue") {
|
|
794
|
-
confidence += 0.2;
|
|
795
|
-
reasons.push(`${context.framework} framework`);
|
|
796
|
-
}
|
|
797
|
-
if (context.patterns?.hasFormHandling) {
|
|
798
|
-
confidence += 0.2;
|
|
799
|
-
reasons.push("form UX");
|
|
800
|
-
}
|
|
801
|
-
}
|
|
802
|
-
if (agent.name === "test") {
|
|
803
|
-
tier = 2;
|
|
804
|
-
if (context.isNewFeature) {
|
|
805
|
-
confidence += 0.4;
|
|
806
|
-
reasons.push("new feature");
|
|
807
|
-
}
|
|
808
|
-
if (context.touchesAuth) {
|
|
809
|
-
confidence += 0.35;
|
|
810
|
-
reasons.push("auth needs tests");
|
|
811
|
-
}
|
|
812
|
-
if (context.touchesPayments) {
|
|
813
|
-
confidence += 0.4;
|
|
814
|
-
reasons.push("payments need tests");
|
|
815
|
-
}
|
|
816
|
-
if (context.touchesAPI) {
|
|
817
|
-
confidence += 0.3;
|
|
818
|
-
reasons.push("API testing");
|
|
819
|
-
}
|
|
820
|
-
if (!context.hasTests) {
|
|
821
|
-
confidence += 0.2;
|
|
822
|
-
reasons.push("no existing tests");
|
|
823
|
-
}
|
|
824
|
-
if (context.complexity === "high") {
|
|
825
|
-
confidence += 0.25;
|
|
826
|
-
reasons.push("complex code");
|
|
827
|
-
}
|
|
828
|
-
}
|
|
829
|
-
if (agent.name === "software-architect") {
|
|
830
|
-
tier = 2;
|
|
831
|
-
if (context.isNewFeature) {
|
|
832
|
-
confidence += 0.35;
|
|
833
|
-
reasons.push("architecture review");
|
|
834
|
-
}
|
|
835
|
-
if (context.touchesDatabase) {
|
|
836
|
-
confidence += 0.35;
|
|
837
|
-
reasons.push("data modeling");
|
|
838
|
-
}
|
|
839
|
-
if (context.linesChanged > 200) {
|
|
840
|
-
confidence += 0.3;
|
|
841
|
-
reasons.push("large change");
|
|
842
|
-
}
|
|
843
|
-
if (context.touchesAPI) {
|
|
844
|
-
confidence += 0.25;
|
|
845
|
-
reasons.push("API design");
|
|
846
|
-
}
|
|
847
|
-
if (context.patterns?.hasWebSockets) {
|
|
848
|
-
confidence += 0.3;
|
|
849
|
-
reasons.push("real-time architecture");
|
|
850
|
-
}
|
|
851
|
-
if (context.patterns?.hasQueue) {
|
|
852
|
-
confidence += 0.3;
|
|
853
|
-
reasons.push("async architecture");
|
|
854
|
-
}
|
|
855
|
-
}
|
|
856
|
-
if (agent.name === "devops") {
|
|
857
|
-
tier = 2;
|
|
858
|
-
if (context.touchesSecurityConfig) {
|
|
859
|
-
confidence += 0.4;
|
|
860
|
-
reasons.push("security config");
|
|
861
|
-
}
|
|
862
|
-
if (context.touchesFileSystem) {
|
|
863
|
-
confidence += 0.3;
|
|
864
|
-
reasons.push("file operations");
|
|
865
|
-
}
|
|
866
|
-
if (context.touchesLogging) {
|
|
867
|
-
confidence += 0.25;
|
|
868
|
-
reasons.push("logging");
|
|
869
|
-
}
|
|
870
|
-
if (context.touchesErrorHandling) {
|
|
871
|
-
confidence += 0.2;
|
|
872
|
-
reasons.push("error handling");
|
|
873
|
-
}
|
|
874
|
-
if (context.patterns?.hasCaching) {
|
|
875
|
-
confidence += 0.25;
|
|
876
|
-
reasons.push("caching");
|
|
877
|
-
}
|
|
878
|
-
if (context.patterns?.hasRateLimiting) {
|
|
879
|
-
confidence += 0.3;
|
|
880
|
-
reasons.push("rate limiting");
|
|
881
|
-
}
|
|
882
|
-
}
|
|
883
|
-
if (agent.name === "bug-finding") {
|
|
884
|
-
tier = 2;
|
|
885
|
-
if (context.touchesPayments) {
|
|
886
|
-
confidence += 0.5;
|
|
887
|
-
reasons.push("payments = zero bugs");
|
|
888
|
-
}
|
|
889
|
-
if (context.isNewFeature) {
|
|
890
|
-
confidence += 0.3;
|
|
891
|
-
reasons.push("new code");
|
|
892
|
-
}
|
|
893
|
-
if (context.patterns?.hasAsyncCode) {
|
|
894
|
-
confidence += 0.35;
|
|
895
|
-
reasons.push("async patterns");
|
|
896
|
-
}
|
|
897
|
-
if (context.complexity === "high") {
|
|
898
|
-
confidence += 0.3;
|
|
899
|
-
reasons.push("complex logic");
|
|
900
|
-
}
|
|
901
|
-
if (context.touchesDatabase) {
|
|
902
|
-
confidence += 0.25;
|
|
903
|
-
reasons.push("data mutations");
|
|
904
|
-
}
|
|
905
|
-
}
|
|
906
|
-
if (agent.name === "user-testing") {
|
|
907
|
-
tier = 3;
|
|
908
|
-
if (context.touchesUI) {
|
|
909
|
-
confidence += 0.5;
|
|
910
|
-
reasons.push("UI changes");
|
|
911
|
-
}
|
|
912
|
-
if (context.isNewFeature && context.touchesUI) {
|
|
913
|
-
confidence += 0.3;
|
|
914
|
-
reasons.push("new UI feature");
|
|
915
|
-
}
|
|
916
|
-
if (context.patterns?.hasFormHandling) {
|
|
917
|
-
confidence += 0.25;
|
|
918
|
-
reasons.push("form UX");
|
|
919
|
-
}
|
|
920
|
-
}
|
|
921
|
-
if (agent.name === "trie_clean") {
|
|
922
|
-
tier = 2;
|
|
923
|
-
if (context.touchesUI) {
|
|
924
|
-
confidence += 0.4;
|
|
925
|
-
reasons.push("UI code");
|
|
926
|
-
}
|
|
927
|
-
if (context.isNewFeature) {
|
|
928
|
-
confidence += 0.3;
|
|
929
|
-
reasons.push("new feature");
|
|
930
|
-
}
|
|
931
|
-
if (context.framework === "react") {
|
|
932
|
-
confidence += 0.2;
|
|
933
|
-
reasons.push("React code");
|
|
934
|
-
}
|
|
935
|
-
}
|
|
936
|
-
if (agent.name === "soc2") {
|
|
937
|
-
tier = 2;
|
|
938
|
-
if (context.touchesAuth) {
|
|
939
|
-
confidence += 0.4;
|
|
940
|
-
reasons.push("authentication");
|
|
941
|
-
}
|
|
942
|
-
if (context.touchesSecurityConfig) {
|
|
943
|
-
confidence += 0.4;
|
|
944
|
-
reasons.push("security config");
|
|
945
|
-
}
|
|
946
|
-
if (context.touchesLogging) {
|
|
947
|
-
confidence += 0.3;
|
|
948
|
-
reasons.push("logging");
|
|
949
|
-
}
|
|
950
|
-
if (context.touchesAPI) {
|
|
951
|
-
confidence += 0.25;
|
|
952
|
-
reasons.push("API endpoints");
|
|
953
|
-
}
|
|
954
|
-
if (context.touchesDatabase) {
|
|
955
|
-
confidence += 0.2;
|
|
956
|
-
reasons.push("data access");
|
|
957
|
-
}
|
|
958
|
-
}
|
|
959
|
-
if (agent.name === "moneybags") {
|
|
960
|
-
tier = 3;
|
|
961
|
-
if (context.touchesPayments) {
|
|
962
|
-
confidence += 0.6;
|
|
963
|
-
reasons.push("payment code = high cost risk");
|
|
964
|
-
}
|
|
965
|
-
if (context.touchesAuth) {
|
|
966
|
-
confidence += 0.4;
|
|
967
|
-
reasons.push("auth bugs are expensive");
|
|
968
|
-
}
|
|
969
|
-
if (context.touchesHealthData) {
|
|
970
|
-
confidence += 0.5;
|
|
971
|
-
reasons.push("HIPAA violations");
|
|
972
|
-
}
|
|
973
|
-
if (context.touchesUserData) {
|
|
974
|
-
confidence += 0.3;
|
|
975
|
-
reasons.push("PII exposure costs");
|
|
976
|
-
}
|
|
977
|
-
if (context.touchesDatabase) {
|
|
978
|
-
confidence += 0.25;
|
|
979
|
-
reasons.push("data loss risk");
|
|
980
|
-
}
|
|
981
|
-
if (context.isNewFeature) {
|
|
982
|
-
confidence += 0.2;
|
|
983
|
-
reasons.push("new code risk");
|
|
984
|
-
}
|
|
985
|
-
if (riskLevel === "high" || riskLevel === "critical") {
|
|
986
|
-
confidence *= 1.3;
|
|
987
|
-
reasons.push("high-stakes context");
|
|
988
|
-
}
|
|
989
|
-
}
|
|
990
|
-
if (agent.name === "production-ready") {
|
|
991
|
-
tier = 3;
|
|
992
|
-
if (context.touchesAPI) {
|
|
993
|
-
confidence += 0.4;
|
|
994
|
-
reasons.push("API deployment");
|
|
995
|
-
}
|
|
996
|
-
if (context.touchesDatabase) {
|
|
997
|
-
confidence += 0.35;
|
|
998
|
-
reasons.push("database operations");
|
|
999
|
-
}
|
|
1000
|
-
if (context.touchesAuth) {
|
|
1001
|
-
confidence += 0.35;
|
|
1002
|
-
reasons.push("auth system");
|
|
1003
|
-
}
|
|
1004
|
-
if (context.touchesPayments) {
|
|
1005
|
-
confidence += 0.5;
|
|
1006
|
-
reasons.push("payment processing");
|
|
1007
|
-
}
|
|
1008
|
-
if (context.linesChanged > 200) {
|
|
1009
|
-
confidence += 0.3;
|
|
1010
|
-
reasons.push("significant changes");
|
|
1011
|
-
}
|
|
1012
|
-
if (riskLevel === "high" || riskLevel === "critical") {
|
|
1013
|
-
confidence += 0.4;
|
|
1014
|
-
reasons.push("production gate check");
|
|
1015
|
-
}
|
|
1016
|
-
}
|
|
1017
|
-
confidence = Math.min(1, confidence);
|
|
1018
|
-
return { agent, confidence, reasons, tier, isCustom: false };
|
|
1019
|
-
}
|
|
1020
|
-
logAgentScoring(scores) {
|
|
1021
|
-
if (isInteractiveMode()) return;
|
|
1022
|
-
console.error("\n Agent Confidence Scores:");
|
|
1023
|
-
const sorted = [...scores].sort((a, b) => b.confidence - a.confidence);
|
|
1024
|
-
for (const score of sorted) {
|
|
1025
|
-
const bar = this.getConfidenceBar(score.confidence);
|
|
1026
|
-
const status = score.confidence >= this.config.minConfidence ? "\u2713" : "\u2717";
|
|
1027
|
-
const tierLabel = score.tier === 1 ? "[T1]" : score.tier === 2 ? "[T2]" : "[T3]";
|
|
1028
|
-
const customLabel = score.isCustom ? " \u{1F4DA}" : "";
|
|
1029
|
-
console.error(` ${status} ${score.agent.name.padEnd(18)} ${tierLabel} ${bar} ${(score.confidence * 100).toFixed(0)}%${customLabel}`);
|
|
1030
|
-
if (score.reasons.length > 0 && score.confidence > 0) {
|
|
1031
|
-
console.error(` \u2514\u2500 ${score.reasons.join(", ")}`);
|
|
1032
|
-
}
|
|
1033
|
-
}
|
|
1034
|
-
console.error("");
|
|
1035
|
-
}
|
|
1036
|
-
getConfidenceBar(confidence) {
|
|
1037
|
-
const filled = Math.round(confidence * 10);
|
|
1038
|
-
const empty = 10 - filled;
|
|
1039
|
-
return "\u2588".repeat(filled) + "\u2591".repeat(empty);
|
|
1040
|
-
}
|
|
1041
|
-
resolveDependencies(agents) {
|
|
1042
|
-
const agentNames = new Set(agents.map((a) => a.name));
|
|
1043
|
-
const resolved = [];
|
|
1044
|
-
const added = /* @__PURE__ */ new Set();
|
|
1045
|
-
const dependencies = {
|
|
1046
|
-
"legal": ["privacy"],
|
|
1047
|
-
// legal should see privacy issues first
|
|
1048
|
-
"test": ["bug-finding"],
|
|
1049
|
-
// find bugs before writing tests
|
|
1050
|
-
"user-testing": ["accessibility"]
|
|
1051
|
-
// accessibility before UX
|
|
1052
|
-
};
|
|
1053
|
-
for (const agent of agents) {
|
|
1054
|
-
const deps = dependencies[agent.name] || [];
|
|
1055
|
-
for (const depName of deps) {
|
|
1056
|
-
if (!added.has(depName)) {
|
|
1057
|
-
const depAgent = this.agentRegistry.getAgent(depName);
|
|
1058
|
-
if (depAgent && agentNames.has(depName)) {
|
|
1059
|
-
resolved.push(depAgent);
|
|
1060
|
-
added.add(depName);
|
|
1061
|
-
}
|
|
1062
|
-
}
|
|
1063
|
-
}
|
|
1064
|
-
if (!added.has(agent.name)) {
|
|
1065
|
-
resolved.push(agent);
|
|
1066
|
-
added.add(agent.name);
|
|
1067
|
-
}
|
|
1068
|
-
}
|
|
1069
|
-
return resolved;
|
|
1070
|
-
}
|
|
1071
|
-
getTriagingReason(context, riskLevel) {
|
|
1072
|
-
if (riskLevel === "critical") {
|
|
1073
|
-
return "Critical risk detected - activating all scouts for comprehensive review";
|
|
1074
|
-
}
|
|
1075
|
-
const reasons = [];
|
|
1076
|
-
if (context.touchesAuth) reasons.push("authentication");
|
|
1077
|
-
if (context.touchesPayments) reasons.push("payments");
|
|
1078
|
-
if (context.touchesDatabase) reasons.push("database");
|
|
1079
|
-
if (context.touchesUserData) reasons.push("user data");
|
|
1080
|
-
if (context.touchesUI) reasons.push("UI");
|
|
1081
|
-
if (context.touchesAPI) reasons.push("API");
|
|
1082
|
-
if (context.isNewFeature) reasons.push("new feature");
|
|
1083
|
-
if (context.touchesCrypto) reasons.push("cryptography");
|
|
1084
|
-
if (context.touchesThirdPartyAPI) reasons.push("3rd party API");
|
|
1085
|
-
if (reasons.length === 0) {
|
|
1086
|
-
return `${riskLevel} risk - general code changes`;
|
|
1087
|
-
}
|
|
1088
|
-
return `${riskLevel} risk: ${reasons.join(", ")}`;
|
|
1089
|
-
}
|
|
1090
|
-
async getSkippedAgents(context, riskLevel) {
|
|
1091
|
-
await this.ensureCustomSkillsLoaded();
|
|
1092
|
-
if (riskLevel === "critical") return [];
|
|
1093
|
-
const scores = this.scoreAgents(context, riskLevel);
|
|
1094
|
-
return scores.filter((s) => s.confidence < this.config.minConfidence).map((s) => s.agent.name);
|
|
1095
|
-
}
|
|
1096
|
-
async getTriagingConfidence(context, riskLevel) {
|
|
1097
|
-
await this.ensureCustomSkillsLoaded();
|
|
1098
|
-
const scores = this.scoreAgents(context, riskLevel);
|
|
1099
|
-
const qualified = scores.filter((s) => s.confidence >= this.config.minConfidence);
|
|
1100
|
-
if (qualified.length === 0) return 0.5;
|
|
1101
|
-
const avgConfidence = qualified.reduce((sum, s) => sum + s.confidence, 0) / qualified.length;
|
|
1102
|
-
const contextStrength = this.getContextStrength(context);
|
|
1103
|
-
return Math.min(1, avgConfidence * 0.7 + contextStrength * 0.3);
|
|
1104
|
-
}
|
|
1105
|
-
getContextStrength(context) {
|
|
1106
|
-
let signals = 0;
|
|
1107
|
-
const checks = [
|
|
1108
|
-
context.touchesAuth,
|
|
1109
|
-
context.touchesPayments,
|
|
1110
|
-
context.touchesDatabase,
|
|
1111
|
-
context.touchesAPI,
|
|
1112
|
-
context.touchesUI,
|
|
1113
|
-
context.touchesUserData,
|
|
1114
|
-
context.touchesHealthData,
|
|
1115
|
-
context.touchesSecurityConfig,
|
|
1116
|
-
context.touchesCrypto,
|
|
1117
|
-
context.touchesFileSystem,
|
|
1118
|
-
context.isNewFeature
|
|
1119
|
-
];
|
|
1120
|
-
for (const check of checks) {
|
|
1121
|
-
if (check) signals++;
|
|
1122
|
-
}
|
|
1123
|
-
return signals > 0 ? Math.min(1, signals / 3) : 0.3;
|
|
1124
|
-
}
|
|
1125
|
-
getAllAgents() {
|
|
1126
|
-
return this.agentRegistry.getAllAgents();
|
|
1127
|
-
}
|
|
1128
|
-
/**
|
|
1129
|
-
* Get custom skills count
|
|
1130
|
-
*/
|
|
1131
|
-
getCustomSkillCount() {
|
|
1132
|
-
return this.agentRegistry.getCustomSkills().length;
|
|
1133
|
-
}
|
|
1134
|
-
// Backward compatibility alias
|
|
1135
|
-
getCustomAgentCount() {
|
|
1136
|
-
return this.getCustomSkillCount();
|
|
1137
|
-
}
|
|
1138
|
-
/**
|
|
1139
|
-
* Reload custom skills
|
|
1140
|
-
*/
|
|
1141
|
-
async reloadCustomSkills() {
|
|
1142
|
-
await this.agentRegistry.reloadCustomSkills();
|
|
1143
|
-
}
|
|
1144
|
-
// Backward compatibility alias
|
|
1145
|
-
async reloadCustomAgents() {
|
|
1146
|
-
return this.reloadCustomSkills();
|
|
1147
|
-
}
|
|
1148
|
-
};
|
|
1149
|
-
|
|
1150
|
-
// src/utils/parallel-executor.ts
|
|
1151
|
-
import { Worker } from "worker_threads";
|
|
1152
|
-
import { cpus } from "os";
|
|
1153
|
-
import { existsSync as existsSync4 } from "fs";
|
|
1154
|
-
import { fileURLToPath } from "url";
|
|
1155
|
-
var ParallelExecutor = class {
|
|
1156
|
-
maxWorkers;
|
|
1157
|
-
cache;
|
|
1158
|
-
streaming;
|
|
1159
|
-
activeWorkers = /* @__PURE__ */ new Set();
|
|
1160
|
-
cacheEnabled = true;
|
|
1161
|
-
useWorkerThreads = false;
|
|
1162
|
-
workerAvailable = null;
|
|
1163
|
-
warnedWorkerFallback = false;
|
|
1164
|
-
constructor(cacheManager, maxWorkers = Math.max(2, Math.min(cpus().length - 1, 8)), options) {
|
|
1165
|
-
this.maxWorkers = maxWorkers;
|
|
1166
|
-
this.cache = cacheManager;
|
|
1167
|
-
this.cacheEnabled = options?.cacheEnabled ?? true;
|
|
1168
|
-
this.useWorkerThreads = options?.useWorkerThreads ?? false;
|
|
1169
|
-
}
|
|
1170
|
-
/**
|
|
1171
|
-
* Set streaming manager for real-time updates
|
|
1172
|
-
*/
|
|
1173
|
-
setStreaming(streaming) {
|
|
1174
|
-
this.streaming = streaming;
|
|
1175
|
-
}
|
|
1176
|
-
/**
|
|
1177
|
-
* Execute agents in parallel with intelligent scheduling
|
|
1178
|
-
*/
|
|
1179
|
-
async executeAgents(agents, files, context) {
|
|
1180
|
-
if (agents.length === 0) {
|
|
1181
|
-
return /* @__PURE__ */ new Map();
|
|
1182
|
-
}
|
|
1183
|
-
if (this.streaming && this.streaming.getProgress().totalFiles === 0) {
|
|
1184
|
-
this.streaming.startScan(files.length);
|
|
1185
|
-
}
|
|
1186
|
-
const cacheResults = /* @__PURE__ */ new Map();
|
|
1187
|
-
const uncachedTasks = [];
|
|
1188
|
-
for (const agent of agents) {
|
|
1189
|
-
const cached = await this.checkAgentCache(agent, files);
|
|
1190
|
-
if (cached) {
|
|
1191
|
-
cacheResults.set(agent.name, cached);
|
|
1192
|
-
this.streaming?.completeAgent(agent.name, cached.issues);
|
|
1193
|
-
} else {
|
|
1194
|
-
uncachedTasks.push({
|
|
1195
|
-
agent,
|
|
1196
|
-
files,
|
|
1197
|
-
context,
|
|
1198
|
-
priority: agent.priority?.tier || 2,
|
|
1199
|
-
timeoutMs: context?.config?.timeoutMs || 12e4
|
|
1200
|
-
});
|
|
1201
|
-
}
|
|
1202
|
-
}
|
|
1203
|
-
uncachedTasks.sort((a, b) => a.priority - b.priority);
|
|
1204
|
-
const parallelResults = await this.executeTasksParallel(uncachedTasks);
|
|
1205
|
-
await this.cacheResults(parallelResults);
|
|
1206
|
-
const allResults = /* @__PURE__ */ new Map();
|
|
1207
|
-
for (const [agent, result] of cacheResults) {
|
|
1208
|
-
allResults.set(agent, result);
|
|
1209
|
-
}
|
|
1210
|
-
for (const result of parallelResults) {
|
|
1211
|
-
allResults.set(result.agent, result.result);
|
|
1212
|
-
}
|
|
1213
|
-
const allIssues = Array.from(allResults.values()).flatMap((r) => r.issues);
|
|
1214
|
-
this.streaming?.completeScan(allIssues);
|
|
1215
|
-
return allResults;
|
|
1216
|
-
}
|
|
1217
|
-
/**
|
|
1218
|
-
* Check if agent has cached results for given files
|
|
1219
|
-
*/
|
|
1220
|
-
async checkAgentCache(agent, files) {
|
|
1221
|
-
if (!this.cacheEnabled || !this.cache) {
|
|
1222
|
-
return null;
|
|
1223
|
-
}
|
|
1224
|
-
const cachedIssues = await this.cache.getCachedBatch(files, agent.name);
|
|
1225
|
-
if (cachedIssues.size === files.length) {
|
|
1226
|
-
const allIssues = Array.from(cachedIssues.values()).flat();
|
|
1227
|
-
return {
|
|
1228
|
-
agent: agent.name,
|
|
1229
|
-
issues: allIssues,
|
|
1230
|
-
executionTime: 0,
|
|
1231
|
-
// Cached
|
|
1232
|
-
success: true,
|
|
1233
|
-
metadata: {
|
|
1234
|
-
filesAnalyzed: files.length,
|
|
1235
|
-
linesAnalyzed: 0
|
|
1236
|
-
}
|
|
1237
|
-
};
|
|
1238
|
-
}
|
|
1239
|
-
return null;
|
|
1240
|
-
}
|
|
1241
|
-
/**
|
|
1242
|
-
* Execute tasks in parallel batches
|
|
1243
|
-
*/
|
|
1244
|
-
async executeTasksParallel(tasks) {
|
|
1245
|
-
if (tasks.length === 0) {
|
|
1246
|
-
return [];
|
|
1247
|
-
}
|
|
1248
|
-
const results = [];
|
|
1249
|
-
const batches = this.createBatches(tasks, this.maxWorkers);
|
|
1250
|
-
for (const batch of batches) {
|
|
1251
|
-
const batchResults = await Promise.all(
|
|
1252
|
-
batch.map((task) => this.executeTask(task))
|
|
1253
|
-
);
|
|
1254
|
-
results.push(...batchResults);
|
|
1255
|
-
}
|
|
1256
|
-
return results;
|
|
1257
|
-
}
|
|
1258
|
-
/**
|
|
1259
|
-
* Create batches for parallel execution
|
|
1260
|
-
*/
|
|
1261
|
-
createBatches(tasks, batchSize) {
|
|
1262
|
-
const batches = [];
|
|
1263
|
-
for (let i = 0; i < tasks.length; i += batchSize) {
|
|
1264
|
-
batches.push(tasks.slice(i, i + batchSize));
|
|
1265
|
-
}
|
|
1266
|
-
return batches;
|
|
1267
|
-
}
|
|
1268
|
-
/**
|
|
1269
|
-
* Execute a single task
|
|
1270
|
-
*/
|
|
1271
|
-
async executeTask(task) {
|
|
1272
|
-
const startTime = Date.now();
|
|
1273
|
-
this.streaming?.startAgent(task.agent.name);
|
|
1274
|
-
try {
|
|
1275
|
-
const result = this.canUseWorkers() ? await this.executeTaskInWorker(task) : await task.agent.scan(task.files, task.context);
|
|
1276
|
-
const executionTime = Date.now() - startTime;
|
|
1277
|
-
this.streaming?.completeAgent(task.agent.name, result.issues);
|
|
1278
|
-
return {
|
|
1279
|
-
agent: task.agent.name,
|
|
1280
|
-
result,
|
|
1281
|
-
fromCache: false,
|
|
1282
|
-
executionTime
|
|
1283
|
-
};
|
|
1284
|
-
} catch (error) {
|
|
1285
|
-
const executionTime = Date.now() - startTime;
|
|
1286
|
-
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
1287
|
-
this.streaming?.reportError(new Error(errorMessage), `Agent: ${task.agent.name}`);
|
|
1288
|
-
return {
|
|
1289
|
-
agent: task.agent.name,
|
|
1290
|
-
result: {
|
|
1291
|
-
agent: task.agent.name,
|
|
1292
|
-
issues: [],
|
|
1293
|
-
executionTime,
|
|
1294
|
-
success: false,
|
|
1295
|
-
error: errorMessage
|
|
1296
|
-
},
|
|
1297
|
-
fromCache: false,
|
|
1298
|
-
executionTime
|
|
1299
|
-
};
|
|
1300
|
-
}
|
|
1301
|
-
}
|
|
1302
|
-
canUseWorkers() {
|
|
1303
|
-
if (!this.useWorkerThreads) {
|
|
1304
|
-
return false;
|
|
1305
|
-
}
|
|
1306
|
-
if (this.workerAvailable !== null) {
|
|
1307
|
-
return this.workerAvailable;
|
|
1308
|
-
}
|
|
1309
|
-
const workerUrl = this.getWorkerUrl();
|
|
1310
|
-
this.workerAvailable = existsSync4(fileURLToPath(workerUrl));
|
|
1311
|
-
if (!this.workerAvailable && !this.warnedWorkerFallback && !isInteractiveMode()) {
|
|
1312
|
-
console.error("Worker threads unavailable; falling back to in-process agents.");
|
|
1313
|
-
this.warnedWorkerFallback = true;
|
|
1314
|
-
}
|
|
1315
|
-
return this.workerAvailable;
|
|
1316
|
-
}
|
|
1317
|
-
getWorkerUrl() {
|
|
1318
|
-
const distDir = new URL(".", import.meta.url);
|
|
1319
|
-
return new URL("workers/agent-worker.js", distDir);
|
|
1320
|
-
}
|
|
1321
|
-
async executeTaskInWorker(task) {
|
|
1322
|
-
const workerUrl = this.getWorkerUrl();
|
|
1323
|
-
return new Promise((resolve2, reject) => {
|
|
1324
|
-
const worker = new Worker(workerUrl, {
|
|
1325
|
-
workerData: {
|
|
1326
|
-
agentName: task.agent.name,
|
|
1327
|
-
files: task.files,
|
|
1328
|
-
context: task.context
|
|
1329
|
-
}
|
|
1330
|
-
});
|
|
1331
|
-
this.activeWorkers.add(worker);
|
|
1332
|
-
const timeout = setTimeout(() => {
|
|
1333
|
-
worker.terminate().catch(() => void 0);
|
|
1334
|
-
reject(new Error(`Agent ${task.agent.name} timed out after ${task.timeoutMs}ms`));
|
|
1335
|
-
}, task.timeoutMs);
|
|
1336
|
-
worker.on("message", (message) => {
|
|
1337
|
-
if (message?.type === "result") {
|
|
1338
|
-
clearTimeout(timeout);
|
|
1339
|
-
resolve2(message.result);
|
|
1340
|
-
} else if (message?.type === "error") {
|
|
1341
|
-
clearTimeout(timeout);
|
|
1342
|
-
reject(new Error(message.error));
|
|
1343
|
-
}
|
|
1344
|
-
});
|
|
1345
|
-
worker.on("error", (error) => {
|
|
1346
|
-
clearTimeout(timeout);
|
|
1347
|
-
reject(error);
|
|
1348
|
-
});
|
|
1349
|
-
worker.on("exit", (code) => {
|
|
1350
|
-
this.activeWorkers.delete(worker);
|
|
1351
|
-
if (code !== 0) {
|
|
1352
|
-
clearTimeout(timeout);
|
|
1353
|
-
reject(new Error(`Worker stopped with exit code ${code}`));
|
|
1354
|
-
}
|
|
1355
|
-
});
|
|
1356
|
-
});
|
|
1357
|
-
}
|
|
1358
|
-
/**
|
|
1359
|
-
* Cache results for future use
|
|
1360
|
-
*/
|
|
1361
|
-
async cacheResults(results) {
|
|
1362
|
-
if (!this.cacheEnabled || !this.cache) {
|
|
1363
|
-
return;
|
|
1364
|
-
}
|
|
1365
|
-
const cachePromises = results.filter((r) => r.result.success && !r.fromCache).map((r) => {
|
|
1366
|
-
const issuesByFile = this.groupIssuesByFile(r.result.issues);
|
|
1367
|
-
const perFilePromises = Object.entries(issuesByFile).map(
|
|
1368
|
-
([file, issues]) => this.cache.setCached(file, r.agent, issues, r.executionTime)
|
|
1369
|
-
);
|
|
1370
|
-
return Promise.all(perFilePromises);
|
|
1371
|
-
});
|
|
1372
|
-
await Promise.allSettled(cachePromises);
|
|
1373
|
-
}
|
|
1374
|
-
/**
|
|
1375
|
-
* Cleanup resources
|
|
1376
|
-
*/
|
|
1377
|
-
async cleanup() {
|
|
1378
|
-
const terminationPromises = Array.from(this.activeWorkers).map(
|
|
1379
|
-
(worker) => worker.terminate()
|
|
1380
|
-
);
|
|
1381
|
-
await Promise.allSettled(terminationPromises);
|
|
1382
|
-
this.activeWorkers.clear();
|
|
1383
|
-
}
|
|
1384
|
-
groupIssuesByFile(issues) {
|
|
1385
|
-
const grouped = {};
|
|
1386
|
-
for (const issue of issues) {
|
|
1387
|
-
if (!grouped[issue.file]) {
|
|
1388
|
-
grouped[issue.file] = [];
|
|
1389
|
-
}
|
|
1390
|
-
grouped[issue.file].push(issue);
|
|
1391
|
-
}
|
|
1392
|
-
return grouped;
|
|
1393
|
-
}
|
|
1394
|
-
};
|
|
1395
|
-
function calculateOptimalConcurrency() {
|
|
1396
|
-
const numCPUs = cpus().length;
|
|
1397
|
-
const availableMemoryGB = process.memoryUsage().rss / 1024 / 1024 / 1024;
|
|
1398
|
-
let optimal = Math.max(2, Math.min(numCPUs - 1, 8));
|
|
1399
|
-
if (availableMemoryGB < 2) {
|
|
1400
|
-
optimal = Math.max(2, Math.floor(optimal / 2));
|
|
1401
|
-
}
|
|
1402
|
-
if (numCPUs > 8) {
|
|
1403
|
-
optimal = Math.min(optimal + 2, 12);
|
|
1404
|
-
}
|
|
1405
|
-
return optimal;
|
|
1406
|
-
}
|
|
1407
|
-
|
|
1408
|
-
// src/orchestrator/executor.ts
|
|
1409
|
-
var Executor = class {
|
|
1410
|
-
async executeAgents(agents, files, context, options) {
|
|
1411
|
-
const parallel = options?.parallel ?? true;
|
|
1412
|
-
const cacheEnabled = options?.cacheEnabled ?? true;
|
|
1413
|
-
const maxConcurrency = options?.maxConcurrency ?? calculateOptimalConcurrency();
|
|
1414
|
-
const useWorkerThreads = options?.useWorkerThreads ?? false;
|
|
1415
|
-
if (!isInteractiveMode()) {
|
|
1416
|
-
console.error(`Executing ${agents.length} scouts ${parallel ? "in parallel" : "sequentially"}...`);
|
|
1417
|
-
}
|
|
1418
|
-
if (parallel) {
|
|
1419
|
-
const cacheManager = cacheEnabled ? new CacheManager(context.workingDir) : null;
|
|
1420
|
-
const executor = new ParallelExecutor(cacheManager, maxConcurrency, {
|
|
1421
|
-
cacheEnabled,
|
|
1422
|
-
useWorkerThreads
|
|
1423
|
-
});
|
|
1424
|
-
if (options?.streaming) {
|
|
1425
|
-
executor.setStreaming(options.streaming);
|
|
1426
|
-
}
|
|
1427
|
-
const results = await executor.executeAgents(agents, files, {
|
|
1428
|
-
...context,
|
|
1429
|
-
config: { timeoutMs: options?.timeoutMs ?? 12e4 }
|
|
1430
|
-
});
|
|
1431
|
-
return agents.map((agent) => results.get(agent.name)).filter(Boolean);
|
|
1432
|
-
}
|
|
1433
|
-
const promises = agents.map(
|
|
1434
|
-
(agent) => this.executeAgentWithTimeout(agent, files, context, options?.timeoutMs ?? 3e4)
|
|
1435
|
-
);
|
|
1436
|
-
try {
|
|
1437
|
-
const results = await Promise.allSettled(promises);
|
|
1438
|
-
return results.map((result, index) => {
|
|
1439
|
-
if (result.status === "fulfilled") {
|
|
1440
|
-
if (!isInteractiveMode()) {
|
|
1441
|
-
console.error(`${agents[index].name} completed in ${result.value.executionTime}ms`);
|
|
1442
|
-
}
|
|
1443
|
-
return result.value;
|
|
1444
|
-
} else {
|
|
1445
|
-
if (!isInteractiveMode()) {
|
|
1446
|
-
console.error(`${agents[index].name} failed:`, result.reason);
|
|
1447
|
-
}
|
|
1448
|
-
return {
|
|
1449
|
-
agent: agents[index].name,
|
|
1450
|
-
issues: [],
|
|
1451
|
-
executionTime: 0,
|
|
1452
|
-
success: false,
|
|
1453
|
-
error: result.reason instanceof Error ? result.reason.message : String(result.reason)
|
|
1454
|
-
};
|
|
1455
|
-
}
|
|
1456
|
-
});
|
|
1457
|
-
} catch (error) {
|
|
1458
|
-
if (!isInteractiveMode()) {
|
|
1459
|
-
console.error("Executor error:", error);
|
|
1460
|
-
}
|
|
1461
|
-
return agents.map((agent) => ({
|
|
1462
|
-
agent: agent.name,
|
|
1463
|
-
issues: [],
|
|
1464
|
-
executionTime: 0,
|
|
1465
|
-
success: false,
|
|
1466
|
-
error: "Execution failed"
|
|
1467
|
-
}));
|
|
1468
|
-
}
|
|
1469
|
-
}
|
|
1470
|
-
async executeAgentWithTimeout(agent, files, context, timeoutMs = 3e4) {
|
|
1471
|
-
return new Promise(async (resolve2, reject) => {
|
|
1472
|
-
const timeout = setTimeout(() => {
|
|
1473
|
-
reject(new Error(`Agent ${agent.name} timed out after ${timeoutMs}ms`));
|
|
1474
|
-
}, timeoutMs);
|
|
1475
|
-
try {
|
|
1476
|
-
const result = await agent.scan(files, context);
|
|
1477
|
-
clearTimeout(timeout);
|
|
1478
|
-
resolve2(result);
|
|
1479
|
-
} catch (error) {
|
|
1480
|
-
clearTimeout(timeout);
|
|
1481
|
-
reject(error);
|
|
1482
|
-
}
|
|
1483
|
-
});
|
|
1484
|
-
}
|
|
1485
|
-
};
|
|
1486
|
-
|
|
1487
|
-
// src/bootstrap/stack-detector.ts
|
|
1488
|
-
import { readFile as readFile2 } from "fs/promises";
|
|
1489
|
-
import { existsSync as existsSync5 } from "fs";
|
|
1490
|
-
import { join as join4 } from "path";
|
|
1491
|
-
var SKILL_MAPPINGS = {
|
|
1492
|
-
// Frontend Frameworks - React/Next.js
|
|
1493
|
-
"next": [
|
|
1494
|
-
"vercel-labs/agent-skills vercel-react-best-practices",
|
|
1495
|
-
"vercel-labs/agent-skills web-design-guidelines",
|
|
1496
|
-
"anthropics/skills frontend-design",
|
|
1497
|
-
"wshobson/agents nextjs-app-router-patterns"
|
|
1498
|
-
],
|
|
1499
|
-
"react": [
|
|
1500
|
-
"vercel-labs/agent-skills vercel-react-best-practices",
|
|
1501
|
-
"anthropics/skills frontend-design",
|
|
1502
|
-
"wshobson/agents react-state-management"
|
|
1503
|
-
],
|
|
1504
|
-
// Vue/Nuxt Ecosystem
|
|
1505
|
-
"vue": [
|
|
1506
|
-
"hyf0/vue-skills vue-best-practices",
|
|
1507
|
-
"hyf0/vue-skills pinia-best-practices",
|
|
1508
|
-
"hyf0/vue-skills vueuse-best-practices",
|
|
1509
|
-
"onmax/nuxt-skills vue"
|
|
1510
|
-
],
|
|
1511
|
-
"nuxt": [
|
|
1512
|
-
"onmax/nuxt-skills nuxt",
|
|
1513
|
-
"onmax/nuxt-skills nuxt-ui",
|
|
1514
|
-
"onmax/nuxt-skills nuxt-content",
|
|
1515
|
-
"onmax/nuxt-skills nuxt-modules",
|
|
1516
|
-
"onmax/nuxt-skills nuxt-better-auth",
|
|
1517
|
-
"onmax/nuxt-skills nuxthub"
|
|
1518
|
-
],
|
|
1519
|
-
"pinia": [
|
|
1520
|
-
"hyf0/vue-skills pinia-best-practices"
|
|
1521
|
-
],
|
|
1522
|
-
"@vueuse/core": [
|
|
1523
|
-
"hyf0/vue-skills vueuse-best-practices",
|
|
1524
|
-
"onmax/nuxt-skills vueuse"
|
|
1525
|
-
],
|
|
1526
|
-
// Mobile - Expo
|
|
1527
|
-
"expo": [
|
|
1528
|
-
"expo/skills building-native-ui",
|
|
1529
|
-
"expo/skills upgrading-expo",
|
|
1530
|
-
"expo/skills native-data-fetching",
|
|
1531
|
-
"expo/skills expo-dev-client",
|
|
1532
|
-
"expo/skills expo-deployment",
|
|
1533
|
-
"expo/skills expo-api-routes",
|
|
1534
|
-
"expo/skills expo-tailwind-setup",
|
|
1535
|
-
"expo/skills expo-cicd-workflows",
|
|
1536
|
-
"expo/skills use-dom"
|
|
1537
|
-
],
|
|
1538
|
-
// Mobile - React Native
|
|
1539
|
-
"react-native": [
|
|
1540
|
-
"callstackincubator/agent-skills react-native-best-practices",
|
|
1541
|
-
"wshobson/agents react-native-architecture"
|
|
1542
|
-
],
|
|
1543
|
-
// Backend Frameworks
|
|
1544
|
-
"@nestjs/core": [
|
|
1545
|
-
"kadajett/agent-nestjs-skills nestjs-best-practices"
|
|
1546
|
-
],
|
|
1547
|
-
"nestjs": [
|
|
1548
|
-
"kadajett/agent-nestjs-skills nestjs-best-practices"
|
|
1549
|
-
],
|
|
1550
|
-
"elysia": [
|
|
1551
|
-
"elysiajs/skills elysiajs"
|
|
1552
|
-
],
|
|
1553
|
-
"hono": [
|
|
1554
|
-
"elysiajs/skills elysiajs"
|
|
1555
|
-
],
|
|
1556
|
-
// Database/BaaS
|
|
1557
|
-
"@supabase/supabase-js": [
|
|
1558
|
-
"supabase/agent-skills supabase-postgres-best-practices"
|
|
1559
|
-
],
|
|
1560
|
-
"convex": [
|
|
1561
|
-
"waynesutton/convexskills convex-best-practices"
|
|
1562
|
-
],
|
|
1563
|
-
"pg": [
|
|
1564
|
-
"wshobson/agents postgresql-table-design"
|
|
1565
|
-
],
|
|
1566
|
-
"postgres": [
|
|
1567
|
-
"wshobson/agents postgresql-table-design"
|
|
1568
|
-
],
|
|
1569
|
-
// Auth
|
|
1570
|
-
"better-auth": [
|
|
1571
|
-
"better-auth/skills better-auth-best-practices",
|
|
1572
|
-
"better-auth/skills create-auth-skill"
|
|
1573
|
-
],
|
|
1574
|
-
// Payments
|
|
1575
|
-
"stripe": [
|
|
1576
|
-
"stripe/ai stripe-best-practices"
|
|
1577
|
-
],
|
|
1578
|
-
"@stripe/stripe-js": [
|
|
1579
|
-
"stripe/ai stripe-best-practices"
|
|
1580
|
-
],
|
|
1581
|
-
// Media/Graphics
|
|
1582
|
-
"remotion": [
|
|
1583
|
-
"remotion-dev/skills remotion-best-practices"
|
|
1584
|
-
],
|
|
1585
|
-
"three": [
|
|
1586
|
-
"cloudai-x/threejs-skills threejs-fundamentals",
|
|
1587
|
-
"cloudai-x/threejs-skills threejs-animation",
|
|
1588
|
-
"cloudai-x/threejs-skills threejs-materials",
|
|
1589
|
-
"cloudai-x/threejs-skills threejs-shaders",
|
|
1590
|
-
"cloudai-x/threejs-skills threejs-lighting",
|
|
1591
|
-
"cloudai-x/threejs-skills threejs-geometry",
|
|
1592
|
-
"cloudai-x/threejs-skills threejs-textures",
|
|
1593
|
-
"cloudai-x/threejs-skills threejs-loaders",
|
|
1594
|
-
"cloudai-x/threejs-skills threejs-interaction",
|
|
1595
|
-
"cloudai-x/threejs-skills threejs-postprocessing"
|
|
1596
|
-
],
|
|
1597
|
-
// UI Libraries
|
|
1598
|
-
"tailwindcss": [
|
|
1599
|
-
"wshobson/agents tailwind-design-system",
|
|
1600
|
-
"jezweb/claude-skills tailwind-v4-shadcn",
|
|
1601
|
-
"wshobson/agents responsive-design"
|
|
1602
|
-
],
|
|
1603
|
-
"@shadcn/ui": [
|
|
1604
|
-
"giuseppe-trisciuoglio/developer-kit shadcn-ui"
|
|
1605
|
-
],
|
|
1606
|
-
"shadcn": [
|
|
1607
|
-
"giuseppe-trisciuoglio/developer-kit shadcn-ui"
|
|
1608
|
-
],
|
|
1609
|
-
"@radix-ui/react-slot": [
|
|
1610
|
-
"onmax/nuxt-skills reka-ui"
|
|
1611
|
-
],
|
|
1612
|
-
// State Management
|
|
1613
|
-
"@tanstack/react-query": [
|
|
1614
|
-
"jezweb/claude-skills tanstack-query"
|
|
1615
|
-
],
|
|
1616
|
-
// Testing
|
|
1617
|
-
"playwright": [
|
|
1618
|
-
"anthropics/skills webapp-testing",
|
|
1619
|
-
"wshobson/agents e2e-testing-patterns"
|
|
1620
|
-
],
|
|
1621
|
-
"puppeteer": [
|
|
1622
|
-
"anthropics/skills webapp-testing"
|
|
1623
|
-
],
|
|
1624
|
-
"vitest": [
|
|
1625
|
-
"wshobson/agents e2e-testing-patterns"
|
|
1626
|
-
],
|
|
1627
|
-
"jest": [
|
|
1628
|
-
"wshobson/agents e2e-testing-patterns"
|
|
1629
|
-
],
|
|
1630
|
-
// DevTools/MCP
|
|
1631
|
-
"@modelcontextprotocol/sdk": [
|
|
1632
|
-
"anthropics/skills mcp-builder"
|
|
1633
|
-
],
|
|
1634
|
-
// Security
|
|
1635
|
-
"semgrep": [
|
|
1636
|
-
"trailofbits/skills semgrep"
|
|
1637
|
-
],
|
|
1638
|
-
// Monorepos
|
|
1639
|
-
"turbo": [
|
|
1640
|
-
"wshobson/agents monorepo-management"
|
|
1641
|
-
],
|
|
1642
|
-
"nx": [
|
|
1643
|
-
"wshobson/agents monorepo-management"
|
|
1644
|
-
],
|
|
1645
|
-
"lerna": [
|
|
1646
|
-
"wshobson/agents monorepo-management"
|
|
1647
|
-
],
|
|
1648
|
-
// TypeScript (handled separately based on tsconfig.json)
|
|
1649
|
-
"typescript": [
|
|
1650
|
-
"wshobson/agents typescript-advanced-types"
|
|
1651
|
-
]
|
|
1652
|
-
};
|
|
1653
|
-
var SKILL_CATEGORIES = {
|
|
1654
|
-
documents: [
|
|
1655
|
-
"anthropics/skills pdf",
|
|
1656
|
-
"anthropics/skills xlsx",
|
|
1657
|
-
"anthropics/skills pptx",
|
|
1658
|
-
"anthropics/skills docx",
|
|
1659
|
-
"anthropics/skills doc-coauthoring"
|
|
1660
|
-
],
|
|
1661
|
-
design: [
|
|
1662
|
-
"anthropics/skills canvas-design",
|
|
1663
|
-
"anthropics/skills theme-factory",
|
|
1664
|
-
"anthropics/skills web-artifacts-builder",
|
|
1665
|
-
"anthropics/skills algorithmic-art",
|
|
1666
|
-
"anthropics/skills brand-guidelines",
|
|
1667
|
-
"anthropics/skills slack-gif-creator",
|
|
1668
|
-
"nextlevelbuilder/ui-ux-pro-max ui-ux-pro-max",
|
|
1669
|
-
"superdesigndev/superdesign-skill superdesign",
|
|
1670
|
-
"wshobson/agents design-system-patterns"
|
|
1671
|
-
],
|
|
1672
|
-
marketing: [
|
|
1673
|
-
"coreyhaines31/marketingskills seo-audit",
|
|
1674
|
-
"coreyhaines31/marketingskills copywriting",
|
|
1675
|
-
"coreyhaines31/marketingskills marketing-psychology",
|
|
1676
|
-
"coreyhaines31/marketingskills programmatic-seo",
|
|
1677
|
-
"coreyhaines31/marketingskills marketing-ideas",
|
|
1678
|
-
"coreyhaines31/marketingskills copy-editing",
|
|
1679
|
-
"coreyhaines31/marketingskills pricing-strategy",
|
|
1680
|
-
"coreyhaines31/marketingskills social-content",
|
|
1681
|
-
"coreyhaines31/marketingskills launch-strategy",
|
|
1682
|
-
"coreyhaines31/marketingskills page-cro",
|
|
1683
|
-
"coreyhaines31/marketingskills competitor-alternatives",
|
|
1684
|
-
"coreyhaines31/marketingskills analytics-tracking",
|
|
1685
|
-
"coreyhaines31/marketingskills schema-markup",
|
|
1686
|
-
"coreyhaines31/marketingskills onboarding-cro",
|
|
1687
|
-
"coreyhaines31/marketingskills email-sequence",
|
|
1688
|
-
"coreyhaines31/marketingskills paid-ads",
|
|
1689
|
-
"coreyhaines31/marketingskills signup-flow-cro",
|
|
1690
|
-
"coreyhaines31/marketingskills free-tool-strategy",
|
|
1691
|
-
"coreyhaines31/marketingskills form-cro",
|
|
1692
|
-
"coreyhaines31/marketingskills paywall-upgrade-cro",
|
|
1693
|
-
"coreyhaines31/marketingskills referral-program",
|
|
1694
|
-
"coreyhaines31/marketingskills popup-cro",
|
|
1695
|
-
"coreyhaines31/marketingskills ab-test-setup"
|
|
1696
|
-
],
|
|
1697
|
-
development: [
|
|
1698
|
-
"obra/superpowers brainstorming",
|
|
1699
|
-
"obra/superpowers test-driven-development",
|
|
1700
|
-
"obra/superpowers systematic-debugging",
|
|
1701
|
-
"obra/superpowers writing-plans",
|
|
1702
|
-
"obra/superpowers executing-plans",
|
|
1703
|
-
"obra/superpowers verification-before-completion",
|
|
1704
|
-
"obra/superpowers using-superpowers",
|
|
1705
|
-
"obra/superpowers subagent-driven-development",
|
|
1706
|
-
"obra/superpowers requesting-code-review",
|
|
1707
|
-
"obra/superpowers writing-skills",
|
|
1708
|
-
"obra/superpowers dispatching-parallel-agents",
|
|
1709
|
-
"obra/superpowers receiving-code-review",
|
|
1710
|
-
"obra/superpowers using-git-worktrees",
|
|
1711
|
-
"obra/superpowers finishing-a-development-branch",
|
|
1712
|
-
"wshobson/agents code-review-excellence",
|
|
1713
|
-
"wshobson/agents api-design-principles",
|
|
1714
|
-
"wshobson/agents architecture-patterns",
|
|
1715
|
-
"wshobson/agents error-handling-patterns",
|
|
1716
|
-
"wshobson/agents nodejs-backend-patterns",
|
|
1717
|
-
"wshobson/agents microservices-patterns",
|
|
1718
|
-
"wshobson/agents modern-javascript-patterns",
|
|
1719
|
-
"wshobson/agents web-component-design",
|
|
1720
|
-
"wshobson/agents async-python-patterns",
|
|
1721
|
-
"wshobson/agents python-testing-patterns",
|
|
1722
|
-
"boristane/agent-skills logging-best-practices"
|
|
1723
|
-
],
|
|
1724
|
-
productivity: [
|
|
1725
|
-
"softaworks/agent-toolkit daily-meeting-update",
|
|
1726
|
-
"softaworks/agent-toolkit agent-md-refactor",
|
|
1727
|
-
"softaworks/agent-toolkit session-handoff",
|
|
1728
|
-
"softaworks/agent-toolkit meme-factory",
|
|
1729
|
-
"softaworks/agent-toolkit qa-test-planner",
|
|
1730
|
-
"softaworks/agent-toolkit writing-clearly-and-concisely",
|
|
1731
|
-
"softaworks/agent-toolkit commit-work",
|
|
1732
|
-
"softaworks/agent-toolkit mermaid-diagrams",
|
|
1733
|
-
"softaworks/agent-toolkit dependency-updater",
|
|
1734
|
-
"softaworks/agent-toolkit crafting-effective-readmes",
|
|
1735
|
-
"softaworks/agent-toolkit reducing-entropy",
|
|
1736
|
-
"softaworks/agent-toolkit feedback-mastery",
|
|
1737
|
-
"softaworks/agent-toolkit marp-slide",
|
|
1738
|
-
"softaworks/agent-toolkit professional-communication",
|
|
1739
|
-
"softaworks/agent-toolkit difficult-workplace-conversations",
|
|
1740
|
-
"anthropics/skills internal-comms",
|
|
1741
|
-
"othmanadi/planning-with-files planning-with-files"
|
|
1742
|
-
],
|
|
1743
|
-
security: [
|
|
1744
|
-
"trailofbits/skills semgrep",
|
|
1745
|
-
"trailofbits/skills secure-workflow-guide",
|
|
1746
|
-
"trailofbits/skills codeql",
|
|
1747
|
-
"trailofbits/skills property-based-testing",
|
|
1748
|
-
"trailofbits/skills variant-analysis",
|
|
1749
|
-
"trailofbits/skills guidelines-advisor",
|
|
1750
|
-
"trailofbits/skills sharp-edges",
|
|
1751
|
-
"trailofbits/skills differential-review",
|
|
1752
|
-
"trailofbits/skills ask-questions-if-underspecified",
|
|
1753
|
-
"squirrelscan/skills audit-website"
|
|
1754
|
-
],
|
|
1755
|
-
mobile: [
|
|
1756
|
-
"wshobson/agents mobile-ios-design",
|
|
1757
|
-
"wshobson/agents mobile-android-design",
|
|
1758
|
-
"dimillian/skills swiftui-ui-patterns",
|
|
1759
|
-
"dimillian/skills swiftui-liquid-glass"
|
|
1760
|
-
],
|
|
1761
|
-
obsidian: [
|
|
1762
|
-
"kepano/obsidian-skills obsidian-markdown",
|
|
1763
|
-
"kepano/obsidian-skills obsidian-bases",
|
|
1764
|
-
"kepano/obsidian-skills json-canvas"
|
|
1765
|
-
],
|
|
1766
|
-
prompts: [
|
|
1767
|
-
"f/awesome-chatgpt-prompts skill-lookup",
|
|
1768
|
-
"f/awesome-chatgpt-prompts prompt-lookup",
|
|
1769
|
-
"wshobson/agents prompt-engineering-patterns"
|
|
1770
|
-
],
|
|
1771
|
-
browser: [
|
|
1772
|
-
"vercel-labs/agent-browser agent-browser"
|
|
1773
|
-
],
|
|
1774
|
-
content: [
|
|
1775
|
-
"op7418/humanizer-zh humanizer-zh",
|
|
1776
|
-
"blader/humanizer humanizer",
|
|
1777
|
-
"op7418/youtube-clipper-skill youtube-clipper",
|
|
1778
|
-
"jimliu/baoyu-skills baoyu-slide-deck",
|
|
1779
|
-
"jimliu/baoyu-skills baoyu-article-illustrator",
|
|
1780
|
-
"jimliu/baoyu-skills baoyu-cover-image",
|
|
1781
|
-
"jimliu/baoyu-skills baoyu-comic",
|
|
1782
|
-
"jimliu/baoyu-skills baoyu-infographic",
|
|
1783
|
-
"jimliu/baoyu-skills baoyu-image-gen"
|
|
1784
|
-
],
|
|
1785
|
-
integrations: [
|
|
1786
|
-
"intellectronica/agent-skills context7",
|
|
1787
|
-
"softaworks/agent-toolkit gemini",
|
|
1788
|
-
"softaworks/agent-toolkit codex"
|
|
1789
|
-
]
|
|
1790
|
-
};
|
|
1791
|
-
async function detectStack(projectDir) {
|
|
1792
|
-
const stack = {
|
|
1793
|
-
suggestedSkills: [],
|
|
1794
|
-
suggestedAgents: ["security", "privacy", "bugs"],
|
|
1795
|
-
dependencies: /* @__PURE__ */ new Set()
|
|
1796
|
-
};
|
|
1797
|
-
if (existsSync5(join4(projectDir, "tsconfig.json"))) {
|
|
1798
|
-
stack.language = "TypeScript";
|
|
1799
|
-
stack.suggestedAgents.push("typecheck");
|
|
1800
|
-
stack.suggestedSkills.push("wshobson/agents typescript-advanced-types");
|
|
1801
|
-
} else if (existsSync5(join4(projectDir, "package.json"))) {
|
|
1802
|
-
stack.language = "JavaScript";
|
|
1803
|
-
} else if (existsSync5(join4(projectDir, "requirements.txt")) || existsSync5(join4(projectDir, "pyproject.toml"))) {
|
|
1804
|
-
stack.language = "Python";
|
|
1805
|
-
} else if (existsSync5(join4(projectDir, "go.mod"))) {
|
|
1806
|
-
stack.language = "Go";
|
|
1807
|
-
} else if (existsSync5(join4(projectDir, "Cargo.toml"))) {
|
|
1808
|
-
stack.language = "Rust";
|
|
1809
|
-
}
|
|
1810
|
-
if (existsSync5(join4(projectDir, "Package.swift")) || existsSync5(join4(projectDir, "project.pbxproj")) || existsSync5(join4(projectDir, "*.xcodeproj"))) {
|
|
1811
|
-
stack.language = "Swift";
|
|
1812
|
-
stack.suggestedSkills.push("dimillian/skills swiftui-ui-patterns");
|
|
1813
|
-
stack.suggestedSkills.push("dimillian/skills swiftui-liquid-glass");
|
|
1814
|
-
}
|
|
1815
|
-
if (existsSync5(join4(projectDir, "pnpm-lock.yaml"))) {
|
|
1816
|
-
stack.packageManager = "pnpm";
|
|
1817
|
-
} else if (existsSync5(join4(projectDir, "yarn.lock"))) {
|
|
1818
|
-
stack.packageManager = "yarn";
|
|
1819
|
-
} else if (existsSync5(join4(projectDir, "bun.lockb"))) {
|
|
1820
|
-
stack.packageManager = "bun";
|
|
1821
|
-
} else if (existsSync5(join4(projectDir, "package-lock.json"))) {
|
|
1822
|
-
stack.packageManager = "npm";
|
|
1823
|
-
}
|
|
1824
|
-
if (existsSync5(join4(projectDir, ".github", "workflows"))) {
|
|
1825
|
-
stack.suggestedSkills.push("wshobson/agents github-actions-templates");
|
|
1826
|
-
}
|
|
1827
|
-
try {
|
|
1828
|
-
const pkgPath = join4(projectDir, "package.json");
|
|
1829
|
-
if (existsSync5(pkgPath)) {
|
|
1830
|
-
const pkgContent = await readFile2(pkgPath, "utf-8");
|
|
1831
|
-
const pkg = JSON.parse(pkgContent);
|
|
1832
|
-
const deps = { ...pkg.dependencies, ...pkg.devDependencies };
|
|
1833
|
-
for (const dep of Object.keys(deps)) {
|
|
1834
|
-
stack.dependencies.add(dep);
|
|
1835
|
-
}
|
|
1836
|
-
for (const dep of Object.keys(deps)) {
|
|
1837
|
-
const skills = SKILL_MAPPINGS[dep];
|
|
1838
|
-
if (skills) {
|
|
1839
|
-
stack.suggestedSkills.push(...skills);
|
|
1840
|
-
}
|
|
1841
|
-
}
|
|
1842
|
-
if (deps["next"]) {
|
|
1843
|
-
stack.framework = `Next.js ${deps["next"].replace("^", "")}`;
|
|
1844
|
-
stack.suggestedAgents.push("accessibility", "design");
|
|
1845
|
-
} else if (deps["react"]) {
|
|
1846
|
-
stack.framework = `React ${deps["react"].replace("^", "")}`;
|
|
1847
|
-
stack.suggestedAgents.push("accessibility");
|
|
1848
|
-
} else if (deps["vue"]) {
|
|
1849
|
-
stack.framework = `Vue ${deps["vue"].replace("^", "")}`;
|
|
1850
|
-
} else if (deps["nuxt"]) {
|
|
1851
|
-
stack.framework = `Nuxt ${deps["nuxt"].replace("^", "")}`;
|
|
1852
|
-
} else if (deps["svelte"]) {
|
|
1853
|
-
stack.framework = "Svelte";
|
|
1854
|
-
} else if (deps["express"]) {
|
|
1855
|
-
stack.framework = "Express.js";
|
|
1856
|
-
} else if (deps["fastify"]) {
|
|
1857
|
-
stack.framework = "Fastify";
|
|
1858
|
-
} else if (deps["hono"]) {
|
|
1859
|
-
stack.framework = "Hono";
|
|
1860
|
-
} else if (deps["elysia"]) {
|
|
1861
|
-
stack.framework = "Elysia";
|
|
1862
|
-
} else if (deps["@nestjs/core"]) {
|
|
1863
|
-
stack.framework = "NestJS";
|
|
1864
|
-
}
|
|
1865
|
-
if (deps["next-auth"] || deps["@auth/core"]) {
|
|
1866
|
-
stack.auth = "NextAuth.js";
|
|
1867
|
-
} else if (deps["passport"]) {
|
|
1868
|
-
stack.auth = "Passport.js";
|
|
1869
|
-
} else if (deps["@clerk/nextjs"] || deps["@clerk/clerk-react"]) {
|
|
1870
|
-
stack.auth = "Clerk";
|
|
1871
|
-
} else if (deps["better-auth"]) {
|
|
1872
|
-
stack.auth = "Better Auth";
|
|
1873
|
-
}
|
|
1874
|
-
if (deps["prisma"] || deps["@prisma/client"]) {
|
|
1875
|
-
stack.database = "Prisma ORM";
|
|
1876
|
-
} else if (deps["drizzle-orm"]) {
|
|
1877
|
-
stack.database = "Drizzle ORM";
|
|
1878
|
-
} else if (deps["@supabase/supabase-js"]) {
|
|
1879
|
-
stack.database = "Supabase";
|
|
1880
|
-
} else if (deps["mongoose"]) {
|
|
1881
|
-
stack.database = "MongoDB (Mongoose)";
|
|
1882
|
-
} else if (deps["pg"]) {
|
|
1883
|
-
stack.database = "PostgreSQL";
|
|
1884
|
-
} else if (deps["convex"]) {
|
|
1885
|
-
stack.database = "Convex";
|
|
1886
|
-
}
|
|
1887
|
-
if (deps["stripe"] || deps["@stripe/stripe-js"]) {
|
|
1888
|
-
stack.suggestedAgents.push("moneybags");
|
|
1889
|
-
}
|
|
1890
|
-
}
|
|
1891
|
-
} catch {
|
|
1892
|
-
}
|
|
1893
|
-
if (!stack.database) {
|
|
1894
|
-
if (existsSync5(join4(projectDir, "prisma", "schema.prisma"))) {
|
|
1895
|
-
stack.database = "Prisma ORM";
|
|
1896
|
-
} else if (existsSync5(join4(projectDir, "drizzle.config.ts"))) {
|
|
1897
|
-
stack.database = "Drizzle ORM";
|
|
1898
|
-
}
|
|
1899
|
-
}
|
|
1900
|
-
stack.suggestedSkills = [...new Set(stack.suggestedSkills)];
|
|
1901
|
-
stack.suggestedAgents = [...new Set(stack.suggestedAgents)];
|
|
1902
|
-
return stack;
|
|
1903
|
-
}
|
|
1904
|
-
function getSkillsByCategory(category) {
|
|
1905
|
-
return SKILL_CATEGORIES[category] || [];
|
|
1906
|
-
}
|
|
1907
|
-
function getSkillCategories() {
|
|
1908
|
-
return Object.entries(SKILL_CATEGORIES).map(([name, skills]) => ({
|
|
1909
|
-
name,
|
|
1910
|
-
count: skills.length
|
|
1911
|
-
}));
|
|
1912
|
-
}
|
|
1913
|
-
|
|
1914
|
-
// src/patterns/saved-patterns.ts
|
|
1915
|
-
import { createHash } from "crypto";
|
|
1916
|
-
import { readFile as readFile3, writeFile as writeFile2 } from "fs/promises";
|
|
1917
|
-
import { existsSync as existsSync6 } from "fs";
|
|
1918
|
-
import { join as join5, basename } from "path";
|
|
1919
|
-
async function loadSavedPatterns(workDir) {
|
|
1920
|
-
const patternsPath = join5(getTrieDirectory(workDir), "saved-patterns.json");
|
|
1921
|
-
try {
|
|
1922
|
-
if (existsSync6(patternsPath)) {
|
|
1923
|
-
const content = await readFile3(patternsPath, "utf-8");
|
|
1924
|
-
return JSON.parse(content);
|
|
1925
|
-
}
|
|
1926
|
-
} catch {
|
|
1927
|
-
}
|
|
1928
|
-
return [];
|
|
1929
|
-
}
|
|
1930
|
-
async function savePatternsToProject(patterns, workDir) {
|
|
1931
|
-
const { mkdir: mkdir2 } = await import("fs/promises");
|
|
1932
|
-
const patternsPath = join5(getTrieDirectory(workDir), "saved-patterns.json");
|
|
1933
|
-
await mkdir2(getTrieDirectory(workDir), { recursive: true });
|
|
1934
|
-
await writeFile2(patternsPath, JSON.stringify(patterns, null, 2));
|
|
1935
|
-
}
|
|
1936
|
-
async function savePatternToProject(pattern, workDir) {
|
|
1937
|
-
const patterns = await loadSavedPatterns(workDir);
|
|
1938
|
-
const existing = patterns.findIndex((p) => p.id === pattern.id);
|
|
1939
|
-
if (existing >= 0) {
|
|
1940
|
-
patterns[existing] = {
|
|
1941
|
-
...patterns[existing],
|
|
1942
|
-
...pattern,
|
|
1943
|
-
occurrences: patterns[existing].occurrences + 1
|
|
1944
|
-
};
|
|
1945
|
-
} else {
|
|
1946
|
-
patterns.push(pattern);
|
|
1947
|
-
}
|
|
1948
|
-
await savePatternsToProject(patterns, workDir);
|
|
1949
|
-
}
|
|
1950
|
-
function detectPatternType(target, workDir) {
|
|
1951
|
-
const scoutNames = [
|
|
1952
|
-
"security",
|
|
1953
|
-
"privacy",
|
|
1954
|
-
"legal",
|
|
1955
|
-
"accessibility",
|
|
1956
|
-
"bug-finding",
|
|
1957
|
-
"architecture",
|
|
1958
|
-
"types",
|
|
1959
|
-
"clean",
|
|
1960
|
-
"devops",
|
|
1961
|
-
"performance",
|
|
1962
|
-
"ux",
|
|
1963
|
-
"design",
|
|
1964
|
-
"production-ready",
|
|
1965
|
-
"agent-smith"
|
|
1966
|
-
];
|
|
1967
|
-
if (scoutNames.includes(target.toLowerCase())) {
|
|
1968
|
-
return "detection-rule";
|
|
1969
|
-
}
|
|
1970
|
-
const fullPath = join5(workDir, target);
|
|
1971
|
-
if (existsSync6(fullPath) || target.includes("/") || target.includes("*") || target.endsWith(".ts") || target.endsWith(".js")) {
|
|
1972
|
-
return "file-structure";
|
|
1973
|
-
}
|
|
1974
|
-
return "code-pattern";
|
|
1975
|
-
}
|
|
1976
|
-
function generatePatternId(target, type) {
|
|
1977
|
-
const hash = createHash("sha256").update(`${type}:${target}`).digest("hex").slice(0, 12);
|
|
1978
|
-
return `${type}-${hash}`;
|
|
1979
|
-
}
|
|
1980
|
-
function getDetectionRuleAgents(patterns) {
|
|
1981
|
-
return patterns.filter((p) => p.type === "detection-rule").map((p) => p.detectionRule?.agent || p.name).filter(Boolean);
|
|
1982
|
-
}
|
|
1983
|
-
async function createSavedPattern(target, note, workDir) {
|
|
1984
|
-
const projectName = basename(workDir);
|
|
1985
|
-
const patternType = detectPatternType(target, workDir);
|
|
1986
|
-
const savedPattern = {
|
|
1987
|
-
id: generatePatternId(target, patternType),
|
|
1988
|
-
type: patternType,
|
|
1989
|
-
name: target,
|
|
1990
|
-
description: note || `Pattern saved from ${projectName}`,
|
|
1991
|
-
validated: false,
|
|
1992
|
-
projects: [projectName],
|
|
1993
|
-
occurrences: 1,
|
|
1994
|
-
savedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
1995
|
-
savedBy: projectName
|
|
1996
|
-
};
|
|
1997
|
-
if (patternType === "file-structure") {
|
|
1998
|
-
savedPattern.filePatterns = [target];
|
|
1999
|
-
savedPattern.architecture = {
|
|
2000
|
-
structure: `Files matching ${target}`,
|
|
2001
|
-
rationale: note || "File structure pattern that worked well"
|
|
2002
|
-
};
|
|
2003
|
-
} else if (patternType === "code-pattern") {
|
|
2004
|
-
const issues = await searchIssues(target, { limit: 5 });
|
|
2005
|
-
if (issues.length > 0) {
|
|
2006
|
-
const latestIssue = issues[0];
|
|
2007
|
-
savedPattern.codePattern = {
|
|
2008
|
-
pattern: latestIssue?.issue.issue || target,
|
|
2009
|
-
fix: latestIssue?.issue.fix || "Review and apply similar fix",
|
|
2010
|
-
context: note || "Code pattern that worked well"
|
|
2011
|
-
};
|
|
2012
|
-
} else {
|
|
2013
|
-
savedPattern.codePattern = {
|
|
2014
|
-
pattern: target,
|
|
2015
|
-
fix: "Review and apply similar fix",
|
|
2016
|
-
context: note || "Code pattern that worked well"
|
|
2017
|
-
};
|
|
2018
|
-
}
|
|
2019
|
-
} else if (patternType === "detection-rule") {
|
|
2020
|
-
savedPattern.detectionRule = {
|
|
2021
|
-
agent: target,
|
|
2022
|
-
rule: `Detection rules from ${target} scout`,
|
|
2023
|
-
severity: "moderate"
|
|
2024
|
-
};
|
|
2025
|
-
}
|
|
2026
|
-
return savedPattern;
|
|
2027
|
-
}
|
|
2028
|
-
async function buildSavedPatternIssues(patterns, files, readFileContent) {
|
|
2029
|
-
const issues = [];
|
|
2030
|
-
for (const pattern of patterns) {
|
|
2031
|
-
if (pattern.type === "detection-rule") continue;
|
|
2032
|
-
const targetFiles = filterFilesForPattern(files, pattern);
|
|
2033
|
-
if (targetFiles.length === 0) continue;
|
|
2034
|
-
if (pattern.type === "file-structure") {
|
|
2035
|
-
for (const file of targetFiles) {
|
|
2036
|
-
issues.push(createPatternIssue(pattern, file, void 0));
|
|
2037
|
-
}
|
|
2038
|
-
continue;
|
|
2039
|
-
}
|
|
2040
|
-
if (pattern.type === "code-pattern" && pattern.codePattern) {
|
|
2041
|
-
for (const file of targetFiles) {
|
|
2042
|
-
const content = await readFileContent(file);
|
|
2043
|
-
const match = findPatternMatch(content, pattern.codePattern.pattern);
|
|
2044
|
-
if (match) {
|
|
2045
|
-
issues.push(createPatternIssue(pattern, file, match.line));
|
|
2046
|
-
}
|
|
2047
|
-
}
|
|
2048
|
-
}
|
|
2049
|
-
}
|
|
2050
|
-
return issues;
|
|
2051
|
-
}
|
|
2052
|
-
function filterFilesForPattern(files, pattern) {
|
|
2053
|
-
if (pattern.type === "file-structure" && pattern.filePatterns) {
|
|
2054
|
-
return files.filter((file) => pattern.filePatterns.some((p) => matchesFilePattern(file, p)));
|
|
2055
|
-
}
|
|
2056
|
-
if (pattern.type === "code-pattern") {
|
|
2057
|
-
return files;
|
|
2058
|
-
}
|
|
2059
|
-
return [];
|
|
2060
|
-
}
|
|
2061
|
-
function matchesFilePattern(filePath, pattern) {
|
|
2062
|
-
const normalized = filePath.replace(/\\/g, "/");
|
|
2063
|
-
const escaped = pattern.replace(/[.+^${}()|[\]\\]/g, "\\$&").replace(/\*\*/g, "___DOUBLESTAR___").replace(/\*/g, "[^/]*").replace(/___DOUBLESTAR___/g, ".*");
|
|
2064
|
-
const regex = new RegExp(`^${escaped}$`, "i");
|
|
2065
|
-
return regex.test(normalized) || normalized.includes(pattern.replace(/\*+/g, ""));
|
|
2066
|
-
}
|
|
2067
|
-
function findPatternMatch(content, pattern) {
|
|
2068
|
-
try {
|
|
2069
|
-
const regex = new RegExp(pattern, "i");
|
|
2070
|
-
const match = regex.exec(content);
|
|
2071
|
-
if (!match || match.index === void 0) return null;
|
|
2072
|
-
const line = getLineNumber(content, match.index);
|
|
2073
|
-
return { line };
|
|
2074
|
-
} catch {
|
|
2075
|
-
const index = content.toLowerCase().indexOf(pattern.toLowerCase());
|
|
2076
|
-
if (index === -1) return null;
|
|
2077
|
-
const line = getLineNumber(content, index);
|
|
2078
|
-
return { line };
|
|
2079
|
-
}
|
|
2080
|
-
}
|
|
2081
|
-
function getLineNumber(content, index) {
|
|
2082
|
-
return content.slice(0, index).split("\n").length;
|
|
2083
|
-
}
|
|
2084
|
-
function createPatternIssue(pattern, file, line) {
|
|
2085
|
-
const description = pattern.description || `Saved pattern: ${pattern.name}`;
|
|
2086
|
-
const fix = pattern.codePattern?.fix || "Apply the saved pattern from your other project.";
|
|
2087
|
-
const issue = {
|
|
2088
|
-
id: `saved-${pattern.id}-${hashFile(file)}`,
|
|
2089
|
-
severity: "low",
|
|
2090
|
-
issue: `Saved pattern suggestion: ${description}`,
|
|
2091
|
-
fix,
|
|
2092
|
-
file,
|
|
2093
|
-
confidence: 0.6,
|
|
2094
|
-
autoFixable: false,
|
|
2095
|
-
agent: "saved-patterns",
|
|
2096
|
-
category: "pattern-sharing"
|
|
2097
|
-
};
|
|
2098
|
-
if (line !== void 0) {
|
|
2099
|
-
issue.line = line;
|
|
2100
|
-
}
|
|
2101
|
-
return issue;
|
|
2102
|
-
}
|
|
2103
|
-
function hashFile(file) {
|
|
2104
|
-
return createHash("sha256").update(file).digest("hex").slice(0, 8);
|
|
2105
|
-
}
|
|
2106
|
-
|
|
2107
|
-
export {
|
|
2108
|
-
loadConfig,
|
|
2109
|
-
saveConfig,
|
|
2110
|
-
Triager,
|
|
2111
|
-
Executor,
|
|
2112
|
-
isTrieInitialized,
|
|
2113
|
-
SKILL_CATEGORIES,
|
|
2114
|
-
detectStack,
|
|
2115
|
-
getSkillsByCategory,
|
|
2116
|
-
getSkillCategories,
|
|
2117
|
-
loadSavedPatterns,
|
|
2118
|
-
savePatternsToProject,
|
|
2119
|
-
savePatternToProject,
|
|
2120
|
-
getDetectionRuleAgents,
|
|
2121
|
-
createSavedPattern,
|
|
2122
|
-
buildSavedPatternIssues
|
|
2123
|
-
};
|
|
2124
|
-
//# sourceMappingURL=chunk-CUXXRM3T.js.map
|