auditor-lambda 0.10.3 → 0.10.8
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/audit-code-wrapper-build.mjs +198 -0
- package/audit-code-wrapper-install-hosts.mjs +1140 -0
- package/audit-code-wrapper-io.mjs +155 -0
- package/audit-code-wrapper-legacy.mjs +125 -0
- package/audit-code-wrapper-lib.mjs +22 -1806
- package/audit-code-wrapper-opencode.mjs +255 -0
- package/dispatch/merge-results.mjs +5 -3
- package/dispatch/validate-result.mjs +2 -2
- package/dist/adapters/coverageSummary.js +6 -2
- package/dist/adapters/normalizeExternal.js +16 -1
- package/dist/adapters/npmAudit.js +20 -9
- package/dist/adapters/semgrep.js +26 -1
- package/dist/cli/advanceAuditCommand.d.ts +1 -0
- package/dist/cli/advanceAuditCommand.js +95 -0
- package/dist/cli/args.js +2 -3
- package/dist/cli/auditStep.js +2 -2
- package/dist/cli/cleanup.d.ts +11 -1
- package/dist/cli/cleanup.js +25 -5
- package/dist/cli/cleanupCommand.d.ts +1 -0
- package/dist/cli/cleanupCommand.js +24 -0
- package/dist/cli/dispatch.d.ts +55 -31
- package/dist/cli/dispatch.js +298 -241
- package/dist/cli/dispatchStatusCommand.d.ts +1 -0
- package/dist/cli/dispatchStatusCommand.js +68 -0
- package/dist/cli/explainTaskCommand.d.ts +1 -0
- package/dist/cli/explainTaskCommand.js +33 -0
- package/dist/cli/importExternalAnalyzerCommand.d.ts +1 -0
- package/dist/cli/importExternalAnalyzerCommand.js +20 -0
- package/dist/cli/ingestResultsCommand.d.ts +1 -0
- package/dist/cli/ingestResultsCommand.js +34 -0
- package/dist/cli/intakeCommand.d.ts +1 -0
- package/dist/cli/intakeCommand.js +17 -0
- package/dist/cli/lineIndex.js +19 -12
- package/dist/cli/nextStepCommand.d.ts +139 -0
- package/dist/cli/nextStepCommand.js +281 -234
- package/dist/cli/planCommand.d.ts +1 -0
- package/dist/cli/planCommand.js +16 -0
- package/dist/cli/prepareDispatchCommand.d.ts +1 -0
- package/dist/cli/prepareDispatchCommand.js +25 -0
- package/dist/cli/quotaCommand.d.ts +1 -0
- package/dist/cli/quotaCommand.js +56 -0
- package/dist/cli/requeueCommand.d.ts +1 -0
- package/dist/cli/requeueCommand.js +10 -0
- package/dist/cli/runToCompletion.js +451 -412
- package/dist/cli/sampleRunCommand.d.ts +1 -0
- package/dist/cli/sampleRunCommand.js +93 -0
- package/dist/cli/statusCommand.js +1 -1
- package/dist/cli/steps.js +4 -1
- package/dist/cli/submitPacketCommand.js +16 -15
- package/dist/cli/synthesizeCommand.d.ts +1 -0
- package/dist/cli/synthesizeCommand.js +15 -0
- package/dist/cli/updateRuntimeValidationCommand.d.ts +1 -0
- package/dist/cli/updateRuntimeValidationCommand.js +16 -0
- package/dist/cli/validateCommand.d.ts +1 -0
- package/dist/cli/validateCommand.js +41 -0
- package/dist/cli/validateResultCommand.d.ts +1 -0
- package/dist/cli/validateResultCommand.js +63 -0
- package/dist/cli/validateResultsCommand.d.ts +1 -0
- package/dist/cli/validateResultsCommand.js +31 -0
- package/dist/cli/workerRunCommand.d.ts +15 -1
- package/dist/cli/workerRunCommand.js +40 -4
- package/dist/cli.d.ts +3 -2
- package/dist/cli.js +21 -628
- package/dist/coverage.js +7 -3
- package/dist/extractors/analyzers/css.js +2 -2
- package/dist/extractors/analyzers/html.js +2 -2
- package/dist/extractors/analyzers/python.js +2 -2
- package/dist/extractors/analyzers/registry.js +17 -36
- package/dist/extractors/analyzers/treeSitter.d.ts +10 -1
- package/dist/extractors/analyzers/treeSitter.js +28 -6
- package/dist/extractors/analyzers/typescript.js +104 -85
- package/dist/extractors/browserExtension.js +4 -1
- package/dist/extractors/designAssessment.js +21 -21
- package/dist/extractors/fsIntake.js +35 -11
- package/dist/extractors/graph.js +17 -7
- package/dist/extractors/graphManifestEdges/cargo.d.ts +4 -0
- package/dist/extractors/graphManifestEdges/cargo.js +107 -0
- package/dist/extractors/graphManifestEdges/go.d.ts +5 -0
- package/dist/extractors/graphManifestEdges/go.js +151 -0
- package/dist/extractors/graphManifestEdges/index.d.ts +8 -0
- package/dist/extractors/graphManifestEdges/index.js +11 -0
- package/dist/extractors/graphManifestEdges/jsonc.d.ts +3 -0
- package/dist/extractors/graphManifestEdges/jsonc.js +97 -0
- package/dist/extractors/graphManifestEdges/maven.d.ts +3 -0
- package/dist/extractors/graphManifestEdges/maven.js +73 -0
- package/dist/extractors/graphManifestEdges/packageJson.d.ts +19 -0
- package/dist/extractors/graphManifestEdges/packageJson.js +204 -0
- package/dist/extractors/graphManifestEdges/pnpm.d.ts +2 -0
- package/dist/extractors/graphManifestEdges/pnpm.js +42 -0
- package/dist/extractors/graphManifestEdges/pyproject.d.ts +3 -0
- package/dist/extractors/graphManifestEdges/pyproject.js +83 -0
- package/dist/extractors/graphManifestEdges/toml.d.ts +4 -0
- package/dist/extractors/graphManifestEdges/toml.js +68 -0
- package/dist/extractors/graphManifestEdges/typescript.d.ts +3 -0
- package/dist/extractors/graphManifestEdges/typescript.js +56 -0
- package/dist/extractors/graphManifestEdges/workspace.d.ts +10 -0
- package/dist/extractors/graphManifestEdges/workspace.js +72 -0
- package/dist/extractors/graphManifestEdges/yaml.d.ts +3 -0
- package/dist/extractors/graphManifestEdges/yaml.js +59 -0
- package/dist/extractors/graphManifestEdges/yamlPaths.d.ts +4 -0
- package/dist/extractors/graphManifestEdges/yamlPaths.js +89 -0
- package/dist/extractors/graphPythonImports.js +4 -20
- package/dist/extractors/pathPatterns.js +3 -13
- package/dist/io/artifacts.d.ts +1 -2
- package/dist/io/artifacts.js +8 -4
- package/dist/io/runArtifacts.d.ts +8 -2
- package/dist/io/runArtifacts.js +103 -69
- package/dist/io/toolingManifest.js +2 -1
- package/dist/orchestrator/advance.js +36 -0
- package/dist/orchestrator/artifactFreshness.d.ts +1 -1
- package/dist/orchestrator/artifactFreshness.js +1 -1
- package/dist/orchestrator/artifactMetadata.js +5 -5
- package/dist/orchestrator/auditTaskUtils.d.ts +4 -0
- package/dist/orchestrator/auditTaskUtils.js +8 -12
- package/dist/orchestrator/autoFixExecutor.js +40 -26
- package/dist/orchestrator/dependencyMap.js +1 -1
- package/dist/orchestrator/executorResult.d.ts +33 -0
- package/dist/orchestrator/executors.d.ts +7 -0
- package/dist/orchestrator/executors.js +24 -0
- package/dist/orchestrator/fileAnchors.js +42 -29
- package/dist/orchestrator/fileIntegrity.js +6 -1
- package/dist/orchestrator/flowCoverage.js +1 -2
- package/dist/orchestrator/flowPlanning.js +8 -4
- package/dist/orchestrator/graphEnrichmentExecutor.js +67 -45
- package/dist/orchestrator/ingestionExecutors.js +9 -1
- package/dist/orchestrator/intakeExecutors.d.ts +0 -4
- package/dist/orchestrator/intakeExecutors.js +24 -14
- package/dist/orchestrator/localCommands.d.ts +1 -0
- package/dist/orchestrator/localCommands.js +10 -17
- package/dist/orchestrator/nextStep.js +3 -1
- package/dist/orchestrator/requeueCommand.js +4 -0
- package/dist/orchestrator/reviewPacketGraph.js +50 -18
- package/dist/orchestrator/reviewPackets.js +10 -8
- package/dist/orchestrator/runtimeCommand.js +35 -7
- package/dist/orchestrator/runtimeValidationUpdate.js +6 -0
- package/dist/orchestrator/selectiveDeepening/highRiskClean.js +3 -2
- package/dist/orchestrator/selectiveDeepening/lensVerification.js +44 -18
- package/dist/orchestrator/staleness.js +3 -3
- package/dist/orchestrator/state.js +1 -1
- package/dist/orchestrator/syntaxResolutionExecutor.js +17 -24
- package/dist/orchestrator/synthesisExecutors.js +1 -0
- package/dist/orchestrator/taskBuilder.js +5 -4
- package/dist/providers/claudeCodeProvider.js +5 -2
- package/dist/providers/opencodeProvider.js +4 -1
- package/dist/quota/discoveredLimits.js +3 -3
- package/dist/quota/headerExtraction.js +5 -2
- package/dist/quota/headerExtractors/claudeCodeHeaderExtractor.js +3 -0
- package/dist/quota/headerExtractors/index.js +3 -3
- package/dist/quota/index.d.ts +3 -1
- package/dist/quota/index.js +3 -0
- package/dist/reporting/findingRanks.d.ts +3 -0
- package/dist/reporting/findingRanks.js +24 -0
- package/dist/reporting/mergeFindings.js +1 -24
- package/dist/reporting/synthesis.d.ts +3 -1
- package/dist/reporting/synthesis.js +30 -6
- package/dist/reporting/synthesisNarrativePrompt.js +3 -0
- package/dist/reporting/workBlocks.js +1 -14
- package/dist/supervisor/operatorHandoff.js +2 -6
- package/dist/supervisor/runLedger.js +30 -41
- package/dist/types/activeDispatch.d.ts +31 -0
- package/dist/types/activeDispatch.js +2 -0
- package/dist/types.d.ts +21 -4
- package/dist/types.js +24 -16
- package/dist/validation/artifacts.js +3 -0
- package/dist/validation/auditResults.js +8 -2
- package/package.json +2 -2
- package/schemas/audit_findings.schema.json +5 -1
- package/schemas/audit_plan_metrics.schema.json +1 -1
- package/schemas/audit_result.schema.json +5 -6
- package/schemas/audit_task.schema.json +1 -4
- package/schemas/blind_spot_register.schema.json +1 -1
- package/schemas/coverage_matrix.schema.json +2 -8
- package/schemas/finding.schema.json +1 -16
- package/schemas/flow_coverage.schema.json +2 -8
- package/schemas/graph_bundle.schema.json +31 -0
- package/schemas/lens.schema.json +7 -0
- package/schemas/review_packets.schema.json +6 -17
- package/schemas/step_contract.schema.json +8 -2
- package/schemas/unit_manifest.schema.json +1 -4
- package/scripts/postinstall.mjs +4 -3
- package/skills/audit-code/audit-code.prompt.md +3 -4
- package/dist/extractors/graphManifestEdges.d.ts +0 -12
- package/dist/extractors/graphManifestEdges.js +0 -1135
|
@@ -4,10 +4,6 @@ import { isGitRepo, writeJsonFile } from "@audit-tools/shared";
|
|
|
4
4
|
import { buildFileDisposition, isAuditExcludedStatus, } from "../extractors/disposition.js";
|
|
5
5
|
import { buildRepoManifestFromFs } from "../extractors/fsIntake.js";
|
|
6
6
|
import { loadIgnoreFile } from "../extractors/ignore.js";
|
|
7
|
-
/** Prefix used to carry the scope summary inside `progress_summary` for hosts
|
|
8
|
-
* that read the step's progress text rather than the `scope_summary.json`
|
|
9
|
-
* artifact. The loader extracts everything after this marker as JSON. */
|
|
10
|
-
export const SCOPE_SUMMARY_PREFIX = "SCOPE_SUMMARY:";
|
|
11
7
|
/**
|
|
12
8
|
* Detect signals that the resolved audit root may be the *wrong* directory.
|
|
13
9
|
* Two heuristics, returned as zero or more human-readable warnings:
|
|
@@ -37,14 +33,30 @@ export function detectMisScopeSmells(root) {
|
|
|
37
33
|
}
|
|
38
34
|
}
|
|
39
35
|
// (b) Workspace member of a parent monorepo.
|
|
36
|
+
// Walk up ancestor directories (up to 3 levels) looking for a package.json
|
|
37
|
+
// that declares a `workspaces` field. This handles standard nested monorepo
|
|
38
|
+
// layouts like `monorepo-root/packages/my-pkg` where the direct parent
|
|
39
|
+
// (`packages/`) has no package.json of its own. Stop early if a .git
|
|
40
|
+
// boundary is found (we already checked that case under heuristic (a)).
|
|
40
41
|
const rootPkg = readPackageJson(root);
|
|
41
42
|
if (rootPkg && rootPkg.name !== undefined) {
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
43
|
+
let current = dirname(root);
|
|
44
|
+
let previous = root;
|
|
45
|
+
let levelsChecked = 0;
|
|
46
|
+
const maxLevels = 3;
|
|
47
|
+
while (current && current !== previous && levelsChecked < maxLevels) {
|
|
48
|
+
const ancestorPkg = readPackageJson(current);
|
|
49
|
+
if (ancestorPkg && ancestorPkg.workspaces !== undefined) {
|
|
50
|
+
smells.push(`root appears to be a workspace member of a parent monorepo at '${current}' — consider auditing from the monorepo root instead`);
|
|
51
|
+
break;
|
|
52
|
+
}
|
|
53
|
+
// Stop at a .git boundary — the repo root won't be a workspaces ancestor.
|
|
54
|
+
if (existsSync(join(current, ".git"))) {
|
|
55
|
+
break;
|
|
47
56
|
}
|
|
57
|
+
previous = current;
|
|
58
|
+
current = dirname(current);
|
|
59
|
+
levelsChecked++;
|
|
48
60
|
}
|
|
49
61
|
}
|
|
50
62
|
return smells;
|
|
@@ -84,15 +96,13 @@ export async function runIntakeExecutor(bundle, root, artifactsDir) {
|
|
|
84
96
|
};
|
|
85
97
|
const artifactsWritten = ["repo_manifest.json", "file_disposition.json"];
|
|
86
98
|
// Persist the scope summary alongside the other intake artifacts when we know
|
|
87
|
-
// where the artifacts directory is.
|
|
88
|
-
//
|
|
89
|
-
// the file directly.
|
|
99
|
+
// where the artifacts directory is. Hosts read scope_summary.json directly;
|
|
100
|
+
// the typed `scope_summary` field on ExecutorRunResult is the in-process channel.
|
|
90
101
|
if (artifactsDir) {
|
|
91
102
|
await writeJsonFile(join(artifactsDir, "scope_summary.json"), scopeSummary);
|
|
92
103
|
artifactsWritten.push("scope_summary.json");
|
|
93
104
|
}
|
|
94
|
-
const progressSummary =
|
|
95
|
-
`Created intake artifacts for ${repoManifest.files.length} files ` +
|
|
105
|
+
const progressSummary = `Created intake artifacts for ${repoManifest.files.length} files ` +
|
|
96
106
|
`(${auditableCount} auditable). Scope: ${root}, git: ${scopeSummary.git_available ? "yes" : "no"}` +
|
|
97
107
|
(scopeSummary.mis_scope_smells.length > 0
|
|
98
108
|
? `; ${scopeSummary.mis_scope_smells.length} mis-scope warning(s)`
|
|
@@ -10,5 +10,6 @@ export interface LocalCommandResult {
|
|
|
10
10
|
stderr: string;
|
|
11
11
|
error?: Error;
|
|
12
12
|
}
|
|
13
|
+
export declare function __resolveFromPathForTests(command: string): string | null;
|
|
13
14
|
export declare function runFirstAvailableCommand(root: string, candidates: LocalCommandCandidate[]): LocalCommandResult | null;
|
|
14
15
|
export declare function resolveNodeTool(root: string, relativePath: string, args: string[], display: string): LocalCommandCandidate[];
|
|
@@ -9,6 +9,9 @@ function toSpawnTuple(candidate) {
|
|
|
9
9
|
const resolved = resolveExecArgv([candidate.command, ...candidate.args]);
|
|
10
10
|
return { command: resolved[0], args: resolved.slice(1) };
|
|
11
11
|
}
|
|
12
|
+
export function __resolveFromPathForTests(command) {
|
|
13
|
+
return resolveFromPath(command);
|
|
14
|
+
}
|
|
12
15
|
function resolveFromPath(command) {
|
|
13
16
|
if (command.trim().length === 0) {
|
|
14
17
|
return null;
|
|
@@ -30,24 +33,14 @@ function resolveFromPath(command) {
|
|
|
30
33
|
.filter((ext) => ext.length > 0)
|
|
31
34
|
.map((ext) => (ext.startsWith(".") ? ext : `.${ext}`))
|
|
32
35
|
: [""];
|
|
36
|
+
// On Win32 without an extension: probe PATHEXT extensions first, then the
|
|
37
|
+
// bare name (empty-string suffix). On Win32 with an extension, or non-Win32:
|
|
38
|
+
// use only the bare name (extensions is already [''] on non-Win32).
|
|
39
|
+
const effectiveExtensions = process.platform === "win32" && extname(command).length === 0
|
|
40
|
+
? [...extensions, ""]
|
|
41
|
+
: [""];
|
|
33
42
|
for (const dir of pathEntries) {
|
|
34
|
-
const
|
|
35
|
-
if (process.platform === "win32" && extname(command).length === 0) {
|
|
36
|
-
for (const ext of extensions) {
|
|
37
|
-
const candidatePath = join(dir, `${command}${ext}`);
|
|
38
|
-
if (existsSync(candidatePath)) {
|
|
39
|
-
return candidatePath;
|
|
40
|
-
}
|
|
41
|
-
}
|
|
42
|
-
if (existsSync(directPath)) {
|
|
43
|
-
return directPath;
|
|
44
|
-
}
|
|
45
|
-
continue;
|
|
46
|
-
}
|
|
47
|
-
if (existsSync(directPath)) {
|
|
48
|
-
return directPath;
|
|
49
|
-
}
|
|
50
|
-
for (const ext of extensions) {
|
|
43
|
+
for (const ext of effectiveExtensions) {
|
|
51
44
|
const candidatePath = join(dir, `${command}${ext}`);
|
|
52
45
|
if (existsSync(candidatePath)) {
|
|
53
46
|
return candidatePath;
|
|
@@ -53,6 +53,8 @@ export function decideNextStep(bundle) {
|
|
|
53
53
|
state,
|
|
54
54
|
selected_obligation: next.id,
|
|
55
55
|
selected_executor: executor?.id ?? null,
|
|
56
|
-
reason:
|
|
56
|
+
reason: executor
|
|
57
|
+
? `Selected highest-priority actionable obligation ${next.id}.`
|
|
58
|
+
: `No executor found for obligation ${next.id}; EXECUTOR_REGISTRY has no entry for this obligation ID. This is a configuration gap — the obligation was selected but cannot be dispatched.`,
|
|
57
59
|
};
|
|
58
60
|
}
|
|
@@ -26,10 +26,14 @@ function dedupeByScope(tasks) {
|
|
|
26
26
|
return deduped;
|
|
27
27
|
}
|
|
28
28
|
export function buildRequeuePayload(matrix, criticalFlows, flowCoverage, externalAnalyzerResults) {
|
|
29
|
+
// Dedupe within each source first — each generator may emit duplicate task_ids independently.
|
|
29
30
|
const fileTasks = dedupeTasks(buildRequeueTasks(matrix, externalAnalyzerResults));
|
|
30
31
|
const flowTasks = criticalFlows && flowCoverage
|
|
31
32
|
? dedupeTasks(buildFlowRequeueTasks(criticalFlows, flowCoverage, matrix, externalAnalyzerResults))
|
|
32
33
|
: [];
|
|
34
|
+
// Two-pass post-merge dedup:
|
|
35
|
+
// 1. dedupeTasks removes any cross-source task_id collisions (same task emitted by both generators).
|
|
36
|
+
// 2. dedupeByScope removes tasks that cover the same lens+file_paths scope but carry different task_ids.
|
|
33
37
|
const tasks = dedupeByScope(dedupeTasks([...fileTasks, ...flowTasks]));
|
|
34
38
|
return {
|
|
35
39
|
task_count: tasks.length,
|
|
@@ -202,26 +202,58 @@ export function unionFindFromGroups(groups, graphEdges) {
|
|
|
202
202
|
const uf = new UnionFind(groups.keys());
|
|
203
203
|
const fileToGroupKeys = buildFileToGroupKeys(groups);
|
|
204
204
|
const degreeIndex = buildGraphDegreeIndex(graphEdges);
|
|
205
|
+
const verbose = Boolean(process.env.AUDIT_CODE_VERBOSE);
|
|
205
206
|
for (const keys of fileToGroupKeys.values()) {
|
|
206
207
|
const [first, ...rest] = [...keys].sort((a, b) => a.localeCompare(b));
|
|
207
208
|
if (!first)
|
|
208
209
|
continue;
|
|
209
210
|
for (const key of rest) {
|
|
210
|
-
|
|
211
|
+
if (verbose) {
|
|
212
|
+
const rootBefore = uf.find(key);
|
|
213
|
+
const rootFirst = uf.find(first);
|
|
214
|
+
uf.union(first, key);
|
|
215
|
+
if (rootFirst !== rootBefore) {
|
|
216
|
+
process.stderr.write(`[audit-code:packet-planning] shared-file merge: "${first}" + "${key}" (roots "${rootFirst}" + "${rootBefore}" → "${uf.find(first)}")\n`);
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
else {
|
|
220
|
+
uf.union(first, key);
|
|
221
|
+
}
|
|
211
222
|
}
|
|
212
223
|
}
|
|
213
224
|
for (const edge of graphEdges) {
|
|
225
|
+
const fromGroups = fileToGroupKeys.get(normalizeGraphPath(edge.from));
|
|
226
|
+
const toGroups = fileToGroupKeys.get(normalizeGraphPath(edge.to));
|
|
214
227
|
if (!isPacketExpansionEdge(edge, degreeIndex)) {
|
|
228
|
+
if (verbose && fromGroups && toGroups) {
|
|
229
|
+
// Edge has group mappings but was filtered — check if it was the
|
|
230
|
+
// high fan-degree guard specifically.
|
|
231
|
+
const fromFanOut = degreeIndex.fanOut.get(normalizeGraphPath(edge.from)) ?? 0;
|
|
232
|
+
const toFanIn = degreeIndex.fanIn.get(normalizeGraphPath(edge.to)) ?? 0;
|
|
233
|
+
const highFanEdge = fromFanOut > HIGH_FAN_DEGREE_THRESHOLD ||
|
|
234
|
+
toFanIn > HIGH_FAN_DEGREE_THRESHOLD;
|
|
235
|
+
if (highFanEdge) {
|
|
236
|
+
process.stderr.write(`[audit-code:packet-planning] edge skip (high-fan-degree): "${edge.from}" → "${edge.to}" (fanOut=${fromFanOut}, fanIn=${toFanIn})\n`);
|
|
237
|
+
}
|
|
238
|
+
}
|
|
215
239
|
continue;
|
|
216
240
|
}
|
|
217
|
-
const fromGroups = fileToGroupKeys.get(normalizeGraphPath(edge.from));
|
|
218
|
-
const toGroups = fileToGroupKeys.get(normalizeGraphPath(edge.to));
|
|
219
241
|
if (!fromGroups || !toGroups) {
|
|
220
242
|
continue;
|
|
221
243
|
}
|
|
222
244
|
for (const fromKey of fromGroups) {
|
|
223
245
|
for (const toKey of toGroups) {
|
|
224
|
-
|
|
246
|
+
if (verbose) {
|
|
247
|
+
const rootFrom = uf.find(fromKey);
|
|
248
|
+
const rootTo = uf.find(toKey);
|
|
249
|
+
uf.union(fromKey, toKey);
|
|
250
|
+
if (rootFrom !== rootTo) {
|
|
251
|
+
process.stderr.write(`[audit-code:packet-planning] edge-driven merge: "${fromKey}" + "${toKey}" via edge "${edge.from}" → "${edge.to}" (kind=${edge.kind ?? "unknown"})\n`);
|
|
252
|
+
}
|
|
253
|
+
}
|
|
254
|
+
else {
|
|
255
|
+
uf.union(fromKey, toKey);
|
|
256
|
+
}
|
|
225
257
|
}
|
|
226
258
|
}
|
|
227
259
|
}
|
|
@@ -588,20 +620,20 @@ function buildEntrypointFlowBridgeEdges(groups, graphEdges, graphBundle) {
|
|
|
588
620
|
return [...bridgeEdges.values()].sort(compareGraphEdges);
|
|
589
621
|
}
|
|
590
622
|
export function buildPlanningGraphEdges(groups, graphEdges, graphBundle, lineIndex, sizeIndex, targetPacketTokens = DEFAULT_TARGET_PACKET_TOKENS) {
|
|
591
|
-
|
|
592
|
-
const
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
const
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
const moduleOwnershipEdges = buildModuleOwnershipClusterEdges(groups,
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
623
|
+
let edges = graphEdges;
|
|
624
|
+
const bridgeEdges = buildEntrypointFlowBridgeEdges(groups, edges, graphBundle);
|
|
625
|
+
if (bridgeEdges.length > 0)
|
|
626
|
+
edges = [...edges, ...bridgeEdges];
|
|
627
|
+
const subsystemEdges = buildSubsystemClusterEdges(groups, edges, lineIndex, sizeIndex, targetPacketTokens);
|
|
628
|
+
if (subsystemEdges.length > 0)
|
|
629
|
+
edges = [...edges, ...subsystemEdges];
|
|
630
|
+
const packageOwnershipEdges = buildPackageOwnershipClusterEdges(groups, edges, lineIndex, sizeIndex, targetPacketTokens);
|
|
631
|
+
if (packageOwnershipEdges.length > 0)
|
|
632
|
+
edges = [...edges, ...packageOwnershipEdges];
|
|
633
|
+
const moduleOwnershipEdges = buildModuleOwnershipClusterEdges(groups, edges, lineIndex, sizeIndex, targetPacketTokens);
|
|
634
|
+
if (moduleOwnershipEdges.length > 0)
|
|
635
|
+
edges = [...edges, ...moduleOwnershipEdges];
|
|
636
|
+
return edges;
|
|
605
637
|
}
|
|
606
638
|
function compareGraphEdges(a, b) {
|
|
607
639
|
const confidenceDelta = graphEdgeConfidence(b) - graphEdgeConfidence(a);
|
|
@@ -3,6 +3,7 @@ import { LENS_ORDER, priorityRank, sortLenses } from "./auditTaskUtils.js";
|
|
|
3
3
|
import { normalizeGraphPath } from "../extractors/graphPathUtils.js";
|
|
4
4
|
import { DEFAULT_MAX_TASKS_PER_PACKET, DEFAULT_TARGET_PACKET_TOKENS, ESTIMATED_TOKENS_PER_LINE, ESTIMATED_PACKET_PROMPT_TOKENS, sizeIndexFromManifest, fileGroupContentTokens, taskContentTokens, estimateTaskGroupTokens, } from "./reviewPacketSizing.js";
|
|
5
5
|
import { HIGH_FAN_DEGREE_THRESHOLD, collectGraphEdges, buildGraphDegreeIndex, isPacketExpansionEdge, buildFileToGroupKeys, isConcreteGraphEdge, unionFindFromGroups, roundQuality, buildPlanningGraphEdges, buildPacketGraphContext, } from "./reviewPacketGraph.js";
|
|
6
|
+
import { sanitizeSegment } from "./selectiveDeepening/shared.js";
|
|
6
7
|
// Re-exported for scope.ts, which imports the canonical path normalizer here.
|
|
7
8
|
export { normalizeGraphPath };
|
|
8
9
|
// Sizing / token-budget arithmetic moved to reviewPacketSizing.ts; re-exported
|
|
@@ -42,12 +43,6 @@ function buildTaskGroups(tasks) {
|
|
|
42
43
|
}
|
|
43
44
|
return groups;
|
|
44
45
|
}
|
|
45
|
-
function sanitizeSegment(value) {
|
|
46
|
-
const sanitized = value
|
|
47
|
-
.replace(/[^a-zA-Z0-9_-]+/g, "-")
|
|
48
|
-
.replace(/^-+|-+$/g, "");
|
|
49
|
-
return sanitized.length > 0 ? sanitized : "packet";
|
|
50
|
-
}
|
|
51
46
|
function packetIdFor(tasks, packetIndex) {
|
|
52
47
|
const unit = sanitizeSegment(tasks[0]?.unit_id ?? "review");
|
|
53
48
|
const lenses = sortLenses(tasks.map((task) => task.lens)).join("-");
|
|
@@ -75,15 +70,19 @@ function comparePackets(a, b) {
|
|
|
75
70
|
function chunkPacketTasks(tasks, options) {
|
|
76
71
|
const chunks = [];
|
|
77
72
|
let current = [];
|
|
73
|
+
const verbose = Boolean(process.env.AUDIT_CODE_VERBOSE);
|
|
78
74
|
for (const task of tasks.sort(compareTasksForPacket)) {
|
|
75
|
+
const taskEstimatedTokens = taskContentTokens(task, options.sizeIndex, options.lineIndex);
|
|
79
76
|
const isolatedLargeFileTask = task.file_paths.length === 1 &&
|
|
80
|
-
|
|
81
|
-
options.targetPacketTokens;
|
|
77
|
+
taskEstimatedTokens > options.targetPacketTokens;
|
|
82
78
|
if (isolatedLargeFileTask) {
|
|
83
79
|
if (current.length > 0) {
|
|
84
80
|
chunks.push(current);
|
|
85
81
|
current = [];
|
|
86
82
|
}
|
|
83
|
+
if (verbose) {
|
|
84
|
+
process.stderr.write(`[audit-code:packet-planning] isolated large-file chunk: task="${task.task_id}" file="${task.file_paths[0]}" estimatedTokens=${taskEstimatedTokens} targetPacketTokens=${options.targetPacketTokens}\n`);
|
|
85
|
+
}
|
|
87
86
|
chunks.push([task]);
|
|
88
87
|
continue;
|
|
89
88
|
}
|
|
@@ -93,6 +92,9 @@ function chunkPacketTasks(tasks, options) {
|
|
|
93
92
|
const wouldExceedTaskCount = options.maxTasksPerPacket > 0 && current.length > 0 && candidate.length > options.maxTasksPerPacket;
|
|
94
93
|
const wouldExceedTokens = current.length > 0 && candidateContentTokens > options.targetPacketTokens;
|
|
95
94
|
if (wouldExceedTaskCount || wouldExceedTokens) {
|
|
95
|
+
if (verbose && wouldExceedTokens) {
|
|
96
|
+
process.stderr.write(`[audit-code:packet-planning] token-budget split: task="${task.task_id}" file="${task.file_paths[0] ?? ""}" candidateContentTokens=${candidateContentTokens} targetPacketTokens=${options.targetPacketTokens}\n`);
|
|
97
|
+
}
|
|
96
98
|
chunks.push(current);
|
|
97
99
|
current = [];
|
|
98
100
|
}
|
|
@@ -32,21 +32,49 @@ export async function runCommand(command, cwd, options = {}) {
|
|
|
32
32
|
child.stderr.on("data", (chunk) => {
|
|
33
33
|
stderr += String(chunk);
|
|
34
34
|
});
|
|
35
|
+
let exitCode = null;
|
|
36
|
+
let exitSignal = null;
|
|
35
37
|
child.on("error", (error) => {
|
|
38
|
+
const output = `${stdout}\n${stderr}`.trim();
|
|
39
|
+
const lines = output.length > 0 ? output.split(/\r?\n/) : [];
|
|
40
|
+
const truncated = lines.length > 10;
|
|
41
|
+
const evidence = truncated
|
|
42
|
+
? [`[... truncated: showing last 10 of ${lines.length} lines ...]`, ...lines.slice(-10)]
|
|
43
|
+
: lines;
|
|
36
44
|
resolve({
|
|
37
45
|
status: "inconclusive",
|
|
38
46
|
summary: `Failed to execute ${displayCommand}: ${error.message}`,
|
|
39
|
-
evidence
|
|
47
|
+
evidence,
|
|
40
48
|
});
|
|
41
49
|
});
|
|
42
|
-
child.on("exit", (code) => {
|
|
50
|
+
child.on("exit", (code, signal) => {
|
|
51
|
+
exitCode = code;
|
|
52
|
+
exitSignal = signal;
|
|
53
|
+
});
|
|
54
|
+
child.on("close", () => {
|
|
43
55
|
const output = `${stdout}\n${stderr}`.trim();
|
|
44
|
-
const
|
|
56
|
+
const lines = output.length > 0 ? output.split(/\r?\n/) : [];
|
|
57
|
+
const truncated = lines.length > 10;
|
|
58
|
+
const evidence = truncated
|
|
59
|
+
? [`[... truncated: showing last 10 of ${lines.length} lines ...]`, ...lines.slice(-10)]
|
|
60
|
+
: lines;
|
|
61
|
+
const succeeded = exitCode === 0;
|
|
62
|
+
let summary;
|
|
63
|
+
if (succeeded) {
|
|
64
|
+
summary = `Deterministic runtime command succeeded: ${displayCommand}`;
|
|
65
|
+
}
|
|
66
|
+
else if (exitCode !== null) {
|
|
67
|
+
summary = `Deterministic runtime command failed with exit code ${exitCode}: ${displayCommand}`;
|
|
68
|
+
}
|
|
69
|
+
else if (exitSignal !== null) {
|
|
70
|
+
summary = `Deterministic runtime command terminated by signal ${exitSignal}: ${displayCommand}`;
|
|
71
|
+
}
|
|
72
|
+
else {
|
|
73
|
+
summary = `Deterministic runtime command exited with unknown status: ${displayCommand}`;
|
|
74
|
+
}
|
|
45
75
|
resolve({
|
|
46
|
-
status:
|
|
47
|
-
summary
|
|
48
|
-
? `Deterministic runtime command succeeded: ${displayCommand}`
|
|
49
|
-
: `Deterministic runtime command failed with exit code ${code}: ${displayCommand}`,
|
|
76
|
+
status: succeeded ? "confirmed" : "not_confirmed",
|
|
77
|
+
summary,
|
|
50
78
|
evidence,
|
|
51
79
|
});
|
|
52
80
|
});
|
|
@@ -8,14 +8,17 @@ function normalizeResult(result) {
|
|
|
8
8
|
export function updateRuntimeValidationReport(tasks, existing, updates) {
|
|
9
9
|
const validTaskIds = new Set(tasks.tasks.map((task) => task.id));
|
|
10
10
|
const merged = new Map();
|
|
11
|
+
const staleIds = new Set();
|
|
11
12
|
for (const result of existing.results) {
|
|
12
13
|
if (!validTaskIds.has(result.task_id)) {
|
|
14
|
+
staleIds.add(result.task_id);
|
|
13
15
|
continue;
|
|
14
16
|
}
|
|
15
17
|
merged.set(result.task_id, normalizeResult(result));
|
|
16
18
|
}
|
|
17
19
|
for (const update of updates.results) {
|
|
18
20
|
if (!validTaskIds.has(update.task_id)) {
|
|
21
|
+
staleIds.add(update.task_id);
|
|
19
22
|
continue;
|
|
20
23
|
}
|
|
21
24
|
const prior = merged.get(update.task_id);
|
|
@@ -33,6 +36,9 @@ export function updateRuntimeValidationReport(tasks, existing, updates) {
|
|
|
33
36
|
notes: [...new Set([...(prior.notes ?? []), ...(update.notes ?? [])])],
|
|
34
37
|
});
|
|
35
38
|
}
|
|
39
|
+
if (staleIds.size > 0) {
|
|
40
|
+
console.warn("[runtimeValidationUpdate] Dropped %d stale result(s) not in task manifest: %s", staleIds.size, [...staleIds].join(", "));
|
|
41
|
+
}
|
|
36
42
|
for (const task of tasks.tasks) {
|
|
37
43
|
if (!merged.has(task.id)) {
|
|
38
44
|
merged.set(task.id, {
|
|
@@ -18,8 +18,9 @@ export function isHighRiskCleanResult(result, task) {
|
|
|
18
18
|
return result.requires_followup === true && task.priority === "medium";
|
|
19
19
|
}
|
|
20
20
|
export function buildHighRiskCleanFollowupTask(params) {
|
|
21
|
-
const
|
|
22
|
-
|
|
21
|
+
const taskFilePaths = params.task?.file_paths;
|
|
22
|
+
const paths = uniqueSorted(taskFilePaths && taskFilePaths.length > 0
|
|
23
|
+
? taskFilePaths
|
|
23
24
|
: params.result.file_coverage.map((coverage) => coverage.path));
|
|
24
25
|
return {
|
|
25
26
|
task_id: taskIdFor("clean", [params.result.task_id, params.result.lens]),
|
|
@@ -1,5 +1,15 @@
|
|
|
1
1
|
import { isHighRiskCleanResult } from "./highRiskClean.js";
|
|
2
2
|
import { DEEPENING_TAG, IMPORTANT_LENS_VERIFICATION_LENSES, LENS_VERIFICATION_TAG, MAX_LENS_VERIFICATION_FILES, MAX_LENS_VERIFICATION_RESULT_SUMMARIES, SEVERITY_RANK, formatList, getExternalAnalyzerPaths, isDeepeningTask, isLensVerificationTask, lineCountForPath, lineCountFromSources, priorityLabel, priorityRank, taskIdFor, uniqueSorted, } from "./shared.js";
|
|
3
|
+
/** Score boost for files touched by a critical-flow task — highest semantic signal. */
|
|
4
|
+
const SCORE_CRITICAL_FLOW = 6;
|
|
5
|
+
/** Score boost for files flagged by an external analyzer tool — treated equally to critical-flow signal. */
|
|
6
|
+
const SCORE_EXTERNAL_ANALYZER_SIGNAL = 6;
|
|
7
|
+
/** Score boost for files from a large-file task — moderately elevated scrutiny. */
|
|
8
|
+
const SCORE_LARGE_FILE = 4;
|
|
9
|
+
/** Score boost for a high-risk task whose result was suspiciously clean — warrants re-examination. */
|
|
10
|
+
const SCORE_HIGH_RISK_CLEAN = 5;
|
|
11
|
+
/** Score boost for files directly matched by an external-analyzer path set — strongest single boost, above tag signals. */
|
|
12
|
+
const SCORE_EXTERNAL_ANALYZER_PATH_MATCH = 8;
|
|
3
13
|
function sourceTaskIds(sources) {
|
|
4
14
|
return uniqueSorted(sources.map((source) => source.result.task_id));
|
|
5
15
|
}
|
|
@@ -16,12 +26,16 @@ function lensVerificationTriggers(params) {
|
|
|
16
26
|
const cleanResults = params.sources.filter((source) => source.result.findings.length === 0 &&
|
|
17
27
|
source.result.requires_followup !== false);
|
|
18
28
|
const highRiskCleanResults = params.sources.filter((source) => isHighRiskCleanResult(source.result, source.task));
|
|
29
|
+
const pathOwnerMap = new Map();
|
|
30
|
+
for (const source of params.sources) {
|
|
31
|
+
for (const path of resultFiles(source)) {
|
|
32
|
+
if (!pathOwnerMap.has(path))
|
|
33
|
+
pathOwnerMap.set(path, source);
|
|
34
|
+
}
|
|
35
|
+
}
|
|
19
36
|
const totalLines = filePaths.reduce((sum, path) => {
|
|
20
|
-
const owner =
|
|
21
|
-
return
|
|
22
|
-
(owner
|
|
23
|
-
? lineCountForPath(path, owner.task, owner.result)
|
|
24
|
-
: 0));
|
|
37
|
+
const owner = pathOwnerMap.get(path);
|
|
38
|
+
return sum + (owner ? lineCountForPath(path, owner.task, owner.result) : 0);
|
|
25
39
|
}, 0);
|
|
26
40
|
const triggers = [];
|
|
27
41
|
if (params.sources.some((source) => source.task?.priority === "high")) {
|
|
@@ -90,7 +104,7 @@ function shouldBuildLensVerificationTask(params) {
|
|
|
90
104
|
const candidateId = taskIdFor("steward", [params.lens, ...sourceSignature]);
|
|
91
105
|
return !params.existingTasks.some((task) => task.task_id === candidateId);
|
|
92
106
|
}
|
|
93
|
-
function selectLensVerificationFiles(sources, externalAnalyzerPaths) {
|
|
107
|
+
function selectLensVerificationFiles(sources, externalAnalyzerPaths, lens) {
|
|
94
108
|
const scores = new Map();
|
|
95
109
|
function add(path, score, lines) {
|
|
96
110
|
const current = scores.get(path) ?? { score: 0, lines };
|
|
@@ -104,13 +118,13 @@ function selectLensVerificationFiles(sources, externalAnalyzerPaths) {
|
|
|
104
118
|
for (const path of resultFiles(source)) {
|
|
105
119
|
add(path, priorityScore, lineCountForPath(path, source.task, source.result));
|
|
106
120
|
if (source.task?.tags?.includes("critical_flow"))
|
|
107
|
-
add(path,
|
|
121
|
+
add(path, SCORE_CRITICAL_FLOW, 0);
|
|
108
122
|
if (source.task?.tags?.includes("external_analyzer_signal"))
|
|
109
|
-
add(path,
|
|
123
|
+
add(path, SCORE_EXTERNAL_ANALYZER_SIGNAL, 0);
|
|
110
124
|
if (source.task?.tags?.includes("large_file"))
|
|
111
|
-
add(path,
|
|
125
|
+
add(path, SCORE_LARGE_FILE, 0);
|
|
112
126
|
if (highRiskClean)
|
|
113
|
-
add(path,
|
|
127
|
+
add(path, SCORE_HIGH_RISK_CLEAN, 0);
|
|
114
128
|
}
|
|
115
129
|
for (const finding of source.result.findings) {
|
|
116
130
|
for (const file of finding.affected_files) {
|
|
@@ -120,7 +134,7 @@ function selectLensVerificationFiles(sources, externalAnalyzerPaths) {
|
|
|
120
134
|
}
|
|
121
135
|
for (const path of externalAnalyzerPaths) {
|
|
122
136
|
if (scores.has(path)) {
|
|
123
|
-
add(path,
|
|
137
|
+
add(path, SCORE_EXTERNAL_ANALYZER_PATH_MATCH, 0);
|
|
124
138
|
}
|
|
125
139
|
}
|
|
126
140
|
const ranked = [...scores.entries()].sort((a, b) => {
|
|
@@ -133,10 +147,15 @@ function selectLensVerificationFiles(sources, externalAnalyzerPaths) {
|
|
|
133
147
|
return a[0].localeCompare(b[0]);
|
|
134
148
|
});
|
|
135
149
|
if (ranked.length > MAX_LENS_VERIFICATION_FILES) {
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
150
|
+
process.stderr.write(JSON.stringify({
|
|
151
|
+
level: "warn",
|
|
152
|
+
source: "audit-code:selectiveDeepening",
|
|
153
|
+
event: "truncated_verification_file_list",
|
|
154
|
+
lens,
|
|
155
|
+
kept: MAX_LENS_VERIFICATION_FILES,
|
|
156
|
+
total: ranked.length,
|
|
157
|
+
ts: new Date().toISOString(),
|
|
158
|
+
}) + "\n");
|
|
140
159
|
}
|
|
141
160
|
return ranked.slice(0, MAX_LENS_VERIFICATION_FILES).map(([path]) => path);
|
|
142
161
|
}
|
|
@@ -156,13 +175,20 @@ function summarizeLensVerificationSource(source) {
|
|
|
156
175
|
}
|
|
157
176
|
function buildLensVerificationTask(params) {
|
|
158
177
|
const sourceIds = sourceTaskIds(params.sources);
|
|
159
|
-
const selectedPaths = selectLensVerificationFiles(params.sources, params.externalAnalyzerPaths);
|
|
178
|
+
const selectedPaths = selectLensVerificationFiles(params.sources, params.externalAnalyzerPaths, params.lens);
|
|
160
179
|
const allPaths = uniqueSorted(params.sources.flatMap(resultFiles));
|
|
161
180
|
const omittedPathCount = Math.max(0, allPaths.length - selectedPaths.length);
|
|
162
181
|
const externalPathsInScope = allPaths.filter((path) => params.externalAnalyzerPaths.has(path));
|
|
163
182
|
if (params.sources.length > MAX_LENS_VERIFICATION_RESULT_SUMMARIES) {
|
|
164
|
-
process.stderr.write(
|
|
165
|
-
|
|
183
|
+
process.stderr.write(JSON.stringify({
|
|
184
|
+
level: "warn",
|
|
185
|
+
source: "audit-code:selectiveDeepening",
|
|
186
|
+
event: "truncated_result_summary_list",
|
|
187
|
+
lens: params.lens,
|
|
188
|
+
kept: MAX_LENS_VERIFICATION_RESULT_SUMMARIES,
|
|
189
|
+
total: params.sources.length,
|
|
190
|
+
ts: new Date().toISOString(),
|
|
191
|
+
}) + "\n");
|
|
166
192
|
}
|
|
167
193
|
const summaries = params.sources
|
|
168
194
|
.sort((a, b) => a.result.task_id.localeCompare(b.result.task_id))
|
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
import { getArtifactValue } from "../io/artifacts.js";
|
|
2
2
|
import { ARTIFACT_DEPENDENTS_MAP } from "./dependencyMap.js";
|
|
3
3
|
import { present } from "./artifactMetadata.js";
|
|
4
|
-
import {
|
|
4
|
+
import { buildArtifactDependenciesMap, hashArtifactValue, stableStringify, } from "./artifactFreshness.js";
|
|
5
5
|
function computeContentHash(artifactName, bundle) {
|
|
6
6
|
const value = getArtifactValue(bundle, artifactName);
|
|
7
7
|
if (value === undefined || value === null)
|
|
8
8
|
return undefined;
|
|
9
9
|
return hashArtifactValue(artifactName, value);
|
|
10
10
|
}
|
|
11
|
-
const
|
|
11
|
+
const ARTIFACT_DEPENDENCIES_MAP = buildArtifactDependenciesMap();
|
|
12
12
|
export function computeStaleArtifacts(bundle) {
|
|
13
13
|
const stale = new Set();
|
|
14
14
|
const metadata = bundle.artifact_metadata;
|
|
@@ -16,7 +16,7 @@ export function computeStaleArtifacts(bundle) {
|
|
|
16
16
|
for (const [artifactName, entry] of Object.entries(metadata.artifacts)) {
|
|
17
17
|
if (!present(bundle, artifactName))
|
|
18
18
|
continue;
|
|
19
|
-
const expectedDependencies = [...(
|
|
19
|
+
const expectedDependencies = [...(ARTIFACT_DEPENDENCIES_MAP[artifactName] ?? [])]
|
|
20
20
|
.filter((dependencyName) => dependencyName !== "artifact_metadata.json")
|
|
21
21
|
.sort();
|
|
22
22
|
const recordedDependencies = Object.keys(entry.dependency_revisions).sort();
|
|
@@ -72,7 +72,7 @@ export function deriveAuditState(bundle) {
|
|
|
72
72
|
obligations.push(obligation("runtime_validation_current", runtimeReady
|
|
73
73
|
? "satisfied"
|
|
74
74
|
: has(bundle.runtime_validation_report)
|
|
75
|
-
? "
|
|
75
|
+
? "stale"
|
|
76
76
|
: "missing", runtimeTasks.length === 0
|
|
77
77
|
? "No deterministic runtime validation tasks were planned."
|
|
78
78
|
: undefined));
|
|
@@ -42,6 +42,19 @@ function hasEslintConfig(root) {
|
|
|
42
42
|
function snippet(value) {
|
|
43
43
|
return value.replace(/\s+/g, " ").trim().slice(0, 500);
|
|
44
44
|
}
|
|
45
|
+
function commandErrorResult(tool, command, results) {
|
|
46
|
+
return {
|
|
47
|
+
results,
|
|
48
|
+
status: {
|
|
49
|
+
tool,
|
|
50
|
+
command: command?.candidate.display,
|
|
51
|
+
resolved: Boolean(command),
|
|
52
|
+
status: command?.error ? "spawn_error" : "not_resolved",
|
|
53
|
+
exit_code: command?.exitCode,
|
|
54
|
+
error: command?.error?.message,
|
|
55
|
+
},
|
|
56
|
+
};
|
|
57
|
+
}
|
|
45
58
|
function runTsc(root) {
|
|
46
59
|
const results = [];
|
|
47
60
|
const command = runFirstAvailableCommand(root, [
|
|
@@ -49,17 +62,7 @@ function runTsc(root) {
|
|
|
49
62
|
{ command: "tsc", args: ["--noEmit"], display: "tsc --noEmit" },
|
|
50
63
|
]);
|
|
51
64
|
if (!command || command.error) {
|
|
52
|
-
return
|
|
53
|
-
results,
|
|
54
|
-
status: {
|
|
55
|
-
tool: "tsc",
|
|
56
|
-
command: command?.candidate.display,
|
|
57
|
-
resolved: Boolean(command),
|
|
58
|
-
status: command?.error ? "spawn_error" : "not_resolved",
|
|
59
|
-
exit_code: command?.exitCode,
|
|
60
|
-
error: command?.error?.message,
|
|
61
|
-
},
|
|
62
|
-
};
|
|
65
|
+
return commandErrorResult("tsc", command, results);
|
|
63
66
|
}
|
|
64
67
|
const output = [command.stdout, command.stderr].filter(Boolean).join("\n");
|
|
65
68
|
const lines = output.split("\n");
|
|
@@ -91,7 +94,7 @@ function runTsc(root) {
|
|
|
91
94
|
}
|
|
92
95
|
if (results.length === 0 && output.trim().length > 0) {
|
|
93
96
|
const outputSnippet = snippet(output);
|
|
94
|
-
process.stderr.write(`[syntax-resolution] tsc output could not be parsed: ${outputSnippet}\n`);
|
|
97
|
+
process.stderr.write(`[syntax-resolution] tsc output could not be parsed: ${outputSnippet} (root=${root}, exit_code=${command.exitCode}, ts=${new Date().toISOString()})\n`);
|
|
95
98
|
return {
|
|
96
99
|
results,
|
|
97
100
|
status: {
|
|
@@ -136,17 +139,7 @@ function runEslint(root) {
|
|
|
136
139
|
},
|
|
137
140
|
]);
|
|
138
141
|
if (!command || command.error) {
|
|
139
|
-
return
|
|
140
|
-
results,
|
|
141
|
-
status: {
|
|
142
|
-
tool: "eslint",
|
|
143
|
-
command: command?.candidate.display,
|
|
144
|
-
resolved: Boolean(command),
|
|
145
|
-
status: command?.error ? "spawn_error" : "not_resolved",
|
|
146
|
-
exit_code: command?.exitCode,
|
|
147
|
-
error: command?.error?.message,
|
|
148
|
-
},
|
|
149
|
-
};
|
|
142
|
+
return commandErrorResult("eslint", command, results);
|
|
150
143
|
}
|
|
151
144
|
const output = [command.stdout, command.stderr].filter(Boolean).join("\n").trim();
|
|
152
145
|
if (output.length === 0) {
|
|
@@ -181,7 +174,7 @@ function runEslint(root) {
|
|
|
181
174
|
}
|
|
182
175
|
catch {
|
|
183
176
|
const outputSnippet = snippet(output);
|
|
184
|
-
process.stderr.write(`[syntax-resolution] eslint output could not be parsed: ${outputSnippet}\n`);
|
|
177
|
+
process.stderr.write(`[syntax-resolution] eslint output could not be parsed: ${outputSnippet} (root=${root}, exit_code=${command.exitCode}, ts=${new Date().toISOString()})\n`);
|
|
185
178
|
return {
|
|
186
179
|
results,
|
|
187
180
|
status: {
|
|
@@ -7,6 +7,7 @@ function buildBaseFindingsReport(bundle, results) {
|
|
|
7
7
|
criticalFlows: bundle.critical_flows,
|
|
8
8
|
coverageMatrix: bundle.coverage_matrix,
|
|
9
9
|
runtimeValidationReport: bundle.runtime_validation_report,
|
|
10
|
+
runtimeValidationTaskManifest: bundle.runtime_validation_tasks,
|
|
10
11
|
externalAnalyzerResults: bundle.external_analyzer_results,
|
|
11
12
|
designAssessment: bundle.design_assessment,
|
|
12
13
|
}));
|