popeye-cli 1.8.0 → 1.9.1
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 +47 -3
- package/cheatsheet.md +33 -0
- package/dist/cli/commands/index.d.ts +1 -0
- package/dist/cli/commands/index.d.ts.map +1 -1
- package/dist/cli/commands/index.js +1 -0
- package/dist/cli/commands/index.js.map +1 -1
- package/dist/cli/commands/review.d.ts +31 -0
- package/dist/cli/commands/review.d.ts.map +1 -0
- package/dist/cli/commands/review.js +156 -0
- package/dist/cli/commands/review.js.map +1 -0
- package/dist/cli/index.d.ts.map +1 -1
- package/dist/cli/index.js +2 -1
- package/dist/cli/index.js.map +1 -1
- package/dist/cli/interactive.d.ts.map +1 -1
- package/dist/cli/interactive.js +122 -61
- package/dist/cli/interactive.js.map +1 -1
- package/dist/types/audit.d.ts +623 -0
- package/dist/types/audit.d.ts.map +1 -0
- package/dist/types/audit.js +240 -0
- package/dist/types/audit.js.map +1 -0
- package/dist/types/workflow.d.ts +15 -0
- package/dist/types/workflow.d.ts.map +1 -1
- package/dist/types/workflow.js +5 -0
- package/dist/types/workflow.js.map +1 -1
- package/dist/workflow/audit-analyzer.d.ts +58 -0
- package/dist/workflow/audit-analyzer.d.ts.map +1 -0
- package/dist/workflow/audit-analyzer.js +438 -0
- package/dist/workflow/audit-analyzer.js.map +1 -0
- package/dist/workflow/audit-mode.d.ts +28 -0
- package/dist/workflow/audit-mode.d.ts.map +1 -0
- package/dist/workflow/audit-mode.js +169 -0
- package/dist/workflow/audit-mode.js.map +1 -0
- package/dist/workflow/audit-recovery.d.ts +61 -0
- package/dist/workflow/audit-recovery.d.ts.map +1 -0
- package/dist/workflow/audit-recovery.js +242 -0
- package/dist/workflow/audit-recovery.js.map +1 -0
- package/dist/workflow/audit-reporter.d.ts +65 -0
- package/dist/workflow/audit-reporter.d.ts.map +1 -0
- package/dist/workflow/audit-reporter.js +301 -0
- package/dist/workflow/audit-reporter.js.map +1 -0
- package/dist/workflow/audit-scanner.d.ts +87 -0
- package/dist/workflow/audit-scanner.d.ts.map +1 -0
- package/dist/workflow/audit-scanner.js +768 -0
- package/dist/workflow/audit-scanner.js.map +1 -0
- package/dist/workflow/index.d.ts +5 -0
- package/dist/workflow/index.d.ts.map +1 -1
- package/dist/workflow/index.js +5 -0
- package/dist/workflow/index.js.map +1 -1
- package/package.json +1 -1
- package/src/cli/commands/index.ts +1 -0
- package/src/cli/commands/review.ts +187 -0
- package/src/cli/index.ts +2 -0
- package/src/cli/interactive.ts +72 -4
- package/src/types/audit.ts +294 -0
- package/src/types/workflow.ts +15 -0
- package/src/workflow/audit-analyzer.ts +510 -0
- package/src/workflow/audit-mode.ts +240 -0
- package/src/workflow/audit-recovery.ts +284 -0
- package/src/workflow/audit-reporter.ts +370 -0
- package/src/workflow/audit-scanner.ts +873 -0
- package/src/workflow/index.ts +5 -0
- package/tests/cli/commands/review.test.ts +52 -0
- package/tests/types/audit.test.ts +250 -0
- package/tests/workflow/audit-analyzer.test.ts +281 -0
- package/tests/workflow/audit-mode.test.ts +114 -0
- package/tests/workflow/audit-recovery.test.ts +237 -0
- package/tests/workflow/audit-reporter.test.ts +254 -0
- package/tests/workflow/audit-scanner.test.ts +270 -0
|
@@ -0,0 +1,438 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* AI-powered project analyzer for the audit system.
|
|
3
|
+
*
|
|
4
|
+
* Constructs analysis prompts, executes them through Claude with Serena-first
|
|
5
|
+
* search strategy (with retries and fallback), parses findings, and scores.
|
|
6
|
+
*/
|
|
7
|
+
import { executePrompt } from '../adapters/claude.js';
|
|
8
|
+
import { AuditFindingSchema } from '../types/audit.js';
|
|
9
|
+
// ---------------------------------------------------------------------------
|
|
10
|
+
// Constants
|
|
11
|
+
// ---------------------------------------------------------------------------
|
|
12
|
+
const SERENA_TOOLS = [
|
|
13
|
+
'mcp__serena__find_symbol',
|
|
14
|
+
'mcp__serena__get_symbols_overview',
|
|
15
|
+
'mcp__serena__search_symbol',
|
|
16
|
+
'mcp__serena__get_file_symbols',
|
|
17
|
+
];
|
|
18
|
+
const FALLBACK_TOOLS = [
|
|
19
|
+
'Read', 'Glob', 'Grep',
|
|
20
|
+
];
|
|
21
|
+
const ALL_AUDIT_TOOLS = [...SERENA_TOOLS, ...FALLBACK_TOOLS];
|
|
22
|
+
const MAX_SERENA_RETRIES = 2;
|
|
23
|
+
const CATEGORY_WEIGHTS = {
|
|
24
|
+
'feature-completeness': 25,
|
|
25
|
+
'integration-wiring': 15,
|
|
26
|
+
'test-coverage': 15,
|
|
27
|
+
'config-deployment': 10,
|
|
28
|
+
'dependency-sanity': 10,
|
|
29
|
+
'consistency': 10,
|
|
30
|
+
'security': 10,
|
|
31
|
+
'documentation': 5,
|
|
32
|
+
};
|
|
33
|
+
const SEVERITY_DEDUCTIONS = {
|
|
34
|
+
critical: 20,
|
|
35
|
+
major: 10,
|
|
36
|
+
minor: 3,
|
|
37
|
+
info: 0,
|
|
38
|
+
};
|
|
39
|
+
// ---------------------------------------------------------------------------
|
|
40
|
+
// Prompt construction
|
|
41
|
+
// ---------------------------------------------------------------------------
|
|
42
|
+
/**
|
|
43
|
+
* Build the analysis prompt for Claude, embedding scan results and context.
|
|
44
|
+
*
|
|
45
|
+
* @param scan - The project scan result.
|
|
46
|
+
* @param state - Current project state.
|
|
47
|
+
* @param depth - Audit depth (1=shallow, 2=standard, 3=deep).
|
|
48
|
+
* @param strict - Whether to use strict scoring.
|
|
49
|
+
* @returns The complete analysis prompt string.
|
|
50
|
+
*/
|
|
51
|
+
export function buildAnalysisPrompt(scan, state, depth, strict) {
|
|
52
|
+
const sections = [];
|
|
53
|
+
sections.push(`# Project Audit Analysis
|
|
54
|
+
|
|
55
|
+
You are auditing the project "${state.name}" (language: ${scan.language}).
|
|
56
|
+
Depth level: ${depth} (1=shallow checks, 2=standard, 3=deep investigation).
|
|
57
|
+
${strict ? 'STRICT MODE: Apply higher standards for all checks.' : ''}
|
|
58
|
+
|
|
59
|
+
## Instructions
|
|
60
|
+
Analyze the project and return findings as a JSON array of objects. Each finding must have:
|
|
61
|
+
- id: string (format "AUD-NNN")
|
|
62
|
+
- category: one of "feature-completeness", "integration-wiring", "test-coverage", "config-deployment", "dependency-sanity", "consistency", "security", "documentation"
|
|
63
|
+
- severity: one of "critical", "major", "minor", "info"
|
|
64
|
+
- title: short summary
|
|
65
|
+
- description: detailed explanation
|
|
66
|
+
- evidence: array of { file: string, line?: number, snippet?: string, description?: string }
|
|
67
|
+
- recommendation: actionable fix
|
|
68
|
+
- autoFixable: boolean
|
|
69
|
+
|
|
70
|
+
Use Serena tools first for code navigation. If they fail, fall back to Read/Glob/Grep.
|
|
71
|
+
|
|
72
|
+
Return ONLY a JSON array wrapped in \`\`\`json fences. No other text.`);
|
|
73
|
+
// Component structure
|
|
74
|
+
sections.push(`## Component Structure
|
|
75
|
+
Components detected: ${scan.detectedComposition.join(', ')}
|
|
76
|
+
State language: ${scan.stateLanguage}
|
|
77
|
+
Composition mismatch: ${scan.compositionMismatch}
|
|
78
|
+
|
|
79
|
+
${scan.components.map((c) => `### ${c.kind} (${c.rootDir})
|
|
80
|
+
- Language: ${c.language}${c.framework ? `, Framework: ${c.framework}` : ''}
|
|
81
|
+
- Source files: ${c.sourceFiles.length}
|
|
82
|
+
- Test files: ${c.testFiles.length}
|
|
83
|
+
- Entry points: ${c.entryPoints.join(', ') || 'none'}
|
|
84
|
+
- Route files: ${c.routeFiles.join(', ') || 'none'}
|
|
85
|
+
- Dependencies: ${c.dependencyManifests.map((d) => d.file).join(', ') || 'none'}`).join('\n\n')}`);
|
|
86
|
+
// File tree
|
|
87
|
+
sections.push(`## Project Tree (truncated)
|
|
88
|
+
\`\`\`
|
|
89
|
+
${scan.tree}
|
|
90
|
+
\`\`\``);
|
|
91
|
+
// Totals
|
|
92
|
+
sections.push(`## Totals
|
|
93
|
+
- Source files: ${scan.totalSourceFiles}
|
|
94
|
+
- Test files: ${scan.totalTestFiles}
|
|
95
|
+
- Lines of code: ${scan.totalLinesOfCode}
|
|
96
|
+
- Lines of tests: ${scan.totalLinesOfTests}
|
|
97
|
+
- Config files: ${scan.configFiles.join(', ') || 'none'}`);
|
|
98
|
+
// CLAUDE.md context
|
|
99
|
+
if (scan.claudeMdContent) {
|
|
100
|
+
sections.push(`## CLAUDE.md (project instructions)
|
|
101
|
+
\`\`\`
|
|
102
|
+
${scan.claudeMdContent.slice(0, 3000)}
|
|
103
|
+
\`\`\``);
|
|
104
|
+
}
|
|
105
|
+
// README
|
|
106
|
+
if (scan.readmeContent) {
|
|
107
|
+
sections.push(`## README.md
|
|
108
|
+
\`\`\`
|
|
109
|
+
${scan.readmeContent.slice(0, 3000)}
|
|
110
|
+
\`\`\``);
|
|
111
|
+
}
|
|
112
|
+
// Specification from state
|
|
113
|
+
if (state.specification) {
|
|
114
|
+
sections.push(`## Project Specification
|
|
115
|
+
\`\`\`
|
|
116
|
+
${state.specification.slice(0, 3000)}
|
|
117
|
+
\`\`\``);
|
|
118
|
+
}
|
|
119
|
+
// Milestone status
|
|
120
|
+
if (state.milestones && state.milestones.length > 0) {
|
|
121
|
+
sections.push(`## Milestone Status
|
|
122
|
+
${state.milestones.map((m) => `- ${m.name}: ${m.status} (${m.tasks.filter((t) => t.status === 'complete').length}/${m.tasks.length} tasks)`).join('\n')}`);
|
|
123
|
+
}
|
|
124
|
+
// Wiring matrix pre-analysis
|
|
125
|
+
if (scan.wiring) {
|
|
126
|
+
sections.push(`## FE<->BE Wiring Matrix
|
|
127
|
+
- Frontend API env keys: ${scan.wiring.frontendApiBaseEnvKeys.join(', ') || 'none'}
|
|
128
|
+
- Frontend API resolved: ${scan.wiring.frontendApiBaseResolved || 'not set'}
|
|
129
|
+
- Backend CORS origins: ${scan.wiring.backendCorsOrigins?.join(', ') || 'not found'}
|
|
130
|
+
- Backend API prefix: ${scan.wiring.backendApiPrefix || 'not found'}
|
|
131
|
+
- Detected mismatches: ${scan.wiring.potentialMismatches.length}`);
|
|
132
|
+
}
|
|
133
|
+
// Env + Docker
|
|
134
|
+
if (scan.envExampleContent) {
|
|
135
|
+
sections.push(`## .env.example
|
|
136
|
+
\`\`\`
|
|
137
|
+
${scan.envExampleContent}
|
|
138
|
+
\`\`\``);
|
|
139
|
+
}
|
|
140
|
+
if (scan.dockerComposeContent) {
|
|
141
|
+
sections.push(`## docker-compose.yml
|
|
142
|
+
\`\`\`
|
|
143
|
+
${scan.dockerComposeContent}
|
|
144
|
+
\`\`\``);
|
|
145
|
+
}
|
|
146
|
+
// Framework-specific checks
|
|
147
|
+
const frameworks = scan.components.map((c) => c.framework).filter(Boolean);
|
|
148
|
+
if (frameworks.some((f) => f === 'next')) {
|
|
149
|
+
sections.push(`## Next.js-Specific Checks (IMPORTANT)
|
|
150
|
+
- Check for hydration mismatches: event handlers (onClick, onSubmit, onChange) in Server Components (files WITHOUT 'use client' directive) cause hydration errors
|
|
151
|
+
- Check for \`new Date()\`, \`Date.now()\`, \`Math.random()\` in Server Components — these produce different values on server vs client
|
|
152
|
+
- Check for \`typeof window\`, \`localStorage\`, \`navigator\` usage in render path of Server Components
|
|
153
|
+
- Check for invalid HTML nesting: \`<p>\` inside \`<p>\`, \`<div>\` inside \`<p>\`, block elements inside inline elements
|
|
154
|
+
- Verify that components with hooks (useState, useEffect, useRef) have 'use client' directive
|
|
155
|
+
- Check for proper 'use client' boundary — interactive components (forms, buttons with handlers) must be Client Components`);
|
|
156
|
+
}
|
|
157
|
+
if (frameworks.some((f) => f === 'react' || f === 'vue' || f === 'svelte')) {
|
|
158
|
+
sections.push(`## Frontend Framework Checks
|
|
159
|
+
- Check for missing key props on list items
|
|
160
|
+
- Verify error boundaries exist for critical routes
|
|
161
|
+
- Check for potential memory leaks (event listeners not cleaned up)
|
|
162
|
+
- Verify environment variables used at runtime are prefixed correctly (VITE_, NEXT_PUBLIC_, REACT_APP_)`);
|
|
163
|
+
}
|
|
164
|
+
// Depth-specific instructions
|
|
165
|
+
if (depth >= 2) {
|
|
166
|
+
sections.push(`## Depth-2 Checks
|
|
167
|
+
- Verify test coverage for all route handlers
|
|
168
|
+
- Check for missing error boundaries / error handling
|
|
169
|
+
- Validate dependency versions are not wildly outdated
|
|
170
|
+
- Confirm env variables used in code match .env.example`);
|
|
171
|
+
}
|
|
172
|
+
if (depth >= 3) {
|
|
173
|
+
sections.push(`## Depth-3 Checks
|
|
174
|
+
- Trace data flow from API endpoints to database
|
|
175
|
+
- Check for security issues (OWASP Top 10)
|
|
176
|
+
- Verify all imports resolve correctly
|
|
177
|
+
- Check for dead code and unused exports`);
|
|
178
|
+
}
|
|
179
|
+
return sections.join('\n\n');
|
|
180
|
+
}
|
|
181
|
+
// ---------------------------------------------------------------------------
|
|
182
|
+
// JSON parsing
|
|
183
|
+
// ---------------------------------------------------------------------------
|
|
184
|
+
/**
|
|
185
|
+
* Parse AI response into validated AuditFinding objects.
|
|
186
|
+
*
|
|
187
|
+
* Handles JSON wrapped in code fences, partial JSON, and malformed responses.
|
|
188
|
+
*
|
|
189
|
+
* @param rawResponse - Raw AI response text.
|
|
190
|
+
* @returns Array of validated findings.
|
|
191
|
+
*/
|
|
192
|
+
export function parseAuditFindings(rawResponse) {
|
|
193
|
+
// Extract JSON from code fences
|
|
194
|
+
const jsonMatch = rawResponse.match(/```(?:json)?\s*\n?([\s\S]*?)\n?```/);
|
|
195
|
+
const jsonStr = jsonMatch ? jsonMatch[1].trim() : rawResponse.trim();
|
|
196
|
+
let parsed;
|
|
197
|
+
try {
|
|
198
|
+
parsed = JSON.parse(jsonStr);
|
|
199
|
+
}
|
|
200
|
+
catch {
|
|
201
|
+
// Attempt to find a JSON array in the response
|
|
202
|
+
const arrayMatch = jsonStr.match(/\[[\s\S]*\]/);
|
|
203
|
+
if (arrayMatch) {
|
|
204
|
+
try {
|
|
205
|
+
parsed = JSON.parse(arrayMatch[0]);
|
|
206
|
+
}
|
|
207
|
+
catch {
|
|
208
|
+
return [];
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
else {
|
|
212
|
+
return [];
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
if (!Array.isArray(parsed)) {
|
|
216
|
+
return [];
|
|
217
|
+
}
|
|
218
|
+
const findings = [];
|
|
219
|
+
for (const item of parsed) {
|
|
220
|
+
try {
|
|
221
|
+
const finding = AuditFindingSchema.parse(item);
|
|
222
|
+
findings.push(finding);
|
|
223
|
+
}
|
|
224
|
+
catch {
|
|
225
|
+
// Skip malformed findings — partial results better than none
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
return findings;
|
|
229
|
+
}
|
|
230
|
+
// ---------------------------------------------------------------------------
|
|
231
|
+
// Deterministic findings from wiring/composition
|
|
232
|
+
// ---------------------------------------------------------------------------
|
|
233
|
+
/**
|
|
234
|
+
* Generate deterministic findings from wiring mismatches and composition issues.
|
|
235
|
+
*
|
|
236
|
+
* @param scan - The project scan result.
|
|
237
|
+
* @returns Array of deterministic findings.
|
|
238
|
+
*/
|
|
239
|
+
function generateDeterministicFindings(scan) {
|
|
240
|
+
const findings = [];
|
|
241
|
+
let counter = 900; // Reason: Start at 900 to avoid ID collision with AI findings
|
|
242
|
+
// Composition mismatch
|
|
243
|
+
if (scan.compositionMismatch) {
|
|
244
|
+
findings.push({
|
|
245
|
+
id: `AUD-${counter++}`,
|
|
246
|
+
category: 'consistency',
|
|
247
|
+
severity: 'major',
|
|
248
|
+
title: 'Workspace composition mismatch',
|
|
249
|
+
description: `State language is "${scan.stateLanguage}" but filesystem shows components: [${scan.detectedComposition.join(', ')}]. This may indicate an incomplete workspace setup or a stale state file.`,
|
|
250
|
+
evidence: [
|
|
251
|
+
{ file: '.popeye/state.json', description: `language: "${scan.stateLanguage}"` },
|
|
252
|
+
],
|
|
253
|
+
recommendation: 'Verify that all expected workspace apps are created and update project language if needed.',
|
|
254
|
+
autoFixable: false,
|
|
255
|
+
});
|
|
256
|
+
}
|
|
257
|
+
// Wiring mismatches
|
|
258
|
+
if (scan.wiring) {
|
|
259
|
+
for (const mismatch of scan.wiring.potentialMismatches) {
|
|
260
|
+
findings.push(wiringMismatchToFinding(mismatch, counter++));
|
|
261
|
+
}
|
|
262
|
+
}
|
|
263
|
+
// No test files at all
|
|
264
|
+
if (scan.totalTestFiles === 0 && scan.totalSourceFiles > 0) {
|
|
265
|
+
findings.push({
|
|
266
|
+
id: `AUD-${counter++}`,
|
|
267
|
+
category: 'test-coverage',
|
|
268
|
+
severity: 'critical',
|
|
269
|
+
title: 'No test files found',
|
|
270
|
+
description: `Project has ${scan.totalSourceFiles} source files but zero test files.`,
|
|
271
|
+
evidence: [],
|
|
272
|
+
recommendation: 'Add unit tests for critical paths.',
|
|
273
|
+
autoFixable: false,
|
|
274
|
+
});
|
|
275
|
+
}
|
|
276
|
+
// No README
|
|
277
|
+
if (!scan.readmeContent) {
|
|
278
|
+
findings.push({
|
|
279
|
+
id: `AUD-${counter++}`,
|
|
280
|
+
category: 'documentation',
|
|
281
|
+
severity: 'minor',
|
|
282
|
+
title: 'Missing README.md',
|
|
283
|
+
description: 'No README.md file found in project root.',
|
|
284
|
+
evidence: [],
|
|
285
|
+
recommendation: 'Add a README.md with project overview, setup, and usage instructions.',
|
|
286
|
+
autoFixable: true,
|
|
287
|
+
});
|
|
288
|
+
}
|
|
289
|
+
// No .env.example for multi-component projects
|
|
290
|
+
if (!scan.envExampleContent && scan.components.length > 1) {
|
|
291
|
+
findings.push({
|
|
292
|
+
id: `AUD-${counter++}`,
|
|
293
|
+
category: 'config-deployment',
|
|
294
|
+
severity: 'major',
|
|
295
|
+
title: 'Missing .env.example for workspace project',
|
|
296
|
+
description: 'Multi-component project should have a .env.example documenting required environment variables.',
|
|
297
|
+
evidence: [],
|
|
298
|
+
recommendation: 'Create .env.example with all required env variables and comments.',
|
|
299
|
+
autoFixable: true,
|
|
300
|
+
});
|
|
301
|
+
}
|
|
302
|
+
return findings;
|
|
303
|
+
}
|
|
304
|
+
/**
|
|
305
|
+
* Convert a wiring mismatch into an audit finding.
|
|
306
|
+
*
|
|
307
|
+
* @param mismatch - The wiring mismatch.
|
|
308
|
+
* @param counter - Finding ID counter.
|
|
309
|
+
* @returns An audit finding.
|
|
310
|
+
*/
|
|
311
|
+
function wiringMismatchToFinding(mismatch, counter) {
|
|
312
|
+
return {
|
|
313
|
+
id: `AUD-${counter}`,
|
|
314
|
+
category: 'integration-wiring',
|
|
315
|
+
severity: 'major',
|
|
316
|
+
title: `Wiring issue: ${mismatch.type}`,
|
|
317
|
+
description: mismatch.details,
|
|
318
|
+
evidence: mismatch.evidence,
|
|
319
|
+
recommendation: 'Update CORS or API base URL configuration to ensure frontend and backend can communicate.',
|
|
320
|
+
autoFixable: true,
|
|
321
|
+
};
|
|
322
|
+
}
|
|
323
|
+
// ---------------------------------------------------------------------------
|
|
324
|
+
// Scoring
|
|
325
|
+
// ---------------------------------------------------------------------------
|
|
326
|
+
/**
|
|
327
|
+
* Calculate audit scores from findings and scan data.
|
|
328
|
+
*
|
|
329
|
+
* @param findings - All audit findings (AI + deterministic).
|
|
330
|
+
* @param scan - The project scan result.
|
|
331
|
+
* @returns Overall score (0-100) and per-category scores.
|
|
332
|
+
*/
|
|
333
|
+
export function calculateAuditScores(findings, _scan) {
|
|
334
|
+
const categories = Object.keys(CATEGORY_WEIGHTS);
|
|
335
|
+
const categoryScores = {};
|
|
336
|
+
for (const cat of categories) {
|
|
337
|
+
const catFindings = findings.filter((f) => f.category === cat);
|
|
338
|
+
let score = 100;
|
|
339
|
+
for (const f of catFindings) {
|
|
340
|
+
score -= SEVERITY_DEDUCTIONS[f.severity] ?? 0;
|
|
341
|
+
}
|
|
342
|
+
categoryScores[cat] = Math.max(0, Math.min(100, score));
|
|
343
|
+
}
|
|
344
|
+
// Weighted average
|
|
345
|
+
let overallScore = 0;
|
|
346
|
+
let totalWeight = 0;
|
|
347
|
+
for (const cat of categories) {
|
|
348
|
+
overallScore += (categoryScores[cat] ?? 100) * CATEGORY_WEIGHTS[cat];
|
|
349
|
+
totalWeight += CATEGORY_WEIGHTS[cat];
|
|
350
|
+
}
|
|
351
|
+
overallScore = Math.round(overallScore / totalWeight);
|
|
352
|
+
return {
|
|
353
|
+
overallScore: Math.max(0, Math.min(100, overallScore)),
|
|
354
|
+
categoryScores: categoryScores,
|
|
355
|
+
};
|
|
356
|
+
}
|
|
357
|
+
// ---------------------------------------------------------------------------
|
|
358
|
+
// Main analyzer
|
|
359
|
+
// ---------------------------------------------------------------------------
|
|
360
|
+
/**
|
|
361
|
+
* Analyze the project using AI with Serena-first search strategy.
|
|
362
|
+
*
|
|
363
|
+
* The analysis flow:
|
|
364
|
+
* 1. Build prompt from scan data and state
|
|
365
|
+
* 2. Execute through Claude with Serena tools + fallback tools
|
|
366
|
+
* 3. Parse AI findings from the response
|
|
367
|
+
* 4. Merge with deterministic findings (wiring, composition, missing tests)
|
|
368
|
+
* 5. Track Serena usage in SearchMetadata
|
|
369
|
+
*
|
|
370
|
+
* @param scan - The project scan result from audit-scanner.
|
|
371
|
+
* @param state - Current project state.
|
|
372
|
+
* @param options - Audit mode options (depth, strict, etc.).
|
|
373
|
+
* @returns Findings array and search metadata.
|
|
374
|
+
*/
|
|
375
|
+
export async function analyzeProject(scan, state, options) {
|
|
376
|
+
const metadata = {
|
|
377
|
+
serenaUsed: false,
|
|
378
|
+
serenaRetries: 0,
|
|
379
|
+
serenaErrors: [],
|
|
380
|
+
fallbackUsed: false,
|
|
381
|
+
fallbackTool: '',
|
|
382
|
+
searchQueries: [],
|
|
383
|
+
};
|
|
384
|
+
const prompt = buildAnalysisPrompt(scan, state, options.depth, options.strict);
|
|
385
|
+
metadata.searchQueries.push('audit-analysis-prompt');
|
|
386
|
+
// Attempt execution with Serena tools
|
|
387
|
+
let result;
|
|
388
|
+
let serenaAttempt = 0;
|
|
389
|
+
while (serenaAttempt <= MAX_SERENA_RETRIES) {
|
|
390
|
+
try {
|
|
391
|
+
result = await executePrompt(prompt, {
|
|
392
|
+
cwd: options.projectDir,
|
|
393
|
+
allowedTools: ALL_AUDIT_TOOLS,
|
|
394
|
+
permissionMode: 'bypassPermissions',
|
|
395
|
+
timeout: 120_000,
|
|
396
|
+
});
|
|
397
|
+
if (result.success) {
|
|
398
|
+
metadata.serenaUsed = true;
|
|
399
|
+
break;
|
|
400
|
+
}
|
|
401
|
+
// Serena failure: retry with alternate approach
|
|
402
|
+
metadata.serenaRetries++;
|
|
403
|
+
metadata.serenaErrors.push(result.error ?? 'Unknown error');
|
|
404
|
+
serenaAttempt++;
|
|
405
|
+
}
|
|
406
|
+
catch (err) {
|
|
407
|
+
metadata.serenaRetries++;
|
|
408
|
+
metadata.serenaErrors.push(err instanceof Error ? err.message : 'Unknown error');
|
|
409
|
+
serenaAttempt++;
|
|
410
|
+
}
|
|
411
|
+
}
|
|
412
|
+
// Fallback: use only Read/Glob/Grep if Serena failed
|
|
413
|
+
if (!result?.success) {
|
|
414
|
+
metadata.fallbackUsed = true;
|
|
415
|
+
metadata.fallbackTool = 'grep';
|
|
416
|
+
try {
|
|
417
|
+
result = await executePrompt(prompt, {
|
|
418
|
+
cwd: options.projectDir,
|
|
419
|
+
allowedTools: FALLBACK_TOOLS,
|
|
420
|
+
permissionMode: 'bypassPermissions',
|
|
421
|
+
timeout: 120_000,
|
|
422
|
+
});
|
|
423
|
+
}
|
|
424
|
+
catch {
|
|
425
|
+
// Complete failure — proceed with deterministic findings only
|
|
426
|
+
}
|
|
427
|
+
}
|
|
428
|
+
// Parse AI findings
|
|
429
|
+
let aiFindings = [];
|
|
430
|
+
if (result?.success && result.response) {
|
|
431
|
+
aiFindings = parseAuditFindings(result.response);
|
|
432
|
+
}
|
|
433
|
+
// Merge with deterministic findings
|
|
434
|
+
const deterministicFindings = generateDeterministicFindings(scan);
|
|
435
|
+
const allFindings = [...aiFindings, ...deterministicFindings];
|
|
436
|
+
return { findings: allFindings, searchMetadata: metadata };
|
|
437
|
+
}
|
|
438
|
+
//# sourceMappingURL=audit-analyzer.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"audit-analyzer.js","sourceRoot":"","sources":["../../src/workflow/audit-analyzer.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Audit mode orchestrator.
|
|
3
|
+
*
|
|
4
|
+
* Coordinates the three audit stages:
|
|
5
|
+
* Stage 1: Scan + Summary
|
|
6
|
+
* Stage 2: Analyze + Report
|
|
7
|
+
* Stage 3: Recovery (evidence-based trigger)
|
|
8
|
+
*
|
|
9
|
+
* Pattern follows plan-mode.ts orchestration style.
|
|
10
|
+
*/
|
|
11
|
+
import type { ConsensusConfig } from '../types/consensus.js';
|
|
12
|
+
import type { AuditModeOptions, AuditModeResult } from '../types/audit.js';
|
|
13
|
+
export interface AuditModeRunOptions extends AuditModeOptions {
|
|
14
|
+
consensusConfig?: Partial<ConsensusConfig>;
|
|
15
|
+
onProgress?: (stage: string, message: string) => void;
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* Run a full audit of the project.
|
|
19
|
+
*
|
|
20
|
+
* Stage 1: Scan the filesystem deterministically
|
|
21
|
+
* Stage 2: Analyze with AI (Serena-first + fallback)
|
|
22
|
+
* Stage 3: Generate recovery plan if evidence warrants it
|
|
23
|
+
*
|
|
24
|
+
* @param options - Audit configuration options.
|
|
25
|
+
* @returns The complete audit result.
|
|
26
|
+
*/
|
|
27
|
+
export declare function runAuditMode(options: AuditModeRunOptions): Promise<AuditModeResult>;
|
|
28
|
+
//# sourceMappingURL=audit-mode.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"audit-mode.d.ts","sourceRoot":"","sources":["../../src/workflow/audit-mode.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAIH,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAC;AAE7D,OAAO,KAAK,EACV,gBAAgB,EAChB,eAAe,EAEhB,MAAM,mBAAmB,CAAC;AAsB3B,MAAM,WAAW,mBAAoB,SAAQ,gBAAgB;IAC3D,eAAe,CAAC,EAAE,OAAO,CAAC,eAAe,CAAC,CAAC;IAC3C,UAAU,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,KAAK,IAAI,CAAC;CACvD;AAMD;;;;;;;;;GASG;AACH,wBAAsB,YAAY,CAAC,OAAO,EAAE,mBAAmB,GAAG,OAAO,CAAC,eAAe,CAAC,CAuHzF"}
|
|
@@ -0,0 +1,169 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Audit mode orchestrator.
|
|
3
|
+
*
|
|
4
|
+
* Coordinates the three audit stages:
|
|
5
|
+
* Stage 1: Scan + Summary
|
|
6
|
+
* Stage 2: Analyze + Report
|
|
7
|
+
* Stage 3: Recovery (evidence-based trigger)
|
|
8
|
+
*
|
|
9
|
+
* Pattern follows plan-mode.ts orchestration style.
|
|
10
|
+
*/
|
|
11
|
+
import { randomUUID } from 'node:crypto';
|
|
12
|
+
import { loadProject, updateState } from '../state/index.js';
|
|
13
|
+
import { scanProject } from './audit-scanner.js';
|
|
14
|
+
import { analyzeProject, calculateAuditScores } from './audit-analyzer.js';
|
|
15
|
+
import { buildSummaryReport, buildAuditReport, writeAuditMarkdown, writeAuditJson, writeRecoveryMarkdown, writeRecoveryJson, } from './audit-reporter.js';
|
|
16
|
+
import { shouldTriggerRecovery, generateRecoveryPlan, recoveryToMilestones, injectRecoveryIntoState, } from './audit-recovery.js';
|
|
17
|
+
// ---------------------------------------------------------------------------
|
|
18
|
+
// Orchestrator
|
|
19
|
+
// ---------------------------------------------------------------------------
|
|
20
|
+
/**
|
|
21
|
+
* Run a full audit of the project.
|
|
22
|
+
*
|
|
23
|
+
* Stage 1: Scan the filesystem deterministically
|
|
24
|
+
* Stage 2: Analyze with AI (Serena-first + fallback)
|
|
25
|
+
* Stage 3: Generate recovery plan if evidence warrants it
|
|
26
|
+
*
|
|
27
|
+
* @param options - Audit configuration options.
|
|
28
|
+
* @returns The complete audit result.
|
|
29
|
+
*/
|
|
30
|
+
export async function runAuditMode(options) {
|
|
31
|
+
const { projectDir, onProgress } = options;
|
|
32
|
+
const depth = options.depth ?? 2;
|
|
33
|
+
const strict = options.strict ?? false;
|
|
34
|
+
const format = options.format ?? 'both';
|
|
35
|
+
const autoRecover = options.autoRecover ?? true;
|
|
36
|
+
const auditRunId = randomUUID();
|
|
37
|
+
let state;
|
|
38
|
+
try {
|
|
39
|
+
state = await loadProject(projectDir);
|
|
40
|
+
}
|
|
41
|
+
catch (err) {
|
|
42
|
+
const errorMsg = err instanceof Error ? err.message : 'Failed to load project';
|
|
43
|
+
return makeErrorResult(errorMsg);
|
|
44
|
+
}
|
|
45
|
+
// -----------------------------------------------------------------------
|
|
46
|
+
// Stage 1: Scan + Summary
|
|
47
|
+
// -----------------------------------------------------------------------
|
|
48
|
+
onProgress?.('stage-1', 'Starting project scan...');
|
|
49
|
+
const scan = await scanProject(projectDir, state.language, (msg) => onProgress?.('stage-1', msg));
|
|
50
|
+
const summary = buildSummaryReport(scan, state);
|
|
51
|
+
onProgress?.('stage-1', `Scan complete: ${scan.totalSourceFiles} source files, ${scan.totalLinesOfCode} LOC, ${scan.components.length} component(s)`);
|
|
52
|
+
// -----------------------------------------------------------------------
|
|
53
|
+
// Stage 2: Analyze + Report
|
|
54
|
+
// -----------------------------------------------------------------------
|
|
55
|
+
onProgress?.('stage-2', 'Starting AI analysis...');
|
|
56
|
+
const { findings, searchMetadata } = await analyzeProject(scan, state, {
|
|
57
|
+
depth,
|
|
58
|
+
strict,
|
|
59
|
+
projectDir,
|
|
60
|
+
});
|
|
61
|
+
const scores = calculateAuditScores(findings, scan);
|
|
62
|
+
const auditReport = buildAuditReport(summary, findings, scores, searchMetadata, { strict }, auditRunId);
|
|
63
|
+
// Write report artifacts
|
|
64
|
+
const reportPaths = {};
|
|
65
|
+
if (format === 'md' || format === 'both') {
|
|
66
|
+
reportPaths.auditMd = await writeAuditMarkdown(projectDir, auditReport);
|
|
67
|
+
}
|
|
68
|
+
if (format === 'json' || format === 'both') {
|
|
69
|
+
reportPaths.auditJson = await writeAuditJson(projectDir, auditReport);
|
|
70
|
+
}
|
|
71
|
+
// Update state with audit report path
|
|
72
|
+
await updateState(projectDir, {
|
|
73
|
+
auditReportPath: reportPaths.auditJson ?? reportPaths.auditMd,
|
|
74
|
+
auditLastRunAt: new Date().toISOString(),
|
|
75
|
+
auditRunId,
|
|
76
|
+
});
|
|
77
|
+
onProgress?.('stage-2', `Analysis complete: score ${scores.overallScore}%, ${findings.length} findings (serena: ${searchMetadata.serenaUsed ? 'used' : 'fallback'})`);
|
|
78
|
+
// -----------------------------------------------------------------------
|
|
79
|
+
// Stage 3: Recovery (evidence-based trigger)
|
|
80
|
+
// -----------------------------------------------------------------------
|
|
81
|
+
let recovery;
|
|
82
|
+
if (shouldTriggerRecovery(auditReport, strict)) {
|
|
83
|
+
onProgress?.('stage-3', 'Generating recovery plan...');
|
|
84
|
+
recovery = generateRecoveryPlan(auditReport);
|
|
85
|
+
// Write recovery artifacts
|
|
86
|
+
if (format === 'md' || format === 'both') {
|
|
87
|
+
reportPaths.recoveryMd = await writeRecoveryMarkdown(projectDir, recovery);
|
|
88
|
+
}
|
|
89
|
+
if (format === 'json' || format === 'both') {
|
|
90
|
+
reportPaths.recoveryJson = await writeRecoveryJson(projectDir, recovery);
|
|
91
|
+
}
|
|
92
|
+
// Auto-recover: inject milestones and switch to execution
|
|
93
|
+
if (autoRecover && recovery.milestones.length > 0) {
|
|
94
|
+
onProgress?.('stage-3', 'Injecting recovery milestones...');
|
|
95
|
+
const milestones = recoveryToMilestones(recovery, state.language);
|
|
96
|
+
await injectRecoveryIntoState(projectDir, milestones, auditRunId);
|
|
97
|
+
onProgress?.('stage-3', `Injected ${milestones.length} recovery milestone(s) — ready for execution`);
|
|
98
|
+
}
|
|
99
|
+
onProgress?.('stage-3', `Recovery plan: ${recovery.milestones.length} milestone(s), estimated ${recovery.estimatedEffort}`);
|
|
100
|
+
}
|
|
101
|
+
else {
|
|
102
|
+
onProgress?.('stage-3', 'No recovery needed based on findings.');
|
|
103
|
+
}
|
|
104
|
+
return {
|
|
105
|
+
success: true,
|
|
106
|
+
summary,
|
|
107
|
+
audit: auditReport,
|
|
108
|
+
recovery,
|
|
109
|
+
reportPaths,
|
|
110
|
+
};
|
|
111
|
+
}
|
|
112
|
+
// ---------------------------------------------------------------------------
|
|
113
|
+
// Helpers
|
|
114
|
+
// ---------------------------------------------------------------------------
|
|
115
|
+
/**
|
|
116
|
+
* Create an error result with minimal valid structure.
|
|
117
|
+
*
|
|
118
|
+
* @param error - Error message.
|
|
119
|
+
* @returns An AuditModeResult indicating failure.
|
|
120
|
+
*/
|
|
121
|
+
function makeErrorResult(error) {
|
|
122
|
+
const emptySummary = {
|
|
123
|
+
projectName: 'unknown',
|
|
124
|
+
language: 'unknown',
|
|
125
|
+
totalSourceFiles: 0,
|
|
126
|
+
totalTestFiles: 0,
|
|
127
|
+
totalLinesOfCode: 0,
|
|
128
|
+
totalLinesOfTests: 0,
|
|
129
|
+
componentCount: 0,
|
|
130
|
+
detectedComposition: [],
|
|
131
|
+
entryPointCount: 0,
|
|
132
|
+
routeCount: 0,
|
|
133
|
+
dependencyCount: 0,
|
|
134
|
+
hasDocker: false,
|
|
135
|
+
hasEnvExample: false,
|
|
136
|
+
hasCiConfig: false,
|
|
137
|
+
};
|
|
138
|
+
return {
|
|
139
|
+
success: false,
|
|
140
|
+
summary: emptySummary,
|
|
141
|
+
audit: {
|
|
142
|
+
projectName: 'unknown',
|
|
143
|
+
language: 'unknown',
|
|
144
|
+
auditedAt: new Date().toISOString(),
|
|
145
|
+
auditRunId: 'error',
|
|
146
|
+
summary: emptySummary,
|
|
147
|
+
findings: [],
|
|
148
|
+
overallScore: 0,
|
|
149
|
+
categoryScores: {},
|
|
150
|
+
criticalCount: 0,
|
|
151
|
+
majorCount: 0,
|
|
152
|
+
minorCount: 0,
|
|
153
|
+
infoCount: 0,
|
|
154
|
+
passedChecks: [],
|
|
155
|
+
searchMetadata: {
|
|
156
|
+
serenaUsed: false,
|
|
157
|
+
serenaRetries: 0,
|
|
158
|
+
serenaErrors: [],
|
|
159
|
+
fallbackUsed: false,
|
|
160
|
+
fallbackTool: '',
|
|
161
|
+
searchQueries: [],
|
|
162
|
+
},
|
|
163
|
+
recommendation: 'major-rework',
|
|
164
|
+
},
|
|
165
|
+
reportPaths: {},
|
|
166
|
+
error,
|
|
167
|
+
};
|
|
168
|
+
}
|
|
169
|
+
//# sourceMappingURL=audit-mode.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"audit-mode.js","sourceRoot":"","sources":["../../src/workflow/audit-mode.ts"],"names":[],"mappings":"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"}
|