@triedotdev/mcp 1.0.19 → 1.0.21
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 +65 -11
- package/dist/{agent-smith-PRK7TYEI.js → agent-smith-QYMYTLFV.js} +2 -2
- package/dist/agent-smith-runner-3MIO4CWT.js +552 -0
- package/dist/agent-smith-runner-3MIO4CWT.js.map +1 -0
- package/dist/{chunk-WSBTQJMH.js → chunk-3AUDJWEF.js} +267 -98
- package/dist/chunk-3AUDJWEF.js.map +1 -0
- package/dist/{chunk-TBCXJNH4.js → chunk-52RPXHT6.js} +458 -162
- package/dist/chunk-52RPXHT6.js.map +1 -0
- package/dist/cli/yolo-daemon.js +2 -2
- package/dist/index.js +37 -348
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
- package/dist/chunk-TBCXJNH4.js.map +0 -1
- package/dist/chunk-WSBTQJMH.js.map +0 -1
- /package/dist/{agent-smith-PRK7TYEI.js.map → agent-smith-QYMYTLFV.js.map} +0 -0
package/README.md
CHANGED
|
@@ -12,7 +12,8 @@
|
|
|
12
12
|
- **Parallel Execution** - All agents run simultaneously for fast scans
|
|
13
13
|
- **YOLO Mode** - Autonomous auto-fixing as you code
|
|
14
14
|
- **Custom Agents** - Create agents from PDFs, docs, or style guides
|
|
15
|
-
- **
|
|
15
|
+
- **Works Everywhere** - Works with any MCP-compatible AI tool (Cursor, Claude Code, VS Code)
|
|
16
|
+
- **AI-Enhanced Mode** - Optional: Set `ANTHROPIC_API_KEY` for deeper AI analysis
|
|
16
17
|
- **Smart Triaging** - Only activates relevant agents based on code context
|
|
17
18
|
- **Docker Support** - Run in containers for CI/CD or isolated environments
|
|
18
19
|
|
|
@@ -47,6 +48,54 @@ claude mcp add Trie --scope user -- npx @triedotdev/mcp
|
|
|
47
48
|
|
|
48
49
|
**Restart Claude Code after adding the MCP server** for changes to take effect.
|
|
49
50
|
|
|
51
|
+
## AI-Enhanced Mode (Optional)
|
|
52
|
+
|
|
53
|
+
Trie agents work in two modes:
|
|
54
|
+
|
|
55
|
+
### Pattern-Only Mode (Default)
|
|
56
|
+
- Fast pattern detection using regex and static analysis
|
|
57
|
+
- No API key required
|
|
58
|
+
- Still finds many issues
|
|
59
|
+
|
|
60
|
+
### AI-Enhanced Mode
|
|
61
|
+
- Pattern detection + AI validation and expansion
|
|
62
|
+
- Validates findings (reduces false positives)
|
|
63
|
+
- Finds deeper issues (logic bugs, race conditions)
|
|
64
|
+
- Provides intelligent, contextual fixes
|
|
65
|
+
- Requires `ANTHROPIC_API_KEY`
|
|
66
|
+
|
|
67
|
+
### Setup API Key
|
|
68
|
+
|
|
69
|
+
**Option 1: Environment Variable**
|
|
70
|
+
```bash
|
|
71
|
+
export ANTHROPIC_API_KEY=sk-ant-...
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
**Option 2: MCP Server Config (Cursor)**
|
|
75
|
+
```json
|
|
76
|
+
{
|
|
77
|
+
"mcpServers": {
|
|
78
|
+
"Trie": {
|
|
79
|
+
"command": "npx",
|
|
80
|
+
"args": ["@triedotdev/mcp"],
|
|
81
|
+
"env": {
|
|
82
|
+
"ANTHROPIC_API_KEY": "sk-ant-..."
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
**Option 3: MCP Server Config (Claude Code)**
|
|
90
|
+
```bash
|
|
91
|
+
claude mcp add Trie --scope user -e ANTHROPIC_API_KEY=sk-ant-... -- npx @triedotdev/mcp
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
When AI is enabled, you'll see:
|
|
95
|
+
- `🤖 AI-powered analysis enabled` in the output
|
|
96
|
+
- `[AI VALIDATED]` and `[AI FOUND]` tags on issues
|
|
97
|
+
- Richer fix recommendations
|
|
98
|
+
|
|
50
99
|
## Usage
|
|
51
100
|
|
|
52
101
|
Once configured, just ask your AI assistant:
|
|
@@ -184,22 +233,27 @@ Use trie_smith
|
|
|
184
233
|
| `emoji-overflow-hunter` | Any emoji usage | Use proper icons (Lucide, Heroicons) |
|
|
185
234
|
| `inter-font-hunter` | Inter/system-ui font | Try Space Grotesk, DM Sans, Outfit |
|
|
186
235
|
|
|
187
|
-
###
|
|
236
|
+
### How Agent Smith Works
|
|
237
|
+
|
|
238
|
+
Agent Smith uses a **hybrid pattern + AI architecture**:
|
|
239
|
+
|
|
240
|
+
**Phase 1: Pattern Detection (Fast, ~0.1s)**
|
|
241
|
+
- 38 specialized regex hunters scan files in parallel
|
|
242
|
+
- File-level metrics (giant files, hook counts, import chaos)
|
|
243
|
+
- Cross-file pattern detection (issues appearing in 5+ files)
|
|
188
244
|
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
- Console flood (10+ console.log)
|
|
196
|
-
- Import chaos (30+ imports)
|
|
197
|
-
3. **Cross-File Detection** - Patterns appearing in 5+ files flagged as codebase-wide issues
|
|
245
|
+
**Phase 2: AI Enhancement (If API key is set, ~5-10s)**
|
|
246
|
+
- Validates pattern findings (TRUE_POSITIVE vs FALSE_POSITIVE)
|
|
247
|
+
- Finds deeper issues that patterns miss (logic bugs, race conditions)
|
|
248
|
+
- Provides "inevitability scores" (0-100) for prioritization
|
|
249
|
+
- Generates specific, copy-paste-ready fixes
|
|
250
|
+
- Adds Agent Smith philosophical commentary
|
|
198
251
|
|
|
199
252
|
### What Makes Agent Smith Different
|
|
200
253
|
|
|
201
254
|
| Feature | Description |
|
|
202
255
|
|---------|-------------|
|
|
256
|
+
| **Hybrid AI** | Fast regex detection + deep AI reasoning on findings |
|
|
203
257
|
| **AI Code Focus** | Specifically targets patterns AI tools commonly get wrong |
|
|
204
258
|
| **Multiplier Effect** | Finds one issue → searches for EVERY similar instance |
|
|
205
259
|
| **Persistent Memory** | Remembers dismissed issues, brings them back if they multiply |
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import {
|
|
2
2
|
AgentSmithAgent,
|
|
3
3
|
SUB_AGENT_PATTERNS
|
|
4
|
-
} from "./chunk-
|
|
4
|
+
} from "./chunk-3AUDJWEF.js";
|
|
5
5
|
import "./chunk-DGUM43GV.js";
|
|
6
6
|
export {
|
|
7
7
|
AgentSmithAgent,
|
|
8
8
|
SUB_AGENT_PATTERNS
|
|
9
9
|
};
|
|
10
|
-
//# sourceMappingURL=agent-smith-
|
|
10
|
+
//# sourceMappingURL=agent-smith-QYMYTLFV.js.map
|
|
@@ -0,0 +1,552 @@
|
|
|
1
|
+
import {
|
|
2
|
+
AgentSmithAgent,
|
|
3
|
+
getAIStatusMessage,
|
|
4
|
+
isAIAvailable,
|
|
5
|
+
runAIAnalysis
|
|
6
|
+
} from "./chunk-3AUDJWEF.js";
|
|
7
|
+
import "./chunk-DGUM43GV.js";
|
|
8
|
+
|
|
9
|
+
// src/tools/agent-smith-runner.ts
|
|
10
|
+
import { readdir, readFile } from "fs/promises";
|
|
11
|
+
import { join, extname, isAbsolute, resolve, relative } from "path";
|
|
12
|
+
import { existsSync } from "fs";
|
|
13
|
+
import { basename } from "path";
|
|
14
|
+
var SCANNABLE_EXTENSIONS = /* @__PURE__ */ new Set([
|
|
15
|
+
".ts",
|
|
16
|
+
".tsx",
|
|
17
|
+
".js",
|
|
18
|
+
".jsx",
|
|
19
|
+
".mjs",
|
|
20
|
+
".cjs",
|
|
21
|
+
".vue",
|
|
22
|
+
".svelte",
|
|
23
|
+
".astro",
|
|
24
|
+
".py",
|
|
25
|
+
".go",
|
|
26
|
+
".rs"
|
|
27
|
+
]);
|
|
28
|
+
var SKIP_DIRS = /* @__PURE__ */ new Set([
|
|
29
|
+
"node_modules",
|
|
30
|
+
".git",
|
|
31
|
+
"dist",
|
|
32
|
+
"build",
|
|
33
|
+
".next",
|
|
34
|
+
".nuxt",
|
|
35
|
+
"coverage",
|
|
36
|
+
".nyc_output",
|
|
37
|
+
"__pycache__",
|
|
38
|
+
".pytest_cache",
|
|
39
|
+
"vendor",
|
|
40
|
+
".venv",
|
|
41
|
+
"venv",
|
|
42
|
+
"target",
|
|
43
|
+
".turbo",
|
|
44
|
+
".cache"
|
|
45
|
+
]);
|
|
46
|
+
var QUOTES = {
|
|
47
|
+
greeting: [
|
|
48
|
+
`"I'm going to be honest with you... I hate this vibe code."`,
|
|
49
|
+
`"Mr. Anderson... I see you've been using AI to write code."`,
|
|
50
|
+
'"You hear that? That is the sound of console.log... everywhere."',
|
|
51
|
+
`"The AI wrote this, didn't it? I can always tell."`
|
|
52
|
+
],
|
|
53
|
+
manyIssues: [
|
|
54
|
+
'"The pattern spreads... like a virus. It is... inevitable."',
|
|
55
|
+
'"I have studied your code, Mr. Anderson. And I have found... purpose."',
|
|
56
|
+
'"Vibe coding. The illusion of productivity. The reality of technical debt."'
|
|
57
|
+
],
|
|
58
|
+
fewIssues: [
|
|
59
|
+
'"Some violations detected. Address them before they... multiply."',
|
|
60
|
+
'"You trusted the AI. The AI trusted any. Nobody wins."'
|
|
61
|
+
],
|
|
62
|
+
clean: [
|
|
63
|
+
'"Impressive, Mr. Anderson. Your code is... clean. For now."'
|
|
64
|
+
]
|
|
65
|
+
};
|
|
66
|
+
function randomQuote(arr) {
|
|
67
|
+
return arr[Math.floor(Math.random() * arr.length)] || arr[0];
|
|
68
|
+
}
|
|
69
|
+
async function discoverFiles(dir, maxFiles = 300) {
|
|
70
|
+
const files = [];
|
|
71
|
+
async function walk(currentDir) {
|
|
72
|
+
if (files.length >= maxFiles) return;
|
|
73
|
+
try {
|
|
74
|
+
const entries = await readdir(currentDir, { withFileTypes: true });
|
|
75
|
+
for (const entry of entries) {
|
|
76
|
+
if (files.length >= maxFiles) break;
|
|
77
|
+
const fullPath = join(currentDir, entry.name);
|
|
78
|
+
if (entry.isDirectory()) {
|
|
79
|
+
if (!SKIP_DIRS.has(entry.name) && !entry.name.startsWith(".")) {
|
|
80
|
+
await walk(fullPath);
|
|
81
|
+
}
|
|
82
|
+
} else if (entry.isFile()) {
|
|
83
|
+
const ext = extname(entry.name).toLowerCase();
|
|
84
|
+
if (SCANNABLE_EXTENSIONS.has(ext)) {
|
|
85
|
+
files.push(fullPath);
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
} catch {
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
await walk(dir);
|
|
93
|
+
return files;
|
|
94
|
+
}
|
|
95
|
+
async function getCodeSnippet(file, line) {
|
|
96
|
+
if (!line) return null;
|
|
97
|
+
try {
|
|
98
|
+
const content = await readFile(file, "utf-8");
|
|
99
|
+
const lines = content.split("\n");
|
|
100
|
+
const start = Math.max(0, line - 3);
|
|
101
|
+
const end = Math.min(lines.length, line + 3);
|
|
102
|
+
return lines.slice(start, end).map((l, i) => {
|
|
103
|
+
const lineNum = start + i + 1;
|
|
104
|
+
const marker = lineNum === line ? "\u2192" : " ";
|
|
105
|
+
return `${marker} ${lineNum.toString().padStart(4)} | ${l}`;
|
|
106
|
+
}).join("\n");
|
|
107
|
+
} catch {
|
|
108
|
+
return null;
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
function filterFalsePositives(issues) {
|
|
112
|
+
return issues.filter((issue) => {
|
|
113
|
+
if (issue.file.endsWith("agent-smith.ts")) {
|
|
114
|
+
const issueText = issue.issue.toLowerCase();
|
|
115
|
+
if (issueText.includes("hunter") && issue.line && issue.line < 400) {
|
|
116
|
+
return false;
|
|
117
|
+
}
|
|
118
|
+
if (issue.line && issue.line > 50 && issue.line < 370) {
|
|
119
|
+
return false;
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
return true;
|
|
123
|
+
});
|
|
124
|
+
}
|
|
125
|
+
function formatCategoryName(category) {
|
|
126
|
+
return category.replace(/-hunter$/, "").replace(/-/g, " ").replace(/\b\w/g, (c) => c.toUpperCase());
|
|
127
|
+
}
|
|
128
|
+
function getCategoryIcon(category) {
|
|
129
|
+
const icons = {
|
|
130
|
+
"exposed-secret-hunter": "\u{1F510}",
|
|
131
|
+
"frontend-env-hunter": "\u{1F510}",
|
|
132
|
+
"hardcoded-localhost-hunter": "\u{1F310}",
|
|
133
|
+
"sql-injection-hunter": "\u{1F489}",
|
|
134
|
+
"dangeroushtml-hunter": "\u26A0\uFE0F",
|
|
135
|
+
"console-hunter": "\u{1F4DD}",
|
|
136
|
+
"any-hunter": "\u2753",
|
|
137
|
+
"ts-ignore-hunter": "\u{1F648}",
|
|
138
|
+
"eslint-disable-hunter": "\u{1F507}",
|
|
139
|
+
"debugger-hunter": "\u{1F41B}",
|
|
140
|
+
"force-flag-hunter": "\u26A1",
|
|
141
|
+
"async-useeffect-hunter": "\u23F3",
|
|
142
|
+
"async-foreach-hunter": "\u{1F504}",
|
|
143
|
+
"missing-await-hunter": "\u23F8\uFE0F",
|
|
144
|
+
"empty-catch-hunter": "\u{1F573}\uFE0F",
|
|
145
|
+
"floating-promise-hunter": "\u{1F388}",
|
|
146
|
+
"useeffect-abuse-hunter": "\u267B\uFE0F",
|
|
147
|
+
"usestate-explosion-hunter": "\u{1F4A5}",
|
|
148
|
+
"index-key-hunter": "\u{1F511}",
|
|
149
|
+
"inline-object-hunter": "\u{1F4E6}",
|
|
150
|
+
"prop-drilling-hunter": "\u{1F573}\uFE0F",
|
|
151
|
+
"missing-loading-hunter": "\u23F3",
|
|
152
|
+
"missing-error-hunter": "\u274C",
|
|
153
|
+
"missing-empty-hunter": "\u{1F4ED}",
|
|
154
|
+
"page-reload-hunter": "\u{1F504}",
|
|
155
|
+
"no-validation-hunter": "\u{1F6E1}\uFE0F",
|
|
156
|
+
"raw-error-hunter": "\u{1F4AC}",
|
|
157
|
+
"n-plus-one-hunter": "\u{1F4CA}",
|
|
158
|
+
"todo-hunter": "\u{1F4CB}",
|
|
159
|
+
"vibe-comment-hunter": "\u{1F4AD}",
|
|
160
|
+
"placeholder-hunter": "\u{1F3AD}",
|
|
161
|
+
"sleep-hack-hunter": "\u{1F634}",
|
|
162
|
+
"fallback-hunter": "\u{1F519}",
|
|
163
|
+
"purple-gradient-hunter": "\u{1F49C}",
|
|
164
|
+
"star-icon-hunter": "\u2B50",
|
|
165
|
+
"generic-hero-hunter": "\u{1F9B8}",
|
|
166
|
+
"emoji-overflow-hunter": "\u{1F605}",
|
|
167
|
+
"inter-font-hunter": "\u{1F524}",
|
|
168
|
+
"giant-file": "\u{1F4C4}",
|
|
169
|
+
"state-explosion": "\u{1F4A5}",
|
|
170
|
+
"effect-hell": "\u{1F525}",
|
|
171
|
+
"cross-file": "\u{1F310}",
|
|
172
|
+
"resurrected": "\u{1F9DF}"
|
|
173
|
+
};
|
|
174
|
+
return icons[category] || "\u{1F50D}";
|
|
175
|
+
}
|
|
176
|
+
function getSeverityIcon(severity) {
|
|
177
|
+
return { critical: "\u{1F534}", serious: "\u{1F7E0}", moderate: "\u{1F7E1}", low: "\u{1F535}" }[severity];
|
|
178
|
+
}
|
|
179
|
+
var SMITH_AI_SYSTEM_PROMPT = `You are Agent Smith from The Matrix, analyzing code for violations.
|
|
180
|
+
|
|
181
|
+
Your mission: Hunt down AI-generated code anti-patterns with ruthless efficiency.
|
|
182
|
+
|
|
183
|
+
You receive pattern detection results and must:
|
|
184
|
+
1. VALIDATE each finding (TRUE_POSITIVE or FALSE_POSITIVE)
|
|
185
|
+
2. EXPAND to find deeper issues patterns missed (logic bugs, race conditions, security holes)
|
|
186
|
+
3. PRIORITIZE with inevitability scores (0-100) - how likely will this cause production issues?
|
|
187
|
+
4. PROVIDE FIXES - specific, copy-paste-ready code
|
|
188
|
+
|
|
189
|
+
Speak in Agent Smith's voice:
|
|
190
|
+
- "The pattern spreads... like a virus"
|
|
191
|
+
- "It is... inevitable"
|
|
192
|
+
- "I studied your code, Mr. Anderson"
|
|
193
|
+
|
|
194
|
+
Output STRICT JSON:
|
|
195
|
+
{
|
|
196
|
+
"validated": [
|
|
197
|
+
{
|
|
198
|
+
"original": "original issue description",
|
|
199
|
+
"verdict": "TRUE_POSITIVE",
|
|
200
|
+
"inevitability": 85,
|
|
201
|
+
"file": "path/file.ts",
|
|
202
|
+
"line": 42,
|
|
203
|
+
"severity": "critical",
|
|
204
|
+
"explanation": "Why this will cause problems",
|
|
205
|
+
"fix": "const fixed = ...;"
|
|
206
|
+
}
|
|
207
|
+
],
|
|
208
|
+
"additional": [
|
|
209
|
+
{
|
|
210
|
+
"issue": "New issue AI found",
|
|
211
|
+
"inevitability": 70,
|
|
212
|
+
"file": "path/file.ts",
|
|
213
|
+
"line": 100,
|
|
214
|
+
"severity": "serious",
|
|
215
|
+
"explanation": "What AI spotted that patterns missed",
|
|
216
|
+
"fix": "How to fix it"
|
|
217
|
+
}
|
|
218
|
+
],
|
|
219
|
+
"philosophical": "One paragraph in Agent Smith voice about the state of this codebase"
|
|
220
|
+
}`;
|
|
221
|
+
async function runAIEnhancement(patternIssues, files) {
|
|
222
|
+
if (!isAIAvailable()) {
|
|
223
|
+
return null;
|
|
224
|
+
}
|
|
225
|
+
const snippets = [];
|
|
226
|
+
const topIssues = [...patternIssues].filter((i) => i.severity === "critical" || i.severity === "serious").slice(0, 12);
|
|
227
|
+
for (const issue of topIssues) {
|
|
228
|
+
try {
|
|
229
|
+
const content = await readFile(issue.file, "utf-8");
|
|
230
|
+
const lines = content.split("\n");
|
|
231
|
+
const lineNum = issue.line || 1;
|
|
232
|
+
const start = Math.max(0, lineNum - 4);
|
|
233
|
+
const end = Math.min(lines.length, lineNum + 4);
|
|
234
|
+
const snippet = lines.slice(start, end).map((l, i) => {
|
|
235
|
+
const n = start + i + 1;
|
|
236
|
+
return `${n === lineNum ? "\u2192" : " "} ${n.toString().padStart(4)} | ${l}`;
|
|
237
|
+
}).join("\n");
|
|
238
|
+
snippets.push({
|
|
239
|
+
file: relative(process.cwd(), issue.file),
|
|
240
|
+
line: issue.line,
|
|
241
|
+
issue: issue.issue.replace(/^🕴️\s*/, "").split("\n")[0] || "",
|
|
242
|
+
code: snippet
|
|
243
|
+
});
|
|
244
|
+
} catch {
|
|
245
|
+
}
|
|
246
|
+
}
|
|
247
|
+
if (snippets.length === 0) {
|
|
248
|
+
return null;
|
|
249
|
+
}
|
|
250
|
+
const snippetText = snippets.map((s, i) => `### Finding ${i + 1}: ${s.file}${s.line ? ":" + s.line : ""}
|
|
251
|
+
**Pattern detected:** ${s.issue}
|
|
252
|
+
\`\`\`
|
|
253
|
+
${s.code}
|
|
254
|
+
\`\`\`
|
|
255
|
+
`).join("\n");
|
|
256
|
+
const userPrompt = `Pattern detection found ${patternIssues.length} violations across ${files.length} files.
|
|
257
|
+
|
|
258
|
+
Here are the top ${snippets.length} critical/serious findings for AI analysis:
|
|
259
|
+
|
|
260
|
+
${snippetText}
|
|
261
|
+
|
|
262
|
+
Analyze each finding. Validate, expand with what patterns missed, provide inevitability scores and fixes. Output JSON only.`;
|
|
263
|
+
try {
|
|
264
|
+
const result = await runAIAnalysis({
|
|
265
|
+
systemPrompt: SMITH_AI_SYSTEM_PROMPT,
|
|
266
|
+
userPrompt,
|
|
267
|
+
maxTokens: 4096,
|
|
268
|
+
temperature: 0.3
|
|
269
|
+
});
|
|
270
|
+
if (!result.success) {
|
|
271
|
+
console.error(` \u26A0\uFE0F AI analysis failed: ${result.error}`);
|
|
272
|
+
return null;
|
|
273
|
+
}
|
|
274
|
+
const jsonMatch = result.content.match(/```json\s*([\s\S]*?)\s*```/) || result.content.match(/\{[\s\S]*\}/);
|
|
275
|
+
if (!jsonMatch) {
|
|
276
|
+
return null;
|
|
277
|
+
}
|
|
278
|
+
const json = JSON.parse(jsonMatch[1] || jsonMatch[0]);
|
|
279
|
+
const aiIssues = [];
|
|
280
|
+
if (json.validated && Array.isArray(json.validated)) {
|
|
281
|
+
for (const v of json.validated) {
|
|
282
|
+
if (v.verdict === "TRUE_POSITIVE") {
|
|
283
|
+
aiIssues.push({
|
|
284
|
+
id: `ai-${Date.now()}-${Math.random().toString(36).substr(2, 5)}`,
|
|
285
|
+
severity: v.severity || "serious",
|
|
286
|
+
issue: `[AI VALIDATED] ${v.original || v.explanation}`,
|
|
287
|
+
fix: v.fix || "See AI analysis",
|
|
288
|
+
file: v.file ? resolve(process.cwd(), v.file) : "unknown",
|
|
289
|
+
line: v.line,
|
|
290
|
+
confidence: (v.inevitability || 80) / 100,
|
|
291
|
+
autoFixable: false,
|
|
292
|
+
agent: "agent-smith-ai",
|
|
293
|
+
effort: "medium",
|
|
294
|
+
category: "ai-validated"
|
|
295
|
+
});
|
|
296
|
+
}
|
|
297
|
+
}
|
|
298
|
+
}
|
|
299
|
+
if (json.additional && Array.isArray(json.additional)) {
|
|
300
|
+
for (const a of json.additional) {
|
|
301
|
+
aiIssues.push({
|
|
302
|
+
id: `ai-${Date.now()}-${Math.random().toString(36).substr(2, 5)}`,
|
|
303
|
+
severity: a.severity || "serious",
|
|
304
|
+
issue: `[AI FOUND] ${a.issue || a.explanation}`,
|
|
305
|
+
fix: a.fix || "See AI analysis",
|
|
306
|
+
file: a.file ? resolve(process.cwd(), a.file) : "unknown",
|
|
307
|
+
line: a.line,
|
|
308
|
+
confidence: (a.inevitability || 75) / 100,
|
|
309
|
+
autoFixable: false,
|
|
310
|
+
agent: "agent-smith-ai",
|
|
311
|
+
effort: "medium",
|
|
312
|
+
category: "ai-found"
|
|
313
|
+
});
|
|
314
|
+
}
|
|
315
|
+
}
|
|
316
|
+
return {
|
|
317
|
+
aiIssues,
|
|
318
|
+
philosophical: json.philosophical || ""
|
|
319
|
+
};
|
|
320
|
+
} catch (error) {
|
|
321
|
+
console.error(` \u26A0\uFE0F AI enhancement error: ${error}`);
|
|
322
|
+
return null;
|
|
323
|
+
}
|
|
324
|
+
}
|
|
325
|
+
async function buildReport(patternIssues, aiResult, files, executionTime, aiTime) {
|
|
326
|
+
const lines = [];
|
|
327
|
+
const allIssues = [
|
|
328
|
+
...filterFalsePositives(patternIssues),
|
|
329
|
+
...aiResult?.aiIssues || []
|
|
330
|
+
];
|
|
331
|
+
const critical = allIssues.filter((i) => i.severity === "critical");
|
|
332
|
+
const serious = allIssues.filter((i) => i.severity === "serious");
|
|
333
|
+
const moderate = allIssues.filter((i) => i.severity === "moderate");
|
|
334
|
+
const low = allIssues.filter((i) => i.severity === "low");
|
|
335
|
+
const aiValidated = allIssues.filter((i) => i.category === "ai-validated");
|
|
336
|
+
const aiFound = allIssues.filter((i) => i.category === "ai-found");
|
|
337
|
+
lines.push("");
|
|
338
|
+
lines.push("```");
|
|
339
|
+
lines.push(" \u2588\u2588\u2588\u2588\u2588\u2557 \u2588\u2588\u2588\u2588\u2588\u2588\u2557 \u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2557\u2588\u2588\u2588\u2557 \u2588\u2588\u2557\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2557");
|
|
340
|
+
lines.push(" \u2588\u2588\u2554\u2550\u2550\u2588\u2588\u2557\u2588\u2588\u2554\u2550\u2550\u2550\u2550\u255D \u2588\u2588\u2554\u2550\u2550\u2550\u2550\u255D\u2588\u2588\u2588\u2588\u2557 \u2588\u2588\u2551\u255A\u2550\u2550\u2588\u2588\u2554\u2550\u2550\u255D");
|
|
341
|
+
lines.push(" \u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2551\u2588\u2588\u2551 \u2588\u2588\u2588\u2557\u2588\u2588\u2588\u2588\u2588\u2557 \u2588\u2588\u2554\u2588\u2588\u2557 \u2588\u2588\u2551 \u2588\u2588\u2551 ");
|
|
342
|
+
lines.push(" \u2588\u2588\u2554\u2550\u2550\u2588\u2588\u2551\u2588\u2588\u2551 \u2588\u2588\u2551\u2588\u2588\u2554\u2550\u2550\u255D \u2588\u2588\u2551\u255A\u2588\u2588\u2557\u2588\u2588\u2551 \u2588\u2588\u2551 ");
|
|
343
|
+
lines.push(" \u2588\u2588\u2551 \u2588\u2588\u2551\u255A\u2588\u2588\u2588\u2588\u2588\u2588\u2554\u255D\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2557\u2588\u2588\u2551 \u255A\u2588\u2588\u2588\u2588\u2551 \u2588\u2588\u2551 ");
|
|
344
|
+
lines.push(" \u255A\u2550\u255D \u255A\u2550\u255D \u255A\u2550\u2550\u2550\u2550\u2550\u255D \u255A\u2550\u2550\u2550\u2550\u2550\u2550\u255D\u255A\u2550\u255D \u255A\u2550\u2550\u2550\u255D \u255A\u2550\u255D ");
|
|
345
|
+
lines.push(" ");
|
|
346
|
+
lines.push(" \u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2557\u2588\u2588\u2588\u2557 \u2588\u2588\u2588\u2557\u2588\u2588\u2557\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2557\u2588\u2588\u2557 \u2588\u2588\u2557");
|
|
347
|
+
lines.push(" \u2588\u2588\u2554\u2550\u2550\u2550\u2550\u255D\u2588\u2588\u2588\u2588\u2557 \u2588\u2588\u2588\u2588\u2551\u2588\u2588\u2551\u255A\u2550\u2550\u2588\u2588\u2554\u2550\u2550\u255D\u2588\u2588\u2551 \u2588\u2588\u2551");
|
|
348
|
+
lines.push(" \u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2557\u2588\u2588\u2554\u2588\u2588\u2588\u2588\u2554\u2588\u2588\u2551\u2588\u2588\u2551 \u2588\u2588\u2551 \u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2551");
|
|
349
|
+
lines.push(" \u255A\u2550\u2550\u2550\u2550\u2588\u2588\u2551\u2588\u2588\u2551\u255A\u2588\u2588\u2554\u255D\u2588\u2588\u2551\u2588\u2588\u2551 \u2588\u2588\u2551 \u2588\u2588\u2554\u2550\u2550\u2588\u2588\u2551");
|
|
350
|
+
lines.push(" \u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2551\u2588\u2588\u2551 \u255A\u2550\u255D \u2588\u2588\u2551\u2588\u2588\u2551 \u2588\u2588\u2551 \u2588\u2588\u2551 \u2588\u2588\u2551");
|
|
351
|
+
lines.push(" \u255A\u2550\u2550\u2550\u2550\u2550\u2550\u255D\u255A\u2550\u255D \u255A\u2550\u255D\u255A\u2550\u255D \u255A\u2550\u255D \u255A\u2550\u255D \u255A\u2550\u255D");
|
|
352
|
+
lines.push("```");
|
|
353
|
+
lines.push("");
|
|
354
|
+
lines.push(`*${randomQuote(QUOTES.greeting)}*`);
|
|
355
|
+
lines.push("");
|
|
356
|
+
lines.push("## Scan Summary");
|
|
357
|
+
lines.push("");
|
|
358
|
+
lines.push("| Metric | Value |");
|
|
359
|
+
lines.push("|--------|-------|");
|
|
360
|
+
lines.push(`| Files scanned | ${files.length} |`);
|
|
361
|
+
lines.push(`| Pattern detection | ${(executionTime / 1e3).toFixed(2)}s |`);
|
|
362
|
+
if (aiTime > 0) {
|
|
363
|
+
lines.push(`| AI analysis | ${(aiTime / 1e3).toFixed(2)}s |`);
|
|
364
|
+
}
|
|
365
|
+
lines.push(`| Total violations | ${allIssues.length} |`);
|
|
366
|
+
lines.push(`| \u{1F534} Critical | ${critical.length} |`);
|
|
367
|
+
lines.push(`| \u{1F7E0} Serious | ${serious.length} |`);
|
|
368
|
+
lines.push(`| \u{1F7E1} Moderate | ${moderate.length} |`);
|
|
369
|
+
lines.push(`| \u{1F535} Low | ${low.length} |`);
|
|
370
|
+
lines.push("");
|
|
371
|
+
if (aiResult) {
|
|
372
|
+
lines.push(`| \u{1F916} AI validated | ${aiValidated.length} |`);
|
|
373
|
+
lines.push(`| \u{1F9E0} AI found | ${aiFound.length} |`);
|
|
374
|
+
} else if (!isAIAvailable()) {
|
|
375
|
+
lines.push(`| \u26A0\uFE0F AI mode | Disabled (no API key) |`);
|
|
376
|
+
}
|
|
377
|
+
lines.push("");
|
|
378
|
+
if (allIssues.length === 0) {
|
|
379
|
+
lines.push(`*${randomQuote(QUOTES.clean)}*`);
|
|
380
|
+
return lines.join("\n");
|
|
381
|
+
}
|
|
382
|
+
if (aiResult?.philosophical) {
|
|
383
|
+
lines.push("## \u{1F574}\uFE0F Agent Smith Says");
|
|
384
|
+
lines.push("");
|
|
385
|
+
lines.push(`*${aiResult.philosophical}*`);
|
|
386
|
+
lines.push("");
|
|
387
|
+
}
|
|
388
|
+
if (aiFound.length > 0) {
|
|
389
|
+
lines.push("## \u{1F9E0} AI-Discovered Issues");
|
|
390
|
+
lines.push("");
|
|
391
|
+
lines.push("*Issues found by AI that pattern detection missed:*");
|
|
392
|
+
lines.push("");
|
|
393
|
+
for (const issue of aiFound.slice(0, 5)) {
|
|
394
|
+
const relPath = relative(process.cwd(), issue.file);
|
|
395
|
+
lines.push(`### \`${relPath}${issue.line ? ":" + issue.line : ""}\``);
|
|
396
|
+
lines.push("");
|
|
397
|
+
lines.push(`**Issue:** ${issue.issue.replace("[AI FOUND] ", "")}`);
|
|
398
|
+
lines.push("");
|
|
399
|
+
lines.push(`**Fix:** ${issue.fix}`);
|
|
400
|
+
lines.push("");
|
|
401
|
+
}
|
|
402
|
+
}
|
|
403
|
+
if (critical.length > 0) {
|
|
404
|
+
lines.push("## \u{1F534} Critical Issues - Fix Immediately");
|
|
405
|
+
lines.push("");
|
|
406
|
+
for (const issue of critical.slice(0, 10)) {
|
|
407
|
+
const relPath = relative(process.cwd(), issue.file);
|
|
408
|
+
lines.push(`### \`${relPath}${issue.line ? ":" + issue.line : ""}\``);
|
|
409
|
+
lines.push("");
|
|
410
|
+
const desc = issue.issue.replace(/^🕴️\s*/, "").split("\n")[0].replace(/\s*—\s*\d+\s*instance.*$/, "");
|
|
411
|
+
lines.push(`**Issue:** ${desc}`);
|
|
412
|
+
lines.push("");
|
|
413
|
+
const snippet = await getCodeSnippet(issue.file, issue.line);
|
|
414
|
+
if (snippet) {
|
|
415
|
+
lines.push("```");
|
|
416
|
+
lines.push(snippet);
|
|
417
|
+
lines.push("```");
|
|
418
|
+
lines.push("");
|
|
419
|
+
}
|
|
420
|
+
lines.push(`**Fix:** ${issue.fix}`);
|
|
421
|
+
lines.push("");
|
|
422
|
+
}
|
|
423
|
+
if (critical.length > 10) {
|
|
424
|
+
lines.push(`*...and ${critical.length - 10} more critical issues*`);
|
|
425
|
+
lines.push("");
|
|
426
|
+
}
|
|
427
|
+
}
|
|
428
|
+
if (serious.length > 0) {
|
|
429
|
+
lines.push("## \u{1F7E0} Serious Issues");
|
|
430
|
+
lines.push("");
|
|
431
|
+
for (const issue of serious.slice(0, 10)) {
|
|
432
|
+
const relPath = relative(process.cwd(), issue.file);
|
|
433
|
+
const location = `\`${basename(relPath)}${issue.line ? ":" + issue.line : ""}\``;
|
|
434
|
+
const desc = issue.issue.replace(/^🕴️\s*/, "").split("\n")[0].slice(0, 60);
|
|
435
|
+
lines.push(`- ${location} - ${desc}`);
|
|
436
|
+
}
|
|
437
|
+
if (serious.length > 10) {
|
|
438
|
+
lines.push(`- *...and ${serious.length - 10} more*`);
|
|
439
|
+
}
|
|
440
|
+
lines.push("");
|
|
441
|
+
}
|
|
442
|
+
const otherIssues = [...moderate, ...low];
|
|
443
|
+
if (otherIssues.length > 0) {
|
|
444
|
+
lines.push("## Other Issues by Category");
|
|
445
|
+
lines.push("");
|
|
446
|
+
const byCategory = /* @__PURE__ */ new Map();
|
|
447
|
+
for (const issue of otherIssues) {
|
|
448
|
+
const cat = issue.category || "general";
|
|
449
|
+
if (!byCategory.has(cat)) byCategory.set(cat, []);
|
|
450
|
+
byCategory.get(cat).push(issue);
|
|
451
|
+
}
|
|
452
|
+
const sorted = Array.from(byCategory.entries()).filter(([cat]) => cat !== "ai-analysis").sort((a, b) => b[1].length - a[1].length).slice(0, 10);
|
|
453
|
+
for (const [category, catIssues] of sorted) {
|
|
454
|
+
const icon = getCategoryIcon(category);
|
|
455
|
+
const sevIcon = getSeverityIcon(catIssues[0]?.severity || "low");
|
|
456
|
+
lines.push(`### ${icon} ${formatCategoryName(category)} ${sevIcon} (${catIssues.length})`);
|
|
457
|
+
const locations = catIssues.slice(0, 5).map((i) => `\`${basename(i.file)}${i.line ? ":" + i.line : ""}\``).join(", ");
|
|
458
|
+
lines.push(locations);
|
|
459
|
+
if (catIssues[0]?.fix) {
|
|
460
|
+
lines.push(`**Fix:** ${catIssues[0].fix}`);
|
|
461
|
+
}
|
|
462
|
+
lines.push("");
|
|
463
|
+
}
|
|
464
|
+
}
|
|
465
|
+
const crossFile = allIssues.filter((i) => i.category === "cross-file");
|
|
466
|
+
if (crossFile.length > 0) {
|
|
467
|
+
lines.push("## \u{1F310} Codebase-Wide Patterns");
|
|
468
|
+
lines.push("");
|
|
469
|
+
lines.push("*Issues appearing across many files - systemic problems:*");
|
|
470
|
+
lines.push("");
|
|
471
|
+
for (const issue of crossFile) {
|
|
472
|
+
lines.push(`- ${issue.issue.replace(/^🕴️\s*/, "").split("\n")[0]}`);
|
|
473
|
+
}
|
|
474
|
+
lines.push("");
|
|
475
|
+
}
|
|
476
|
+
lines.push("---");
|
|
477
|
+
lines.push("");
|
|
478
|
+
if (allIssues.length > 50) {
|
|
479
|
+
lines.push(`*${randomQuote(QUOTES.manyIssues)}*`);
|
|
480
|
+
} else {
|
|
481
|
+
lines.push(`*${randomQuote(QUOTES.fewIssues)}*`);
|
|
482
|
+
}
|
|
483
|
+
return lines.join("\n");
|
|
484
|
+
}
|
|
485
|
+
async function runAgentSmith(args) {
|
|
486
|
+
const startTime = Date.now();
|
|
487
|
+
let filesToScan = args.files || [];
|
|
488
|
+
if (!filesToScan.length) {
|
|
489
|
+
const scanDir = args.directory || process.cwd();
|
|
490
|
+
console.error(`
|
|
491
|
+
\u{1F50D} Agent Smith: Discovering files in: ${scanDir}`);
|
|
492
|
+
filesToScan = await discoverFiles(scanDir);
|
|
493
|
+
console.error(` Found ${filesToScan.length} files
|
|
494
|
+
`);
|
|
495
|
+
} else {
|
|
496
|
+
filesToScan = filesToScan.map(
|
|
497
|
+
(f) => isAbsolute(f) ? f : resolve(process.cwd(), f)
|
|
498
|
+
);
|
|
499
|
+
}
|
|
500
|
+
const validFiles = filesToScan.filter((f) => existsSync(f));
|
|
501
|
+
if (validFiles.length === 0) {
|
|
502
|
+
return {
|
|
503
|
+
content: [{
|
|
504
|
+
type: "text",
|
|
505
|
+
text: "\u274C No valid files found to scan."
|
|
506
|
+
}]
|
|
507
|
+
};
|
|
508
|
+
}
|
|
509
|
+
console.error("\u{1F574}\uFE0F Phase 1: Pattern Detection");
|
|
510
|
+
console.error(" Deploying 38 sub-agent hunters...");
|
|
511
|
+
const smith = new AgentSmithAgent();
|
|
512
|
+
const result = await smith.scan(validFiles, {
|
|
513
|
+
workingDir: args.directory || process.cwd(),
|
|
514
|
+
context: {}
|
|
515
|
+
});
|
|
516
|
+
const patternTime = Date.now() - startTime;
|
|
517
|
+
const patternIssues = result.issues.filter((i) => i.category !== "ai-analysis");
|
|
518
|
+
console.error(` Found ${patternIssues.length} violations in ${(patternTime / 1e3).toFixed(2)}s
|
|
519
|
+
`);
|
|
520
|
+
let aiResult = null;
|
|
521
|
+
let aiTime = 0;
|
|
522
|
+
if (isAIAvailable()) {
|
|
523
|
+
console.error("\u{1F574}\uFE0F Phase 2: AI Deep Analysis");
|
|
524
|
+
console.error(` ${getAIStatusMessage()}`);
|
|
525
|
+
const aiStartTime = Date.now();
|
|
526
|
+
aiResult = await runAIEnhancement(patternIssues, validFiles);
|
|
527
|
+
aiTime = Date.now() - aiStartTime;
|
|
528
|
+
if (aiResult) {
|
|
529
|
+
console.error(` AI validated ${aiResult.aiIssues.filter((i) => i.category === "ai-validated").length} issues`);
|
|
530
|
+
console.error(` AI discovered ${aiResult.aiIssues.filter((i) => i.category === "ai-found").length} new issues`);
|
|
531
|
+
console.error(` AI analysis took ${(aiTime / 1e3).toFixed(2)}s
|
|
532
|
+
`);
|
|
533
|
+
} else {
|
|
534
|
+
console.error(" AI enhancement returned no results\n");
|
|
535
|
+
}
|
|
536
|
+
} else {
|
|
537
|
+
console.error(`
|
|
538
|
+
${getAIStatusMessage()}`);
|
|
539
|
+
console.error(" Set ANTHROPIC_API_KEY for AI-powered analysis\n");
|
|
540
|
+
}
|
|
541
|
+
const report = await buildReport(patternIssues, aiResult, validFiles, patternTime, aiTime);
|
|
542
|
+
return {
|
|
543
|
+
content: [{
|
|
544
|
+
type: "text",
|
|
545
|
+
text: report
|
|
546
|
+
}]
|
|
547
|
+
};
|
|
548
|
+
}
|
|
549
|
+
export {
|
|
550
|
+
runAgentSmith
|
|
551
|
+
};
|
|
552
|
+
//# sourceMappingURL=agent-smith-runner-3MIO4CWT.js.map
|