audit-tools 0.28.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.audit.md +223 -0
- package/README.md +42 -0
- package/README.remediate.md +113 -0
- package/audit-code-wrapper-build.mjs +185 -0
- package/audit-code-wrapper-install-hosts.mjs +1079 -0
- package/audit-code-wrapper-install-renderers.mjs +58 -0
- package/audit-code-wrapper-io.mjs +155 -0
- package/audit-code-wrapper-legacy.mjs +125 -0
- package/audit-code-wrapper-lib.mjs +314 -0
- package/audit-code-wrapper-opencode.mjs +241 -0
- package/audit-code.mjs +12 -0
- package/dispatch/lens-definitions.json +46 -0
- package/dispatch/merge-results.mjs +110 -0
- package/dispatch/validate-result.mjs +59 -0
- package/dispatch/validate.mjs +16 -0
- package/dist/audit/adapters/coverageSummary.d.ts +9 -0
- package/dist/audit/adapters/coverageSummary.d.ts.map +1 -0
- package/dist/audit/adapters/coverageSummary.js +18 -0
- package/dist/audit/adapters/coverageSummary.js.map +1 -0
- package/dist/audit/adapters/eslint.d.ts +14 -0
- package/dist/audit/adapters/eslint.d.ts.map +1 -0
- package/dist/audit/adapters/eslint.js +28 -0
- package/dist/audit/adapters/eslint.js.map +1 -0
- package/dist/audit/adapters/normalizeExternal.d.ts +13 -0
- package/dist/audit/adapters/normalizeExternal.d.ts.map +1 -0
- package/dist/audit/adapters/normalizeExternal.js +44 -0
- package/dist/audit/adapters/normalizeExternal.js.map +1 -0
- package/dist/audit/adapters/npmAudit.d.ts +16 -0
- package/dist/audit/adapters/npmAudit.d.ts.map +1 -0
- package/dist/audit/adapters/npmAudit.js +24 -0
- package/dist/audit/adapters/npmAudit.js.map +1 -0
- package/dist/audit/adapters/semgrep.d.ts +23 -0
- package/dist/audit/adapters/semgrep.d.ts.map +1 -0
- package/dist/audit/adapters/semgrep.js +40 -0
- package/dist/audit/adapters/semgrep.js.map +1 -0
- package/dist/audit/cli/advanceAuditCommand.d.ts +2 -0
- package/dist/audit/cli/advanceAuditCommand.d.ts.map +1 -0
- package/dist/audit/cli/advanceAuditCommand.js +95 -0
- package/dist/audit/cli/advanceAuditCommand.js.map +1 -0
- package/dist/audit/cli/args.d.ts +95 -0
- package/dist/audit/cli/args.d.ts.map +1 -0
- package/dist/audit/cli/args.js +274 -0
- package/dist/audit/cli/args.js.map +1 -0
- package/dist/audit/cli/auditStep.d.ts +34 -0
- package/dist/audit/cli/auditStep.d.ts.map +1 -0
- package/dist/audit/cli/auditStep.js +162 -0
- package/dist/audit/cli/auditStep.js.map +1 -0
- package/dist/audit/cli/cleanup.d.ts +12 -0
- package/dist/audit/cli/cleanup.d.ts.map +1 -0
- package/dist/audit/cli/cleanup.js +44 -0
- package/dist/audit/cli/cleanup.js.map +1 -0
- package/dist/audit/cli/cleanupCommand.d.ts +2 -0
- package/dist/audit/cli/cleanupCommand.d.ts.map +1 -0
- package/dist/audit/cli/cleanupCommand.js +25 -0
- package/dist/audit/cli/cleanupCommand.js.map +1 -0
- package/dist/audit/cli/conceptualDispatch.d.ts +74 -0
- package/dist/audit/cli/conceptualDispatch.d.ts.map +1 -0
- package/dist/audit/cli/conceptualDispatch.js +118 -0
- package/dist/audit/cli/conceptualDispatch.js.map +1 -0
- package/dist/audit/cli/confirmIntentStep.d.ts +25 -0
- package/dist/audit/cli/confirmIntentStep.d.ts.map +1 -0
- package/dist/audit/cli/confirmIntentStep.js +210 -0
- package/dist/audit/cli/confirmIntentStep.js.map +1 -0
- package/dist/audit/cli/dispatch/packetFilter.d.ts +102 -0
- package/dist/audit/cli/dispatch/packetFilter.d.ts.map +1 -0
- package/dist/audit/cli/dispatch/packetFilter.js +148 -0
- package/dist/audit/cli/dispatch/packetFilter.js.map +1 -0
- package/dist/audit/cli/dispatch/packetPrompt.d.ts +48 -0
- package/dist/audit/cli/dispatch/packetPrompt.d.ts.map +1 -0
- package/dist/audit/cli/dispatch/packetPrompt.js +258 -0
- package/dist/audit/cli/dispatch/packetPrompt.js.map +1 -0
- package/dist/audit/cli/dispatch/paths.d.ts +7 -0
- package/dist/audit/cli/dispatch/paths.d.ts.map +1 -0
- package/dist/audit/cli/dispatch/paths.js +38 -0
- package/dist/audit/cli/dispatch/paths.js.map +1 -0
- package/dist/audit/cli/dispatch/quotaPool.d.ts +75 -0
- package/dist/audit/cli/dispatch/quotaPool.d.ts.map +1 -0
- package/dist/audit/cli/dispatch/quotaPool.js +163 -0
- package/dist/audit/cli/dispatch/quotaPool.js.map +1 -0
- package/dist/audit/cli/dispatch/tierRouting.d.ts +36 -0
- package/dist/audit/cli/dispatch/tierRouting.d.ts.map +1 -0
- package/dist/audit/cli/dispatch/tierRouting.js +121 -0
- package/dist/audit/cli/dispatch/tierRouting.js.map +1 -0
- package/dist/audit/cli/dispatch/types.d.ts +90 -0
- package/dist/audit/cli/dispatch/types.d.ts.map +1 -0
- package/dist/audit/cli/dispatch/types.js +15 -0
- package/dist/audit/cli/dispatch/types.js.map +1 -0
- package/dist/audit/cli/dispatch.d.ts +29 -0
- package/dist/audit/cli/dispatch.d.ts.map +1 -0
- package/dist/audit/cli/dispatch.js +303 -0
- package/dist/audit/cli/dispatch.js.map +1 -0
- package/dist/audit/cli/dispatchStatusCommand.d.ts +2 -0
- package/dist/audit/cli/dispatchStatusCommand.d.ts.map +1 -0
- package/dist/audit/cli/dispatchStatusCommand.js +81 -0
- package/dist/audit/cli/dispatchStatusCommand.js.map +1 -0
- package/dist/audit/cli/envelope.d.ts +50 -0
- package/dist/audit/cli/envelope.d.ts.map +1 -0
- package/dist/audit/cli/envelope.js +69 -0
- package/dist/audit/cli/envelope.js.map +1 -0
- package/dist/audit/cli/explainTaskCommand.d.ts +2 -0
- package/dist/audit/cli/explainTaskCommand.d.ts.map +1 -0
- package/dist/audit/cli/explainTaskCommand.js +34 -0
- package/dist/audit/cli/explainTaskCommand.js.map +1 -0
- package/dist/audit/cli/importExternalAnalyzerCommand.d.ts +2 -0
- package/dist/audit/cli/importExternalAnalyzerCommand.d.ts.map +1 -0
- package/dist/audit/cli/importExternalAnalyzerCommand.js +25 -0
- package/dist/audit/cli/importExternalAnalyzerCommand.js.map +1 -0
- package/dist/audit/cli/ingestResultsCommand.d.ts +2 -0
- package/dist/audit/cli/ingestResultsCommand.d.ts.map +1 -0
- package/dist/audit/cli/ingestResultsCommand.js +42 -0
- package/dist/audit/cli/ingestResultsCommand.js.map +1 -0
- package/dist/audit/cli/intakeCommand.d.ts +2 -0
- package/dist/audit/cli/intakeCommand.d.ts.map +1 -0
- package/dist/audit/cli/intakeCommand.js +18 -0
- package/dist/audit/cli/intakeCommand.js.map +1 -0
- package/dist/audit/cli/lineIndex.d.ts +5 -0
- package/dist/audit/cli/lineIndex.d.ts.map +1 -0
- package/dist/audit/cli/lineIndex.js +70 -0
- package/dist/audit/cli/lineIndex.js.map +1 -0
- package/dist/audit/cli/mergeAndIngestCommand.d.ts +46 -0
- package/dist/audit/cli/mergeAndIngestCommand.d.ts.map +1 -0
- package/dist/audit/cli/mergeAndIngestCommand.js +541 -0
- package/dist/audit/cli/mergeAndIngestCommand.js.map +1 -0
- package/dist/audit/cli/nextStepCommand.d.ts +22 -0
- package/dist/audit/cli/nextStepCommand.d.ts.map +1 -0
- package/dist/audit/cli/nextStepCommand.js +531 -0
- package/dist/audit/cli/nextStepCommand.js.map +1 -0
- package/dist/audit/cli/nextStepHelpers.d.ts +303 -0
- package/dist/audit/cli/nextStepHelpers.d.ts.map +1 -0
- package/dist/audit/cli/nextStepHelpers.js +861 -0
- package/dist/audit/cli/nextStepHelpers.js.map +1 -0
- package/dist/audit/cli/paths.d.ts +2 -0
- package/dist/audit/cli/paths.d.ts.map +1 -0
- package/dist/audit/cli/paths.js +10 -0
- package/dist/audit/cli/paths.js.map +1 -0
- package/dist/audit/cli/planCommand.d.ts +2 -0
- package/dist/audit/cli/planCommand.d.ts.map +1 -0
- package/dist/audit/cli/planCommand.js +17 -0
- package/dist/audit/cli/planCommand.js.map +1 -0
- package/dist/audit/cli/prepareDispatchCommand.d.ts +2 -0
- package/dist/audit/cli/prepareDispatchCommand.d.ts.map +1 -0
- package/dist/audit/cli/prepareDispatchCommand.js +37 -0
- package/dist/audit/cli/prepareDispatchCommand.js.map +1 -0
- package/dist/audit/cli/prompts.d.ts +54 -0
- package/dist/audit/cli/prompts.d.ts.map +1 -0
- package/dist/audit/cli/prompts.js +324 -0
- package/dist/audit/cli/prompts.js.map +1 -0
- package/dist/audit/cli/quotaCommand.d.ts +2 -0
- package/dist/audit/cli/quotaCommand.d.ts.map +1 -0
- package/dist/audit/cli/quotaCommand.js +64 -0
- package/dist/audit/cli/quotaCommand.js.map +1 -0
- package/dist/audit/cli/requeueCommand.d.ts +2 -0
- package/dist/audit/cli/requeueCommand.d.ts.map +1 -0
- package/dist/audit/cli/requeueCommand.js +11 -0
- package/dist/audit/cli/requeueCommand.js.map +1 -0
- package/dist/audit/cli/resynthesizeCommand.d.ts +2 -0
- package/dist/audit/cli/resynthesizeCommand.d.ts.map +1 -0
- package/dist/audit/cli/resynthesizeCommand.js +57 -0
- package/dist/audit/cli/resynthesizeCommand.js.map +1 -0
- package/dist/audit/cli/reviewRun.d.ts +57 -0
- package/dist/audit/cli/reviewRun.d.ts.map +1 -0
- package/dist/audit/cli/reviewRun.js +180 -0
- package/dist/audit/cli/reviewRun.js.map +1 -0
- package/dist/audit/cli/rollingAuditDispatch.d.ts +119 -0
- package/dist/audit/cli/rollingAuditDispatch.d.ts.map +1 -0
- package/dist/audit/cli/rollingAuditDispatch.js +264 -0
- package/dist/audit/cli/rollingAuditDispatch.js.map +1 -0
- package/dist/audit/cli/sampleRunCommand.d.ts +2 -0
- package/dist/audit/cli/sampleRunCommand.d.ts.map +1 -0
- package/dist/audit/cli/sampleRunCommand.js +106 -0
- package/dist/audit/cli/sampleRunCommand.js.map +1 -0
- package/dist/audit/cli/semanticReviewStep.d.ts +23 -0
- package/dist/audit/cli/semanticReviewStep.d.ts.map +1 -0
- package/dist/audit/cli/semanticReviewStep.js +123 -0
- package/dist/audit/cli/semanticReviewStep.js.map +1 -0
- package/dist/audit/cli/statusCommand.d.ts +2 -0
- package/dist/audit/cli/statusCommand.d.ts.map +1 -0
- package/dist/audit/cli/statusCommand.js +133 -0
- package/dist/audit/cli/statusCommand.js.map +1 -0
- package/dist/audit/cli/steps.d.ts +204 -0
- package/dist/audit/cli/steps.d.ts.map +1 -0
- package/dist/audit/cli/steps.js +105 -0
- package/dist/audit/cli/steps.js.map +1 -0
- package/dist/audit/cli/submitPacketCommand.d.ts +2 -0
- package/dist/audit/cli/submitPacketCommand.d.ts.map +1 -0
- package/dist/audit/cli/submitPacketCommand.js +126 -0
- package/dist/audit/cli/submitPacketCommand.js.map +1 -0
- package/dist/audit/cli/synthesizeCommand.d.ts +2 -0
- package/dist/audit/cli/synthesizeCommand.d.ts.map +1 -0
- package/dist/audit/cli/synthesizeCommand.js +16 -0
- package/dist/audit/cli/synthesizeCommand.js.map +1 -0
- package/dist/audit/cli/updateRuntimeValidationCommand.d.ts +2 -0
- package/dist/audit/cli/updateRuntimeValidationCommand.d.ts.map +1 -0
- package/dist/audit/cli/updateRuntimeValidationCommand.js +17 -0
- package/dist/audit/cli/updateRuntimeValidationCommand.js.map +1 -0
- package/dist/audit/cli/validateCommand.d.ts +2 -0
- package/dist/audit/cli/validateCommand.d.ts.map +1 -0
- package/dist/audit/cli/validateCommand.js +42 -0
- package/dist/audit/cli/validateCommand.js.map +1 -0
- package/dist/audit/cli/validateResultCommand.d.ts +2 -0
- package/dist/audit/cli/validateResultCommand.d.ts.map +1 -0
- package/dist/audit/cli/validateResultCommand.js +92 -0
- package/dist/audit/cli/validateResultCommand.js.map +1 -0
- package/dist/audit/cli/validateResultsCommand.d.ts +2 -0
- package/dist/audit/cli/validateResultsCommand.d.ts.map +1 -0
- package/dist/audit/cli/validateResultsCommand.js +32 -0
- package/dist/audit/cli/validateResultsCommand.js.map +1 -0
- package/dist/audit/cli/waveManifest.d.ts +41 -0
- package/dist/audit/cli/waveManifest.d.ts.map +1 -0
- package/dist/audit/cli/waveManifest.js +42 -0
- package/dist/audit/cli/waveManifest.js.map +1 -0
- package/dist/audit/cli/workerResult.d.ts +19 -0
- package/dist/audit/cli/workerResult.d.ts.map +1 -0
- package/dist/audit/cli/workerResult.js +43 -0
- package/dist/audit/cli/workerResult.js.map +1 -0
- package/dist/audit/cli/workerRunCommand.d.ts +16 -0
- package/dist/audit/cli/workerRunCommand.d.ts.map +1 -0
- package/dist/audit/cli/workerRunCommand.js +132 -0
- package/dist/audit/cli/workerRunCommand.js.map +1 -0
- package/dist/audit/cli.d.ts +21 -0
- package/dist/audit/cli.d.ts.map +1 -0
- package/dist/audit/cli.js +137 -0
- package/dist/audit/cli.js.map +1 -0
- package/dist/audit/contracts/workerSchemas.d.ts +1448 -0
- package/dist/audit/contracts/workerSchemas.d.ts.map +1 -0
- package/dist/audit/contracts/workerSchemas.js +117 -0
- package/dist/audit/contracts/workerSchemas.js.map +1 -0
- package/dist/audit/contracts/wrapperResponse.d.ts +316 -0
- package/dist/audit/contracts/wrapperResponse.d.ts.map +1 -0
- package/dist/audit/contracts/wrapperResponse.js +96 -0
- package/dist/audit/contracts/wrapperResponse.js.map +1 -0
- package/dist/audit/coverage.d.ts +11 -0
- package/dist/audit/coverage.d.ts.map +1 -0
- package/dist/audit/coverage.js +78 -0
- package/dist/audit/coverage.js.map +1 -0
- package/dist/audit/extractors/analyzers/css.d.ts +3 -0
- package/dist/audit/extractors/analyzers/css.d.ts.map +1 -0
- package/dist/audit/extractors/analyzers/css.js +102 -0
- package/dist/audit/extractors/analyzers/css.js.map +1 -0
- package/dist/audit/extractors/analyzers/html.d.ts +3 -0
- package/dist/audit/extractors/analyzers/html.d.ts.map +1 -0
- package/dist/audit/extractors/analyzers/html.js +93 -0
- package/dist/audit/extractors/analyzers/html.js.map +1 -0
- package/dist/audit/extractors/analyzers/merge.d.ts +15 -0
- package/dist/audit/extractors/analyzers/merge.d.ts.map +1 -0
- package/dist/audit/extractors/analyzers/merge.js +86 -0
- package/dist/audit/extractors/analyzers/merge.js.map +1 -0
- package/dist/audit/extractors/analyzers/python.d.ts +3 -0
- package/dist/audit/extractors/analyzers/python.d.ts.map +1 -0
- package/dist/audit/extractors/analyzers/python.js +105 -0
- package/dist/audit/extractors/analyzers/python.js.map +1 -0
- package/dist/audit/extractors/analyzers/registry.d.ts +34 -0
- package/dist/audit/extractors/analyzers/registry.d.ts.map +1 -0
- package/dist/audit/extractors/analyzers/registry.js +82 -0
- package/dist/audit/extractors/analyzers/registry.js.map +1 -0
- package/dist/audit/extractors/analyzers/resourceUrl.d.ts +8 -0
- package/dist/audit/extractors/analyzers/resourceUrl.d.ts.map +1 -0
- package/dist/audit/extractors/analyzers/resourceUrl.js +26 -0
- package/dist/audit/extractors/analyzers/resourceUrl.js.map +1 -0
- package/dist/audit/extractors/analyzers/sql.d.ts +3 -0
- package/dist/audit/extractors/analyzers/sql.d.ts.map +1 -0
- package/dist/audit/extractors/analyzers/sql.js +23 -0
- package/dist/audit/extractors/analyzers/sql.js.map +1 -0
- package/dist/audit/extractors/analyzers/treeSitter.d.ts +44 -0
- package/dist/audit/extractors/analyzers/treeSitter.d.ts.map +1 -0
- package/dist/audit/extractors/analyzers/treeSitter.js +148 -0
- package/dist/audit/extractors/analyzers/treeSitter.js.map +1 -0
- package/dist/audit/extractors/analyzers/types.d.ts +54 -0
- package/dist/audit/extractors/analyzers/types.d.ts.map +1 -0
- package/dist/audit/extractors/analyzers/types.js +2 -0
- package/dist/audit/extractors/analyzers/types.js.map +1 -0
- package/dist/audit/extractors/analyzers/typescript.d.ts +3 -0
- package/dist/audit/extractors/analyzers/typescript.d.ts.map +1 -0
- package/dist/audit/extractors/analyzers/typescript.js +279 -0
- package/dist/audit/extractors/analyzers/typescript.js.map +1 -0
- package/dist/audit/extractors/browserExtension.d.ts +12 -0
- package/dist/audit/extractors/browserExtension.d.ts.map +1 -0
- package/dist/audit/extractors/browserExtension.js +388 -0
- package/dist/audit/extractors/browserExtension.js.map +1 -0
- package/dist/audit/extractors/bucketing.d.ts +12 -0
- package/dist/audit/extractors/bucketing.d.ts.map +1 -0
- package/dist/audit/extractors/bucketing.js +56 -0
- package/dist/audit/extractors/bucketing.js.map +1 -0
- package/dist/audit/extractors/designAssessment.d.ts +10 -0
- package/dist/audit/extractors/designAssessment.d.ts.map +1 -0
- package/dist/audit/extractors/designAssessment.js +280 -0
- package/dist/audit/extractors/designAssessment.js.map +1 -0
- package/dist/audit/extractors/disposition.d.ts +76 -0
- package/dist/audit/extractors/disposition.d.ts.map +1 -0
- package/dist/audit/extractors/disposition.js +265 -0
- package/dist/audit/extractors/disposition.js.map +1 -0
- package/dist/audit/extractors/fileInventory.d.ts +8 -0
- package/dist/audit/extractors/fileInventory.d.ts.map +1 -0
- package/dist/audit/extractors/fileInventory.js +36 -0
- package/dist/audit/extractors/fileInventory.js.map +1 -0
- package/dist/audit/extractors/flows.d.ts +9 -0
- package/dist/audit/extractors/flows.d.ts.map +1 -0
- package/dist/audit/extractors/flows.js +111 -0
- package/dist/audit/extractors/flows.js.map +1 -0
- package/dist/audit/extractors/fsIntake.d.ts +9 -0
- package/dist/audit/extractors/fsIntake.d.ts.map +1 -0
- package/dist/audit/extractors/fsIntake.js +95 -0
- package/dist/audit/extractors/fsIntake.js.map +1 -0
- package/dist/audit/extractors/graph.d.ts +11 -0
- package/dist/audit/extractors/graph.d.ts.map +1 -0
- package/dist/audit/extractors/graph.js +472 -0
- package/dist/audit/extractors/graph.js.map +1 -0
- package/dist/audit/extractors/graphManifestEdges/cargo.d.ts +15 -0
- package/dist/audit/extractors/graphManifestEdges/cargo.d.ts.map +1 -0
- package/dist/audit/extractors/graphManifestEdges/cargo.js +74 -0
- package/dist/audit/extractors/graphManifestEdges/cargo.js.map +1 -0
- package/dist/audit/extractors/graphManifestEdges/go.d.ts +6 -0
- package/dist/audit/extractors/graphManifestEdges/go.d.ts.map +1 -0
- package/dist/audit/extractors/graphManifestEdges/go.js +152 -0
- package/dist/audit/extractors/graphManifestEdges/go.js.map +1 -0
- package/dist/audit/extractors/graphManifestEdges/index.d.ts +9 -0
- package/dist/audit/extractors/graphManifestEdges/index.d.ts.map +1 -0
- package/dist/audit/extractors/graphManifestEdges/index.js +12 -0
- package/dist/audit/extractors/graphManifestEdges/index.js.map +1 -0
- package/dist/audit/extractors/graphManifestEdges/jsonc.d.ts +4 -0
- package/dist/audit/extractors/graphManifestEdges/jsonc.d.ts.map +1 -0
- package/dist/audit/extractors/graphManifestEdges/jsonc.js +98 -0
- package/dist/audit/extractors/graphManifestEdges/jsonc.js.map +1 -0
- package/dist/audit/extractors/graphManifestEdges/maven.d.ts +4 -0
- package/dist/audit/extractors/graphManifestEdges/maven.d.ts.map +1 -0
- package/dist/audit/extractors/graphManifestEdges/maven.js +74 -0
- package/dist/audit/extractors/graphManifestEdges/maven.js.map +1 -0
- package/dist/audit/extractors/graphManifestEdges/packageJson.d.ts +20 -0
- package/dist/audit/extractors/graphManifestEdges/packageJson.d.ts.map +1 -0
- package/dist/audit/extractors/graphManifestEdges/packageJson.js +205 -0
- package/dist/audit/extractors/graphManifestEdges/packageJson.js.map +1 -0
- package/dist/audit/extractors/graphManifestEdges/pnpm.d.ts +10 -0
- package/dist/audit/extractors/graphManifestEdges/pnpm.d.ts.map +1 -0
- package/dist/audit/extractors/graphManifestEdges/pnpm.js +18 -0
- package/dist/audit/extractors/graphManifestEdges/pnpm.js.map +1 -0
- package/dist/audit/extractors/graphManifestEdges/pyproject.d.ts +4 -0
- package/dist/audit/extractors/graphManifestEdges/pyproject.d.ts.map +1 -0
- package/dist/audit/extractors/graphManifestEdges/pyproject.js +45 -0
- package/dist/audit/extractors/graphManifestEdges/pyproject.js.map +1 -0
- package/dist/audit/extractors/graphManifestEdges/toml.d.ts +25 -0
- package/dist/audit/extractors/graphManifestEdges/toml.d.ts.map +1 -0
- package/dist/audit/extractors/graphManifestEdges/toml.js +49 -0
- package/dist/audit/extractors/graphManifestEdges/toml.js.map +1 -0
- package/dist/audit/extractors/graphManifestEdges/typescript.d.ts +4 -0
- package/dist/audit/extractors/graphManifestEdges/typescript.d.ts.map +1 -0
- package/dist/audit/extractors/graphManifestEdges/typescript.js +57 -0
- package/dist/audit/extractors/graphManifestEdges/typescript.js.map +1 -0
- package/dist/audit/extractors/graphManifestEdges/workspace.d.ts +11 -0
- package/dist/audit/extractors/graphManifestEdges/workspace.d.ts.map +1 -0
- package/dist/audit/extractors/graphManifestEdges/workspace.js +73 -0
- package/dist/audit/extractors/graphManifestEdges/workspace.js.map +1 -0
- package/dist/audit/extractors/graphManifestEdges/yaml.d.ts +24 -0
- package/dist/audit/extractors/graphManifestEdges/yaml.d.ts.map +1 -0
- package/dist/audit/extractors/graphManifestEdges/yaml.js +57 -0
- package/dist/audit/extractors/graphManifestEdges/yaml.js.map +1 -0
- package/dist/audit/extractors/graphManifestEdges/yamlPaths.d.ts +5 -0
- package/dist/audit/extractors/graphManifestEdges/yamlPaths.d.ts.map +1 -0
- package/dist/audit/extractors/graphManifestEdges/yamlPaths.js +75 -0
- package/dist/audit/extractors/graphManifestEdges/yamlPaths.js.map +1 -0
- package/dist/audit/extractors/graphPathUtils.d.ts +34 -0
- package/dist/audit/extractors/graphPathUtils.d.ts.map +1 -0
- package/dist/audit/extractors/graphPathUtils.js +174 -0
- package/dist/audit/extractors/graphPathUtils.js.map +1 -0
- package/dist/audit/extractors/graphPythonImports.d.ts +19 -0
- package/dist/audit/extractors/graphPythonImports.d.ts.map +1 -0
- package/dist/audit/extractors/graphPythonImports.js +318 -0
- package/dist/audit/extractors/graphPythonImports.js.map +1 -0
- package/dist/audit/extractors/graphRoutes.d.ts +13 -0
- package/dist/audit/extractors/graphRoutes.d.ts.map +1 -0
- package/dist/audit/extractors/graphRoutes.js +447 -0
- package/dist/audit/extractors/graphRoutes.js.map +1 -0
- package/dist/audit/extractors/graphSuites.d.ts +5 -0
- package/dist/audit/extractors/graphSuites.d.ts.map +1 -0
- package/dist/audit/extractors/graphSuites.js +248 -0
- package/dist/audit/extractors/graphSuites.js.map +1 -0
- package/dist/audit/extractors/graphTestSources.d.ts +3 -0
- package/dist/audit/extractors/graphTestSources.d.ts.map +1 -0
- package/dist/audit/extractors/graphTestSources.js +103 -0
- package/dist/audit/extractors/graphTestSources.js.map +1 -0
- package/dist/audit/extractors/ignore.d.ts +2 -0
- package/dist/audit/extractors/ignore.d.ts.map +1 -0
- package/dist/audit/extractors/ignore.js +18 -0
- package/dist/audit/extractors/ignore.js.map +1 -0
- package/dist/audit/extractors/languageMap.generated.d.ts +2 -0
- package/dist/audit/extractors/languageMap.generated.d.ts.map +1 -0
- package/dist/audit/extractors/languageMap.generated.js +1456 -0
- package/dist/audit/extractors/languageMap.generated.js.map +1 -0
- package/dist/audit/extractors/pathPatterns.d.ts +55 -0
- package/dist/audit/extractors/pathPatterns.d.ts.map +1 -0
- package/dist/audit/extractors/pathPatterns.js +303 -0
- package/dist/audit/extractors/pathPatterns.js.map +1 -0
- package/dist/audit/extractors/risk.d.ts +5 -0
- package/dist/audit/extractors/risk.d.ts.map +1 -0
- package/dist/audit/extractors/risk.js +54 -0
- package/dist/audit/extractors/risk.js.map +1 -0
- package/dist/audit/extractors/surfaces.d.ts +10 -0
- package/dist/audit/extractors/surfaces.d.ts.map +1 -0
- package/dist/audit/extractors/surfaces.js +49 -0
- package/dist/audit/extractors/surfaces.js.map +1 -0
- package/dist/audit/index.d.ts +2 -0
- package/dist/audit/index.d.ts.map +1 -0
- package/dist/audit/index.js +3 -0
- package/dist/audit/index.js.map +1 -0
- package/dist/audit/io/artifacts.d.ts +152 -0
- package/dist/audit/io/artifacts.d.ts.map +1 -0
- package/dist/audit/io/artifacts.js +239 -0
- package/dist/audit/io/artifacts.js.map +1 -0
- package/dist/audit/io/runArtifactTypes.d.ts +19 -0
- package/dist/audit/io/runArtifactTypes.d.ts.map +1 -0
- package/dist/audit/io/runArtifactTypes.js +2 -0
- package/dist/audit/io/runArtifactTypes.js.map +1 -0
- package/dist/audit/io/runArtifacts.d.ts +33 -0
- package/dist/audit/io/runArtifacts.d.ts.map +1 -0
- package/dist/audit/io/runArtifacts.js +254 -0
- package/dist/audit/io/runArtifacts.js.map +1 -0
- package/dist/audit/io/toolingManifest.d.ts +4 -0
- package/dist/audit/io/toolingManifest.d.ts.map +1 -0
- package/dist/audit/io/toolingManifest.js +79 -0
- package/dist/audit/io/toolingManifest.js.map +1 -0
- package/dist/audit/orchestrator/advance.d.ts +5 -0
- package/dist/audit/orchestrator/advance.d.ts.map +1 -0
- package/dist/audit/orchestrator/advance.js +172 -0
- package/dist/audit/orchestrator/advance.js.map +1 -0
- package/dist/audit/orchestrator/advanceTypes.d.ts +50 -0
- package/dist/audit/orchestrator/advanceTypes.d.ts.map +1 -0
- package/dist/audit/orchestrator/advanceTypes.js +2 -0
- package/dist/audit/orchestrator/advanceTypes.js.map +1 -0
- package/dist/audit/orchestrator/artifactFreshness.d.ts +4 -0
- package/dist/audit/orchestrator/artifactFreshness.d.ts.map +1 -0
- package/dist/audit/orchestrator/artifactFreshness.js +99 -0
- package/dist/audit/orchestrator/artifactFreshness.js.map +1 -0
- package/dist/audit/orchestrator/artifactMetadata.d.ts +6 -0
- package/dist/audit/orchestrator/artifactMetadata.d.ts.map +1 -0
- package/dist/audit/orchestrator/artifactMetadata.js +98 -0
- package/dist/audit/orchestrator/artifactMetadata.js.map +1 -0
- package/dist/audit/orchestrator/auditTaskUtils.d.ts +10 -0
- package/dist/audit/orchestrator/auditTaskUtils.d.ts.map +1 -0
- package/dist/audit/orchestrator/auditTaskUtils.js +53 -0
- package/dist/audit/orchestrator/auditTaskUtils.js.map +1 -0
- package/dist/audit/orchestrator/autoFixExecutor.d.ts +4 -0
- package/dist/audit/orchestrator/autoFixExecutor.d.ts.map +1 -0
- package/dist/audit/orchestrator/autoFixExecutor.js +152 -0
- package/dist/audit/orchestrator/autoFixExecutor.js.map +1 -0
- package/dist/audit/orchestrator/chunking.d.ts +6 -0
- package/dist/audit/orchestrator/chunking.d.ts.map +1 -0
- package/dist/audit/orchestrator/chunking.js +14 -0
- package/dist/audit/orchestrator/chunking.js.map +1 -0
- package/dist/audit/orchestrator/dependencyMap.d.ts +74 -0
- package/dist/audit/orchestrator/dependencyMap.d.ts.map +1 -0
- package/dist/audit/orchestrator/dependencyMap.js +193 -0
- package/dist/audit/orchestrator/dependencyMap.js.map +1 -0
- package/dist/audit/orchestrator/designReviewProjection.d.ts +66 -0
- package/dist/audit/orchestrator/designReviewProjection.d.ts.map +1 -0
- package/dist/audit/orchestrator/designReviewProjection.js +215 -0
- package/dist/audit/orchestrator/designReviewProjection.js.map +1 -0
- package/dist/audit/orchestrator/designReviewPrompt.d.ts +82 -0
- package/dist/audit/orchestrator/designReviewPrompt.d.ts.map +1 -0
- package/dist/audit/orchestrator/designReviewPrompt.js +474 -0
- package/dist/audit/orchestrator/designReviewPrompt.js.map +1 -0
- package/dist/audit/orchestrator/designReviewSnapshot.d.ts +69 -0
- package/dist/audit/orchestrator/designReviewSnapshot.d.ts.map +1 -0
- package/dist/audit/orchestrator/designReviewSnapshot.js +135 -0
- package/dist/audit/orchestrator/designReviewSnapshot.js.map +1 -0
- package/dist/audit/orchestrator/edgeReasoning.d.ts +40 -0
- package/dist/audit/orchestrator/edgeReasoning.d.ts.map +1 -0
- package/dist/audit/orchestrator/edgeReasoning.js +126 -0
- package/dist/audit/orchestrator/edgeReasoning.js.map +1 -0
- package/dist/audit/orchestrator/executorResult.d.ts +71 -0
- package/dist/audit/orchestrator/executorResult.d.ts.map +1 -0
- package/dist/audit/orchestrator/executorResult.js +2 -0
- package/dist/audit/orchestrator/executorResult.js.map +1 -0
- package/dist/audit/orchestrator/executorRunners.d.ts +34 -0
- package/dist/audit/orchestrator/executorRunners.d.ts.map +1 -0
- package/dist/audit/orchestrator/executorRunners.js +85 -0
- package/dist/audit/orchestrator/executorRunners.js.map +1 -0
- package/dist/audit/orchestrator/executors.d.ts +13 -0
- package/dist/audit/orchestrator/executors.d.ts.map +1 -0
- package/dist/audit/orchestrator/executors.js +114 -0
- package/dist/audit/orchestrator/executors.js.map +1 -0
- package/dist/audit/orchestrator/fileAnchors.d.ts +33 -0
- package/dist/audit/orchestrator/fileAnchors.d.ts.map +1 -0
- package/dist/audit/orchestrator/fileAnchors.js +242 -0
- package/dist/audit/orchestrator/fileAnchors.js.map +1 -0
- package/dist/audit/orchestrator/fileIntegrity.d.ts +9 -0
- package/dist/audit/orchestrator/fileIntegrity.d.ts.map +1 -0
- package/dist/audit/orchestrator/fileIntegrity.js +58 -0
- package/dist/audit/orchestrator/fileIntegrity.js.map +1 -0
- package/dist/audit/orchestrator/flowCoverage.d.ts +5 -0
- package/dist/audit/orchestrator/flowCoverage.d.ts.map +1 -0
- package/dist/audit/orchestrator/flowCoverage.js +46 -0
- package/dist/audit/orchestrator/flowCoverage.js.map +1 -0
- package/dist/audit/orchestrator/flowPlanning.d.ts +8 -0
- package/dist/audit/orchestrator/flowPlanning.d.ts.map +1 -0
- package/dist/audit/orchestrator/flowPlanning.js +65 -0
- package/dist/audit/orchestrator/flowPlanning.js.map +1 -0
- package/dist/audit/orchestrator/flowRequeue.d.ts +6 -0
- package/dist/audit/orchestrator/flowRequeue.d.ts.map +1 -0
- package/dist/audit/orchestrator/flowRequeue.js +73 -0
- package/dist/audit/orchestrator/flowRequeue.js.map +1 -0
- package/dist/audit/orchestrator/graphEnrichmentExecutor.d.ts +30 -0
- package/dist/audit/orchestrator/graphEnrichmentExecutor.d.ts.map +1 -0
- package/dist/audit/orchestrator/graphEnrichmentExecutor.js +227 -0
- package/dist/audit/orchestrator/graphEnrichmentExecutor.js.map +1 -0
- package/dist/audit/orchestrator/ingestionExecutors.d.ts +10 -0
- package/dist/audit/orchestrator/ingestionExecutors.d.ts.map +1 -0
- package/dist/audit/orchestrator/ingestionExecutors.js +262 -0
- package/dist/audit/orchestrator/ingestionExecutors.js.map +1 -0
- package/dist/audit/orchestrator/intakeExecutors.d.ts +26 -0
- package/dist/audit/orchestrator/intakeExecutors.d.ts.map +1 -0
- package/dist/audit/orchestrator/intakeExecutors.js +138 -0
- package/dist/audit/orchestrator/intakeExecutors.js.map +1 -0
- package/dist/audit/orchestrator/intentCheckpointExecutor.d.ts +89 -0
- package/dist/audit/orchestrator/intentCheckpointExecutor.d.ts.map +1 -0
- package/dist/audit/orchestrator/intentCheckpointExecutor.js +264 -0
- package/dist/audit/orchestrator/intentCheckpointExecutor.js.map +1 -0
- package/dist/audit/orchestrator/intentInterpreter.d.ts +49 -0
- package/dist/audit/orchestrator/intentInterpreter.d.ts.map +1 -0
- package/dist/audit/orchestrator/intentInterpreter.js +110 -0
- package/dist/audit/orchestrator/intentInterpreter.js.map +1 -0
- package/dist/audit/orchestrator/lensSelection.d.ts +35 -0
- package/dist/audit/orchestrator/lensSelection.d.ts.map +1 -0
- package/dist/audit/orchestrator/lensSelection.js +81 -0
- package/dist/audit/orchestrator/lensSelection.js.map +1 -0
- package/dist/audit/orchestrator/localCommands.d.ts +16 -0
- package/dist/audit/orchestrator/localCommands.d.ts.map +1 -0
- package/dist/audit/orchestrator/localCommands.js +113 -0
- package/dist/audit/orchestrator/localCommands.js.map +1 -0
- package/dist/audit/orchestrator/nextStep.d.ts +12 -0
- package/dist/audit/orchestrator/nextStep.d.ts.map +1 -0
- package/dist/audit/orchestrator/nextStep.js +63 -0
- package/dist/audit/orchestrator/nextStep.js.map +1 -0
- package/dist/audit/orchestrator/partitionTaskGraph.d.ts +32 -0
- package/dist/audit/orchestrator/partitionTaskGraph.d.ts.map +1 -0
- package/dist/audit/orchestrator/partitionTaskGraph.js +98 -0
- package/dist/audit/orchestrator/partitionTaskGraph.js.map +1 -0
- package/dist/audit/orchestrator/planning.d.ts +5 -0
- package/dist/audit/orchestrator/planning.d.ts.map +1 -0
- package/dist/audit/orchestrator/planning.js +81 -0
- package/dist/audit/orchestrator/planning.js.map +1 -0
- package/dist/audit/orchestrator/planningExecutors.d.ts +21 -0
- package/dist/audit/orchestrator/planningExecutors.d.ts.map +1 -0
- package/dist/audit/orchestrator/planningExecutors.js +228 -0
- package/dist/audit/orchestrator/planningExecutors.js.map +1 -0
- package/dist/audit/orchestrator/providerConfirmation.d.ts +21 -0
- package/dist/audit/orchestrator/providerConfirmation.d.ts.map +1 -0
- package/dist/audit/orchestrator/providerConfirmation.js +54 -0
- package/dist/audit/orchestrator/providerConfirmation.js.map +1 -0
- package/dist/audit/orchestrator/requeue.d.ts +4 -0
- package/dist/audit/orchestrator/requeue.d.ts.map +1 -0
- package/dist/audit/orchestrator/requeue.js +33 -0
- package/dist/audit/orchestrator/requeue.js.map +1 -0
- package/dist/audit/orchestrator/requeueCommand.d.ts +32 -0
- package/dist/audit/orchestrator/requeueCommand.d.ts.map +1 -0
- package/dist/audit/orchestrator/requeueCommand.js +45 -0
- package/dist/audit/orchestrator/requeueCommand.js.map +1 -0
- package/dist/audit/orchestrator/requeueUtils.d.ts +14 -0
- package/dist/audit/orchestrator/requeueUtils.d.ts.map +1 -0
- package/dist/audit/orchestrator/requeueUtils.js +22 -0
- package/dist/audit/orchestrator/requeueUtils.js.map +1 -0
- package/dist/audit/orchestrator/resultIngestion.d.ts +18 -0
- package/dist/audit/orchestrator/resultIngestion.d.ts.map +1 -0
- package/dist/audit/orchestrator/resultIngestion.js +63 -0
- package/dist/audit/orchestrator/resultIngestion.js.map +1 -0
- package/dist/audit/orchestrator/reviewPacketGraph.d.ts +5 -0
- package/dist/audit/orchestrator/reviewPacketGraph.d.ts.map +1 -0
- package/dist/audit/orchestrator/reviewPacketGraph.js +11 -0
- package/dist/audit/orchestrator/reviewPacketGraph.js.map +1 -0
- package/dist/audit/orchestrator/reviewPacketGraphClustering.d.ts +4 -0
- package/dist/audit/orchestrator/reviewPacketGraphClustering.d.ts.map +1 -0
- package/dist/audit/orchestrator/reviewPacketGraphClustering.js +481 -0
- package/dist/audit/orchestrator/reviewPacketGraphClustering.js.map +1 -0
- package/dist/audit/orchestrator/reviewPacketGraphContext.d.ts +10 -0
- package/dist/audit/orchestrator/reviewPacketGraphContext.d.ts.map +1 -0
- package/dist/audit/orchestrator/reviewPacketGraphContext.js +95 -0
- package/dist/audit/orchestrator/reviewPacketGraphContext.js.map +1 -0
- package/dist/audit/orchestrator/reviewPacketGraphEdges.d.ts +23 -0
- package/dist/audit/orchestrator/reviewPacketGraphEdges.d.ts.map +1 -0
- package/dist/audit/orchestrator/reviewPacketGraphEdges.js +169 -0
- package/dist/audit/orchestrator/reviewPacketGraphEdges.js.map +1 -0
- package/dist/audit/orchestrator/reviewPacketMetrics.d.ts +17 -0
- package/dist/audit/orchestrator/reviewPacketMetrics.d.ts.map +1 -0
- package/dist/audit/orchestrator/reviewPacketMetrics.js +322 -0
- package/dist/audit/orchestrator/reviewPacketMetrics.js.map +1 -0
- package/dist/audit/orchestrator/reviewPacketSizing.d.ts +27 -0
- package/dist/audit/orchestrator/reviewPacketSizing.d.ts.map +1 -0
- package/dist/audit/orchestrator/reviewPacketSizing.js +64 -0
- package/dist/audit/orchestrator/reviewPacketSizing.js.map +1 -0
- package/dist/audit/orchestrator/reviewPackets.d.ts +54 -0
- package/dist/audit/orchestrator/reviewPackets.d.ts.map +1 -0
- package/dist/audit/orchestrator/reviewPackets.js +318 -0
- package/dist/audit/orchestrator/reviewPackets.js.map +1 -0
- package/dist/audit/orchestrator/rollingDispatch.d.ts +45 -0
- package/dist/audit/orchestrator/rollingDispatch.d.ts.map +1 -0
- package/dist/audit/orchestrator/rollingDispatch.js +103 -0
- package/dist/audit/orchestrator/rollingDispatch.js.map +1 -0
- package/dist/audit/orchestrator/runtimeCommand.d.ts +10 -0
- package/dist/audit/orchestrator/runtimeCommand.d.ts.map +1 -0
- package/dist/audit/orchestrator/runtimeCommand.js +129 -0
- package/dist/audit/orchestrator/runtimeCommand.js.map +1 -0
- package/dist/audit/orchestrator/runtimeValidation.d.ts +13 -0
- package/dist/audit/orchestrator/runtimeValidation.d.ts.map +1 -0
- package/dist/audit/orchestrator/runtimeValidation.js +94 -0
- package/dist/audit/orchestrator/runtimeValidation.js.map +1 -0
- package/dist/audit/orchestrator/runtimeValidationUpdate.d.ts +3 -0
- package/dist/audit/orchestrator/runtimeValidationUpdate.d.ts.map +1 -0
- package/dist/audit/orchestrator/runtimeValidationUpdate.js +57 -0
- package/dist/audit/orchestrator/runtimeValidationUpdate.js.map +1 -0
- package/dist/audit/orchestrator/scope.d.ts +75 -0
- package/dist/audit/orchestrator/scope.d.ts.map +1 -0
- package/dist/audit/orchestrator/scope.js +268 -0
- package/dist/audit/orchestrator/scope.js.map +1 -0
- package/dist/audit/orchestrator/selectiveDeepening/conflict.d.ts +9 -0
- package/dist/audit/orchestrator/selectiveDeepening/conflict.d.ts.map +1 -0
- package/dist/audit/orchestrator/selectiveDeepening/conflict.js +72 -0
- package/dist/audit/orchestrator/selectiveDeepening/conflict.js.map +1 -0
- package/dist/audit/orchestrator/selectiveDeepening/findingFollowup.d.ts +11 -0
- package/dist/audit/orchestrator/selectiveDeepening/findingFollowup.d.ts.map +1 -0
- package/dist/audit/orchestrator/selectiveDeepening/findingFollowup.js +53 -0
- package/dist/audit/orchestrator/selectiveDeepening/findingFollowup.js.map +1 -0
- package/dist/audit/orchestrator/selectiveDeepening/highRiskClean.d.ts +8 -0
- package/dist/audit/orchestrator/selectiveDeepening/highRiskClean.d.ts.map +1 -0
- package/dist/audit/orchestrator/selectiveDeepening/highRiskClean.js +46 -0
- package/dist/audit/orchestrator/selectiveDeepening/highRiskClean.js.map +1 -0
- package/dist/audit/orchestrator/selectiveDeepening/index.d.ts +25 -0
- package/dist/audit/orchestrator/selectiveDeepening/index.d.ts.map +1 -0
- package/dist/audit/orchestrator/selectiveDeepening/index.js +157 -0
- package/dist/audit/orchestrator/selectiveDeepening/index.js.map +1 -0
- package/dist/audit/orchestrator/selectiveDeepening/lensVerification.d.ts +13 -0
- package/dist/audit/orchestrator/selectiveDeepening/lensVerification.d.ts.map +1 -0
- package/dist/audit/orchestrator/selectiveDeepening/lensVerification.js +269 -0
- package/dist/audit/orchestrator/selectiveDeepening/lensVerification.js.map +1 -0
- package/dist/audit/orchestrator/selectiveDeepening/runtimeValidation.d.ts +14 -0
- package/dist/audit/orchestrator/selectiveDeepening/runtimeValidation.d.ts.map +1 -0
- package/dist/audit/orchestrator/selectiveDeepening/runtimeValidation.js +58 -0
- package/dist/audit/orchestrator/selectiveDeepening/runtimeValidation.js.map +1 -0
- package/dist/audit/orchestrator/selectiveDeepening/shared.d.ts +42 -0
- package/dist/audit/orchestrator/selectiveDeepening/shared.d.ts.map +1 -0
- package/dist/audit/orchestrator/selectiveDeepening/shared.js +121 -0
- package/dist/audit/orchestrator/selectiveDeepening/shared.js.map +1 -0
- package/dist/audit/orchestrator/selectiveDeepening/stewardFollowup.d.ts +7 -0
- package/dist/audit/orchestrator/selectiveDeepening/stewardFollowup.d.ts.map +1 -0
- package/dist/audit/orchestrator/selectiveDeepening/stewardFollowup.js +73 -0
- package/dist/audit/orchestrator/selectiveDeepening/stewardFollowup.js.map +1 -0
- package/dist/audit/orchestrator/selectiveDeepening.d.ts +3 -0
- package/dist/audit/orchestrator/selectiveDeepening.d.ts.map +1 -0
- package/dist/audit/orchestrator/selectiveDeepening.js +7 -0
- package/dist/audit/orchestrator/selectiveDeepening.js.map +1 -0
- package/dist/audit/orchestrator/staleness.d.ts +3 -0
- package/dist/audit/orchestrator/staleness.d.ts.map +1 -0
- package/dist/audit/orchestrator/staleness.js +102 -0
- package/dist/audit/orchestrator/staleness.js.map +1 -0
- package/dist/audit/orchestrator/state.d.ts +4 -0
- package/dist/audit/orchestrator/state.d.ts.map +1 -0
- package/dist/audit/orchestrator/state.js +158 -0
- package/dist/audit/orchestrator/state.js.map +1 -0
- package/dist/audit/orchestrator/structureExecutors.d.ts +6 -0
- package/dist/audit/orchestrator/structureExecutors.d.ts.map +1 -0
- package/dist/audit/orchestrator/structureExecutors.js +116 -0
- package/dist/audit/orchestrator/structureExecutors.js.map +1 -0
- package/dist/audit/orchestrator/syntaxResolutionExecutor.d.ts +4 -0
- package/dist/audit/orchestrator/syntaxResolutionExecutor.d.ts.map +1 -0
- package/dist/audit/orchestrator/syntaxResolutionExecutor.js +260 -0
- package/dist/audit/orchestrator/syntaxResolutionExecutor.js.map +1 -0
- package/dist/audit/orchestrator/synthesisExecutors.d.ts +13 -0
- package/dist/audit/orchestrator/synthesisExecutors.d.ts.map +1 -0
- package/dist/audit/orchestrator/synthesisExecutors.js +107 -0
- package/dist/audit/orchestrator/synthesisExecutors.js.map +1 -0
- package/dist/audit/orchestrator/taskAffinityGraph.d.ts +154 -0
- package/dist/audit/orchestrator/taskAffinityGraph.d.ts.map +1 -0
- package/dist/audit/orchestrator/taskAffinityGraph.js +216 -0
- package/dist/audit/orchestrator/taskAffinityGraph.js.map +1 -0
- package/dist/audit/orchestrator/taskBuilder.d.ts +43 -0
- package/dist/audit/orchestrator/taskBuilder.d.ts.map +1 -0
- package/dist/audit/orchestrator/taskBuilder.js +355 -0
- package/dist/audit/orchestrator/taskBuilder.js.map +1 -0
- package/dist/audit/orchestrator/trivialAudit.d.ts +5 -0
- package/dist/audit/orchestrator/trivialAudit.d.ts.map +1 -0
- package/dist/audit/orchestrator/trivialAudit.js +50 -0
- package/dist/audit/orchestrator/trivialAudit.js.map +1 -0
- package/dist/audit/orchestrator/unionFind.d.ts +8 -0
- package/dist/audit/orchestrator/unionFind.d.ts.map +1 -0
- package/dist/audit/orchestrator/unionFind.js +43 -0
- package/dist/audit/orchestrator/unionFind.js.map +1 -0
- package/dist/audit/orchestrator/unitBuilder.d.ts +8 -0
- package/dist/audit/orchestrator/unitBuilder.d.ts.map +1 -0
- package/dist/audit/orchestrator/unitBuilder.js +171 -0
- package/dist/audit/orchestrator/unitBuilder.js.map +1 -0
- package/dist/audit/orchestrator.d.ts +7 -0
- package/dist/audit/orchestrator.d.ts.map +1 -0
- package/dist/audit/orchestrator.js +68 -0
- package/dist/audit/orchestrator.js.map +1 -0
- package/dist/audit/prompts/renderWorkerPrompt.d.ts +3 -0
- package/dist/audit/prompts/renderWorkerPrompt.d.ts.map +1 -0
- package/dist/audit/prompts/renderWorkerPrompt.js +87 -0
- package/dist/audit/prompts/renderWorkerPrompt.js.map +1 -0
- package/dist/audit/providers/claudeCodeProvider.d.ts +11 -0
- package/dist/audit/providers/claudeCodeProvider.d.ts.map +1 -0
- package/dist/audit/providers/claudeCodeProvider.js +23 -0
- package/dist/audit/providers/claudeCodeProvider.js.map +1 -0
- package/dist/audit/providers/constants.d.ts +2 -0
- package/dist/audit/providers/constants.d.ts.map +1 -0
- package/dist/audit/providers/constants.js +2 -0
- package/dist/audit/providers/constants.js.map +1 -0
- package/dist/audit/providers/index.d.ts +14 -0
- package/dist/audit/providers/index.d.ts.map +1 -0
- package/dist/audit/providers/index.js +21 -0
- package/dist/audit/providers/index.js.map +1 -0
- package/dist/audit/providers/opencodeProvider.d.ts +5 -0
- package/dist/audit/providers/opencodeProvider.d.ts.map +1 -0
- package/dist/audit/providers/opencodeProvider.js +10 -0
- package/dist/audit/providers/opencodeProvider.js.map +1 -0
- package/dist/audit/quota/discoveredLimits.d.ts +27 -0
- package/dist/audit/quota/discoveredLimits.d.ts.map +1 -0
- package/dist/audit/quota/discoveredLimits.js +91 -0
- package/dist/audit/quota/discoveredLimits.js.map +1 -0
- package/dist/audit/quota/headerExtraction.d.ts +9 -0
- package/dist/audit/quota/headerExtraction.d.ts.map +1 -0
- package/dist/audit/quota/headerExtraction.js +148 -0
- package/dist/audit/quota/headerExtraction.js.map +1 -0
- package/dist/audit/quota/headerExtractors/claudeCodeHeaderExtractor.d.ts +7 -0
- package/dist/audit/quota/headerExtractors/claudeCodeHeaderExtractor.d.ts.map +1 -0
- package/dist/audit/quota/headerExtractors/claudeCodeHeaderExtractor.js +27 -0
- package/dist/audit/quota/headerExtractors/claudeCodeHeaderExtractor.js.map +1 -0
- package/dist/audit/quota/headerExtractors/genericHeaderExtractor.d.ts +10 -0
- package/dist/audit/quota/headerExtractors/genericHeaderExtractor.d.ts.map +1 -0
- package/dist/audit/quota/headerExtractors/genericHeaderExtractor.js +8 -0
- package/dist/audit/quota/headerExtractors/genericHeaderExtractor.js.map +1 -0
- package/dist/audit/quota/headerExtractors/index.d.ts +6 -0
- package/dist/audit/quota/headerExtractors/index.d.ts.map +1 -0
- package/dist/audit/quota/headerExtractors/index.js +11 -0
- package/dist/audit/quota/headerExtractors/index.js.map +1 -0
- package/dist/audit/quota/hostLimits.d.ts +8 -0
- package/dist/audit/quota/hostLimits.d.ts.map +1 -0
- package/dist/audit/quota/hostLimits.js +9 -0
- package/dist/audit/quota/hostLimits.js.map +1 -0
- package/dist/audit/quota/index.d.ts +383 -0
- package/dist/audit/quota/index.d.ts.map +1 -0
- package/dist/audit/quota/index.js +45 -0
- package/dist/audit/quota/index.js.map +1 -0
- package/dist/audit/reporting/findingIdentity.d.ts +34 -0
- package/dist/audit/reporting/findingIdentity.d.ts.map +1 -0
- package/dist/audit/reporting/findingIdentity.js +64 -0
- package/dist/audit/reporting/findingIdentity.js.map +1 -0
- package/dist/audit/reporting/findingRanks.d.ts +2 -0
- package/dist/audit/reporting/findingRanks.d.ts.map +1 -0
- package/dist/audit/reporting/findingRanks.js +7 -0
- package/dist/audit/reporting/findingRanks.js.map +1 -0
- package/dist/audit/reporting/mergeFindings.d.ts +6 -0
- package/dist/audit/reporting/mergeFindings.d.ts.map +1 -0
- package/dist/audit/reporting/mergeFindings.js +326 -0
- package/dist/audit/reporting/mergeFindings.js.map +1 -0
- package/dist/audit/reporting/synthesis.d.ts +124 -0
- package/dist/audit/reporting/synthesis.d.ts.map +1 -0
- package/dist/audit/reporting/synthesis.js +369 -0
- package/dist/audit/reporting/synthesis.js.map +1 -0
- package/dist/audit/reporting/synthesisNarrativePrompt.d.ts +8 -0
- package/dist/audit/reporting/synthesisNarrativePrompt.d.ts.map +1 -0
- package/dist/audit/reporting/synthesisNarrativePrompt.js +66 -0
- package/dist/audit/reporting/synthesisNarrativePrompt.js.map +1 -0
- package/dist/audit/reporting/workBlocks.d.ts +10 -0
- package/dist/audit/reporting/workBlocks.d.ts.map +1 -0
- package/dist/audit/reporting/workBlocks.js +154 -0
- package/dist/audit/reporting/workBlocks.js.map +1 -0
- package/dist/audit/supervisor/operatorHandoff.d.ts +65 -0
- package/dist/audit/supervisor/operatorHandoff.d.ts.map +1 -0
- package/dist/audit/supervisor/operatorHandoff.js +277 -0
- package/dist/audit/supervisor/operatorHandoff.js.map +1 -0
- package/dist/audit/supervisor/runLedger.d.ts +4 -0
- package/dist/audit/supervisor/runLedger.d.ts.map +1 -0
- package/dist/audit/supervisor/runLedger.js +118 -0
- package/dist/audit/supervisor/runLedger.js.map +1 -0
- package/dist/audit/supervisor/sessionConfig.d.ts +12 -0
- package/dist/audit/supervisor/sessionConfig.d.ts.map +1 -0
- package/dist/audit/supervisor/sessionConfig.js +49 -0
- package/dist/audit/supervisor/sessionConfig.js.map +1 -0
- package/dist/audit/types/activeDispatch.d.ts +36 -0
- package/dist/audit/types/activeDispatch.d.ts.map +1 -0
- package/dist/audit/types/activeDispatch.js +3 -0
- package/dist/audit/types/activeDispatch.js.map +1 -0
- package/dist/audit/types/analyzerCapability.d.ts +17 -0
- package/dist/audit/types/analyzerCapability.d.ts.map +1 -0
- package/dist/audit/types/analyzerCapability.js +2 -0
- package/dist/audit/types/analyzerCapability.js.map +1 -0
- package/dist/audit/types/artifactMetadata.d.ts +9 -0
- package/dist/audit/types/artifactMetadata.d.ts.map +1 -0
- package/dist/audit/types/artifactMetadata.js +2 -0
- package/dist/audit/types/artifactMetadata.js.map +1 -0
- package/dist/audit/types/auditScope.d.ts +58 -0
- package/dist/audit/types/auditScope.d.ts.map +1 -0
- package/dist/audit/types/auditScope.js +15 -0
- package/dist/audit/types/auditScope.js.map +1 -0
- package/dist/audit/types/auditState.d.ts +18 -0
- package/dist/audit/types/auditState.d.ts.map +1 -0
- package/dist/audit/types/auditState.js +2 -0
- package/dist/audit/types/auditState.js.map +1 -0
- package/dist/audit/types/designAssessment.d.ts +22 -0
- package/dist/audit/types/designAssessment.d.ts.map +1 -0
- package/dist/audit/types/designAssessment.js +8 -0
- package/dist/audit/types/designAssessment.js.map +1 -0
- package/dist/audit/types/externalAnalyzer.d.ts +225 -0
- package/dist/audit/types/externalAnalyzer.d.ts.map +1 -0
- package/dist/audit/types/externalAnalyzer.js +56 -0
- package/dist/audit/types/externalAnalyzer.js.map +1 -0
- package/dist/audit/types/flowCoverage.d.ts +16 -0
- package/dist/audit/types/flowCoverage.d.ts.map +1 -0
- package/dist/audit/types/flowCoverage.js +6 -0
- package/dist/audit/types/flowCoverage.js.map +1 -0
- package/dist/audit/types/reviewPlanning.d.ts +513 -0
- package/dist/audit/types/reviewPlanning.d.ts.map +1 -0
- package/dist/audit/types/reviewPlanning.js +109 -0
- package/dist/audit/types/reviewPlanning.js.map +1 -0
- package/dist/audit/types/runtimeValidation.d.ts +155 -0
- package/dist/audit/types/runtimeValidation.d.ts.map +1 -0
- package/dist/audit/types/runtimeValidation.js +52 -0
- package/dist/audit/types/runtimeValidation.js.map +1 -0
- package/dist/audit/types/synthesisNarrative.d.ts +8 -0
- package/dist/audit/types/synthesisNarrative.d.ts.map +1 -0
- package/dist/audit/types/synthesisNarrative.js +6 -0
- package/dist/audit/types/synthesisNarrative.js.map +1 -0
- package/dist/audit/types/toolingManifest.d.ts +8 -0
- package/dist/audit/types/toolingManifest.d.ts.map +1 -0
- package/dist/audit/types/toolingManifest.js +2 -0
- package/dist/audit/types/toolingManifest.js.map +1 -0
- package/dist/audit/types/workerResult.d.ts +14 -0
- package/dist/audit/types/workerResult.d.ts.map +1 -0
- package/dist/audit/types/workerResult.js +2 -0
- package/dist/audit/types/workerResult.js.map +1 -0
- package/dist/audit/types/workerSession.d.ts +28 -0
- package/dist/audit/types/workerSession.d.ts.map +1 -0
- package/dist/audit/types/workerSession.js +5 -0
- package/dist/audit/types/workerSession.js.map +1 -0
- package/dist/audit/types.d.ts +1077 -0
- package/dist/audit/types.d.ts.map +1 -0
- package/dist/audit/types.js +160 -0
- package/dist/audit/types.js.map +1 -0
- package/dist/audit/validation/anchorGrounding.d.ts +49 -0
- package/dist/audit/validation/anchorGrounding.d.ts.map +1 -0
- package/dist/audit/validation/anchorGrounding.js +183 -0
- package/dist/audit/validation/anchorGrounding.js.map +1 -0
- package/dist/audit/validation/artifacts.d.ts +4 -0
- package/dist/audit/validation/artifacts.d.ts.map +1 -0
- package/dist/audit/validation/artifacts.js +313 -0
- package/dist/audit/validation/artifacts.js.map +1 -0
- package/dist/audit/validation/auditResults.d.ts +16 -0
- package/dist/audit/validation/auditResults.d.ts.map +1 -0
- package/dist/audit/validation/auditResults.js +619 -0
- package/dist/audit/validation/auditResults.js.map +1 -0
- package/dist/audit/validation/designFindingGrounding.d.ts +33 -0
- package/dist/audit/validation/designFindingGrounding.d.ts.map +1 -0
- package/dist/audit/validation/designFindingGrounding.js +43 -0
- package/dist/audit/validation/designFindingGrounding.js.map +1 -0
- package/dist/audit/validation/quoteGrounding.d.ts +18 -0
- package/dist/audit/validation/quoteGrounding.d.ts.map +1 -0
- package/dist/audit/validation/quoteGrounding.js +18 -0
- package/dist/audit/validation/quoteGrounding.js.map +1 -0
- package/dist/audit/validation/sessionConfig.d.ts +8 -0
- package/dist/audit/validation/sessionConfig.d.ts.map +1 -0
- package/dist/audit/validation/sessionConfig.js +334 -0
- package/dist/audit/validation/sessionConfig.js.map +1 -0
- package/dist/remediate/contractPipeline/artifactStore.d.ts +58 -0
- package/dist/remediate/contractPipeline/artifactStore.d.ts.map +1 -0
- package/dist/remediate/contractPipeline/artifactStore.js +201 -0
- package/dist/remediate/contractPipeline/artifactStore.js.map +1 -0
- package/dist/remediate/contractPipeline/cyclicSeamResolution.d.ts +68 -0
- package/dist/remediate/contractPipeline/cyclicSeamResolution.d.ts.map +1 -0
- package/dist/remediate/contractPipeline/cyclicSeamResolution.js +151 -0
- package/dist/remediate/contractPipeline/cyclicSeamResolution.js.map +1 -0
- package/dist/remediate/contractPipeline/derive.d.ts +88 -0
- package/dist/remediate/contractPipeline/derive.d.ts.map +1 -0
- package/dist/remediate/contractPipeline/derive.js +216 -0
- package/dist/remediate/contractPipeline/derive.js.map +1 -0
- package/dist/remediate/contractPipeline/idRegistry.d.ts +49 -0
- package/dist/remediate/contractPipeline/idRegistry.d.ts.map +1 -0
- package/dist/remediate/contractPipeline/idRegistry.js +57 -0
- package/dist/remediate/contractPipeline/idRegistry.js.map +1 -0
- package/dist/remediate/contractPipeline/reviewSnapshot.d.ts +52 -0
- package/dist/remediate/contractPipeline/reviewSnapshot.d.ts.map +1 -0
- package/dist/remediate/contractPipeline/reviewSnapshot.js +116 -0
- package/dist/remediate/contractPipeline/reviewSnapshot.js.map +1 -0
- package/dist/remediate/contractPipeline/semanticProjection.d.ts +46 -0
- package/dist/remediate/contractPipeline/semanticProjection.d.ts.map +1 -0
- package/dist/remediate/contractPipeline/semanticProjection.js +102 -0
- package/dist/remediate/contractPipeline/semanticProjection.js.map +1 -0
- package/dist/remediate/coverage/findingLedger.d.ts +99 -0
- package/dist/remediate/coverage/findingLedger.d.ts.map +1 -0
- package/dist/remediate/coverage/findingLedger.js +110 -0
- package/dist/remediate/coverage/findingLedger.js.map +1 -0
- package/dist/remediate/dedup/crossLensDedup.d.ts +9 -0
- package/dist/remediate/dedup/crossLensDedup.d.ts.map +1 -0
- package/dist/remediate/dedup/crossLensDedup.js +191 -0
- package/dist/remediate/dedup/crossLensDedup.js.map +1 -0
- package/dist/remediate/dispatch/amendmentClaim.d.ts +41 -0
- package/dist/remediate/dispatch/amendmentClaim.d.ts.map +1 -0
- package/dist/remediate/dispatch/amendmentClaim.js +60 -0
- package/dist/remediate/dispatch/amendmentClaim.js.map +1 -0
- package/dist/remediate/dispatch/ownershipRegistry.d.ts +97 -0
- package/dist/remediate/dispatch/ownershipRegistry.d.ts.map +1 -0
- package/dist/remediate/dispatch/ownershipRegistry.js +217 -0
- package/dist/remediate/dispatch/ownershipRegistry.js.map +1 -0
- package/dist/remediate/findingFilter.d.ts +42 -0
- package/dist/remediate/findingFilter.d.ts.map +1 -0
- package/dist/remediate/findingFilter.js +62 -0
- package/dist/remediate/findingFilter.js.map +1 -0
- package/dist/remediate/index.d.ts +45 -0
- package/dist/remediate/index.d.ts.map +1 -0
- package/dist/remediate/index.js +434 -0
- package/dist/remediate/index.js.map +1 -0
- package/dist/remediate/intake.d.ts +168 -0
- package/dist/remediate/intake.d.ts.map +1 -0
- package/dist/remediate/intake.js +340 -0
- package/dist/remediate/intake.js.map +1 -0
- package/dist/remediate/intent/checkpointFilter.d.ts +14 -0
- package/dist/remediate/intent/checkpointFilter.d.ts.map +1 -0
- package/dist/remediate/intent/checkpointFilter.js +111 -0
- package/dist/remediate/intent/checkpointFilter.js.map +1 -0
- package/dist/remediate/phases/close.d.ts +32 -0
- package/dist/remediate/phases/close.d.ts.map +1 -0
- package/dist/remediate/phases/close.js +992 -0
- package/dist/remediate/phases/close.js.map +1 -0
- package/dist/remediate/phases/constants.d.ts +3 -0
- package/dist/remediate/phases/constants.d.ts.map +1 -0
- package/dist/remediate/phases/constants.js +3 -0
- package/dist/remediate/phases/constants.js.map +1 -0
- package/dist/remediate/phases/grounding.d.ts +77 -0
- package/dist/remediate/phases/grounding.d.ts.map +1 -0
- package/dist/remediate/phases/grounding.js +153 -0
- package/dist/remediate/phases/grounding.js.map +1 -0
- package/dist/remediate/phases/plan.d.ts +113 -0
- package/dist/remediate/phases/plan.d.ts.map +1 -0
- package/dist/remediate/phases/plan.js +988 -0
- package/dist/remediate/phases/plan.js.map +1 -0
- package/dist/remediate/phases/triage.d.ts +4 -0
- package/dist/remediate/phases/triage.d.ts.map +1 -0
- package/dist/remediate/phases/triage.js +175 -0
- package/dist/remediate/phases/triage.js.map +1 -0
- package/dist/remediate/phases/workerTasks.d.ts +21 -0
- package/dist/remediate/phases/workerTasks.d.ts.map +1 -0
- package/dist/remediate/phases/workerTasks.js +31 -0
- package/dist/remediate/phases/workerTasks.js.map +1 -0
- package/dist/remediate/providers/claudeCodeProvider.d.ts +12 -0
- package/dist/remediate/providers/claudeCodeProvider.d.ts.map +1 -0
- package/dist/remediate/providers/claudeCodeProvider.js +24 -0
- package/dist/remediate/providers/claudeCodeProvider.js.map +1 -0
- package/dist/remediate/providers/constants.d.ts +2 -0
- package/dist/remediate/providers/constants.d.ts.map +1 -0
- package/dist/remediate/providers/constants.js +2 -0
- package/dist/remediate/providers/constants.js.map +1 -0
- package/dist/remediate/providers/index.d.ts +15 -0
- package/dist/remediate/providers/index.d.ts.map +1 -0
- package/dist/remediate/providers/index.js +22 -0
- package/dist/remediate/providers/index.js.map +1 -0
- package/dist/remediate/providers/opencodeProvider.d.ts +5 -0
- package/dist/remediate/providers/opencodeProvider.d.ts.map +1 -0
- package/dist/remediate/providers/opencodeProvider.js +10 -0
- package/dist/remediate/providers/opencodeProvider.js.map +1 -0
- package/dist/remediate/quota/hostLimits.d.ts +8 -0
- package/dist/remediate/quota/hostLimits.d.ts.map +1 -0
- package/dist/remediate/quota/hostLimits.js +9 -0
- package/dist/remediate/quota/hostLimits.js.map +1 -0
- package/dist/remediate/quota/index.d.ts +8 -0
- package/dist/remediate/quota/index.d.ts.map +1 -0
- package/dist/remediate/quota/index.js +12 -0
- package/dist/remediate/quota/index.js.map +1 -0
- package/dist/remediate/review/reviewGate.d.ts +72 -0
- package/dist/remediate/review/reviewGate.d.ts.map +1 -0
- package/dist/remediate/review/reviewGate.js +112 -0
- package/dist/remediate/review/reviewGate.js.map +1 -0
- package/dist/remediate/review/reviewNecessity.d.ts +53 -0
- package/dist/remediate/review/reviewNecessity.d.ts.map +1 -0
- package/dist/remediate/review/reviewNecessity.js +129 -0
- package/dist/remediate/review/reviewNecessity.js.map +1 -0
- package/dist/remediate/state/closingActions.d.ts +3 -0
- package/dist/remediate/state/closingActions.d.ts.map +1 -0
- package/dist/remediate/state/closingActions.js +10 -0
- package/dist/remediate/state/closingActions.js.map +1 -0
- package/dist/remediate/state/itemStatus.d.ts +40 -0
- package/dist/remediate/state/itemStatus.d.ts.map +1 -0
- package/dist/remediate/state/itemStatus.js +138 -0
- package/dist/remediate/state/itemStatus.js.map +1 -0
- package/dist/remediate/state/store.d.ts +65 -0
- package/dist/remediate/state/store.d.ts.map +1 -0
- package/dist/remediate/state/store.js +141 -0
- package/dist/remediate/state/store.js.map +1 -0
- package/dist/remediate/state/types.d.ts +766 -0
- package/dist/remediate/state/types.d.ts.map +1 -0
- package/dist/remediate/state/types.js +122 -0
- package/dist/remediate/state/types.js.map +1 -0
- package/dist/remediate/steps/contractPipeline.d.ts +173 -0
- package/dist/remediate/steps/contractPipeline.d.ts.map +1 -0
- package/dist/remediate/steps/contractPipeline.js +1229 -0
- package/dist/remediate/steps/contractPipeline.js.map +1 -0
- package/dist/remediate/steps/contractPipelinePrompts.d.ts +72 -0
- package/dist/remediate/steps/contractPipelinePrompts.d.ts.map +1 -0
- package/dist/remediate/steps/contractPipelinePrompts.js +438 -0
- package/dist/remediate/steps/contractPipelinePrompts.js.map +1 -0
- package/dist/remediate/steps/dispatch.d.ts +434 -0
- package/dist/remediate/steps/dispatch.d.ts.map +1 -0
- package/dist/remediate/steps/dispatch.js +2180 -0
- package/dist/remediate/steps/dispatch.js.map +1 -0
- package/dist/remediate/steps/intakeResolver.d.ts +32 -0
- package/dist/remediate/steps/intakeResolver.d.ts.map +1 -0
- package/dist/remediate/steps/intakeResolver.js +310 -0
- package/dist/remediate/steps/intakeResolver.js.map +1 -0
- package/dist/remediate/steps/leanFastPath.d.ts +49 -0
- package/dist/remediate/steps/leanFastPath.d.ts.map +1 -0
- package/dist/remediate/steps/leanFastPath.js +151 -0
- package/dist/remediate/steps/leanFastPath.js.map +1 -0
- package/dist/remediate/steps/nextStep.d.ts +323 -0
- package/dist/remediate/steps/nextStep.d.ts.map +1 -0
- package/dist/remediate/steps/nextStep.js +2721 -0
- package/dist/remediate/steps/nextStep.js.map +1 -0
- package/dist/remediate/steps/prompts.d.ts +26 -0
- package/dist/remediate/steps/prompts.d.ts.map +1 -0
- package/dist/remediate/steps/prompts.js +370 -0
- package/dist/remediate/steps/prompts.js.map +1 -0
- package/dist/remediate/steps/providerNodeDispatch.d.ts +42 -0
- package/dist/remediate/steps/providerNodeDispatch.d.ts.map +1 -0
- package/dist/remediate/steps/providerNodeDispatch.js +100 -0
- package/dist/remediate/steps/providerNodeDispatch.js.map +1 -0
- package/dist/remediate/steps/rollingSession.d.ts +84 -0
- package/dist/remediate/steps/rollingSession.d.ts.map +1 -0
- package/dist/remediate/steps/rollingSession.js +147 -0
- package/dist/remediate/steps/rollingSession.js.map +1 -0
- package/dist/remediate/steps/stepUtils.d.ts +63 -0
- package/dist/remediate/steps/stepUtils.d.ts.map +1 -0
- package/dist/remediate/steps/stepUtils.js +117 -0
- package/dist/remediate/steps/stepUtils.js.map +1 -0
- package/dist/remediate/steps/stepWriter.d.ts +27 -0
- package/dist/remediate/steps/stepWriter.d.ts.map +1 -0
- package/dist/remediate/steps/stepWriter.js +37 -0
- package/dist/remediate/steps/stepWriter.js.map +1 -0
- package/dist/remediate/steps/types.d.ts +83 -0
- package/dist/remediate/steps/types.d.ts.map +1 -0
- package/dist/remediate/steps/types.js +6 -0
- package/dist/remediate/steps/types.js.map +1 -0
- package/dist/remediate/types/options.d.ts +6 -0
- package/dist/remediate/types/options.d.ts.map +1 -0
- package/dist/remediate/types/options.js +2 -0
- package/dist/remediate/types/options.js.map +1 -0
- package/dist/remediate/types/workerSession.d.ts +36 -0
- package/dist/remediate/types/workerSession.d.ts.map +1 -0
- package/dist/remediate/types/workerSession.js +13 -0
- package/dist/remediate/types/workerSession.js.map +1 -0
- package/dist/remediate/utils/commands.d.ts +17 -0
- package/dist/remediate/utils/commands.d.ts.map +1 -0
- package/dist/remediate/utils/commands.js +26 -0
- package/dist/remediate/utils/commands.js.map +1 -0
- package/dist/remediate/utils/fileIntegrity.d.ts +27 -0
- package/dist/remediate/utils/fileIntegrity.d.ts.map +1 -0
- package/dist/remediate/utils/fileIntegrity.js +201 -0
- package/dist/remediate/utils/fileIntegrity.js.map +1 -0
- package/dist/remediate/utils/hostAssets.d.ts +18 -0
- package/dist/remediate/utils/hostAssets.d.ts.map +1 -0
- package/dist/remediate/utils/hostAssets.js +31 -0
- package/dist/remediate/utils/hostAssets.js.map +1 -0
- package/dist/remediate/validation/artifacts.d.ts +9 -0
- package/dist/remediate/validation/artifacts.d.ts.map +1 -0
- package/dist/remediate/validation/artifacts.js +316 -0
- package/dist/remediate/validation/artifacts.js.map +1 -0
- package/dist/remediate/validation/contractPipeline.d.ts +36 -0
- package/dist/remediate/validation/contractPipeline.d.ts.map +1 -0
- package/dist/remediate/validation/contractPipeline.js +569 -0
- package/dist/remediate/validation/contractPipeline.js.map +1 -0
- package/dist/remediate/validation/contractPipelineGates.d.ts +161 -0
- package/dist/remediate/validation/contractPipelineGates.d.ts.map +1 -0
- package/dist/remediate/validation/contractPipelineGates.js +739 -0
- package/dist/remediate/validation/contractPipelineGates.js.map +1 -0
- package/dist/remediate/validation/remediationState.d.ts +8 -0
- package/dist/remediate/validation/remediationState.d.ts.map +1 -0
- package/dist/remediate/validation/remediationState.js +187 -0
- package/dist/remediate/validation/remediationState.js.map +1 -0
- package/dist/shared/agentReflections.d.ts +61 -0
- package/dist/shared/agentReflections.d.ts.map +1 -0
- package/dist/shared/agentReflections.js +180 -0
- package/dist/shared/agentReflections.js.map +1 -0
- package/dist/shared/concurrency.d.ts +16 -0
- package/dist/shared/concurrency.d.ts.map +1 -0
- package/dist/shared/concurrency.js +34 -0
- package/dist/shared/concurrency.js.map +1 -0
- package/dist/shared/contracts.d.ts +2 -0
- package/dist/shared/contracts.d.ts.map +1 -0
- package/dist/shared/contracts.js +2 -0
- package/dist/shared/contracts.js.map +1 -0
- package/dist/shared/dispatch/rollingDispatch.d.ts +192 -0
- package/dist/shared/dispatch/rollingDispatch.d.ts.map +1 -0
- package/dist/shared/dispatch/rollingDispatch.js +389 -0
- package/dist/shared/dispatch/rollingDispatch.js.map +1 -0
- package/dist/shared/dispatch/tierRank.d.ts +53 -0
- package/dist/shared/dispatch/tierRank.d.ts.map +1 -0
- package/dist/shared/dispatch/tierRank.js +69 -0
- package/dist/shared/dispatch/tierRank.js.map +1 -0
- package/dist/shared/engine/obligationEngine.d.ts +159 -0
- package/dist/shared/engine/obligationEngine.d.ts.map +1 -0
- package/dist/shared/engine/obligationEngine.js +124 -0
- package/dist/shared/engine/obligationEngine.js.map +1 -0
- package/dist/shared/findingIdentitySignature.d.ts +82 -0
- package/dist/shared/findingIdentitySignature.d.ts.map +1 -0
- package/dist/shared/findingIdentitySignature.js +114 -0
- package/dist/shared/findingIdentitySignature.js.map +1 -0
- package/dist/shared/git.d.ts +18 -0
- package/dist/shared/git.d.ts.map +1 -0
- package/dist/shared/git.js +63 -0
- package/dist/shared/git.js.map +1 -0
- package/dist/shared/hash.d.ts +16 -0
- package/dist/shared/hash.d.ts.map +1 -0
- package/dist/shared/hash.js +36 -0
- package/dist/shared/hash.js.map +1 -0
- package/dist/shared/hostAssets.d.ts +40 -0
- package/dist/shared/hostAssets.d.ts.map +1 -0
- package/dist/shared/hostAssets.js +110 -0
- package/dist/shared/hostAssets.js.map +1 -0
- package/dist/shared/ids.d.ts +18 -0
- package/dist/shared/ids.d.ts.map +1 -0
- package/dist/shared/ids.js +27 -0
- package/dist/shared/ids.js.map +1 -0
- package/dist/shared/index.d.ts +150 -0
- package/dist/shared/index.d.ts.map +1 -0
- package/dist/shared/index.js +112 -0
- package/dist/shared/index.js.map +1 -0
- package/dist/shared/intent/clauseInterpreter.d.ts +84 -0
- package/dist/shared/intent/clauseInterpreter.d.ts.map +1 -0
- package/dist/shared/intent/clauseInterpreter.js +183 -0
- package/dist/shared/intent/clauseInterpreter.js.map +1 -0
- package/dist/shared/intent/freeFormIntentInterpreter.d.ts +46 -0
- package/dist/shared/intent/freeFormIntentInterpreter.d.ts.map +1 -0
- package/dist/shared/intent/freeFormIntentInterpreter.js +126 -0
- package/dist/shared/intent/freeFormIntentInterpreter.js.map +1 -0
- package/dist/shared/intent/sharedIntentData.d.ts +16 -0
- package/dist/shared/intent/sharedIntentData.d.ts.map +1 -0
- package/dist/shared/intent/sharedIntentData.js +38 -0
- package/dist/shared/intent/sharedIntentData.js.map +1 -0
- package/dist/shared/io/auditToolsPaths.d.ts +36 -0
- package/dist/shared/io/auditToolsPaths.d.ts.map +1 -0
- package/dist/shared/io/auditToolsPaths.js +47 -0
- package/dist/shared/io/auditToolsPaths.js.map +1 -0
- package/dist/shared/io/json.d.ts +30 -0
- package/dist/shared/io/json.d.ts.map +1 -0
- package/dist/shared/io/json.js +183 -0
- package/dist/shared/io/json.js.map +1 -0
- package/dist/shared/io/stepContractWriter.d.ts +103 -0
- package/dist/shared/io/stepContractWriter.d.ts.map +1 -0
- package/dist/shared/io/stepContractWriter.js +85 -0
- package/dist/shared/io/stepContractWriter.js.map +1 -0
- package/dist/shared/observability/runLog.d.ts +37 -0
- package/dist/shared/observability/runLog.d.ts.map +1 -0
- package/dist/shared/observability/runLog.js +40 -0
- package/dist/shared/observability/runLog.js.map +1 -0
- package/dist/shared/opencodePermissions.d.ts +49 -0
- package/dist/shared/opencodePermissions.d.ts.map +1 -0
- package/dist/shared/opencodePermissions.js +118 -0
- package/dist/shared/opencodePermissions.js.map +1 -0
- package/dist/shared/parsing/stringAwareScanner.d.ts +32 -0
- package/dist/shared/parsing/stringAwareScanner.d.ts.map +1 -0
- package/dist/shared/parsing/stringAwareScanner.js +51 -0
- package/dist/shared/parsing/stringAwareScanner.js.map +1 -0
- package/dist/shared/prompts.d.ts +47 -0
- package/dist/shared/prompts.d.ts.map +1 -0
- package/dist/shared/prompts.js +41 -0
- package/dist/shared/prompts.js.map +1 -0
- package/dist/shared/providers/claudeCodeProvider.d.ts +56 -0
- package/dist/shared/providers/claudeCodeProvider.d.ts.map +1 -0
- package/dist/shared/providers/claudeCodeProvider.js +67 -0
- package/dist/shared/providers/claudeCodeProvider.js.map +1 -0
- package/dist/shared/providers/codexProvider.d.ts +37 -0
- package/dist/shared/providers/codexProvider.d.ts.map +1 -0
- package/dist/shared/providers/codexProvider.js +79 -0
- package/dist/shared/providers/codexProvider.js.map +1 -0
- package/dist/shared/providers/constants.d.ts +4 -0
- package/dist/shared/providers/constants.d.ts.map +1 -0
- package/dist/shared/providers/constants.js +4 -0
- package/dist/shared/providers/constants.js.map +1 -0
- package/dist/shared/providers/localSubprocessProvider.d.ts +10 -0
- package/dist/shared/providers/localSubprocessProvider.d.ts.map +1 -0
- package/dist/shared/providers/localSubprocessProvider.js +20 -0
- package/dist/shared/providers/localSubprocessProvider.js.map +1 -0
- package/dist/shared/providers/openAiCompatibleProvider.d.ts +62 -0
- package/dist/shared/providers/openAiCompatibleProvider.d.ts.map +1 -0
- package/dist/shared/providers/openAiCompatibleProvider.js +333 -0
- package/dist/shared/providers/openAiCompatibleProvider.js.map +1 -0
- package/dist/shared/providers/opencodeLaunch.d.ts +28 -0
- package/dist/shared/providers/opencodeLaunch.d.ts.map +1 -0
- package/dist/shared/providers/opencodeLaunch.js +39 -0
- package/dist/shared/providers/opencodeLaunch.js.map +1 -0
- package/dist/shared/providers/opencodeProvider.d.ts +19 -0
- package/dist/shared/providers/opencodeProvider.d.ts.map +1 -0
- package/dist/shared/providers/opencodeProvider.js +41 -0
- package/dist/shared/providers/opencodeProvider.js.map +1 -0
- package/dist/shared/providers/providerConfirmation.d.ts +56 -0
- package/dist/shared/providers/providerConfirmation.d.ts.map +1 -0
- package/dist/shared/providers/providerConfirmation.js +195 -0
- package/dist/shared/providers/providerConfirmation.js.map +1 -0
- package/dist/shared/providers/providerDiagnostics.d.ts +11 -0
- package/dist/shared/providers/providerDiagnostics.d.ts.map +1 -0
- package/dist/shared/providers/providerDiagnostics.js +28 -0
- package/dist/shared/providers/providerDiagnostics.js.map +1 -0
- package/dist/shared/providers/providerFactory.d.ts +72 -0
- package/dist/shared/providers/providerFactory.d.ts.map +1 -0
- package/dist/shared/providers/providerFactory.js +246 -0
- package/dist/shared/providers/providerFactory.js.map +1 -0
- package/dist/shared/providers/providerKeyedFactory.d.ts +14 -0
- package/dist/shared/providers/providerKeyedFactory.d.ts.map +1 -0
- package/dist/shared/providers/providerKeyedFactory.js +16 -0
- package/dist/shared/providers/providerKeyedFactory.js.map +1 -0
- package/dist/shared/providers/spawnLoggedCommand.d.ts +10 -0
- package/dist/shared/providers/spawnLoggedCommand.d.ts.map +1 -0
- package/dist/shared/providers/spawnLoggedCommand.js +304 -0
- package/dist/shared/providers/spawnLoggedCommand.js.map +1 -0
- package/dist/shared/providers/subprocessTemplateProvider.d.ts +19 -0
- package/dist/shared/providers/subprocessTemplateProvider.d.ts.map +1 -0
- package/dist/shared/providers/subprocessTemplateProvider.js +91 -0
- package/dist/shared/providers/subprocessTemplateProvider.js.map +1 -0
- package/dist/shared/providers/types.d.ts +43 -0
- package/dist/shared/providers/types.d.ts.map +1 -0
- package/dist/shared/providers/types.js +2 -0
- package/dist/shared/providers/types.js.map +1 -0
- package/dist/shared/providers/workerTaskLaunch.d.ts +32 -0
- package/dist/shared/providers/workerTaskLaunch.d.ts.map +1 -0
- package/dist/shared/providers/workerTaskLaunch.js +27 -0
- package/dist/shared/providers/workerTaskLaunch.js.map +1 -0
- package/dist/shared/quota/antigravityQuotaSource.d.ts +44 -0
- package/dist/shared/quota/antigravityQuotaSource.d.ts.map +1 -0
- package/dist/shared/quota/antigravityQuotaSource.js +101 -0
- package/dist/shared/quota/antigravityQuotaSource.js.map +1 -0
- package/dist/shared/quota/capacity.d.ts +283 -0
- package/dist/shared/quota/capacity.d.ts.map +1 -0
- package/dist/shared/quota/capacity.js +290 -0
- package/dist/shared/quota/capacity.js.map +1 -0
- package/dist/shared/quota/claudeCodeJsonLines.d.ts +15 -0
- package/dist/shared/quota/claudeCodeJsonLines.d.ts.map +1 -0
- package/dist/shared/quota/claudeCodeJsonLines.js +34 -0
- package/dist/shared/quota/claudeCodeJsonLines.js.map +1 -0
- package/dist/shared/quota/claudeOAuthQuotaSource.d.ts +56 -0
- package/dist/shared/quota/claudeOAuthQuotaSource.d.ts.map +1 -0
- package/dist/shared/quota/claudeOAuthQuotaSource.js +136 -0
- package/dist/shared/quota/claudeOAuthQuotaSource.js.map +1 -0
- package/dist/shared/quota/codexQuotaSource.d.ts +49 -0
- package/dist/shared/quota/codexQuotaSource.d.ts.map +1 -0
- package/dist/shared/quota/codexQuotaSource.js +96 -0
- package/dist/shared/quota/codexQuotaSource.js.map +1 -0
- package/dist/shared/quota/compositeQuotaSource.d.ts +29 -0
- package/dist/shared/quota/compositeQuotaSource.d.ts.map +1 -0
- package/dist/shared/quota/compositeQuotaSource.js +58 -0
- package/dist/shared/quota/compositeQuotaSource.js.map +1 -0
- package/dist/shared/quota/copilotQuotaSource.d.ts +57 -0
- package/dist/shared/quota/copilotQuotaSource.d.ts.map +1 -0
- package/dist/shared/quota/copilotQuotaSource.js +141 -0
- package/dist/shared/quota/copilotQuotaSource.js.map +1 -0
- package/dist/shared/quota/errorParsers/claudeCodeErrorParser.d.ts +7 -0
- package/dist/shared/quota/errorParsers/claudeCodeErrorParser.d.ts.map +1 -0
- package/dist/shared/quota/errorParsers/claudeCodeErrorParser.js +33 -0
- package/dist/shared/quota/errorParsers/claudeCodeErrorParser.js.map +1 -0
- package/dist/shared/quota/errorParsers/genericErrorParser.d.ts +10 -0
- package/dist/shared/quota/errorParsers/genericErrorParser.d.ts.map +1 -0
- package/dist/shared/quota/errorParsers/genericErrorParser.js +8 -0
- package/dist/shared/quota/errorParsers/genericErrorParser.js.map +1 -0
- package/dist/shared/quota/errorParsers/index.d.ts +6 -0
- package/dist/shared/quota/errorParsers/index.d.ts.map +1 -0
- package/dist/shared/quota/errorParsers/index.js +16 -0
- package/dist/shared/quota/errorParsers/index.js.map +1 -0
- package/dist/shared/quota/errorParsing.d.ts +8 -0
- package/dist/shared/quota/errorParsing.d.ts.map +1 -0
- package/dist/shared/quota/errorParsing.js +129 -0
- package/dist/shared/quota/errorParsing.js.map +1 -0
- package/dist/shared/quota/fileLock.d.ts +9 -0
- package/dist/shared/quota/fileLock.d.ts.map +1 -0
- package/dist/shared/quota/fileLock.js +202 -0
- package/dist/shared/quota/fileLock.js.map +1 -0
- package/dist/shared/quota/hostLimits.d.ts +16 -0
- package/dist/shared/quota/hostLimits.d.ts.map +1 -0
- package/dist/shared/quota/hostLimits.js +57 -0
- package/dist/shared/quota/hostLimits.js.map +1 -0
- package/dist/shared/quota/httpQuotaSource.d.ts +87 -0
- package/dist/shared/quota/httpQuotaSource.d.ts.map +1 -0
- package/dist/shared/quota/httpQuotaSource.js +90 -0
- package/dist/shared/quota/httpQuotaSource.js.map +1 -0
- package/dist/shared/quota/learnedQuotaSource.d.ts +8 -0
- package/dist/shared/quota/learnedQuotaSource.d.ts.map +1 -0
- package/dist/shared/quota/learnedQuotaSource.js +26 -0
- package/dist/shared/quota/learnedQuotaSource.js.map +1 -0
- package/dist/shared/quota/limits.d.ts +35 -0
- package/dist/shared/quota/limits.d.ts.map +1 -0
- package/dist/shared/quota/limits.js +110 -0
- package/dist/shared/quota/limits.js.map +1 -0
- package/dist/shared/quota/openCodeQuotaSource.d.ts +18 -0
- package/dist/shared/quota/openCodeQuotaSource.d.ts.map +1 -0
- package/dist/shared/quota/openCodeQuotaSource.js +84 -0
- package/dist/shared/quota/openCodeQuotaSource.js.map +1 -0
- package/dist/shared/quota/quotaSource.d.ts +29 -0
- package/dist/shared/quota/quotaSource.d.ts.map +1 -0
- package/dist/shared/quota/quotaSource.js +12 -0
- package/dist/shared/quota/quotaSource.js.map +1 -0
- package/dist/shared/quota/rollingEngine.d.ts +130 -0
- package/dist/shared/quota/rollingEngine.d.ts.map +1 -0
- package/dist/shared/quota/rollingEngine.js +153 -0
- package/dist/shared/quota/rollingEngine.js.map +1 -0
- package/dist/shared/quota/scheduler.d.ts +94 -0
- package/dist/shared/quota/scheduler.d.ts.map +1 -0
- package/dist/shared/quota/scheduler.js +313 -0
- package/dist/shared/quota/scheduler.js.map +1 -0
- package/dist/shared/quota/slidingWindow.d.ts +5 -0
- package/dist/shared/quota/slidingWindow.d.ts.map +1 -0
- package/dist/shared/quota/slidingWindow.js +29 -0
- package/dist/shared/quota/slidingWindow.js.map +1 -0
- package/dist/shared/quota/state.d.ts +27 -0
- package/dist/shared/quota/state.d.ts.map +1 -0
- package/dist/shared/quota/state.js +204 -0
- package/dist/shared/quota/state.js.map +1 -0
- package/dist/shared/quota/types.d.ts +109 -0
- package/dist/shared/quota/types.d.ts.map +1 -0
- package/dist/shared/quota/types.js +56 -0
- package/dist/shared/quota/types.js.map +1 -0
- package/dist/shared/reReview/projectionDiff.d.ts +65 -0
- package/dist/shared/reReview/projectionDiff.d.ts.map +1 -0
- package/dist/shared/reReview/projectionDiff.js +144 -0
- package/dist/shared/reReview/projectionDiff.js.map +1 -0
- package/dist/shared/rolling/pausedState.d.ts +109 -0
- package/dist/shared/rolling/pausedState.d.ts.map +1 -0
- package/dist/shared/rolling/pausedState.js +100 -0
- package/dist/shared/rolling/pausedState.js.map +1 -0
- package/dist/shared/tokens.d.ts +24 -0
- package/dist/shared/tokens.d.ts.map +1 -0
- package/dist/shared/tokens.js +54 -0
- package/dist/shared/tokens.js.map +1 -0
- package/dist/shared/tooling/allowlistedExec.d.ts +45 -0
- package/dist/shared/tooling/allowlistedExec.d.ts.map +1 -0
- package/dist/shared/tooling/allowlistedExec.js +340 -0
- package/dist/shared/tooling/allowlistedExec.js.map +1 -0
- package/dist/shared/tooling/analyzerDeps.d.ts +65 -0
- package/dist/shared/tooling/analyzerDeps.d.ts.map +1 -0
- package/dist/shared/tooling/analyzerDeps.js +130 -0
- package/dist/shared/tooling/analyzerDeps.js.map +1 -0
- package/dist/shared/tooling/exec.d.ts +99 -0
- package/dist/shared/tooling/exec.d.ts.map +1 -0
- package/dist/shared/tooling/exec.js +217 -0
- package/dist/shared/tooling/exec.js.map +1 -0
- package/dist/shared/tooling/repoConventions.d.ts +23 -0
- package/dist/shared/tooling/repoConventions.d.ts.map +1 -0
- package/dist/shared/tooling/repoConventions.js +177 -0
- package/dist/shared/tooling/repoConventions.js.map +1 -0
- package/dist/shared/tooling/testCommand.d.ts +17 -0
- package/dist/shared/tooling/testCommand.d.ts.map +1 -0
- package/dist/shared/tooling/testCommand.js +106 -0
- package/dist/shared/tooling/testCommand.js.map +1 -0
- package/dist/shared/types/accessDeclaration.d.ts +16 -0
- package/dist/shared/types/accessDeclaration.d.ts.map +1 -0
- package/dist/shared/types/accessDeclaration.js +9 -0
- package/dist/shared/types/accessDeclaration.js.map +1 -0
- package/dist/shared/types/contractPipeline/design.d.ts +74 -0
- package/dist/shared/types/contractPipeline/design.d.ts.map +1 -0
- package/dist/shared/types/contractPipeline/design.js +10 -0
- package/dist/shared/types/contractPipeline/design.js.map +1 -0
- package/dist/shared/types/contractPipeline/goal.d.ts +41 -0
- package/dist/shared/types/contractPipeline/goal.d.ts.map +1 -0
- package/dist/shared/types/contractPipeline/goal.js +10 -0
- package/dist/shared/types/contractPipeline/goal.js.map +1 -0
- package/dist/shared/types/contractPipeline/implementation.d.ts +64 -0
- package/dist/shared/types/contractPipeline/implementation.d.ts.map +1 -0
- package/dist/shared/types/contractPipeline/implementation.js +8 -0
- package/dist/shared/types/contractPipeline/implementation.js.map +1 -0
- package/dist/shared/types/contractPipeline/obligations.d.ts +141 -0
- package/dist/shared/types/contractPipeline/obligations.d.ts.map +1 -0
- package/dist/shared/types/contractPipeline/obligations.js +16 -0
- package/dist/shared/types/contractPipeline/obligations.js.map +1 -0
- package/dist/shared/types/contractPipeline/verification.d.ts +64 -0
- package/dist/shared/types/contractPipeline/verification.d.ts.map +1 -0
- package/dist/shared/types/contractPipeline/verification.js +10 -0
- package/dist/shared/types/contractPipeline/verification.js.map +1 -0
- package/dist/shared/types/contractPipeline.d.ts +36 -0
- package/dist/shared/types/contractPipeline.d.ts.map +1 -0
- package/dist/shared/types/contractPipeline.js +31 -0
- package/dist/shared/types/contractPipeline.js.map +1 -0
- package/dist/shared/types/disposition.d.ts +46 -0
- package/dist/shared/types/disposition.d.ts.map +1 -0
- package/dist/shared/types/disposition.js +22 -0
- package/dist/shared/types/disposition.js.map +1 -0
- package/dist/shared/types/finding.d.ts +1463 -0
- package/dist/shared/types/finding.d.ts.map +1 -0
- package/dist/shared/types/finding.js +234 -0
- package/dist/shared/types/finding.js.map +1 -0
- package/dist/shared/types/flows.d.ts +84 -0
- package/dist/shared/types/flows.d.ts.map +1 -0
- package/dist/shared/types/flows.js +23 -0
- package/dist/shared/types/flows.js.map +1 -0
- package/dist/shared/types/graph.d.ts +359 -0
- package/dist/shared/types/graph.d.ts.map +1 -0
- package/dist/shared/types/graph.js +38 -0
- package/dist/shared/types/graph.js.map +1 -0
- package/dist/shared/types/intentCheckpoint.d.ts +95 -0
- package/dist/shared/types/intentCheckpoint.d.ts.map +1 -0
- package/dist/shared/types/intentCheckpoint.js +2 -0
- package/dist/shared/types/intentCheckpoint.js.map +1 -0
- package/dist/shared/types/intentInterpretation.d.ts +57 -0
- package/dist/shared/types/intentInterpretation.d.ts.map +1 -0
- package/dist/shared/types/intentInterpretation.js +20 -0
- package/dist/shared/types/intentInterpretation.js.map +1 -0
- package/dist/shared/types/lens.d.ts +38 -0
- package/dist/shared/types/lens.d.ts.map +1 -0
- package/dist/shared/types/lens.js +80 -0
- package/dist/shared/types/lens.js.map +1 -0
- package/dist/shared/types/obligationLedger.d.ts +35 -0
- package/dist/shared/types/obligationLedger.d.ts.map +1 -0
- package/dist/shared/types/obligationLedger.js +77 -0
- package/dist/shared/types/obligationLedger.js.map +1 -0
- package/dist/shared/types/providerConfirmation.d.ts +51 -0
- package/dist/shared/types/providerConfirmation.d.ts.map +1 -0
- package/dist/shared/types/providerConfirmation.js +19 -0
- package/dist/shared/types/providerConfirmation.js.map +1 -0
- package/dist/shared/types/remediationOutcome.d.ts +41 -0
- package/dist/shared/types/remediationOutcome.d.ts.map +1 -0
- package/dist/shared/types/remediationOutcome.js +7 -0
- package/dist/shared/types/remediationOutcome.js.map +1 -0
- package/dist/shared/types/risk.d.ts +52 -0
- package/dist/shared/types/risk.d.ts.map +1 -0
- package/dist/shared/types/risk.js +17 -0
- package/dist/shared/types/risk.js.map +1 -0
- package/dist/shared/types/rollingDispatch.d.ts +61 -0
- package/dist/shared/types/rollingDispatch.d.ts.map +1 -0
- package/dist/shared/types/rollingDispatch.js +19 -0
- package/dist/shared/types/rollingDispatch.js.map +1 -0
- package/dist/shared/types/runLedger.d.ts +18 -0
- package/dist/shared/types/runLedger.d.ts.map +1 -0
- package/dist/shared/types/runLedger.js +7 -0
- package/dist/shared/types/runLedger.js.map +1 -0
- package/dist/shared/types/sessionConfig.d.ts +294 -0
- package/dist/shared/types/sessionConfig.d.ts.map +1 -0
- package/dist/shared/types/sessionConfig.js +44 -0
- package/dist/shared/types/sessionConfig.js.map +1 -0
- package/dist/shared/types/stepContract.d.ts +10 -0
- package/dist/shared/types/stepContract.d.ts.map +1 -0
- package/dist/shared/types/stepContract.js +4 -0
- package/dist/shared/types/stepContract.js.map +1 -0
- package/dist/shared/types/surfaces.d.ts +73 -0
- package/dist/shared/types/surfaces.d.ts.map +1 -0
- package/dist/shared/types/surfaces.js +21 -0
- package/dist/shared/types/surfaces.js.map +1 -0
- package/dist/shared/validation/basic.d.ts +24 -0
- package/dist/shared/validation/basic.d.ts.map +1 -0
- package/dist/shared/validation/basic.js +57 -0
- package/dist/shared/validation/basic.js.map +1 -0
- package/dist/shared/validation/findingGrounding.d.ts +45 -0
- package/dist/shared/validation/findingGrounding.d.ts.map +1 -0
- package/dist/shared/validation/findingGrounding.js +103 -0
- package/dist/shared/validation/findingGrounding.js.map +1 -0
- package/dist/shared/validation/findingsReport.d.ts +42 -0
- package/dist/shared/validation/findingsReport.d.ts.map +1 -0
- package/dist/shared/validation/findingsReport.js +76 -0
- package/dist/shared/validation/findingsReport.js.map +1 -0
- package/dist/shared/validation/sessionConfig.d.ts +22 -0
- package/dist/shared/validation/sessionConfig.d.ts.map +1 -0
- package/dist/shared/validation/sessionConfig.js +38 -0
- package/dist/shared/validation/sessionConfig.js.map +1 -0
- package/docs/audit-pkg/contracts.md +227 -0
- package/docs/audit-pkg/development.md +112 -0
- package/docs/audit-pkg/history.md +66 -0
- package/docs/audit-pkg/operator-guide.md +204 -0
- package/docs/audit-pkg/product.md +119 -0
- package/docs/audit-pkg/release.md +131 -0
- package/opencode.json +159 -0
- package/package.json +104 -0
- package/remediate-code.mjs +116 -0
- package/schemas/audit_result.schema.json +510 -0
- package/schemas/audit_results.schema.json +514 -0
- package/schemas/audit_task.schema.json +127 -0
- package/schemas/finding.schema.json +261 -0
- package/schemas/lens.schema.json +19 -0
- package/scripts/audit/postinstall.mjs +385 -0
- package/scripts/postinstall.mjs +24 -0
- package/scripts/remediate/postinstall.mjs +387 -0
- package/skills/audit-code/SKILL.md +166 -0
- package/skills/audit-code/agents/openai.yaml +4 -0
- package/skills/audit-code/audit-code.prompt.md +112 -0
- package/skills/audit-code/opencode-command-template.txt +13 -0
- package/skills/remediate-code/SKILL.md +90 -0
- package/skills/remediate-code/agents/openai.yaml +4 -0
- package/skills/remediate-code/remediate-code.prompt.md +94 -0
- package/templates/AGENTS.remediate-code.md +6 -0
|
@@ -0,0 +1,2721 @@
|
|
|
1
|
+
import { existsSync } from "node:fs";
|
|
2
|
+
import { mkdir, readFile, rename } from "node:fs/promises";
|
|
3
|
+
import { dirname, join, resolve } from "node:path";
|
|
4
|
+
import { StateStore } from "../state/store.js";
|
|
5
|
+
import { readOptionalJsonFile, writeJsonFile, formatValidationIssues, isRecord, withFsRetry, RunLogger, DO_NOT_TOKEN_WRAP_NOTE, DISPATCH_PROMPT_HANDOFF_NOTE, coerceJsonObjectArg, createRollingDispatcher, setQuotaStateDir, interpretFreeFormIntent, advance } from "audit-tools/shared";
|
|
6
|
+
import { applyPlanPipeline, buildCoverageLedger } from "../phases/plan.js";
|
|
7
|
+
import { groundExtractedFindings } from "../phases/grounding.js";
|
|
8
|
+
import { runTriagePhase } from "../phases/triage.js";
|
|
9
|
+
import { runClosePhase } from "../phases/close.js";
|
|
10
|
+
import { validateRemediationPlan } from "../validation/remediationState.js";
|
|
11
|
+
import { mergeImplementResults, prepareImplementDispatch, readExtractedPlanIfPresent, buildConfirmedPools, createWorktree, removeWorktree, resetNodeWorktreeAndBranch, acceptNodeWorktree, recordNodeAcceptOutcome, ensureWorktreeNodeModules, worktreePath, worktreeBranchForBlock, } from "./dispatch.js";
|
|
12
|
+
import { makeProviderNodeDispatcher } from "./providerNodeDispatch.js";
|
|
13
|
+
import { prepareHostRollingDispatch } from "./rollingSession.js";
|
|
14
|
+
import { writeCurrentStep } from "./stepWriter.js";
|
|
15
|
+
import { dependencyVerifiedComplete } from "./stepUtils.js";
|
|
16
|
+
import { isTerminalStatus, isVerifiedCompleteStatus, isSkipStatus, } from "../state/itemStatus.js";
|
|
17
|
+
import { deduplicateCrossLensFindings, fixupBlocksAfterDedup, } from "../dedup/crossLensDedup.js";
|
|
18
|
+
import { checkAffectedFileIntegrity } from "../utils/fileIntegrity.js";
|
|
19
|
+
import { resolveIntakeStep } from "./intakeResolver.js";
|
|
20
|
+
import { runCommand } from "../utils/commands.js";
|
|
21
|
+
import { buildNextContractPipelineStep, shouldEnterContractPipeline, writePathASeedFromFindings, } from "./contractPipeline.js";
|
|
22
|
+
import { evaluateFastPath, buildLeanExtractedPlan, } from "./leanFastPath.js";
|
|
23
|
+
import { contractArtifactExists, contractPipelineDir, } from "../contractPipeline/artifactStore.js";
|
|
24
|
+
import { buildReviewRequest, applyReviewResolution, } from "../review/reviewGate.js";
|
|
25
|
+
import { runFindingFilterPass } from "../findingFilter.js";
|
|
26
|
+
import { intakePaths, isIntakeReady, readIntakeArtifacts, resolveManifestSources, } from "../intake.js";
|
|
27
|
+
import { clarificationPrompt, collectIntakeClarificationsPrompt, collectStartingPointPrompt, loaderCommand, reviewApprovalPrompt, synthesizeIntakePrompt, triagePrompt, } from "./prompts.js";
|
|
28
|
+
export function resolveHostDispatchCapability(options) {
|
|
29
|
+
if (options.hostCanDispatchSubagents !== undefined) {
|
|
30
|
+
return options.hostCanDispatchSubagents;
|
|
31
|
+
}
|
|
32
|
+
if (options.sessionConfig?.host_can_dispatch_subagents !== undefined) {
|
|
33
|
+
return options.sessionConfig.host_can_dispatch_subagents;
|
|
34
|
+
}
|
|
35
|
+
const envValue = (options.env ?? process.env).REMEDIATE_HOST_CAN_DISPATCH;
|
|
36
|
+
if (envValue === "true")
|
|
37
|
+
return true;
|
|
38
|
+
if (envValue === "false")
|
|
39
|
+
return false;
|
|
40
|
+
// Conversation-first default: an interactive agent host (e.g. Claude Code) can
|
|
41
|
+
// dispatch callable subagents, so default to parallel wave dispatch. A host that
|
|
42
|
+
// genuinely cannot dispatch opts out via host_can_dispatch_subagents:false,
|
|
43
|
+
// REMEDIATE_HOST_CAN_DISPATCH=false, or --host-can-dispatch-subagents=false.
|
|
44
|
+
return true;
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* Whether the rolling dispatch engine drives the implement phase. Defaults to TRUE:
|
|
48
|
+
* both rolling drivers on the shared `acceptNodeWorktree` core (per-node worktree →
|
|
49
|
+
* tool-owned commit → verify → cherry-pick merge; verify-fail → triage) are now
|
|
50
|
+
* validated end-to-end — the host-subagent driver via a real-subagent smoke
|
|
51
|
+
* (f18138fe) and the in-process provider driver via a live-NIM run THROUGH
|
|
52
|
+
* decideNextStep (2026-06-17, tests/nim-rolling-e2e.test.ts). The legacy host-fanned
|
|
53
|
+
* wave (`dispatch_implement`) is retained as an explicit opt-OUT (rolling_engine:false
|
|
54
|
+
* / REMEDIATE_ROLLING_ENGINE=false), not deleted. Resolution order: explicit option →
|
|
55
|
+
* sessionConfig.dispatch.rolling_engine → REMEDIATE_ROLLING_ENGINE env → true.
|
|
56
|
+
*/
|
|
57
|
+
export function resolveRollingEngineEnabled(options) {
|
|
58
|
+
if (options.rollingEngine !== undefined)
|
|
59
|
+
return options.rollingEngine;
|
|
60
|
+
const cfg = options.sessionConfig?.dispatch?.rolling_engine;
|
|
61
|
+
if (cfg !== undefined)
|
|
62
|
+
return cfg;
|
|
63
|
+
const envValue = (options.env ?? process.env).REMEDIATE_ROLLING_ENGINE;
|
|
64
|
+
if (envValue === "true")
|
|
65
|
+
return true;
|
|
66
|
+
if (envValue === "false")
|
|
67
|
+
return false;
|
|
68
|
+
return true;
|
|
69
|
+
}
|
|
70
|
+
function randomRunId(prefix = "RUN") {
|
|
71
|
+
return `${prefix}-${Date.now().toString(36)}-${Math.random().toString(36).slice(2, 8)}`;
|
|
72
|
+
}
|
|
73
|
+
/**
|
|
74
|
+
* Host-facing note interposing a shared rebuild between rolling dependency
|
|
75
|
+
* levels. The tool admits a downstream node only once its upstream node is
|
|
76
|
+
* verified-complete; once that upstream edit lands, the host must rebuild the
|
|
77
|
+
* shared surface before the next next-step pass so the downstream node
|
|
78
|
+
* typechecks/runs against the realized output rather than stale `dist/`. The
|
|
79
|
+
* rebuild is build-FREE single-flight at the package level — one central build,
|
|
80
|
+
* never a per-node `npm run build` racing it (CE-001).
|
|
81
|
+
*/
|
|
82
|
+
const SHARED_REBUILD_BETWEEN_LEVELS_NOTE = `## Shared rebuild between dependency levels
|
|
83
|
+
|
|
84
|
+
These nodes were selected because their dependencies are verified-complete. When a
|
|
85
|
+
node you just merged edited a shared/upstream surface a later node depends on,
|
|
86
|
+
rebuild that surface ONCE — \`npm run build\`
|
|
87
|
+
— before the next \`next-step\` dispatches the now-eligible downstream nodes, so they
|
|
88
|
+
build against the realized upstream output. Do not run a per-node \`npm run build\`;
|
|
89
|
+
the central rebuild is single-flight (one build, never one-per-node racing \`dist/\`).`;
|
|
90
|
+
function resolveRoot(root) {
|
|
91
|
+
return resolve(root ?? ".");
|
|
92
|
+
}
|
|
93
|
+
function resolveArtifactsDir(root, artifactsDir) {
|
|
94
|
+
return resolve(artifactsDir ?? join(root, ".audit-tools", "remediation"));
|
|
95
|
+
}
|
|
96
|
+
function stateRunId(state) {
|
|
97
|
+
return state?.plan?.plan_id ?? randomRunId("REMEDIATE");
|
|
98
|
+
}
|
|
99
|
+
function defaultInputCandidates(root) {
|
|
100
|
+
// Prefer the canonical machine contract (audit-findings.json) over its
|
|
101
|
+
// human-facing render (audit-report.md). The JSON is the source of truth on
|
|
102
|
+
// both sides of the audit -> remediate pipeline, and feeding it triggers the
|
|
103
|
+
// lossless structured hand-off in the plan phase instead of a lossy LLM
|
|
104
|
+
// re-extraction from the markdown render that sits beside it.
|
|
105
|
+
return [
|
|
106
|
+
join(root, ".audit-tools", "audit-findings.json"),
|
|
107
|
+
join(root, ".audit-tools", "audit", "audit-findings.json"),
|
|
108
|
+
join(root, "audit-findings.json"),
|
|
109
|
+
join(root, ".audit-tools", "audit-report.md"),
|
|
110
|
+
join(root, ".audit-tools", "audit", "audit-report.md"),
|
|
111
|
+
join(root, "audit-report.md"),
|
|
112
|
+
];
|
|
113
|
+
}
|
|
114
|
+
function inputValues(input) {
|
|
115
|
+
if (input === undefined)
|
|
116
|
+
return [];
|
|
117
|
+
return Array.isArray(input) ? input : [input];
|
|
118
|
+
}
|
|
119
|
+
function resolveInputPaths(root, input) {
|
|
120
|
+
const values = inputValues(input).filter((value) => value.trim().length > 0);
|
|
121
|
+
if (values.length > 0) {
|
|
122
|
+
const checked = values.map((value) => resolve(root, value));
|
|
123
|
+
return {
|
|
124
|
+
supplied: true,
|
|
125
|
+
existing: checked.filter((candidate) => existsSync(candidate)),
|
|
126
|
+
missing: checked.filter((candidate) => !existsSync(candidate)),
|
|
127
|
+
checked,
|
|
128
|
+
};
|
|
129
|
+
}
|
|
130
|
+
const checked = defaultInputCandidates(root);
|
|
131
|
+
// Default discovery probes the same logical artifact (the audit output) in
|
|
132
|
+
// several canonical locations and two formats. Select the single
|
|
133
|
+
// highest-priority match — never feed both the structured contract and its
|
|
134
|
+
// markdown render — so a lone .json input takes the lossless structured
|
|
135
|
+
// fast-path instead of being demoted to multi-source LLM extraction.
|
|
136
|
+
const best = checked.find((candidate) => existsSync(candidate));
|
|
137
|
+
return {
|
|
138
|
+
supplied: false,
|
|
139
|
+
existing: best ? [best] : [],
|
|
140
|
+
missing: [],
|
|
141
|
+
checked,
|
|
142
|
+
};
|
|
143
|
+
}
|
|
144
|
+
export { NO_CHANGE_RE, dependenciesSatisfied, dependencyVerifiedComplete, specIndicatesNoChange, classifyFindingRisk, } from "./stepUtils.js";
|
|
145
|
+
export { isTerminalStatus, isVerifiedCompleteStatus };
|
|
146
|
+
function documentableFindings(state) {
|
|
147
|
+
if (!state.plan || !state.items)
|
|
148
|
+
return [];
|
|
149
|
+
return state.plan.findings.filter((finding) => state.items?.[finding.id]?.status === "pending");
|
|
150
|
+
}
|
|
151
|
+
/**
|
|
152
|
+
* Blocks/nodes eligible for the next rolling dispatch pass: those with pending
|
|
153
|
+
* work AND every dependency VERIFIED-COMPLETE (INV-RS-01 — a SKIP or blocked
|
|
154
|
+
* dependency never makes a dependent eligible). This is the rolling-scheduler
|
|
155
|
+
* eligibility gate; it replaced the old `dependenciesSatisfied` (any-terminal)
|
|
156
|
+
* wave gate so a node whose prerequisite was skipped/blocked is held back rather
|
|
157
|
+
* than dispatched against a surface that never landed.
|
|
158
|
+
*/
|
|
159
|
+
function implementableBlocks(state) {
|
|
160
|
+
if (!state.plan || !state.items)
|
|
161
|
+
return [];
|
|
162
|
+
return state.plan.blocks.filter((block) => dependencyVerifiedComplete(block, state) &&
|
|
163
|
+
block.items.some((findingId) => {
|
|
164
|
+
const item = state.items?.[findingId];
|
|
165
|
+
return item?.status === "pending";
|
|
166
|
+
}));
|
|
167
|
+
}
|
|
168
|
+
/**
|
|
169
|
+
* Pending nodes that are NOT eligible because at least one dependency did not
|
|
170
|
+
* reach a verified-complete disposition (a prerequisite was skipped, blocked, or
|
|
171
|
+
* is still pending). Once no eligible block remains, these are dead-ended: the
|
|
172
|
+
* rolling scheduler marks them `blocked` (their upstream surface never landed)
|
|
173
|
+
* rather than looping forever. Used by `handlePlanning` to make that transition
|
|
174
|
+
* deterministic.
|
|
175
|
+
*/
|
|
176
|
+
function blockedByUnsatisfiedDependency(state) {
|
|
177
|
+
if (!state.plan || !state.items)
|
|
178
|
+
return [];
|
|
179
|
+
return state.plan.blocks.filter((block) => !dependencyVerifiedComplete(block, state) &&
|
|
180
|
+
block.items.some((findingId) => state.items?.[findingId]?.status === "pending"));
|
|
181
|
+
}
|
|
182
|
+
// ---------------------------------------------------------------------------
|
|
183
|
+
// Rolling per-node scheduler (CP-BLOCK-N-rolling-scheduler)
|
|
184
|
+
// ---------------------------------------------------------------------------
|
|
185
|
+
//
|
|
186
|
+
// The rolling scheduler replaced the wave-batch shim: instead of dispatching one
|
|
187
|
+
// fixed-size wave per next-step and folding back through `implementing`, a node
|
|
188
|
+
// becomes eligible the instant every dependency reaches a verified-complete
|
|
189
|
+
// disposition (INV-RS-01). Concurrency is owned entirely by the quota scheduler
|
|
190
|
+
// (the `dispatch-quota.json` max_concurrent_agents from `scheduleWave` /
|
|
191
|
+
// `computeDispatchCapacity` — INV-S05 / INV-QD-11), never a separate wave cap.
|
|
192
|
+
// A shared rebuild is interposed between dependency levels so a downstream node
|
|
193
|
+
// typechecks/runs against the freshly-built upstream `audit-tools/shared`
|
|
194
|
+
// surface; the rebuild is single-flight (CE-001) so the same package is never
|
|
195
|
+
// built twice or concurrently within one dispatch run.
|
|
196
|
+
/**
|
|
197
|
+
* Partition pending nodes into rolling dependency LEVELS. Level 0 is every
|
|
198
|
+
* pending node already eligible (deps verified-complete now); each subsequent
|
|
199
|
+
* level is the pending nodes that become eligible once all earlier levels are
|
|
200
|
+
* assumed verified-complete. The boundary between two levels is exactly where a
|
|
201
|
+
* shared rebuild is interposed (so a later level builds against the realized
|
|
202
|
+
* upstream surface). A node with a permanently-unsatisfiable edge (its
|
|
203
|
+
* prerequisite is skipped/blocked, not merely pending) is NOT placed in any
|
|
204
|
+
* level — it is dead-ended by `handlePlanning`.
|
|
205
|
+
*
|
|
206
|
+
* Pure and deterministic: levels and the nodes within a level are ordered by
|
|
207
|
+
* block_id so the interposed-rebuild boundaries are stable across runs.
|
|
208
|
+
*/
|
|
209
|
+
export function rollingDependencyLevels(state) {
|
|
210
|
+
const plan = state.plan;
|
|
211
|
+
const items = state.items;
|
|
212
|
+
if (!plan || !items)
|
|
213
|
+
return [];
|
|
214
|
+
const blockById = new Map(plan.blocks.map((b) => [b.block_id, b]));
|
|
215
|
+
const pendingBlocks = plan.blocks
|
|
216
|
+
.filter((b) => b.items.some((id) => items[id]?.status === "pending"))
|
|
217
|
+
.sort((a, b) => a.block_id.localeCompare(b.block_id));
|
|
218
|
+
// A dependency edge is "completable" only when the dep node is itself pending
|
|
219
|
+
// (will be satisfied by some level) or already verified-complete. A skipped /
|
|
220
|
+
// blocked dependency makes the dependent permanently ineligible — such nodes
|
|
221
|
+
// never enter a level (INV-RS-01).
|
|
222
|
+
const isVerifiedNow = (depBlock) => depBlock.items.every((id) => isVerifiedCompleteStatus(items[id]?.status));
|
|
223
|
+
const isPending = (depBlock) => depBlock.items.some((id) => items[id]?.status === "pending");
|
|
224
|
+
const permanentlyIneligible = (block) => {
|
|
225
|
+
for (const depId of block.dependencies ?? []) {
|
|
226
|
+
const dep = blockById.get(depId);
|
|
227
|
+
if (!dep)
|
|
228
|
+
continue; // dangling edge never strands the DAG
|
|
229
|
+
if (!isVerifiedNow(dep) && !isPending(dep))
|
|
230
|
+
return true; // skipped/blocked dep
|
|
231
|
+
}
|
|
232
|
+
return false;
|
|
233
|
+
};
|
|
234
|
+
const levels = [];
|
|
235
|
+
const placed = new Set();
|
|
236
|
+
let remaining = pendingBlocks.filter((b) => !permanentlyIneligible(b));
|
|
237
|
+
while (remaining.length > 0) {
|
|
238
|
+
const ready = remaining.filter((block) => (block.dependencies ?? []).every((depId) => {
|
|
239
|
+
const dep = blockById.get(depId);
|
|
240
|
+
if (!dep)
|
|
241
|
+
return true; // dangling edge
|
|
242
|
+
// Satisfied if already verified-complete, or every pending item of the
|
|
243
|
+
// dep was placed in an earlier level (so it will be verified by then).
|
|
244
|
+
if (isVerifiedNow(dep))
|
|
245
|
+
return true;
|
|
246
|
+
return dep.items.every((id) => isVerifiedCompleteStatus(items[id]?.status) ||
|
|
247
|
+
(items[id]?.status === "pending" && placed.has(dep.block_id)));
|
|
248
|
+
}));
|
|
249
|
+
if (ready.length === 0) {
|
|
250
|
+
// A cycle among the remaining pending nodes: no further level can form.
|
|
251
|
+
// Leave them unplaced — `handlePlanning` marks them blocked deterministically.
|
|
252
|
+
break;
|
|
253
|
+
}
|
|
254
|
+
levels.push(ready);
|
|
255
|
+
for (const block of ready)
|
|
256
|
+
placed.add(block.block_id);
|
|
257
|
+
remaining = remaining.filter((b) => !placed.has(b.block_id));
|
|
258
|
+
}
|
|
259
|
+
return levels;
|
|
260
|
+
}
|
|
261
|
+
/**
|
|
262
|
+
* Drive a rolling per-node dispatch run IN PROCESS over the precomputed
|
|
263
|
+
* dependency levels, wiring onto the shared `createRollingDispatcher`
|
|
264
|
+
* (quota-only throttle; transient-429 re-queue + empty-pool stranding owned by
|
|
265
|
+
* the shared engine). The driver's own responsibilities are the two properties
|
|
266
|
+
* the shared engine does not own:
|
|
267
|
+
* 1. SHARED-REBUILD-BETWEEN-LEVELS — after a level completes, rebuild the
|
|
268
|
+
* upstream surface before the next level dispatches, so dependents
|
|
269
|
+
* typecheck/run against the realized upstream output.
|
|
270
|
+
* 2. SINGLE-FLIGHT BUILD (CE-001) — the rebuild runs exactly once per
|
|
271
|
+
* inter-level boundary, never twice or concurrently.
|
|
272
|
+
*
|
|
273
|
+
* Within a level, concurrency is whatever the shared engine's quota headroom
|
|
274
|
+
* allows over `confirmedPools` — there is no wave-size cap (INV-S05).
|
|
275
|
+
*/
|
|
276
|
+
export async function driveRollingDispatch(levels, options) {
|
|
277
|
+
if (options.quotaStateDir) {
|
|
278
|
+
setQuotaStateDir(options.quotaStateDir);
|
|
279
|
+
}
|
|
280
|
+
const estimateTokens = options.estimateTokens ?? (() => 2000);
|
|
281
|
+
const out = { levels: [], rebuilds: 0 };
|
|
282
|
+
let rebuildInFlight = false; // single-flight guard (CE-001)
|
|
283
|
+
for (let levelIndex = 0; levelIndex < levels.length; levelIndex++) {
|
|
284
|
+
const level = levels[levelIndex];
|
|
285
|
+
// Interpose the shared rebuild BEFORE every level after the first. Guarded so
|
|
286
|
+
// it can never run twice or concurrently for the same boundary.
|
|
287
|
+
if (levelIndex > 0) {
|
|
288
|
+
if (rebuildInFlight) {
|
|
289
|
+
throw new Error("driveRollingDispatch: shared rebuild already in flight — single-flight invariant violated (CE-001).");
|
|
290
|
+
}
|
|
291
|
+
rebuildInFlight = true;
|
|
292
|
+
try {
|
|
293
|
+
await options.rebuildSharedBetweenLevels();
|
|
294
|
+
out.rebuilds += 1;
|
|
295
|
+
}
|
|
296
|
+
finally {
|
|
297
|
+
rebuildInFlight = false;
|
|
298
|
+
}
|
|
299
|
+
}
|
|
300
|
+
const blockByPacketId = new Map(level.map((b) => [b.block_id, b]));
|
|
301
|
+
const packets = level.map((block) => ({
|
|
302
|
+
id: block.block_id,
|
|
303
|
+
payload: { block_id: block.block_id },
|
|
304
|
+
estimatedTokens: estimateTokens(block),
|
|
305
|
+
complexity: 0.5,
|
|
306
|
+
}));
|
|
307
|
+
const dispatcher = createRollingDispatcher({
|
|
308
|
+
confirmedPools: options.confirmedPools,
|
|
309
|
+
sessionConfig: options.sessionConfig,
|
|
310
|
+
dispatchPacket: async (packet, slot) => {
|
|
311
|
+
const block = blockByPacketId.get(packet.payload.block_id);
|
|
312
|
+
return options.dispatchNode(block, slot);
|
|
313
|
+
},
|
|
314
|
+
});
|
|
315
|
+
dispatcher.enqueue(packets);
|
|
316
|
+
const results = await dispatcher.run();
|
|
317
|
+
out.levels.push({ blockIds: level.map((b) => b.block_id), results });
|
|
318
|
+
}
|
|
319
|
+
return out;
|
|
320
|
+
}
|
|
321
|
+
/**
|
|
322
|
+
* Backends the orchestrator can drive IN-PROCESS as the per-node implement worker
|
|
323
|
+
* via `driveRollingImplementDispatch` (it resolves + launches the provider with each
|
|
324
|
+
* node's worktree-rooted prompt, cwd-confined to that worktree). The conversation
|
|
325
|
+
* host (claude-code) and IDE-bound providers (vscode-task / antigravity) are
|
|
326
|
+
* excluded: claude-code self-blocks inside a session, and the IDE providers have no
|
|
327
|
+
* headless invocation. "auto" is intentionally absent — auto-resolution stays on the
|
|
328
|
+
* conversation host-subagent default, so the in-process driver is opt-in via an
|
|
329
|
+
* EXPLICIT backend provider in session config. When one is set, it takes precedence
|
|
330
|
+
* over the host-subagent driver: an operator who configured a backend (e.g. a NIM
|
|
331
|
+
* pool for headless autonomy) wants it to do the implement work, not the host.
|
|
332
|
+
*/
|
|
333
|
+
const IN_PROCESS_DISPATCH_PROVIDERS = new Set([
|
|
334
|
+
"openai-compatible",
|
|
335
|
+
"codex",
|
|
336
|
+
"opencode",
|
|
337
|
+
"subprocess-template",
|
|
338
|
+
"local-subprocess",
|
|
339
|
+
]);
|
|
340
|
+
function resolvesToInProcessDispatchProvider(sessionConfig) {
|
|
341
|
+
const provider = sessionConfig?.provider;
|
|
342
|
+
return provider !== undefined && IN_PROCESS_DISPATCH_PROVIDERS.has(provider);
|
|
343
|
+
}
|
|
344
|
+
/**
|
|
345
|
+
* Drive the implement phase through the in-process rolling engine. Engages the
|
|
346
|
+
* shared `createRollingDispatcher` (via `driveRollingDispatch`) over
|
|
347
|
+
* quota-derived `confirmedPools`, runs each node in an isolated worktree, gates
|
|
348
|
+
* acceptance on a per-node verify, and finally merges through the deterministic
|
|
349
|
+
* `mergeImplementResults`. Returns null when there is no eligible pending work.
|
|
350
|
+
*
|
|
351
|
+
* SAFETY: this never touches the main tree except through `mergeWorktree` (which
|
|
352
|
+
* cherry-picks a verified branch and aborts cleanly on conflict). A node whose
|
|
353
|
+
* verify fails is NOT merged; its worktree is removed and the deterministic merge
|
|
354
|
+
* marks it blocked (its result file is absent / unaccounted) so the run routes it
|
|
355
|
+
* to triage rather than landing an unverified change.
|
|
356
|
+
*/
|
|
357
|
+
export async function driveRollingImplementDispatch(options) {
|
|
358
|
+
const { root, artifactsDir, runId } = options;
|
|
359
|
+
// Prepare the dispatch plan (eligible verified-complete frontier) with the SAME
|
|
360
|
+
// quota-derived sizing the wave path uses. This writes per-node prompts +
|
|
361
|
+
// dispatch-plan.json + dispatch-quota.json.
|
|
362
|
+
const plan = await prepareImplementDispatch({ root, artifactsDir }, runId, undefined, {
|
|
363
|
+
hostMaxConcurrent: options.waveOptions?.hostMaxConcurrent,
|
|
364
|
+
sessionConfig: options.sessionConfig,
|
|
365
|
+
hostContextTokens: options.waveOptions?.hostContextTokens,
|
|
366
|
+
hostOutputTokens: options.waveOptions?.hostOutputTokens,
|
|
367
|
+
hostModels: options.waveOptions?.hostModels,
|
|
368
|
+
hostModelId: options.waveOptions?.hostModelId,
|
|
369
|
+
// Each node runs in its own worktree, so its prompt is rooted there.
|
|
370
|
+
worktreeRootedPrompts: true,
|
|
371
|
+
});
|
|
372
|
+
if (plan.items.length === 0) {
|
|
373
|
+
return null;
|
|
374
|
+
}
|
|
375
|
+
// Map each planned block id to its result path so the per-node dispatcher
|
|
376
|
+
// writes where the merge expects to read.
|
|
377
|
+
const resultPathByBlock = new Map(plan.items
|
|
378
|
+
.filter((i) => typeof i.block_id === "string")
|
|
379
|
+
.map((i) => [i.block_id, i.result_path]));
|
|
380
|
+
// Map each planned block id to its worktree-rooted prompt path so the
|
|
381
|
+
// provider-backed dispatcher launches the worker with the right prompt.
|
|
382
|
+
const promptPathByBlock = new Map(plan.items
|
|
383
|
+
.filter((i) => typeof i.block_id === "string")
|
|
384
|
+
.map((i) => [i.block_id, i.prompt_path]));
|
|
385
|
+
// The live per-node worker: the configured provider, launched with the node's
|
|
386
|
+
// worktree-rooted prompt and cwd = its worktree. Tests inject `options.dispatchNode`
|
|
387
|
+
// to exercise the engine without spawning a real worker.
|
|
388
|
+
const dispatchNode = options.dispatchNode ??
|
|
389
|
+
makeProviderNodeDispatcher({
|
|
390
|
+
root,
|
|
391
|
+
artifactsDir,
|
|
392
|
+
runId,
|
|
393
|
+
sessionConfig: options.sessionConfig,
|
|
394
|
+
promptPathByBlock,
|
|
395
|
+
});
|
|
396
|
+
// Confirmed pools: quota-derived concurrency, never the raw host flag (INV-QD-11).
|
|
397
|
+
const confirmedPools = await buildConfirmedPools({
|
|
398
|
+
sessionConfig: options.sessionConfig,
|
|
399
|
+
hostMaxConcurrent: options.waveOptions?.hostMaxConcurrent,
|
|
400
|
+
hostContextTokens: options.waveOptions?.hostContextTokens,
|
|
401
|
+
hostOutputTokens: options.waveOptions?.hostOutputTokens,
|
|
402
|
+
hostModels: options.waveOptions?.hostModels,
|
|
403
|
+
hostModelId: options.waveOptions?.hostModelId,
|
|
404
|
+
});
|
|
405
|
+
// Load state to partition the eligible frontier into rolling dependency levels.
|
|
406
|
+
const state = await new StateStore(artifactsDir).loadState();
|
|
407
|
+
if (!state)
|
|
408
|
+
return null;
|
|
409
|
+
const plannedBlockIds = new Set(resultPathByBlock.keys());
|
|
410
|
+
const allLevels = rollingDependencyLevels(state);
|
|
411
|
+
// Keep only the blocks that were actually planned this dispatch (eligible now).
|
|
412
|
+
const levels = allLevels
|
|
413
|
+
.map((level) => level.filter((b) => plannedBlockIds.has(b.block_id)))
|
|
414
|
+
.filter((level) => level.length > 0);
|
|
415
|
+
const nodeOutcomes = [];
|
|
416
|
+
// Per-node worktree dispatch + verify-before-accept, wrapped so the rolling
|
|
417
|
+
// engine's dispatchNode callback always RESOLVES (never rejects).
|
|
418
|
+
const dispatchNodeWithWorktree = async (block, slot) => {
|
|
419
|
+
const branch = worktreeBranchForBlock(block.block_id, runId);
|
|
420
|
+
const wt = worktreePath(root, block.block_id, runId);
|
|
421
|
+
const resultPath = resultPathByBlock.get(block.block_id);
|
|
422
|
+
try {
|
|
423
|
+
// Idempotent reset of any worktree dir AND leftover branch from a prior
|
|
424
|
+
// attempt before creating this node's isolated worktree. A `rate_limited`
|
|
425
|
+
// re-queue re-enters this dispatcher for the same block with the branch
|
|
426
|
+
// still present; a bare `createWorktree -b` would then fail with "branch
|
|
427
|
+
// already exists". `resetNodeWorktreeAndBranch` clears both (+ prunes stale
|
|
428
|
+
// admin entries) so every (re-)dispatch starts clean from HEAD.
|
|
429
|
+
resetNodeWorktreeAndBranch(root, wt, branch);
|
|
430
|
+
createWorktree(root, wt, branch);
|
|
431
|
+
// A fresh worktree has no node_modules (gitignored); link the main checkout's
|
|
432
|
+
// so this node's verify commands can run.
|
|
433
|
+
ensureWorktreeNodeModules(root, wt);
|
|
434
|
+
const result = await dispatchNode({
|
|
435
|
+
block,
|
|
436
|
+
slot,
|
|
437
|
+
worktreeRoot: wt,
|
|
438
|
+
resultPath,
|
|
439
|
+
});
|
|
440
|
+
// Shared post-worker lifecycle (commit → verify → merge), identical to the
|
|
441
|
+
// host-subagent driver's `accept-node` callback. Records the LIFECYCLE
|
|
442
|
+
// outcome but returns the worker's TRANSPORT result to the engine (so a
|
|
443
|
+
// rate_limited worker re-queues; a verify-failure routes to triage via merge).
|
|
444
|
+
const targeted = uniqueStrings(block.items.flatMap((id) => {
|
|
445
|
+
const finding = state.plan?.findings.find((f) => f.id === id);
|
|
446
|
+
return finding?.targeted_commands ?? [];
|
|
447
|
+
}));
|
|
448
|
+
const accept = acceptNodeWorktree({
|
|
449
|
+
root,
|
|
450
|
+
runId,
|
|
451
|
+
blockId: block.block_id,
|
|
452
|
+
worktreeRoot: wt,
|
|
453
|
+
branch,
|
|
454
|
+
workerOutcome: result.outcome,
|
|
455
|
+
targetedCommands: targeted,
|
|
456
|
+
});
|
|
457
|
+
// Persist the tool-owned verify/merge outcome so finalization blocks a node
|
|
458
|
+
// that self-reported resolved but never actually landed (OBL-DS-06). Parity
|
|
459
|
+
// with the host-subagent driver's `accept-node` callback.
|
|
460
|
+
await recordNodeAcceptOutcome(artifactsDir, runId, block.block_id, accept);
|
|
461
|
+
nodeOutcomes.push({
|
|
462
|
+
block_id: block.block_id,
|
|
463
|
+
outcome: accept.outcome,
|
|
464
|
+
verify_passed: accept.verifyPassed,
|
|
465
|
+
merged: accept.merged,
|
|
466
|
+
});
|
|
467
|
+
return result;
|
|
468
|
+
}
|
|
469
|
+
catch (err) {
|
|
470
|
+
removeWorktree(root, wt);
|
|
471
|
+
await recordNodeAcceptOutcome(artifactsDir, runId, block.block_id, {
|
|
472
|
+
outcome: "error",
|
|
473
|
+
verifyPassed: false,
|
|
474
|
+
merged: false,
|
|
475
|
+
});
|
|
476
|
+
nodeOutcomes.push({ block_id: block.block_id, outcome: "error", verify_passed: false, merged: false });
|
|
477
|
+
return {
|
|
478
|
+
packet: { id: block.block_id, payload: { block_id: block.block_id }, estimatedTokens: 0, complexity: 0.5 },
|
|
479
|
+
outcome: "error",
|
|
480
|
+
error: err,
|
|
481
|
+
};
|
|
482
|
+
}
|
|
483
|
+
};
|
|
484
|
+
await driveRollingDispatch(levels, {
|
|
485
|
+
confirmedPools,
|
|
486
|
+
sessionConfig: options.sessionConfig ?? {},
|
|
487
|
+
dispatchNode: dispatchNodeWithWorktree,
|
|
488
|
+
rebuildSharedBetweenLevels: options.rebuildSharedBetweenLevels,
|
|
489
|
+
quotaStateDir: artifactsDir,
|
|
490
|
+
});
|
|
491
|
+
// Deterministic merge: same path the wave flow uses (tolerant remap, write-scope
|
|
492
|
+
// gate against each verified branch, lost-update detection). Worktrees are
|
|
493
|
+
// already removed; the merge reads each node's result file + branch diff.
|
|
494
|
+
const merged = await mergeImplementResults({ root, artifactsDir }, runId);
|
|
495
|
+
return {
|
|
496
|
+
nodes: nodeOutcomes,
|
|
497
|
+
rebuilds: Math.max(0, levels.length - 1),
|
|
498
|
+
state_status: merged.status,
|
|
499
|
+
};
|
|
500
|
+
}
|
|
501
|
+
/** Dedupe a string list preserving order (local helper for verify command sets). */
|
|
502
|
+
function uniqueStrings(values) {
|
|
503
|
+
return [...new Set(values.filter((v) => typeof v === "string" && v.length > 0))];
|
|
504
|
+
}
|
|
505
|
+
/**
|
|
506
|
+
* Whether `root` is the audit-tools monorepo — the repo the tool-owned final
|
|
507
|
+
* gate's suite (INV-RS-10, literally the audit-tools build/check/per-package
|
|
508
|
+
* commands) applies to. The gate's command list is audit-tools-specific by
|
|
509
|
+
* design (this remediation run remediates the audit-tools monorepo), so it is
|
|
510
|
+
* scoped to that structure rather than fabricated for an arbitrary target repo.
|
|
511
|
+
*/
|
|
512
|
+
export function isAuditToolsMonorepo(root) {
|
|
513
|
+
// Single-package layout: the three subsystems are inlined under src/ and both
|
|
514
|
+
// bins live at the repo root. (Name kept for continuity; it is now one package.)
|
|
515
|
+
return (existsSync(join(root, "src", "shared")) &&
|
|
516
|
+
existsSync(join(root, "src", "audit")) &&
|
|
517
|
+
existsSync(join(root, "src", "remediate")) &&
|
|
518
|
+
existsSync(join(root, "audit-code.mjs")) &&
|
|
519
|
+
existsSync(join(root, "remediate-code.mjs")));
|
|
520
|
+
}
|
|
521
|
+
/**
|
|
522
|
+
* The tool-owned final-gate command list (INV-RS-10) for the audit-tools
|
|
523
|
+
* monorepo. Pure and deterministic so tests can assert: it is non-vacuous
|
|
524
|
+
* (always > 0 build + check + unit commands) for the audit-tools structure,
|
|
525
|
+
* never references `plan.test_command`, every UNIT command is build-free, and no
|
|
526
|
+
* package's unit suite appears twice (single-flight — CE-001). Returns `[]` when
|
|
527
|
+
* `root` is not the audit-tools monorepo (the audit-tools-specific suite is
|
|
528
|
+
* inapplicable there — see `runToolOwnedFinalGate`).
|
|
529
|
+
*/
|
|
530
|
+
export function toolOwnedFinalGateCommands(root) {
|
|
531
|
+
if (!isAuditToolsMonorepo(root))
|
|
532
|
+
return [];
|
|
533
|
+
return [
|
|
534
|
+
{ argv: ["npm", "run", "build"], build_free: false, layer: "build" },
|
|
535
|
+
{ argv: ["npm", "run", "check"], build_free: true, layer: "check" },
|
|
536
|
+
// BUILD-FREE unit suites at the repo root (single package — no `npm -w`, never
|
|
537
|
+
// `npm test`, which prepends a build). node:test for shared+audit, vitest for remediate.
|
|
538
|
+
{
|
|
539
|
+
argv: ["node", "--import", "tsx/esm", "--test", "tests/shared/*.test.mjs", "tests/audit/*.test.mjs"],
|
|
540
|
+
build_free: true,
|
|
541
|
+
layer: "unit",
|
|
542
|
+
},
|
|
543
|
+
{
|
|
544
|
+
argv: ["npx", "vitest", "run"],
|
|
545
|
+
build_free: true,
|
|
546
|
+
layer: "unit",
|
|
547
|
+
},
|
|
548
|
+
];
|
|
549
|
+
}
|
|
550
|
+
/**
|
|
551
|
+
* Run the tool-owned final gate (INV-RS-10). Each command runs through
|
|
552
|
+
* `runCommand` → shared `runTracked`, which scrubs CLAUDECODE / CLAUDE_CODE_*.
|
|
553
|
+
* The first failing command short-circuits the floor (a broken build makes the
|
|
554
|
+
* later layers meaningless). A `runner` may be injected for tests. When the
|
|
555
|
+
* audit-tools suite does not apply (non-monorepo target), the gate is
|
|
556
|
+
* `scoped_out` (does not block) rather than vacuously passing.
|
|
557
|
+
*/
|
|
558
|
+
export async function runToolOwnedFinalGate(root, opts = {}) {
|
|
559
|
+
const runtime_residual = {
|
|
560
|
+
surface: "runtime/packaged-bin smokes (verify:release)",
|
|
561
|
+
commands: [
|
|
562
|
+
"npm run smoke:packaged-audit-code",
|
|
563
|
+
"npm run smoke:packaged-remediate-code",
|
|
564
|
+
],
|
|
565
|
+
};
|
|
566
|
+
const commands = toolOwnedFinalGateCommands(root);
|
|
567
|
+
if (commands.length === 0) {
|
|
568
|
+
// Audit-tools-specific suite does not apply here — declared scope, not a
|
|
569
|
+
// vacuous pass (it never substitutes for a real gate on the audit-tools repo).
|
|
570
|
+
return { passed: true, results: [], scoped_out: true, runtime_residual };
|
|
571
|
+
}
|
|
572
|
+
const runner = opts.runner ??
|
|
573
|
+
((argv, cwd, packageDir) => {
|
|
574
|
+
const [command, ...args] = argv;
|
|
575
|
+
// Package-scoped unit suites run with cwd at the package (no `npm -w`); the
|
|
576
|
+
// monorepo-root build/check commands run at the repo root.
|
|
577
|
+
const effectiveCwd = packageDir ? join(root, packageDir) : cwd;
|
|
578
|
+
// runCommand → runTracked strips CLAUDECODE / CLAUDE_CODE_* (INV-RS-10).
|
|
579
|
+
const result = runCommand(command, args, {
|
|
580
|
+
cwd: effectiveCwd,
|
|
581
|
+
stdio: ["ignore", "pipe", "pipe"],
|
|
582
|
+
});
|
|
583
|
+
return { status: result.status };
|
|
584
|
+
});
|
|
585
|
+
const results = [];
|
|
586
|
+
let passed = true;
|
|
587
|
+
for (const spec of commands) {
|
|
588
|
+
const { status } = runner(spec.argv, root, spec.package_dir);
|
|
589
|
+
const cmdPassed = status === 0;
|
|
590
|
+
results.push({
|
|
591
|
+
argv: spec.argv,
|
|
592
|
+
layer: spec.layer,
|
|
593
|
+
...(spec.package_dir ? { package_dir: spec.package_dir } : {}),
|
|
594
|
+
exit_code: status,
|
|
595
|
+
passed: cmdPassed,
|
|
596
|
+
});
|
|
597
|
+
if (!cmdPassed) {
|
|
598
|
+
passed = false;
|
|
599
|
+
break; // short-circuit: later layers are meaningless on a broken floor
|
|
600
|
+
}
|
|
601
|
+
}
|
|
602
|
+
return { passed, results, scoped_out: false, runtime_residual };
|
|
603
|
+
}
|
|
604
|
+
/**
|
|
605
|
+
* The bound on coarse re-block iterations before the run converges to a terminal
|
|
606
|
+
* `blocked` close (CE-003). Two re-block attempts give a flaky-but-recoverable
|
|
607
|
+
* suite a chance to settle; the third unattributable red terminates
|
|
608
|
+
* deterministically rather than livelocking.
|
|
609
|
+
*/
|
|
610
|
+
export const COARSE_REBLOCK_BOUND = 2;
|
|
611
|
+
const FINAL_GATE_STATE_FILENAME = "final-gate.json";
|
|
612
|
+
async function readFinalGateSidecar(artifactsDir) {
|
|
613
|
+
const sidecar = await readOptionalJsonFile(join(artifactsDir, FINAL_GATE_STATE_FILENAME));
|
|
614
|
+
const n = sidecar?.coarse_reblock_count;
|
|
615
|
+
return {
|
|
616
|
+
count: typeof n === "number" && Number.isFinite(n) && n >= 0 ? n : 0,
|
|
617
|
+
terminated: sidecar?.terminated === true,
|
|
618
|
+
};
|
|
619
|
+
}
|
|
620
|
+
async function writeFinalGateSidecar(artifactsDir, count, terminated) {
|
|
621
|
+
await writeJsonFile(join(artifactsDir, FINAL_GATE_STATE_FILENAME), {
|
|
622
|
+
schema_version: "remediate-code-final-gate/v1alpha1",
|
|
623
|
+
coarse_reblock_count: count,
|
|
624
|
+
terminated,
|
|
625
|
+
});
|
|
626
|
+
}
|
|
627
|
+
/**
|
|
628
|
+
* Coarse re-block-ALL-non-terminal on an unattributable final-gate red
|
|
629
|
+
* (INV-RS-09) with a bounded, monotonic auto-terminate (CE-003).
|
|
630
|
+
*
|
|
631
|
+
* The tool-owned gate is whole-repo, so a red is inherently unattributable to a
|
|
632
|
+
* single node. Below the bound, EVERY non-skip item (including `resolved` ones —
|
|
633
|
+
* a resolved item's own change may have caused the red) is re-opened to `pending`
|
|
634
|
+
* and the run re-attempts the whole repo through the rolling scheduler
|
|
635
|
+
* (`reattempt_all` → `implementing`). At or above the bound, the run STOPS
|
|
636
|
+
* re-attempting and converges DETERMINISTICALLY: every non-skip item becomes
|
|
637
|
+
* terminal `blocked` and the run advances to `closing`.
|
|
638
|
+
*
|
|
639
|
+
* CE-003 no-human-host guarantee: the loop is owned entirely by the gate + the
|
|
640
|
+
* rolling scheduler — it NEVER routes through the human triage prompt
|
|
641
|
+
* (`waiting_for_triage`) and is bounded by `bound`, so a permanently-red sibling
|
|
642
|
+
* converges to a terminal `blocked` close deterministically: never livelocking,
|
|
643
|
+
* never stranding on a human prompt, and never force-closed to green (a RED gate
|
|
644
|
+
* always leaves `blocked` items, so close.ts's `!anyBlocked` guard keeps the run
|
|
645
|
+
* out of the fully-green path). User SKIP dispositions (ignored /
|
|
646
|
+
* deemed_inappropriate) are settled decisions and are left alone. Pure (the
|
|
647
|
+
* counter is supplied / returned).
|
|
648
|
+
*/
|
|
649
|
+
export function applyCoarseReblock(state, currentCount, gateSummary, bound = COARSE_REBLOCK_BOUND) {
|
|
650
|
+
const now = new Date().toISOString();
|
|
651
|
+
if (currentCount >= bound) {
|
|
652
|
+
// Bounded auto-terminate: converge DETERMINISTICALLY to a terminal `blocked`
|
|
653
|
+
// close for a no-human host — never livelock, never a triage prompt, never green.
|
|
654
|
+
for (const it of Object.values(state.items ?? {})) {
|
|
655
|
+
if (isSkipStatus(it.status))
|
|
656
|
+
continue; // settled user decision — never overturn
|
|
657
|
+
it.status = "blocked";
|
|
658
|
+
it.started_at ??= now;
|
|
659
|
+
it.completed_at = now;
|
|
660
|
+
it.failure_reason =
|
|
661
|
+
`Tool-owned final gate failed and the coarse re-block backstop reached its ` +
|
|
662
|
+
`bound (${bound}); converging to a terminal blocked close (no-human host). ${gateSummary}`;
|
|
663
|
+
}
|
|
664
|
+
return { state, action: "terminal_blocked", next_count: currentCount };
|
|
665
|
+
}
|
|
666
|
+
// Below the bound: re-open every non-skip item to `pending` and re-attempt the
|
|
667
|
+
// whole repo via the rolling scheduler (NOT the human triage prompt).
|
|
668
|
+
for (const it of Object.values(state.items ?? {})) {
|
|
669
|
+
if (isSkipStatus(it.status))
|
|
670
|
+
continue;
|
|
671
|
+
it.status = "pending";
|
|
672
|
+
it.failure_context =
|
|
673
|
+
`Re-attempted by the coarse final-gate backstop (unattributable whole-repo red). ${gateSummary}`;
|
|
674
|
+
delete it.completed_at;
|
|
675
|
+
}
|
|
676
|
+
return { state, action: "reattempt_all", next_count: currentCount + 1 };
|
|
677
|
+
}
|
|
678
|
+
function resolvedOrTerminalItems(state) {
|
|
679
|
+
return Object.values(state.items ?? {}).filter((item) => isTerminalStatus(item.status));
|
|
680
|
+
}
|
|
681
|
+
function allItemsTerminal(state) {
|
|
682
|
+
const items = Object.values(state.items ?? {});
|
|
683
|
+
return items.length > 0 && resolvedOrTerminalItems(state).length === items.length;
|
|
684
|
+
}
|
|
685
|
+
function normalizeExtractedPlan(value) {
|
|
686
|
+
if (!isRecord(value)) {
|
|
687
|
+
throw new Error("extracted-plan.json must be an object.");
|
|
688
|
+
}
|
|
689
|
+
const rawFindings = Array.isArray(value.findings) ? value.findings : [];
|
|
690
|
+
const findings = rawFindings.map((finding) => {
|
|
691
|
+
if (!isRecord(finding))
|
|
692
|
+
return finding;
|
|
693
|
+
return {
|
|
694
|
+
category: "General",
|
|
695
|
+
affected_files: [],
|
|
696
|
+
evidence: [],
|
|
697
|
+
...finding,
|
|
698
|
+
};
|
|
699
|
+
});
|
|
700
|
+
const rawBlocks = Array.isArray(value.blocks) ? value.blocks : [];
|
|
701
|
+
const blocks = rawBlocks.length > 0
|
|
702
|
+
? rawBlocks.map((block) => {
|
|
703
|
+
if (!isRecord(block))
|
|
704
|
+
return block;
|
|
705
|
+
return {
|
|
706
|
+
parallel_safe: true,
|
|
707
|
+
dependencies: [],
|
|
708
|
+
...block,
|
|
709
|
+
};
|
|
710
|
+
})
|
|
711
|
+
: findings.map((finding, index) => ({
|
|
712
|
+
block_id: `B-${String(index + 1).padStart(3, "0")}`,
|
|
713
|
+
items: [finding.id],
|
|
714
|
+
parallel_safe: true,
|
|
715
|
+
}));
|
|
716
|
+
const dedup = deduplicateCrossLensFindings(findings);
|
|
717
|
+
const dedupBlocks = fixupBlocksAfterDedup(blocks, dedup.mergeMap);
|
|
718
|
+
const plan = {
|
|
719
|
+
plan_id: typeof value.plan_id === "string" ? value.plan_id : randomRunId("PLAN"),
|
|
720
|
+
...(typeof value.goal_id === "string" ? { goal_id: value.goal_id } : {}),
|
|
721
|
+
...(typeof value.source === "string" ? { source: value.source } : {}),
|
|
722
|
+
findings: dedup.findings,
|
|
723
|
+
blocks: dedupBlocks,
|
|
724
|
+
project_type: typeof value.project_type === "string" ? value.project_type : "unknown",
|
|
725
|
+
test_command: typeof value.test_command === "string" ? value.test_command : undefined,
|
|
726
|
+
e2e_command: typeof value.e2e_command === "string" ? value.e2e_command : undefined,
|
|
727
|
+
candidate_closing_actions: ["none"],
|
|
728
|
+
block_strategy: value.block_strategy === "test_graph" ||
|
|
729
|
+
value.block_strategy === "git_cocommit" ||
|
|
730
|
+
value.block_strategy === "file_overlap" ||
|
|
731
|
+
value.block_strategy === "manual"
|
|
732
|
+
? value.block_strategy
|
|
733
|
+
: undefined,
|
|
734
|
+
};
|
|
735
|
+
const issues = validateRemediationPlan(plan).filter((issue) => issue.severity === "error");
|
|
736
|
+
if (issues.length > 0) {
|
|
737
|
+
throw new Error(`Invalid extracted plan:\n${formatValidationIssues(issues)}`);
|
|
738
|
+
}
|
|
739
|
+
if (plan.findings.length === 0) {
|
|
740
|
+
throw new Error("Extracted plan contains zero findings.");
|
|
741
|
+
}
|
|
742
|
+
return { plan, sourceFindings: findings, mergeMap: dedup.mergeMap };
|
|
743
|
+
}
|
|
744
|
+
async function saveStateForPlan(artifactsDir, existing, plan, planCoverage) {
|
|
745
|
+
const items = {};
|
|
746
|
+
for (const finding of plan.findings) {
|
|
747
|
+
const block = plan.blocks.find((candidate) => candidate.items.includes(finding.id));
|
|
748
|
+
items[finding.id] = {
|
|
749
|
+
finding_id: finding.id,
|
|
750
|
+
status: "pending",
|
|
751
|
+
block_id: block?.block_id ?? "UNKNOWN",
|
|
752
|
+
};
|
|
753
|
+
}
|
|
754
|
+
const state = {
|
|
755
|
+
...existing,
|
|
756
|
+
status: "planning",
|
|
757
|
+
plan,
|
|
758
|
+
items,
|
|
759
|
+
closing_plan: { action: "none" },
|
|
760
|
+
...(planCoverage ? { plan_coverage: planCoverage } : {}),
|
|
761
|
+
};
|
|
762
|
+
await new StateStore(artifactsDir).saveState(state);
|
|
763
|
+
await writeJsonFile(join(artifactsDir, "remediation_plan.json"), plan);
|
|
764
|
+
return state;
|
|
765
|
+
}
|
|
766
|
+
// Plan-time bookkeeping recomputed on every plan pass; it must not participate
|
|
767
|
+
// in the carry-forward identity of a finding.
|
|
768
|
+
const PLAN_TIME_BOOKKEEPING_KEYS = new Set([
|
|
769
|
+
"hash_at_plan_time",
|
|
770
|
+
"evidence_grounded",
|
|
771
|
+
]);
|
|
772
|
+
function stripPlanTimeBookkeeping(value) {
|
|
773
|
+
if (Array.isArray(value)) {
|
|
774
|
+
return value.map((entry) => stripPlanTimeBookkeeping(entry));
|
|
775
|
+
}
|
|
776
|
+
if (!isRecord(value)) {
|
|
777
|
+
return value;
|
|
778
|
+
}
|
|
779
|
+
const stripped = {};
|
|
780
|
+
for (const key of Object.keys(value).sort()) {
|
|
781
|
+
if (PLAN_TIME_BOOKKEEPING_KEYS.has(key))
|
|
782
|
+
continue;
|
|
783
|
+
stripped[key] = stripPlanTimeBookkeeping(value[key]);
|
|
784
|
+
}
|
|
785
|
+
return stripped;
|
|
786
|
+
}
|
|
787
|
+
function findingCarryForwardKey(finding) {
|
|
788
|
+
return JSON.stringify(stripPlanTimeBookkeeping(finding));
|
|
789
|
+
}
|
|
790
|
+
function blockIdsByFinding(plan) {
|
|
791
|
+
const byFinding = new Map();
|
|
792
|
+
for (const block of plan.blocks) {
|
|
793
|
+
for (const id of block.items) {
|
|
794
|
+
byFinding.set(id, block.block_id);
|
|
795
|
+
}
|
|
796
|
+
}
|
|
797
|
+
return byFinding;
|
|
798
|
+
}
|
|
799
|
+
function carryForwardMatchingItems(previous, replanned) {
|
|
800
|
+
if (!previous.plan || !previous.items || !replanned.plan || !replanned.items) {
|
|
801
|
+
return replanned;
|
|
802
|
+
}
|
|
803
|
+
const previousFindings = new Map(previous.plan.findings.map((finding) => [finding.id, finding]));
|
|
804
|
+
const replannedBlockIds = blockIdsByFinding(replanned.plan);
|
|
805
|
+
const items = { ...replanned.items };
|
|
806
|
+
let carried = false;
|
|
807
|
+
for (const finding of replanned.plan.findings) {
|
|
808
|
+
const previousFinding = previousFindings.get(finding.id);
|
|
809
|
+
const previousItem = previous.items[finding.id];
|
|
810
|
+
// Skip items that were never documented (pending with no item_spec). Under
|
|
811
|
+
// N-R13 (document phase dissolved), a pending item that already has an
|
|
812
|
+
// item_spec from a prior planning/document pass should carry forward
|
|
813
|
+
// together with its spec rather than being discarded.
|
|
814
|
+
if (!previousFinding || !previousItem) {
|
|
815
|
+
continue;
|
|
816
|
+
}
|
|
817
|
+
if (previousItem.status === "pending" && !previousItem.item_spec) {
|
|
818
|
+
continue;
|
|
819
|
+
}
|
|
820
|
+
if (findingCarryForwardKey(previousFinding) !== findingCarryForwardKey(finding)) {
|
|
821
|
+
continue;
|
|
822
|
+
}
|
|
823
|
+
items[finding.id] = {
|
|
824
|
+
...previousItem,
|
|
825
|
+
block_id: replannedBlockIds.get(finding.id) ?? previousItem.block_id,
|
|
826
|
+
};
|
|
827
|
+
carried = true;
|
|
828
|
+
}
|
|
829
|
+
if (!carried) {
|
|
830
|
+
return replanned;
|
|
831
|
+
}
|
|
832
|
+
const hasPending = replanned.plan.findings.some((finding) => items[finding.id]?.status === "pending");
|
|
833
|
+
return {
|
|
834
|
+
...replanned,
|
|
835
|
+
items,
|
|
836
|
+
status: hasPending ? "planning" : replanned.status,
|
|
837
|
+
};
|
|
838
|
+
}
|
|
839
|
+
async function forceReplanFromExistingIntake(root, artifactsDir, previous, store) {
|
|
840
|
+
const pendingState = {
|
|
841
|
+
status: "pending",
|
|
842
|
+
started_at: previous.started_at,
|
|
843
|
+
step_count: previous.step_count,
|
|
844
|
+
};
|
|
845
|
+
const extractedPlan = await readExtractedPlanIfPresent(artifactsDir);
|
|
846
|
+
if (!extractedPlan) {
|
|
847
|
+
await store.saveState(pendingState);
|
|
848
|
+
return null;
|
|
849
|
+
}
|
|
850
|
+
const replanned = await handlePendingExtractedPlan(root, artifactsDir, pendingState, extractedPlan);
|
|
851
|
+
if (!replanned) {
|
|
852
|
+
return null;
|
|
853
|
+
}
|
|
854
|
+
const carried = carryForwardMatchingItems(previous, replanned);
|
|
855
|
+
await store.saveState(carried);
|
|
856
|
+
return carried;
|
|
857
|
+
}
|
|
858
|
+
async function presentReportStep(root, artifactsDir, state) {
|
|
859
|
+
const reportPath = join(dirname(artifactsDir), "remediation-report.md");
|
|
860
|
+
return writeCurrentStep({
|
|
861
|
+
stepKind: "present_report",
|
|
862
|
+
status: "complete",
|
|
863
|
+
runId: stateRunId(state),
|
|
864
|
+
repoRoot: root,
|
|
865
|
+
artifactsDir,
|
|
866
|
+
prompt: `
|
|
867
|
+
# Present Remediation Report
|
|
868
|
+
|
|
869
|
+
Read \`${reportPath}\` and summarize the remediation outcome for the user.
|
|
870
|
+
Mention the resolved, ignored, and deemed-inappropriate counts plus the closing action.
|
|
871
|
+
Stop after presenting the summary.
|
|
872
|
+
`,
|
|
873
|
+
allowedCommands: [],
|
|
874
|
+
stopCondition: "Stop after presenting the remediation report summary.",
|
|
875
|
+
artifactPaths: {
|
|
876
|
+
final_report: reportPath,
|
|
877
|
+
},
|
|
878
|
+
});
|
|
879
|
+
}
|
|
880
|
+
async function buildImplementDispatchStep(ctx) {
|
|
881
|
+
const { root, artifactsDir, state, options, store } = ctx;
|
|
882
|
+
const sessionConfigImpl = options.sessionConfig ??
|
|
883
|
+
await readOptionalJsonFile(join(root, ".remediation-artifacts", "session-config.json")) ?? await readOptionalJsonFile(join(root, "session-config.json"));
|
|
884
|
+
const canDispatchImpl = resolveHostDispatchCapability({
|
|
885
|
+
hostCanDispatchSubagents: options.hostCanDispatchSubagents,
|
|
886
|
+
sessionConfig: sessionConfigImpl,
|
|
887
|
+
});
|
|
888
|
+
// A8 host-subagent rolling driver: when the rolling engine is enabled AND the
|
|
889
|
+
// host can dispatch subagents, drive a FULL-ROLLING, worktree-isolated flow via
|
|
890
|
+
// the `accept-node` per-completion callback — the conversation-first co-equal of
|
|
891
|
+
// the in-process provider engine (`driveRollingImplementDispatch`), sharing the
|
|
892
|
+
// same `acceptNodeWorktree` core. Gated behind the flag so the default stays the
|
|
893
|
+
// proven host-fanned wave step until the rolling path is validated end-to-end.
|
|
894
|
+
const rollingEngineEnabled = resolveRollingEngineEnabled({
|
|
895
|
+
rollingEngine: options.rollingEngine,
|
|
896
|
+
sessionConfig: sessionConfigImpl,
|
|
897
|
+
});
|
|
898
|
+
const runId = stateRunId(state);
|
|
899
|
+
const waveOptsImpl = {
|
|
900
|
+
hostMaxConcurrent: options.hostMaxConcurrent,
|
|
901
|
+
sessionConfig: sessionConfigImpl ?? null,
|
|
902
|
+
hostContextTokens: options.hostContextTokens,
|
|
903
|
+
hostOutputTokens: options.hostOutputTokens,
|
|
904
|
+
hostModels: options.hostModels,
|
|
905
|
+
hostModelId: options.hostModelId,
|
|
906
|
+
};
|
|
907
|
+
// A8 in-process provider driver: when the rolling engine is enabled AND the
|
|
908
|
+
// operator EXPLICITLY configured a programmatic backend provider (openai-compatible
|
|
909
|
+
// / codex / opencode / …), the orchestrator drives the FULL rolling implement
|
|
910
|
+
// dispatch ITSELF — the configured provider is the per-node worker, cwd-confined to
|
|
911
|
+
// each node's worktree, sharing the same `acceptNodeWorktree` core (commit → verify
|
|
912
|
+
// → merge, verify-fail → triage) as the host-subagent driver. Checked BEFORE the
|
|
913
|
+
// host-subagent branch so an explicit backend (e.g. a NIM pool for headless
|
|
914
|
+
// autonomy) drives the work rather than the conversation host's subagents.
|
|
915
|
+
if (rollingEngineEnabled && resolvesToInProcessDispatchProvider(sessionConfigImpl)) {
|
|
916
|
+
const driven = await driveRollingImplementDispatch({
|
|
917
|
+
root,
|
|
918
|
+
artifactsDir,
|
|
919
|
+
runId,
|
|
920
|
+
sessionConfig: sessionConfigImpl ?? null,
|
|
921
|
+
// Per-node verify (targeted_commands) owns each node's build/test; an
|
|
922
|
+
// inter-level "shared surface" rebuild is a monorepo-self-remediation concern
|
|
923
|
+
// the host-driven paths handle, not a generic target-repo step → no-op here.
|
|
924
|
+
rebuildSharedBetweenLevels: async () => { },
|
|
925
|
+
waveOptions: {
|
|
926
|
+
hostMaxConcurrent: options.hostMaxConcurrent,
|
|
927
|
+
hostContextTokens: options.hostContextTokens,
|
|
928
|
+
hostOutputTokens: options.hostOutputTokens,
|
|
929
|
+
hostModels: options.hostModels,
|
|
930
|
+
hostModelId: options.hostModelId,
|
|
931
|
+
},
|
|
932
|
+
});
|
|
933
|
+
// null = no eligible pending work this pass; the engine merges internally once
|
|
934
|
+
// it has run, so only the empty-frontier case needs a merge here. Either way the
|
|
935
|
+
// implement frontier is resolved — transition on the freshly-merged state so the
|
|
936
|
+
// engine re-scans (triage / closing) without recursion.
|
|
937
|
+
if (driven === null) {
|
|
938
|
+
await mergeImplementResults({ root, artifactsDir }, runId);
|
|
939
|
+
}
|
|
940
|
+
return { kind: "transition", state: await store.loadState() };
|
|
941
|
+
}
|
|
942
|
+
if (rollingEngineEnabled && canDispatchImpl) {
|
|
943
|
+
const rolling = await prepareHostRollingDispatch({ root, artifactsDir }, runId, waveOptsImpl);
|
|
944
|
+
// Everything eligible may already be done/skipped — fold straight to merge
|
|
945
|
+
// rather than emitting a dispatch step with zero nodes.
|
|
946
|
+
if (rolling.session.frontier.length === 0) {
|
|
947
|
+
await mergeImplementResults({ root, artifactsDir }, runId);
|
|
948
|
+
return { kind: "transition", state: await store.loadState() };
|
|
949
|
+
}
|
|
950
|
+
const rollMerge = loaderCommand(`merge-implement-results --run-id ${runId}`);
|
|
951
|
+
const rollNext = loaderCommand("next-step");
|
|
952
|
+
const acceptCmd = loaderCommand("accept-node --id <BLOCK_ID>");
|
|
953
|
+
const nodeLines = rolling.initial
|
|
954
|
+
.map((n) => `- \`${n.block_id}\` — prompt: \`${n.prompt_path}\` — worktree (subagent cwd): \`${n.worktree_root}\``)
|
|
955
|
+
.join("\n");
|
|
956
|
+
return { kind: "emit", step: await writeCurrentStep({
|
|
957
|
+
stepKind: "dispatch_implement_rolling",
|
|
958
|
+
status: "ready",
|
|
959
|
+
runId,
|
|
960
|
+
repoRoot: root,
|
|
961
|
+
artifactsDir,
|
|
962
|
+
prompt: `
|
|
963
|
+
# Dispatch Implementation Work (host-subagent rolling, worktree-isolated)
|
|
964
|
+
|
|
965
|
+
Each eligible node runs in its OWN git worktree (hard isolation between nodes). The
|
|
966
|
+
TOOL owns commit -> verify -> merge + write-scope; you only spawn a subagent per
|
|
967
|
+
node and call \`accept-node\` as each finishes.
|
|
968
|
+
|
|
969
|
+
Concurrency target: **${rolling.session.slots}** subagents at once (the quota
|
|
970
|
+
scheduler's \`max_concurrent_agents\`), NOT a wave cap.
|
|
971
|
+
|
|
972
|
+
Spawn ONE subagent for EACH initial node below. Give the subagent that node's
|
|
973
|
+
\`prompt\`, and set its working directory to the node's **worktree** path. The
|
|
974
|
+
subagent edits source files INSIDE that worktree and writes ONLY its result file.
|
|
975
|
+
Do NOT let any subagent edit the main repository tree.
|
|
976
|
+
|
|
977
|
+
Initial nodes (worktrees already created):
|
|
978
|
+
${nodeLines}
|
|
979
|
+
|
|
980
|
+
As EACH subagent finishes, run (substituting the finished node's block id):
|
|
981
|
+
|
|
982
|
+
\`${acceptCmd}\`
|
|
983
|
+
|
|
984
|
+
It runs the commit -> verify -> merge lifecycle for that node and prints a JSON
|
|
985
|
+
directive on stdout:
|
|
986
|
+
- \`{"directive":"dispatch","node":{...},"worktree_root":"..."}\` — spawn a subagent
|
|
987
|
+
for that next node (its worktree is already created), keeping up to
|
|
988
|
+
${rolling.session.slots} running.
|
|
989
|
+
- \`{"directive":"wait",...}\` — other nodes are still in flight; do not spawn more yet.
|
|
990
|
+
- \`{"directive":"done",...}\` — every node has been accepted. Then run:
|
|
991
|
+
|
|
992
|
+
${DO_NOT_TOKEN_WRAP_NOTE}
|
|
993
|
+
|
|
994
|
+
\`${rollMerge}\`
|
|
995
|
+
|
|
996
|
+
Then run:
|
|
997
|
+
|
|
998
|
+
\`${rollNext}\`
|
|
999
|
+
|
|
1000
|
+
${DISPATCH_PROMPT_HANDOFF_NOTE}
|
|
1001
|
+
`,
|
|
1002
|
+
allowedCommands: [acceptCmd, rollMerge, rollNext],
|
|
1003
|
+
stopCondition: "Stop after every node has been accepted (accept-node returns done), results merged, and next-step has been run.",
|
|
1004
|
+
artifactPaths: { dispatch_plan: rolling.planPath, dispatch_quota: rolling.quotaPath },
|
|
1005
|
+
}) };
|
|
1006
|
+
}
|
|
1007
|
+
// Rolling per-node dispatch: prepare EVERY currently-eligible node (deps all
|
|
1008
|
+
// verified-complete), never a single artificially-serialized block. There is
|
|
1009
|
+
// no wave-size cap — concurrency is owned by the quota scheduler
|
|
1010
|
+
// (`dispatch-quota.json` max_concurrent_agents). `prepareImplementDispatch`
|
|
1011
|
+
// itself only admits verified-complete-eligible blocks
|
|
1012
|
+
// (`dependencyVerifiedComplete`), so this is the rolling-eligible frontier.
|
|
1013
|
+
const dispatchPlan = await prepareImplementDispatch({ root, artifactsDir }, runId, undefined, waveOptsImpl);
|
|
1014
|
+
// Everything eligible may already be done or skipped (e.g. every Tier 3
|
|
1015
|
+
// finding excluded) — fold straight to merge rather than dispatching a wave
|
|
1016
|
+
// of zero workers.
|
|
1017
|
+
if (dispatchPlan.items.length === 0) {
|
|
1018
|
+
await mergeImplementResults({ root, artifactsDir }, runId);
|
|
1019
|
+
return { kind: "transition", state: await store.loadState() };
|
|
1020
|
+
}
|
|
1021
|
+
const planPath = join(artifactsDir, "runs", runId, "implement", "dispatch-plan.json");
|
|
1022
|
+
const mergeCommand = loaderCommand(`merge-implement-results --run-id ${runId}`);
|
|
1023
|
+
const nextCommand = loaderCommand("next-step");
|
|
1024
|
+
const implQuotaPath = join(artifactsDir, "runs", runId, "implement", "dispatch-quota.json");
|
|
1025
|
+
if (!canDispatchImpl) {
|
|
1026
|
+
// A host that cannot dispatch parallel subagents runs the eligible nodes
|
|
1027
|
+
// ITSELF, one at a time — but the orchestrator still emits the FULL eligible
|
|
1028
|
+
// frontier (not one node per next-step). The shared rebuild between
|
|
1029
|
+
// dependency levels happens naturally on the next next-step pass: this
|
|
1030
|
+
// level's results are merged, and the next pass emits the now-eligible
|
|
1031
|
+
// downstream level after the host rebuilds the shared surface.
|
|
1032
|
+
return { kind: "emit", step: await writeCurrentStep({
|
|
1033
|
+
stepKind: "implement_rolling_sequential",
|
|
1034
|
+
status: "ready",
|
|
1035
|
+
runId,
|
|
1036
|
+
repoRoot: root,
|
|
1037
|
+
artifactsDir,
|
|
1038
|
+
prompt: `
|
|
1039
|
+
# Implement Eligible Remediation Nodes (sequential)
|
|
1040
|
+
|
|
1041
|
+
Read the dispatch plan:
|
|
1042
|
+
|
|
1043
|
+
\`${planPath}\`
|
|
1044
|
+
|
|
1045
|
+
Every item in \`items\` is a node whose dependencies are all verified-complete, so
|
|
1046
|
+
they are safe to implement now. Work through them ONE AT A TIME, in order: for each
|
|
1047
|
+
item, read and follow only its \`prompt_path\`, then move to the next.
|
|
1048
|
+
|
|
1049
|
+
${SHARED_REBUILD_BETWEEN_LEVELS_NOTE}
|
|
1050
|
+
|
|
1051
|
+
After all results in this plan exist:
|
|
1052
|
+
|
|
1053
|
+
\`${mergeCommand}\`
|
|
1054
|
+
|
|
1055
|
+
Then run:
|
|
1056
|
+
|
|
1057
|
+
\`${nextCommand}\`
|
|
1058
|
+
`,
|
|
1059
|
+
allowedCommands: [mergeCommand, nextCommand],
|
|
1060
|
+
stopCondition: "Stop after every eligible node's result has been merged and next-step has been run.",
|
|
1061
|
+
artifactPaths: {
|
|
1062
|
+
dispatch_plan: planPath,
|
|
1063
|
+
dispatch_quota: implQuotaPath,
|
|
1064
|
+
},
|
|
1065
|
+
}) };
|
|
1066
|
+
}
|
|
1067
|
+
return { kind: "emit", step: await writeCurrentStep({
|
|
1068
|
+
stepKind: "dispatch_implement",
|
|
1069
|
+
status: "ready",
|
|
1070
|
+
runId,
|
|
1071
|
+
repoRoot: root,
|
|
1072
|
+
artifactsDir,
|
|
1073
|
+
prompt: `
|
|
1074
|
+
# Dispatch Implementation Work (rolling)
|
|
1075
|
+
|
|
1076
|
+
Read the dispatch plan and quota JSONs:
|
|
1077
|
+
|
|
1078
|
+
\`${planPath}\`
|
|
1079
|
+
\`${implQuotaPath}\`
|
|
1080
|
+
|
|
1081
|
+
Every item in \`items\` is a node whose dependencies are all VERIFIED-COMPLETE
|
|
1082
|
+
(INV-RS-01), so all of them are eligible to run now. Concurrency is owned by the
|
|
1083
|
+
quota scheduler — maintain up to \`max_concurrent_agents\` subagents running
|
|
1084
|
+
simultaneously (from the quota file), with no separate wave-size cap. Each item's
|
|
1085
|
+
\`model_hint.tier\` suggests which model to use (small/standard/deep). If your
|
|
1086
|
+
provider has rate limits, pace launches accordingly.
|
|
1087
|
+
|
|
1088
|
+
For each item in \`items\`, dispatch one subagent with that item's
|
|
1089
|
+
\`prompt_path\`. Each subagent may edit source files needed for that bounded
|
|
1090
|
+
block and must write only its assigned \`result_path\`.
|
|
1091
|
+
|
|
1092
|
+
${SHARED_REBUILD_BETWEEN_LEVELS_NOTE}
|
|
1093
|
+
|
|
1094
|
+
${DISPATCH_PROMPT_HANDOFF_NOTE}
|
|
1095
|
+
|
|
1096
|
+
After all results exist:
|
|
1097
|
+
|
|
1098
|
+
${DO_NOT_TOKEN_WRAP_NOTE}
|
|
1099
|
+
|
|
1100
|
+
\`${mergeCommand}\`
|
|
1101
|
+
|
|
1102
|
+
Then run:
|
|
1103
|
+
|
|
1104
|
+
\`${nextCommand}\`
|
|
1105
|
+
`,
|
|
1106
|
+
allowedCommands: [mergeCommand, nextCommand],
|
|
1107
|
+
stopCondition: "Stop after all implementation results have been merged and next-step has been run.",
|
|
1108
|
+
artifactPaths: { dispatch_plan: planPath, dispatch_quota: implQuotaPath },
|
|
1109
|
+
}) };
|
|
1110
|
+
}
|
|
1111
|
+
// --- Per-state handlers -----------------------------------------------------
|
|
1112
|
+
// Each handler owns one branch of the original decideNextStepInner dispatch.
|
|
1113
|
+
// Handlers that emit a step return RemediationStep directly; handlers that need
|
|
1114
|
+
// the loop to continue with mutated state return { continueWithState }.
|
|
1115
|
+
async function handleComplete(root, artifactsDir, state) {
|
|
1116
|
+
return presentReportStep(root, artifactsDir, state);
|
|
1117
|
+
}
|
|
1118
|
+
async function handlePendingExtractedPlan(root, artifactsDir, existing, extractedPlan) {
|
|
1119
|
+
try {
|
|
1120
|
+
const { plan, sourceFindings, mergeMap } = normalizeExtractedPlan(extractedPlan);
|
|
1121
|
+
// Deterministic grounding for the LLM-extracted plan (this path never sees
|
|
1122
|
+
// structured audit findings): strip phantom affected_files paths, drop
|
|
1123
|
+
// findings whose every cited path was phantom, and classify evidence. No
|
|
1124
|
+
// bounded LLM repair here — the host re-extracts with the corrected prompt
|
|
1125
|
+
// if the whole plan grounds to nothing. Contract-pipeline-promoted plans
|
|
1126
|
+
// are grounded by construction (the traceability gate ties every node to
|
|
1127
|
+
// obligations/accepted counterexamples), so their obligation-reference
|
|
1128
|
+
// evidence is exempt from the path-citation check.
|
|
1129
|
+
const grounding = await groundExtractedFindings(plan.findings, {
|
|
1130
|
+
root,
|
|
1131
|
+
evidenceGrounding: plan.source !== "contract_pipeline",
|
|
1132
|
+
});
|
|
1133
|
+
if (grounding.dropped.length > 0) {
|
|
1134
|
+
process.stderr.write(`[remediate-code] Grounding dropped ${grounding.dropped.length} extracted finding(s) whose cited paths do not exist: ${grounding.dropped.map((d) => `${d.finding.id} (${d.phantomPaths.join(", ")})`).join("; ")}\n`);
|
|
1135
|
+
}
|
|
1136
|
+
plan.findings = grounding.findings;
|
|
1137
|
+
const keptIds = new Set(plan.findings.map((f) => f.id));
|
|
1138
|
+
plan.blocks = plan.blocks
|
|
1139
|
+
.map((b) => ({ ...b, items: (b.items ?? []).filter((id) => keptIds.has(id)) }))
|
|
1140
|
+
.filter((b) => (b.items ?? []).length > 0);
|
|
1141
|
+
if (plan.findings.length === 0) {
|
|
1142
|
+
throw new Error("Every extracted finding cited only phantom paths; re-extract with real repo-relative paths.");
|
|
1143
|
+
}
|
|
1144
|
+
const pipelined = await applyPlanPipeline(plan, { root, artifactsDir });
|
|
1145
|
+
const reviewDecision = await readOptionalJsonFile(reviewDecisionPath(artifactsDir));
|
|
1146
|
+
// Coverage ledger. Path A (structured_audit): the single filter pass ran at
|
|
1147
|
+
// intake over the ORIGINAL findings and persisted its dispositions — build
|
|
1148
|
+
// coverage over those originals so every audit finding gets exactly one
|
|
1149
|
+
// disposition (planned / folded_into / dropped_* / dropped_by_checkpoint /
|
|
1150
|
+
// declined_by_review), reconciling to the original count. Path B (no persisted
|
|
1151
|
+
// dispositions): build over the post-pipeline node findings as before. Either
|
|
1152
|
+
// way declined findings are recorded; their payloads recover at close from the
|
|
1153
|
+
// unfiltered intake source.
|
|
1154
|
+
const filterDisp = await readOptionalJsonFile(reviewFilterDispositionsPath(artifactsDir));
|
|
1155
|
+
const coverage = filterDisp
|
|
1156
|
+
? buildCoverageLedger({
|
|
1157
|
+
planId: pipelined.plan_id,
|
|
1158
|
+
sourceFindings: filterDisp.originals,
|
|
1159
|
+
droppedNoEvidence: filterDisp.droppedNoEvidence,
|
|
1160
|
+
droppedByCheckpoint: filterDisp.droppedByCheckpoint,
|
|
1161
|
+
declinedByReview: reviewDecision?.declined ?? [],
|
|
1162
|
+
droppedPhantomPaths: new Map(filterDisp.droppedPhantomPaths),
|
|
1163
|
+
phantomPathsRemoved: new Map(filterDisp.phantomPathsRemoved),
|
|
1164
|
+
mergeMap: new Map(filterDisp.mergeMap),
|
|
1165
|
+
items: {}, // originals carry no node block_id; planned entries omit it
|
|
1166
|
+
})
|
|
1167
|
+
: buildCoverageLedger({
|
|
1168
|
+
planId: pipelined.plan_id,
|
|
1169
|
+
sourceFindings,
|
|
1170
|
+
droppedNoEvidence: [],
|
|
1171
|
+
droppedByCheckpoint: [],
|
|
1172
|
+
declinedByReview: reviewDecision?.declined ?? [],
|
|
1173
|
+
droppedPhantomPaths: new Map(grounding.dropped.map((d) => [d.finding.id, d.phantomPaths])),
|
|
1174
|
+
phantomPathsRemoved: grounding.phantomPathsByFinding,
|
|
1175
|
+
mergeMap,
|
|
1176
|
+
items: Object.fromEntries(pipelined.findings.map((finding) => [
|
|
1177
|
+
finding.id,
|
|
1178
|
+
{
|
|
1179
|
+
finding_id: finding.id,
|
|
1180
|
+
status: "pending",
|
|
1181
|
+
block_id: pipelined.blocks.find((b) => b.items.includes(finding.id))
|
|
1182
|
+
?.block_id ?? "UNKNOWN",
|
|
1183
|
+
},
|
|
1184
|
+
])),
|
|
1185
|
+
});
|
|
1186
|
+
return await saveStateForPlan(artifactsDir, existing, pipelined, coverage);
|
|
1187
|
+
}
|
|
1188
|
+
catch (error) {
|
|
1189
|
+
const paths = intakePaths(artifactsDir);
|
|
1190
|
+
try {
|
|
1191
|
+
const { unlink } = await import("node:fs/promises");
|
|
1192
|
+
await unlink(paths.extractedPlan);
|
|
1193
|
+
}
|
|
1194
|
+
catch { /* already gone */ }
|
|
1195
|
+
process.stderr.write(`[remediate-code] Corrupted extracted-plan.json removed (${error instanceof Error ? error.message : String(error)}). Re-emitting extraction step.\n`);
|
|
1196
|
+
return null;
|
|
1197
|
+
}
|
|
1198
|
+
}
|
|
1199
|
+
// ── Review-approval gate (go-forward program item 1) ───────────────────────────
|
|
1200
|
+
//
|
|
1201
|
+
// Between the audit findings and the contract pipeline, every ORIGINAL finding is
|
|
1202
|
+
// presented to the user bucketed by review-necessity (src/review/reviewGate.ts).
|
|
1203
|
+
// Approved findings seed the pipeline; disapproved findings are excluded from it
|
|
1204
|
+
// AND recorded as a declined disposition (review_decision.json) — never silently
|
|
1205
|
+
// swept to a terminal status inside a quality-tail node, the 2026-06-15 failure
|
|
1206
|
+
// this gate exists to prevent.
|
|
1207
|
+
//
|
|
1208
|
+
// Fires only on Path A (structured_audit) — the only intake path with a
|
|
1209
|
+
// pre-existing finding set; document/conversation runs derive findings inside the
|
|
1210
|
+
// pipeline. File-driven and pre-state (no RemediationState exists at intake yet),
|
|
1211
|
+
// mirroring the intake-clarification gate rather than waiting_for_clarification.
|
|
1212
|
+
const REVIEW_DECISION_SCHEMA_VERSION = "remediate-code-review-decision/v1";
|
|
1213
|
+
/** Stable, informational plan id for the pre-plan review request/decision pair. */
|
|
1214
|
+
const REVIEW_GATE_PLAN_ID = "path-a-review";
|
|
1215
|
+
function reviewRequestPath(artifactsDir) {
|
|
1216
|
+
return join(artifactsDir, "review_request.json");
|
|
1217
|
+
}
|
|
1218
|
+
function reviewResolutionPath(artifactsDir) {
|
|
1219
|
+
return join(artifactsDir, "review_resolution.json");
|
|
1220
|
+
}
|
|
1221
|
+
function reviewDecisionPath(artifactsDir) {
|
|
1222
|
+
return join(artifactsDir, "review_decision.json");
|
|
1223
|
+
}
|
|
1224
|
+
/** Pull the Finding[] out of a parsed audit-findings.json payload. */
|
|
1225
|
+
function extractAuditFindings(parsed) {
|
|
1226
|
+
if (isRecord(parsed) && Array.isArray(parsed.findings)) {
|
|
1227
|
+
return parsed.findings.filter((f) => isRecord(f) && typeof f.id === "string");
|
|
1228
|
+
}
|
|
1229
|
+
return [];
|
|
1230
|
+
}
|
|
1231
|
+
async function handleWaitingForReviewApproval(root, artifactsDir, request) {
|
|
1232
|
+
return writeCurrentStep({
|
|
1233
|
+
stepKind: "collect_review_approval",
|
|
1234
|
+
status: "blocked",
|
|
1235
|
+
runId: randomRunId("REVIEW"),
|
|
1236
|
+
repoRoot: root,
|
|
1237
|
+
artifactsDir,
|
|
1238
|
+
prompt: reviewApprovalPrompt(request, reviewResolutionPath(artifactsDir)),
|
|
1239
|
+
allowedCommands: [loaderCommand("next-step")],
|
|
1240
|
+
stopCondition: "Stop after presenting the findings for approval and collecting the user's approve/disapprove decision, unless the decision is already recorded and the prompt told you to continue.",
|
|
1241
|
+
artifactPaths: {
|
|
1242
|
+
review_request: reviewRequestPath(artifactsDir),
|
|
1243
|
+
review_resolution: reviewResolutionPath(artifactsDir),
|
|
1244
|
+
},
|
|
1245
|
+
});
|
|
1246
|
+
}
|
|
1247
|
+
/**
|
|
1248
|
+
* Run the review-approval gate over the SURVIVOR finding set (already passed
|
|
1249
|
+
* through the single filter pass: deduped, evidence-bearing, path-grounded,
|
|
1250
|
+
* checkpoint-kept). Returns a halt step while awaiting the user's decision, or a
|
|
1251
|
+
* `proceed` splitting the survivors into approved (seed the pipeline) and declined
|
|
1252
|
+
* (recorded, never acted on).
|
|
1253
|
+
*
|
|
1254
|
+
* Idempotent across the many pipeline next-step calls: once review_decision.json
|
|
1255
|
+
* exists the gate consumes it directly and proceeds, so it fires (and halts) at
|
|
1256
|
+
* most once per run. Empty survivors → nothing to review → approve-none/proceed.
|
|
1257
|
+
*/
|
|
1258
|
+
async function runReviewApprovalGate(root, artifactsDir, survivors) {
|
|
1259
|
+
const decisionPath = reviewDecisionPath(artifactsDir);
|
|
1260
|
+
// First crossing only: no decision yet AND the pipeline has not started.
|
|
1261
|
+
const gateOpen = survivors.length > 0 &&
|
|
1262
|
+
!existsSync(decisionPath) &&
|
|
1263
|
+
!contractArtifactExists(artifactsDir, "goal_spec");
|
|
1264
|
+
if (gateOpen) {
|
|
1265
|
+
const resolutionPath = reviewResolutionPath(artifactsDir);
|
|
1266
|
+
const requestPath = reviewRequestPath(artifactsDir);
|
|
1267
|
+
if (!existsSync(resolutionPath)) {
|
|
1268
|
+
// Halt: present the tiered survivors and wait for the user's decision.
|
|
1269
|
+
const request = buildReviewRequest(survivors, REVIEW_GATE_PLAN_ID);
|
|
1270
|
+
await writeJsonFile(requestPath, request);
|
|
1271
|
+
return {
|
|
1272
|
+
kind: "halt",
|
|
1273
|
+
step: await handleWaitingForReviewApproval(root, artifactsDir, request),
|
|
1274
|
+
};
|
|
1275
|
+
}
|
|
1276
|
+
// Consume the resolution into a durable, reasoned decision record.
|
|
1277
|
+
const request = (await readOptionalJsonFile(requestPath)) ??
|
|
1278
|
+
buildReviewRequest(survivors, REVIEW_GATE_PLAN_ID);
|
|
1279
|
+
const resolution = await readOptionalJsonFile(resolutionPath);
|
|
1280
|
+
const decision = applyReviewResolution(request, resolution);
|
|
1281
|
+
const record = {
|
|
1282
|
+
schema_version: REVIEW_DECISION_SCHEMA_VERSION,
|
|
1283
|
+
plan_id: REVIEW_GATE_PLAN_ID,
|
|
1284
|
+
approved_ids: decision.approved_ids,
|
|
1285
|
+
declined: decision.declined,
|
|
1286
|
+
created_at: new Date().toISOString(),
|
|
1287
|
+
};
|
|
1288
|
+
await writeJsonFile(decisionPath, record);
|
|
1289
|
+
// Archive the consumed inputs so the gate cannot re-halt.
|
|
1290
|
+
for (const p of [resolutionPath, requestPath]) {
|
|
1291
|
+
if (existsSync(p)) {
|
|
1292
|
+
await withFsRetry(() => rename(p, `${p}.consumed-${Date.now()}`));
|
|
1293
|
+
}
|
|
1294
|
+
}
|
|
1295
|
+
}
|
|
1296
|
+
// Decision recorded (now or on a prior call): split the survivors.
|
|
1297
|
+
const decision = await readOptionalJsonFile(decisionPath);
|
|
1298
|
+
const declined = decision?.declined ?? [];
|
|
1299
|
+
const declinedIds = new Set(declined.map((d) => d.finding_id));
|
|
1300
|
+
return {
|
|
1301
|
+
kind: "proceed",
|
|
1302
|
+
approved: survivors.filter((f) => !declinedIds.has(f.id)),
|
|
1303
|
+
declined,
|
|
1304
|
+
};
|
|
1305
|
+
}
|
|
1306
|
+
// ── Path-A filter dispositions (persisted for the coverage ledger) ──────────────
|
|
1307
|
+
// The single filter pass runs at intake over the ORIGINAL findings; its
|
|
1308
|
+
// dispositions are persisted here so handlePendingExtractedPlan can build the
|
|
1309
|
+
// coverage ledger over the originals (every audit finding → exactly one
|
|
1310
|
+
// disposition), even though it runs after the pipeline has collapsed the approved
|
|
1311
|
+
// survivors into DAG nodes. Maps are serialized as entry arrays for JSON.
|
|
1312
|
+
const REVIEW_FILTER_DISPOSITIONS_FILENAME = "review_filter_dispositions.json";
|
|
1313
|
+
function reviewFilterDispositionsPath(artifactsDir) {
|
|
1314
|
+
return join(artifactsDir, REVIEW_FILTER_DISPOSITIONS_FILENAME);
|
|
1315
|
+
}
|
|
1316
|
+
async function persistReviewFilterDispositions(artifactsDir, originals, filter) {
|
|
1317
|
+
const payload = {
|
|
1318
|
+
originals,
|
|
1319
|
+
mergeMap: [...filter.mergeMap.entries()],
|
|
1320
|
+
droppedNoEvidence: filter.droppedNoEvidence,
|
|
1321
|
+
droppedPhantomPaths: [...filter.droppedPhantomPaths.entries()],
|
|
1322
|
+
phantomPathsRemoved: [...filter.phantomPathsRemoved.entries()],
|
|
1323
|
+
droppedByCheckpoint: filter.droppedByCheckpoint,
|
|
1324
|
+
};
|
|
1325
|
+
await writeJsonFile(reviewFilterDispositionsPath(artifactsDir), payload);
|
|
1326
|
+
}
|
|
1327
|
+
async function handleReadyIntakeContractPipeline(root, artifactsDir) {
|
|
1328
|
+
// Fast path: if an extracted-plan.json already exists (pipeline complete or
|
|
1329
|
+
// promoted from a previous contract pipeline run), consume it directly without
|
|
1330
|
+
// requiring intake artifacts. This handles both "plan promoted, ready to
|
|
1331
|
+
// ground+plan" and the grounding tests that write extracted-plan.json directly.
|
|
1332
|
+
const earlyExtractedPlan = await readExtractedPlanIfPresent(artifactsDir);
|
|
1333
|
+
if (earlyExtractedPlan) {
|
|
1334
|
+
return handlePendingExtractedPlan(root, artifactsDir, { status: "pending" }, earlyExtractedPlan);
|
|
1335
|
+
}
|
|
1336
|
+
const intake = await readIntakeArtifacts(artifactsDir);
|
|
1337
|
+
if (!intake.summary || !isIntakeReady(intake.summary)) {
|
|
1338
|
+
return null;
|
|
1339
|
+
}
|
|
1340
|
+
const pipeline = shouldEnterContractPipeline(artifactsDir, intake.summary.source_type);
|
|
1341
|
+
if (!pipeline.shouldHandleContractPipeline) {
|
|
1342
|
+
return null;
|
|
1343
|
+
}
|
|
1344
|
+
// Path A: run the single filter pass over the ORIGINAL findings, present the
|
|
1345
|
+
// SURVIVORS at the review gate (deduped / evidence-bearing / path-grounded /
|
|
1346
|
+
// checkpoint-kept, tiered by review-necessity), then seed the pipeline with the
|
|
1347
|
+
// approved survivors. The filter dispositions are persisted so the coverage
|
|
1348
|
+
// ledger is built over the originals (every audit finding → exactly one
|
|
1349
|
+
// disposition). The gate may halt to collect the user's decision.
|
|
1350
|
+
let reviewSourceSwap;
|
|
1351
|
+
if (intake.summary.source_type === "structured_audit" && intake.manifest) {
|
|
1352
|
+
const auditSource = resolveManifestSources(root, intake.manifest).resolved.find((s) => s.type === "structured_audit");
|
|
1353
|
+
if (auditSource) {
|
|
1354
|
+
let auditFindings;
|
|
1355
|
+
try {
|
|
1356
|
+
auditFindings = JSON.parse(await readFile(auditSource.path, "utf8"));
|
|
1357
|
+
}
|
|
1358
|
+
catch {
|
|
1359
|
+
auditFindings = undefined;
|
|
1360
|
+
}
|
|
1361
|
+
const originals = extractAuditFindings(auditFindings);
|
|
1362
|
+
if (originals.length > 0) {
|
|
1363
|
+
const checkpoint = await readOptionalJsonFile(join(artifactsDir, "intent_checkpoint.json"));
|
|
1364
|
+
const filter = await runFindingFilterPass(originals, {
|
|
1365
|
+
root,
|
|
1366
|
+
checkpoint: checkpoint ?? undefined,
|
|
1367
|
+
evidenceGrounding: true,
|
|
1368
|
+
});
|
|
1369
|
+
const gate = await runReviewApprovalGate(root, artifactsDir, filter.survivors);
|
|
1370
|
+
if (gate.kind === "halt") {
|
|
1371
|
+
return gate.step;
|
|
1372
|
+
}
|
|
1373
|
+
// Persist the filter dispositions so coverage is built over the originals.
|
|
1374
|
+
await persistReviewFilterDispositions(artifactsDir, originals, filter);
|
|
1375
|
+
// A1 — conservative lean fast path. When the approved set is a handful
|
|
1376
|
+
// of grounded, high-confidence, localized, non-cross-cutting findings,
|
|
1377
|
+
// skip the contract pipeline and synthesize the extracted plan directly;
|
|
1378
|
+
// the plan→implement→close machinery (per-node verify-before-merge + the
|
|
1379
|
+
// final whole-repo gate) is the retained safety net. Any doubt routes to
|
|
1380
|
+
// the full pipeline below. Runs only here — on Path A (structured_audit),
|
|
1381
|
+
// the only intake with a pre-existing finding set to judge.
|
|
1382
|
+
const fast = evaluateFastPath(gate.approved);
|
|
1383
|
+
if (fast.eligible) {
|
|
1384
|
+
const leanPlan = buildLeanExtractedPlan(gate.approved, randomRunId("LEAN"));
|
|
1385
|
+
await writeJsonFile(intakePaths(artifactsDir).extractedPlan, leanPlan);
|
|
1386
|
+
process.stderr.write(`[remediate-code] Lean fast path: ${fast.reason}. Skipping the contract pipeline; routing straight to plan→implement.\n`);
|
|
1387
|
+
const planned = await handlePendingExtractedPlan(root, artifactsDir, { status: "pending" }, leanPlan);
|
|
1388
|
+
if (planned) {
|
|
1389
|
+
return planned;
|
|
1390
|
+
}
|
|
1391
|
+
// Defensive: a deterministically-built lean plan should always
|
|
1392
|
+
// normalize. If it somehow didn't, handlePendingExtractedPlan removed
|
|
1393
|
+
// the file; fall through to the full pipeline (the safety net) rather
|
|
1394
|
+
// than stalling the run.
|
|
1395
|
+
process.stderr.write("[remediate-code] Lean fast-path plan failed to materialize; falling back to the contract pipeline.\n");
|
|
1396
|
+
}
|
|
1397
|
+
// Seed the pipeline with the approved survivors only. When that set is
|
|
1398
|
+
// narrower than the originals (anything filtered or declined), route the
|
|
1399
|
+
// seed AND the pipeline's source inputs at a filtered file so a removed
|
|
1400
|
+
// finding can never re-enter via the raw audit-findings.json (tool-enforced).
|
|
1401
|
+
const approvedPayload = isRecord(auditFindings)
|
|
1402
|
+
? { ...auditFindings, findings: gate.approved }
|
|
1403
|
+
: { findings: gate.approved };
|
|
1404
|
+
let seedSourcePath = auditSource.path;
|
|
1405
|
+
if (gate.approved.length < originals.length) {
|
|
1406
|
+
await mkdir(contractPipelineDir(artifactsDir), { recursive: true });
|
|
1407
|
+
seedSourcePath = join(contractPipelineDir(artifactsDir), "approved-findings.json");
|
|
1408
|
+
await writeJsonFile(seedSourcePath, approvedPayload);
|
|
1409
|
+
reviewSourceSwap = { from: auditSource.path, to: seedSourcePath };
|
|
1410
|
+
}
|
|
1411
|
+
try {
|
|
1412
|
+
await writePathASeedFromFindings(artifactsDir, seedSourcePath, approvedPayload);
|
|
1413
|
+
}
|
|
1414
|
+
catch {
|
|
1415
|
+
// If the seed cannot be written, the pipeline still runs; the LLM
|
|
1416
|
+
// phases use the source files from sourcePaths.
|
|
1417
|
+
}
|
|
1418
|
+
}
|
|
1419
|
+
}
|
|
1420
|
+
}
|
|
1421
|
+
const paths = intakePaths(artifactsDir);
|
|
1422
|
+
const sourcePaths = new Set();
|
|
1423
|
+
if (existsSync(paths.brief)) {
|
|
1424
|
+
sourcePaths.add(paths.brief);
|
|
1425
|
+
}
|
|
1426
|
+
if (intake.manifest) {
|
|
1427
|
+
for (const source of resolveManifestSources(root, intake.manifest).resolved) {
|
|
1428
|
+
// Swap the raw audit-findings.json for the approved-only filtered file so a
|
|
1429
|
+
// declined finding can never re-enter the pipeline as a source input.
|
|
1430
|
+
sourcePaths.add(reviewSourceSwap && source.path === reviewSourceSwap.from
|
|
1431
|
+
? reviewSourceSwap.to
|
|
1432
|
+
: source.path);
|
|
1433
|
+
}
|
|
1434
|
+
}
|
|
1435
|
+
const step = await buildNextContractPipelineStep({
|
|
1436
|
+
root,
|
|
1437
|
+
artifactsDir,
|
|
1438
|
+
runId: randomRunId("CONTRACT"),
|
|
1439
|
+
sourcePaths: [...sourcePaths],
|
|
1440
|
+
});
|
|
1441
|
+
if (step) {
|
|
1442
|
+
return step;
|
|
1443
|
+
}
|
|
1444
|
+
const extractedPlan = await readExtractedPlanIfPresent(artifactsDir);
|
|
1445
|
+
if (!extractedPlan) {
|
|
1446
|
+
return null;
|
|
1447
|
+
}
|
|
1448
|
+
return handlePendingExtractedPlan(root, artifactsDir, { status: "pending" }, extractedPlan);
|
|
1449
|
+
}
|
|
1450
|
+
async function handlePendingIntake(root, artifactsDir, options) {
|
|
1451
|
+
// Short-circuit: if an extracted-plan.json already exists (promoted from the
|
|
1452
|
+
// contract pipeline), consume it directly without requiring intake artifacts.
|
|
1453
|
+
// This allows decideNextStep to resume a plan-grounding pass even when the
|
|
1454
|
+
// full intake artifact set is no longer present.
|
|
1455
|
+
const earlyExtractedPlan = await readExtractedPlanIfPresent(artifactsDir);
|
|
1456
|
+
if (earlyExtractedPlan) {
|
|
1457
|
+
return handleReadyIntakeContractPipeline(root, artifactsDir);
|
|
1458
|
+
}
|
|
1459
|
+
const inputResolution = resolveInputPaths(root, options.input);
|
|
1460
|
+
const intakeResult = await resolveIntakeStep({
|
|
1461
|
+
root,
|
|
1462
|
+
artifactsDir,
|
|
1463
|
+
input: options.input,
|
|
1464
|
+
inputResolution,
|
|
1465
|
+
loaderCommand,
|
|
1466
|
+
randomRunId,
|
|
1467
|
+
collectStartingPointPrompt,
|
|
1468
|
+
synthesizeIntakePrompt,
|
|
1469
|
+
collectIntakeClarificationsPrompt,
|
|
1470
|
+
});
|
|
1471
|
+
if (intakeResult.kind === "step") {
|
|
1472
|
+
return intakeResult.step;
|
|
1473
|
+
}
|
|
1474
|
+
// Intake is complete — route both paths through the contract pipeline.
|
|
1475
|
+
return handleReadyIntakeContractPipeline(root, artifactsDir);
|
|
1476
|
+
}
|
|
1477
|
+
async function handleNoState(root, artifactsDir) {
|
|
1478
|
+
const paths = intakePaths(artifactsDir);
|
|
1479
|
+
return writeCurrentStep({
|
|
1480
|
+
stepKind: "collect_starting_point",
|
|
1481
|
+
status: "blocked",
|
|
1482
|
+
runId: randomRunId("INPUT"),
|
|
1483
|
+
repoRoot: root,
|
|
1484
|
+
artifactsDir,
|
|
1485
|
+
prompt: collectStartingPointPrompt(root, defaultInputCandidates(root), [], paths),
|
|
1486
|
+
allowedCommands: [loaderCommand("next-step"), loaderCommand("next-step --input <path>")],
|
|
1487
|
+
stopCondition: "Stop after collecting a remediation starting point and rerunning next-step.",
|
|
1488
|
+
artifactPaths: {
|
|
1489
|
+
source_manifest: paths.sourceManifest,
|
|
1490
|
+
conversation_start: paths.conversationStart,
|
|
1491
|
+
},
|
|
1492
|
+
});
|
|
1493
|
+
}
|
|
1494
|
+
async function handleInputConflict(root, artifactsDir, state, inputResolution) {
|
|
1495
|
+
const planId = state.plan?.plan_id ?? "(none)";
|
|
1496
|
+
const itemCount = state.items ? Object.keys(state.items).length : 0;
|
|
1497
|
+
const suppliedInline = inputResolution.checked.length > 0
|
|
1498
|
+
? inputResolution.checked.map((p) => `\`${p}\``).join(", ")
|
|
1499
|
+
: "(input supplied)";
|
|
1500
|
+
return writeCurrentStep({
|
|
1501
|
+
stepKind: "input_conflict",
|
|
1502
|
+
status: "blocked",
|
|
1503
|
+
runId: stateRunId(state),
|
|
1504
|
+
repoRoot: root,
|
|
1505
|
+
artifactsDir,
|
|
1506
|
+
prompt: `
|
|
1507
|
+
# New \`--input\` given, but a remediation run is already in progress
|
|
1508
|
+
|
|
1509
|
+
A remediation run already exists in \`${artifactsDir}\` and has advanced past intake,
|
|
1510
|
+
so the new \`--input\` you passed will **not** replace it — it would be ignored and the
|
|
1511
|
+
existing plan resumed.
|
|
1512
|
+
|
|
1513
|
+
- **Current state**: \`${state.status}\`
|
|
1514
|
+
- **Plan**: \`${planId}\` (${itemCount} item(s))
|
|
1515
|
+
- **Supplied input**: ${suppliedInline}
|
|
1516
|
+
|
|
1517
|
+
Choose one explicitly and report the choice to the user:
|
|
1518
|
+
|
|
1519
|
+
1. **Resume the existing run** — re-run WITHOUT \`--input\`: \`${loaderCommand("next-step")}\`
|
|
1520
|
+
2. **Start fresh from the new input** — first move aside or delete the existing
|
|
1521
|
+
\`${artifactsDir}\` directory (and the stale \`remediation-report.md\` /
|
|
1522
|
+
\`remediation-report.json\` in \`.audit-tools/\`, which would otherwise be overwritten on completion),
|
|
1523
|
+
then re-run \`${loaderCommand("next-step --input <path>")}\`.
|
|
1524
|
+
|
|
1525
|
+
Stop after presenting this choice. Do not advance the run until the user decides.
|
|
1526
|
+
`,
|
|
1527
|
+
allowedCommands: [
|
|
1528
|
+
loaderCommand("next-step"),
|
|
1529
|
+
loaderCommand("next-step --input <path>"),
|
|
1530
|
+
],
|
|
1531
|
+
stopCondition: "Stop after presenting the resume-vs-restart choice to the user.",
|
|
1532
|
+
artifactPaths: {
|
|
1533
|
+
state_file: join(artifactsDir, "state.json"),
|
|
1534
|
+
},
|
|
1535
|
+
});
|
|
1536
|
+
}
|
|
1537
|
+
function normalizePlanClarificationResolutions(value) {
|
|
1538
|
+
if (Array.isArray(value)) {
|
|
1539
|
+
return value.filter(isRecord).flatMap((entry) => {
|
|
1540
|
+
if (typeof entry.finding_id === "string" &&
|
|
1541
|
+
(entry.action === "clarified" || entry.action === "deemed_inappropriate")) {
|
|
1542
|
+
return [
|
|
1543
|
+
{
|
|
1544
|
+
finding_id: entry.finding_id,
|
|
1545
|
+
action: entry.action,
|
|
1546
|
+
rationale: typeof entry.rationale === "string" ? entry.rationale : undefined,
|
|
1547
|
+
},
|
|
1548
|
+
];
|
|
1549
|
+
}
|
|
1550
|
+
return [];
|
|
1551
|
+
});
|
|
1552
|
+
}
|
|
1553
|
+
if (!isRecord(value))
|
|
1554
|
+
return [];
|
|
1555
|
+
if (Array.isArray(value.resolutions)) {
|
|
1556
|
+
return normalizePlanClarificationResolutions(value.resolutions);
|
|
1557
|
+
}
|
|
1558
|
+
if (Array.isArray(value.items)) {
|
|
1559
|
+
return normalizePlanClarificationResolutions(value.items);
|
|
1560
|
+
}
|
|
1561
|
+
return Object.entries(value).flatMap(([findingId, entry]) => {
|
|
1562
|
+
if (!isRecord(entry))
|
|
1563
|
+
return [];
|
|
1564
|
+
if (entry.action !== "clarified" && entry.action !== "deemed_inappropriate")
|
|
1565
|
+
return [];
|
|
1566
|
+
return [{
|
|
1567
|
+
finding_id: typeof entry.finding_id === "string" ? entry.finding_id : findingId,
|
|
1568
|
+
action: entry.action,
|
|
1569
|
+
rationale: typeof entry.rationale === "string" ? entry.rationale : undefined,
|
|
1570
|
+
}];
|
|
1571
|
+
});
|
|
1572
|
+
}
|
|
1573
|
+
/**
|
|
1574
|
+
* Consume clarification_resolution.json for plan-phase clarifications.
|
|
1575
|
+
* Mirrors the triage resolution consume: deemed_inappropriate → terminal,
|
|
1576
|
+
* clarified → re-open (pending) for implement dispatch. Archives the file.
|
|
1577
|
+
*/
|
|
1578
|
+
async function applyPlanClarificationResolution(artifactsDir, state, store) {
|
|
1579
|
+
if (!state.plan || !state.items)
|
|
1580
|
+
return state;
|
|
1581
|
+
const resolutionPath = join(artifactsDir, "clarification_resolution.json");
|
|
1582
|
+
const resolutions = normalizePlanClarificationResolutions(await readOptionalJsonFile(resolutionPath));
|
|
1583
|
+
const now = new Date().toISOString();
|
|
1584
|
+
for (const res of resolutions) {
|
|
1585
|
+
const item = state.items[res.finding_id];
|
|
1586
|
+
if (!item)
|
|
1587
|
+
continue;
|
|
1588
|
+
if (res.action === "deemed_inappropriate") {
|
|
1589
|
+
item.status = "deemed_inappropriate";
|
|
1590
|
+
item.failure_reason = res.rationale;
|
|
1591
|
+
item.started_at ??= now;
|
|
1592
|
+
item.completed_at = now;
|
|
1593
|
+
}
|
|
1594
|
+
else {
|
|
1595
|
+
item.status = "pending";
|
|
1596
|
+
item.clarification_context = res.rationale;
|
|
1597
|
+
}
|
|
1598
|
+
}
|
|
1599
|
+
if (existsSync(resolutionPath)) {
|
|
1600
|
+
await withFsRetry(() => rename(resolutionPath, `${resolutionPath}.consumed-${Date.now()}`));
|
|
1601
|
+
}
|
|
1602
|
+
const remainingPending = state.plan.findings.some((f) => state.items?.[f.id]?.status === "pending");
|
|
1603
|
+
state.status = remainingPending ? "implementing" : "closing";
|
|
1604
|
+
state.clarifications = [];
|
|
1605
|
+
state.closing_plan ??= { action: "none" };
|
|
1606
|
+
await store.saveState(state);
|
|
1607
|
+
return state;
|
|
1608
|
+
}
|
|
1609
|
+
async function handleWaitingForClarification(root, artifactsDir, state) {
|
|
1610
|
+
const clarifications = state.clarifications ??
|
|
1611
|
+
(await readOptionalJsonFile(join(artifactsDir, "clarification_request.json"))) ??
|
|
1612
|
+
[];
|
|
1613
|
+
const resolutionPath = join(artifactsDir, "clarification_resolution.json");
|
|
1614
|
+
return writeCurrentStep({
|
|
1615
|
+
stepKind: "collect_clarifications",
|
|
1616
|
+
status: "blocked",
|
|
1617
|
+
runId: stateRunId(state),
|
|
1618
|
+
repoRoot: root,
|
|
1619
|
+
artifactsDir,
|
|
1620
|
+
prompt: clarificationPrompt(clarifications, resolutionPath),
|
|
1621
|
+
allowedCommands: [loaderCommand("next-step")],
|
|
1622
|
+
stopCondition: "Stop after asking the user for clarification answers, unless the answers are already available and the prompt told you to continue.",
|
|
1623
|
+
artifactPaths: {
|
|
1624
|
+
clarification_request: join(artifactsDir, "clarification_request.json"),
|
|
1625
|
+
clarification_resolution: resolutionPath,
|
|
1626
|
+
},
|
|
1627
|
+
});
|
|
1628
|
+
}
|
|
1629
|
+
async function handleWaitingForTriage(root, artifactsDir, state) {
|
|
1630
|
+
const resolutionPath = join(artifactsDir, "triage_resolution.json");
|
|
1631
|
+
return writeCurrentStep({
|
|
1632
|
+
stepKind: "collect_triage",
|
|
1633
|
+
status: "blocked",
|
|
1634
|
+
runId: stateRunId(state),
|
|
1635
|
+
repoRoot: root,
|
|
1636
|
+
artifactsDir,
|
|
1637
|
+
prompt: triagePrompt(state, resolutionPath),
|
|
1638
|
+
allowedCommands: [loaderCommand("next-step")],
|
|
1639
|
+
stopCondition: "Stop after asking the user for triage decisions, unless the decisions are already available and the prompt told you to continue.",
|
|
1640
|
+
artifactPaths: {
|
|
1641
|
+
triage_batch: join(artifactsDir, "triage_batch.json"),
|
|
1642
|
+
triage_resolution: resolutionPath,
|
|
1643
|
+
},
|
|
1644
|
+
});
|
|
1645
|
+
}
|
|
1646
|
+
/** Stable, informational plan id for the Path-B (planning-point) review pair. */
|
|
1647
|
+
const REVIEW_GATE_PLAN_ID_PATH_B = "path-b-review";
|
|
1648
|
+
/**
|
|
1649
|
+
* Path-B (document / conversation) review-necessity gate, fired at the PLANNING
|
|
1650
|
+
* point over the deduped/grounded node findings. Path A records its review
|
|
1651
|
+
* decision at intake over the ORIGINAL findings — before the contract pipeline
|
|
1652
|
+
* collapses them into DAG nodes (`runReviewApprovalGate`). Path B has no
|
|
1653
|
+
* pre-pipeline finding set (its findings are DERIVED inside the pipeline), so it
|
|
1654
|
+
* is gated here instead. The decision is applied to the existing plan state:
|
|
1655
|
+
* declined nodes become a RECORDED terminal disposition (`ignored`) rather than
|
|
1656
|
+
* being silently bulk-dispositioned inside a quality-tail node — the 2026-06-15
|
|
1657
|
+
* failure this gate exists to prevent.
|
|
1658
|
+
*
|
|
1659
|
+
* The caller fires this only when `review_decision.json` is ABSENT, so Path A
|
|
1660
|
+
* (decision already written at intake) never reaches it — no double review.
|
|
1661
|
+
* Returns a halt step while awaiting the user's decision, or null to proceed
|
|
1662
|
+
* (decision recorded, any declined nodes marked terminal).
|
|
1663
|
+
*/
|
|
1664
|
+
async function runPlanningReviewGate(root, artifactsDir, state, store) {
|
|
1665
|
+
const findings = state.plan?.findings ?? [];
|
|
1666
|
+
if (findings.length === 0)
|
|
1667
|
+
return null;
|
|
1668
|
+
const requestPath = reviewRequestPath(artifactsDir);
|
|
1669
|
+
const resolutionPath = reviewResolutionPath(artifactsDir);
|
|
1670
|
+
const decisionPath = reviewDecisionPath(artifactsDir);
|
|
1671
|
+
if (!existsSync(resolutionPath)) {
|
|
1672
|
+
// Halt: present the tiered node findings and wait for the user's decision.
|
|
1673
|
+
const request = buildReviewRequest(findings, REVIEW_GATE_PLAN_ID_PATH_B);
|
|
1674
|
+
await writeJsonFile(requestPath, request);
|
|
1675
|
+
return handleWaitingForReviewApproval(root, artifactsDir, request);
|
|
1676
|
+
}
|
|
1677
|
+
// Resolution present: consume it into a durable, reasoned decision record.
|
|
1678
|
+
const request = (await readOptionalJsonFile(requestPath)) ??
|
|
1679
|
+
buildReviewRequest(findings, REVIEW_GATE_PLAN_ID_PATH_B);
|
|
1680
|
+
const resolution = await readOptionalJsonFile(resolutionPath);
|
|
1681
|
+
const decision = applyReviewResolution(request, resolution);
|
|
1682
|
+
const record = {
|
|
1683
|
+
schema_version: REVIEW_DECISION_SCHEMA_VERSION,
|
|
1684
|
+
plan_id: REVIEW_GATE_PLAN_ID_PATH_B,
|
|
1685
|
+
approved_ids: decision.approved_ids,
|
|
1686
|
+
declined: decision.declined,
|
|
1687
|
+
created_at: new Date().toISOString(),
|
|
1688
|
+
};
|
|
1689
|
+
await writeJsonFile(decisionPath, record);
|
|
1690
|
+
// Archive the consumed inputs so the gate cannot re-halt.
|
|
1691
|
+
for (const p of [resolutionPath, requestPath]) {
|
|
1692
|
+
if (existsSync(p)) {
|
|
1693
|
+
await withFsRetry(() => rename(p, `${p}.consumed-${Date.now()}`));
|
|
1694
|
+
}
|
|
1695
|
+
}
|
|
1696
|
+
// Declined nodes → recorded terminal disposition (never a silent close).
|
|
1697
|
+
let changed = false;
|
|
1698
|
+
for (const { finding_id, reason } of decision.declined) {
|
|
1699
|
+
const it = state.items?.[finding_id];
|
|
1700
|
+
if (it && !isTerminalStatus(it.status)) {
|
|
1701
|
+
const now = new Date().toISOString();
|
|
1702
|
+
it.status = "ignored";
|
|
1703
|
+
it.failure_reason = reason;
|
|
1704
|
+
it.started_at ??= now;
|
|
1705
|
+
it.completed_at = now;
|
|
1706
|
+
changed = true;
|
|
1707
|
+
}
|
|
1708
|
+
}
|
|
1709
|
+
if (changed)
|
|
1710
|
+
await store.saveState(state);
|
|
1711
|
+
return null;
|
|
1712
|
+
}
|
|
1713
|
+
async function handlePlanning(root, artifactsDir, state, store) {
|
|
1714
|
+
// Review-necessity gate (Path B). Path A records its review decision at intake,
|
|
1715
|
+
// over the ORIGINAL findings, before the contract pipeline collapses them into
|
|
1716
|
+
// DAG nodes; Path B (document / conversation) derives findings INSIDE the
|
|
1717
|
+
// pipeline, so it is gated here, at the planning point, over the deduped/
|
|
1718
|
+
// grounded node findings. Fires only when no decision exists yet, so Path A
|
|
1719
|
+
// (decision already written) never double-reviews. Declined nodes get a
|
|
1720
|
+
// recorded terminal disposition.
|
|
1721
|
+
if (state.plan && !existsSync(reviewDecisionPath(artifactsDir))) {
|
|
1722
|
+
const halt = await runPlanningReviewGate(root, artifactsDir, state, store);
|
|
1723
|
+
if (halt)
|
|
1724
|
+
return { kind: "emit", step: halt };
|
|
1725
|
+
}
|
|
1726
|
+
// Document phase dissolved: planning transitions directly to implementing.
|
|
1727
|
+
// The rolling implement dispatch reads item_spec from the plan DAG node when
|
|
1728
|
+
// present, or uses finding context directly when absent.
|
|
1729
|
+
const implementBlocks = implementableBlocks(state);
|
|
1730
|
+
if (implementBlocks.length > 0) {
|
|
1731
|
+
if (state.plan) {
|
|
1732
|
+
const integrity = await checkAffectedFileIntegrity(root, state.plan.findings);
|
|
1733
|
+
if (!integrity.is_clean) {
|
|
1734
|
+
const details = [
|
|
1735
|
+
...integrity.changed.map((p) => `changed: ${p}`),
|
|
1736
|
+
...integrity.missing.map((p) => `missing: ${p}`),
|
|
1737
|
+
...integrity.io_errors.map((p) => `io-error: ${p}`),
|
|
1738
|
+
];
|
|
1739
|
+
const replanCommand = loaderCommand("next-step --force-replan");
|
|
1740
|
+
return { kind: "emit", step: await writeCurrentStep({
|
|
1741
|
+
stepKind: "collect_starting_point",
|
|
1742
|
+
status: "blocked",
|
|
1743
|
+
runId: stateRunId(state),
|
|
1744
|
+
repoRoot: root,
|
|
1745
|
+
artifactsDir,
|
|
1746
|
+
prompt: [
|
|
1747
|
+
"## File integrity check failed",
|
|
1748
|
+
"",
|
|
1749
|
+
"The following files have changed since the remediation plan was created:",
|
|
1750
|
+
...details.map((d) => `- ${d}`),
|
|
1751
|
+
"",
|
|
1752
|
+
"Re-run planning to pick up the current file state before implementation begins.",
|
|
1753
|
+
"Run:",
|
|
1754
|
+
"",
|
|
1755
|
+
`\`${replanCommand}\``,
|
|
1756
|
+
].join("\n"),
|
|
1757
|
+
allowedCommands: [replanCommand],
|
|
1758
|
+
stopCondition: "Stop after re-planning completes.",
|
|
1759
|
+
}) };
|
|
1760
|
+
}
|
|
1761
|
+
}
|
|
1762
|
+
}
|
|
1763
|
+
// Transition directly to implementing — no separate document round.
|
|
1764
|
+
// Any pending item whose node is NOT eligible for any rolling dispatch pass is
|
|
1765
|
+
// dead-ended (INV-RS-01): a prerequisite was skipped/blocked, so its
|
|
1766
|
+
// verified-complete edge can never be satisfied — never dispatch a dependent
|
|
1767
|
+
// against an upstream surface that did not land. Mark it blocked so the run
|
|
1768
|
+
// advances to close rather than looping forever. A node that is merely
|
|
1769
|
+
// waiting on a still-running prerequisite is NOT here (it would appear in a
|
|
1770
|
+
// later eligible pass); only nodes with a permanently-unsatisfiable edge are.
|
|
1771
|
+
if (implementBlocks.length === 0) {
|
|
1772
|
+
for (const block of blockedByUnsatisfiedDependency(state)) {
|
|
1773
|
+
for (const findingId of block.items) {
|
|
1774
|
+
const it = state.items?.[findingId];
|
|
1775
|
+
if (!it || it.status !== "pending")
|
|
1776
|
+
continue;
|
|
1777
|
+
it.status = "blocked";
|
|
1778
|
+
it.failure_reason =
|
|
1779
|
+
it.failure_reason ??
|
|
1780
|
+
"A dependency node did not reach a verified-complete disposition " +
|
|
1781
|
+
"(a prerequisite was skipped, blocked, or the dependencies are cyclic); " +
|
|
1782
|
+
"the rolling scheduler will not dispatch this node against an upstream " +
|
|
1783
|
+
"surface that never landed (INV-RS-01).";
|
|
1784
|
+
}
|
|
1785
|
+
}
|
|
1786
|
+
}
|
|
1787
|
+
state.status = "implementing";
|
|
1788
|
+
await store.saveState(state);
|
|
1789
|
+
return { kind: "transition", state };
|
|
1790
|
+
}
|
|
1791
|
+
async function handleImplementing(root, artifactsDir, state, runLogger, store) {
|
|
1792
|
+
const triageStart = Date.now();
|
|
1793
|
+
runLogger.event({ phase: "next-step", kind: "executor_start", obligation: state.status, note: "triage" });
|
|
1794
|
+
const triaged = await runTriagePhase(state, { root, artifactsDir });
|
|
1795
|
+
runLogger.event({ phase: "next-step", kind: "executor_end", obligation: state.status, note: "triage", duration_ms: Date.now() - triageStart });
|
|
1796
|
+
await store.saveState(triaged);
|
|
1797
|
+
return { kind: "transition", state: triaged };
|
|
1798
|
+
}
|
|
1799
|
+
function hasResolvedItems(state) {
|
|
1800
|
+
return Object.values(state.items ?? {}).some((it) => isVerifiedCompleteStatus(it.status));
|
|
1801
|
+
}
|
|
1802
|
+
async function handleAllTerminalTransition(root, artifactsDir, state, store, options, runLogger) {
|
|
1803
|
+
const gateDisabled = options.skipFinalGate === true ||
|
|
1804
|
+
process.env.REMEDIATE_SKIP_FINAL_GATE === "1" ||
|
|
1805
|
+
process.env.REMEDIATE_SKIP_FINAL_GATE === "true";
|
|
1806
|
+
const sidecar = await readFinalGateSidecar(artifactsDir);
|
|
1807
|
+
// The tool-owned final gate (INV-RS-10) runs at the single all-terminal →
|
|
1808
|
+
// closing funnel, exactly once per arrival here. It is skipped when:
|
|
1809
|
+
// - there is nothing resolved to validate (everything blocked/skipped), or
|
|
1810
|
+
// - the bounded backstop already terminated (CE-003 — never re-run after), or
|
|
1811
|
+
// - it is explicitly disabled for test hermeticity.
|
|
1812
|
+
// The gate is INDEPENDENT of plan.test_command and runs through the
|
|
1813
|
+
// env-scrubbing runTracked path.
|
|
1814
|
+
if (!gateDisabled && !sidecar.terminated && hasResolvedItems(state)) {
|
|
1815
|
+
const gateStart = Date.now();
|
|
1816
|
+
runLogger.event({
|
|
1817
|
+
phase: "next-step",
|
|
1818
|
+
kind: "executor_start",
|
|
1819
|
+
obligation: state.status,
|
|
1820
|
+
note: "tool_owned_final_gate",
|
|
1821
|
+
});
|
|
1822
|
+
const gate = await runToolOwnedFinalGate(root, { runner: options.finalGateRunner });
|
|
1823
|
+
runLogger.event({
|
|
1824
|
+
phase: "next-step",
|
|
1825
|
+
kind: "executor_end",
|
|
1826
|
+
obligation: state.status,
|
|
1827
|
+
note: `tool_owned_final_gate passed=${gate.passed}`,
|
|
1828
|
+
duration_ms: Date.now() - gateStart,
|
|
1829
|
+
});
|
|
1830
|
+
if (!gate.passed) {
|
|
1831
|
+
// INV-RS-09: a whole-repo gate red is unattributable → coarse re-block.
|
|
1832
|
+
// CE-003: bounded, monotonic auto-terminate to terminal `blocked`.
|
|
1833
|
+
const failedCmd = gate.results.find((r) => !r.passed);
|
|
1834
|
+
const summary = failedCmd
|
|
1835
|
+
? `Failing command: ${failedCmd.argv.join(" ")} (exit ${failedCmd.exit_code}).`
|
|
1836
|
+
: "Tool-owned final gate failed.";
|
|
1837
|
+
const decision = applyCoarseReblock(state, sidecar.count, summary);
|
|
1838
|
+
await writeFinalGateSidecar(artifactsDir, decision.next_count, decision.action === "terminal_blocked");
|
|
1839
|
+
runLogger.event({
|
|
1840
|
+
phase: "next-step",
|
|
1841
|
+
kind: "outcome",
|
|
1842
|
+
obligation: state.status,
|
|
1843
|
+
note: `coarse_reblock action=${decision.action} count=${decision.next_count}`,
|
|
1844
|
+
});
|
|
1845
|
+
// reattempt_all → re-open items to pending and re-run the rolling scheduler
|
|
1846
|
+
// (NEVER the human triage prompt — CE-003 no-human-host path); terminal_blocked
|
|
1847
|
+
// → everything non-skip is now blocked, so close writes the partial report.
|
|
1848
|
+
decision.state.status =
|
|
1849
|
+
decision.action === "reattempt_all" ? "implementing" : "closing";
|
|
1850
|
+
await store.saveState(decision.state);
|
|
1851
|
+
return { kind: "transition", state: decision.state };
|
|
1852
|
+
}
|
|
1853
|
+
}
|
|
1854
|
+
state.status = "closing";
|
|
1855
|
+
await store.saveState(state);
|
|
1856
|
+
return { kind: "transition", state };
|
|
1857
|
+
}
|
|
1858
|
+
async function handleClosing(root, artifactsDir, state, runLogger, store) {
|
|
1859
|
+
const closeStart = Date.now();
|
|
1860
|
+
runLogger.event({ phase: "next-step", kind: "executor_start", obligation: state.status, note: "close" });
|
|
1861
|
+
const closed = await runClosePhase(state, { root, artifactsDir }, runLogger);
|
|
1862
|
+
runLogger.event({ phase: "next-step", kind: "executor_end", obligation: state.status, note: "close", duration_ms: Date.now() - closeStart });
|
|
1863
|
+
if (closed.status !== "complete") {
|
|
1864
|
+
// Not done (preview / re-blocked to triage): persist and re-scan.
|
|
1865
|
+
await store.saveState(closed);
|
|
1866
|
+
return { kind: "transition", state: closed };
|
|
1867
|
+
}
|
|
1868
|
+
// Close-complete CROSSES the engine boundary: `complete` is a pre-intake
|
|
1869
|
+
// obligation, unreachable from a main-engine transition. Emit the durable
|
|
1870
|
+
// report directly, passing exactly what the original recursion reloaded — the
|
|
1871
|
+
// artifact dir is DELETED on a fully-green close (reload → null → randomRunId)
|
|
1872
|
+
// and PRESERVED on a not-green complete (reload → the saved complete state →
|
|
1873
|
+
// its plan_id). `store.loadState()` reproduces both, so present_report is
|
|
1874
|
+
// identical to the cascade. (Regression-locked in next-step-implement-dispatch.)
|
|
1875
|
+
return {
|
|
1876
|
+
kind: "emit",
|
|
1877
|
+
step: await handleComplete(root, artifactsDir, await store.loadState()),
|
|
1878
|
+
};
|
|
1879
|
+
}
|
|
1880
|
+
async function handleZeroDocumentableFindings(root, artifactsDir, state) {
|
|
1881
|
+
const nextStepCommand = loaderCommand("next-step");
|
|
1882
|
+
const nextStepInputCommand = loaderCommand("next-step --input <path>");
|
|
1883
|
+
const checkpointPath = join(artifactsDir, "intent_checkpoint.json");
|
|
1884
|
+
return writeCurrentStep({
|
|
1885
|
+
stepKind: "zero_documentable_findings",
|
|
1886
|
+
status: "blocked",
|
|
1887
|
+
runId: stateRunId(state),
|
|
1888
|
+
repoRoot: root,
|
|
1889
|
+
artifactsDir,
|
|
1890
|
+
prompt: `
|
|
1891
|
+
# No Documentable Findings
|
|
1892
|
+
|
|
1893
|
+
The remediation plan is in the \`planning\` state but there are no findings with
|
|
1894
|
+
status \`pending\` — every finding has already been documented, ignored, or
|
|
1895
|
+
deemed inappropriate.
|
|
1896
|
+
|
|
1897
|
+
Choose one of the following options:
|
|
1898
|
+
|
|
1899
|
+
1. **Adjust or remove the intent checkpoint** — edit or delete
|
|
1900
|
+
\`${checkpointPath}\`, then re-run:
|
|
1901
|
+
|
|
1902
|
+
\`${nextStepCommand}\`
|
|
1903
|
+
|
|
1904
|
+
2. **Supply a different input file** — provide a new audit report or feedback
|
|
1905
|
+
file as the remediation source, then re-run with:
|
|
1906
|
+
|
|
1907
|
+
\`${nextStepInputCommand}\`
|
|
1908
|
+
|
|
1909
|
+
3. **Stop** — no further remediation work is needed. You may stop now.
|
|
1910
|
+
|
|
1911
|
+
Report this situation to the user and let them choose.
|
|
1912
|
+
`,
|
|
1913
|
+
allowedCommands: [nextStepCommand, nextStepInputCommand],
|
|
1914
|
+
stopCondition: "Stop after presenting the three choices to the user and waiting for their decision.",
|
|
1915
|
+
});
|
|
1916
|
+
}
|
|
1917
|
+
async function handleUnhandledState(root, artifactsDir, state) {
|
|
1918
|
+
const itemsByStatus = {};
|
|
1919
|
+
for (const item of Object.values(state.items ?? {})) {
|
|
1920
|
+
(itemsByStatus[item.status] ??= []).push(item.finding_id);
|
|
1921
|
+
}
|
|
1922
|
+
const statusBreakdown = Object.entries(itemsByStatus)
|
|
1923
|
+
.map(([status, ids]) => `- **${status}**: ${ids.join(", ")}`)
|
|
1924
|
+
.join("\n");
|
|
1925
|
+
return writeCurrentStep({
|
|
1926
|
+
stepKind: "unhandled_state",
|
|
1927
|
+
status: "blocked",
|
|
1928
|
+
runId: stateRunId(state),
|
|
1929
|
+
repoRoot: root,
|
|
1930
|
+
artifactsDir,
|
|
1931
|
+
prompt: `
|
|
1932
|
+
# Unhandled State
|
|
1933
|
+
|
|
1934
|
+
The remediation workflow reached a state it has no transition for.
|
|
1935
|
+
|
|
1936
|
+
- **State status**: \`${state.status}\`
|
|
1937
|
+
- **State file**: \`${join(artifactsDir, "state.json")}\`
|
|
1938
|
+
|
|
1939
|
+
## Item Breakdown
|
|
1940
|
+
|
|
1941
|
+
${statusBreakdown || "No items in state."}
|
|
1942
|
+
|
|
1943
|
+
Report this diagnostic to the user and stop. Do not attempt to advance the run.
|
|
1944
|
+
`,
|
|
1945
|
+
allowedCommands: [],
|
|
1946
|
+
stopCondition: "Stop after reporting the diagnostic to the user.",
|
|
1947
|
+
});
|
|
1948
|
+
}
|
|
1949
|
+
export async function decideNextStep(options = {}) {
|
|
1950
|
+
const normalizedOptions = coerceJsonObjectArg(options, "decideNextStep options");
|
|
1951
|
+
const root = resolveRoot(normalizedOptions.root);
|
|
1952
|
+
const artifactsDir = resolveArtifactsDir(root, normalizedOptions.artifactsDir);
|
|
1953
|
+
const sessionConfig = normalizedOptions.sessionConfig ??
|
|
1954
|
+
(await readOptionalJsonFile(join(root, "session-config.json")));
|
|
1955
|
+
const runLogger = new RunLogger(join(artifactsDir, "run.log.jsonl"), {
|
|
1956
|
+
enabled: sessionConfig?.observability?.run_log ?? true,
|
|
1957
|
+
});
|
|
1958
|
+
const startedAt = Date.now();
|
|
1959
|
+
try {
|
|
1960
|
+
const step = await decideNextStepLoop(normalizedOptions, runLogger);
|
|
1961
|
+
runLogger.event({
|
|
1962
|
+
phase: "next-step",
|
|
1963
|
+
kind: "step",
|
|
1964
|
+
obligation: step.step_kind,
|
|
1965
|
+
note: step.status,
|
|
1966
|
+
duration_ms: Date.now() - startedAt,
|
|
1967
|
+
});
|
|
1968
|
+
return step;
|
|
1969
|
+
}
|
|
1970
|
+
catch (error) {
|
|
1971
|
+
runLogger.event({
|
|
1972
|
+
phase: "next-step",
|
|
1973
|
+
kind: "error",
|
|
1974
|
+
duration_ms: Date.now() - startedAt,
|
|
1975
|
+
note: error instanceof Error ? error.message : String(error),
|
|
1976
|
+
});
|
|
1977
|
+
throw error;
|
|
1978
|
+
}
|
|
1979
|
+
}
|
|
1980
|
+
async function buildConfirmResumeOrRestartStep(ctx) {
|
|
1981
|
+
const { root, artifactsDir, state, ackPath } = ctx;
|
|
1982
|
+
const runId = stateRunId(state);
|
|
1983
|
+
const nextCommand = loaderCommand("next-step");
|
|
1984
|
+
const itemsByStatus = {};
|
|
1985
|
+
for (const item of Object.values(state.items ?? {})) {
|
|
1986
|
+
itemsByStatus[item.status] = (itemsByStatus[item.status] ?? 0) + 1;
|
|
1987
|
+
}
|
|
1988
|
+
const statusLines = Object.entries(itemsByStatus)
|
|
1989
|
+
.map(([status, count]) => `- **${status}**: ${count}`)
|
|
1990
|
+
.join("\n");
|
|
1991
|
+
return writeCurrentStep({
|
|
1992
|
+
stepKind: "confirm_resume_or_restart",
|
|
1993
|
+
status: "blocked",
|
|
1994
|
+
runId,
|
|
1995
|
+
repoRoot: root,
|
|
1996
|
+
artifactsDir,
|
|
1997
|
+
prompt: [
|
|
1998
|
+
"# Remediation Run Already In Progress",
|
|
1999
|
+
"",
|
|
2000
|
+
"A remediation run is already in progress. Choose what to do:",
|
|
2001
|
+
"",
|
|
2002
|
+
`- **Current state**: \`${state.status}\``,
|
|
2003
|
+
`- **Plan**: \`${state.plan?.plan_id ?? "(none)"}\``,
|
|
2004
|
+
`- **Started**: ${state.started_at ?? "(unknown)"}`,
|
|
2005
|
+
"",
|
|
2006
|
+
"## Item Counts",
|
|
2007
|
+
"",
|
|
2008
|
+
statusLines || "No items in state.",
|
|
2009
|
+
"",
|
|
2010
|
+
"## Choices",
|
|
2011
|
+
"",
|
|
2012
|
+
"1. **Resume** — continue the existing run. Write to the ack file:",
|
|
2013
|
+
" ```json",
|
|
2014
|
+
' { "choice": "resume" }',
|
|
2015
|
+
" ```",
|
|
2016
|
+
" Then re-run without `--input`:",
|
|
2017
|
+
` \`${nextCommand}\``,
|
|
2018
|
+
"",
|
|
2019
|
+
"2. **Restart from new input** — delete the existing run and start fresh.",
|
|
2020
|
+
" Write to the ack file:",
|
|
2021
|
+
" ```json",
|
|
2022
|
+
' { "choice": "restart" }',
|
|
2023
|
+
" ```",
|
|
2024
|
+
` Then delete \`${artifactsDir}\` and re-run with \`--input <path>\`.`,
|
|
2025
|
+
"",
|
|
2026
|
+
"3. **Merge new recommendations into existing plan** — carry the current plan",
|
|
2027
|
+
" forward with additional findings merged in. Write to the ack file:",
|
|
2028
|
+
" ```json",
|
|
2029
|
+
' { "choice": "merge" }',
|
|
2030
|
+
" ```",
|
|
2031
|
+
` Then re-run with \`--input <path>\` pointing at your new recommendations.`,
|
|
2032
|
+
"",
|
|
2033
|
+
`Write your choice to: \`${ackPath}\``,
|
|
2034
|
+
].join("\n"),
|
|
2035
|
+
allowedCommands: [nextCommand, loaderCommand("next-step --input <path>")],
|
|
2036
|
+
stopCondition: "Stop after presenting the resume/restart/merge choice to the user and writing the ack.",
|
|
2037
|
+
artifactPaths: {
|
|
2038
|
+
state_file: join(artifactsDir, "state.json"),
|
|
2039
|
+
confirm_resume_ack: ackPath,
|
|
2040
|
+
},
|
|
2041
|
+
});
|
|
2042
|
+
}
|
|
2043
|
+
async function buildConfirmIntentStep(ctx) {
|
|
2044
|
+
const { root, artifactsDir, state } = ctx;
|
|
2045
|
+
const runId = stateRunId(state);
|
|
2046
|
+
const nextCommand = loaderCommand("next-step");
|
|
2047
|
+
const checkpointPath = join(artifactsDir, "intent_checkpoint.json");
|
|
2048
|
+
// Read the pre-drafted checkpoint if one exists (confirmed_by: "draft").
|
|
2049
|
+
const draft = await readOptionalJsonFile(checkpointPath);
|
|
2050
|
+
const isDraft = draft?.confirmed_by === "draft";
|
|
2051
|
+
let prompt;
|
|
2052
|
+
if (isDraft && draft) {
|
|
2053
|
+
// Build a consolidated single-stop proposal from the draft.
|
|
2054
|
+
const draftRaw = draft;
|
|
2055
|
+
const preDraftQuestions = Array.isArray(draftRaw.pre_draft_questions)
|
|
2056
|
+
? draftRaw.pre_draft_questions
|
|
2057
|
+
: [];
|
|
2058
|
+
// INV-remediate-state-06: only explicit blocking===true is blocking.
|
|
2059
|
+
const blockingQs = preDraftQuestions.filter((q) => q.blocking === true);
|
|
2060
|
+
const nonBlockingQs = preDraftQuestions.filter((q) => q.blocking !== true);
|
|
2061
|
+
const intentInterpretation = typeof draftRaw.intent_interpretation === "string" ? draftRaw.intent_interpretation : undefined;
|
|
2062
|
+
const suggestedClosingAction = typeof draftRaw.closing_action === "string" ? draftRaw.closing_action : undefined;
|
|
2063
|
+
const questionLines = [
|
|
2064
|
+
...blockingQs.map((q) => `- **[blocking] ${q.id}**: ${q.question}`),
|
|
2065
|
+
...nonBlockingQs.map((q) => `- **[FYI] ${q.id}**: ${q.question}`),
|
|
2066
|
+
].join("\n") || "- None";
|
|
2067
|
+
const filtersBlock = draft.filters && Object.keys(draft.filters).length > 0
|
|
2068
|
+
? `\`\`\`json\n${JSON.stringify(draft.filters, null, 2)}\n\`\`\``
|
|
2069
|
+
: "(none — remediating all findings)";
|
|
2070
|
+
const closingOptions = "`commit` or `none`";
|
|
2071
|
+
prompt = `
|
|
2072
|
+
# Confirm Remediation Scope and Intent
|
|
2073
|
+
|
|
2074
|
+
The intake worker has pre-populated the following proposal. Review each section
|
|
2075
|
+
and adjust where needed, then confirm by writing the final \`intent_checkpoint.json\`.
|
|
2076
|
+
|
|
2077
|
+
## Proposed Scope
|
|
2078
|
+
|
|
2079
|
+
${draft.scope_summary ?? "(not set)"}
|
|
2080
|
+
|
|
2081
|
+
## Proposed Intent
|
|
2082
|
+
|
|
2083
|
+
${draft.intent_summary ?? "(not set)"}
|
|
2084
|
+
${intentInterpretation ? `\n**How free-form intent was interpreted:** ${intentInterpretation}\n` : ""}
|
|
2085
|
+
## Proposed Filters
|
|
2086
|
+
|
|
2087
|
+
${filtersBlock}
|
|
2088
|
+
|
|
2089
|
+
## Open Questions
|
|
2090
|
+
|
|
2091
|
+
${questionLines}
|
|
2092
|
+
|
|
2093
|
+
## Suggested Closing Action
|
|
2094
|
+
|
|
2095
|
+
${suggestedClosingAction ?? "commit"} (valid options: ${closingOptions})
|
|
2096
|
+
|
|
2097
|
+
---
|
|
2098
|
+
|
|
2099
|
+
To confirm, write the final checkpoint to:
|
|
2100
|
+
|
|
2101
|
+
\`${checkpointPath}\`
|
|
2102
|
+
|
|
2103
|
+
\`\`\`json
|
|
2104
|
+
{
|
|
2105
|
+
"schema_version": "intent-checkpoint/v1",
|
|
2106
|
+
"confirmed_at": "<ISO-8601 timestamp>",
|
|
2107
|
+
"confirmed_by": "host",
|
|
2108
|
+
"scope_summary": "${draft.scope_summary ?? "<the files/areas in scope>"}",
|
|
2109
|
+
"intent_summary": "${draft.intent_summary ?? "<the goal>"}",
|
|
2110
|
+
"free_form_intent": "<optional: additional guidance>",
|
|
2111
|
+
"filters": ${JSON.stringify(draft.filters ?? {}, null, 2)},
|
|
2112
|
+
"excluded_scope": [],
|
|
2113
|
+
"must_not_touch": []
|
|
2114
|
+
}
|
|
2115
|
+
\`\`\`
|
|
2116
|
+
|
|
2117
|
+
Adjust \`filters\`, \`excluded_scope\`, \`must_not_touch\`, or \`free_form_intent\` to
|
|
2118
|
+
narrow scope. Valid severities: \`critical\`, \`high\`, \`medium\`, \`low\`, \`info\`.
|
|
2119
|
+
Valid lenses: \`correctness\`, \`architecture\`, \`maintainability\`, \`security\`,
|
|
2120
|
+
\`reliability\`, \`performance\`, \`data_integrity\`, \`tests\`, \`operability\`,
|
|
2121
|
+
\`config_deployment\`, \`observability\`.
|
|
2122
|
+
|
|
2123
|
+
Once written with \`"confirmed_by": "host"\`, run:
|
|
2124
|
+
|
|
2125
|
+
\`${nextCommand}\`
|
|
2126
|
+
`;
|
|
2127
|
+
}
|
|
2128
|
+
else {
|
|
2129
|
+
// Fallback for when there is no pre-drafted checkpoint.
|
|
2130
|
+
prompt = `
|
|
2131
|
+
# Confirm Remediation Scope and Intent
|
|
2132
|
+
|
|
2133
|
+
Please review the intake summary at \`.audit-tools/remediation/intake/intake-summary.json\` (and the audit report, if this run consumes one).
|
|
2134
|
+
|
|
2135
|
+
Confirm or refine the remediation scope and intent by writing a valid \`intent_checkpoint.json\` artifact under \`.audit-tools/remediation/\`.
|
|
2136
|
+
|
|
2137
|
+
Only \`scope_summary\` and \`intent_summary\` are required; add the optional fields to narrow what gets remediated:
|
|
2138
|
+
|
|
2139
|
+
\`\`\`json
|
|
2140
|
+
{
|
|
2141
|
+
"schema_version": "intent-checkpoint/v1",
|
|
2142
|
+
"confirmed_at": "<ISO-8601 timestamp>",
|
|
2143
|
+
"confirmed_by": "host",
|
|
2144
|
+
"scope_summary": "<the files/areas in scope>",
|
|
2145
|
+
"intent_summary": "<the goal, e.g. full-remediation / security-only>",
|
|
2146
|
+
"free_form_intent": "<optional: guidance threaded into remediation worker prompts>",
|
|
2147
|
+
"filters": {
|
|
2148
|
+
"severity": ["critical", "high"],
|
|
2149
|
+
"lenses": ["security", "reliability"],
|
|
2150
|
+
"packages": ["<package or path prefix>"],
|
|
2151
|
+
"themes": ["<theme id>"]
|
|
2152
|
+
},
|
|
2153
|
+
"excluded_scope": [{ "path": "<path or prefix>", "reason": "<why>" }],
|
|
2154
|
+
"must_not_touch": ["<glob>"]
|
|
2155
|
+
}
|
|
2156
|
+
\`\`\`
|
|
2157
|
+
|
|
2158
|
+
- \`filters\` drop findings that don't match BEFORE planning, so only the work you want is remediated. Valid severities: \`critical\`, \`high\`, \`medium\`, \`low\`, \`info\`. Valid lenses: \`correctness\`, \`architecture\`, \`maintainability\`, \`security\`, \`reliability\`, \`performance\`, \`data_integrity\`, \`tests\`, \`operability\`, \`config_deployment\`, \`observability\`. Draw \`packages\`/\`themes\` from the findings in the audit report.
|
|
2159
|
+
- \`excluded_scope\` drops findings whose files match a path or directory prefix; \`must_not_touch\` globs are never written.
|
|
2160
|
+
- Skipped findings are listed in the final remediation report under "Skipped by Intent Checkpoint".
|
|
2161
|
+
- Leave the optional fields out to remediate everything in the report.
|
|
2162
|
+
|
|
2163
|
+
Once the file is written, run:
|
|
2164
|
+
|
|
2165
|
+
\`${nextCommand}\`
|
|
2166
|
+
`;
|
|
2167
|
+
}
|
|
2168
|
+
return writeCurrentStep({
|
|
2169
|
+
stepKind: "confirm_intent",
|
|
2170
|
+
status: "ready",
|
|
2171
|
+
runId,
|
|
2172
|
+
repoRoot: root,
|
|
2173
|
+
artifactsDir,
|
|
2174
|
+
prompt,
|
|
2175
|
+
allowedCommands: [nextCommand],
|
|
2176
|
+
stopCondition: "Stop after writing intent_checkpoint.json and running next-step.",
|
|
2177
|
+
artifactPaths: {
|
|
2178
|
+
intent_checkpoint: checkpointPath,
|
|
2179
|
+
},
|
|
2180
|
+
});
|
|
2181
|
+
}
|
|
2182
|
+
// ---------------------------------------------------------------------------
|
|
2183
|
+
// Deterministic free_form_intent interpretation at the call site (INV-S04)
|
|
2184
|
+
// ---------------------------------------------------------------------------
|
|
2185
|
+
//
|
|
2186
|
+
// The IntentCheckpoint contract states `free_form_intent` is "interpreted into
|
|
2187
|
+
// priority/lens/scope signals at planning time via freeFormIntentInterpreter.
|
|
2188
|
+
// Never threaded verbatim into worker or dispatch prompts (INV-S04)." This is
|
|
2189
|
+
// the call site that honours that: when a CONFIRMED checkpoint carries a
|
|
2190
|
+
// free_form_intent, we run the shared deterministic interpreter HERE — never
|
|
2191
|
+
// pass the raw string downstream — and persist the structured signals so
|
|
2192
|
+
// planning consumes the encoded lens-weights/priority/scope, and so the
|
|
2193
|
+
// unencodable clauses are surfaced (never silently dropped) rather than relying
|
|
2194
|
+
// on an LLM-authored free-text `intent_interpretation`.
|
|
2195
|
+
/** Sidecar artifact recording the deterministic interpretation of free_form_intent. */
|
|
2196
|
+
export const INTENT_INTERPRETATION_FILENAME = "intent-interpretation.json";
|
|
2197
|
+
export const INTENT_INTERPRETATION_SCHEMA_VERSION = "remediate-code-intent-interpretation/v1alpha1";
|
|
2198
|
+
/**
|
|
2199
|
+
* Interpret a confirmed checkpoint's `free_form_intent` via the shared
|
|
2200
|
+
* deterministic interpreter and persist the structured signals to a sidecar
|
|
2201
|
+
* artifact. Idempotent and best-effort: returns the persisted interpretation (or
|
|
2202
|
+
* null when there is nothing to interpret / no confirmed checkpoint) and never
|
|
2203
|
+
* throws into the decide loop. The raw `free_form_intent` string is NOT returned
|
|
2204
|
+
* or threaded anywhere — only the structured `InterpretedIntent` is (INV-S04).
|
|
2205
|
+
*/
|
|
2206
|
+
export async function interpretConfirmedCheckpointIntent(artifactsDir, checkpoint) {
|
|
2207
|
+
if (!checkpoint || checkpoint.confirmed_by !== "host")
|
|
2208
|
+
return null;
|
|
2209
|
+
const raw = checkpoint.free_form_intent;
|
|
2210
|
+
if (typeof raw !== "string" || raw.trim().length === 0)
|
|
2211
|
+
return null;
|
|
2212
|
+
const interpreted = interpretFreeFormIntent(raw);
|
|
2213
|
+
const persisted = {
|
|
2214
|
+
schema_version: INTENT_INTERPRETATION_SCHEMA_VERSION,
|
|
2215
|
+
interpreted,
|
|
2216
|
+
unencodable_clauses: interpreted.unencodableClauses,
|
|
2217
|
+
created_at: new Date().toISOString(),
|
|
2218
|
+
};
|
|
2219
|
+
try {
|
|
2220
|
+
await writeJsonFile(join(artifactsDir, INTENT_INTERPRETATION_FILENAME), persisted);
|
|
2221
|
+
}
|
|
2222
|
+
catch {
|
|
2223
|
+
// Best-effort sidecar: a write failure must never block the decide loop.
|
|
2224
|
+
}
|
|
2225
|
+
if (interpreted.unencodableClauses.length > 0) {
|
|
2226
|
+
process.stderr.write(`[remediate-code] free_form_intent: ${interpreted.unencodableClauses.length} ` +
|
|
2227
|
+
`clause(s) could not be encoded as lens/priority/scope signals and are ` +
|
|
2228
|
+
`surfaced for promotion to constraints: ` +
|
|
2229
|
+
`${interpreted.unencodableClauses.join("; ")}\n`);
|
|
2230
|
+
}
|
|
2231
|
+
return persisted;
|
|
2232
|
+
}
|
|
2233
|
+
/**
|
|
2234
|
+
* Narrow a nullable engine state to non-null inside an executor whose `derive`
|
|
2235
|
+
* only marks it actionable when the state is present — a violation is an engine
|
|
2236
|
+
* contract bug, not a runtime condition.
|
|
2237
|
+
*/
|
|
2238
|
+
function requireState(state) {
|
|
2239
|
+
if (!state) {
|
|
2240
|
+
throw new Error("remediate obligation executor reached with a null state — derive() contract violated");
|
|
2241
|
+
}
|
|
2242
|
+
return state;
|
|
2243
|
+
}
|
|
2244
|
+
/**
|
|
2245
|
+
* Priority order for the pre-intake obligations — mirrors the original cascade's
|
|
2246
|
+
* top-down guard order exactly so selection cannot drift.
|
|
2247
|
+
*/
|
|
2248
|
+
const PRE_INTAKE_PRIORITY = [
|
|
2249
|
+
"input_conflict",
|
|
2250
|
+
"confirm_resume",
|
|
2251
|
+
"confirm_intent",
|
|
2252
|
+
"interpret_intent",
|
|
2253
|
+
"complete_redelivery",
|
|
2254
|
+
"report_warning",
|
|
2255
|
+
"complete",
|
|
2256
|
+
"pending_intake",
|
|
2257
|
+
];
|
|
2258
|
+
/**
|
|
2259
|
+
* The linear pre-intake gates as declarative obligations (A3 slice 1). Built per
|
|
2260
|
+
* call so each `derive` can close over `ctx` paths + the pre-read `snapshot` and
|
|
2261
|
+
* read the remaining signals (existsSync, status, inputResolution) synchronously.
|
|
2262
|
+
* The matching executors are the original cascade handlers, classified emit vs
|
|
2263
|
+
* transition; the host-facing behaviour is unchanged.
|
|
2264
|
+
*/
|
|
2265
|
+
function buildPreIntakeObligations(ctx, snapshot) {
|
|
2266
|
+
const { artifactsDir, inputResolution } = ctx;
|
|
2267
|
+
const { existingCheckpoint, resumeAck, entryState } = snapshot;
|
|
2268
|
+
const ip = intakePaths(artifactsDir);
|
|
2269
|
+
const checkpointPath = join(artifactsDir, "intent_checkpoint.json");
|
|
2270
|
+
const ackPath = join(artifactsDir, "confirm_resume_ack.json");
|
|
2271
|
+
const interpretationPath = join(artifactsDir, INTENT_INTERPRETATION_FILENAME);
|
|
2272
|
+
const reportPath = join(dirname(artifactsDir), "remediation-report.md");
|
|
2273
|
+
// Fires at most once per host call; gates the leftover-report warning so a
|
|
2274
|
+
// re-scan after a transition cannot re-print it (mirrors the cascade's
|
|
2275
|
+
// single fall-through hit).
|
|
2276
|
+
const warned = { value: false };
|
|
2277
|
+
return [
|
|
2278
|
+
{
|
|
2279
|
+
// A new --input against a run already past intake must not silently resume
|
|
2280
|
+
// the old plan; require an explicit resume-vs-restart choice. Derives from
|
|
2281
|
+
// the frozen entry state — never an intake-created one.
|
|
2282
|
+
id: "input_conflict",
|
|
2283
|
+
derive: () => inputResolution.supplied &&
|
|
2284
|
+
entryState != null &&
|
|
2285
|
+
entryState.status !== "pending"
|
|
2286
|
+
? "missing"
|
|
2287
|
+
: "satisfied",
|
|
2288
|
+
execute: async (_state, c) => {
|
|
2289
|
+
const s = requireState(entryState);
|
|
2290
|
+
await c.countStep(s);
|
|
2291
|
+
return {
|
|
2292
|
+
kind: "emit",
|
|
2293
|
+
step: await handleInputConflict(c.root, c.artifactsDir, s, c.inputResolution),
|
|
2294
|
+
};
|
|
2295
|
+
},
|
|
2296
|
+
},
|
|
2297
|
+
{
|
|
2298
|
+
// Bare re-invocation of an in-progress run: present resume/restart/merge
|
|
2299
|
+
// once (gated on the ack file) rather than silently resuming. An ack of
|
|
2300
|
+
// choice==='resume' is satisfied — fall through to normal dispatch. Derives
|
|
2301
|
+
// from the frozen entry state (a resume is of a *pre-existing* run).
|
|
2302
|
+
id: "confirm_resume",
|
|
2303
|
+
derive: () => {
|
|
2304
|
+
if (inputResolution.supplied ||
|
|
2305
|
+
entryState == null ||
|
|
2306
|
+
entryState.status === "complete" ||
|
|
2307
|
+
entryState.status === "pending") {
|
|
2308
|
+
return "satisfied";
|
|
2309
|
+
}
|
|
2310
|
+
return !resumeAck || resumeAck.choice !== "resume" ? "missing" : "satisfied";
|
|
2311
|
+
},
|
|
2312
|
+
execute: async (_state, c) => {
|
|
2313
|
+
const s = requireState(entryState);
|
|
2314
|
+
await c.countStep(s);
|
|
2315
|
+
return {
|
|
2316
|
+
kind: "emit",
|
|
2317
|
+
step: await buildConfirmResumeOrRestartStep({
|
|
2318
|
+
root: c.root,
|
|
2319
|
+
artifactsDir: c.artifactsDir,
|
|
2320
|
+
state: s,
|
|
2321
|
+
ackPath,
|
|
2322
|
+
}),
|
|
2323
|
+
};
|
|
2324
|
+
},
|
|
2325
|
+
},
|
|
2326
|
+
{
|
|
2327
|
+
// Intent gate: fire when no confirmed checkpoint exists (no checkpoint + any
|
|
2328
|
+
// intake artifact or an active run, or a draft checkpoint). Never for
|
|
2329
|
+
// complete/closing — those already confirmed their checkpoint.
|
|
2330
|
+
id: "confirm_intent",
|
|
2331
|
+
derive: (state) => {
|
|
2332
|
+
const checkpointIsDraft = existingCheckpoint?.confirmed_by === "draft";
|
|
2333
|
+
const activeRunState = state != null &&
|
|
2334
|
+
state.status !== "pending" &&
|
|
2335
|
+
state.status !== "complete" &&
|
|
2336
|
+
state.status !== "closing";
|
|
2337
|
+
const fires = checkpointIsDraft ||
|
|
2338
|
+
(!existsSync(checkpointPath) &&
|
|
2339
|
+
(existsSync(ip.summary) ||
|
|
2340
|
+
existsSync(ip.extractedPlan) ||
|
|
2341
|
+
activeRunState));
|
|
2342
|
+
return fires ? "missing" : "satisfied";
|
|
2343
|
+
},
|
|
2344
|
+
execute: async (state, c) => {
|
|
2345
|
+
await c.countStep(state);
|
|
2346
|
+
return {
|
|
2347
|
+
kind: "emit",
|
|
2348
|
+
step: await buildConfirmIntentStep({
|
|
2349
|
+
root: c.root,
|
|
2350
|
+
artifactsDir: c.artifactsDir,
|
|
2351
|
+
state,
|
|
2352
|
+
}),
|
|
2353
|
+
};
|
|
2354
|
+
},
|
|
2355
|
+
},
|
|
2356
|
+
{
|
|
2357
|
+
// Past the intent gate: interpret the confirmed checkpoint's
|
|
2358
|
+
// free_form_intent once (INV-S04) and persist the structured signals. A
|
|
2359
|
+
// transition (state unchanged) — the re-scan skips it once the sidecar
|
|
2360
|
+
// exists.
|
|
2361
|
+
id: "interpret_intent",
|
|
2362
|
+
derive: () => existingCheckpoint?.confirmed_by === "host" &&
|
|
2363
|
+
typeof existingCheckpoint.free_form_intent === "string" &&
|
|
2364
|
+
existingCheckpoint.free_form_intent.trim().length > 0 &&
|
|
2365
|
+
!existsSync(interpretationPath)
|
|
2366
|
+
? "missing"
|
|
2367
|
+
: "satisfied",
|
|
2368
|
+
execute: async (state) => {
|
|
2369
|
+
await interpretConfirmedCheckpointIntent(artifactsDir, existingCheckpoint);
|
|
2370
|
+
return { kind: "transition", state };
|
|
2371
|
+
},
|
|
2372
|
+
},
|
|
2373
|
+
{
|
|
2374
|
+
// Finished runs delete the artifact dir but leave the root report. A bare
|
|
2375
|
+
// re-invocation with no fresh intent re-presents that report instead of
|
|
2376
|
+
// asking for a new starting point.
|
|
2377
|
+
id: "complete_redelivery",
|
|
2378
|
+
derive: (state) => {
|
|
2379
|
+
if (state != null || inputResolution.supplied || !existsSync(reportPath)) {
|
|
2380
|
+
return "satisfied";
|
|
2381
|
+
}
|
|
2382
|
+
const freshIntent = existsSync(ip.conversationStart) || existsSync(ip.extractedPlan);
|
|
2383
|
+
return freshIntent ? "satisfied" : "missing";
|
|
2384
|
+
},
|
|
2385
|
+
execute: async (state, c) => ({
|
|
2386
|
+
kind: "emit",
|
|
2387
|
+
step: await handleComplete(c.root, c.artifactsDir, state),
|
|
2388
|
+
}),
|
|
2389
|
+
},
|
|
2390
|
+
{
|
|
2391
|
+
// Diagnostic (not a gate): a leftover root report will be overwritten when a
|
|
2392
|
+
// fresh/active run completes. A transition (prints once, state unchanged);
|
|
2393
|
+
// its priority slot — after complete_redelivery, before complete — means a
|
|
2394
|
+
// re-presented/complete run never reaches it, exactly as the cascade's
|
|
2395
|
+
// fall-through ordering did.
|
|
2396
|
+
id: "report_warning",
|
|
2397
|
+
derive: (state) => !warned.value &&
|
|
2398
|
+
existsSync(reportPath) &&
|
|
2399
|
+
state?.status !== "complete"
|
|
2400
|
+
? "missing"
|
|
2401
|
+
: "satisfied",
|
|
2402
|
+
execute: async (state) => {
|
|
2403
|
+
warned.value = true;
|
|
2404
|
+
process.stderr.write("[remediate-code] A previous remediation-report.md exists in .audit-tools/; it will be overwritten when this run completes.\n");
|
|
2405
|
+
return { kind: "transition", state };
|
|
2406
|
+
},
|
|
2407
|
+
},
|
|
2408
|
+
{
|
|
2409
|
+
id: "complete",
|
|
2410
|
+
derive: (state) => (state?.status === "complete" ? "missing" : "satisfied"),
|
|
2411
|
+
execute: async (state, c) => {
|
|
2412
|
+
await c.countStep(state);
|
|
2413
|
+
return {
|
|
2414
|
+
kind: "emit",
|
|
2415
|
+
step: await handleComplete(c.root, c.artifactsDir, state),
|
|
2416
|
+
};
|
|
2417
|
+
},
|
|
2418
|
+
},
|
|
2419
|
+
{
|
|
2420
|
+
// No state yet: resolve intake. A produced step is emitted; a produced state
|
|
2421
|
+
// transitions (the re-scan falls through to the inline tail); a null result
|
|
2422
|
+
// emits the collect-starting-point step (the folded old no-state branch).
|
|
2423
|
+
id: "pending_intake",
|
|
2424
|
+
derive: (state) => (state == null ? "missing" : "satisfied"),
|
|
2425
|
+
execute: async (_state, c) => {
|
|
2426
|
+
const outcome = await handlePendingIntake(c.root, c.artifactsDir, c.options);
|
|
2427
|
+
if (outcome && "step_kind" in outcome) {
|
|
2428
|
+
return { kind: "emit", step: outcome };
|
|
2429
|
+
}
|
|
2430
|
+
if (outcome) {
|
|
2431
|
+
return { kind: "transition", state: outcome };
|
|
2432
|
+
}
|
|
2433
|
+
return { kind: "emit", step: await handleNoState(c.root, c.artifactsDir) };
|
|
2434
|
+
},
|
|
2435
|
+
},
|
|
2436
|
+
];
|
|
2437
|
+
}
|
|
2438
|
+
/**
|
|
2439
|
+
* Priority order for the main (post-intake) obligations — mirrors the original
|
|
2440
|
+
* cascade tail's guard order exactly so selection cannot drift.
|
|
2441
|
+
*/
|
|
2442
|
+
const MAIN_PRIORITY = [
|
|
2443
|
+
"waiting_for_clarification",
|
|
2444
|
+
"waiting_for_triage",
|
|
2445
|
+
"planning_documentable",
|
|
2446
|
+
"partial_terminal",
|
|
2447
|
+
"implementing",
|
|
2448
|
+
"triage",
|
|
2449
|
+
"planning_zero",
|
|
2450
|
+
"all_terminal",
|
|
2451
|
+
"closing",
|
|
2452
|
+
"unhandled",
|
|
2453
|
+
];
|
|
2454
|
+
/**
|
|
2455
|
+
* The post-intake cascade tail as declarative obligations (A3 slice 2). Runs on a
|
|
2456
|
+
* non-null state (pre-intake resolved it). Every phase handler returns a
|
|
2457
|
+
* `RemediateOutcome` — a `transition` (planning→implementing, triage, the
|
|
2458
|
+
* re-block/close funnel, the dispatch merge-then-reenter folds) or an `emit` (a
|
|
2459
|
+
* host-actionable step). `advance` drives the whole fold with ZERO recursion
|
|
2460
|
+
* (slice 2b). The one cross-engine case — `handleClosing` reaching `complete`,
|
|
2461
|
+
* which lives in the pre-intake engine — emits the report directly rather than
|
|
2462
|
+
* transitioning (a main transition could never select it).
|
|
2463
|
+
*/
|
|
2464
|
+
function buildMainObligations(ctx) {
|
|
2465
|
+
const { root, artifactsDir, options, runLogger, store } = ctx;
|
|
2466
|
+
const clarificationResolutionPath = join(artifactsDir, "clarification_resolution.json");
|
|
2467
|
+
const triageResolutionPath = join(artifactsDir, "triage_resolution.json");
|
|
2468
|
+
return [
|
|
2469
|
+
{
|
|
2470
|
+
// Plan-phase clarification wait: apply a resolution if present (transition →
|
|
2471
|
+
// re-scan), else surface the wait step.
|
|
2472
|
+
id: "waiting_for_clarification",
|
|
2473
|
+
derive: (state) => state?.status === "waiting_for_clarification" ? "missing" : "satisfied",
|
|
2474
|
+
execute: async (state) => {
|
|
2475
|
+
const s = requireState(state);
|
|
2476
|
+
if (existsSync(clarificationResolutionPath)) {
|
|
2477
|
+
const next = await applyPlanClarificationResolution(artifactsDir, s, store);
|
|
2478
|
+
return { kind: "transition", state: next };
|
|
2479
|
+
}
|
|
2480
|
+
return {
|
|
2481
|
+
kind: "emit",
|
|
2482
|
+
step: await handleWaitingForClarification(root, artifactsDir, s),
|
|
2483
|
+
};
|
|
2484
|
+
},
|
|
2485
|
+
},
|
|
2486
|
+
{
|
|
2487
|
+
// Triage wait: apply a resolution (→ triage, transition) if present, else
|
|
2488
|
+
// surface the wait step.
|
|
2489
|
+
id: "waiting_for_triage",
|
|
2490
|
+
derive: (state) => state?.status === "waiting_for_triage" ? "missing" : "satisfied",
|
|
2491
|
+
execute: async (state) => {
|
|
2492
|
+
const s = requireState(state);
|
|
2493
|
+
if (existsSync(triageResolutionPath)) {
|
|
2494
|
+
s.status = "triage";
|
|
2495
|
+
await store.saveState(s);
|
|
2496
|
+
return { kind: "transition", state: s };
|
|
2497
|
+
}
|
|
2498
|
+
return {
|
|
2499
|
+
kind: "emit",
|
|
2500
|
+
step: await handleWaitingForTriage(root, artifactsDir, s),
|
|
2501
|
+
};
|
|
2502
|
+
},
|
|
2503
|
+
},
|
|
2504
|
+
{
|
|
2505
|
+
id: "planning_documentable",
|
|
2506
|
+
derive: (state) => state != null &&
|
|
2507
|
+
state.status === "planning" &&
|
|
2508
|
+
documentableFindings(state).length > 0
|
|
2509
|
+
? "missing"
|
|
2510
|
+
: "satisfied",
|
|
2511
|
+
execute: async (state) => handlePlanning(root, artifactsDir, requireState(state), store),
|
|
2512
|
+
},
|
|
2513
|
+
{
|
|
2514
|
+
// Partial-completion terminal consume (OBL-S09 / INV-X06): block the
|
|
2515
|
+
// precisely-named stranded ids + every other non-terminal item (the
|
|
2516
|
+
// no-livelock guarantee), clear the flag, then force the close transition
|
|
2517
|
+
// via handleAllTerminalTransition (blocked is non-terminal, so all_terminal
|
|
2518
|
+
// would not otherwise fire).
|
|
2519
|
+
id: "partial_terminal",
|
|
2520
|
+
derive: (state) => state != null &&
|
|
2521
|
+
state.partial_completion_terminal != null &&
|
|
2522
|
+
!allItemsTerminal(state)
|
|
2523
|
+
? "missing"
|
|
2524
|
+
: "satisfied",
|
|
2525
|
+
execute: async (state) => {
|
|
2526
|
+
const s = requireState(state);
|
|
2527
|
+
const terminal = s.partial_completion_terminal;
|
|
2528
|
+
if (!terminal)
|
|
2529
|
+
return { kind: "transition", state: s };
|
|
2530
|
+
const strandedSet = new Set(terminal.stranded_ids ?? []);
|
|
2531
|
+
for (const it of Object.values(s.items ?? {})) {
|
|
2532
|
+
if (isTerminalStatus(it.status))
|
|
2533
|
+
continue;
|
|
2534
|
+
it.status = "blocked";
|
|
2535
|
+
const stranded = strandedSet.has(it.finding_id);
|
|
2536
|
+
it.failure_reason =
|
|
2537
|
+
it.failure_reason ??
|
|
2538
|
+
(stranded
|
|
2539
|
+
? `Stranded by partial-completion terminal (${terminal.reason}): the provider pool was exhausted before this item could be dispatched (no pool survived re-routing).`
|
|
2540
|
+
: `Blocked after partial-completion terminal (${terminal.reason}): no provider pool remained to dispatch this item.`);
|
|
2541
|
+
}
|
|
2542
|
+
delete s.partial_completion_terminal;
|
|
2543
|
+
await store.saveState(s);
|
|
2544
|
+
return handleAllTerminalTransition(root, artifactsDir, s, store, options, runLogger);
|
|
2545
|
+
},
|
|
2546
|
+
},
|
|
2547
|
+
{
|
|
2548
|
+
id: "implementing",
|
|
2549
|
+
derive: (state) => state?.status === "implementing" ? "missing" : "satisfied",
|
|
2550
|
+
execute: async (state) => {
|
|
2551
|
+
const s = requireState(state);
|
|
2552
|
+
// Pending implementable blocks dispatch; triage only runs once every item
|
|
2553
|
+
// has left "pending".
|
|
2554
|
+
const pendingBlocks = implementableBlocks(s);
|
|
2555
|
+
if (pendingBlocks.length > 0) {
|
|
2556
|
+
return buildImplementDispatchStep({
|
|
2557
|
+
root,
|
|
2558
|
+
artifactsDir,
|
|
2559
|
+
state: s,
|
|
2560
|
+
options,
|
|
2561
|
+
store,
|
|
2562
|
+
});
|
|
2563
|
+
}
|
|
2564
|
+
// Dead-end pending nodes whose dependency never reached verified-complete
|
|
2565
|
+
// (INV-RS-01) so the implementing→triage loop can't livelock; transition
|
|
2566
|
+
// so the engine re-scans on the updated state.
|
|
2567
|
+
const deadEnded = blockedByUnsatisfiedDependency(s);
|
|
2568
|
+
if (deadEnded.length > 0) {
|
|
2569
|
+
const now = new Date().toISOString();
|
|
2570
|
+
let changed = false;
|
|
2571
|
+
for (const block of deadEnded) {
|
|
2572
|
+
for (const findingId of block.items) {
|
|
2573
|
+
const it = s.items?.[findingId];
|
|
2574
|
+
if (!it || it.status !== "pending")
|
|
2575
|
+
continue;
|
|
2576
|
+
it.status = "blocked";
|
|
2577
|
+
it.started_at ??= now;
|
|
2578
|
+
it.completed_at = now;
|
|
2579
|
+
it.failure_reason =
|
|
2580
|
+
it.failure_reason ??
|
|
2581
|
+
"A dependency node did not reach a verified-complete disposition " +
|
|
2582
|
+
"(a prerequisite was skipped, blocked, or the dependencies are cyclic); " +
|
|
2583
|
+
"the rolling scheduler will not dispatch this node (INV-RS-01).";
|
|
2584
|
+
changed = true;
|
|
2585
|
+
}
|
|
2586
|
+
}
|
|
2587
|
+
if (changed) {
|
|
2588
|
+
await store.saveState(s);
|
|
2589
|
+
return { kind: "transition", state: s };
|
|
2590
|
+
}
|
|
2591
|
+
}
|
|
2592
|
+
return handleImplementing(root, artifactsDir, s, runLogger, store);
|
|
2593
|
+
},
|
|
2594
|
+
},
|
|
2595
|
+
{
|
|
2596
|
+
id: "triage",
|
|
2597
|
+
derive: (state) => (state?.status === "triage" ? "missing" : "satisfied"),
|
|
2598
|
+
execute: async (state) => handleImplementing(root, artifactsDir, requireState(state), runLogger, store),
|
|
2599
|
+
},
|
|
2600
|
+
{
|
|
2601
|
+
// planning with zero documentable findings is a user question, not a
|
|
2602
|
+
// dead-end — must fire BEFORE all_terminal so an all-resolved planning state
|
|
2603
|
+
// doesn't silently advance to close.
|
|
2604
|
+
id: "planning_zero",
|
|
2605
|
+
derive: (state) => state != null &&
|
|
2606
|
+
state.status === "planning" &&
|
|
2607
|
+
documentableFindings(state).length === 0
|
|
2608
|
+
? "missing"
|
|
2609
|
+
: "satisfied",
|
|
2610
|
+
execute: async (state) => ({
|
|
2611
|
+
kind: "emit",
|
|
2612
|
+
step: await handleZeroDocumentableFindings(root, artifactsDir, requireState(state)),
|
|
2613
|
+
}),
|
|
2614
|
+
},
|
|
2615
|
+
{
|
|
2616
|
+
id: "all_terminal",
|
|
2617
|
+
derive: (state) => state != null && allItemsTerminal(state) && state.status !== "closing"
|
|
2618
|
+
? "missing"
|
|
2619
|
+
: "satisfied",
|
|
2620
|
+
execute: async (state) => handleAllTerminalTransition(root, artifactsDir, requireState(state), store, options, runLogger),
|
|
2621
|
+
},
|
|
2622
|
+
{
|
|
2623
|
+
id: "closing",
|
|
2624
|
+
derive: (state) => (state?.status === "closing" ? "missing" : "satisfied"),
|
|
2625
|
+
execute: async (state) => handleClosing(root, artifactsDir, requireState(state), runLogger, store),
|
|
2626
|
+
},
|
|
2627
|
+
{
|
|
2628
|
+
// Catch-all: reached only when no specific obligation matched. Always
|
|
2629
|
+
// actionable on a non-null state (the lowest-priority slot), so `advance`
|
|
2630
|
+
// surfaces the diagnostic rather than returning a null step.
|
|
2631
|
+
id: "unhandled",
|
|
2632
|
+
derive: (state) => (state != null ? "missing" : "satisfied"),
|
|
2633
|
+
execute: async (state) => ({
|
|
2634
|
+
kind: "emit",
|
|
2635
|
+
step: await handleUnhandledState(root, artifactsDir, requireState(state)),
|
|
2636
|
+
}),
|
|
2637
|
+
},
|
|
2638
|
+
];
|
|
2639
|
+
}
|
|
2640
|
+
async function decideNextStepLoop(options, runLogger) {
|
|
2641
|
+
const root = resolveRoot(options.root);
|
|
2642
|
+
const artifactsDir = resolveArtifactsDir(root, options.artifactsDir);
|
|
2643
|
+
await mkdir(artifactsDir, { recursive: true });
|
|
2644
|
+
const store = new StateStore(artifactsDir);
|
|
2645
|
+
let state = await store.loadState();
|
|
2646
|
+
runLogger.event({
|
|
2647
|
+
phase: "next-step",
|
|
2648
|
+
kind: "state",
|
|
2649
|
+
obligation: state?.status ?? "pending",
|
|
2650
|
+
});
|
|
2651
|
+
// step_count is incremented once per host invocation. The `counted` flag guards
|
|
2652
|
+
// the shared `countStep` closure so the forceReplan preamble, the pre-intake
|
|
2653
|
+
// obligation executors, and the post-intake count point can never double-count
|
|
2654
|
+
// within a call. step_count is not embedded in the emitted step, so the
|
|
2655
|
+
// count-vs-build ordering is unobservable. (Every phase handler now returns a
|
|
2656
|
+
// transition/emit outcome, so `advance` drives the whole fold in ONE call —
|
|
2657
|
+
// there is no recursive re-entry to guard against.)
|
|
2658
|
+
const counted = { value: false };
|
|
2659
|
+
const countStep = async (current) => {
|
|
2660
|
+
if (!current || counted.value)
|
|
2661
|
+
return;
|
|
2662
|
+
if (!current.started_at)
|
|
2663
|
+
current.started_at = new Date().toISOString();
|
|
2664
|
+
current.step_count = (current.step_count ?? 0) + 1;
|
|
2665
|
+
counted.value = true;
|
|
2666
|
+
await store.saveState(current);
|
|
2667
|
+
};
|
|
2668
|
+
const inputResolution = resolveInputPaths(root, options.input);
|
|
2669
|
+
// Preamble — forceReplan re-grounds from existing intake. The whole decide loop
|
|
2670
|
+
// runs once per host call (the engine folds planning → implementing → … through
|
|
2671
|
+
// transitions, never a recursive decideNextStepLoop), so this fires at most once.
|
|
2672
|
+
if (options.forceReplan && state != null) {
|
|
2673
|
+
await countStep(state);
|
|
2674
|
+
state = await forceReplanFromExistingIntake(root, artifactsDir, state, store);
|
|
2675
|
+
}
|
|
2676
|
+
// Pre-read the once-async signals the pre-intake derive()s consume
|
|
2677
|
+
// synchronously (no transition inside this advance call rewrites either file).
|
|
2678
|
+
const checkpointPath = join(artifactsDir, "intent_checkpoint.json");
|
|
2679
|
+
const existingCheckpoint = existsSync(checkpointPath)
|
|
2680
|
+
? await readOptionalJsonFile(checkpointPath)
|
|
2681
|
+
: undefined;
|
|
2682
|
+
const resumeAck = await readOptionalJsonFile(join(artifactsDir, "confirm_resume_ack.json"));
|
|
2683
|
+
// The linear pre-intake gates run as obligations through the shared advance
|
|
2684
|
+
// loop. An emit returns to the host; a transition re-scans within this call;
|
|
2685
|
+
// exhausting them (step === null) means the run is past intake and falls
|
|
2686
|
+
// through to the post-intake `advance` (MAIN_PRIORITY) below.
|
|
2687
|
+
const ctx = {
|
|
2688
|
+
root,
|
|
2689
|
+
artifactsDir,
|
|
2690
|
+
options,
|
|
2691
|
+
runLogger,
|
|
2692
|
+
store,
|
|
2693
|
+
inputResolution,
|
|
2694
|
+
countStep,
|
|
2695
|
+
};
|
|
2696
|
+
const preIntake = await advance({
|
|
2697
|
+
priority: PRE_INTAKE_PRIORITY,
|
|
2698
|
+
obligations: buildPreIntakeObligations(ctx, {
|
|
2699
|
+
existingCheckpoint,
|
|
2700
|
+
resumeAck,
|
|
2701
|
+
entryState: state,
|
|
2702
|
+
}),
|
|
2703
|
+
}, state, ctx);
|
|
2704
|
+
if (preIntake.step)
|
|
2705
|
+
return preIntake.step;
|
|
2706
|
+
state = preIntake.state;
|
|
2707
|
+
// pending_intake folds the old no-state branch (it emits handleNoState on a
|
|
2708
|
+
// null intake), so advance only falls through here with a non-null state; keep
|
|
2709
|
+
// the guard as the type narrowing + a defensive fallback.
|
|
2710
|
+
if (!state) {
|
|
2711
|
+
return handleNoState(root, artifactsDir);
|
|
2712
|
+
}
|
|
2713
|
+
await countStep(state);
|
|
2714
|
+
const main = await advance({ priority: MAIN_PRIORITY, obligations: buildMainObligations(ctx) }, state, ctx);
|
|
2715
|
+
if (main.step)
|
|
2716
|
+
return main.step;
|
|
2717
|
+
// The unhandled catch-all always emits on a non-null state, so a null step here
|
|
2718
|
+
// is unreachable; keep an explicit fallback rather than a non-null assertion.
|
|
2719
|
+
return handleUnhandledState(root, artifactsDir, state);
|
|
2720
|
+
}
|
|
2721
|
+
//# sourceMappingURL=nextStep.js.map
|