code-auditor-mcp 3.6.0 → 3.8.0
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/.claude-plugin/marketplace.json +1 -1
- package/CHANGELOG.md +73 -0
- package/dist/analyzers/cross-language/DependencyGraphBuilder.d.ts.map +1 -1
- package/dist/analyzers/cross-language/DependencyGraphBuilder.js +12 -1
- package/dist/analyzers/cross-language/DependencyGraphBuilder.js.map +1 -1
- package/dist/analyzers/cross-language/SchemaValidator.d.ts.map +1 -1
- package/dist/analyzers/cross-language/SchemaValidator.js +122 -43
- package/dist/analyzers/cross-language/SchemaValidator.js.map +1 -1
- package/dist/analyzers/crossDomain/CrossDomainAnalyzer.d.ts +2 -2
- package/dist/analyzers/crossDomain/CrossDomainAnalyzer.js +6 -7
- package/dist/analyzers/crossDomain/CrossDomainAnalyzer.js.map +1 -1
- package/dist/analyzers/ruleRegistry.d.ts.map +1 -1
- package/dist/analyzers/ruleRegistry.js +152 -20
- package/dist/analyzers/ruleRegistry.js.map +1 -1
- package/dist/analyzers/universal/UniversalDRYAnalyzer.d.ts +38 -1
- package/dist/analyzers/universal/UniversalDRYAnalyzer.d.ts.map +1 -1
- package/dist/analyzers/universal/UniversalDRYAnalyzer.js +437 -48
- package/dist/analyzers/universal/UniversalDRYAnalyzer.js.map +1 -1
- package/dist/analyzers/universal/UniversalDataAccessAnalyzer.d.ts +6 -0
- package/dist/analyzers/universal/UniversalDataAccessAnalyzer.d.ts.map +1 -1
- package/dist/analyzers/universal/UniversalDataAccessAnalyzer.js +117 -35
- package/dist/analyzers/universal/UniversalDataAccessAnalyzer.js.map +1 -1
- package/dist/analyzers/universal/UniversalDocumentationAnalyzer.d.ts.map +1 -1
- package/dist/analyzers/universal/UniversalDocumentationAnalyzer.js +86 -15
- package/dist/analyzers/universal/UniversalDocumentationAnalyzer.js.map +1 -1
- package/dist/analyzers/universal/UniversalSOLIDAnalyzer.d.ts +32 -7
- package/dist/analyzers/universal/UniversalSOLIDAnalyzer.d.ts.map +1 -1
- package/dist/analyzers/universal/UniversalSOLIDAnalyzer.js +104 -23
- package/dist/analyzers/universal/UniversalSOLIDAnalyzer.js.map +1 -1
- package/dist/analyzers/universal/UniversalSecretsAnalyzer.d.ts +55 -0
- package/dist/analyzers/universal/UniversalSecretsAnalyzer.d.ts.map +1 -0
- package/dist/analyzers/universal/UniversalSecretsAnalyzer.js +318 -0
- package/dist/analyzers/universal/UniversalSecretsAnalyzer.js.map +1 -0
- package/dist/analyzers/universal/UniversalStylesAnalyzer.d.ts +2 -8
- package/dist/analyzers/universal/UniversalStylesAnalyzer.d.ts.map +1 -1
- package/dist/analyzers/universal/UniversalStylesAnalyzer.js +54 -45
- package/dist/analyzers/universal/UniversalStylesAnalyzer.js.map +1 -1
- package/dist/analyzers/universal/functionConcerns.d.ts +57 -0
- package/dist/analyzers/universal/functionConcerns.d.ts.map +1 -0
- package/dist/analyzers/universal/functionConcerns.js +239 -0
- package/dist/analyzers/universal/functionConcerns.js.map +1 -0
- package/dist/analyzers/universal/schema/codeAnalysis.d.ts.map +1 -1
- package/dist/analyzers/universal/schema/codeAnalysis.js +13 -7
- package/dist/analyzers/universal/schema/codeAnalysis.js.map +1 -1
- package/dist/analyzers/universal/schema/jsonSchema.js +124 -11
- package/dist/analyzers/universal/schema/jsonSchema.js.map +1 -1
- package/dist/auditRouter.d.ts.map +1 -1
- package/dist/auditRouter.js +4 -6
- package/dist/auditRouter.js.map +1 -1
- package/dist/auditRunner.d.ts.map +1 -1
- package/dist/auditRunner.js +74 -48
- package/dist/auditRunner.js.map +1 -1
- package/dist/cli.js +321 -98
- package/dist/cli.js.map +1 -1
- package/dist/config/configLoader.d.ts.map +1 -1
- package/dist/config/configLoader.js +23 -0
- package/dist/config/configLoader.js.map +1 -1
- package/dist/config/defaults.d.ts +6 -0
- package/dist/config/defaults.d.ts.map +1 -1
- package/dist/config/defaults.js +45 -10
- package/dist/config/defaults.js.map +1 -1
- package/dist/config/effectiveConfig.d.ts.map +1 -1
- package/dist/config/effectiveConfig.js +2 -0
- package/dist/config/effectiveConfig.js.map +1 -1
- package/dist/conventions/conventionMiner.d.ts +18 -3
- package/dist/conventions/conventionMiner.d.ts.map +1 -1
- package/dist/conventions/conventionMiner.js +130 -12
- package/dist/conventions/conventionMiner.js.map +1 -1
- package/dist/daemon/core.d.ts +128 -0
- package/dist/daemon/core.d.ts.map +1 -0
- package/dist/daemon/core.js +700 -0
- package/dist/daemon/core.js.map +1 -0
- package/dist/daemon/lspServer.d.ts +51 -0
- package/dist/daemon/lspServer.d.ts.map +1 -0
- package/dist/daemon/lspServer.js +168 -0
- package/dist/daemon/lspServer.js.map +1 -0
- package/dist/daemon/main.d.ts +34 -0
- package/dist/daemon/main.d.ts.map +1 -0
- package/dist/daemon/main.js +147 -0
- package/dist/daemon/main.js.map +1 -0
- package/dist/daemon/resolve.d.ts +41 -0
- package/dist/daemon/resolve.d.ts.map +1 -0
- package/dist/daemon/resolve.js +90 -0
- package/dist/daemon/resolve.js.map +1 -0
- package/dist/daemon/socketClient.d.ts +21 -0
- package/dist/daemon/socketClient.d.ts.map +1 -0
- package/dist/daemon/socketClient.js +60 -0
- package/dist/daemon/socketClient.js.map +1 -0
- package/dist/daemon/socketServer.d.ts +33 -0
- package/dist/daemon/socketServer.d.ts.map +1 -0
- package/dist/daemon/socketServer.js +106 -0
- package/dist/daemon/socketServer.js.map +1 -0
- package/dist/daemon/types.d.ts +78 -0
- package/dist/daemon/types.d.ts.map +1 -0
- package/dist/daemon/types.js +10 -0
- package/dist/daemon/types.js.map +1 -0
- package/dist/dataPaths.d.ts +21 -0
- package/dist/dataPaths.d.ts.map +1 -1
- package/dist/dataPaths.js +27 -0
- package/dist/dataPaths.js.map +1 -1
- package/dist/graph/importGraph.d.ts +11 -0
- package/dist/graph/importGraph.d.ts.map +1 -1
- package/dist/graph/importGraph.js +11 -3
- package/dist/graph/importGraph.js.map +1 -1
- package/dist/hooks/core.d.ts.map +1 -1
- package/dist/hooks/core.js +21 -4
- package/dist/hooks/core.js.map +1 -1
- package/dist/installer.d.ts.map +1 -1
- package/dist/installer.js +2 -5
- package/dist/installer.js.map +1 -1
- package/dist/languages/RuntimeManager.js +10 -0
- package/dist/languages/RuntimeManager.js.map +1 -1
- package/dist/languages/go/analyzer +0 -0
- package/dist/languages/go/analyzer-src/analyzer.go +166 -35
- package/dist/languages/go/analyzer-src/solid.go +80 -172
- package/dist/languages/go/analyzer-src/types.go +18 -18
- package/dist/ledger.d.ts +1 -1
- package/dist/ledger.d.ts.map +1 -1
- package/dist/ledger.js +3 -3
- package/dist/ledger.js.map +1 -1
- package/dist/mcp.js +1 -1
- package/dist/mcp.js.map +1 -1
- package/dist/mcpAuditJobs.js +1 -1
- package/dist/mcpAuditJobs.js.map +1 -1
- package/dist/nextFileIncremental.d.ts +9 -3
- package/dist/nextFileIncremental.d.ts.map +1 -1
- package/dist/nextFileIncremental.js +32 -6
- package/dist/nextFileIncremental.js.map +1 -1
- package/dist/pipeline.d.ts +26 -0
- package/dist/pipeline.d.ts.map +1 -1
- package/dist/pipeline.js +86 -10
- package/dist/pipeline.js.map +1 -1
- package/dist/pipelineAdapters.d.ts +2 -1
- package/dist/pipelineAdapters.d.ts.map +1 -1
- package/dist/pipelineAdapters.js +228 -5
- package/dist/pipelineAdapters.js.map +1 -1
- package/dist/reporting/csvReportGenerator.js +1 -1
- package/dist/ruleAliases.d.ts.map +1 -1
- package/dist/ruleAliases.js +41 -2
- package/dist/ruleAliases.js.map +1 -1
- package/dist/styles/tailwindProbe.d.ts +8 -0
- package/dist/styles/tailwindProbe.d.ts.map +1 -1
- package/dist/styles/tailwindProbe.js +11 -1
- package/dist/styles/tailwindProbe.js.map +1 -1
- package/dist/types/crossLanguage.d.ts +1 -0
- package/dist/types/crossLanguage.d.ts.map +1 -1
- package/dist/types.d.ts +30 -1
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js.map +1 -1
- package/package.json +7 -3
- package/plugin/.claude-plugin/plugin.json +1 -1
- package/plugin/skills/code-auditor/SKILL-RULE-KINDS.md +4 -2
- package/plugin/skills/code-auditor/SKILL.md +19 -11
package/dist/cli.js
CHANGED
|
@@ -139,6 +139,20 @@ program
|
|
|
139
139
|
});
|
|
140
140
|
const violations = Object.values(result.analyzerResults).flatMap((r) => r.violations || []);
|
|
141
141
|
const baseline = result.metadata?.baseline;
|
|
142
|
+
// ── Coverage panel leads the report (Spec 47 R2) ─────────────
|
|
143
|
+
// A diagnostic report opens with what was measured before it lists any
|
|
144
|
+
// readings, so a zero-reading report can't be mistaken for a clean tree.
|
|
145
|
+
const coverage = result.metadata?.coverage;
|
|
146
|
+
if (coverage && coverage.length > 0) {
|
|
147
|
+
const covFired = coverage.filter(c => c.state === 'fired').length;
|
|
148
|
+
const covClean = coverage.filter(c => c.state === 'clean').length;
|
|
149
|
+
const covUnassessed = coverage.filter(c => c.state === 'unassessed').length;
|
|
150
|
+
const covNotApplicable = coverage.filter(c => c.state === 'notApplicable').length;
|
|
151
|
+
const covCannotFire = coverage.filter(c => c.state === 'cannot-fire').length;
|
|
152
|
+
console.log(chalk.gray(`── Coverage panel ── ${covFired} fired · ${covClean} clean · ` +
|
|
153
|
+
`${covUnassessed} unassessed · ${covNotApplicable} not-applicable · ` +
|
|
154
|
+
`${covCannotFire} cannot-fire`));
|
|
155
|
+
}
|
|
142
156
|
// ── Delta output (Spec 18 R2) ─────────────────────────────────
|
|
143
157
|
if (baseline && !options.full) {
|
|
144
158
|
const newViolations = violations.filter((v) => v.new === true);
|
|
@@ -155,7 +169,7 @@ program
|
|
|
155
169
|
: '(unchanged)';
|
|
156
170
|
console.log(`\n📊 Delta: +${newViolations.length} new · −${fixedCount} fixed · ${knownCount} known ${trendIcon} ${trendLabel}`);
|
|
157
171
|
if (newViolations.length > 0) {
|
|
158
|
-
console.log(chalk.gray(`\n── New
|
|
172
|
+
console.log(chalk.gray(`\n── New readings (${newViolations.length}) ──────────────────────────`));
|
|
159
173
|
for (const v of newViolations) {
|
|
160
174
|
const icon = v.severity === 'critical' ? '🔴' :
|
|
161
175
|
v.severity === 'warning' ? '🟡' : '🔵';
|
|
@@ -163,9 +177,9 @@ program
|
|
|
163
177
|
}
|
|
164
178
|
}
|
|
165
179
|
else {
|
|
166
|
-
console.log(chalk.green('\n✓ No new
|
|
180
|
+
console.log(chalk.green('\n✓ No new readings since last baseline.'));
|
|
167
181
|
if (knownCount > 0) {
|
|
168
|
-
console.log(chalk.gray(` ${knownCount} known
|
|
182
|
+
console.log(chalk.gray(` ${knownCount} known reading(s) are still open — recorded, not resolved.`));
|
|
169
183
|
}
|
|
170
184
|
}
|
|
171
185
|
// Debt by analyzer
|
|
@@ -195,26 +209,26 @@ program
|
|
|
195
209
|
.sort((a, b) => b[1] - a[1])
|
|
196
210
|
.slice(0, 5);
|
|
197
211
|
for (const [file, count] of topFiles) {
|
|
198
|
-
console.log(`${file} — ${count}
|
|
212
|
+
console.log(`${file} — ${count} reading${count !== 1 ? 's' : ''}`);
|
|
199
213
|
}
|
|
200
|
-
console.log(chalk.gray(`\n💡 Run ${chalk.cyan('code-audit --full')} to see all ${currentDebt.toLocaleString()}
|
|
214
|
+
console.log(chalk.gray(`\n💡 Run ${chalk.cyan('code-audit --full')} to see all ${currentDebt.toLocaleString()} readings.`));
|
|
201
215
|
}
|
|
202
216
|
else if (!baseline) {
|
|
203
217
|
// No baseline: current behavior + hint
|
|
204
|
-
console.log(`\nFound ${result.summary.totalViolations}
|
|
218
|
+
console.log(`\nFound ${result.summary.totalViolations} readings`);
|
|
205
219
|
console.log(`Critical: ${result.summary.criticalIssues}`);
|
|
206
220
|
console.log(`Warnings: ${result.summary.warnings}`);
|
|
207
221
|
console.log(`Suggestions: ${result.summary.suggestions}`);
|
|
208
|
-
console.log(chalk.gray(`\nEvery
|
|
222
|
+
console.log(chalk.gray(`\nEvery reading is a measurement, not a verdict — severity is triage, the order to act.`));
|
|
209
223
|
console.log(chalk.gray(`\n💡 Run ${chalk.cyan('code-audit baseline')} to adopt the ratchet and track changes over time.`));
|
|
210
224
|
}
|
|
211
225
|
else {
|
|
212
226
|
// --full with baseline: full itemized inventory (current behavior)
|
|
213
|
-
console.log(`\nFound ${result.summary.totalViolations}
|
|
227
|
+
console.log(`\nFound ${result.summary.totalViolations} readings`);
|
|
214
228
|
console.log(`Critical: ${result.summary.criticalIssues}`);
|
|
215
229
|
console.log(`Warnings: ${result.summary.warnings}`);
|
|
216
230
|
console.log(`Suggestions: ${result.summary.suggestions}`);
|
|
217
|
-
console.log(chalk.gray(`\nEvery
|
|
231
|
+
console.log(chalk.gray(`\nEvery reading is a measurement, not a verdict — severity is triage, the order to act.`));
|
|
218
232
|
}
|
|
219
233
|
// Spec 44 R4 — file accounting: analyzed/dropped totals + optional breakdown.
|
|
220
234
|
printFileAccounting(result, !!options.explainSkipped);
|
|
@@ -296,7 +310,7 @@ program
|
|
|
296
310
|
}
|
|
297
311
|
}
|
|
298
312
|
if (unassessed.length > 0) {
|
|
299
|
-
console.log(chalk.gray(` ── Unassessed (zero
|
|
313
|
+
console.log(chalk.gray(` ── Unassessed (zero readings, applicability unknown) ──`));
|
|
300
314
|
for (const c of unassessed) {
|
|
301
315
|
console.log(` ${c.ruleId} (0)`);
|
|
302
316
|
}
|
|
@@ -308,7 +322,7 @@ program
|
|
|
308
322
|
const builtinCapped = Object.values(result.analyzerResults)
|
|
309
323
|
.reduce((count, ar) => count + ar.violations.filter(v => v.profile === 'scripts-and-tests').length, 0);
|
|
310
324
|
if (builtinCapped > 0) {
|
|
311
|
-
console.log(chalk.blue(`\nℹ️ ${builtinCapped.toLocaleString()}
|
|
325
|
+
console.log(chalk.blue(`\nℹ️ ${builtinCapped.toLocaleString()} readings capped by built-in profile "scripts-and-tests" (scripts/tests/fixtures → suggestion).`));
|
|
312
326
|
console.log(chalk.gray(` Set ${chalk.cyan('"builtin": false')} in .codeauditor.json to disable.`));
|
|
313
327
|
}
|
|
314
328
|
// Generate formatted report if --format is specified
|
|
@@ -333,7 +347,7 @@ program
|
|
|
333
347
|
const currentDebt = violations.filter((v) => v.new || v.new === false).length;
|
|
334
348
|
const snapshotDebt = baseline.previousKnownCount ?? 0;
|
|
335
349
|
if (currentDebt > snapshotDebt) {
|
|
336
|
-
console.error(chalk.red(`Debt regression: ${currentDebt - snapshotDebt}
|
|
350
|
+
console.error(chalk.red(`Debt regression: ${currentDebt - snapshotDebt} readings added without re-baselining.`));
|
|
337
351
|
process.exit(2);
|
|
338
352
|
}
|
|
339
353
|
}
|
|
@@ -392,7 +406,6 @@ program
|
|
|
392
406
|
.option('-p, --path <projectPath>', 'Project root path', process.cwd())
|
|
393
407
|
.action(async (paths, options) => {
|
|
394
408
|
try {
|
|
395
|
-
await initParsers();
|
|
396
409
|
const fileSet = new Set();
|
|
397
410
|
// Collect paths from stdin if requested
|
|
398
411
|
if (options.stdin) {
|
|
@@ -413,18 +426,43 @@ program
|
|
|
413
426
|
}
|
|
414
427
|
// Resolve scope
|
|
415
428
|
let scope = 'changed';
|
|
429
|
+
let resolvedPaths = [];
|
|
416
430
|
if (fileSet.size > 0) {
|
|
417
431
|
// Convert to absolute paths
|
|
418
|
-
|
|
419
|
-
scope =
|
|
432
|
+
resolvedPaths = [...fileSet].map((f) => isAbsolute(f) ? f : resolve(process.cwd(), f));
|
|
433
|
+
scope = resolvedPaths;
|
|
434
|
+
}
|
|
435
|
+
// R2 — resolve to a live daemon first (fast path); fall back in-process.
|
|
436
|
+
// The daemon serves per-file diagnostics for exactly the changed set. It is
|
|
437
|
+
// only trusted when ready and none of the queried files are stale (R4): a
|
|
438
|
+
// just-edited file whose re-audit hasn't landed falls through in-process so
|
|
439
|
+
// the gate never misses a finding. SARIF needs full run metadata, so it
|
|
440
|
+
// always runs in-process.
|
|
441
|
+
const projectRoot = resolve(options.path || process.cwd());
|
|
442
|
+
let result;
|
|
443
|
+
if (resolvedPaths.length > 0 && options.format !== 'sarif') {
|
|
444
|
+
const { resolveDaemon, readDaemonDiagnostics } = await import('./daemon/resolve.js');
|
|
445
|
+
const daemon = await resolveDaemon(projectRoot);
|
|
446
|
+
if (daemon.mode === 'not-ready') {
|
|
447
|
+
reportDaemonIndexing(daemon.state, !!options.json);
|
|
448
|
+
return;
|
|
449
|
+
}
|
|
450
|
+
if (daemon.mode === 'ready') {
|
|
451
|
+
const diag = await readDaemonDiagnostics(daemon.socketPath, resolvedPaths);
|
|
452
|
+
if (diag && diag.status === 'ready' && diag.staleFiles.length === 0) {
|
|
453
|
+
result = await buildChangedResultFromDiagnostics(diag.diagnostics, projectRoot);
|
|
454
|
+
}
|
|
455
|
+
}
|
|
456
|
+
}
|
|
457
|
+
if (!result) {
|
|
458
|
+
await initParsers();
|
|
459
|
+
const runner = createAuditRunner({
|
|
460
|
+
projectRoot: options.path,
|
|
461
|
+
scope,
|
|
462
|
+
analyzerConcurrency: 4
|
|
463
|
+
});
|
|
464
|
+
result = await runner.run();
|
|
420
465
|
}
|
|
421
|
-
// Create runner
|
|
422
|
-
const runner = createAuditRunner({
|
|
423
|
-
projectRoot: options.path,
|
|
424
|
-
scope,
|
|
425
|
-
analyzerConcurrency: 4
|
|
426
|
-
});
|
|
427
|
-
const result = await runner.run();
|
|
428
466
|
// Collect all violations
|
|
429
467
|
const violations = Object.values(result.analyzerResults).flatMap((r) => r.violations || []);
|
|
430
468
|
// Blocking gate decision (Spec 45 R1/R2/R4), computed once so the
|
|
@@ -459,7 +497,7 @@ program
|
|
|
459
497
|
const col = v.column ?? v.start?.column ?? 1;
|
|
460
498
|
return {
|
|
461
499
|
analyzer: v.analyzer || '',
|
|
462
|
-
rule: v.rule
|
|
500
|
+
rule: v.rule,
|
|
463
501
|
severity: v.severity,
|
|
464
502
|
message: v.message,
|
|
465
503
|
file: filePath,
|
|
@@ -497,7 +535,7 @@ program
|
|
|
497
535
|
}
|
|
498
536
|
}
|
|
499
537
|
else {
|
|
500
|
-
console.log(chalk.green('\n✓ No
|
|
538
|
+
console.log(chalk.green('\n✓ No readings.'));
|
|
501
539
|
}
|
|
502
540
|
}
|
|
503
541
|
// Spec 38 R2/R3 — per-rule timing + gate wall-clock, opt-in by env var.
|
|
@@ -572,7 +610,7 @@ function summarizeFindings(violations) {
|
|
|
572
610
|
bySeverity.set(severity, (bySeverity.get(severity) ?? 0) + 1);
|
|
573
611
|
const analyzer = v.analyzer ?? 'unknown';
|
|
574
612
|
byAnalyzer.set(analyzer, (byAnalyzer.get(analyzer) ?? 0) + 1);
|
|
575
|
-
const rule = v.rule
|
|
613
|
+
const rule = v.rule;
|
|
576
614
|
byRule.set(rule, (byRule.get(rule) ?? 0) + 1);
|
|
577
615
|
}
|
|
578
616
|
return { bySeverity, byAnalyzer, byRule };
|
|
@@ -590,6 +628,32 @@ function printCountSummary(violations) {
|
|
|
590
628
|
console.log(`by analyzer: ${groupedCounts(byAnalyzer)}`);
|
|
591
629
|
console.log(`by rule: ${groupedCounts(byRule)}`);
|
|
592
630
|
}
|
|
631
|
+
/**
|
|
632
|
+
* Reconstruct a `changed`-compatible result from daemon-served diagnostics so the
|
|
633
|
+
* gate/output logic below stays identical to the in-process path. Gate severities
|
|
634
|
+
* are read from the project config (one JSON file, no parsing) so a custom
|
|
635
|
+
* `gateSeverities` never diverges from what the in-process run would have used.
|
|
636
|
+
*/
|
|
637
|
+
async function buildChangedResultFromDiagnostics(violations, projectRoot) {
|
|
638
|
+
const analyzerResults = {};
|
|
639
|
+
for (const v of violations) {
|
|
640
|
+
const key = v.analyzer || 'unknown';
|
|
641
|
+
(analyzerResults[key] = analyzerResults[key] || { violations: [] }).violations.push(v);
|
|
642
|
+
}
|
|
643
|
+
let configUsed;
|
|
644
|
+
try {
|
|
645
|
+
const { findConfigFileUp, loadConfig } = await import('./config/configLoader.js');
|
|
646
|
+
const configPath = await findConfigFileUp(projectRoot);
|
|
647
|
+
const config = await loadConfig({ configPath: configPath ?? undefined });
|
|
648
|
+
if (Array.isArray(config.gateSeverities) && config.gateSeverities.length > 0) {
|
|
649
|
+
configUsed = { gateSeverities: config.gateSeverities };
|
|
650
|
+
}
|
|
651
|
+
}
|
|
652
|
+
catch {
|
|
653
|
+
// No config — the gate falls back to DEFAULT_BLOCKING_SEVERITIES, matching in-process.
|
|
654
|
+
}
|
|
655
|
+
return { analyzerResults, metadata: { configUsed, diagnostics: [] } };
|
|
656
|
+
}
|
|
593
657
|
// Self-audit gate (Spec 33 Item 15 + Spec 44 remediation). Runs the full
|
|
594
658
|
// analyzer pipeline over the tool's own production source and asserts zero
|
|
595
659
|
// *blocking* (critical/warning) findings in the self-audit scope — the same
|
|
@@ -621,7 +685,7 @@ function isSelfAuditInScope(file) {
|
|
|
621
685
|
}
|
|
622
686
|
program
|
|
623
687
|
.command('self-audit [paths...]')
|
|
624
|
-
.description('Audit the tool\'s own analyzers/ + languages/ source and fail on blocking
|
|
688
|
+
.description('Audit the tool\'s own analyzers/ + languages/ source and fail on blocking readings')
|
|
625
689
|
.option('--json', 'Output violations as machine-readable JSON to stdout')
|
|
626
690
|
.option('--stdin', 'Read file paths from stdin (one per line)')
|
|
627
691
|
.option('-p, --path <projectPath>', 'Project root path', process.cwd())
|
|
@@ -685,7 +749,7 @@ program
|
|
|
685
749
|
}
|
|
686
750
|
return {
|
|
687
751
|
analyzer: v.analyzer || '',
|
|
688
|
-
rule: v.rule
|
|
752
|
+
rule: v.rule,
|
|
689
753
|
severity: v.severity,
|
|
690
754
|
message: v.message,
|
|
691
755
|
file: filePath,
|
|
@@ -702,7 +766,7 @@ program
|
|
|
702
766
|
}
|
|
703
767
|
else if (blocking.length > 0) {
|
|
704
768
|
// Spec 45 A2 — counts plus findings (per analyzer/rule/severity).
|
|
705
|
-
console.log(chalk.red('\nSelf-audit blocking
|
|
769
|
+
console.log(chalk.red('\nSelf-audit blocking readings:'));
|
|
706
770
|
printCountSummary(blocking);
|
|
707
771
|
for (const v of blocking) {
|
|
708
772
|
const icon = v.severity === 'critical' ? '🔴' :
|
|
@@ -711,7 +775,7 @@ program
|
|
|
711
775
|
}
|
|
712
776
|
}
|
|
713
777
|
else {
|
|
714
|
-
console.log(chalk.green('\n✓ Self-audit clean — zero blocking
|
|
778
|
+
console.log(chalk.green('\n✓ Self-audit clean — zero blocking readings in scope.'));
|
|
715
779
|
}
|
|
716
780
|
if (blocking.length > 0)
|
|
717
781
|
process.exit(2);
|
|
@@ -732,88 +796,110 @@ program
|
|
|
732
796
|
// skipping the file.
|
|
733
797
|
program
|
|
734
798
|
.command('next-file')
|
|
735
|
-
.description('Audit and return the highest-priority file with
|
|
799
|
+
.description('Audit and return the highest-priority file with readings (file-by-file refactor loop)')
|
|
736
800
|
.option('-p, --path <projectPath>', 'Project root path', process.cwd())
|
|
737
801
|
.option('-c, --config <config>', 'Configuration name')
|
|
738
802
|
.option('--json', 'Output a single JSON object (or {done:true}) to stdout')
|
|
739
803
|
.action(async (options) => {
|
|
740
804
|
try {
|
|
805
|
+
const projectDir = resolve(options.path || process.cwd());
|
|
806
|
+
// R2 — resolve to a live daemon first; fall back in-process when absent.
|
|
807
|
+
// The daemon is an optimisation: a ready daemon serves the current ranking
|
|
808
|
+
// without re-auditing, and an indexing daemon reports its status (R3).
|
|
809
|
+
const { resolveDaemon, readDaemonFindings } = await import('./daemon/resolve.js');
|
|
810
|
+
const daemon = await resolveDaemon(projectDir);
|
|
811
|
+
if (daemon.mode === 'not-ready') {
|
|
812
|
+
reportDaemonIndexing(daemon.state, !!options.json);
|
|
813
|
+
return;
|
|
814
|
+
}
|
|
815
|
+
if (daemon.mode === 'ready') {
|
|
816
|
+
const findings = await readDaemonFindings(daemon.socketPath);
|
|
817
|
+
if (findings && findings.status === 'ready' && findings.staleFiles.length === 0) {
|
|
818
|
+
const { summarizeViolations } = await import('./nextFileIncremental.js');
|
|
819
|
+
printNextFile(findings.violations, summarizeViolations(findings.violations), projectDir, !!options.json);
|
|
820
|
+
return;
|
|
821
|
+
}
|
|
822
|
+
// Daemon fell behind (R4) or vanished — fall through to in-process.
|
|
823
|
+
}
|
|
741
824
|
await initParsers();
|
|
742
825
|
const { violations, summary } = await runNextFile({
|
|
743
826
|
projectRoot: options.path,
|
|
744
827
|
configName: options.config,
|
|
745
828
|
});
|
|
746
|
-
|
|
747
|
-
const ranked = rankFilesByPriority(violations);
|
|
748
|
-
if (ranked.length === 0) {
|
|
749
|
-
if (options.json) {
|
|
750
|
-
process.stdout.write(JSON.stringify({ done: true, summary }, null, 2) + '\n');
|
|
751
|
-
}
|
|
752
|
-
else {
|
|
753
|
-
console.log(chalk.green('\n✓ No findings — nothing left to refactor.'));
|
|
754
|
-
}
|
|
755
|
-
return;
|
|
756
|
-
}
|
|
757
|
-
const top = ranked[0];
|
|
758
|
-
// Every issue on the file, ordered critical → warning → suggestion.
|
|
759
|
-
const ordered = orderFindingsWithinFile(top.violations);
|
|
760
|
-
const projectDir = resolve(options.path || process.cwd());
|
|
761
|
-
const relativize = (filePath) => {
|
|
762
|
-
if (!filePath)
|
|
763
|
-
return '';
|
|
764
|
-
if (filePath.startsWith('/') || filePath.startsWith('\\\\')) {
|
|
765
|
-
const rel = relative(projectDir, filePath);
|
|
766
|
-
if (!rel.startsWith('..') && !isAbsolute(rel))
|
|
767
|
-
return rel;
|
|
768
|
-
}
|
|
769
|
-
return filePath;
|
|
770
|
-
};
|
|
771
|
-
if (options.json) {
|
|
772
|
-
const output = {
|
|
773
|
-
done: false,
|
|
774
|
-
file: relativize(top.file),
|
|
775
|
-
remainingFiles: ranked.length - 1,
|
|
776
|
-
remainingFindings: violations.length - top.count,
|
|
777
|
-
summary,
|
|
778
|
-
findings: ordered.map((v) => ({
|
|
779
|
-
analyzer: v.analyzer || '',
|
|
780
|
-
rule: v.rule || v.type || '',
|
|
781
|
-
severity: v.severity,
|
|
782
|
-
message: v.message,
|
|
783
|
-
file: relativize(v.file || ''),
|
|
784
|
-
line: v.line ?? v.start?.line,
|
|
785
|
-
column: v.column ?? v.start?.column ?? 1,
|
|
786
|
-
endLine: v.end?.line,
|
|
787
|
-
endColumn: v.end?.column,
|
|
788
|
-
enclosingSymbol: v.symbol || v.enclosingFunction || '',
|
|
789
|
-
suggestion: v.suggestion || '',
|
|
790
|
-
details: v.details || '',
|
|
791
|
-
...(v.new !== undefined && { new: v.new }),
|
|
792
|
-
})),
|
|
793
|
-
};
|
|
794
|
-
process.stdout.write(JSON.stringify(output, null, 2) + '\n');
|
|
795
|
-
}
|
|
796
|
-
else {
|
|
797
|
-
console.log(chalk.blue('🔍 Next File to Refactor'));
|
|
798
|
-
console.log(chalk.gray('══════════════════════════════════════════════════'));
|
|
799
|
-
console.log(`\n${chalk.bold(relativize(top.file))} — ${top.count} finding(s), highest severity ${top.maxSeverity}`);
|
|
800
|
-
console.log(chalk.gray(`${ranked.length - 1} more file(s) with findings · ${violations.length - top.count} remaining finding(s)`));
|
|
801
|
-
console.log(chalk.gray('\n── Findings ────────────────────────────────────────'));
|
|
802
|
-
for (const v of ordered) {
|
|
803
|
-
const icon = v.severity === 'critical' ? '🔴' : v.severity === 'warning' ? '🟡' : '🔵';
|
|
804
|
-
console.log(`${icon} ${chalk.bold(relativize(v.file || ''))}${v.line ? `:${v.line}` : ''} [${v.severity}] ${v.rule} — ${v.message}`);
|
|
805
|
-
}
|
|
806
|
-
}
|
|
829
|
+
printNextFile(violations, summary, projectDir, !!options.json);
|
|
807
830
|
}
|
|
808
831
|
catch (error) {
|
|
809
832
|
console.error(chalk.red('Error:'), error);
|
|
810
833
|
process.exit(1);
|
|
811
834
|
}
|
|
812
835
|
});
|
|
836
|
+
/** Rank the violation set and emit the `next-file` result (shared by both paths). */
|
|
837
|
+
function printNextFile(violations, summary, projectDir, json) {
|
|
838
|
+
// Rank files worst-first from the (incrementally-merged) violation set.
|
|
839
|
+
const ranked = rankFilesByPriority(violations);
|
|
840
|
+
if (ranked.length === 0) {
|
|
841
|
+
if (json) {
|
|
842
|
+
process.stdout.write(JSON.stringify({ done: true, summary }, null, 2) + '\n');
|
|
843
|
+
}
|
|
844
|
+
else {
|
|
845
|
+
console.log(chalk.green('\n✓ No readings — nothing left to refactor.'));
|
|
846
|
+
}
|
|
847
|
+
return;
|
|
848
|
+
}
|
|
849
|
+
const top = ranked[0];
|
|
850
|
+
// Every issue on the file, ordered critical → warning → suggestion.
|
|
851
|
+
const ordered = orderFindingsWithinFile(top.violations);
|
|
852
|
+
const relativize = (filePath) => {
|
|
853
|
+
if (!filePath)
|
|
854
|
+
return '';
|
|
855
|
+
if (filePath.startsWith('/') || filePath.startsWith('\\\\')) {
|
|
856
|
+
const rel = relative(projectDir, filePath);
|
|
857
|
+
if (!rel.startsWith('..') && !isAbsolute(rel))
|
|
858
|
+
return rel;
|
|
859
|
+
}
|
|
860
|
+
return filePath;
|
|
861
|
+
};
|
|
862
|
+
if (json) {
|
|
863
|
+
const output = {
|
|
864
|
+
done: false,
|
|
865
|
+
file: relativize(top.file),
|
|
866
|
+
remainingFiles: ranked.length - 1,
|
|
867
|
+
remainingFindings: violations.length - top.count,
|
|
868
|
+
summary,
|
|
869
|
+
findings: ordered.map((v) => ({
|
|
870
|
+
analyzer: v.analyzer || '',
|
|
871
|
+
rule: v.rule,
|
|
872
|
+
severity: v.severity,
|
|
873
|
+
message: v.message,
|
|
874
|
+
file: relativize(v.file || ''),
|
|
875
|
+
line: v.line ?? v.start?.line,
|
|
876
|
+
column: v.column ?? v.start?.column ?? 1,
|
|
877
|
+
endLine: v.end?.line,
|
|
878
|
+
endColumn: v.end?.column,
|
|
879
|
+
enclosingSymbol: v.symbol || v.enclosingFunction || '',
|
|
880
|
+
suggestion: v.suggestion || '',
|
|
881
|
+
details: v.details || '',
|
|
882
|
+
...(v.new !== undefined && { new: v.new }),
|
|
883
|
+
})),
|
|
884
|
+
};
|
|
885
|
+
process.stdout.write(JSON.stringify(output, null, 2) + '\n');
|
|
886
|
+
}
|
|
887
|
+
else {
|
|
888
|
+
console.log(chalk.blue('🔍 Next File to Refactor'));
|
|
889
|
+
console.log(chalk.gray('══════════════════════════════════════════════════'));
|
|
890
|
+
console.log(`\n${chalk.bold(relativize(top.file))} — ${top.count} reading(s), highest severity ${top.maxSeverity}`);
|
|
891
|
+
console.log(chalk.gray(`${ranked.length - 1} more file(s) with readings · ${violations.length - top.count} remaining reading(s)`));
|
|
892
|
+
console.log(chalk.gray('\n── Readings ────────────────────────────────────────'));
|
|
893
|
+
for (const v of ordered) {
|
|
894
|
+
const icon = v.severity === 'critical' ? '🔴' : v.severity === 'warning' ? '🟡' : '🔵';
|
|
895
|
+
console.log(`${icon} ${chalk.bold(relativize(v.file || ''))}${v.line ? `:${v.line}` : ''} [${v.severity}] ${v.rule} — ${v.message}`);
|
|
896
|
+
}
|
|
897
|
+
}
|
|
898
|
+
}
|
|
813
899
|
// Baseline command (Spec 18 R1)
|
|
814
900
|
program
|
|
815
901
|
.command('baseline')
|
|
816
|
-
.description('Snapshot current advisory
|
|
902
|
+
.description('Snapshot current advisory readings as the baseline (excludes invariants)')
|
|
817
903
|
.option('-p, --path <path>', 'Project path', process.cwd())
|
|
818
904
|
.option('--json', 'Output as JSON')
|
|
819
905
|
.action(async (options) => {
|
|
@@ -864,7 +950,7 @@ program
|
|
|
864
950
|
const absorbed = diff?.absorbed ?? newBaseline.entries.length;
|
|
865
951
|
const fixed = diff?.fixed ?? 0;
|
|
866
952
|
const totalKnown = newBaseline.entries.length;
|
|
867
|
-
console.log(chalk.green(`\n✓ Baseline updated: ${absorbed}
|
|
953
|
+
console.log(chalk.green(`\n✓ Baseline updated: ${absorbed} reading${absorbed !== 1 ? 's' : ''} absorbed, ${fixed} fixed, ${totalKnown} total known.`));
|
|
868
954
|
console.log(chalk.gray('Invariants excluded (they always enforce).'));
|
|
869
955
|
if (totalKnown > 0) {
|
|
870
956
|
console.log(chalk.gray(`\nRun ${chalk.cyan('code-audit')} to see your delta view.`));
|
|
@@ -2030,7 +2116,7 @@ ledgerCmd
|
|
|
2030
2116
|
});
|
|
2031
2117
|
ledgerCmd
|
|
2032
2118
|
.command('trends')
|
|
2033
|
-
.description('Compare consecutive full-audit runs and report new vs fixed
|
|
2119
|
+
.description('Compare consecutive full-audit runs and report new vs fixed readings per rule')
|
|
2034
2120
|
.option('--since <runId>', 'Only consider runs after this run ID')
|
|
2035
2121
|
.option('--json', 'Output as JSON')
|
|
2036
2122
|
.action(async (options) => {
|
|
@@ -2948,9 +3034,9 @@ program
|
|
|
2948
3034
|
// tracked count, no state that can drift from the code.
|
|
2949
3035
|
program
|
|
2950
3036
|
.command('outstanding')
|
|
2951
|
-
.description('List outstanding
|
|
3037
|
+
.description('List outstanding readings, re-derived from the codebase (never a stored list)')
|
|
2952
3038
|
.option('-p, --path <path>', 'Path to audit', process.cwd())
|
|
2953
|
-
.option('--json', 'Output
|
|
3039
|
+
.option('--json', 'Output readings as machine-readable JSON')
|
|
2954
3040
|
.action(async (options) => {
|
|
2955
3041
|
try {
|
|
2956
3042
|
await initParsers();
|
|
@@ -2985,7 +3071,7 @@ program
|
|
|
2985
3071
|
filePath = rel;
|
|
2986
3072
|
}
|
|
2987
3073
|
return {
|
|
2988
|
-
rule: v.rule
|
|
3074
|
+
rule: v.rule,
|
|
2989
3075
|
analyzer: v.analyzer || '',
|
|
2990
3076
|
severity: v.severity,
|
|
2991
3077
|
file: filePath,
|
|
@@ -3020,6 +3106,143 @@ function renderBar(value, width) {
|
|
|
3020
3106
|
const color = value > 0.8 ? chalk.green : value > 0.5 ? chalk.yellow : chalk.red;
|
|
3021
3107
|
return color('█'.repeat(filled) + '░'.repeat(empty));
|
|
3022
3108
|
}
|
|
3109
|
+
// ── Daemon command (Spec 50) ────────────────────────────────────────────
|
|
3110
|
+
// The daemon is an optimisation, never a dependency (R2). These commands start,
|
|
3111
|
+
// stop, and inspect it. The hot-path reads — `changed` (the hook gate) and
|
|
3112
|
+
// `next-file` (the refactor loop) — resolve to a live daemon and fall back
|
|
3113
|
+
// in-process when it is absent. `audit` stays in-process on purpose: it emits
|
|
3114
|
+
// full reports (baseline, recommendations, per-category SARIF/HTML) that need
|
|
3115
|
+
// the complete analyzer results, which the daemon does not serve over its
|
|
3116
|
+
// findings face (it serves the flattened violation set).
|
|
3117
|
+
const DAEMON_NOT_READY_EXIT_CODE = 3;
|
|
3118
|
+
/** R3 — a query while the seed is still running: the status is the answer. */
|
|
3119
|
+
function reportDaemonIndexing(state, json) {
|
|
3120
|
+
const progress = state?.progress;
|
|
3121
|
+
const filesIndexed = progress?.filesIndexed ?? 0;
|
|
3122
|
+
const filesTotal = progress?.filesTotal ?? 0;
|
|
3123
|
+
const phase = progress?.phase ?? 'files';
|
|
3124
|
+
const retryAfterMs = state?.retryAfterMs ?? null;
|
|
3125
|
+
const throughputUnknown = state?.throughputUnknown ?? false;
|
|
3126
|
+
if (json) {
|
|
3127
|
+
process.stdout.write(JSON.stringify({
|
|
3128
|
+
status: 'indexing',
|
|
3129
|
+
progress: { filesIndexed, filesTotal, phase },
|
|
3130
|
+
retryAfterMs,
|
|
3131
|
+
throughputUnknown,
|
|
3132
|
+
}, null, 2) + '\n');
|
|
3133
|
+
}
|
|
3134
|
+
else {
|
|
3135
|
+
const retry = retryAfterMs != null
|
|
3136
|
+
? `try again in ~${Math.max(1, Math.round(retryAfterMs / 1000))}s`
|
|
3137
|
+
: 'check back shortly';
|
|
3138
|
+
const phaseDetail = phase === 'files'
|
|
3139
|
+
? `${filesIndexed} of ${filesTotal} files`
|
|
3140
|
+
: `${phase} phase`;
|
|
3141
|
+
console.log(chalk.yellow(`⏳ Daemon indexing — ${phaseDetail}; ${retry}.`));
|
|
3142
|
+
}
|
|
3143
|
+
process.exit(DAEMON_NOT_READY_EXIT_CODE);
|
|
3144
|
+
}
|
|
3145
|
+
const daemonCmd = program
|
|
3146
|
+
.command('daemon')
|
|
3147
|
+
.description('Manage the per-project code-auditor daemon (Spec 50)')
|
|
3148
|
+
.action(() => {
|
|
3149
|
+
console.log(chalk.yellow('Use a daemon subcommand:'));
|
|
3150
|
+
console.log(chalk.gray(' code-audit daemon start [--foreground] Start the daemon for this project'));
|
|
3151
|
+
console.log(chalk.gray(' code-audit daemon stop Ask the daemon to shut down'));
|
|
3152
|
+
console.log(chalk.gray(' code-audit daemon status Show daemon status'));
|
|
3153
|
+
});
|
|
3154
|
+
daemonCmd
|
|
3155
|
+
.command('start')
|
|
3156
|
+
.description('Start the daemon for this project (detached by default)')
|
|
3157
|
+
.option('-p, --path <path>', 'Project root', process.cwd())
|
|
3158
|
+
.option('-c, --config <config>', 'Configuration name')
|
|
3159
|
+
.option('--foreground', 'Run in the foreground (blocking; useful for debugging)')
|
|
3160
|
+
.action(async (options) => {
|
|
3161
|
+
try {
|
|
3162
|
+
const { resolveDaemonSocketPath } = await import('./dataPaths.js');
|
|
3163
|
+
const { isDaemonListening } = await import('./daemon/socketClient.js');
|
|
3164
|
+
const projectRoot = resolve(options.path);
|
|
3165
|
+
const socketPath = resolveDaemonSocketPath(projectRoot);
|
|
3166
|
+
if (await isDaemonListening(socketPath)) {
|
|
3167
|
+
console.log(chalk.green('✓ Daemon already running.'));
|
|
3168
|
+
return;
|
|
3169
|
+
}
|
|
3170
|
+
if (options.foreground) {
|
|
3171
|
+
const { runDaemonForeground } = await import('./daemon/main.js');
|
|
3172
|
+
await runDaemonForeground({ projectRoot, configName: options.config, foreground: true });
|
|
3173
|
+
return;
|
|
3174
|
+
}
|
|
3175
|
+
const { startDaemonDetached } = await import('./daemon/resolve.js');
|
|
3176
|
+
startDaemonDetached(projectRoot, options.config);
|
|
3177
|
+
console.log(chalk.green('✓ Daemon started (detached).'));
|
|
3178
|
+
console.log(chalk.gray(` Socket: ${socketPath}`));
|
|
3179
|
+
console.log(chalk.gray(' It indexes on startup — `code-audit daemon status` to watch.'));
|
|
3180
|
+
}
|
|
3181
|
+
catch (error) {
|
|
3182
|
+
console.error(chalk.red('Error:'), error);
|
|
3183
|
+
process.exit(1);
|
|
3184
|
+
}
|
|
3185
|
+
});
|
|
3186
|
+
daemonCmd
|
|
3187
|
+
.command('stop')
|
|
3188
|
+
.description('Ask the daemon to shut down')
|
|
3189
|
+
.option('-p, --path <path>', 'Project root', process.cwd())
|
|
3190
|
+
.action(async (options) => {
|
|
3191
|
+
try {
|
|
3192
|
+
const { resolveDaemonSocketPath } = await import('./dataPaths.js');
|
|
3193
|
+
const { isDaemonListening } = await import('./daemon/socketClient.js');
|
|
3194
|
+
const { requestDaemonShutdown } = await import('./daemon/resolve.js');
|
|
3195
|
+
const socketPath = resolveDaemonSocketPath(resolve(options.path));
|
|
3196
|
+
if (!(await isDaemonListening(socketPath))) {
|
|
3197
|
+
console.log(chalk.gray('No daemon running.'));
|
|
3198
|
+
return;
|
|
3199
|
+
}
|
|
3200
|
+
await requestDaemonShutdown(socketPath);
|
|
3201
|
+
console.log(chalk.green('✓ Shutdown requested.'));
|
|
3202
|
+
}
|
|
3203
|
+
catch (error) {
|
|
3204
|
+
console.error(chalk.red('Error:'), error);
|
|
3205
|
+
process.exit(1);
|
|
3206
|
+
}
|
|
3207
|
+
});
|
|
3208
|
+
daemonCmd
|
|
3209
|
+
.command('status')
|
|
3210
|
+
.description('Show daemon status')
|
|
3211
|
+
.option('-p, --path <path>', 'Project root', process.cwd())
|
|
3212
|
+
.option('--json', 'Output as JSON')
|
|
3213
|
+
.action(async (options) => {
|
|
3214
|
+
try {
|
|
3215
|
+
const { resolveDaemon } = await import('./daemon/resolve.js');
|
|
3216
|
+
const { resolveDaemonSocketPath } = await import('./dataPaths.js');
|
|
3217
|
+
const projectRoot = resolve(options.path);
|
|
3218
|
+
const resolved = await resolveDaemon(projectRoot);
|
|
3219
|
+
const socketPath = resolveDaemonSocketPath(projectRoot);
|
|
3220
|
+
if (options.json) {
|
|
3221
|
+
process.stdout.write(JSON.stringify({
|
|
3222
|
+
running: resolved.mode !== 'absent',
|
|
3223
|
+
mode: resolved.mode,
|
|
3224
|
+
socketPath,
|
|
3225
|
+
...(resolved.state && { state: resolved.state }),
|
|
3226
|
+
}, null, 2) + '\n');
|
|
3227
|
+
return;
|
|
3228
|
+
}
|
|
3229
|
+
if (resolved.mode === 'absent') {
|
|
3230
|
+
console.log(chalk.gray('No daemon running.'));
|
|
3231
|
+
console.log(chalk.gray('Start one: code-audit daemon start'));
|
|
3232
|
+
return;
|
|
3233
|
+
}
|
|
3234
|
+
if (resolved.mode === 'not-ready') {
|
|
3235
|
+
reportDaemonIndexing(resolved.state, false);
|
|
3236
|
+
return;
|
|
3237
|
+
}
|
|
3238
|
+
console.log(chalk.green('✓ Daemon ready.'));
|
|
3239
|
+
console.log(chalk.gray(` Socket: ${socketPath}`));
|
|
3240
|
+
}
|
|
3241
|
+
catch (error) {
|
|
3242
|
+
console.error(chalk.red('Error:'), error);
|
|
3243
|
+
process.exit(1);
|
|
3244
|
+
}
|
|
3245
|
+
});
|
|
3023
3246
|
// Parse command line arguments
|
|
3024
3247
|
program.parse(process.argv);
|
|
3025
3248
|
// If no command was provided, show help
|
|
@@ -3174,7 +3397,7 @@ async function generateConfigurations(options) {
|
|
|
3174
3397
|
console.log(chalk.blue('\nNext steps:'));
|
|
3175
3398
|
console.log(chalk.gray(' 1. Edit .codeauditor.json to match your codebase conventions'));
|
|
3176
3399
|
console.log(chalk.gray(' 2. Run ') + chalk.cyan('code-audit') + chalk.gray(' to enforce your rules'));
|
|
3177
|
-
console.log(chalk.gray(' 3. Use ') + chalk.cyan('code-audit changed') + chalk.gray(' in your agent hook (gating rules block on new
|
|
3400
|
+
console.log(chalk.gray(' 3. Use ') + chalk.cyan('code-audit changed') + chalk.gray(' in your agent hook (gating rules block on new readings)'));
|
|
3178
3401
|
}
|
|
3179
3402
|
/**
|
|
3180
3403
|
* Interactive rule builder — walks the user through adding rules one at a time.
|