auditor-lambda 0.8.0 → 0.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/audit-code-wrapper-lib.mjs +149 -129
- package/dist/adapters/normalizeExternal.js +6 -3
- package/dist/cli/args.d.ts +0 -1
- package/dist/cli/args.js +0 -6
- package/dist/cli/dispatch.js +3 -2
- package/dist/cli/lineIndex.js +4 -1
- package/dist/cli/mergeAndIngestCommand.d.ts +1 -0
- package/dist/cli/mergeAndIngestCommand.js +219 -0
- package/dist/cli/nextStepCommand.js +5 -1
- package/dist/cli/runToCompletion.d.ts +9 -0
- package/dist/cli/runToCompletion.js +655 -480
- package/dist/cli/statusCommand.d.ts +1 -0
- package/dist/cli/statusCommand.js +113 -0
- package/dist/cli/submitPacketCommand.d.ts +1 -0
- package/dist/cli/submitPacketCommand.js +155 -0
- package/dist/cli/workerResult.d.ts +1 -1
- package/dist/cli/workerRunCommand.d.ts +1 -0
- package/dist/cli/workerRunCommand.js +88 -0
- package/dist/cli.js +14 -563
- package/dist/extractors/analyzers/sql.js +4 -1
- package/dist/extractors/analyzers/treeSitter.js +29 -15
- package/dist/extractors/analyzers/typescript.js +10 -8
- package/dist/extractors/designAssessment.js +43 -24
- package/dist/extractors/graph.js +139 -73
- package/dist/extractors/pathPatterns.js +17 -5
- package/dist/io/runArtifactTypes.d.ts +18 -0
- package/dist/io/runArtifactTypes.js +1 -0
- package/dist/io/runArtifacts.d.ts +2 -18
- package/dist/io/runArtifacts.js +14 -3
- package/dist/mcp/server.js +9 -0
- package/dist/orchestrator/advance.js +37 -22
- package/dist/orchestrator/artifactFreshness.js +2 -2
- package/dist/orchestrator/autoFixExecutor.d.ts +1 -1
- package/dist/orchestrator/autoFixExecutor.js +16 -8
- package/dist/orchestrator/dependencyMap.d.ts +1 -1
- package/dist/orchestrator/dependencyMap.js +7 -1
- package/dist/orchestrator/fileAnchors.js +14 -3
- package/dist/orchestrator/flowCoverage.js +1 -0
- package/dist/orchestrator/flowRequeue.js +4 -1
- package/dist/orchestrator/{internalExecutors.d.ts → ingestionExecutors.d.ts} +0 -6
- package/dist/orchestrator/ingestionExecutors.js +237 -0
- package/dist/orchestrator/intakeExecutors.d.ts +3 -0
- package/dist/orchestrator/intakeExecutors.js +25 -0
- package/dist/orchestrator/planningExecutors.d.ts +4 -0
- package/dist/orchestrator/planningExecutors.js +95 -0
- package/dist/orchestrator/runtimeCommand.js +7 -15
- package/dist/orchestrator/selectiveDeepening/conflict.d.ts +8 -0
- package/dist/orchestrator/selectiveDeepening/conflict.js +71 -0
- package/dist/orchestrator/selectiveDeepening/findingFollowup.d.ts +10 -0
- package/dist/orchestrator/selectiveDeepening/findingFollowup.js +52 -0
- package/dist/orchestrator/selectiveDeepening/highRiskClean.d.ts +7 -0
- package/dist/orchestrator/selectiveDeepening/highRiskClean.js +44 -0
- package/dist/orchestrator/selectiveDeepening/index.d.ts +18 -0
- package/dist/orchestrator/selectiveDeepening/index.js +128 -0
- package/dist/orchestrator/selectiveDeepening/lensVerification.d.ts +12 -0
- package/dist/orchestrator/selectiveDeepening/lensVerification.js +242 -0
- package/dist/orchestrator/selectiveDeepening/runtimeValidation.d.ts +13 -0
- package/dist/orchestrator/selectiveDeepening/runtimeValidation.js +57 -0
- package/dist/orchestrator/selectiveDeepening/shared.d.ts +45 -0
- package/dist/orchestrator/selectiveDeepening/shared.js +128 -0
- package/dist/orchestrator/selectiveDeepening/stewardFollowup.d.ts +6 -0
- package/dist/orchestrator/selectiveDeepening/stewardFollowup.js +72 -0
- package/dist/orchestrator/selectiveDeepening.d.ts +2 -20
- package/dist/orchestrator/selectiveDeepening.js +6 -760
- package/dist/orchestrator/staleness.js +3 -3
- package/dist/orchestrator/structureExecutors.d.ts +5 -0
- package/dist/orchestrator/structureExecutors.js +94 -0
- package/dist/orchestrator/taskBuilder.d.ts +2 -2
- package/dist/orchestrator/taskBuilder.js +101 -82
- package/dist/providers/index.d.ts +7 -0
- package/dist/providers/index.js +14 -95
- package/dist/quota/discoveredLimits.d.ts +1 -0
- package/dist/quota/discoveredLimits.js +7 -1
- package/dist/quota/index.d.ts +0 -2
- package/dist/quota/index.js +1 -2
- package/dist/reporting/workBlocks.js +7 -4
- package/dist/types/reviewPlanning.d.ts +23 -16
- package/dist/validation/auditResults.js +97 -95
- package/dist/validation/sessionConfig.d.ts +2 -2
- package/dist/validation/sessionConfig.js +14 -7
- package/package.json +4 -3
- package/schemas/audit_findings.schema.json +3 -3
- package/schemas/critical_flows.schema.json +3 -2
- package/schemas/dispatch_quota.schema.json +1 -1
- package/schemas/graph_bundle.schema.json +1 -1
- package/schemas/review_packets.schema.json +1 -1
- package/schemas/step_contract.schema.json +80 -0
- package/scripts/postinstall.mjs +19 -2
- package/skills/audit-code/opencode-command-template.txt +3 -3
- package/dist/orchestrator/internalExecutors.js +0 -424
- package/dist/providers/localSubprocessProvider.d.ts +0 -9
- package/dist/providers/localSubprocessProvider.js +0 -18
- package/dist/providers/subprocessTemplateProvider.d.ts +0 -8
- package/dist/providers/subprocessTemplateProvider.js +0 -59
- package/dist/providers/vscodeTaskProvider.d.ts +0 -7
- package/dist/providers/vscodeTaskProvider.js +0 -14
- package/dist/quota/probe.d.ts +0 -10
- package/dist/quota/probe.js +0 -18
|
@@ -1268,14 +1268,11 @@ async function createStoredZipBuffer(sourceDir) {
|
|
|
1268
1268
|
return Buffer.concat([...localParts, centralDirectory, endOfCentralDirectory]);
|
|
1269
1269
|
}
|
|
1270
1270
|
|
|
1271
|
-
|
|
1272
|
-
|
|
1273
|
-
|
|
1274
|
-
|
|
1275
|
-
|
|
1276
|
-
const dxtPath = join(root, '.audit-code', 'install', 'claude-desktop', 'auditor-lambda.dxt');
|
|
1277
|
-
const mcpbPath = join(root, '.audit-code', 'install', 'claude-desktop', 'auditor-lambda.mcpb');
|
|
1278
|
-
|
|
1271
|
+
// Copy the auditor's dist + schemas + skills + wrapper entrypoints (and, best
|
|
1272
|
+
// effort, the resolved @audit-tools/shared dist) into the Claude Desktop bundle
|
|
1273
|
+
// tree. Returns whether the bundle directory already existed (for the
|
|
1274
|
+
// created/updated result marker).
|
|
1275
|
+
async function copyClaudeDesktopBundleFiles(bundleRoot, serverRoot) {
|
|
1279
1276
|
const bundleExisted = await fileExists(bundleRoot);
|
|
1280
1277
|
await mkdir(serverRoot, { recursive: true });
|
|
1281
1278
|
await cp(distEntry.replace(/dist[\\/]index\.js$/, 'dist'), join(bundleRoot, 'dist'), { recursive: true, force: true });
|
|
@@ -1300,9 +1297,13 @@ async function buildClaudeDesktopBundle(root, results) {
|
|
|
1300
1297
|
// @audit-tools/shared not resolvable — bundle will use runtime resolution
|
|
1301
1298
|
}
|
|
1302
1299
|
|
|
1303
|
-
|
|
1300
|
+
return { bundleExisted };
|
|
1301
|
+
}
|
|
1304
1302
|
|
|
1305
|
-
|
|
1303
|
+
// Source for the bundle's server/index.js shim: it spawns the bundled
|
|
1304
|
+
// audit-code.mjs in MCP mode against the user-configured repo root.
|
|
1305
|
+
function renderClaudeDesktopServerEntry() {
|
|
1306
|
+
return [
|
|
1306
1307
|
"import { spawn } from 'node:child_process';",
|
|
1307
1308
|
"import { dirname, join } from 'node:path';",
|
|
1308
1309
|
"import { fileURLToPath } from 'node:url';",
|
|
@@ -1328,10 +1329,12 @@ async function buildClaudeDesktopBundle(root, results) {
|
|
|
1328
1329
|
'});',
|
|
1329
1330
|
'',
|
|
1330
1331
|
].join('\n');
|
|
1332
|
+
}
|
|
1331
1333
|
|
|
1332
|
-
|
|
1333
|
-
|
|
1334
|
-
|
|
1334
|
+
// The DXT/MCPB manifest.json describing the bundled node MCP server and its
|
|
1335
|
+
// Claude Desktop user-config inputs.
|
|
1336
|
+
function buildClaudeDesktopManifest() {
|
|
1337
|
+
return {
|
|
1335
1338
|
manifest_version: '0.3',
|
|
1336
1339
|
name: 'auditor-lambda',
|
|
1337
1340
|
display_name: 'Auditor Lambda',
|
|
@@ -1386,8 +1389,26 @@ async function buildClaudeDesktopBundle(root, results) {
|
|
|
1386
1389
|
},
|
|
1387
1390
|
},
|
|
1388
1391
|
};
|
|
1392
|
+
}
|
|
1393
|
+
|
|
1394
|
+
// Orchestrates the Claude Desktop bundle: copy files, write the server shim and
|
|
1395
|
+
// manifest, then zip into the .dxt / .mcpb archives. Pushes each generated file
|
|
1396
|
+
// into `results`.
|
|
1397
|
+
async function buildClaudeDesktopBundle(root, results) {
|
|
1398
|
+
const bundleRoot = join(root, '.audit-code', 'install', 'claude-desktop', 'bundle');
|
|
1399
|
+
const serverRoot = join(bundleRoot, 'server');
|
|
1400
|
+
const manifestPath = join(bundleRoot, 'manifest.json');
|
|
1401
|
+
const serverEntrypointPath = join(serverRoot, 'index.js');
|
|
1402
|
+
const dxtPath = join(root, '.audit-code', 'install', 'claude-desktop', 'auditor-lambda.dxt');
|
|
1403
|
+
const mcpbPath = join(root, '.audit-code', 'install', 'claude-desktop', 'auditor-lambda.mcpb');
|
|
1389
1404
|
|
|
1390
|
-
|
|
1405
|
+
const { bundleExisted } = await copyClaudeDesktopBundleFiles(bundleRoot, serverRoot);
|
|
1406
|
+
results.push({ path: bundleRoot, mode: bundleExisted ? 'updated' : 'created' });
|
|
1407
|
+
|
|
1408
|
+
results.push(
|
|
1409
|
+
await writeGeneratedMarkdown(serverEntrypointPath, renderClaudeDesktopServerEntry()),
|
|
1410
|
+
);
|
|
1411
|
+
results.push(await writeGeneratedJson(manifestPath, buildClaudeDesktopManifest()));
|
|
1391
1412
|
|
|
1392
1413
|
const archive = await createStoredZipBuffer(bundleRoot);
|
|
1393
1414
|
results.push(await writeGeneratedBinary(dxtPath, archive));
|
|
@@ -2509,21 +2530,15 @@ async function ensureBootstrap(argv) {
|
|
|
2509
2530
|
return payload;
|
|
2510
2531
|
}
|
|
2511
2532
|
|
|
2512
|
-
|
|
2513
|
-
|
|
2514
|
-
|
|
2515
|
-
await assertDirectoryExists(root, 'Target repository root');
|
|
2516
|
-
const profile = getInstallProfile(host);
|
|
2517
|
-
const promptSource = await readFile(promptAssetPath, 'utf8');
|
|
2518
|
-
const skillSource = (await readFile(skillAssetPath, 'utf8')).replace(/\r\n/g, '\n');
|
|
2519
|
-
const { body: promptBody } = splitFrontmatter(promptSource);
|
|
2533
|
+
// Compute the full asset-path map for an install profile. Each per-host path is
|
|
2534
|
+
// gated on its profile flag (null when the host is not part of this profile).
|
|
2535
|
+
function buildInstallAssetPaths(root, profile) {
|
|
2520
2536
|
const installedPromptPath = join(root, '.audit-code', 'install', INSTALLED_PROMPT_FILENAME);
|
|
2521
|
-
const legacyInstalledPromptPath = join(root, '.audit-code', 'install', 'audit-code.prompt.md');
|
|
2522
2537
|
const installedSkillPath = join(root, '.audit-code', 'install', 'SKILL.md');
|
|
2523
2538
|
const installGuidePath = join(root, '.audit-code', 'install', INSTALL_GUIDE_FILENAME);
|
|
2524
2539
|
const installManifestPath = join(root, '.audit-code', 'install', INSTALL_MANIFEST_FILENAME);
|
|
2525
2540
|
const mcpLauncherPath = join(root, '.audit-code', 'install', MCP_LAUNCHER_FILENAME);
|
|
2526
|
-
|
|
2541
|
+
return {
|
|
2527
2542
|
installedPromptPath,
|
|
2528
2543
|
installedSkillPath,
|
|
2529
2544
|
installGuidePath,
|
|
@@ -2579,144 +2594,149 @@ async function installBootstrap(argv, options = {}) {
|
|
|
2579
2594
|
? join(root, '.agent', 'skills', 'audit-code', 'SKILL.md')
|
|
2580
2595
|
: null,
|
|
2581
2596
|
};
|
|
2597
|
+
}
|
|
2582
2598
|
|
|
2599
|
+
// Always-written core assets (installed prompt + skill, shared MCP launcher,
|
|
2600
|
+
// AGENTS/copilot compatibility directive blocks) plus legacy-surface cleanup.
|
|
2601
|
+
async function writeCoreInstallAssets(root, assetPaths, promptSource, skillSource) {
|
|
2583
2602
|
const results = [];
|
|
2603
|
+
const legacyInstalledPromptPath = join(root, '.audit-code', 'install', 'audit-code.prompt.md');
|
|
2584
2604
|
if (await fileExists(legacyInstalledPromptPath)) {
|
|
2585
2605
|
await unlink(legacyInstalledPromptPath).catch(() => {});
|
|
2586
2606
|
}
|
|
2607
|
+
results.push(await writeGeneratedMarkdown(assetPaths.installedPromptPath, promptSource));
|
|
2608
|
+
results.push(await writeGeneratedMarkdown(assetPaths.installedSkillPath, skillSource));
|
|
2587
2609
|
results.push(
|
|
2588
|
-
await writeGeneratedMarkdown(
|
|
2589
|
-
installedPromptPath,
|
|
2590
|
-
promptSource,
|
|
2591
|
-
),
|
|
2592
|
-
);
|
|
2593
|
-
results.push(await writeGeneratedMarkdown(installedSkillPath, skillSource));
|
|
2594
|
-
|
|
2595
|
-
results.push(
|
|
2596
|
-
await writeGeneratedMarkdown(mcpLauncherPath, renderSharedMcpLauncher(repoRoot)),
|
|
2610
|
+
await writeGeneratedMarkdown(assetPaths.mcpLauncherPath, renderSharedMcpLauncher(repoRoot)),
|
|
2597
2611
|
);
|
|
2598
2612
|
|
|
2599
2613
|
const compatibilityBlockTargets = [
|
|
2600
2614
|
assetPaths.agentsInstructionsPath,
|
|
2601
2615
|
assetPaths.copilotInstructionsPath,
|
|
2602
2616
|
].filter(Boolean);
|
|
2603
|
-
|
|
2604
2617
|
for (const targetPath of compatibilityBlockTargets) {
|
|
2605
2618
|
results.push(
|
|
2606
2619
|
await writeManagedMarkdown(
|
|
2607
2620
|
targetPath,
|
|
2608
2621
|
buildInstallDirective(
|
|
2609
|
-
relative(dirname(targetPath), installedPromptPath) || `./.audit-code/install/${INSTALLED_PROMPT_FILENAME}`,
|
|
2622
|
+
relative(dirname(targetPath), assetPaths.installedPromptPath) || `./.audit-code/install/${INSTALLED_PROMPT_FILENAME}`,
|
|
2610
2623
|
),
|
|
2611
2624
|
),
|
|
2612
2625
|
);
|
|
2613
2626
|
}
|
|
2614
2627
|
|
|
2615
2628
|
results.push(...await removeLegacyAuditCodeSurfaceFiles(root));
|
|
2629
|
+
return results;
|
|
2630
|
+
}
|
|
2616
2631
|
|
|
2617
|
-
|
|
2618
|
-
|
|
2619
|
-
|
|
2620
|
-
|
|
2621
|
-
|
|
2622
|
-
|
|
2623
|
-
|
|
2624
|
-
|
|
2625
|
-
|
|
2626
|
-
|
|
2627
|
-
|
|
2628
|
-
|
|
2629
|
-
|
|
2630
|
-
|
|
2631
|
-
|
|
2632
|
-
|
|
2633
|
-
|
|
2634
|
-
|
|
2635
|
-
|
|
2636
|
-
|
|
2637
|
-
|
|
2638
|
-
|
|
2639
|
-
|
|
2632
|
+
async function writeCodexAssets(assetPaths, promptSource, skillSource, root) {
|
|
2633
|
+
return [
|
|
2634
|
+
await writeGeneratedMarkdown(assetPaths.codexSkillPath, skillSource),
|
|
2635
|
+
await writeGeneratedMarkdown(assetPaths.codexPromptPath, promptSource),
|
|
2636
|
+
await writeGeneratedMarkdown(assetPaths.codexMcpSetupPath, renderCodexMcpSetupGuide(root)),
|
|
2637
|
+
await writeGeneratedMarkdown(assetPaths.codexAutomationRecipePath, renderCodexAutomationRecipe()),
|
|
2638
|
+
];
|
|
2639
|
+
}
|
|
2640
|
+
|
|
2641
|
+
// Builds the Claude Desktop DXT/MCPB bundle (mutating assetPaths with the
|
|
2642
|
+
// produced bundle paths) and writes the project template + remote connector.
|
|
2643
|
+
async function writeClaudeDesktopAssets(assetPaths, root) {
|
|
2644
|
+
const results = [];
|
|
2645
|
+
const claudeDesktopBundle = await buildClaudeDesktopBundle(root, results);
|
|
2646
|
+
assetPaths.claudeDesktopDxtPath = claudeDesktopBundle.dxtPath;
|
|
2647
|
+
assetPaths.claudeDesktopMcpbPath = claudeDesktopBundle.mcpbPath;
|
|
2648
|
+
results.push(
|
|
2649
|
+
await writeGeneratedMarkdown(
|
|
2650
|
+
assetPaths.claudeDesktopProjectTemplatePath,
|
|
2651
|
+
renderClaudeDesktopProjectTemplate(),
|
|
2652
|
+
),
|
|
2653
|
+
);
|
|
2654
|
+
results.push(
|
|
2655
|
+
await writeGeneratedJson(
|
|
2656
|
+
assetPaths.claudeDesktopRemoteConnectorPath,
|
|
2657
|
+
JSON.parse(renderClaudeDesktopRemoteConnectorTemplate()),
|
|
2658
|
+
),
|
|
2659
|
+
);
|
|
2660
|
+
return results;
|
|
2661
|
+
}
|
|
2662
|
+
|
|
2663
|
+
async function writeOpenCodeAssets(assetPaths, root) {
|
|
2664
|
+
return [
|
|
2665
|
+
await writeMergedGeneratedJson(
|
|
2666
|
+
assetPaths.opencodeConfigPath,
|
|
2667
|
+
'OpenCode project config',
|
|
2668
|
+
(existing) => buildMergedOpenCodeProjectConfig(existing, root),
|
|
2669
|
+
),
|
|
2670
|
+
];
|
|
2671
|
+
}
|
|
2672
|
+
|
|
2673
|
+
async function writeVSCodeAssets(assetPaths, promptBody) {
|
|
2674
|
+
return [
|
|
2675
|
+
await writeGeneratedMarkdown(
|
|
2676
|
+
assetPaths.vscodePromptPath,
|
|
2677
|
+
renderPromptFile(
|
|
2678
|
+
{
|
|
2679
|
+
name: 'audit-code',
|
|
2680
|
+
description: 'Autonomous local loop code auditing',
|
|
2681
|
+
agent: 'auditor',
|
|
2682
|
+
},
|
|
2683
|
+
promptBody,
|
|
2640
2684
|
),
|
|
2641
|
-
)
|
|
2642
|
-
|
|
2685
|
+
),
|
|
2686
|
+
await writeGeneratedMarkdown(assetPaths.vscodeAgentPath, renderVSCodeAgentFile()),
|
|
2687
|
+
await writeMergedGeneratedJson(
|
|
2688
|
+
assetPaths.vscodeMcpConfigPath,
|
|
2689
|
+
'VS Code MCP config',
|
|
2690
|
+
buildMergedVSCodeMcpConfig,
|
|
2691
|
+
),
|
|
2692
|
+
];
|
|
2693
|
+
}
|
|
2694
|
+
|
|
2695
|
+
async function writeAntigravityAssets(assetPaths, promptBody, skillSource, root) {
|
|
2696
|
+
return [
|
|
2697
|
+
await writeGeneratedMarkdown(
|
|
2698
|
+
assetPaths.antigravityPlanningGuidePath,
|
|
2699
|
+
renderAntigravityPlanningGuide(root),
|
|
2700
|
+
),
|
|
2701
|
+
await writeGeneratedMarkdown(assetPaths.geminiCommandPath, renderGeminiCommandToml(promptBody)),
|
|
2702
|
+
await writeGeneratedMarkdown(assetPaths.antigravitySkillPath, skillSource),
|
|
2703
|
+
];
|
|
2704
|
+
}
|
|
2705
|
+
|
|
2706
|
+
async function installBootstrap(argv, options = {}) {
|
|
2707
|
+
const host = (getFlag(argv, '--host') ?? DEFAULT_INSTALL_HOST).toLowerCase();
|
|
2708
|
+
const root = resolve(getFlag(argv, '--root') ?? '.');
|
|
2709
|
+
await assertDirectoryExists(root, 'Target repository root');
|
|
2710
|
+
const profile = getInstallProfile(host);
|
|
2711
|
+
const promptSource = await readFile(promptAssetPath, 'utf8');
|
|
2712
|
+
const skillSource = (await readFile(skillAssetPath, 'utf8')).replace(/\r\n/g, '\n');
|
|
2713
|
+
const { body: promptBody } = splitFrontmatter(promptSource);
|
|
2714
|
+
const assetPaths = buildInstallAssetPaths(root, profile);
|
|
2715
|
+
const {
|
|
2716
|
+
installedPromptPath,
|
|
2717
|
+
installedSkillPath,
|
|
2718
|
+
installGuidePath,
|
|
2719
|
+
installManifestPath,
|
|
2720
|
+
mcpLauncherPath,
|
|
2721
|
+
} = assetPaths;
|
|
2643
2722
|
|
|
2723
|
+
const results = [];
|
|
2724
|
+
results.push(...await writeCoreInstallAssets(root, assetPaths, promptSource, skillSource));
|
|
2725
|
+
|
|
2726
|
+
if (profile.writeCodex) {
|
|
2727
|
+
results.push(...await writeCodexAssets(assetPaths, promptSource, skillSource, root));
|
|
2728
|
+
}
|
|
2644
2729
|
if (profile.writeClaudeDesktop) {
|
|
2645
|
-
|
|
2646
|
-
assetPaths.claudeDesktopDxtPath = claudeDesktopBundle.dxtPath;
|
|
2647
|
-
assetPaths.claudeDesktopMcpbPath = claudeDesktopBundle.mcpbPath;
|
|
2648
|
-
results.push(
|
|
2649
|
-
await writeGeneratedMarkdown(
|
|
2650
|
-
assetPaths.claudeDesktopProjectTemplatePath,
|
|
2651
|
-
renderClaudeDesktopProjectTemplate(),
|
|
2652
|
-
),
|
|
2653
|
-
);
|
|
2654
|
-
results.push(
|
|
2655
|
-
await writeGeneratedJson(
|
|
2656
|
-
assetPaths.claudeDesktopRemoteConnectorPath,
|
|
2657
|
-
JSON.parse(renderClaudeDesktopRemoteConnectorTemplate()),
|
|
2658
|
-
),
|
|
2659
|
-
);
|
|
2730
|
+
results.push(...await writeClaudeDesktopAssets(assetPaths, root));
|
|
2660
2731
|
}
|
|
2661
|
-
|
|
2662
2732
|
if (profile.writeOpenCode) {
|
|
2663
|
-
results.push(
|
|
2664
|
-
await writeMergedGeneratedJson(
|
|
2665
|
-
assetPaths.opencodeConfigPath,
|
|
2666
|
-
'OpenCode project config',
|
|
2667
|
-
(existing) => buildMergedOpenCodeProjectConfig(existing, root),
|
|
2668
|
-
),
|
|
2669
|
-
);
|
|
2733
|
+
results.push(...await writeOpenCodeAssets(assetPaths, root));
|
|
2670
2734
|
}
|
|
2671
|
-
|
|
2672
2735
|
if (profile.writeVSCode) {
|
|
2673
|
-
results.push(
|
|
2674
|
-
await writeGeneratedMarkdown(
|
|
2675
|
-
assetPaths.vscodePromptPath,
|
|
2676
|
-
renderPromptFile(
|
|
2677
|
-
{
|
|
2678
|
-
name: 'audit-code',
|
|
2679
|
-
description: 'Autonomous local loop code auditing',
|
|
2680
|
-
agent: 'auditor',
|
|
2681
|
-
},
|
|
2682
|
-
promptBody,
|
|
2683
|
-
),
|
|
2684
|
-
),
|
|
2685
|
-
);
|
|
2686
|
-
results.push(
|
|
2687
|
-
await writeGeneratedMarkdown(
|
|
2688
|
-
assetPaths.vscodeAgentPath,
|
|
2689
|
-
renderVSCodeAgentFile(),
|
|
2690
|
-
),
|
|
2691
|
-
);
|
|
2692
|
-
results.push(
|
|
2693
|
-
await writeMergedGeneratedJson(
|
|
2694
|
-
assetPaths.vscodeMcpConfigPath,
|
|
2695
|
-
'VS Code MCP config',
|
|
2696
|
-
buildMergedVSCodeMcpConfig,
|
|
2697
|
-
),
|
|
2698
|
-
);
|
|
2736
|
+
results.push(...await writeVSCodeAssets(assetPaths, promptBody));
|
|
2699
2737
|
}
|
|
2700
|
-
|
|
2701
2738
|
if (profile.writeAntigravity) {
|
|
2702
|
-
results.push(
|
|
2703
|
-
await writeGeneratedMarkdown(
|
|
2704
|
-
assetPaths.antigravityPlanningGuidePath,
|
|
2705
|
-
renderAntigravityPlanningGuide(root),
|
|
2706
|
-
),
|
|
2707
|
-
);
|
|
2708
|
-
results.push(
|
|
2709
|
-
await writeGeneratedMarkdown(
|
|
2710
|
-
assetPaths.geminiCommandPath,
|
|
2711
|
-
renderGeminiCommandToml(promptBody),
|
|
2712
|
-
),
|
|
2713
|
-
);
|
|
2714
|
-
results.push(
|
|
2715
|
-
await writeGeneratedMarkdown(
|
|
2716
|
-
assetPaths.antigravitySkillPath,
|
|
2717
|
-
skillSource,
|
|
2718
|
-
),
|
|
2719
|
-
);
|
|
2739
|
+
results.push(...await writeAntigravityAssets(assetPaths, promptBody, skillSource, root));
|
|
2720
2740
|
}
|
|
2721
2741
|
|
|
2722
2742
|
const hostGuidance = buildHostCatalog({
|
|
@@ -1,10 +1,13 @@
|
|
|
1
1
|
export function normalizeGenericExternalResults(tool, items) {
|
|
2
|
+
const valid = items.filter((item) => item.path && item.summary);
|
|
3
|
+
const dropped = items.length - valid.length;
|
|
4
|
+
if (dropped > 0) {
|
|
5
|
+
process.stderr.write(`[audit-code] normalizeExternal: dropped ${dropped}/${items.length} ${tool} finding(s) missing path or summary\n`);
|
|
6
|
+
}
|
|
2
7
|
return {
|
|
3
8
|
tool,
|
|
4
9
|
generated_at: new Date().toISOString(),
|
|
5
|
-
results:
|
|
6
|
-
.filter((item) => item.path && item.summary)
|
|
7
|
-
.map((item, index) => ({
|
|
10
|
+
results: valid.map((item, index) => ({
|
|
8
11
|
id: item.id ?? `${tool}-${index + 1}`,
|
|
9
12
|
category: item.category ?? "unknown",
|
|
10
13
|
severity: item.severity ?? "unknown",
|
package/dist/cli/args.d.ts
CHANGED
|
@@ -51,7 +51,6 @@ export declare function getTimeoutMs(argv: string[], sessionConfig: SessionConfi
|
|
|
51
51
|
export declare function getExplicitProvider(argv: string[]): string | undefined;
|
|
52
52
|
export declare function getHostModel(argv: string[]): string | null;
|
|
53
53
|
export declare function getHostMaxActiveSubagents(argv: string[]): number | null;
|
|
54
|
-
export declare function getQuotaProbeMode(argv: string[], sessionConfig: SessionConfig): "auto" | "never" | "force";
|
|
55
54
|
export declare function resolveRunProviderName(argv: string[], sessionConfig: SessionConfig): string;
|
|
56
55
|
export declare function chunkArray<T>(arr: T[], size: number): T[][];
|
|
57
56
|
export declare function getUiMode(argv: string[], fallback?: UiMode): UiMode;
|
package/dist/cli/args.js
CHANGED
|
@@ -185,12 +185,6 @@ export function getHostModel(argv) {
|
|
|
185
185
|
export function getHostMaxActiveSubagents(argv) {
|
|
186
186
|
return parsePositiveIntegerFlag(argv, "--host-max-active-subagents") ?? null;
|
|
187
187
|
}
|
|
188
|
-
export function getQuotaProbeMode(argv, sessionConfig) {
|
|
189
|
-
const raw = getFlag(argv, "--quota-probe") ?? sessionConfig.quota?.probe ?? "auto";
|
|
190
|
-
if (raw === "auto" || raw === "never" || raw === "force")
|
|
191
|
-
return raw;
|
|
192
|
-
return "auto";
|
|
193
|
-
}
|
|
194
188
|
export function resolveRunProviderName(argv, sessionConfig) {
|
|
195
189
|
return resolveFreshSessionProviderName(getExplicitProvider(argv), sessionConfig);
|
|
196
190
|
}
|
package/dist/cli/dispatch.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { mkdir, readFile, writeFile } from "node:fs/promises";
|
|
2
2
|
import { existsSync } from "node:fs";
|
|
3
3
|
import { isAbsolute, join, relative, resolve } from "node:path";
|
|
4
|
-
import { isFileMissingError, readJsonFile, writeJsonFile } from "@audit-tools/shared";
|
|
4
|
+
import { isFileMissingError, readJsonFile, writeJsonFile, DEFAULT_EMPIRICAL_HALF_LIFE_HOURS, } from "@audit-tools/shared";
|
|
5
5
|
import { buildQuotaSource } from "@audit-tools/shared/quota/compositeQuotaSource";
|
|
6
6
|
import { loadArtifactBundle } from "../io/artifacts.js";
|
|
7
7
|
import { orderTasksForPacketReview, buildReviewPackets, sizeIndexFromManifest, } from "../orchestrator/reviewPackets.js";
|
|
@@ -480,7 +480,8 @@ export async function prepareDispatchArtifacts(params) {
|
|
|
480
480
|
?? null;
|
|
481
481
|
const dispatchCachedLimits = await lookupDiscoveredLimits(quotaProviderKey).catch(() => null);
|
|
482
482
|
const discoveredLimits = mergeDiscoveredLimits(providerLimits, dispatchCachedLimits);
|
|
483
|
-
const halfLifeHours = sessionConfig.quota?.empirical_half_life_hours ??
|
|
483
|
+
const halfLifeHours = sessionConfig.quota?.empirical_half_life_hours ??
|
|
484
|
+
DEFAULT_EMPIRICAL_HALF_LIFE_HOURS;
|
|
484
485
|
const quotaSource = buildQuotaSource({ halfLifeHours });
|
|
485
486
|
const quotaSourceSnapshot = await quotaSource.queryCurrentUsage(quotaProviderKey).catch(() => null);
|
|
486
487
|
const waveSchedule = scheduleWave({
|
package/dist/cli/lineIndex.js
CHANGED
|
@@ -3,9 +3,12 @@ import { countLines } from "./args.js";
|
|
|
3
3
|
// Line-count helpers extracted from cli.ts. Pure functions over the repo
|
|
4
4
|
// manifest / task file paths — used to annotate audit tasks with per-file line
|
|
5
5
|
// counts and to build line indexes for prompt rendering.
|
|
6
|
+
// How many files to read concurrently when counting lines, bounding open file
|
|
7
|
+
// descriptors so a large repo manifest does not exhaust the fd limit.
|
|
8
|
+
const LINE_COUNT_BATCH_SIZE = 25;
|
|
6
9
|
export async function buildLineIndex(root, repoManifest) {
|
|
7
10
|
const entries = [];
|
|
8
|
-
const batchSize =
|
|
11
|
+
const batchSize = LINE_COUNT_BATCH_SIZE;
|
|
9
12
|
for (let i = 0; i < repoManifest.files.length; i += batchSize) {
|
|
10
13
|
const batch = repoManifest.files.slice(i, i + batchSize);
|
|
11
14
|
const results = await Promise.all(batch.map(async (file) => {
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function cmdMergeAndIngest(argv: string[]): Promise<void>;
|
|
@@ -0,0 +1,219 @@
|
|
|
1
|
+
import { readFile, readdir } from "node:fs/promises";
|
|
2
|
+
import { join, resolve } from "node:path";
|
|
3
|
+
import { isFileMissingError, readJsonFile, writeJsonFile } from "@audit-tools/shared";
|
|
4
|
+
import { validateAuditResults } from "../validation/auditResults.js";
|
|
5
|
+
import { runAuditStep } from "./auditStep.js";
|
|
6
|
+
import { DISPATCH_RESULT_MAP_FILENAME, ACTIVE_DISPATCH_FILENAME, loadDispatchResultMap, entriesByTaskId, buildPendingAuditTasks, } from "./dispatch.js";
|
|
7
|
+
import { addFileLineCountHints } from "./lineIndex.js";
|
|
8
|
+
import { isCanonicalResultFilename, getArtifactsDir, getFlag } from "./args.js";
|
|
9
|
+
import { buildWorkerResult } from "./workerResult.js";
|
|
10
|
+
export async function cmdMergeAndIngest(argv) {
|
|
11
|
+
const runId = getFlag(argv, "--run-id");
|
|
12
|
+
if (!runId)
|
|
13
|
+
throw new Error("merge-and-ingest requires --run-id <run_id>");
|
|
14
|
+
const artifactsDir = getArtifactsDir(argv);
|
|
15
|
+
const runDir = join(artifactsDir, "runs", runId);
|
|
16
|
+
const taskResultsDir = join(runDir, "task-results");
|
|
17
|
+
const auditResultsPath = join(runDir, "audit-results.json");
|
|
18
|
+
const taskPath = join(runDir, "task.json");
|
|
19
|
+
const tasksPath = join(runDir, "pending-audit-tasks.json");
|
|
20
|
+
const workerTask = await readJsonFile(taskPath);
|
|
21
|
+
const resultMap = await loadDispatchResultMap(runDir);
|
|
22
|
+
if (!resultMap) {
|
|
23
|
+
throw new Error(`No ${DISPATCH_RESULT_MAP_FILENAME} found for run ${runId}; run prepare-dispatch first.`);
|
|
24
|
+
}
|
|
25
|
+
let allTasks = [];
|
|
26
|
+
try {
|
|
27
|
+
allTasks = await readJsonFile(tasksPath);
|
|
28
|
+
}
|
|
29
|
+
catch { /* may not exist */ }
|
|
30
|
+
const entryByTaskId = entriesByTaskId(resultMap.entries);
|
|
31
|
+
if (entryByTaskId.size !== resultMap.entries.length) {
|
|
32
|
+
throw new Error(`Dispatch result map for run ${runId} contains duplicate task entries.`);
|
|
33
|
+
}
|
|
34
|
+
const expectedPaths = new Set(resultMap.entries.map((entry) => resolve(entry.result_path)));
|
|
35
|
+
let files;
|
|
36
|
+
try {
|
|
37
|
+
files = (await readdir(taskResultsDir)).filter(f => f.endsWith(".json")).sort();
|
|
38
|
+
}
|
|
39
|
+
catch {
|
|
40
|
+
files = [];
|
|
41
|
+
}
|
|
42
|
+
const passing = [];
|
|
43
|
+
const failing = [];
|
|
44
|
+
const seenTaskIds = new Set();
|
|
45
|
+
let spuriousFileCount = 0;
|
|
46
|
+
const fallbackByTaskId = new Map();
|
|
47
|
+
for (const filename of files) {
|
|
48
|
+
const filePath = resolve(join(taskResultsDir, filename));
|
|
49
|
+
if (expectedPaths.has(filePath))
|
|
50
|
+
continue;
|
|
51
|
+
// Not part of this round's plan. Still read it so a current task can be
|
|
52
|
+
// recovered by task_id (e.g. a subagent wrote a valid result under a
|
|
53
|
+
// non-assigned name).
|
|
54
|
+
try {
|
|
55
|
+
const raw = await readFile(filePath, "utf8");
|
|
56
|
+
const parsed = JSON.parse(raw);
|
|
57
|
+
if (parsed && typeof parsed === "object" && !Array.isArray(parsed)) {
|
|
58
|
+
const tid = typeof parsed.task_id === "string"
|
|
59
|
+
? String(parsed.task_id) : undefined;
|
|
60
|
+
if (tid && !fallbackByTaskId.has(tid)) {
|
|
61
|
+
fallbackByTaskId.set(tid, parsed);
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
catch { /* not parseable — skip */ }
|
|
66
|
+
// Only genuinely stray files are "spurious". Canonical per-task result files
|
|
67
|
+
// (<stem>_<digest>.json) left by prior deepening rounds in the same
|
|
68
|
+
// task-results/ dir are legitimate and must not inflate the count or bury
|
|
69
|
+
// the real stray-file signal (3 -> 191 over a run before this fix).
|
|
70
|
+
if (!isCanonicalResultFilename(filename)) {
|
|
71
|
+
spuriousFileCount++;
|
|
72
|
+
process.stderr.write(`[merge-and-ingest] Warning: unexpected file in task-results/: ${filename}\n`);
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
for (const task of allTasks) {
|
|
76
|
+
const entry = entryByTaskId.get(task.task_id);
|
|
77
|
+
if (!entry) {
|
|
78
|
+
failing.push({
|
|
79
|
+
task_id: task.task_id,
|
|
80
|
+
errors: ["Missing dispatch result-map entry for assigned task."],
|
|
81
|
+
});
|
|
82
|
+
continue;
|
|
83
|
+
}
|
|
84
|
+
const filePath = entry.result_path;
|
|
85
|
+
let obj;
|
|
86
|
+
try {
|
|
87
|
+
obj = JSON.parse(await readFile(filePath, "utf8"));
|
|
88
|
+
}
|
|
89
|
+
catch (e) {
|
|
90
|
+
if (isFileMissingError(e)) {
|
|
91
|
+
const fallback = fallbackByTaskId.get(task.task_id);
|
|
92
|
+
if (fallback) {
|
|
93
|
+
process.stderr.write(`[merge-and-ingest] Recovered result for '${task.task_id}' from unexpected file (matched by task_id)\n`);
|
|
94
|
+
obj = fallback;
|
|
95
|
+
}
|
|
96
|
+
else {
|
|
97
|
+
failing.push({
|
|
98
|
+
task_id: task.task_id,
|
|
99
|
+
errors: ["Missing audit result for assigned task."],
|
|
100
|
+
});
|
|
101
|
+
continue;
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
else {
|
|
105
|
+
failing.push({ task_id: task.task_id, errors: [`Invalid JSON: ${e.message}`] });
|
|
106
|
+
continue;
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
const record = obj && typeof obj === "object" && !Array.isArray(obj)
|
|
110
|
+
? obj
|
|
111
|
+
: undefined;
|
|
112
|
+
const taskId = typeof record?.task_id === "string"
|
|
113
|
+
? String(record.task_id) : undefined;
|
|
114
|
+
const resultErrors = [];
|
|
115
|
+
if (taskId) {
|
|
116
|
+
if (seenTaskIds.has(taskId)) {
|
|
117
|
+
resultErrors.push(`Duplicate audit result for assigned task '${taskId}'.`);
|
|
118
|
+
}
|
|
119
|
+
else {
|
|
120
|
+
seenTaskIds.add(taskId);
|
|
121
|
+
}
|
|
122
|
+
if (taskId !== task.task_id) {
|
|
123
|
+
resultErrors.push(`Result file is assigned to '${task.task_id}' but contains task_id '${taskId}'.`);
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
const issues = validateAuditResults([obj], [task], { lineIndex: task.file_line_counts ?? {} });
|
|
127
|
+
resultErrors.push(...issues
|
|
128
|
+
.filter(i => i.severity === "error")
|
|
129
|
+
.map(i => i.message));
|
|
130
|
+
if (resultErrors.length === 0) {
|
|
131
|
+
passing.push(obj);
|
|
132
|
+
}
|
|
133
|
+
else {
|
|
134
|
+
failing.push({ task_id: taskId ?? task.task_id, errors: resultErrors });
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
await writeJsonFile(auditResultsPath, passing);
|
|
138
|
+
const failedTasksPath = join(runDir, "failed-tasks.json");
|
|
139
|
+
if (failing.length > 0) {
|
|
140
|
+
await writeJsonFile(failedTasksPath, failing);
|
|
141
|
+
}
|
|
142
|
+
if (passing.length === 0 && failing.length > 0) {
|
|
143
|
+
throw new Error(`All ${failing.length} assigned task result(s) were missing or invalid; blocked before ingestion. See ${failedTasksPath}`);
|
|
144
|
+
}
|
|
145
|
+
const findingCount = passing.reduce((sum, result) => sum + result.findings.length, 0);
|
|
146
|
+
let result = null;
|
|
147
|
+
if (passing.length > 0) {
|
|
148
|
+
result = await runAuditStep({
|
|
149
|
+
root: workerTask.repo_root,
|
|
150
|
+
artifactsDir,
|
|
151
|
+
preferredExecutor: "result_ingestion_executor",
|
|
152
|
+
auditResultsPath,
|
|
153
|
+
});
|
|
154
|
+
const updatedPendingTasks = await addFileLineCountHints(workerTask.repo_root, buildPendingAuditTasks(result.updated_bundle));
|
|
155
|
+
await writeJsonFile(tasksPath, updatedPendingTasks);
|
|
156
|
+
}
|
|
157
|
+
const activeDispatchPath = join(artifactsDir, ACTIVE_DISPATCH_FILENAME);
|
|
158
|
+
try {
|
|
159
|
+
const dispatch = await readJsonFile(activeDispatchPath);
|
|
160
|
+
if (dispatch.run_id === runId) {
|
|
161
|
+
dispatch.status = failing.length > 0 ? "active" : "merged";
|
|
162
|
+
await writeJsonFile(activeDispatchPath, dispatch);
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
catch { /* no active dispatch file — skip */ }
|
|
166
|
+
let retryDispatchPath = null;
|
|
167
|
+
if (failing.length > 0) {
|
|
168
|
+
const failedTaskIds = new Set(failing.map((f) => f.task_id));
|
|
169
|
+
const failedPacketIds = [
|
|
170
|
+
...new Set(resultMap.entries
|
|
171
|
+
.filter((e) => failedTaskIds.has(e.task_id))
|
|
172
|
+
.map((e) => e.packet_id)),
|
|
173
|
+
];
|
|
174
|
+
const retryDispatch = {
|
|
175
|
+
run_id: runId,
|
|
176
|
+
retry_packet_ids: failedPacketIds,
|
|
177
|
+
failed_task_count: failing.length,
|
|
178
|
+
accepted_task_count: passing.length,
|
|
179
|
+
};
|
|
180
|
+
retryDispatchPath = join(runDir, "retry-dispatch.json");
|
|
181
|
+
await writeJsonFile(retryDispatchPath, retryDispatch);
|
|
182
|
+
process.stderr.write(`[merge-and-ingest] ${passing.length} accepted, ${failing.length} failed. ` +
|
|
183
|
+
`Retry packets: ${failedPacketIds.join(", ")}\n`);
|
|
184
|
+
}
|
|
185
|
+
const status = failing.length > 0
|
|
186
|
+
? "partial"
|
|
187
|
+
: (result?.progress_made ? "completed" : "no_progress");
|
|
188
|
+
const workerResult = buildWorkerResult({
|
|
189
|
+
runId,
|
|
190
|
+
obligationId: workerTask.obligation_id,
|
|
191
|
+
status: failing.length > 0 ? "no_progress" : (result?.progress_made ? "completed" : "no_progress"),
|
|
192
|
+
progressMade: result?.progress_made ?? false,
|
|
193
|
+
selectedExecutor: result?.selected_executor ?? null,
|
|
194
|
+
artifactsWritten: result?.artifacts_written ?? [],
|
|
195
|
+
summary: result?.progress_summary ?? `${failing.length} task(s) failed`,
|
|
196
|
+
nextLikelyStep: result?.next_likely_step ?? null,
|
|
197
|
+
errors: [],
|
|
198
|
+
});
|
|
199
|
+
await writeJsonFile(workerTask.result_path, workerResult);
|
|
200
|
+
console.log(JSON.stringify({
|
|
201
|
+
run_id: runId,
|
|
202
|
+
status,
|
|
203
|
+
accepted_count: passing.length,
|
|
204
|
+
rejected_count: failing.length,
|
|
205
|
+
spurious_file_count: spuriousFileCount,
|
|
206
|
+
finding_count: findingCount,
|
|
207
|
+
audit_results_path: auditResultsPath,
|
|
208
|
+
...(retryDispatchPath ? { retry_dispatch_path: retryDispatchPath } : {}),
|
|
209
|
+
...(result ? {
|
|
210
|
+
selected_executor: workerResult.selected_executor,
|
|
211
|
+
progress_made: workerResult.progress_made,
|
|
212
|
+
progress_summary: workerResult.summary,
|
|
213
|
+
next_likely_step: workerResult.next_likely_step,
|
|
214
|
+
} : {}),
|
|
215
|
+
}, null, 2));
|
|
216
|
+
if (failing.length > 0) {
|
|
217
|
+
process.exitCode = 2;
|
|
218
|
+
}
|
|
219
|
+
}
|
|
@@ -71,7 +71,11 @@ async function runDeterministicForNextStep(params) {
|
|
|
71
71
|
if (taskFiles.size > 0) {
|
|
72
72
|
const integrity = await checkFileIntegrity(params.root, bundle.repo_manifest, [...taskFiles]);
|
|
73
73
|
if (!integrity.is_clean) {
|
|
74
|
-
|
|
74
|
+
// Route this diagnostic OFF stdout: cmdNextStep emits the step
|
|
75
|
+
// contract as the sole stdout payload via console.log(JSON.stringify),
|
|
76
|
+
// so a console.log here would corrupt the JSON-on-stdout contract.
|
|
77
|
+
process.stderr.write(`[audit-code] nextStep: integrity check — ${integrity.changed_files.length} changed, ` +
|
|
78
|
+
`${integrity.missing_files.length} missing, ${integrity.io_errors.length} io-error(s); re-running intake.\n`);
|
|
75
79
|
await advanceAudit(bundle, { root: params.root, preferredExecutor: "intake_executor", opentoken: params.opentoken });
|
|
76
80
|
continue;
|
|
77
81
|
}
|