auditor-lambda 0.2.8 → 0.2.10
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +6 -0
- package/audit-code-wrapper-lib.mjs +1 -1
- package/dist/adapters/eslint.js +9 -5
- package/dist/cli.d.ts +42 -1
- package/dist/cli.js +234 -63
- package/dist/extractors/bucketing.d.ts +4 -0
- package/dist/extractors/bucketing.js +6 -2
- package/dist/extractors/disposition.d.ts +4 -0
- package/dist/extractors/disposition.js +6 -2
- package/dist/extractors/fileInventory.js +24 -28
- package/dist/extractors/flows.d.ts +5 -0
- package/dist/extractors/flows.js +18 -38
- package/dist/extractors/pathPatterns.d.ts +10 -3
- package/dist/extractors/pathPatterns.js +109 -61
- package/dist/extractors/surfaces.d.ts +4 -0
- package/dist/extractors/surfaces.js +11 -11
- package/dist/index.d.ts +1 -1
- package/dist/index.js +2 -1
- package/dist/io/artifacts.d.ts +55 -40
- package/dist/io/artifacts.js +73 -110
- package/dist/io/json.js +52 -21
- package/dist/io/runArtifacts.d.ts +1 -1
- package/dist/io/runArtifacts.js +26 -3
- package/dist/orchestrator/advance.js +83 -62
- package/dist/orchestrator/autoFixExecutor.js +32 -15
- package/dist/orchestrator/flowCoverage.js +11 -5
- package/dist/orchestrator/flowPlanning.d.ts +7 -2
- package/dist/orchestrator/flowPlanning.js +46 -21
- package/dist/orchestrator/flowRequeue.js +28 -8
- package/dist/orchestrator/internalExecutors.js +12 -8
- package/dist/orchestrator/localCommands.d.ts +14 -0
- package/dist/orchestrator/localCommands.js +124 -0
- package/dist/orchestrator/planning.js +25 -3
- package/dist/orchestrator/requeue.js +11 -1
- package/dist/orchestrator/syntaxResolutionExecutor.js +60 -59
- package/dist/orchestrator/taskBuilder.d.ts +4 -2
- package/dist/orchestrator/taskBuilder.js +153 -52
- package/dist/orchestrator/unitBuilder.d.ts +3 -1
- package/dist/orchestrator/unitBuilder.js +24 -16
- package/dist/prompts/renderWorkerPrompt.d.ts +1 -1
- package/dist/prompts/renderWorkerPrompt.js +16 -8
- package/dist/providers/claudeCodeProvider.d.ts +4 -1
- package/dist/providers/claudeCodeProvider.js +8 -5
- package/dist/providers/localSubprocessProvider.d.ts +4 -0
- package/dist/providers/localSubprocessProvider.js +7 -2
- package/dist/providers/spawnLoggedCommand.d.ts +9 -1
- package/dist/providers/spawnLoggedCommand.js +77 -29
- package/dist/reporting/synthesis.d.ts +2 -0
- package/dist/reporting/synthesis.js +12 -9
- package/dist/supervisor/operatorHandoff.d.ts +1 -1
- package/dist/supervisor/operatorHandoff.js +56 -18
- package/dist/supervisor/runLedger.d.ts +1 -1
- package/dist/supervisor/runLedger.js +112 -5
- package/dist/supervisor/sessionConfig.js +10 -10
- package/dist/types/externalAnalyzer.d.ts +3 -0
- package/dist/types/flowCoverage.d.ts +5 -1
- package/dist/types/flowCoverage.js +5 -1
- package/dist/types/flows.d.ts +5 -1
- package/dist/types/flows.js +1 -1
- package/dist/types/runLedger.d.ts +5 -1
- package/dist/types/runLedger.js +6 -1
- package/dist/types/runtimeValidation.d.ts +12 -3
- package/dist/types/runtimeValidation.js +16 -1
- package/dist/types/sessionConfig.d.ts +15 -2
- package/dist/types/sessionConfig.js +15 -1
- package/dist/types/surfaces.d.ts +4 -1
- package/dist/types/surfaces.js +1 -1
- package/dist/types/workerSession.d.ts +9 -0
- package/dist/types/workerSession.js +5 -1
- package/dist/validation/artifacts.d.ts +1 -1
- package/dist/validation/artifacts.js +33 -20
- package/dist/validation/auditResults.d.ts +2 -2
- package/dist/validation/auditResults.js +7 -15
- package/dist/validation/basic.d.ts +9 -1
- package/dist/validation/basic.js +40 -3
- package/dist/validation/sessionConfig.d.ts +4 -2
- package/dist/validation/sessionConfig.js +62 -15
- package/docs/agent-integrations.md +31 -11
- package/docs/next-steps.md +21 -4
- package/docs/packaging.md +14 -0
- package/docs/product-direction.md +22 -0
- package/docs/production-launch-bar.md +2 -0
- package/docs/releasing.md +17 -0
- package/docs/remediation-baseline.md +75 -0
- package/docs/run-flow.md +23 -11
- package/docs/session-config.md +53 -6
- package/docs/supervisor.md +7 -0
- package/docs/workflow-refactor-brief.md +177 -0
- package/package.json +1 -1
- package/schemas/audit-code-v1alpha1.schema.json +1 -0
- package/schemas/audit_result.schema.json +4 -1
- package/schemas/audit_task.schema.json +3 -1
- package/schemas/coverage_matrix.schema.json +3 -3
- package/schemas/critical_flows.schema.json +6 -2
- package/schemas/file_disposition.schema.json +2 -2
- package/schemas/finding.schema.json +9 -4
- package/schemas/flow_coverage.schema.json +2 -2
- package/schemas/repo_manifest.schema.json +4 -4
- package/schemas/risk_register.schema.json +2 -2
- package/schemas/runtime_validation_report.schema.json +2 -2
- package/schemas/runtime_validation_tasks.schema.json +8 -2
- package/schemas/surface_manifest.schema.json +6 -3
- package/schemas/unit_manifest.schema.json +3 -2
- package/skills/audit-code/SKILL.md +5 -0
package/README.md
CHANGED
|
@@ -11,6 +11,7 @@ Normal product usage should:
|
|
|
11
11
|
- use the active conversation model by default
|
|
12
12
|
- use project files and attached repository context by default
|
|
13
13
|
- avoid manual paths, provider flags, and model-selection arguments
|
|
14
|
+
- keep semantic review with the active conversation agent by default
|
|
14
15
|
- advance the audit automatically until it completes or no further automatic progress is possible
|
|
15
16
|
|
|
16
17
|
## Conversation Setup
|
|
@@ -86,6 +87,7 @@ This wrapper:
|
|
|
86
87
|
- auto-builds `dist/` if it is missing
|
|
87
88
|
- advances fresh worker sessions automatically until the audit completes or the remaining work requires imported results or an interactive provider
|
|
88
89
|
- continues through provider-assisted audit review automatically when `.audit-artifacts/session-config.json` selects an interactive provider bridge
|
|
90
|
+
- keeps those provider bridges as fallback compatibility modes rather than the primary product path
|
|
89
91
|
- emits `contract_version: "audit-code/v1alpha1"`
|
|
90
92
|
- refreshes `.audit-artifacts/operator-handoff.json` and `.audit-artifacts/operator-handoff.md` with suggested evidence-import paths and continuation hints
|
|
91
93
|
|
|
@@ -160,6 +162,7 @@ Optional backend config:
|
|
|
160
162
|
- use `audit-code` from the repository root only when you need the repo-local backend fallback
|
|
161
163
|
- use omitted provider or `local-subprocess` for the safest deterministic fallback behavior
|
|
162
164
|
- use `provider: "auto"` only when you want best-effort routing across installed backends
|
|
165
|
+
- treat explicit provider bridges as compatibility fallback, not as the intended owner of semantic review
|
|
163
166
|
|
|
164
167
|
## Implementation Next Steps
|
|
165
168
|
|
|
@@ -169,6 +172,7 @@ The next implementation work is tracked in:
|
|
|
169
172
|
|
|
170
173
|
The short version is:
|
|
171
174
|
|
|
175
|
+
- realign review dispatch around the conversation-owned, non-overlapping lens-block workflow
|
|
172
176
|
- prove the generated Codex, Claude Desktop, OpenCode, VS Code, and Antigravity guidance in real host flows
|
|
173
177
|
- tighten the repo-local MCP-first bootstrap where host smoke tests expose friction
|
|
174
178
|
- polish provider-assisted continuation and failure guidance
|
|
@@ -186,6 +190,8 @@ For GitHub Actions publication and npm Trusted Publishing setup, see `docs/relea
|
|
|
186
190
|
## Key Docs
|
|
187
191
|
|
|
188
192
|
- `docs/product-direction.md`
|
|
193
|
+
- `docs/workflow-refactor-brief.md`
|
|
194
|
+
- `docs/remediation-baseline.md`
|
|
189
195
|
- `docs/releasing.md`
|
|
190
196
|
- `docs/production-readiness.md`
|
|
191
197
|
- `docs/production-launch-bar.md`
|
|
@@ -2049,7 +2049,7 @@ async function installBootstrap(argv) {
|
|
|
2049
2049
|
|
|
2050
2050
|
const sessionConfigPath = join(root, '.audit-artifacts', 'session-config.json');
|
|
2051
2051
|
if (!(await fileExists(sessionConfigPath))) {
|
|
2052
|
-
const defaultConfig = { provider: '
|
|
2052
|
+
const defaultConfig = { provider: 'local-subprocess' };
|
|
2053
2053
|
await mkdir(dirname(sessionConfigPath), { recursive: true });
|
|
2054
2054
|
await writeFile(sessionConfigPath, JSON.stringify(defaultConfig, null, 2) + '\n', 'utf8');
|
|
2055
2055
|
results.push({ path: sessionConfigPath, mode: 'created' });
|
package/dist/adapters/eslint.js
CHANGED
|
@@ -1,12 +1,16 @@
|
|
|
1
1
|
import { normalizeGenericExternalResults } from "./normalizeExternal.js";
|
|
2
2
|
const ESLINT_SEVERITY_ERROR = 2;
|
|
3
3
|
const ESLINT_SEVERITY_WARNING = 1;
|
|
4
|
+
const ESLINT_SEVERITY_MAP = {
|
|
5
|
+
[ESLINT_SEVERITY_ERROR]: "medium",
|
|
6
|
+
[ESLINT_SEVERITY_WARNING]: "low",
|
|
7
|
+
};
|
|
4
8
|
function mapSeverity(value) {
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
return "info";
|
|
9
|
+
// ESLint's JSON formatter emits 2 for errors and 1 for warnings.
|
|
10
|
+
if (typeof value !== "number") {
|
|
11
|
+
return "info";
|
|
12
|
+
}
|
|
13
|
+
return ESLINT_SEVERITY_MAP[value] ?? "info";
|
|
10
14
|
}
|
|
11
15
|
export function normalizeEslintJson(input) {
|
|
12
16
|
return normalizeGenericExternalResults("eslint", input.flatMap((file) => (file.messages ?? []).map((message, index) => ({
|
package/dist/cli.d.ts
CHANGED
|
@@ -1 +1,42 @@
|
|
|
1
|
-
|
|
1
|
+
import type { SessionConfig } from "./types/sessionConfig.js";
|
|
2
|
+
type UiMode = "visible" | "headless";
|
|
3
|
+
declare function getFlag(argv: string[], name: string, fallback?: string): string | undefined;
|
|
4
|
+
declare function hasFlag(argv: string[], name: string): boolean;
|
|
5
|
+
declare function getArtifactsDir(argv: string[]): string;
|
|
6
|
+
declare function getRootDir(argv: string[]): string;
|
|
7
|
+
declare function getBatchResultsDir(argv: string[]): string | undefined;
|
|
8
|
+
declare function getMaxRuns(argv: string[]): number;
|
|
9
|
+
declare function getAgentBatchSize(argv: string[], sessionConfig: SessionConfig): number;
|
|
10
|
+
declare function getParallelWorkers(argv: string[], sessionConfig: SessionConfig): number;
|
|
11
|
+
declare function getTimeoutMs(argv: string[], sessionConfig: SessionConfig): number;
|
|
12
|
+
declare function chunkArray<T>(arr: T[], size: number): T[][];
|
|
13
|
+
declare function getUiMode(argv: string[], fallback?: UiMode): UiMode;
|
|
14
|
+
declare function countLines(path: string): Promise<number>;
|
|
15
|
+
declare function looksLikeCliFlag(value: string | undefined): boolean;
|
|
16
|
+
export declare const cliTestUtils: {
|
|
17
|
+
defaults: {
|
|
18
|
+
rootDir: string;
|
|
19
|
+
artifactsDir: string;
|
|
20
|
+
maxRuns: number;
|
|
21
|
+
agentBatchSize: number;
|
|
22
|
+
parallelWorkers: number;
|
|
23
|
+
timeoutMs: number;
|
|
24
|
+
uiMode: UiMode;
|
|
25
|
+
};
|
|
26
|
+
getFlag: typeof getFlag;
|
|
27
|
+
hasFlag: typeof hasFlag;
|
|
28
|
+
getArtifactsDir: typeof getArtifactsDir;
|
|
29
|
+
getRootDir: typeof getRootDir;
|
|
30
|
+
getBatchResultsDir: typeof getBatchResultsDir;
|
|
31
|
+
getMaxRuns: typeof getMaxRuns;
|
|
32
|
+
getAgentBatchSize: typeof getAgentBatchSize;
|
|
33
|
+
getParallelWorkers: typeof getParallelWorkers;
|
|
34
|
+
getTimeoutMs: typeof getTimeoutMs;
|
|
35
|
+
chunkArray: typeof chunkArray;
|
|
36
|
+
getUiMode: typeof getUiMode;
|
|
37
|
+
looksLikeCliFlag: typeof looksLikeCliFlag;
|
|
38
|
+
countLines: typeof countLines;
|
|
39
|
+
};
|
|
40
|
+
export declare function runSample(argv?: string[]): Promise<void>;
|
|
41
|
+
export declare function runCli(argv: string[]): Promise<void>;
|
|
42
|
+
export {};
|
package/dist/cli.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { access, mkdir, readdir, rename } from "node:fs/promises";
|
|
2
2
|
import { createReadStream } from "node:fs";
|
|
3
3
|
import { basename, dirname, join, resolve } from "node:path";
|
|
4
|
+
import { fileURLToPath } from "node:url";
|
|
4
5
|
import { buildRepoManifest } from "./extractors/fileInventory.js";
|
|
5
6
|
import { buildFileDisposition } from "./extractors/disposition.js";
|
|
6
7
|
import { buildCriticalFlowManifest } from "./extractors/flows.js";
|
|
@@ -13,6 +14,7 @@ import { loadArtifactBundle, writeCoreArtifacts, promoteFinalAuditReport, } from
|
|
|
13
14
|
import { readJsonFile, writeJsonFile } from "./io/json.js";
|
|
14
15
|
import { validateArtifactBundle } from "./validation/artifacts.js";
|
|
15
16
|
import { validateAuditResults, formatAuditResultIssues, } from "./validation/auditResults.js";
|
|
17
|
+
import { prefixValidationIssues } from "./validation/basic.js";
|
|
16
18
|
import { validateConfiguredProviderEnvironment, validateSessionConfig, } from "./validation/sessionConfig.js";
|
|
17
19
|
import { buildAuditReportModel, renderAuditReportMarkdown, } from "./reporting/synthesis.js";
|
|
18
20
|
import { deriveAuditState } from "./orchestrator/state.js";
|
|
@@ -28,78 +30,101 @@ import { LOCAL_SUBPROCESS_PROVIDER_NAME } from "./providers/constants.js";
|
|
|
28
30
|
import { runAuditCodeMcpServer } from "./mcp/server.js";
|
|
29
31
|
const ADVANCE_AUDIT_CONTRACT_VERSION = "audit-code/v1alpha1";
|
|
30
32
|
const WORKER_RESULT_CONTRACT_VERSION = "audit-code-worker-result/v1alpha1";
|
|
31
|
-
const
|
|
32
|
-
|
|
33
|
-
|
|
33
|
+
const DIRECT_CLI_DEFAULTS = {
|
|
34
|
+
rootDir: ".",
|
|
35
|
+
artifactsDir: ".artifacts",
|
|
36
|
+
maxRuns: 1000,
|
|
37
|
+
agentBatchSize: 1,
|
|
38
|
+
parallelWorkers: 1,
|
|
39
|
+
timeoutMs: 30 * 60 * 1000, // 30 minutes
|
|
40
|
+
uiMode: "headless",
|
|
41
|
+
};
|
|
42
|
+
// Keep the sample-run payload explicit so the demo command is deterministic.
|
|
43
|
+
const SAMPLE_REPO_FILES = [
|
|
34
44
|
{ path: "src/api/auth.ts", size_bytes: 1240, hash: "abc123" },
|
|
35
45
|
{ path: "src/lib/session.ts", size_bytes: 980, hash: "def456" },
|
|
36
46
|
{ path: "infra/deploy.yml", size_bytes: 420, hash: "ghi789" },
|
|
37
47
|
{ path: "docs/notes.md", size_bytes: 300, hash: "doc111" },
|
|
38
48
|
];
|
|
49
|
+
function isLongFlagToken(value) {
|
|
50
|
+
return typeof value === "string" && value.startsWith("--");
|
|
51
|
+
}
|
|
52
|
+
// Read a long-form CLI flag while treating a following flag token as "missing".
|
|
39
53
|
function getFlag(argv, name, fallback) {
|
|
40
54
|
const index = argv.indexOf(name);
|
|
41
|
-
if (index
|
|
42
|
-
return
|
|
43
|
-
|
|
55
|
+
if (index < 0)
|
|
56
|
+
return fallback;
|
|
57
|
+
const candidate = argv[index + 1];
|
|
58
|
+
if (!candidate || isLongFlagToken(candidate))
|
|
59
|
+
return fallback;
|
|
60
|
+
return candidate;
|
|
44
61
|
}
|
|
62
|
+
// Boolean flags only care whether the token is present at all.
|
|
45
63
|
function hasFlag(argv, name) {
|
|
46
64
|
return argv.includes(name);
|
|
47
65
|
}
|
|
66
|
+
function resolveFlagPath(argv, name, fallback) {
|
|
67
|
+
return resolve(getFlag(argv, name, fallback));
|
|
68
|
+
}
|
|
69
|
+
function normalizePositiveInteger(value) {
|
|
70
|
+
if (typeof value !== "number" || !Number.isFinite(value) || value <= 0) {
|
|
71
|
+
return undefined;
|
|
72
|
+
}
|
|
73
|
+
return Math.floor(value);
|
|
74
|
+
}
|
|
75
|
+
function parsePositiveIntegerFlag(argv, name) {
|
|
76
|
+
const raw = getFlag(argv, name);
|
|
77
|
+
if (raw === undefined) {
|
|
78
|
+
return undefined;
|
|
79
|
+
}
|
|
80
|
+
return normalizePositiveInteger(Number(raw));
|
|
81
|
+
}
|
|
48
82
|
function getArtifactsDir(argv) {
|
|
49
|
-
return
|
|
83
|
+
return resolveFlagPath(argv, "--artifacts-dir", DIRECT_CLI_DEFAULTS.artifactsDir);
|
|
50
84
|
}
|
|
51
85
|
function getRootDir(argv) {
|
|
52
|
-
return
|
|
86
|
+
return resolveFlagPath(argv, "--root", DIRECT_CLI_DEFAULTS.rootDir);
|
|
53
87
|
}
|
|
54
88
|
function getBatchResultsDir(argv) {
|
|
55
89
|
const value = getFlag(argv, "--batch-results");
|
|
56
90
|
return value ? resolve(value) : undefined;
|
|
57
91
|
}
|
|
58
92
|
function getMaxRuns(argv) {
|
|
59
|
-
|
|
60
|
-
return Number.isFinite(raw) && raw > 0 ? Math.floor(raw) : DEFAULT_MAX_RUNS;
|
|
93
|
+
return parsePositiveIntegerFlag(argv, "--max-runs") ?? DIRECT_CLI_DEFAULTS.maxRuns;
|
|
61
94
|
}
|
|
62
95
|
function getAgentBatchSize(argv, sessionConfig) {
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
if (Number.isFinite(parsed) && parsed > 0)
|
|
67
|
-
return Math.floor(parsed);
|
|
68
|
-
}
|
|
69
|
-
if (typeof sessionConfig.agent_task_batch_size === "number" && sessionConfig.agent_task_batch_size > 0) {
|
|
70
|
-
return Math.floor(sessionConfig.agent_task_batch_size);
|
|
71
|
-
}
|
|
72
|
-
return 1;
|
|
96
|
+
return (parsePositiveIntegerFlag(argv, "--agent-batch-size") ??
|
|
97
|
+
normalizePositiveInteger(sessionConfig.agent_task_batch_size) ??
|
|
98
|
+
DIRECT_CLI_DEFAULTS.agentBatchSize);
|
|
73
99
|
}
|
|
74
100
|
function getParallelWorkers(argv, sessionConfig) {
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
if (Number.isFinite(parsed) && parsed > 0)
|
|
79
|
-
return Math.floor(parsed);
|
|
80
|
-
}
|
|
81
|
-
if (typeof sessionConfig.parallel_workers === "number" && sessionConfig.parallel_workers > 0) {
|
|
82
|
-
return Math.floor(sessionConfig.parallel_workers);
|
|
83
|
-
}
|
|
84
|
-
return 1;
|
|
101
|
+
return (parsePositiveIntegerFlag(argv, "--parallel") ??
|
|
102
|
+
normalizePositiveInteger(sessionConfig.parallel_workers) ??
|
|
103
|
+
DIRECT_CLI_DEFAULTS.parallelWorkers);
|
|
85
104
|
}
|
|
86
105
|
function getTimeoutMs(argv, sessionConfig) {
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
106
|
+
return (parsePositiveIntegerFlag(argv, "--timeout") ??
|
|
107
|
+
normalizePositiveInteger(sessionConfig.timeout_ms) ??
|
|
108
|
+
DIRECT_CLI_DEFAULTS.timeoutMs);
|
|
109
|
+
}
|
|
110
|
+
function getExplicitProvider(argv) {
|
|
111
|
+
return getFlag(argv, "--provider");
|
|
112
|
+
}
|
|
113
|
+
function resolveRunProviderName(argv, sessionConfig) {
|
|
114
|
+
return resolveFreshSessionProviderName(getExplicitProvider(argv) ?? LOCAL_SUBPROCESS_PROVIDER_NAME, sessionConfig);
|
|
94
115
|
}
|
|
95
116
|
function chunkArray(arr, size) {
|
|
117
|
+
const chunkSize = normalizePositiveInteger(size);
|
|
118
|
+
if (chunkSize === undefined) {
|
|
119
|
+
throw new Error("chunkArray size must be a positive integer.");
|
|
120
|
+
}
|
|
96
121
|
const chunks = [];
|
|
97
|
-
for (let i = 0; i < arr.length; i +=
|
|
98
|
-
chunks.push(arr.slice(i, i +
|
|
122
|
+
for (let i = 0; i < arr.length; i += chunkSize) {
|
|
123
|
+
chunks.push(arr.slice(i, i + chunkSize));
|
|
99
124
|
}
|
|
100
125
|
return chunks;
|
|
101
126
|
}
|
|
102
|
-
function getUiMode(argv, fallback =
|
|
127
|
+
function getUiMode(argv, fallback = DIRECT_CLI_DEFAULTS.uiMode) {
|
|
103
128
|
const raw = getFlag(argv, "--ui");
|
|
104
129
|
if (raw === "visible")
|
|
105
130
|
return "visible";
|
|
@@ -144,18 +169,11 @@ async function emitEnvelope(params) {
|
|
|
144
169
|
}
|
|
145
170
|
function buildManualReviewBlocker(providerName) {
|
|
146
171
|
return providerName === LOCAL_SUBPROCESS_PROVIDER_NAME
|
|
147
|
-
? "Automatic
|
|
172
|
+
? "Automatic backend steps are exhausted. Remaining semantic review now belongs to the active conversation agent. Review the dispatched files, write structured audit results, and ingest them with audit-code --results <file> or audit-code --batch-results <dir>. If you intentionally want a backend bridge instead, re-run audit-code with --provider auto, --provider claude-code, --provider opencode, --provider subprocess-template, or --provider vscode-task."
|
|
148
173
|
: "Automatic work is exhausted. Remaining audit tasks require explicit audit results or an interactive provider.";
|
|
149
174
|
}
|
|
150
|
-
function
|
|
151
|
-
return
|
|
152
|
-
path: issue.path.length === 0
|
|
153
|
-
? prefix
|
|
154
|
-
: issue.path === prefix || issue.path.startsWith(`${prefix}.`)
|
|
155
|
-
? issue.path
|
|
156
|
-
: `${prefix}.${issue.path}`,
|
|
157
|
-
message: issue.message,
|
|
158
|
-
}));
|
|
175
|
+
function shouldRunInlineExecutor(selectedExecutor) {
|
|
176
|
+
return selectedExecutor !== null && selectedExecutor !== "agent";
|
|
159
177
|
}
|
|
160
178
|
function buildBlockedAuditState(params) {
|
|
161
179
|
return {
|
|
@@ -279,8 +297,24 @@ function buildWorkerFailureBlocker(workerResult) {
|
|
|
279
297
|
: workerResult.summary;
|
|
280
298
|
}
|
|
281
299
|
function looksLikeCliFlag(value) {
|
|
282
|
-
return
|
|
300
|
+
return isLongFlagToken(value);
|
|
283
301
|
}
|
|
302
|
+
export const cliTestUtils = {
|
|
303
|
+
defaults: DIRECT_CLI_DEFAULTS,
|
|
304
|
+
getFlag,
|
|
305
|
+
hasFlag,
|
|
306
|
+
getArtifactsDir,
|
|
307
|
+
getRootDir,
|
|
308
|
+
getBatchResultsDir,
|
|
309
|
+
getMaxRuns,
|
|
310
|
+
getAgentBatchSize,
|
|
311
|
+
getParallelWorkers,
|
|
312
|
+
getTimeoutMs,
|
|
313
|
+
chunkArray,
|
|
314
|
+
getUiMode,
|
|
315
|
+
looksLikeCliFlag,
|
|
316
|
+
countLines,
|
|
317
|
+
};
|
|
284
318
|
async function maybeArchiveLegacyPendingResults(auditResultsPath) {
|
|
285
319
|
if (!auditResultsPath || basename(auditResultsPath) !== "worker_results_pending.json") {
|
|
286
320
|
return undefined;
|
|
@@ -388,8 +422,8 @@ function isWorkerResult(value) {
|
|
|
388
422
|
value.contract_version ===
|
|
389
423
|
WORKER_RESULT_CONTRACT_VERSION);
|
|
390
424
|
}
|
|
391
|
-
export async function runSample() {
|
|
392
|
-
const repoManifest = buildRepoManifest("sample-repo",
|
|
425
|
+
export async function runSample(argv = process.argv) {
|
|
426
|
+
const repoManifest = buildRepoManifest("sample-repo", SAMPLE_REPO_FILES);
|
|
393
427
|
const disposition = buildFileDisposition(repoManifest);
|
|
394
428
|
const unitManifest = buildUnitManifest(repoManifest, disposition);
|
|
395
429
|
const surfaceManifest = buildSurfaceManifest(repoManifest, disposition);
|
|
@@ -444,7 +478,7 @@ export async function runSample() {
|
|
|
444
478
|
audit_results: sampleResults,
|
|
445
479
|
audit_report: auditReport,
|
|
446
480
|
});
|
|
447
|
-
const artifactsDir = getArtifactsDir(
|
|
481
|
+
const artifactsDir = getArtifactsDir(argv);
|
|
448
482
|
await mkdir(artifactsDir, { recursive: true });
|
|
449
483
|
await writeCoreArtifacts(artifactsDir, {
|
|
450
484
|
repo_manifest: repoManifest,
|
|
@@ -466,7 +500,7 @@ async function cmdAdvanceAudit(argv) {
|
|
|
466
500
|
const root = getRootDir(argv);
|
|
467
501
|
const artifactsDir = getArtifactsDir(argv);
|
|
468
502
|
const sessionConfig = await loadSessionConfig(artifactsDir);
|
|
469
|
-
const providerName =
|
|
503
|
+
const providerName = resolveRunProviderName(argv, sessionConfig);
|
|
470
504
|
const batchResultsDir = getBatchResultsDir(argv);
|
|
471
505
|
if (batchResultsDir && getFlag(argv, "--results")) {
|
|
472
506
|
throw new Error("Use either --results <file> or --batch-results <dir>, not both.");
|
|
@@ -532,13 +566,14 @@ async function cmdRunToCompletion(argv) {
|
|
|
532
566
|
const root = getRootDir(argv);
|
|
533
567
|
const artifactsDir = getArtifactsDir(argv);
|
|
534
568
|
const sessionConfig = await loadSessionConfig(artifactsDir);
|
|
535
|
-
const
|
|
569
|
+
const explicitProvider = getExplicitProvider(argv);
|
|
570
|
+
const provider = createFreshSessionProvider(explicitProvider ?? LOCAL_SUBPROCESS_PROVIDER_NAME, sessionConfig);
|
|
536
571
|
const uiMode = getUiMode(argv, sessionConfig.ui_mode ?? "headless");
|
|
537
572
|
const maxRuns = getMaxRuns(argv);
|
|
538
573
|
const agentBatchSize = getAgentBatchSize(argv, sessionConfig);
|
|
539
574
|
const parallelWorkers = getParallelWorkers(argv, sessionConfig);
|
|
540
575
|
const timeoutMs = getTimeoutMs(argv, sessionConfig);
|
|
541
|
-
const selfCliPath = resolve(process.argv[1] ?? "");
|
|
576
|
+
const selfCliPath = resolve(argv[1] ?? process.argv[1] ?? "");
|
|
542
577
|
await mkdir(artifactsDir, { recursive: true });
|
|
543
578
|
await ensureSupervisorDirs(artifactsDir);
|
|
544
579
|
const batchResultsDir = getBatchResultsDir(argv);
|
|
@@ -646,6 +681,8 @@ async function cmdRunToCompletion(argv) {
|
|
|
646
681
|
],
|
|
647
682
|
audit_results_path: blockAuditResultsPath,
|
|
648
683
|
pending_audit_tasks_path: blockPendingTasksPath,
|
|
684
|
+
timeout_ms: timeoutMs,
|
|
685
|
+
max_retries: 0,
|
|
649
686
|
};
|
|
650
687
|
const blockPrompt = renderWorkerPrompt(blockTask);
|
|
651
688
|
await writeWorkerTaskFiles(blockTask, blockPrompt, blockPaths, artifactsDir, blockPendingTasks);
|
|
@@ -716,7 +753,9 @@ async function cmdRunToCompletion(argv) {
|
|
|
716
753
|
worker_command: [process.execPath, selfCliPath, "worker-run", "--task", slotPaths.taskPath],
|
|
717
754
|
audit_results_path: slotAuditResultsPath,
|
|
718
755
|
pending_audit_tasks_path: slotPendingTasksPath,
|
|
719
|
-
|
|
756
|
+
worker_command_mode: "deferred",
|
|
757
|
+
timeout_ms: timeoutMs,
|
|
758
|
+
max_retries: 0,
|
|
720
759
|
};
|
|
721
760
|
const slotPrompt = renderWorkerPrompt(slotTask);
|
|
722
761
|
await writeWorkerTaskFiles(slotTask, slotPrompt, slotPaths, artifactsDir, group);
|
|
@@ -860,6 +899,124 @@ async function cmdRunToCompletion(argv) {
|
|
|
860
899
|
runCount += 1;
|
|
861
900
|
const runId = buildRunId(obligationId, runCount);
|
|
862
901
|
const paths = getRunPaths(artifactsDir, runId);
|
|
902
|
+
if (shouldRunInlineExecutor(preferredExecutor)) {
|
|
903
|
+
await clearDispatchFiles(artifactsDir);
|
|
904
|
+
const startedAt = new Date().toISOString();
|
|
905
|
+
let workerResult;
|
|
906
|
+
try {
|
|
907
|
+
const result = await runAuditStep({
|
|
908
|
+
root,
|
|
909
|
+
artifactsDir,
|
|
910
|
+
preferredExecutor,
|
|
911
|
+
auditResultsPath,
|
|
912
|
+
runtimeUpdatesPath,
|
|
913
|
+
externalAnalyzerPath,
|
|
914
|
+
});
|
|
915
|
+
workerResult = {
|
|
916
|
+
contract_version: WORKER_RESULT_CONTRACT_VERSION,
|
|
917
|
+
run_id: runId,
|
|
918
|
+
obligation_id: obligationId,
|
|
919
|
+
status: result.progress_made ? "completed" : "no_progress",
|
|
920
|
+
progress_made: result.progress_made,
|
|
921
|
+
selected_executor: result.selected_executor,
|
|
922
|
+
artifacts_written: result.artifacts_written,
|
|
923
|
+
summary: result.progress_summary,
|
|
924
|
+
next_likely_step: result.next_likely_step,
|
|
925
|
+
errors: [],
|
|
926
|
+
};
|
|
927
|
+
}
|
|
928
|
+
catch (error) {
|
|
929
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
930
|
+
workerResult = {
|
|
931
|
+
contract_version: WORKER_RESULT_CONTRACT_VERSION,
|
|
932
|
+
run_id: runId,
|
|
933
|
+
obligation_id: obligationId,
|
|
934
|
+
status: "failed",
|
|
935
|
+
progress_made: false,
|
|
936
|
+
selected_executor: preferredExecutor,
|
|
937
|
+
artifacts_written: [],
|
|
938
|
+
summary: `Inline executor failed for ${preferredExecutor}: ${message}`,
|
|
939
|
+
next_likely_step: decision.selected_obligation,
|
|
940
|
+
errors: [message],
|
|
941
|
+
};
|
|
942
|
+
}
|
|
943
|
+
await writeJsonFile(paths.resultPath, workerResult);
|
|
944
|
+
await writeJsonFile(paths.statusPath, {
|
|
945
|
+
run_id: runId,
|
|
946
|
+
status: workerResult.status,
|
|
947
|
+
execution_mode: "inline",
|
|
948
|
+
});
|
|
949
|
+
await appendRunLedgerEntry(artifactsDir, {
|
|
950
|
+
run_id: runId,
|
|
951
|
+
provider: provider.name,
|
|
952
|
+
obligation_id: obligationId,
|
|
953
|
+
selected_executor: workerResult.selected_executor,
|
|
954
|
+
status: workerResult.status,
|
|
955
|
+
started_at: startedAt,
|
|
956
|
+
ended_at: new Date().toISOString(),
|
|
957
|
+
result_path: paths.resultPath,
|
|
958
|
+
});
|
|
959
|
+
lastResult = workerResult;
|
|
960
|
+
if (workerResult.progress_made) {
|
|
961
|
+
anyProgress = true;
|
|
962
|
+
}
|
|
963
|
+
for (const artifact of workerResult.artifacts_written) {
|
|
964
|
+
artifactsWritten.add(artifact);
|
|
965
|
+
}
|
|
966
|
+
artifactsWritten.add("run-ledger.json");
|
|
967
|
+
if (externalAnalyzerPath)
|
|
968
|
+
pendingExternalAnalyzerPath = undefined;
|
|
969
|
+
if (auditResultsPath &&
|
|
970
|
+
pendingBatchAuditResults[0] === auditResultsPath &&
|
|
971
|
+
preferredExecutor === "result_ingestion_executor" &&
|
|
972
|
+
workerResult.status !== "failed" &&
|
|
973
|
+
workerResult.status !== "blocked") {
|
|
974
|
+
pendingBatchAuditResults.shift();
|
|
975
|
+
}
|
|
976
|
+
if (auditResultsPath)
|
|
977
|
+
pendingAuditResultsPath = undefined;
|
|
978
|
+
if (runtimeUpdatesPath)
|
|
979
|
+
pendingRuntimeUpdatesPath = undefined;
|
|
980
|
+
if (workerResult.status === "failed" ||
|
|
981
|
+
workerResult.status === "blocked" ||
|
|
982
|
+
workerResult.status === "no_progress") {
|
|
983
|
+
const bundleAfter = await loadArtifactBundle(artifactsDir);
|
|
984
|
+
const shouldBlock = workerResult.status === "failed" || workerResult.status === "blocked";
|
|
985
|
+
const state = shouldBlock
|
|
986
|
+
? buildBlockedAuditState({
|
|
987
|
+
state: bundleAfter.audit_state ?? deriveAuditState(bundleAfter),
|
|
988
|
+
obligationId: workerResult.obligation_id,
|
|
989
|
+
executor: workerResult.selected_executor,
|
|
990
|
+
blocker: buildWorkerFailureBlocker(workerResult),
|
|
991
|
+
})
|
|
992
|
+
: bundleAfter.audit_state ?? deriveAuditState(bundleAfter);
|
|
993
|
+
if (shouldBlock) {
|
|
994
|
+
await writeCoreArtifacts(artifactsDir, {
|
|
995
|
+
...bundleAfter,
|
|
996
|
+
audit_state: state,
|
|
997
|
+
});
|
|
998
|
+
}
|
|
999
|
+
await emitEnvelope({
|
|
1000
|
+
root,
|
|
1001
|
+
artifactsDir,
|
|
1002
|
+
bundle: shouldBlock
|
|
1003
|
+
? { ...bundleAfter, audit_state: state }
|
|
1004
|
+
: bundleAfter,
|
|
1005
|
+
audit_state: state,
|
|
1006
|
+
selected_obligation: workerResult.obligation_id,
|
|
1007
|
+
selected_executor: workerResult.selected_executor,
|
|
1008
|
+
progress_made: anyProgress,
|
|
1009
|
+
artifacts_written: Array.from(shouldBlock
|
|
1010
|
+
? new Set([...artifactsWritten, "audit_state.json"])
|
|
1011
|
+
: artifactsWritten),
|
|
1012
|
+
progress_summary: buildWorkerFailureBlocker(workerResult),
|
|
1013
|
+
next_likely_step: shouldBlock ? null : workerResult.next_likely_step,
|
|
1014
|
+
providerName: provider.name,
|
|
1015
|
+
});
|
|
1016
|
+
return;
|
|
1017
|
+
}
|
|
1018
|
+
continue;
|
|
1019
|
+
}
|
|
863
1020
|
const pendingAuditTasks = preferredExecutor === "agent"
|
|
864
1021
|
? buildPendingAuditTasks(bundle).slice(0, agentBatchSize)
|
|
865
1022
|
: undefined;
|
|
@@ -888,6 +1045,8 @@ async function cmdRunToCompletion(argv) {
|
|
|
888
1045
|
pending_audit_tasks_path: pendingAuditTasksPath,
|
|
889
1046
|
runtime_updates_path: runtimeUpdatesPath,
|
|
890
1047
|
external_analyzer_results_path: externalAnalyzerPath,
|
|
1048
|
+
timeout_ms: timeoutMs,
|
|
1049
|
+
max_retries: 0,
|
|
891
1050
|
};
|
|
892
1051
|
const prompt = renderWorkerPrompt(task);
|
|
893
1052
|
await writeWorkerTaskFiles(task, prompt, paths, artifactsDir, pendingAuditTasks);
|
|
@@ -1317,7 +1476,7 @@ async function main(argv) {
|
|
|
1317
1476
|
const command = argv[2] ?? "sample-run";
|
|
1318
1477
|
switch (command) {
|
|
1319
1478
|
case "sample-run":
|
|
1320
|
-
await runSample();
|
|
1479
|
+
await runSample(argv);
|
|
1321
1480
|
return;
|
|
1322
1481
|
case "advance-audit":
|
|
1323
1482
|
await cmdAdvanceAudit(argv);
|
|
@@ -1367,7 +1526,19 @@ async function main(argv) {
|
|
|
1367
1526
|
process.exitCode = 1;
|
|
1368
1527
|
}
|
|
1369
1528
|
}
|
|
1370
|
-
|
|
1371
|
-
|
|
1372
|
-
|
|
1373
|
-
|
|
1529
|
+
export async function runCli(argv) {
|
|
1530
|
+
await main(argv).catch((error) => {
|
|
1531
|
+
console.error(error instanceof Error ? error.message : String(error));
|
|
1532
|
+
process.exitCode = 1;
|
|
1533
|
+
});
|
|
1534
|
+
}
|
|
1535
|
+
function isDirectCliExecution(argv) {
|
|
1536
|
+
const entryPath = argv[1];
|
|
1537
|
+
if (!entryPath) {
|
|
1538
|
+
return false;
|
|
1539
|
+
}
|
|
1540
|
+
return resolve(entryPath) === fileURLToPath(import.meta.url);
|
|
1541
|
+
}
|
|
1542
|
+
if (isDirectCliExecution(process.argv)) {
|
|
1543
|
+
await runCli(process.argv);
|
|
1544
|
+
}
|
|
@@ -4,4 +4,8 @@ export interface BucketAssignment {
|
|
|
4
4
|
buckets: FileBucket[];
|
|
5
5
|
rationale: string[];
|
|
6
6
|
}
|
|
7
|
+
/**
|
|
8
|
+
* Buckets files using the shared extractor heuristics so intake stays
|
|
9
|
+
* consistent across OS-specific path separators and mixed-case manifests.
|
|
10
|
+
*/
|
|
7
11
|
export declare function bucketFile(path: string): BucketAssignment;
|
|
@@ -1,12 +1,16 @@
|
|
|
1
|
-
import { isNodeModulesOrGit, isTestPath, isInterfacePath, isDataLayerPath, isSecuritySensitivePath, isConcurrencyPath, isScriptPath, isDeploymentConfigPath, isDocPath, isGeneratedPath, } from "./pathPatterns.js";
|
|
1
|
+
import { isNodeModulesOrGit, isTestPath, isInterfacePath, isDataLayerPath, isSecuritySensitivePath, isConcurrencyPath, isScriptPath, isDeploymentConfigPath, isDocPath, isGeneratedPath, normalizeExtractorPath, } from "./pathPatterns.js";
|
|
2
2
|
function addBucket(buckets, rationale, bucket, reason) {
|
|
3
3
|
if (!buckets.has(bucket)) {
|
|
4
4
|
buckets.add(bucket);
|
|
5
5
|
rationale.push(reason);
|
|
6
6
|
}
|
|
7
7
|
}
|
|
8
|
+
/**
|
|
9
|
+
* Buckets files using the shared extractor heuristics so intake stays
|
|
10
|
+
* consistent across OS-specific path separators and mixed-case manifests.
|
|
11
|
+
*/
|
|
8
12
|
export function bucketFile(path) {
|
|
9
|
-
const normalized = path
|
|
13
|
+
const normalized = normalizeExtractorPath(path);
|
|
10
14
|
const buckets = new Set();
|
|
11
15
|
const rationale = [];
|
|
12
16
|
if (isNodeModulesOrGit(normalized)) {
|
|
@@ -1,4 +1,8 @@
|
|
|
1
1
|
import type { RepoManifest } from "../types.js";
|
|
2
2
|
import type { FileDisposition, FileDispositionStatus } from "../types/disposition.js";
|
|
3
|
+
/**
|
|
4
|
+
* Applies shared path heuristics to mark files that should be excluded or
|
|
5
|
+
* down-scoped before audit planning begins.
|
|
6
|
+
*/
|
|
3
7
|
export declare function buildFileDisposition(repoManifest: RepoManifest): FileDisposition;
|
|
4
8
|
export declare function isAuditExcludedStatus(status: FileDispositionStatus): boolean;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { isNodeModulesOrGit, isBuildOutput, isVendorPath, isBinaryArtifact, isLicensePath, isLockfilePath, isLogPath, isDocPath, } from "./pathPatterns.js";
|
|
1
|
+
import { isNodeModulesOrGit, isBuildOutput, isVendorPath, isBinaryArtifact, isLicensePath, isLockfilePath, isLogPath, isDocPath, normalizeExtractorPath, } from "./pathPatterns.js";
|
|
2
2
|
function inferDisposition(path) {
|
|
3
|
-
const normalized = path
|
|
3
|
+
const normalized = normalizeExtractorPath(path);
|
|
4
4
|
if (isNodeModulesOrGit(normalized)) {
|
|
5
5
|
return { path, status: "excluded", reason: "node_modules or .git excluded by convention." };
|
|
6
6
|
}
|
|
@@ -35,6 +35,10 @@ function inferDisposition(path) {
|
|
|
35
35
|
reason: "Default included source or config artifact.",
|
|
36
36
|
};
|
|
37
37
|
}
|
|
38
|
+
/**
|
|
39
|
+
* Applies shared path heuristics to mark files that should be excluded or
|
|
40
|
+
* down-scoped before audit planning begins.
|
|
41
|
+
*/
|
|
38
42
|
export function buildFileDisposition(repoManifest) {
|
|
39
43
|
return {
|
|
40
44
|
files: repoManifest.files.map((file) => inferDisposition(file.path)),
|