auditor-lambda 0.3.41 → 0.5.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/dist/cli/dispatch.js +5 -1
- package/dist/cli/prompts.d.ts +19 -0
- package/dist/cli/prompts.js +95 -0
- package/dist/cli/steps.d.ts +1 -1
- package/dist/cli.js +287 -7
- package/dist/extractors/analyzers/css.d.ts +2 -0
- package/dist/extractors/analyzers/css.js +101 -0
- package/dist/extractors/analyzers/html.d.ts +2 -0
- package/dist/extractors/analyzers/html.js +92 -0
- package/dist/extractors/analyzers/merge.d.ts +14 -0
- package/dist/extractors/analyzers/merge.js +85 -0
- package/dist/extractors/analyzers/python.d.ts +2 -0
- package/dist/extractors/analyzers/python.js +104 -0
- package/dist/extractors/analyzers/registry.d.ts +33 -0
- package/dist/extractors/analyzers/registry.js +100 -0
- package/dist/extractors/analyzers/resourceUrl.d.ts +7 -0
- package/dist/extractors/analyzers/resourceUrl.js +25 -0
- package/dist/extractors/analyzers/sql.d.ts +2 -0
- package/dist/extractors/analyzers/sql.js +19 -0
- package/dist/extractors/analyzers/treeSitter.d.ts +34 -0
- package/dist/extractors/analyzers/treeSitter.js +111 -0
- package/dist/extractors/analyzers/types.d.ts +53 -0
- package/dist/extractors/analyzers/types.js +1 -0
- package/dist/extractors/analyzers/typescript.d.ts +2 -0
- package/dist/extractors/analyzers/typescript.js +257 -0
- package/dist/extractors/disposition.js +8 -1
- package/dist/extractors/graph.d.ts +1 -0
- package/dist/extractors/graph.js +167 -1
- package/dist/extractors/graphPythonImports.d.ts +15 -0
- package/dist/extractors/graphPythonImports.js +36 -0
- package/dist/extractors/pathPatterns.d.ts +6 -0
- package/dist/extractors/pathPatterns.js +8 -0
- package/dist/io/artifacts.d.ts +12 -1
- package/dist/io/artifacts.js +12 -0
- package/dist/orchestrator/advance.d.ts +20 -0
- package/dist/orchestrator/advance.js +61 -2
- package/dist/orchestrator/dependencyMap.js +27 -0
- package/dist/orchestrator/edgeReasoning.d.ts +39 -0
- package/dist/orchestrator/edgeReasoning.js +125 -0
- package/dist/orchestrator/executors.js +11 -1
- package/dist/orchestrator/graphEnrichmentExecutor.d.ts +29 -0
- package/dist/orchestrator/graphEnrichmentExecutor.js +196 -0
- package/dist/orchestrator/internalExecutors.d.ts +10 -1
- package/dist/orchestrator/internalExecutors.js +89 -11
- package/dist/orchestrator/localCommands.js +6 -25
- package/dist/orchestrator/nextStep.js +2 -0
- package/dist/orchestrator/reviewPackets.d.ts +37 -4
- package/dist/orchestrator/reviewPackets.js +93 -46
- package/dist/orchestrator/runtimeValidation.js +4 -31
- package/dist/orchestrator/scope.d.ts +62 -0
- package/dist/orchestrator/scope.js +227 -0
- package/dist/orchestrator/state.js +2 -0
- package/dist/reporting/synthesis.d.ts +37 -2
- package/dist/reporting/synthesis.js +95 -16
- package/dist/reporting/synthesisNarrativePrompt.d.ts +7 -0
- package/dist/reporting/synthesisNarrativePrompt.js +60 -0
- package/dist/reporting/workBlocks.d.ts +2 -10
- package/dist/supervisor/sessionConfig.d.ts +8 -1
- package/dist/supervisor/sessionConfig.js +22 -1
- package/dist/types/analyzerCapability.d.ts +16 -0
- package/dist/types/analyzerCapability.js +1 -0
- package/dist/types/auditScope.d.ts +43 -0
- package/dist/types/auditScope.js +14 -0
- package/dist/types/synthesisNarrative.d.ts +7 -0
- package/dist/types/synthesisNarrative.js +5 -0
- package/dist/types.d.ts +2 -19
- package/dist/validation/artifacts.js +9 -0
- package/dist/validation/sessionConfig.js +24 -1
- package/package.json +4 -2
- package/schemas/analyzer_capability.schema.json +47 -0
- package/schemas/audit_findings.schema.json +141 -0
- package/schemas/finding.schema.json +2 -1
- package/schemas/graph_bundle.schema.json +5 -0
- package/schemas/scope.schema.json +46 -0
package/dist/cli/dispatch.js
CHANGED
|
@@ -3,7 +3,7 @@ import { existsSync } from "node:fs";
|
|
|
3
3
|
import { isAbsolute, join, relative, resolve } from "node:path";
|
|
4
4
|
import { isFileMissingError, readJsonFile, writeJsonFile } from "@audit-tools/shared";
|
|
5
5
|
import { loadArtifactBundle } from "../io/artifacts.js";
|
|
6
|
-
import { orderTasksForPacketReview, buildReviewPackets } from "../orchestrator/reviewPackets.js";
|
|
6
|
+
import { orderTasksForPacketReview, buildReviewPackets, sizeIndexFromManifest, } from "../orchestrator/reviewPackets.js";
|
|
7
7
|
import { buildFileAnchorSummary } from "../orchestrator/fileAnchors.js";
|
|
8
8
|
import { resolveFreshSessionProviderName } from "../providers/index.js";
|
|
9
9
|
import { loadSessionConfig } from "../supervisor/sessionConfig.js";
|
|
@@ -166,6 +166,7 @@ export function buildPendingAuditTasks(bundle) {
|
|
|
166
166
|
return orderTasksForPacketReview(pendingTasks, {
|
|
167
167
|
graphBundle: bundle.graph_bundle,
|
|
168
168
|
lineIndex,
|
|
169
|
+
sizeIndex: sizeIndexFromManifest(bundle.repo_manifest),
|
|
169
170
|
});
|
|
170
171
|
}
|
|
171
172
|
export async function prepareDispatchArtifacts(params) {
|
|
@@ -205,13 +206,16 @@ export async function prepareDispatchArtifacts(params) {
|
|
|
205
206
|
? tasks.filter((task) => !priorResultTaskIds.has(task.task_id))
|
|
206
207
|
: tasks;
|
|
207
208
|
const lineIndex = Object.fromEntries(dispatchTasks.flatMap((task) => Object.entries(task.file_line_counts ?? {})));
|
|
209
|
+
const sizeIndex = sizeIndexFromManifest(bundle.repo_manifest);
|
|
208
210
|
const orderedTasks = orderTasksForPacketReview(dispatchTasks, {
|
|
209
211
|
graphBundle: bundle.graph_bundle,
|
|
210
212
|
lineIndex,
|
|
213
|
+
sizeIndex,
|
|
211
214
|
});
|
|
212
215
|
const packets = buildReviewPackets(orderedTasks, {
|
|
213
216
|
graphBundle: bundle.graph_bundle,
|
|
214
217
|
lineIndex,
|
|
218
|
+
sizeIndex,
|
|
215
219
|
});
|
|
216
220
|
const tasksById = new Map(orderedTasks.map((task) => [task.task_id, task]));
|
|
217
221
|
const resultPathByTaskId = new Map(orderedTasks.map((task) => [
|
package/dist/cli/prompts.d.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import type { ActiveReviewRun } from "../supervisor/operatorHandoff.js";
|
|
2
|
+
import type { AnalyzerPlanEntry } from "../extractors/analyzers/types.js";
|
|
2
3
|
export declare function nextStepCommand(root: string, artifactsDir: string): string;
|
|
3
4
|
export declare function mergeAndIngestCommand(artifactsDir: string, runId: string): string;
|
|
4
5
|
export declare function renderDispatchReviewPrompt(params: {
|
|
@@ -14,5 +15,23 @@ export declare function renderSingleTaskFallbackStepPrompt(params: {
|
|
|
14
15
|
singleTaskPromptPath: string;
|
|
15
16
|
activeReviewRun: ActiveReviewRun;
|
|
16
17
|
}): string;
|
|
18
|
+
export declare function renderEdgeReasoningStepPrompt(params: {
|
|
19
|
+
basePrompt: string;
|
|
20
|
+
resultsPath: string;
|
|
21
|
+
continueCommand: string;
|
|
22
|
+
contentHash: string;
|
|
23
|
+
}): string;
|
|
24
|
+
export declare function renderEdgeReasoningDispatchPrompt(params: {
|
|
25
|
+
promptPath: string;
|
|
26
|
+
resultsPath: string;
|
|
27
|
+
continueCommand: string;
|
|
28
|
+
contentHash: string;
|
|
29
|
+
candidateCount: number;
|
|
30
|
+
}): string;
|
|
17
31
|
export declare function renderPresentReportPrompt(finalReportPath: string): string;
|
|
32
|
+
export declare function renderAnalyzerInstallPrompt(params: {
|
|
33
|
+
unresolved: AnalyzerPlanEntry[];
|
|
34
|
+
decisionsPath: string;
|
|
35
|
+
continueCommand: string;
|
|
36
|
+
}): string;
|
|
18
37
|
export declare function renderBlockedStepPrompt(reason: string): string;
|
package/dist/cli/prompts.js
CHANGED
|
@@ -102,6 +102,62 @@ export function renderSingleTaskFallbackStepPrompt(params) {
|
|
|
102
102
|
"",
|
|
103
103
|
].join("\n");
|
|
104
104
|
}
|
|
105
|
+
export function renderEdgeReasoningStepPrompt(params) {
|
|
106
|
+
return [
|
|
107
|
+
params.basePrompt,
|
|
108
|
+
"",
|
|
109
|
+
"## Results path",
|
|
110
|
+
"",
|
|
111
|
+
'Write the JSON object ({"rewrites":[{"from":"...","to":"...","kind":"...","reason":"..."}]}) to:',
|
|
112
|
+
"",
|
|
113
|
+
` ${params.resultsPath}`,
|
|
114
|
+
"",
|
|
115
|
+
`Cache key (edge-set content hash): ${params.contentHash}.`,
|
|
116
|
+
"If you already produced rewrites for this exact key, you may reuse them instead of regenerating.",
|
|
117
|
+
"",
|
|
118
|
+
`Then run: ${params.continueCommand}`,
|
|
119
|
+
"",
|
|
120
|
+
"Read and follow only the new step prompt returned by that command.",
|
|
121
|
+
"",
|
|
122
|
+
].join("\n");
|
|
123
|
+
}
|
|
124
|
+
export function renderEdgeReasoningDispatchPrompt(params) {
|
|
125
|
+
return [
|
|
126
|
+
"# audit-code edge reasoning (subagent dispatch)",
|
|
127
|
+
"",
|
|
128
|
+
`The dependency graph has ${params.candidateCount} low-confidence edge(s) whose`,
|
|
129
|
+
"machine-generated `reason` text can be clarified. This is a single, bounded,",
|
|
130
|
+
"optional pass: it only rewrites the `reason` string of those edges — it never",
|
|
131
|
+
"adds, removes, re-targets, or re-weights an edge.",
|
|
132
|
+
"",
|
|
133
|
+
"Dispatch exactly ONE subagent (via the `task` tool or equivalent). Hand it this",
|
|
134
|
+
"prompt file path; do not load the file into this orchestrator context:",
|
|
135
|
+
"",
|
|
136
|
+
` ${params.promptPath}`,
|
|
137
|
+
"",
|
|
138
|
+
"Subagent prompt shape:",
|
|
139
|
+
"",
|
|
140
|
+
" Read and follow the edge-reasoning instructions in: <prompt path above>",
|
|
141
|
+
"",
|
|
142
|
+
'The subagent must write its JSON result ({"rewrites":[...]}) to:',
|
|
143
|
+
"",
|
|
144
|
+
` ${params.resultsPath}`,
|
|
145
|
+
"",
|
|
146
|
+
`Cache key (edge-set content hash): ${params.contentHash}.`,
|
|
147
|
+
"If you hold a cached result for this exact key from a previous run, you may write",
|
|
148
|
+
"it to the results path directly instead of dispatching a subagent.",
|
|
149
|
+
"",
|
|
150
|
+
"**File access pre-approval:** if your host supports per-subagent file access",
|
|
151
|
+
`restrictions, allow the subagent to read ${params.promptPath} and write ${params.resultsPath}.`,
|
|
152
|
+
"",
|
|
153
|
+
"After the subagent writes the result, run exactly:",
|
|
154
|
+
"",
|
|
155
|
+
` ${params.continueCommand}`,
|
|
156
|
+
"",
|
|
157
|
+
"Read and follow only the new step prompt returned by that command.",
|
|
158
|
+
"",
|
|
159
|
+
].join("\n");
|
|
160
|
+
}
|
|
105
161
|
export function renderPresentReportPrompt(finalReportPath) {
|
|
106
162
|
return [
|
|
107
163
|
"# audit-code present report",
|
|
@@ -116,6 +172,45 @@ export function renderPresentReportPrompt(finalReportPath) {
|
|
|
116
172
|
"",
|
|
117
173
|
].join("\n");
|
|
118
174
|
}
|
|
175
|
+
export function renderAnalyzerInstallPrompt(params) {
|
|
176
|
+
const analyzerLines = params.unresolved.flatMap((entry) => [
|
|
177
|
+
`- **${entry.id}** — needs \`${entry.dependency ?? entry.id}\`; ${entry.supportedCount} in-scope file(s) would be analyzed.`,
|
|
178
|
+
]);
|
|
179
|
+
const exampleObject = `{ ${params.unresolved
|
|
180
|
+
.map((entry) => `"${entry.id}": "ephemeral"`)
|
|
181
|
+
.join(", ")} }`;
|
|
182
|
+
return [
|
|
183
|
+
"# audit-code analyzer install",
|
|
184
|
+
"",
|
|
185
|
+
"The deterministic regex graph is built. These optional language analyzers can",
|
|
186
|
+
"produce a richer graph (real module resolution, inheritance, and a call graph),",
|
|
187
|
+
"but their compiler dependency is not installed in the audited repo:",
|
|
188
|
+
"",
|
|
189
|
+
...analyzerLines,
|
|
190
|
+
"",
|
|
191
|
+
"Choose how to resolve each one and write a JSON object of `{ \"<analyzer-id>\": <setting> }`",
|
|
192
|
+
"to the decisions path below. Valid settings:",
|
|
193
|
+
"",
|
|
194
|
+
"- `ephemeral` — install into a shared, version-keyed cache (never touches this project); compile once, reuse across audits.",
|
|
195
|
+
"- `permanent` — same as `ephemeral` but a durable opt-in recorded in session config.",
|
|
196
|
+
"- `skip` — do not run this analyzer; keep the regex floor.",
|
|
197
|
+
"",
|
|
198
|
+
"Default if you are unsure or cannot install: choose `skip`. The audit proceeds either way.",
|
|
199
|
+
"",
|
|
200
|
+
"## Decisions path",
|
|
201
|
+
"",
|
|
202
|
+
"Write your choices to:",
|
|
203
|
+
"",
|
|
204
|
+
` ${params.decisionsPath}`,
|
|
205
|
+
"",
|
|
206
|
+
`Example: ${exampleObject}`,
|
|
207
|
+
"",
|
|
208
|
+
`Then run: ${params.continueCommand}`,
|
|
209
|
+
"",
|
|
210
|
+
"Read and follow only the new step prompt returned by that command.",
|
|
211
|
+
"",
|
|
212
|
+
].join("\n");
|
|
213
|
+
}
|
|
119
214
|
export function renderBlockedStepPrompt(reason) {
|
|
120
215
|
return [
|
|
121
216
|
"# audit-code blocked",
|
package/dist/cli/steps.d.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import type { StepStatus } from "@audit-tools/shared";
|
|
2
2
|
import type { AccessDeclaration } from "../types/workerSession.js";
|
|
3
3
|
export declare const STEP_CONTRACT_VERSION = "audit-code-step/v1alpha1";
|
|
4
|
-
export type StepKind = "dispatch_review" | "single_task_fallback" | "design_review" | "present_report" | "blocked";
|
|
4
|
+
export type StepKind = "dispatch_review" | "single_task_fallback" | "design_review" | "analyzer_install" | "edge_reasoning" | "edge_reasoning_dispatch" | "synthesis_narrative" | "present_report" | "blocked";
|
|
5
5
|
export interface StepArtifact {
|
|
6
6
|
contract_version: typeof STEP_CONTRACT_VERSION;
|
|
7
7
|
step_kind: StepKind;
|
package/dist/cli.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { mkdir, readFile, readdir, rename, rm, unlink } from "node:fs/promises";
|
|
1
|
+
import { mkdir, readFile, readdir, rename, rm, unlink, writeFile } from "node:fs/promises";
|
|
2
2
|
import { homedir } from "node:os";
|
|
3
3
|
import { basename, dirname, join, resolve } from "node:path";
|
|
4
4
|
import { fileURLToPath } from "node:url";
|
|
@@ -11,7 +11,7 @@ import { buildFlowCoverage } from "./orchestrator/flowCoverage.js";
|
|
|
11
11
|
import { buildRuntimeValidationTasks, } from "./orchestrator/runtimeValidation.js";
|
|
12
12
|
import { initializeCoverageFromPlan } from "./orchestrator/planning.js";
|
|
13
13
|
import { loadArtifactBundle, writeCoreArtifacts, promoteFinalAuditReport, } from "./io/artifacts.js";
|
|
14
|
-
import { isFileMissingError, readJsonFile, writeJsonFile, prefixValidationIssues } from "@audit-tools/shared";
|
|
14
|
+
import { isFileMissingError, readJsonFile, writeJsonFile, prefixValidationIssues, RunLogger } from "@audit-tools/shared";
|
|
15
15
|
import { validateArtifactBundle } from "./validation/artifacts.js";
|
|
16
16
|
import { validateAuditResults, formatAuditResultIssues, } from "./validation/auditResults.js";
|
|
17
17
|
import { validateConfiguredProviderEnvironment, validateSessionConfig, } from "./validation/sessionConfig.js";
|
|
@@ -20,21 +20,26 @@ import { deriveAuditState } from "./orchestrator/state.js";
|
|
|
20
20
|
import { advanceAudit } from "./orchestrator/advance.js";
|
|
21
21
|
import { checkFileIntegrity } from "./orchestrator/fileIntegrity.js";
|
|
22
22
|
import { decideNextStep } from "./orchestrator/nextStep.js";
|
|
23
|
+
import { collectLowConfidenceEdges, buildEdgeReasoningPrompt, edgeReasoningContentHash, } from "./orchestrator/edgeReasoning.js";
|
|
23
24
|
import { renderDesignReviewPrompt } from "./orchestrator/designReviewPrompt.js";
|
|
25
|
+
import { renderSynthesisNarrativePrompt } from "./reporting/synthesisNarrativePrompt.js";
|
|
24
26
|
import { createFreshSessionProvider, resolveFreshSessionProviderName, } from "./providers/index.js";
|
|
25
27
|
import { appendRunLedgerEntry, loadRunLedger } from "./supervisor/runLedger.js";
|
|
26
28
|
import { buildAuditCodeHandoff, writeAuditCodeHandoffArtifacts, } from "./supervisor/operatorHandoff.js";
|
|
27
|
-
import { getSessionConfigPath, loadSessionConfig, readSessionConfigFile, } from "./supervisor/sessionConfig.js";
|
|
29
|
+
import { getSessionConfigPath, loadSessionConfig, persistAnalyzerSettings, readSessionConfigFile, } from "./supervisor/sessionConfig.js";
|
|
30
|
+
import { resolveAnalyzerPlan, needsInstallDecision, } from "./extractors/analyzers/registry.js";
|
|
31
|
+
import { buildPathLookup } from "./extractors/graph.js";
|
|
32
|
+
import { buildDispositionMap } from "./extractors/disposition.js";
|
|
28
33
|
import { clearDispatchFiles, buildRunId, ensureSupervisorDirs, getRunPaths, writeDispatchBatchFiles, writeWorkerTaskFiles, } from "./io/runArtifacts.js";
|
|
29
34
|
import { renderWorkerPrompt } from "./prompts/renderWorkerPrompt.js";
|
|
30
|
-
import { estimateTaskGroupTokens, } from "./orchestrator/reviewPackets.js";
|
|
35
|
+
import { estimateTaskGroupTokens, sizeIndexFromManifest, } from "./orchestrator/reviewPackets.js";
|
|
31
36
|
import { LOCAL_SUBPROCESS_PROVIDER_NAME } from "./providers/constants.js";
|
|
32
37
|
import { runAuditCodeMcpServer } from "./mcp/server.js";
|
|
33
38
|
import { scheduleWave, buildProviderModelKey, readQuotaState, recordWaveOutcome, resolveLimits, resolveHostActiveSubagentLimit, probeProvider, computeMaxSafeConcurrency, getQuotaStatePath, detectRateLimitError, computeCooldownUntil, runSlidingWindow, LearnedQuotaSource, CompositeQuotaSource, lookupDiscoveredLimits, updateDiscoveredLimits, mergeDiscoveredLimits, getHeaderExtractorForProvider, setQuotaStateDir, } from "./quota/index.js";
|
|
34
39
|
// Re-exports from extracted modules
|
|
35
40
|
export { resolveHostDispatchCapability, DIRECT_CLI_DEFAULTS, getFlag, hasFlag, getOptionalBooleanFlag, getArtifactsDir, getRootDir, getBatchResultsDir, getMaxRuns, getAgentBatchSize, getParallelWorkers, getTimeoutMs, chunkArray, getUiMode, looksLikeCliFlag, countLines, warnIfNotGitRepo, } from "./cli/args.js";
|
|
36
41
|
import { DIRECT_CLI_DEFAULTS, getFlag, hasFlag, getOptionalBooleanFlag, fromBase64Url, renderCommand, summarizeLaunchExit, taskResultPath, readStdinText, getArtifactsDir, getRootDir, warnIfNotGitRepo, getBatchResultsDir, getMaxRuns, getAgentBatchSize, getParallelWorkers, getTimeoutMs, getExplicitProvider, getHostModel, getHostMaxActiveSubagents, getQuotaProbeMode, resolveRunProviderName, chunkArray, getUiMode, looksLikeCliFlag, resolveHostDispatchCapability, countLines, listBatchResultFiles, } from "./cli/args.js";
|
|
37
|
-
import { nextStepCommand, mergeAndIngestCommand, renderDispatchReviewPrompt, renderSingleTaskFallbackStepPrompt, renderPresentReportPrompt, renderBlockedStepPrompt, } from "./cli/prompts.js";
|
|
42
|
+
import { nextStepCommand, mergeAndIngestCommand, renderDispatchReviewPrompt, renderSingleTaskFallbackStepPrompt, renderPresentReportPrompt, renderAnalyzerInstallPrompt, renderEdgeReasoningStepPrompt, renderEdgeReasoningDispatchPrompt, renderBlockedStepPrompt, } from "./cli/prompts.js";
|
|
38
43
|
import { writeCurrentStep, } from "./cli/steps.js";
|
|
39
44
|
import { WORKER_RESULT_CONTRACT_VERSION, buildWorkerResult, persistWorkerRunArtifacts, isWorkerResult, buildWorkerFailureBlocker, formatAuditResultValidationError, } from "./cli/workerResult.js";
|
|
40
45
|
import { DISPATCH_RESULT_MAP_FILENAME, ACTIVE_DISPATCH_FILENAME, resolveRunScopedArg, loadDispatchResultMap, entriesByTaskId, buildPendingAuditTasks, prepareDispatchArtifacts, } from "./cli/dispatch.js";
|
|
@@ -313,9 +318,15 @@ async function maybeArchiveLegacyPendingResults(auditResultsPath) {
|
|
|
313
318
|
}
|
|
314
319
|
async function runAuditStep(options) {
|
|
315
320
|
const bundle = await loadArtifactBundle(options.artifactsDir);
|
|
321
|
+
const runLogger = new RunLogger(join(options.artifactsDir, "run.log.jsonl"), {
|
|
322
|
+
enabled: options.runLog ?? true,
|
|
323
|
+
});
|
|
316
324
|
const lineIndex = bundle.repo_manifest
|
|
317
325
|
? await buildLineIndex(options.root, bundle.repo_manifest)
|
|
318
326
|
: undefined;
|
|
327
|
+
const sizeIndex = bundle.repo_manifest
|
|
328
|
+
? sizeIndexFromManifest(bundle.repo_manifest)
|
|
329
|
+
: undefined;
|
|
319
330
|
if (looksLikeCliFlag(options.auditResultsPath)) {
|
|
320
331
|
throw new Error(`Invalid audit results path '${options.auditResultsPath}'. This looks like a CLI flag rather than a file path.`);
|
|
321
332
|
}
|
|
@@ -343,14 +354,27 @@ async function runAuditStep(options) {
|
|
|
343
354
|
const externalAnalyzerResults = options.externalAnalyzerPath
|
|
344
355
|
? await readJsonFile(options.externalAnalyzerPath)
|
|
345
356
|
: undefined;
|
|
357
|
+
const narrativeResults = options.narrativeResultsPath
|
|
358
|
+
? await readJsonFile(options.narrativeResultsPath)
|
|
359
|
+
: undefined;
|
|
360
|
+
const edgeReasoningResults = options.edgeReasoningResultsPath
|
|
361
|
+
? await readJsonFile(options.edgeReasoningResultsPath)
|
|
362
|
+
: undefined;
|
|
346
363
|
const result = await advanceAudit(bundle, {
|
|
347
364
|
root: options.root,
|
|
348
365
|
lineIndex,
|
|
366
|
+
sizeIndex,
|
|
349
367
|
auditResults: auditResults,
|
|
350
368
|
runtimeValidationUpdates,
|
|
351
369
|
externalAnalyzerResults,
|
|
370
|
+
narrativeResults,
|
|
371
|
+
edgeReasoningResults,
|
|
372
|
+
analyzers: options.analyzers,
|
|
373
|
+
graphLlmEdgeReasoning: options.graphLlmEdgeReasoning,
|
|
374
|
+
since: options.since,
|
|
352
375
|
preferredExecutor: options.preferredExecutor,
|
|
353
376
|
opentoken: options.opentoken,
|
|
377
|
+
runLogger,
|
|
354
378
|
});
|
|
355
379
|
await writeCoreArtifacts(options.artifactsDir, result.updated_bundle);
|
|
356
380
|
const archivedPendingResults = await maybeArchiveLegacyPendingResults(options.auditResultsPath);
|
|
@@ -555,7 +579,11 @@ async function cmdAdvanceAudit(argv) {
|
|
|
555
579
|
auditResultsPath: getFlag(argv, "--results"),
|
|
556
580
|
runtimeUpdatesPath: getFlag(argv, "--updates"),
|
|
557
581
|
externalAnalyzerPath,
|
|
582
|
+
analyzers: sessionConfig.analyzers,
|
|
583
|
+
graphLlmEdgeReasoning: sessionConfig.graph?.llm_edge_reasoning,
|
|
584
|
+
since: getFlag(argv, "--since"),
|
|
558
585
|
opentoken: sessionConfig.opentoken?.enabled,
|
|
586
|
+
runLog: sessionConfig.observability?.run_log,
|
|
559
587
|
});
|
|
560
588
|
if (result.selected_executor !== "agent") {
|
|
561
589
|
await clearDispatchFiles(artifactsDir);
|
|
@@ -579,6 +607,7 @@ async function cmdAdvanceAudit(argv) {
|
|
|
579
607
|
}
|
|
580
608
|
async function runDeterministicForNextStep(params) {
|
|
581
609
|
let lastSummary = "";
|
|
610
|
+
let analyzers = params.analyzers;
|
|
582
611
|
for (let index = 0; index < params.maxRuns; index++) {
|
|
583
612
|
const bundle = await loadArtifactBundle(params.artifactsDir);
|
|
584
613
|
const decision = decideNextStep(bundle);
|
|
@@ -621,6 +650,89 @@ async function runDeterministicForNextStep(params) {
|
|
|
621
650
|
}
|
|
622
651
|
}
|
|
623
652
|
}
|
|
653
|
+
if (decision.selected_executor === "graph_enrichment_executor") {
|
|
654
|
+
const includedFiles = bundle.repo_manifest
|
|
655
|
+
? [
|
|
656
|
+
...new Set(buildPathLookup(bundle.repo_manifest, buildDispositionMap(bundle.file_disposition)).values()),
|
|
657
|
+
]
|
|
658
|
+
: [];
|
|
659
|
+
const plan = resolveAnalyzerPlan(params.root, analyzers, includedFiles);
|
|
660
|
+
const unresolved = plan.filter(needsInstallDecision);
|
|
661
|
+
if (unresolved.length > 0) {
|
|
662
|
+
const decisionsPath = join(params.artifactsDir, "incoming", "analyzer-decisions.json");
|
|
663
|
+
let decisions;
|
|
664
|
+
try {
|
|
665
|
+
decisions = await readJsonFile(decisionsPath);
|
|
666
|
+
}
|
|
667
|
+
catch (error) {
|
|
668
|
+
if (!isFileMissingError(error))
|
|
669
|
+
throw error;
|
|
670
|
+
}
|
|
671
|
+
if (decisions && typeof decisions === "object") {
|
|
672
|
+
const settings = {};
|
|
673
|
+
for (const [id, value] of Object.entries(decisions)) {
|
|
674
|
+
if (value === "ephemeral" ||
|
|
675
|
+
value === "permanent" ||
|
|
676
|
+
value === "skip" ||
|
|
677
|
+
value === "repo" ||
|
|
678
|
+
value === "auto") {
|
|
679
|
+
settings[id] = value;
|
|
680
|
+
}
|
|
681
|
+
}
|
|
682
|
+
if (Object.keys(settings).length > 0) {
|
|
683
|
+
const merged = await persistAnalyzerSettings(params.artifactsDir, settings);
|
|
684
|
+
analyzers = merged.analyzers;
|
|
685
|
+
}
|
|
686
|
+
await unlink(decisionsPath).catch(() => { });
|
|
687
|
+
continue;
|
|
688
|
+
}
|
|
689
|
+
return {
|
|
690
|
+
kind: "analyzer_install",
|
|
691
|
+
state,
|
|
692
|
+
bundle,
|
|
693
|
+
unresolved,
|
|
694
|
+
};
|
|
695
|
+
}
|
|
696
|
+
// Phase 4B — optional edge-reasoning producing turn. Once analyzer installs
|
|
697
|
+
// are resolved, if the flag is on and the floor carries low-confidence
|
|
698
|
+
// (< 0.65) edges, emit one bounded host turn (subagent dispatch or a single
|
|
699
|
+
// host step) to produce reason rewrites, then re-run. The enrichment
|
|
700
|
+
// executor applies the host-supplied rewrites in the SAME advanceAudit call
|
|
701
|
+
// that merges analyzer edges and writes analyzer_capability, so graph_bundle
|
|
702
|
+
// and its marker stay revision-consistent (no staleness loop). Flag off or
|
|
703
|
+
// no candidates → fall through and run the executor with no rewrites.
|
|
704
|
+
if (params.graphLlmEdgeReasoning === true && bundle.graph_bundle) {
|
|
705
|
+
const candidates = collectLowConfidenceEdges(bundle.graph_bundle);
|
|
706
|
+
if (candidates.length > 0) {
|
|
707
|
+
const edgeReasoningResultsPath = join(params.artifactsDir, "incoming", "edge-reasoning.json");
|
|
708
|
+
let edgeReasoningResults;
|
|
709
|
+
try {
|
|
710
|
+
edgeReasoningResults = await readJsonFile(edgeReasoningResultsPath);
|
|
711
|
+
}
|
|
712
|
+
catch (error) {
|
|
713
|
+
if (!isFileMissingError(error))
|
|
714
|
+
throw error;
|
|
715
|
+
}
|
|
716
|
+
if (edgeReasoningResults) {
|
|
717
|
+
await runAuditStep({
|
|
718
|
+
root: params.root,
|
|
719
|
+
artifactsDir: params.artifactsDir,
|
|
720
|
+
analyzers,
|
|
721
|
+
graphLlmEdgeReasoning: true,
|
|
722
|
+
edgeReasoningResultsPath,
|
|
723
|
+
since: params.since,
|
|
724
|
+
opentoken: params.opentoken,
|
|
725
|
+
});
|
|
726
|
+
await unlink(edgeReasoningResultsPath).catch(() => { });
|
|
727
|
+
continue;
|
|
728
|
+
}
|
|
729
|
+
return { kind: "edge_reasoning", state, bundle, candidates };
|
|
730
|
+
}
|
|
731
|
+
}
|
|
732
|
+
// No undecided installs (and no pending edge reasoning): fall through to run
|
|
733
|
+
// the executor below (it installs for ephemeral/permanent, uses repo/cache,
|
|
734
|
+
// skips the rest).
|
|
735
|
+
}
|
|
624
736
|
if (decision.selected_executor === "design_review") {
|
|
625
737
|
const findingsPath = join(params.artifactsDir, "incoming", "design-review-findings.json");
|
|
626
738
|
let reviewFindings;
|
|
@@ -647,6 +759,36 @@ async function runDeterministicForNextStep(params) {
|
|
|
647
759
|
bundle,
|
|
648
760
|
};
|
|
649
761
|
}
|
|
762
|
+
if (decision.selected_executor === "synthesis_narrative_executor") {
|
|
763
|
+
const narrativePath = join(params.artifactsDir, "incoming", "synthesis-narrative.json");
|
|
764
|
+
let narrativeResults;
|
|
765
|
+
try {
|
|
766
|
+
narrativeResults = await readJsonFile(narrativePath);
|
|
767
|
+
}
|
|
768
|
+
catch (error) {
|
|
769
|
+
if (!isFileMissingError(error))
|
|
770
|
+
throw error;
|
|
771
|
+
}
|
|
772
|
+
if (narrativeResults) {
|
|
773
|
+
await runAuditStep({
|
|
774
|
+
root: params.root,
|
|
775
|
+
artifactsDir: params.artifactsDir,
|
|
776
|
+
preferredExecutor: "synthesis_narrative_executor",
|
|
777
|
+
narrativeResultsPath: narrativePath,
|
|
778
|
+
opentoken: params.opentoken,
|
|
779
|
+
});
|
|
780
|
+
await unlink(narrativePath).catch(() => { });
|
|
781
|
+
continue;
|
|
782
|
+
}
|
|
783
|
+
if (params.narrativeEnabled) {
|
|
784
|
+
return {
|
|
785
|
+
kind: "synthesis_narrative",
|
|
786
|
+
state,
|
|
787
|
+
bundle,
|
|
788
|
+
};
|
|
789
|
+
}
|
|
790
|
+
// Narrative disabled: fall through so the deterministic omit runs below.
|
|
791
|
+
}
|
|
650
792
|
if (decision.selected_executor === "agent") {
|
|
651
793
|
return {
|
|
652
794
|
kind: "semantic_review",
|
|
@@ -682,6 +824,9 @@ async function runDeterministicForNextStep(params) {
|
|
|
682
824
|
result = await runAuditStep({
|
|
683
825
|
root: params.root,
|
|
684
826
|
artifactsDir: params.artifactsDir,
|
|
827
|
+
analyzers,
|
|
828
|
+
graphLlmEdgeReasoning: params.graphLlmEdgeReasoning,
|
|
829
|
+
since: params.since,
|
|
685
830
|
opentoken: params.opentoken,
|
|
686
831
|
});
|
|
687
832
|
}
|
|
@@ -783,6 +928,10 @@ async function cmdNextStep(argv) {
|
|
|
783
928
|
timeoutMs: getTimeoutMs(argv, sessionConfig),
|
|
784
929
|
maxRuns: getMaxRuns(argv),
|
|
785
930
|
opentoken: sessionConfig.opentoken?.enabled,
|
|
931
|
+
narrativeEnabled: sessionConfig.synthesis?.narrative !== false,
|
|
932
|
+
analyzers: sessionConfig.analyzers,
|
|
933
|
+
graphLlmEdgeReasoning: sessionConfig.graph?.llm_edge_reasoning,
|
|
934
|
+
since: getFlag(argv, "--since"),
|
|
786
935
|
});
|
|
787
936
|
if (result.kind === "complete") {
|
|
788
937
|
const step = await writeCurrentStep({
|
|
@@ -850,6 +999,130 @@ async function cmdNextStep(argv) {
|
|
|
850
999
|
console.log(JSON.stringify(step, null, 2));
|
|
851
1000
|
return;
|
|
852
1001
|
}
|
|
1002
|
+
if (result.kind === "analyzer_install") {
|
|
1003
|
+
const decisionsPath = join(artifactsDir, "incoming", "analyzer-decisions.json");
|
|
1004
|
+
await mkdir(join(artifactsDir, "incoming"), { recursive: true });
|
|
1005
|
+
const continueCommand = nextStepCommand(root, artifactsDir);
|
|
1006
|
+
const step = await writeCurrentStep({
|
|
1007
|
+
artifactsDir,
|
|
1008
|
+
stepKind: "analyzer_install",
|
|
1009
|
+
status: "ready",
|
|
1010
|
+
runId: null,
|
|
1011
|
+
allowedCommands: [continueCommand],
|
|
1012
|
+
stopCondition: "Write analyzer install decisions to the results path, then run next-step.",
|
|
1013
|
+
repoRoot: root,
|
|
1014
|
+
artifactPaths: {
|
|
1015
|
+
analyzer_decisions: decisionsPath,
|
|
1016
|
+
},
|
|
1017
|
+
prompt: renderAnalyzerInstallPrompt({
|
|
1018
|
+
unresolved: result.unresolved,
|
|
1019
|
+
decisionsPath,
|
|
1020
|
+
continueCommand,
|
|
1021
|
+
}),
|
|
1022
|
+
});
|
|
1023
|
+
console.log(JSON.stringify(step, null, 2));
|
|
1024
|
+
return;
|
|
1025
|
+
}
|
|
1026
|
+
if (result.kind === "edge_reasoning") {
|
|
1027
|
+
await mkdir(join(artifactsDir, "incoming"), { recursive: true });
|
|
1028
|
+
const edgeReasoningResultsPath = join(artifactsDir, "incoming", "edge-reasoning.json");
|
|
1029
|
+
const continueCommand = nextStepCommand(root, artifactsDir);
|
|
1030
|
+
const basePrompt = buildEdgeReasoningPrompt(result.candidates);
|
|
1031
|
+
const contentHash = edgeReasoningContentHash(result.candidates);
|
|
1032
|
+
if (hostCanDispatch) {
|
|
1033
|
+
// Dispatch path: isolate the (potentially large) edge-list prompt in a file
|
|
1034
|
+
// and have the host fan it out to one subagent, mirroring the packet review
|
|
1035
|
+
// dispatch contract. The subagent writes the rewrites file; next-step applies.
|
|
1036
|
+
const edgeReasoningPromptPath = join(artifactsDir, "incoming", "edge-reasoning-prompt.md");
|
|
1037
|
+
await writeFile(edgeReasoningPromptPath, basePrompt, "utf8");
|
|
1038
|
+
const step = await writeCurrentStep({
|
|
1039
|
+
artifactsDir,
|
|
1040
|
+
stepKind: "edge_reasoning_dispatch",
|
|
1041
|
+
status: "ready",
|
|
1042
|
+
runId: null,
|
|
1043
|
+
allowedCommands: [continueCommand],
|
|
1044
|
+
stopCondition: "Dispatch one subagent to write the edge-reasoning rewrites, then run next-step.",
|
|
1045
|
+
repoRoot: root,
|
|
1046
|
+
artifactPaths: {
|
|
1047
|
+
edge_reasoning_prompt: edgeReasoningPromptPath,
|
|
1048
|
+
edge_reasoning_results: edgeReasoningResultsPath,
|
|
1049
|
+
},
|
|
1050
|
+
prompt: renderEdgeReasoningDispatchPrompt({
|
|
1051
|
+
promptPath: edgeReasoningPromptPath,
|
|
1052
|
+
resultsPath: edgeReasoningResultsPath,
|
|
1053
|
+
continueCommand,
|
|
1054
|
+
contentHash,
|
|
1055
|
+
candidateCount: result.candidates.length,
|
|
1056
|
+
}),
|
|
1057
|
+
access: {
|
|
1058
|
+
read_paths: [edgeReasoningPromptPath],
|
|
1059
|
+
write_paths: [edgeReasoningResultsPath],
|
|
1060
|
+
},
|
|
1061
|
+
});
|
|
1062
|
+
console.log(JSON.stringify(step, null, 2));
|
|
1063
|
+
return;
|
|
1064
|
+
}
|
|
1065
|
+
// One-step fallback (no callable subagent facility): the host produces the
|
|
1066
|
+
// rewrites itself in a single bounded turn, mirroring the narrative step.
|
|
1067
|
+
const step = await writeCurrentStep({
|
|
1068
|
+
artifactsDir,
|
|
1069
|
+
stepKind: "edge_reasoning",
|
|
1070
|
+
status: "ready",
|
|
1071
|
+
runId: null,
|
|
1072
|
+
allowedCommands: [continueCommand],
|
|
1073
|
+
stopCondition: "Write the edge-reasoning rewrites to the results path, then run next-step.",
|
|
1074
|
+
repoRoot: root,
|
|
1075
|
+
artifactPaths: {
|
|
1076
|
+
edge_reasoning_results: edgeReasoningResultsPath,
|
|
1077
|
+
},
|
|
1078
|
+
prompt: renderEdgeReasoningStepPrompt({
|
|
1079
|
+
basePrompt,
|
|
1080
|
+
resultsPath: edgeReasoningResultsPath,
|
|
1081
|
+
continueCommand,
|
|
1082
|
+
contentHash,
|
|
1083
|
+
}),
|
|
1084
|
+
access: {
|
|
1085
|
+
read_paths: [],
|
|
1086
|
+
write_paths: [edgeReasoningResultsPath],
|
|
1087
|
+
},
|
|
1088
|
+
});
|
|
1089
|
+
console.log(JSON.stringify(step, null, 2));
|
|
1090
|
+
return;
|
|
1091
|
+
}
|
|
1092
|
+
if (result.kind === "synthesis_narrative") {
|
|
1093
|
+
const narrativeResultsPath = join(artifactsDir, "incoming", "synthesis-narrative.json");
|
|
1094
|
+
await mkdir(join(artifactsDir, "incoming"), { recursive: true });
|
|
1095
|
+
const continueCommand = nextStepCommand(root, artifactsDir);
|
|
1096
|
+
const basePrompt = result.bundle.audit_findings
|
|
1097
|
+
? renderSynthesisNarrativePrompt(result.bundle.audit_findings)
|
|
1098
|
+
: "# Synthesis narrative\n\nNo findings report is available; write an empty themes array.";
|
|
1099
|
+
const fullPrompt = [
|
|
1100
|
+
basePrompt,
|
|
1101
|
+
"## Results path",
|
|
1102
|
+
"",
|
|
1103
|
+
"Write the SynthesisNarrative JSON object to:",
|
|
1104
|
+
"",
|
|
1105
|
+
` ${narrativeResultsPath}`,
|
|
1106
|
+
"",
|
|
1107
|
+
`Then run: ${continueCommand}`,
|
|
1108
|
+
"",
|
|
1109
|
+
].join("\n");
|
|
1110
|
+
const step = await writeCurrentStep({
|
|
1111
|
+
artifactsDir,
|
|
1112
|
+
stepKind: "synthesis_narrative",
|
|
1113
|
+
status: "ready",
|
|
1114
|
+
runId: null,
|
|
1115
|
+
allowedCommands: [continueCommand],
|
|
1116
|
+
stopCondition: "Write the synthesis narrative to the results path, then run next-step.",
|
|
1117
|
+
repoRoot: root,
|
|
1118
|
+
artifactPaths: {
|
|
1119
|
+
synthesis_narrative_results: narrativeResultsPath,
|
|
1120
|
+
},
|
|
1121
|
+
prompt: fullPrompt,
|
|
1122
|
+
});
|
|
1123
|
+
console.log(JSON.stringify(step, null, 2));
|
|
1124
|
+
return;
|
|
1125
|
+
}
|
|
853
1126
|
if (!hostCanDispatch) {
|
|
854
1127
|
const singleTaskPromptPath = join(artifactsDir, "dispatch", "current-single-task-prompt.md");
|
|
855
1128
|
const workerCommand = renderCommand(result.activeReviewRun.worker_command);
|
|
@@ -1151,7 +1424,8 @@ async function cmdRunToCompletion(argv) {
|
|
|
1151
1424
|
const quotaStateEntry = quotaState.entries[providerModelKey] ?? null;
|
|
1152
1425
|
const allCandidateTasks = buildPendingAuditTasks(bundle);
|
|
1153
1426
|
const candidateGroups = chunkArray(allCandidateTasks.slice(0, parallelWorkers * agentBatchSize), agentBatchSize);
|
|
1154
|
-
const
|
|
1427
|
+
const candidateSizeIndex = sizeIndexFromManifest(bundle.repo_manifest);
|
|
1428
|
+
const slotTokenEstimates = candidateGroups.map((g) => estimateTaskGroupTokens(g, candidateSizeIndex));
|
|
1155
1429
|
const providerLimits = await provider.queryLimits?.(hostModel)
|
|
1156
1430
|
.then((r) => r ? { ...r, source: "provider_query" } : null)
|
|
1157
1431
|
.catch(() => null)
|
|
@@ -1457,6 +1731,8 @@ async function cmdRunToCompletion(argv) {
|
|
|
1457
1731
|
auditResultsPath,
|
|
1458
1732
|
runtimeUpdatesPath,
|
|
1459
1733
|
externalAnalyzerPath,
|
|
1734
|
+
analyzers: sessionConfig.analyzers,
|
|
1735
|
+
since: getFlag(argv, "--since"),
|
|
1460
1736
|
});
|
|
1461
1737
|
workerResult = {
|
|
1462
1738
|
contract_version: WORKER_RESULT_CONTRACT_VERSION,
|
|
@@ -2290,7 +2566,11 @@ async function cmdIntake(argv) {
|
|
|
2290
2566
|
}
|
|
2291
2567
|
async function cmdPlan(argv) {
|
|
2292
2568
|
const artifactsDir = getArtifactsDir(argv);
|
|
2293
|
-
const result = await runAuditStep({
|
|
2569
|
+
const result = await runAuditStep({
|
|
2570
|
+
root: getRootDir(argv),
|
|
2571
|
+
artifactsDir,
|
|
2572
|
+
since: getFlag(argv, "--since"),
|
|
2573
|
+
});
|
|
2294
2574
|
console.log(JSON.stringify({
|
|
2295
2575
|
artifacts_dir: artifactsDir,
|
|
2296
2576
|
selected_executor: result.selected_executor,
|