auditor-lambda 0.7.0 → 0.8.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +0 -21
- package/dist/cli/auditStep.js +7 -1
- package/dist/cli.d.ts +0 -1
- package/dist/cli.js +0 -2
- package/dist/extractors/graph.js +12 -2
- package/dist/io/artifacts.d.ts +3 -1
- package/dist/io/artifacts.js +18 -2
- package/dist/orchestrator/advance.js +2 -1
- package/dist/orchestrator/artifactFreshness.js +12 -2
- package/dist/orchestrator/autoFixExecutor.d.ts +1 -1
- package/dist/orchestrator/autoFixExecutor.js +10 -0
- package/dist/orchestrator/executorResult.d.ts +12 -0
- package/dist/orchestrator/executorResult.js +1 -0
- package/dist/orchestrator/fileIntegrity.d.ts +1 -0
- package/dist/orchestrator/fileIntegrity.js +12 -3
- package/dist/orchestrator/graphEnrichmentExecutor.d.ts +1 -1
- package/dist/orchestrator/graphEnrichmentExecutor.js +3 -1
- package/dist/orchestrator/internalExecutors.d.ts +1 -18
- package/dist/orchestrator/internalExecutors.js +1 -158
- package/dist/orchestrator/reviewPacketGraph.d.ts +31 -0
- package/dist/orchestrator/reviewPacketGraph.js +691 -0
- package/dist/orchestrator/reviewPackets.d.ts +2 -15
- package/dist/orchestrator/reviewPackets.js +3 -685
- package/dist/orchestrator/runtimeCommand.d.ts +11 -0
- package/dist/orchestrator/runtimeCommand.js +79 -0
- package/dist/orchestrator/scope.js +1 -1
- package/dist/orchestrator/syntaxResolutionExecutor.d.ts +1 -1
- package/dist/orchestrator/synthesisExecutors.d.ts +12 -0
- package/dist/orchestrator/synthesisExecutors.js +90 -0
- package/docs/development.md +35 -139
- package/docs/history.md +26 -0
- package/docs/product.md +41 -108
- package/package.json +1 -1
- package/schemas/audit_findings.schema.json +3 -2
- package/schemas/dispatch_quota.schema.json +2 -0
- package/schemas/external_analyzer_results.schema.json +2 -2
- package/schemas/repo_manifest.schema.json +1 -1
- package/docs/handoff.md +0 -204
package/README.md
CHANGED
|
@@ -215,26 +215,6 @@ Optional backend config:
|
|
|
215
215
|
- use `provider: "auto"` only when you want best-effort routing across installed backends
|
|
216
216
|
- treat explicit provider bridges as compatibility fallback, not as the intended owner of semantic review
|
|
217
217
|
|
|
218
|
-
## Current Development Focus
|
|
219
|
-
|
|
220
|
-
The next implementation work is tracked in:
|
|
221
|
-
|
|
222
|
-
- `docs/product.md`
|
|
223
|
-
- `docs/development.md`
|
|
224
|
-
- `docs/handoff.md`
|
|
225
|
-
|
|
226
|
-
The short version is:
|
|
227
|
-
|
|
228
|
-
- keep the packet dispatch workflow verified in real host environments
|
|
229
|
-
- make graph-informed packetization observable before adding more ecosystem-specific parsers
|
|
230
|
-
- consolidate graph extraction and exercise generic ownership hints for analyzer-supplied module roots
|
|
231
|
-
- add deterministic Python import, package, and test/source graph support as a core language path
|
|
232
|
-
- use semantic/NLP-style affinity only as low-authority context unless deterministic graph evidence supports it
|
|
233
|
-
- keep generated Codex, Claude Desktop, OpenCode, VS Code, and Antigravity guidance aligned with real host behavior
|
|
234
|
-
- tighten the repo-local MCP-first bootstrap where host smoke tests expose friction
|
|
235
|
-
- polish provider-assisted continuation and failure guidance
|
|
236
|
-
- keep schema contracts and examples easy for workers and host integrations to validate
|
|
237
|
-
|
|
238
218
|
## Build And Test
|
|
239
219
|
|
|
240
220
|
```bash
|
|
@@ -253,6 +233,5 @@ For GitHub Actions publication and npm Trusted Publishing setup, see `docs/relea
|
|
|
253
233
|
- `docs/contracts.md`
|
|
254
234
|
- `docs/release.md`
|
|
255
235
|
- `docs/development.md`
|
|
256
|
-
- `docs/handoff.md`
|
|
257
236
|
- `docs/history.md`
|
|
258
237
|
- `skills/audit-code/SKILL.md`
|
package/dist/cli/auditStep.js
CHANGED
|
@@ -84,7 +84,13 @@ export async function runAuditStep(options) {
|
|
|
84
84
|
opentoken: options.opentoken,
|
|
85
85
|
runLogger,
|
|
86
86
|
});
|
|
87
|
-
|
|
87
|
+
// Prune: result.updated_bundle is the full accumulated bundle, so an artifact
|
|
88
|
+
// an executor cleared to `undefined` must be removed from disk (not left to
|
|
89
|
+
// reload as a stale "present" artifact). Safe only because this is the
|
|
90
|
+
// authoritative per-step persist.
|
|
91
|
+
await writeCoreArtifacts(options.artifactsDir, result.updated_bundle, {
|
|
92
|
+
prune: true,
|
|
93
|
+
});
|
|
88
94
|
const archivedPendingResults = await maybeArchiveLegacyPendingResults(options.auditResultsPath);
|
|
89
95
|
if (archivedPendingResults) {
|
|
90
96
|
result.progress_summary +=
|
package/dist/cli.d.ts
CHANGED
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
export { resolveHostDispatchCapability, DIRECT_CLI_DEFAULTS, getFlag, hasFlag, getOptionalBooleanFlag, getArtifactsDir, getRootDir, getBatchResultsDir, getMaxRuns, getAgentBatchSize, getParallelWorkers, getTimeoutMs, chunkArray, getUiMode, looksLikeCliFlag, countLines, warnIfNotGitRepo, } from "./cli/args.js";
|
|
2
1
|
import { getFlag, hasFlag, getArtifactsDir, getRootDir, warnIfNotGitRepo, getBatchResultsDir, getMaxRuns, getAgentBatchSize, getParallelWorkers, getTimeoutMs, chunkArray, getUiMode, looksLikeCliFlag, countLines } from "./cli/args.js";
|
|
3
2
|
export declare const cliTestUtils: {
|
|
4
3
|
defaults: {
|
package/dist/cli.js
CHANGED
|
@@ -24,8 +24,6 @@ import { getSessionConfigPath, loadSessionConfig, readSessionConfigFile, } from
|
|
|
24
24
|
import { clearDispatchFiles, ensureSupervisorDirs, } from "./io/runArtifacts.js";
|
|
25
25
|
import { runAuditCodeMcpServer } from "./mcp/server.js";
|
|
26
26
|
import { scheduleWave, buildProviderModelKey, readQuotaState, resolveLimits, resolveHostActiveSubagentLimit, probeProvider, computeMaxSafeConcurrency, getQuotaStatePath, lookupDiscoveredLimits, setQuotaStateDir, } from "./quota/index.js";
|
|
27
|
-
// Re-exports from extracted modules
|
|
28
|
-
export { resolveHostDispatchCapability, DIRECT_CLI_DEFAULTS, getFlag, hasFlag, getOptionalBooleanFlag, getArtifactsDir, getRootDir, getBatchResultsDir, getMaxRuns, getAgentBatchSize, getParallelWorkers, getTimeoutMs, chunkArray, getUiMode, looksLikeCliFlag, countLines, warnIfNotGitRepo, } from "./cli/args.js";
|
|
29
27
|
import { DIRECT_CLI_DEFAULTS, getFlag, hasFlag, fromBase64Url, taskResultPath, isCanonicalResultFilename, readStdinText, getArtifactsDir, getRootDir, warnIfNotGitRepo, getBatchResultsDir, getMaxRuns, getAgentBatchSize, getParallelWorkers, getTimeoutMs, getExplicitProvider, getHostModel, getHostMaxActiveSubagents, getQuotaProbeMode, resolveRunProviderName, chunkArray, getUiMode, looksLikeCliFlag, countLines, } from "./cli/args.js";
|
|
30
28
|
import { WORKER_RESULT_CONTRACT_VERSION, buildWorkerResult, formatAuditResultValidationError, } from "./cli/workerResult.js";
|
|
31
29
|
import { DISPATCH_RESULT_MAP_FILENAME, ACTIVE_DISPATCH_FILENAME, resolveRunScopedArg, loadDispatchResultMap, entriesByTaskId, buildPendingAuditTasks, prepareDispatchArtifacts, } from "./cli/dispatch.js";
|
package/dist/extractors/graph.js
CHANGED
|
@@ -262,6 +262,7 @@ export async function buildGraphBundleFromFs(repoManifest, root, disposition, op
|
|
|
262
262
|
const rootPath = resolve(root);
|
|
263
263
|
const dispositionMap = buildDispositionMap(disposition);
|
|
264
264
|
const fileContents = {};
|
|
265
|
+
const skippedFiles = [];
|
|
265
266
|
await Promise.all(repoManifest.files.map(async (file) => {
|
|
266
267
|
const status = dispositionMap.get(file.path);
|
|
267
268
|
if ((status && isAuditExcludedStatus(status)) ||
|
|
@@ -277,10 +278,19 @@ export async function buildGraphBundleFromFs(repoManifest, root, disposition, op
|
|
|
277
278
|
try {
|
|
278
279
|
fileContents[file.path] = await readFile(absolutePath, "utf8");
|
|
279
280
|
}
|
|
280
|
-
catch {
|
|
281
|
-
// Best-effort graph extraction should not block structure planning
|
|
281
|
+
catch (e) {
|
|
282
|
+
// Best-effort graph extraction should not block structure planning,
|
|
283
|
+
// but record the skip so a coverage gap is observable to operators.
|
|
284
|
+
skippedFiles.push({ path: file.path, error: e.code ?? String(e) });
|
|
282
285
|
}
|
|
283
286
|
}));
|
|
287
|
+
if (skippedFiles.length > 0) {
|
|
288
|
+
process.stderr.write("[audit-code] graph: skipped " +
|
|
289
|
+
skippedFiles.length +
|
|
290
|
+
" unreadable file(s): " +
|
|
291
|
+
skippedFiles.map((s) => s.path + " (" + s.error + ")").join(", ") +
|
|
292
|
+
"\n");
|
|
293
|
+
}
|
|
284
294
|
return buildGraphBundle(repoManifest, disposition, { ...options, fileContents });
|
|
285
295
|
}
|
|
286
296
|
export function buildGraphBundle(repoManifest, disposition, options = {}) {
|
package/dist/io/artifacts.d.ts
CHANGED
|
@@ -89,7 +89,9 @@ export declare const ARTIFACT_DEFINITIONS: {
|
|
|
89
89
|
export declare const ARTIFACT_FILE_TO_BUNDLE_KEY: Record<string, ArtifactBundleKey>;
|
|
90
90
|
export declare function getArtifactValue(bundle: ArtifactBundle, artifactName: string): unknown;
|
|
91
91
|
export declare function loadArtifactBundle(root: string): Promise<ArtifactBundle>;
|
|
92
|
-
export declare function writeCoreArtifacts(root: string, bundle: ArtifactBundle
|
|
92
|
+
export declare function writeCoreArtifacts(root: string, bundle: ArtifactBundle, options?: {
|
|
93
|
+
prune?: boolean;
|
|
94
|
+
}): Promise<void>;
|
|
93
95
|
export declare function cleanupIntermediateArtifacts(root: string): Promise<string[]>;
|
|
94
96
|
export declare function promoteFinalAuditReport(params: {
|
|
95
97
|
artifactsDir: string;
|
package/dist/io/artifacts.js
CHANGED
|
@@ -79,13 +79,29 @@ export async function loadArtifactBundle(root) {
|
|
|
79
79
|
bundle.tooling_manifest = await buildToolingManifest();
|
|
80
80
|
return bundle;
|
|
81
81
|
}
|
|
82
|
-
export async function writeCoreArtifacts(root, bundle) {
|
|
82
|
+
export async function writeCoreArtifacts(root, bundle, options = {}) {
|
|
83
83
|
const bundleRecord = bundle;
|
|
84
84
|
for (const entry of ARTIFACT_ENTRIES) {
|
|
85
85
|
const [key, definition] = entry;
|
|
86
86
|
const value = bundleRecord[key];
|
|
87
|
+
const path = join(root, definition.fileName);
|
|
87
88
|
if (value !== undefined) {
|
|
88
|
-
await definition.write(
|
|
89
|
+
await definition.write(path, value);
|
|
90
|
+
}
|
|
91
|
+
else if (options.prune) {
|
|
92
|
+
// The bundle is authoritative. An executor that clears an artifact to
|
|
93
|
+
// `undefined` (to force a downstream rebuild — e.g. planning/ingestion
|
|
94
|
+
// reset audit_report) intends the file gone; if it lingers it reloads as a
|
|
95
|
+
// stale "present" artifact with no metadata entry, which deriveAuditState
|
|
96
|
+
// reads as satisfied — masking the invalidation and stranding a stale
|
|
97
|
+
// report. Only callers passing the full accumulated bundle may prune.
|
|
98
|
+
try {
|
|
99
|
+
await unlink(path);
|
|
100
|
+
}
|
|
101
|
+
catch (error) {
|
|
102
|
+
if (!isFileMissingError(error))
|
|
103
|
+
throw error;
|
|
104
|
+
}
|
|
89
105
|
}
|
|
90
106
|
}
|
|
91
107
|
}
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import { decideNextStep, findObligation } from "./nextStep.js";
|
|
2
2
|
import { deriveAuditState } from "./state.js";
|
|
3
3
|
import { computeArtifactMetadata } from "./artifactMetadata.js";
|
|
4
|
-
import { runIntakeExecutor, runStructureExecutor, runPlanningExecutor, runResultIngestionExecutor, runRuntimeValidationExecutor, runRuntimeValidationUpdateExecutor,
|
|
4
|
+
import { runIntakeExecutor, runStructureExecutor, runPlanningExecutor, runResultIngestionExecutor, runRuntimeValidationExecutor, runRuntimeValidationUpdateExecutor, runDesignAssessmentExecutor, runDesignReviewAutoComplete, runExternalAnalyzerImportExecutor, } from "./internalExecutors.js";
|
|
5
|
+
import { runSynthesisExecutor, runSynthesisNarrativeExecutor, } from "./synthesisExecutors.js";
|
|
5
6
|
import { runAutoFixExecutor } from "./autoFixExecutor.js";
|
|
6
7
|
import { runSyntaxResolutionExecutor } from "./syntaxResolutionExecutor.js";
|
|
7
8
|
import { runGraphEnrichmentExecutor } from "./graphEnrichmentExecutor.js";
|
|
@@ -15,9 +15,19 @@ export function stableStringify(value) {
|
|
|
15
15
|
.sort(([a], [b]) => a.localeCompare(b));
|
|
16
16
|
return `{${entries.map(([key, item]) => `${JSON.stringify(key)}:${stableStringify(item)}`).join(",")}}`;
|
|
17
17
|
}
|
|
18
|
+
// Artifacts that stamp a wall-clock `generated_at` on every (re)build. The
|
|
19
|
+
// timestamp is provenance, not content: two rebuilds with identical data but
|
|
20
|
+
// different timestamps must hash equal, or the artifact's revision churns every
|
|
21
|
+
// rebuild and perpetually re-stales its downstreams (e.g. audit-report.md
|
|
22
|
+
// depends on design_assessment) — a finalization-oscillation hazard.
|
|
23
|
+
const GENERATED_AT_STRIPPED_ARTIFACTS = new Set([
|
|
24
|
+
"repo_manifest.json",
|
|
25
|
+
"tooling_manifest.json",
|
|
26
|
+
"audit_plan_metrics.json",
|
|
27
|
+
"design_assessment.json",
|
|
28
|
+
]);
|
|
18
29
|
export function normalizeForMetadataHash(artifactName, value) {
|
|
19
|
-
if ((artifactName
|
|
20
|
-
artifactName === "tooling_manifest.json") &&
|
|
30
|
+
if (GENERATED_AT_STRIPPED_ARTIFACTS.has(artifactName) &&
|
|
21
31
|
value &&
|
|
22
32
|
typeof value === "object" &&
|
|
23
33
|
!Array.isArray(value)) {
|
|
@@ -1,3 +1,3 @@
|
|
|
1
1
|
import type { ArtifactBundle } from "../io/artifacts.js";
|
|
2
|
-
import type { ExecutorRunResult } from "./
|
|
2
|
+
import type { ExecutorRunResult } from "./executorResult.js";
|
|
3
3
|
export declare function runAutoFixExecutor(bundle: ArtifactBundle, root: string): ExecutorRunResult;
|
|
@@ -49,6 +49,7 @@ export function runAutoFixExecutor(bundle, root) {
|
|
|
49
49
|
}
|
|
50
50
|
}
|
|
51
51
|
const executedTools = [];
|
|
52
|
+
const toolTimings = [];
|
|
52
53
|
// JS, TS, HTML, CSS, JSON, YAML, MD
|
|
53
54
|
if (hasPrettierConfig(root) &&
|
|
54
55
|
(extensions.has("ts") ||
|
|
@@ -61,16 +62,19 @@ export function runAutoFixExecutor(bundle, root) {
|
|
|
61
62
|
extensions.has("yml") ||
|
|
62
63
|
extensions.has("yaml") ||
|
|
63
64
|
extensions.has("md"))) {
|
|
65
|
+
const prettierStart = Date.now();
|
|
64
66
|
if (tryRunConfiguredFormatter(root, [
|
|
65
67
|
...resolveNodeTool(root, join("node_modules", "prettier", "bin", "prettier.cjs"), ["--write", "."], "prettier --write ."),
|
|
66
68
|
{ command: "prettier", args: ["--write", "."], display: "prettier --write ." },
|
|
67
69
|
{ command: "npx", args: ["--yes", "prettier", "--write", "."], display: "npx --yes prettier --write ." },
|
|
68
70
|
])) {
|
|
69
71
|
executedTools.push("prettier");
|
|
72
|
+
toolTimings.push({ tool: "prettier", duration_ms: Date.now() - prettierStart });
|
|
70
73
|
}
|
|
71
74
|
}
|
|
72
75
|
// Python
|
|
73
76
|
if (extensions.has("py")) {
|
|
77
|
+
const blackStart = Date.now();
|
|
74
78
|
if (tryRunConfiguredFormatter(root, [
|
|
75
79
|
{ command: "black", args: ["."], display: "black ." },
|
|
76
80
|
{ command: "python", args: ["-m", "black", "."], display: "python -m black ." },
|
|
@@ -78,28 +82,34 @@ export function runAutoFixExecutor(bundle, root) {
|
|
|
78
82
|
{ command: "pipx", args: ["run", "black", "."], display: "pipx run black ." },
|
|
79
83
|
])) {
|
|
80
84
|
executedTools.push("black");
|
|
85
|
+
toolTimings.push({ tool: "black", duration_ms: Date.now() - blackStart });
|
|
81
86
|
}
|
|
82
87
|
}
|
|
83
88
|
// SQL
|
|
84
89
|
if (extensions.has("sql")) {
|
|
90
|
+
const sqlfluffStart = Date.now();
|
|
85
91
|
if (tryRunConfiguredFormatter(root, [
|
|
86
92
|
{ command: "sqlfluff", args: ["fix", "--force", "."], display: "sqlfluff fix --force ." },
|
|
87
93
|
{ command: "uvx", args: ["sqlfluff", "fix", "--force", "."], display: "uvx sqlfluff fix --force ." },
|
|
88
94
|
{ command: "pipx", args: ["run", "sqlfluff", "fix", "--force", "."], display: "pipx run sqlfluff fix --force ." },
|
|
89
95
|
])) {
|
|
90
96
|
executedTools.push("sqlfluff");
|
|
97
|
+
toolTimings.push({ tool: "sqlfluff", duration_ms: Date.now() - sqlfluffStart });
|
|
91
98
|
}
|
|
92
99
|
}
|
|
93
100
|
// Go
|
|
94
101
|
if (extensions.has("go")) {
|
|
102
|
+
const gofmtStart = Date.now();
|
|
95
103
|
if (tryRunConfiguredFormatter(root, [
|
|
96
104
|
{ command: "gofmt", args: ["-w", "."], display: "gofmt -w ." },
|
|
97
105
|
])) {
|
|
98
106
|
executedTools.push("gofmt");
|
|
107
|
+
toolTimings.push({ tool: "gofmt", duration_ms: Date.now() - gofmtStart });
|
|
99
108
|
}
|
|
100
109
|
}
|
|
101
110
|
const resultsArtifact = {
|
|
102
111
|
executed_tools: executedTools,
|
|
112
|
+
tool_timings: toolTimings,
|
|
103
113
|
timestamp: new Date().toISOString(),
|
|
104
114
|
};
|
|
105
115
|
return {
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import type { ArtifactBundle } from "../io/artifacts.js";
|
|
2
|
+
/**
|
|
3
|
+
* Uniform result of running one audit executor: the updated artifact bundle, the
|
|
4
|
+
* artifact filenames it wrote (which drive metadata/staleness bookkeeping in
|
|
5
|
+
* advanceAudit), and a one-line human progress summary. Shared by every executor
|
|
6
|
+
* module so they need not depend on the internalExecutors barrel.
|
|
7
|
+
*/
|
|
8
|
+
export interface ExecutorRunResult {
|
|
9
|
+
updated: ArtifactBundle;
|
|
10
|
+
artifacts_written: string[];
|
|
11
|
+
progress_summary: string;
|
|
12
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -2,6 +2,7 @@ import type { RepoManifest } from "../types.js";
|
|
|
2
2
|
export interface FileIntegrityResult {
|
|
3
3
|
changed_files: string[];
|
|
4
4
|
missing_files: string[];
|
|
5
|
+
io_errors: string[];
|
|
5
6
|
is_clean: boolean;
|
|
6
7
|
}
|
|
7
8
|
export declare function checkFileIntegrity(root: string, manifest: RepoManifest, scope?: string[]): Promise<FileIntegrityResult>;
|
|
@@ -9,6 +9,7 @@ async function hashFile(absolutePath) {
|
|
|
9
9
|
export async function checkFileIntegrity(root, manifest, scope) {
|
|
10
10
|
const changed = [];
|
|
11
11
|
const missing = [];
|
|
12
|
+
const ioErrors = [];
|
|
12
13
|
const scopeSet = scope ? new Set(scope) : null;
|
|
13
14
|
const files = scopeSet
|
|
14
15
|
? manifest.files.filter((f) => scopeSet.has(f.path))
|
|
@@ -29,13 +30,21 @@ export async function checkFileIntegrity(root, manifest, scope) {
|
|
|
29
30
|
changed.push(record.path);
|
|
30
31
|
}
|
|
31
32
|
}
|
|
32
|
-
catch {
|
|
33
|
-
|
|
33
|
+
catch (err) {
|
|
34
|
+
const code = err.code;
|
|
35
|
+
if (code === "ENOENT") {
|
|
36
|
+
missing.push(record.path);
|
|
37
|
+
}
|
|
38
|
+
else {
|
|
39
|
+
console.warn(`fileIntegrity: I/O error on ${record.path}: ${code ?? String(err)}`);
|
|
40
|
+
ioErrors.push(record.path);
|
|
41
|
+
}
|
|
34
42
|
}
|
|
35
43
|
}
|
|
36
44
|
return {
|
|
37
45
|
changed_files: changed,
|
|
38
46
|
missing_files: missing,
|
|
39
|
-
|
|
47
|
+
io_errors: ioErrors,
|
|
48
|
+
is_clean: changed.length === 0 && missing.length === 0 && ioErrors.length === 0,
|
|
40
49
|
};
|
|
41
50
|
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { ArtifactBundle } from "../io/artifacts.js";
|
|
2
|
-
import type { ExecutorRunResult } from "./
|
|
2
|
+
import type { ExecutorRunResult } from "./executorResult.js";
|
|
3
3
|
import type { AnalyzerSetting } from "@audit-tools/shared";
|
|
4
4
|
import type { LanguageAnalyzer } from "../extractors/analyzers/types.js";
|
|
5
5
|
import { type EdgeReasoningResults } from "./edgeReasoning.js";
|
|
@@ -133,7 +133,9 @@ export async function runGraphEnrichmentExecutor(bundle, options = {}) {
|
|
|
133
133
|
setting,
|
|
134
134
|
edges_added: 0,
|
|
135
135
|
routes_added: 0,
|
|
136
|
-
note:
|
|
136
|
+
note: error instanceof Error
|
|
137
|
+
? `Analyzer failed [${error.name}]: ${error.message}${error.stack ? ` — stack: ${error.stack.split("\n").slice(0, 4).join(" | ")}` : ""}`
|
|
138
|
+
: `Analyzer failed: ${String(error)}.`,
|
|
137
139
|
});
|
|
138
140
|
continue;
|
|
139
141
|
}
|
|
@@ -3,16 +3,7 @@ import type { AuditResult } from "../types.js";
|
|
|
3
3
|
import type { RuntimeValidationReport } from "../types/runtimeValidation.js";
|
|
4
4
|
import type { ExternalAnalyzerResults } from "../types/externalAnalyzer.js";
|
|
5
5
|
import type { AuditScopeManifest } from "../types/auditScope.js";
|
|
6
|
-
import type {
|
|
7
|
-
export interface ExecutorRunResult {
|
|
8
|
-
updated: ArtifactBundle;
|
|
9
|
-
artifacts_written: string[];
|
|
10
|
-
progress_summary: string;
|
|
11
|
-
}
|
|
12
|
-
export declare function resolveRuntimeValidationSpawnCommand(command: string[], platform?: NodeJS.Platform, shellCommand?: string): {
|
|
13
|
-
command: string;
|
|
14
|
-
args: string[];
|
|
15
|
-
};
|
|
6
|
+
import type { ExecutorRunResult } from "./executorResult.js";
|
|
16
7
|
export declare function runIntakeExecutor(bundle: ArtifactBundle, root: string): Promise<ExecutorRunResult>;
|
|
17
8
|
export declare function runStructureExecutor(bundle: ArtifactBundle, root?: string): Promise<ExecutorRunResult>;
|
|
18
9
|
export declare function runDesignAssessmentExecutor(bundle: ArtifactBundle): ExecutorRunResult;
|
|
@@ -23,12 +14,4 @@ export declare function runRuntimeValidationExecutor(bundle: ArtifactBundle, roo
|
|
|
23
14
|
opentoken?: boolean;
|
|
24
15
|
}): Promise<ExecutorRunResult>;
|
|
25
16
|
export declare function runRuntimeValidationUpdateExecutor(bundle: ArtifactBundle, updates: RuntimeValidationReport): ExecutorRunResult;
|
|
26
|
-
export declare function runSynthesisExecutor(bundle: ArtifactBundle, results?: AuditResult[]): ExecutorRunResult;
|
|
27
|
-
/**
|
|
28
|
-
* Resolve the optional synthesis-narrative obligation. When a host/provider
|
|
29
|
-
* narrative is supplied it is merged into the canonical findings report and the
|
|
30
|
-
* human report is re-rendered with themes/executive-summary/top-risks; without
|
|
31
|
-
* one the narrative is recorded as omitted and the deterministic report stands.
|
|
32
|
-
*/
|
|
33
|
-
export declare function runSynthesisNarrativeExecutor(bundle: ArtifactBundle, narrative?: SynthesisNarrative): ExecutorRunResult;
|
|
34
17
|
export declare function runExternalAnalyzerImportExecutor(bundle: ArtifactBundle, externalResults: ExternalAnalyzerResults): ExecutorRunResult;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { runCommand } from "./runtimeCommand.js";
|
|
2
2
|
import { buildFileDisposition, isAuditExcludedStatus, } from "../extractors/disposition.js";
|
|
3
3
|
import { buildGraphBundle, buildGraphBundleFromFs, } from "../extractors/graph.js";
|
|
4
4
|
import { buildCriticalFlowManifest } from "../extractors/flows.js";
|
|
@@ -9,7 +9,6 @@ import { applyScopeToCoverage, fullAuditScope } from "./scope.js";
|
|
|
9
9
|
import { buildFlowCoverage } from "./flowCoverage.js";
|
|
10
10
|
import { buildRequeuePayload } from "./requeueCommand.js";
|
|
11
11
|
import { buildRuntimeValidationTasks, discoverRuntimeValidationCommand, mergeRuntimeValidationReport, } from "./runtimeValidation.js";
|
|
12
|
-
import { applyNarrative, buildAuditFindingsReport, buildAuditReportModel, renderAuditReportMarkdown, } from "../reporting/synthesis.js";
|
|
13
12
|
import { buildChunkedAuditTasks, } from "./taskBuilder.js";
|
|
14
13
|
import { buildAuditPlanMetrics, buildReviewPackets, sizeIndexFromManifest, } from "./reviewPackets.js";
|
|
15
14
|
import { buildUnitManifest } from "./unitBuilder.js";
|
|
@@ -60,79 +59,6 @@ function appendSelectiveDeepeningTasks(params) {
|
|
|
60
59
|
artifacts: ["audit_tasks.json", "audit_plan_metrics.json", "review_packets.json"],
|
|
61
60
|
};
|
|
62
61
|
}
|
|
63
|
-
function resolveOpentokenWrap(resolved, platform = process.platform) {
|
|
64
|
-
if (platform === "win32") {
|
|
65
|
-
const shell = process.env.ComSpec ?? "cmd.exe";
|
|
66
|
-
const inner = [resolved.command, ...resolved.args]
|
|
67
|
-
.map((v) => (/^[A-Za-z0-9_./:=@+-]+$/.test(v) ? v : `"${v.replace(/(["^&|<>%])/g, "^$1")}"`))
|
|
68
|
-
.join(" ");
|
|
69
|
-
return { command: shell, args: ["/d", "/s", "/c", `opentoken wrap ${inner}`] };
|
|
70
|
-
}
|
|
71
|
-
return { command: "opentoken", args: ["wrap", resolved.command, ...resolved.args] };
|
|
72
|
-
}
|
|
73
|
-
async function runCommand(command, cwd, options = {}) {
|
|
74
|
-
let spawnCommand = resolveRuntimeValidationSpawnCommand(command);
|
|
75
|
-
if (options.opentoken) {
|
|
76
|
-
spawnCommand = resolveOpentokenWrap(spawnCommand);
|
|
77
|
-
}
|
|
78
|
-
const displayCommand = command.join(" ");
|
|
79
|
-
return await new Promise((resolve) => {
|
|
80
|
-
const child = spawn(spawnCommand.command, spawnCommand.args, {
|
|
81
|
-
cwd,
|
|
82
|
-
env: process.env,
|
|
83
|
-
stdio: ["ignore", "pipe", "pipe"],
|
|
84
|
-
});
|
|
85
|
-
let stdout = "";
|
|
86
|
-
let stderr = "";
|
|
87
|
-
child.stdout.on("data", (chunk) => {
|
|
88
|
-
stdout += String(chunk);
|
|
89
|
-
});
|
|
90
|
-
child.stderr.on("data", (chunk) => {
|
|
91
|
-
stderr += String(chunk);
|
|
92
|
-
});
|
|
93
|
-
child.on("error", (error) => {
|
|
94
|
-
resolve({
|
|
95
|
-
status: "inconclusive",
|
|
96
|
-
summary: `Failed to execute ${displayCommand}: ${error.message}`,
|
|
97
|
-
evidence: [],
|
|
98
|
-
});
|
|
99
|
-
});
|
|
100
|
-
child.on("exit", (code) => {
|
|
101
|
-
const output = `${stdout}\n${stderr}`.trim();
|
|
102
|
-
const evidence = output.length > 0 ? output.split(/\r?\n/).slice(-10) : [];
|
|
103
|
-
resolve({
|
|
104
|
-
status: code === 0 ? "confirmed" : "not_confirmed",
|
|
105
|
-
summary: code === 0
|
|
106
|
-
? `Deterministic runtime command succeeded: ${displayCommand}`
|
|
107
|
-
: `Deterministic runtime command failed with exit code ${code}: ${displayCommand}`,
|
|
108
|
-
evidence,
|
|
109
|
-
});
|
|
110
|
-
});
|
|
111
|
-
});
|
|
112
|
-
}
|
|
113
|
-
export function resolveRuntimeValidationSpawnCommand(command, platform = process.platform, shellCommand = process.env.ComSpec ?? "cmd.exe") {
|
|
114
|
-
const [executable, ...args] = command;
|
|
115
|
-
if (!executable) {
|
|
116
|
-
return { command: "", args: [] };
|
|
117
|
-
}
|
|
118
|
-
if (platform !== "win32") {
|
|
119
|
-
return { command: executable, args };
|
|
120
|
-
}
|
|
121
|
-
const packageManager = executable.replace(/\.(cmd|bat)$/i, "").toLowerCase();
|
|
122
|
-
if (["npm", "npx", "pnpm", "yarn"].includes(packageManager)) {
|
|
123
|
-
return {
|
|
124
|
-
command: shellCommand,
|
|
125
|
-
args: ["/d", "/s", "/c", command.map(quoteCmdArg).join(" ")],
|
|
126
|
-
};
|
|
127
|
-
}
|
|
128
|
-
return { command: executable, args };
|
|
129
|
-
}
|
|
130
|
-
function quoteCmdArg(value) {
|
|
131
|
-
if (/^[A-Za-z0-9_./:=+-]+$/.test(value)) {
|
|
132
|
-
return value;
|
|
133
|
-
}
|
|
134
|
-
return `"${value.replace(/(["^&|<>%])/g, "^$1")}"`;
|
|
135
|
-
}
|
|
136
62
|
export async function runIntakeExecutor(bundle, root) {
|
|
137
63
|
const ignore = await loadIgnoreFile(root);
|
|
138
64
|
const repoManifest = await buildRepoManifestFromFs({
|
|
@@ -476,89 +402,6 @@ export function runRuntimeValidationUpdateExecutor(bundle, updates) {
|
|
|
476
402
|
: ""),
|
|
477
403
|
};
|
|
478
404
|
}
|
|
479
|
-
function buildBaseFindingsReport(bundle, results) {
|
|
480
|
-
return buildAuditFindingsReport(buildAuditReportModel({
|
|
481
|
-
results,
|
|
482
|
-
unitManifest: bundle.unit_manifest,
|
|
483
|
-
graphBundle: bundle.graph_bundle,
|
|
484
|
-
criticalFlows: bundle.critical_flows,
|
|
485
|
-
coverageMatrix: bundle.coverage_matrix,
|
|
486
|
-
runtimeValidationReport: bundle.runtime_validation_report,
|
|
487
|
-
externalAnalyzerResults: bundle.external_analyzer_results,
|
|
488
|
-
designAssessment: bundle.design_assessment,
|
|
489
|
-
}));
|
|
490
|
-
}
|
|
491
|
-
export function runSynthesisExecutor(bundle, results) {
|
|
492
|
-
const finalResults = results ?? bundle.audit_results ?? [];
|
|
493
|
-
// Emit the canonical machine contract and render the human report from it.
|
|
494
|
-
// No narrative yet — that is layered by the synthesis-narrative obligation.
|
|
495
|
-
const findings = buildBaseFindingsReport(bundle, finalResults);
|
|
496
|
-
return {
|
|
497
|
-
updated: {
|
|
498
|
-
...bundle,
|
|
499
|
-
audit_results: finalResults,
|
|
500
|
-
audit_findings: findings,
|
|
501
|
-
audit_report: renderAuditReportMarkdown(findings, { scope: bundle.scope }),
|
|
502
|
-
},
|
|
503
|
-
artifacts_written: ["audit-findings.json", "audit-report.md"],
|
|
504
|
-
progress_summary: `Rendered deterministic audit report and canonical findings for ${finalResults.length} audit result entries.`,
|
|
505
|
-
};
|
|
506
|
-
}
|
|
507
|
-
/**
|
|
508
|
-
* Resolve the optional synthesis-narrative obligation. When a host/provider
|
|
509
|
-
* narrative is supplied it is merged into the canonical findings report and the
|
|
510
|
-
* human report is re-rendered with themes/executive-summary/top-risks; without
|
|
511
|
-
* one the narrative is recorded as omitted and the deterministic report stands.
|
|
512
|
-
*/
|
|
513
|
-
export function runSynthesisNarrativeExecutor(bundle, narrative) {
|
|
514
|
-
const baseReport = bundle.audit_findings ??
|
|
515
|
-
buildBaseFindingsReport(bundle, bundle.audit_results ?? []);
|
|
516
|
-
const needsBaseWrite = !bundle.audit_findings;
|
|
517
|
-
const hasNarrative = Boolean(narrative &&
|
|
518
|
-
((narrative.themes?.length ?? 0) > 0 ||
|
|
519
|
-
(narrative.executive_summary?.trim().length ?? 0) > 0 ||
|
|
520
|
-
(narrative.top_risks?.length ?? 0) > 0));
|
|
521
|
-
if (!hasNarrative) {
|
|
522
|
-
const record = {
|
|
523
|
-
status: "omitted",
|
|
524
|
-
theme_count: 0,
|
|
525
|
-
executive_summary_present: false,
|
|
526
|
-
top_risk_count: 0,
|
|
527
|
-
};
|
|
528
|
-
return {
|
|
529
|
-
updated: {
|
|
530
|
-
...bundle,
|
|
531
|
-
audit_findings: baseReport,
|
|
532
|
-
synthesis_narrative: record,
|
|
533
|
-
},
|
|
534
|
-
artifacts_written: needsBaseWrite
|
|
535
|
-
? ["audit-findings.json", "synthesis-narrative.json"]
|
|
536
|
-
: ["synthesis-narrative.json"],
|
|
537
|
-
progress_summary: "Synthesis narrative omitted; deterministic findings report retained.",
|
|
538
|
-
};
|
|
539
|
-
}
|
|
540
|
-
const enriched = applyNarrative(baseReport, narrative);
|
|
541
|
-
const record = {
|
|
542
|
-
status: "applied",
|
|
543
|
-
theme_count: enriched.themes?.length ?? 0,
|
|
544
|
-
executive_summary_present: (enriched.executive_summary?.trim().length ?? 0) > 0,
|
|
545
|
-
top_risk_count: enriched.top_risks?.length ?? 0,
|
|
546
|
-
};
|
|
547
|
-
return {
|
|
548
|
-
updated: {
|
|
549
|
-
...bundle,
|
|
550
|
-
audit_findings: enriched,
|
|
551
|
-
audit_report: renderAuditReportMarkdown(enriched, { scope: bundle.scope }),
|
|
552
|
-
synthesis_narrative: record,
|
|
553
|
-
},
|
|
554
|
-
artifacts_written: [
|
|
555
|
-
"audit-findings.json",
|
|
556
|
-
"audit-report.md",
|
|
557
|
-
"synthesis-narrative.json",
|
|
558
|
-
],
|
|
559
|
-
progress_summary: `Synthesis narrative applied: ${record.theme_count} theme(s), ${record.top_risk_count} top risk(s).`,
|
|
560
|
-
};
|
|
561
|
-
}
|
|
562
405
|
export function runExternalAnalyzerImportExecutor(bundle, externalResults) {
|
|
563
406
|
const summary = `Imported ${externalResults.results.length} normalized findings from ${externalResults.tool}.`;
|
|
564
407
|
return {
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import type { AuditTask } from "../types.js";
|
|
2
|
+
import type { ReviewPacketGraphEdge, ReviewPacketQuality } from "../types/reviewPlanning.js";
|
|
3
|
+
import type { GraphBundle, GraphEdge } from "@audit-tools/shared";
|
|
4
|
+
import { UnionFind } from "./unionFind.js";
|
|
5
|
+
import { normalizeGraphPath } from "../extractors/graphPathUtils.js";
|
|
6
|
+
export { normalizeGraphPath };
|
|
7
|
+
/**
|
|
8
|
+
* Fan-in / fan-out degree above which a node is treated as a hub. Exported so
|
|
9
|
+
* the Phase 3 delta-scope expansion skips the same hubs that packet planning
|
|
10
|
+
* skips, preventing scope blow-up through highly-connected modules.
|
|
11
|
+
*/
|
|
12
|
+
export declare const HIGH_FAN_DEGREE_THRESHOLD = 12;
|
|
13
|
+
export declare function collectGraphEdges(graphBundle?: GraphBundle): GraphEdge[];
|
|
14
|
+
export declare function graphEdgeConfidence(edge: GraphEdge): number;
|
|
15
|
+
export declare function isConcreteGraphEdge(edge: GraphEdge): boolean;
|
|
16
|
+
export interface GraphDegreeIndex {
|
|
17
|
+
fanIn: Map<string, number>;
|
|
18
|
+
fanOut: Map<string, number>;
|
|
19
|
+
}
|
|
20
|
+
export declare function buildGraphDegreeIndex(edges: GraphEdge[]): GraphDegreeIndex;
|
|
21
|
+
export declare function isPacketExpansionEdge(edge: GraphEdge, degreeIndex: GraphDegreeIndex): boolean;
|
|
22
|
+
export declare function buildFileToGroupKeys(groups: Map<string, AuditTask[]>): Map<string, Set<string>>;
|
|
23
|
+
export declare function unionFindFromGroups(groups: Map<string, AuditTask[]>, graphEdges: GraphEdge[]): UnionFind;
|
|
24
|
+
export declare function buildPlanningGraphEdges(groups: Map<string, AuditTask[]>, graphEdges: GraphEdge[], graphBundle?: GraphBundle, lineIndex?: Record<string, number>, sizeIndex?: Record<string, number>, targetPacketTokens?: number): GraphEdge[];
|
|
25
|
+
export declare function roundQuality(value: number): number;
|
|
26
|
+
export declare function buildPacketGraphContext(filePaths: string[], graphEdges: GraphEdge[], graphBundle?: GraphBundle): {
|
|
27
|
+
keyEdges: ReviewPacketGraphEdge[];
|
|
28
|
+
boundaryFiles: string[];
|
|
29
|
+
entrypoints: string[];
|
|
30
|
+
quality: ReviewPacketQuality;
|
|
31
|
+
};
|