dorfl 0.0.0 → 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/advance-ci-template.d.ts +73 -0
- package/dist/advance-ci-template.d.ts.map +1 -0
- package/dist/advance-ci-template.js +104 -0
- package/dist/advance-ci-template.js.map +1 -0
- package/dist/advance-classify.d.ts +132 -0
- package/dist/advance-classify.d.ts.map +1 -0
- package/dist/advance-classify.js +120 -0
- package/dist/advance-classify.js.map +1 -0
- package/dist/advance-drivers.d.ts +182 -0
- package/dist/advance-drivers.d.ts.map +1 -0
- package/dist/advance-drivers.js +231 -0
- package/dist/advance-drivers.js.map +1 -0
- package/dist/advance-isolated.d.ts +156 -0
- package/dist/advance-isolated.d.ts.map +1 -0
- package/dist/advance-isolated.js +256 -0
- package/dist/advance-isolated.js.map +1 -0
- package/dist/advance-lifecycle-template.d.ts +107 -0
- package/dist/advance-lifecycle-template.d.ts.map +1 -0
- package/dist/advance-lifecycle-template.js +668 -0
- package/dist/advance-lifecycle-template.js.map +1 -0
- package/dist/advance-loop-driver.d.ts +325 -0
- package/dist/advance-loop-driver.d.ts.map +1 -0
- package/dist/advance-loop-driver.js +437 -0
- package/dist/advance-loop-driver.js.map +1 -0
- package/dist/advance-treeless-publish.d.ts +108 -0
- package/dist/advance-treeless-publish.d.ts.map +1 -0
- package/dist/advance-treeless-publish.js +71 -0
- package/dist/advance-treeless-publish.js.map +1 -0
- package/dist/advance.d.ts +340 -0
- package/dist/advance.d.ts.map +1 -0
- package/dist/advance.js +1122 -0
- package/dist/advance.js.map +1 -0
- package/dist/advancing-lock.d.ts +294 -0
- package/dist/advancing-lock.d.ts.map +1 -0
- package/dist/advancing-lock.js +594 -0
- package/dist/advancing-lock.js.map +1 -0
- package/dist/agent-launch.d.ts +79 -0
- package/dist/agent-launch.d.ts.map +1 -0
- package/dist/agent-launch.js +61 -0
- package/dist/agent-launch.js.map +1 -0
- package/dist/agent-stop.d.ts +149 -0
- package/dist/agent-stop.d.ts.map +1 -0
- package/dist/agent-stop.js +307 -0
- package/dist/agent-stop.js.map +1 -0
- package/dist/apply-decide.d.ts +127 -0
- package/dist/apply-decide.d.ts.map +1 -0
- package/dist/apply-decide.js +176 -0
- package/dist/apply-decide.js.map +1 -0
- package/dist/apply-merge-action.d.ts +206 -0
- package/dist/apply-merge-action.d.ts.map +1 -0
- package/dist/apply-merge-action.js +307 -0
- package/dist/apply-merge-action.js.map +1 -0
- package/dist/apply-persist.d.ts +174 -0
- package/dist/apply-persist.d.ts.map +1 -0
- package/dist/apply-persist.js +359 -0
- package/dist/apply-persist.js.map +1 -0
- package/dist/arbiter.d.ts +120 -0
- package/dist/arbiter.d.ts.map +1 -0
- package/dist/arbiter.js +255 -0
- package/dist/arbiter.js.map +1 -0
- package/dist/brand.d.ts +70 -0
- package/dist/brand.d.ts.map +1 -0
- package/dist/brand.js +84 -0
- package/dist/brand.js.map +1 -0
- package/dist/buildable-body.d.ts +132 -0
- package/dist/buildable-body.d.ts.map +1 -0
- package/dist/buildable-body.js +131 -0
- package/dist/buildable-body.js.map +1 -0
- package/dist/categorise.d.ts +66 -0
- package/dist/categorise.d.ts.map +1 -0
- package/dist/categorise.js +106 -0
- package/dist/categorise.js.map +1 -0
- package/dist/claim-cas.d.ts +117 -0
- package/dist/claim-cas.d.ts.map +1 -0
- package/dist/claim-cas.js +312 -0
- package/dist/claim-cas.js.map +1 -0
- package/dist/cli-spinner.d.ts +112 -0
- package/dist/cli-spinner.d.ts.map +1 -0
- package/dist/cli-spinner.js +157 -0
- package/dist/cli-spinner.js.map +1 -0
- package/dist/cli.d.ts +11 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +3094 -0
- package/dist/cli.js.map +1 -0
- package/dist/close-job-template.d.ts +70 -0
- package/dist/close-job-template.d.ts.map +1 -0
- package/dist/close-job-template.js +180 -0
- package/dist/close-job-template.js.map +1 -0
- package/dist/close-job.d.ts +95 -0
- package/dist/close-job.d.ts.map +1 -0
- package/dist/close-job.js +226 -0
- package/dist/close-job.js.map +1 -0
- package/dist/complete.d.ts +361 -0
- package/dist/complete.d.ts.map +1 -0
- package/dist/complete.js +885 -0
- package/dist/complete.js.map +1 -0
- package/dist/concurrency.d.ts +68 -0
- package/dist/concurrency.d.ts.map +1 -0
- package/dist/concurrency.js +112 -0
- package/dist/concurrency.js.map +1 -0
- package/dist/config-override.d.ts +76 -0
- package/dist/config-override.d.ts.map +1 -0
- package/dist/config-override.js +50 -0
- package/dist/config-override.js.map +1 -0
- package/dist/config.d.ts +668 -0
- package/dist/config.d.ts.map +1 -0
- package/dist/config.js +241 -0
- package/dist/config.js.map +1 -0
- package/dist/continue-branch.d.ts +249 -0
- package/dist/continue-branch.d.ts.map +1 -0
- package/dist/continue-branch.js +389 -0
- package/dist/continue-branch.js.map +1 -0
- package/dist/cwd-section.d.ts +186 -0
- package/dist/cwd-section.d.ts.map +1 -0
- package/dist/cwd-section.js +209 -0
- package/dist/cwd-section.js.map +1 -0
- package/dist/decision-engine.d.ts +170 -0
- package/dist/decision-engine.d.ts.map +1 -0
- package/dist/decision-engine.js +136 -0
- package/dist/decision-engine.js.map +1 -0
- package/dist/detect.d.ts +17 -0
- package/dist/detect.d.ts.map +1 -0
- package/dist/detect.js +118 -0
- package/dist/detect.js.map +1 -0
- package/dist/do-autopick.d.ts +85 -0
- package/dist/do-autopick.d.ts.map +1 -0
- package/dist/do-autopick.js +112 -0
- package/dist/do-autopick.js.map +1 -0
- package/dist/do-config.d.ts +312 -0
- package/dist/do-config.d.ts.map +1 -0
- package/dist/do-config.js +358 -0
- package/dist/do-config.js.map +1 -0
- package/dist/do-remote-auto.d.ts +75 -0
- package/dist/do-remote-auto.d.ts.map +1 -0
- package/dist/do-remote-auto.js +111 -0
- package/dist/do-remote-auto.js.map +1 -0
- package/dist/do.d.ts +621 -0
- package/dist/do.d.ts.map +1 -0
- package/dist/do.js +1882 -0
- package/dist/do.js.map +1 -0
- package/dist/drop-source.d.ts +96 -0
- package/dist/drop-source.d.ts.map +1 -0
- package/dist/drop-source.js +91 -0
- package/dist/drop-source.js.map +1 -0
- package/dist/eligibility.d.ts +46 -0
- package/dist/eligibility.d.ts.map +1 -0
- package/dist/eligibility.js +34 -0
- package/dist/eligibility.js.map +1 -0
- package/dist/env-config.d.ts +51 -0
- package/dist/env-config.d.ts.map +1 -0
- package/dist/env-config.js +272 -0
- package/dist/env-config.js.map +1 -0
- package/dist/failure-cause.d.ts +70 -0
- package/dist/failure-cause.d.ts.map +1 -0
- package/dist/failure-cause.js +126 -0
- package/dist/failure-cause.js.map +1 -0
- package/dist/format.d.ts +43 -0
- package/dist/format.d.ts.map +1 -0
- package/dist/format.js +256 -0
- package/dist/format.js.map +1 -0
- package/dist/frontmatter.d.ts +215 -0
- package/dist/frontmatter.d.ts.map +1 -0
- package/dist/frontmatter.js +345 -0
- package/dist/frontmatter.js.map +1 -0
- package/dist/gate-readiness.d.ts +84 -0
- package/dist/gate-readiness.d.ts.map +1 -0
- package/dist/gate-readiness.js +103 -0
- package/dist/gate-readiness.js.map +1 -0
- package/dist/gc.d.ts +165 -0
- package/dist/gc.d.ts.map +1 -0
- package/dist/gc.js +313 -0
- package/dist/gc.js.map +1 -0
- package/dist/gh-failure.d.ts +42 -0
- package/dist/gh-failure.d.ts.map +1 -0
- package/dist/gh-failure.js +49 -0
- package/dist/gh-failure.js.map +1 -0
- package/dist/git.d.ts +75 -0
- package/dist/git.d.ts.map +1 -0
- package/dist/git.js +130 -0
- package/dist/git.js.map +1 -0
- package/dist/github.d.ts +187 -0
- package/dist/github.d.ts.map +1 -0
- package/dist/github.js +343 -0
- package/dist/github.js.map +1 -0
- package/dist/harness.d.ts +242 -0
- package/dist/harness.d.ts.map +1 -0
- package/dist/harness.js +157 -0
- package/dist/harness.js.map +1 -0
- package/dist/identity.d.ts +167 -0
- package/dist/identity.d.ts.map +1 -0
- package/dist/identity.js +231 -0
- package/dist/identity.js.map +1 -0
- package/dist/index.d.ts +147 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +76 -0
- package/dist/index.js.map +1 -0
- package/dist/install-ci-branch-protection.d.ts +147 -0
- package/dist/install-ci-branch-protection.d.ts.map +1 -0
- package/dist/install-ci-branch-protection.js +166 -0
- package/dist/install-ci-branch-protection.js.map +1 -0
- package/dist/install-ci-capabilities/advance-lifecycle.d.ts +15 -0
- package/dist/install-ci-capabilities/advance-lifecycle.d.ts.map +1 -0
- package/dist/install-ci-capabilities/advance-lifecycle.js +28 -0
- package/dist/install-ci-capabilities/advance-lifecycle.js.map +1 -0
- package/dist/install-ci-capabilities/close-job.d.ts +13 -0
- package/dist/install-ci-capabilities/close-job.d.ts.map +1 -0
- package/dist/install-ci-capabilities/close-job.js +26 -0
- package/dist/install-ci-capabilities/close-job.js.map +1 -0
- package/dist/install-ci-capabilities/example-noop.d.ts +16 -0
- package/dist/install-ci-capabilities/example-noop.d.ts.map +1 -0
- package/dist/install-ci-capabilities/example-noop.js +23 -0
- package/dist/install-ci-capabilities/example-noop.js.map +1 -0
- package/dist/install-ci-capabilities/intake.d.ts +15 -0
- package/dist/install-ci-capabilities/intake.d.ts.map +1 -0
- package/dist/install-ci-capabilities/intake.js +28 -0
- package/dist/install-ci-capabilities/intake.js.map +1 -0
- package/dist/install-ci-capabilities/verify.d.ts +14 -0
- package/dist/install-ci-capabilities/verify.d.ts.map +1 -0
- package/dist/install-ci-capabilities/verify.js +27 -0
- package/dist/install-ci-capabilities/verify.js.map +1 -0
- package/dist/install-ci-core.d.ts +446 -0
- package/dist/install-ci-core.d.ts.map +1 -0
- package/dist/install-ci-core.js +760 -0
- package/dist/install-ci-core.js.map +1 -0
- package/dist/install-ci-github.d.ts +167 -0
- package/dist/install-ci-github.d.ts.map +1 -0
- package/dist/install-ci-github.js +315 -0
- package/dist/install-ci-github.js.map +1 -0
- package/dist/install-ci.d.ts +105 -0
- package/dist/install-ci.d.ts.map +1 -0
- package/dist/install-ci.js +363 -0
- package/dist/install-ci.js.map +1 -0
- package/dist/intake-event.d.ts +88 -0
- package/dist/intake-event.d.ts.map +1 -0
- package/dist/intake-event.js +66 -0
- package/dist/intake-event.js.map +1 -0
- package/dist/intake-marker.d.ts +95 -0
- package/dist/intake-marker.d.ts.map +1 -0
- package/dist/intake-marker.js +127 -0
- package/dist/intake-marker.js.map +1 -0
- package/dist/intake-triage.d.ts +48 -0
- package/dist/intake-triage.d.ts.map +1 -0
- package/dist/intake-triage.js +95 -0
- package/dist/intake-triage.js.map +1 -0
- package/dist/intake-trigger-template.d.ts +185 -0
- package/dist/intake-trigger-template.d.ts.map +1 -0
- package/dist/intake-trigger-template.js +449 -0
- package/dist/intake-trigger-template.js.map +1 -0
- package/dist/intake.d.ts +569 -0
- package/dist/intake.d.ts.map +1 -0
- package/dist/intake.js +1628 -0
- package/dist/intake.js.map +1 -0
- package/dist/integration-core.d.ts +539 -0
- package/dist/integration-core.d.ts.map +1 -0
- package/dist/integration-core.js +2195 -0
- package/dist/integration-core.js.map +1 -0
- package/dist/integrator.d.ts +343 -0
- package/dist/integrator.d.ts.map +1 -0
- package/dist/integrator.js +400 -0
- package/dist/integrator.js.map +1 -0
- package/dist/isolation.d.ts +219 -0
- package/dist/isolation.d.ts.map +1 -0
- package/dist/isolation.js +261 -0
- package/dist/isolation.js.map +1 -0
- package/dist/issue-provider.d.ts +349 -0
- package/dist/issue-provider.d.ts.map +1 -0
- package/dist/issue-provider.js +360 -0
- package/dist/issue-provider.js.map +1 -0
- package/dist/item-lock.d.ts +626 -0
- package/dist/item-lock.d.ts.map +1 -0
- package/dist/item-lock.js +1381 -0
- package/dist/item-lock.js.map +1 -0
- package/dist/item-path.d.ts +49 -0
- package/dist/item-path.d.ts.map +1 -0
- package/dist/item-path.js +66 -0
- package/dist/item-path.js.map +1 -0
- package/dist/ledger-lint.d.ts +129 -0
- package/dist/ledger-lint.d.ts.map +1 -0
- package/dist/ledger-lint.js +249 -0
- package/dist/ledger-lint.js.map +1 -0
- package/dist/ledger-read.d.ts +357 -0
- package/dist/ledger-read.d.ts.map +1 -0
- package/dist/ledger-read.js +442 -0
- package/dist/ledger-read.js.map +1 -0
- package/dist/ledger-write.d.ts +330 -0
- package/dist/ledger-write.d.ts.map +1 -0
- package/dist/ledger-write.js +411 -0
- package/dist/ledger-write.js.map +1 -0
- package/dist/lifecycle-gather.d.ts +30 -0
- package/dist/lifecycle-gather.d.ts.map +1 -0
- package/dist/lifecycle-gather.js +205 -0
- package/dist/lifecycle-gather.js.map +1 -0
- package/dist/lifecycle-pools.d.ts +180 -0
- package/dist/lifecycle-pools.d.ts.map +1 -0
- package/dist/lifecycle-pools.js +78 -0
- package/dist/lifecycle-pools.js.map +1 -0
- package/dist/merge-question-surfacer.d.ts +166 -0
- package/dist/merge-question-surfacer.d.ts.map +1 -0
- package/dist/merge-question-surfacer.js +297 -0
- package/dist/merge-question-surfacer.js.map +1 -0
- package/dist/mint-adr.d.ts +126 -0
- package/dist/mint-adr.d.ts.map +1 -0
- package/dist/mint-adr.js +257 -0
- package/dist/mint-adr.js.map +1 -0
- package/dist/mirror-pool-scan.d.ts +125 -0
- package/dist/mirror-pool-scan.d.ts.map +1 -0
- package/dist/mirror-pool-scan.js +104 -0
- package/dist/mirror-pool-scan.js.map +1 -0
- package/dist/needs-attention.d.ts +341 -0
- package/dist/needs-attention.d.ts.map +1 -0
- package/dist/needs-attention.js +900 -0
- package/dist/needs-attention.js.map +1 -0
- package/dist/orphan-sidecar.d.ts +79 -0
- package/dist/orphan-sidecar.d.ts.map +1 -0
- package/dist/orphan-sidecar.js +71 -0
- package/dist/orphan-sidecar.js.map +1 -0
- package/dist/output.d.ts +48 -0
- package/dist/output.d.ts.map +1 -0
- package/dist/output.js +66 -0
- package/dist/output.js.map +1 -0
- package/dist/pi-harness.d.ts +179 -0
- package/dist/pi-harness.d.ts.map +1 -0
- package/dist/pi-harness.js +342 -0
- package/dist/pi-harness.js.map +1 -0
- package/dist/placement.d.ts +99 -0
- package/dist/placement.d.ts.map +1 -0
- package/dist/placement.js +67 -0
- package/dist/placement.js.map +1 -0
- package/dist/prd-to-spec.d.ts +315 -0
- package/dist/prd-to-spec.d.ts.map +1 -0
- package/dist/prd-to-spec.js +684 -0
- package/dist/prd-to-spec.js.map +1 -0
- package/dist/prepare.d.ts +121 -0
- package/dist/prepare.d.ts.map +1 -0
- package/dist/prepare.js +140 -0
- package/dist/prepare.js.map +1 -0
- package/dist/prompt.d.ts +360 -0
- package/dist/prompt.d.ts.map +1 -0
- package/dist/prompt.js +499 -0
- package/dist/prompt.js.map +1 -0
- package/dist/protocol/ADR-FORMAT.md +47 -0
- package/dist/protocol/CLAIM-PROTOCOL.md +217 -0
- package/dist/protocol/REVIEW-PROTOCOL.md +119 -0
- package/dist/protocol/SURFACE-PROTOCOL.md +121 -0
- package/dist/protocol/TASKING-PROTOCOL.md +122 -0
- package/dist/protocol/WORK-CONTRACT.md +276 -0
- package/dist/protocol/spec-template.md +71 -0
- package/dist/protocol/task-template.md +65 -0
- package/dist/readiness.d.ts +66 -0
- package/dist/readiness.d.ts.map +1 -0
- package/dist/readiness.js +36 -0
- package/dist/readiness.js.map +1 -0
- package/dist/reap-branches.d.ts +102 -0
- package/dist/reap-branches.d.ts.map +1 -0
- package/dist/reap-branches.js +149 -0
- package/dist/reap-branches.js.map +1 -0
- package/dist/recover-isolated.d.ts +72 -0
- package/dist/recover-isolated.d.ts.map +1 -0
- package/dist/recover-isolated.js +188 -0
- package/dist/recover-isolated.js.map +1 -0
- package/dist/registry.d.ts +172 -0
- package/dist/registry.d.ts.map +1 -0
- package/dist/registry.js +296 -0
- package/dist/registry.js.map +1 -0
- package/dist/repo-config.d.ts +201 -0
- package/dist/repo-config.d.ts.map +1 -0
- package/dist/repo-config.js +414 -0
- package/dist/repo-config.js.map +1 -0
- package/dist/repo-key.d.ts +20 -0
- package/dist/repo-key.d.ts.map +1 -0
- package/dist/repo-key.js +68 -0
- package/dist/repo-key.js.map +1 -0
- package/dist/repo-mirror.d.ts +177 -0
- package/dist/repo-mirror.d.ts.map +1 -0
- package/dist/repo-mirror.js +271 -0
- package/dist/repo-mirror.js.map +1 -0
- package/dist/retry-backoff.d.ts +90 -0
- package/dist/retry-backoff.d.ts.map +1 -0
- package/dist/retry-backoff.js +98 -0
- package/dist/retry-backoff.js.map +1 -0
- package/dist/review-gate.d.ts +173 -0
- package/dist/review-gate.d.ts.map +1 -0
- package/dist/review-gate.js +261 -0
- package/dist/review-gate.js.map +1 -0
- package/dist/review-verdict.d.ts +149 -0
- package/dist/review-verdict.d.ts.map +1 -0
- package/dist/review-verdict.js +332 -0
- package/dist/review-verdict.js.map +1 -0
- package/dist/run.d.ts +221 -0
- package/dist/run.d.ts.map +1 -0
- package/dist/run.js +963 -0
- package/dist/run.js.map +1 -0
- package/dist/scan.d.ts +308 -0
- package/dist/scan.d.ts.map +1 -0
- package/dist/scan.js +374 -0
- package/dist/scan.js.map +1 -0
- package/dist/select-order.d.ts +75 -0
- package/dist/select-order.d.ts.map +1 -0
- package/dist/select-order.js +108 -0
- package/dist/select-order.js.map +1 -0
- package/dist/select-priority.d.ts +188 -0
- package/dist/select-priority.d.ts.map +1 -0
- package/dist/select-priority.js +80 -0
- package/dist/select-priority.js.map +1 -0
- package/dist/select.d.ts +25 -0
- package/dist/select.d.ts.map +1 -0
- package/dist/select.js +43 -0
- package/dist/select.js.map +1 -0
- package/dist/session-path.d.ts +36 -0
- package/dist/session-path.d.ts.map +1 -0
- package/dist/session-path.js +129 -0
- package/dist/session-path.js.map +1 -0
- package/dist/sidecar-apply.d.ts +83 -0
- package/dist/sidecar-apply.d.ts.map +1 -0
- package/dist/sidecar-apply.js +111 -0
- package/dist/sidecar-apply.js.map +1 -0
- package/dist/sidecar.d.ts +245 -0
- package/dist/sidecar.d.ts.map +1 -0
- package/dist/sidecar.js +481 -0
- package/dist/sidecar.js.map +1 -0
- package/dist/slug-namespace.d.ts +204 -0
- package/dist/slug-namespace.d.ts.map +1 -0
- package/dist/slug-namespace.js +229 -0
- package/dist/slug-namespace.js.map +1 -0
- package/dist/spec-complete.d.ts +44 -0
- package/dist/spec-complete.d.ts.map +1 -0
- package/dist/spec-complete.js +69 -0
- package/dist/spec-complete.js.map +1 -0
- package/dist/start.d.ts +97 -0
- package/dist/start.d.ts.map +1 -0
- package/dist/start.js +633 -0
- package/dist/start.js.map +1 -0
- package/dist/status.d.ts +199 -0
- package/dist/status.d.ts.map +1 -0
- package/dist/status.js +228 -0
- package/dist/status.js.map +1 -0
- package/dist/surface-gate.d.ts +162 -0
- package/dist/surface-gate.d.ts.map +1 -0
- package/dist/surface-gate.js +206 -0
- package/dist/surface-gate.js.map +1 -0
- package/dist/surface-persist.d.ts +86 -0
- package/dist/surface-persist.d.ts.map +1 -0
- package/dist/surface-persist.js +129 -0
- package/dist/surface-persist.js.map +1 -0
- package/dist/tasker-review-loop.d.ts +249 -0
- package/dist/tasker-review-loop.d.ts.map +1 -0
- package/dist/tasker-review-loop.js +369 -0
- package/dist/tasker-review-loop.js.map +1 -0
- package/dist/tasking-eligibility.d.ts +74 -0
- package/dist/tasking-eligibility.d.ts.map +1 -0
- package/dist/tasking-eligibility.js +52 -0
- package/dist/tasking-eligibility.js.map +1 -0
- package/dist/tasking-lock.d.ts +111 -0
- package/dist/tasking-lock.d.ts.map +1 -0
- package/dist/tasking-lock.js +256 -0
- package/dist/tasking-lock.js.map +1 -0
- package/dist/tasking.d.ts +275 -0
- package/dist/tasking.d.ts.map +1 -0
- package/dist/tasking.js +952 -0
- package/dist/tasking.js.map +1 -0
- package/dist/triage-gate.d.ts +127 -0
- package/dist/triage-gate.d.ts.map +1 -0
- package/dist/triage-gate.js +139 -0
- package/dist/triage-gate.js.map +1 -0
- package/dist/triage-persist.d.ts +163 -0
- package/dist/triage-persist.d.ts.map +1 -0
- package/dist/triage-persist.js +387 -0
- package/dist/triage-persist.js.map +1 -0
- package/dist/verdict-json.d.ts +32 -0
- package/dist/verdict-json.d.ts.map +1 -0
- package/dist/verdict-json.js +74 -0
- package/dist/verdict-json.js.map +1 -0
- package/dist/verify-workflow-template.d.ts +60 -0
- package/dist/verify-workflow-template.d.ts.map +1 -0
- package/dist/verify-workflow-template.js +126 -0
- package/dist/verify-workflow-template.js.map +1 -0
- package/dist/verify.d.ts +60 -0
- package/dist/verify.d.ts.map +1 -0
- package/dist/verify.js +62 -0
- package/dist/verify.js.map +1 -0
- package/dist/watch-session.d.ts +112 -0
- package/dist/watch-session.d.ts.map +1 -0
- package/dist/watch-session.js +347 -0
- package/dist/watch-session.js.map +1 -0
- package/dist/work-layout.d.ts +198 -0
- package/dist/work-layout.d.ts.map +1 -0
- package/dist/work-layout.js +217 -0
- package/dist/work-layout.js.map +1 -0
- package/dist/work-on.d.ts +154 -0
- package/dist/work-on.d.ts.map +1 -0
- package/dist/work-on.js +387 -0
- package/dist/work-on.js.map +1 -0
- package/dist/workspace.d.ts +224 -0
- package/dist/workspace.d.ts.map +1 -0
- package/dist/workspace.js +325 -0
- package/dist/workspace.js.map +1 -0
- package/package.json +46 -2
- package/src/advance-ci-template.ts +203 -0
- package/src/advance-classify.ts +197 -0
- package/src/advance-drivers.ts +414 -0
- package/src/advance-isolated.ts +432 -0
- package/src/advance-lifecycle-template.ts +791 -0
- package/src/advance-loop-driver.ts +745 -0
- package/src/advance-treeless-publish.ts +177 -0
- package/src/advance.ts +1564 -0
- package/src/advancing-lock.ts +988 -0
- package/src/agent-launch.ts +137 -0
- package/src/agent-stop.ts +361 -0
- package/src/apply-decide.ts +242 -0
- package/src/apply-merge-action.ts +502 -0
- package/src/apply-persist.ts +518 -0
- package/src/arbiter.ts +372 -0
- package/src/brand.ts +111 -0
- package/src/buildable-body.ts +196 -0
- package/src/categorise.ts +158 -0
- package/src/claim-cas.ts +513 -0
- package/src/cli-spinner.ts +225 -0
- package/src/cli.ts +4369 -0
- package/src/close-job-template.ts +236 -0
- package/src/close-job.ts +319 -0
- package/src/complete.ts +1379 -0
- package/src/concurrency.ts +151 -0
- package/src/config-override.ts +116 -0
- package/src/config.ts +883 -0
- package/src/continue-branch.ts +542 -0
- package/src/cwd-section.ts +392 -0
- package/src/decision-engine.ts +272 -0
- package/src/detect.ts +124 -0
- package/src/do-autopick.ts +223 -0
- package/src/do-config.ts +589 -0
- package/src/do-remote-auto.ts +197 -0
- package/src/do.ts +2623 -0
- package/src/drop-source.ts +194 -0
- package/src/eligibility.ts +79 -0
- package/src/env-config.ts +305 -0
- package/src/failure-cause.ts +142 -0
- package/src/format.ts +313 -0
- package/src/frontmatter.ts +485 -0
- package/src/gate-readiness.ts +147 -0
- package/src/gc.ts +510 -0
- package/src/gh-failure.ts +53 -0
- package/src/git.ts +186 -0
- package/src/github.ts +468 -0
- package/src/harness.ts +355 -0
- package/src/identity.ts +322 -0
- package/src/index.ts +785 -0
- package/src/install-ci-branch-protection.ts +255 -0
- package/src/install-ci-capabilities/advance-lifecycle.ts +34 -0
- package/src/install-ci-capabilities/close-job.ts +32 -0
- package/src/install-ci-capabilities/example-noop.ts +24 -0
- package/src/install-ci-capabilities/intake.ts +34 -0
- package/src/install-ci-capabilities/verify.ts +33 -0
- package/src/install-ci-core.ts +1088 -0
- package/src/install-ci-github.ts +376 -0
- package/src/install-ci.ts +552 -0
- package/src/intake-event.ts +102 -0
- package/src/intake-marker.ts +195 -0
- package/src/intake-triage.ts +138 -0
- package/src/intake-trigger-template.ts +591 -0
- package/src/intake.ts +2445 -0
- package/src/integration-core.ts +3065 -0
- package/src/integrator.ts +771 -0
- package/src/isolation.ts +484 -0
- package/src/issue-provider.ts +733 -0
- package/src/item-lock.ts +1858 -0
- package/src/item-path.ts +75 -0
- package/src/ledger-lint.ts +332 -0
- package/src/ledger-read.ts +924 -0
- package/src/ledger-write.ts +865 -0
- package/src/lifecycle-gather.ts +298 -0
- package/src/lifecycle-pools.ts +250 -0
- package/src/merge-question-surfacer.ts +496 -0
- package/src/mint-adr.ts +362 -0
- package/src/mirror-pool-scan.ts +240 -0
- package/src/needs-attention.ts +1506 -0
- package/src/orphan-sidecar.ts +150 -0
- package/src/output.ts +89 -0
- package/src/pi-harness.ts +403 -0
- package/src/placement.ts +131 -0
- package/src/prd-to-spec.ts +1023 -0
- package/src/prepare.ts +230 -0
- package/src/prompt.ts +760 -0
- package/src/readiness.ts +98 -0
- package/src/reap-branches.ts +278 -0
- package/src/recover-isolated.ts +276 -0
- package/src/registry.ts +475 -0
- package/src/repo-config.ts +550 -0
- package/src/repo-key.ts +74 -0
- package/src/repo-mirror.ts +367 -0
- package/src/retry-backoff.ts +130 -0
- package/src/review-gate.ts +389 -0
- package/src/review-verdict.ts +422 -0
- package/src/run.ts +1430 -0
- package/src/scan.ts +611 -0
- package/src/select-order.ts +143 -0
- package/src/select-priority.ts +266 -0
- package/src/select.ts +62 -0
- package/src/session-path.ts +153 -0
- package/src/sidecar-apply.ts +216 -0
- package/src/sidecar.ts +700 -0
- package/src/slug-namespace.ts +367 -0
- package/src/spec-complete.ts +118 -0
- package/src/start.ts +974 -0
- package/src/status.ts +441 -0
- package/src/surface-gate.ts +337 -0
- package/src/surface-persist.ts +241 -0
- package/src/tasker-review-loop.ts +671 -0
- package/src/tasking-eligibility.ts +114 -0
- package/src/tasking-lock.ts +416 -0
- package/src/tasking.ts +1438 -0
- package/src/triage-gate.ts +248 -0
- package/src/triage-persist.ts +570 -0
- package/src/verdict-json.ts +73 -0
- package/src/verify-workflow-template.ts +159 -0
- package/src/verify.ts +123 -0
- package/src/watch-session.ts +397 -0
- package/src/work-layout.ts +262 -0
- package/src/work-on.ts +660 -0
- package/src/workspace.ts +502 -0
|
@@ -0,0 +1,392 @@
|
|
|
1
|
+
import {run, runAsync, localMainDivergence} from './git.js';
|
|
2
|
+
import {isParticipatingRepo} from './detect.js';
|
|
3
|
+
import {scanRepoPaths, type RepoReport} from './scan.js';
|
|
4
|
+
import {arbiterStatus} from './arbiter.js';
|
|
5
|
+
import {listMirrors} from './registry.js';
|
|
6
|
+
import {encodeRepoKey, mirrorPath} from './repo-mirror.js';
|
|
7
|
+
import {heldTaskSlugsStrict, listItemLockEntries} from './item-lock.js';
|
|
8
|
+
import type {Config} from './config.js';
|
|
9
|
+
import type {ConfigOverrideMap} from './config-override.js';
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* The CWD-LOCAL section of `scan`/`status` (the `scan-status-read-cwd-repo`
|
|
13
|
+
* task). When a command runs INSIDE a participating repo, it ALSO reports that
|
|
14
|
+
* CURRENT repo as a clearly-labelled, separately-counted LOCAL section, in
|
|
15
|
+
* addition to (NEVER merged into) the cross-repo REGISTRY view.
|
|
16
|
+
*
|
|
17
|
+
* The consistency rule this module enforces (do not violate):
|
|
18
|
+
*
|
|
19
|
+
* - The local section reads the LOCAL WORKING TREE (`scanRepoPaths([cwd])`) —
|
|
20
|
+
* your possibly-uncommitted / unpushed / diverged state — NOT the bare
|
|
21
|
+
* mirror-ref the registry reads. The two reads have DIFFERENT freshness +
|
|
22
|
+
* storage models, so they are kept VISUALLY + SEMANTICALLY distinct, each
|
|
23
|
+
* with its OWN count. A merged grand total would be true in NEITHER model.
|
|
24
|
+
* - **The SELECTION pool is REMOTE-AUTHORITATIVE + FAILS CLOSED offline.** The
|
|
25
|
+
* held-lock set (`refs/dorfl/lock/*`) lives ONLY on the arbiter, and it is the
|
|
26
|
+
* LOAD-BEARING signal that keeps a claimed / in-flight item out of the
|
|
27
|
+
* eligible pool (the body no longer moves on claim). So the cwd pool reads the
|
|
28
|
+
* held set from the arbiter (`heldTaskSlugsStrict`) and SUBTRACTS it before
|
|
29
|
+
* reporting eligibility — exactly as the registry `scan()` does. When the cwd
|
|
30
|
+
* repo has a configured arbiter but that read cannot reach it, eligibility is
|
|
31
|
+
* UNKNOWN and the section THROWS rather than emit a confident-but-wrong pool
|
|
32
|
+
* (the
|
|
33
|
+
* `scan-cwd-selection-pool-read-local-skips-held-lock-subtraction-offline-must-fail`
|
|
34
|
+
* decision: offline selection fails; there is NO `--local` fallback). This is
|
|
35
|
+
* the SELECTION concern; the divergence line is the SURFACE concern and keeps
|
|
36
|
+
* its graceful warn+last-known behaviour.
|
|
37
|
+
* - **Fetch-first ALSO for the cwd** (the maintainer's explicit ask): the cwd
|
|
38
|
+
* repo's arbiter is fetched BEFORE the divergence is computed (the local
|
|
39
|
+
* working tree is the LEAST authoritative view), reusing the
|
|
40
|
+
* `scan-status-fetch-first` fetch+warn+fallback discipline — a failed fetch
|
|
41
|
+
* WARNS and falls back to last-known, NEVER errors out (a read-only command
|
|
42
|
+
* must degrade, ADR §5/§6).
|
|
43
|
+
* - The divergence-vs-arbiter is shown with the `main-divergence-guard` framing
|
|
44
|
+
* (`local main is N commits ahead of <arbiter>/main` = unpushed).
|
|
45
|
+
* - **De-dup:** if the cwd repo is ALSO registered, it is shown ONCE in the
|
|
46
|
+
* local section marked "(also registered)" and its registry row is dropped
|
|
47
|
+
* from the registry list — so the same repo never appears as two mystery
|
|
48
|
+
* rows with possibly-disagreeing states.
|
|
49
|
+
*
|
|
50
|
+
* The registry model is UNCHANGED by this: `scan`/`status` are read-only DISPLAY
|
|
51
|
+
* surfaces; the daemon (`run`) + the arbiter CAS still claim against the REGISTRY
|
|
52
|
+
* only. Showing the cwd changes nothing about where claims happen.
|
|
53
|
+
*/
|
|
54
|
+
|
|
55
|
+
/** The cwd repo's arbiter, as resolved for the local section's divergence line. */
|
|
56
|
+
export interface CwdArbiter {
|
|
57
|
+
/** The arbiter remote name inspected (e.g. `arbiter` / `origin`). */
|
|
58
|
+
remote: string;
|
|
59
|
+
/** True iff the cwd repo has a remote with that name. */
|
|
60
|
+
configured: boolean;
|
|
61
|
+
/** The arbiter's URL, when configured. */
|
|
62
|
+
url?: string;
|
|
63
|
+
/**
|
|
64
|
+
* True iff the cwd repo's arbiter `main` was FRESHLY FETCHED before the
|
|
65
|
+
* divergence was computed. False ⇒ the fetch failed (offline / no arbiter) and
|
|
66
|
+
* the divergence reflects the last-known arbiter ref (a warning was emitted).
|
|
67
|
+
*/
|
|
68
|
+
fetched: boolean;
|
|
69
|
+
/** Commits local `main` is AHEAD of `<arbiter>/main` (unpushed). */
|
|
70
|
+
ahead: number;
|
|
71
|
+
/** Commits local `main` is BEHIND `<arbiter>/main` (needs a pull/rebase). */
|
|
72
|
+
behind: number;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
/** The cwd-local section report (one repo: the current working tree). */
|
|
76
|
+
export interface CwdSection {
|
|
77
|
+
/** Absolute path to the cwd repo. */
|
|
78
|
+
path: string;
|
|
79
|
+
/**
|
|
80
|
+
* True iff the cwd is a participating repo (a `work/` tree with lifecycle
|
|
81
|
+
* content in any pool — see {@link isParticipatingRepo}, NOT `tasks/ready/`
|
|
82
|
+
* alone). When false, every other field is absent — there is NO local section.
|
|
83
|
+
*/
|
|
84
|
+
participating: boolean;
|
|
85
|
+
/** The cwd repo's `work/` lifecycle, read from the LOCAL WORKING TREE. */
|
|
86
|
+
repo?: RepoReport;
|
|
87
|
+
/** Total backlog item count for the cwd (its OWN count, never merged). */
|
|
88
|
+
totalItems?: number;
|
|
89
|
+
/** Eligible item count for the cwd (its OWN count). */
|
|
90
|
+
totalEligible?: number;
|
|
91
|
+
/**
|
|
92
|
+
* True iff the cwd repo is ALSO in the registry (its arbiter URL keys to a
|
|
93
|
+
* registered hub mirror). When true the cwd is de-duped: shown once here,
|
|
94
|
+
* marked "(also registered)", and its registry row is dropped.
|
|
95
|
+
*/
|
|
96
|
+
alsoRegistered?: boolean;
|
|
97
|
+
/**
|
|
98
|
+
* The registered hub-mirror PATH the cwd de-dups against (so the registry view
|
|
99
|
+
* can drop that row). Present only when {@link alsoRegistered} is true.
|
|
100
|
+
*/
|
|
101
|
+
registeredMirrorPath?: string;
|
|
102
|
+
/** The cwd repo's arbiter + divergence (fetch-first). Absent when no arbiter. */
|
|
103
|
+
arbiter?: CwdArbiter;
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
/** True iff the working repo has a git remote with name `remote`. The held-lock
|
|
107
|
+
* read targets the COORDINATION arbiter (default `origin`); we only attempt it
|
|
108
|
+
* when that remote actually exists, so a repo with no coordination remote keeps
|
|
109
|
+
* the empty held set rather than failing on a `git remote get-url` miss. */
|
|
110
|
+
function remoteExists(
|
|
111
|
+
cwd: string,
|
|
112
|
+
remote: string,
|
|
113
|
+
env: NodeJS.ProcessEnv | undefined,
|
|
114
|
+
): boolean {
|
|
115
|
+
return run('git', ['remote', 'get-url', remote], cwd, {env}).status === 0;
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
/** The verdict of the FETCH-FREE cwd pre-check {@link cwdSectionDisposition}. */
|
|
119
|
+
export interface CwdDisposition {
|
|
120
|
+
/** True iff the cwd is a participating repo (a `work/` tree with lifecycle
|
|
121
|
+
* content in any pool — see {@link isParticipatingRepo}, NOT `tasks/ready/`
|
|
122
|
+
* alone). */
|
|
123
|
+
participating: boolean;
|
|
124
|
+
/**
|
|
125
|
+
* True iff the cwd's arbiter URL keys to a registered hub mirror. When true the
|
|
126
|
+
* registry view ALREADY covers this repo, so a default `scan`/`status` should
|
|
127
|
+
* SKIP resolving the (expensive, fetch-first) cwd section entirely — the registry
|
|
128
|
+
* row represents it, and re-reading the cwd would just re-fetch the SAME arbiter
|
|
129
|
+
* `main` + lock refs the registry loop already fetched (the redundant-fetch the
|
|
130
|
+
* `scan-here-and-skip-redundant-cwd` decision eliminates). Meaningful only when
|
|
131
|
+
* {@link participating}.
|
|
132
|
+
*/
|
|
133
|
+
alsoRegistered: boolean;
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
/**
|
|
137
|
+
* The FETCH-FREE pre-check that decides whether a DEFAULT `scan`/`status` should
|
|
138
|
+
* pay for the cwd section at all. It does NO network I/O: it reads whether the cwd
|
|
139
|
+
* participates (local `readdirSync`) and resolves the cwd's arbiter URL via the
|
|
140
|
+
* fetch-free {@link arbiterStatus} (a local `git remote get-url`), then asks the
|
|
141
|
+
* fetch-free {@link resolveRegistration} (local {@link listMirrors} key match)
|
|
142
|
+
* whether that URL is already a registered mirror.
|
|
143
|
+
*
|
|
144
|
+
* The CLI gates on this BEFORE calling {@link resolveCwdSection}: a participating
|
|
145
|
+
* cwd that is ALSO registered is skipped (the registry already covers it, and the
|
|
146
|
+
* cwd read would only re-fetch the same arbiter), while a participating cwd with
|
|
147
|
+
* NO mirror is resolved + shown standalone so a mirror-less repo you are standing
|
|
148
|
+
* in is never invisible. `--here` bypasses this gate (it ALWAYS resolves the cwd,
|
|
149
|
+
* and only the cwd).
|
|
150
|
+
*/
|
|
151
|
+
export function cwdSectionDisposition(input: {
|
|
152
|
+
cwd: string;
|
|
153
|
+
config: Config;
|
|
154
|
+
/** The DIVERGENCE/arbiter remote whose URL keys the registration check. */
|
|
155
|
+
arbiterRemote?: string;
|
|
156
|
+
env?: NodeJS.ProcessEnv;
|
|
157
|
+
}): CwdDisposition {
|
|
158
|
+
if (!isParticipatingRepo(input.cwd)) {
|
|
159
|
+
return {participating: false, alsoRegistered: false};
|
|
160
|
+
}
|
|
161
|
+
// Fetch-free: arbiterStatus reads the local remote config only (no fetch).
|
|
162
|
+
const status = arbiterStatus({
|
|
163
|
+
cwd: input.cwd,
|
|
164
|
+
remote: input.arbiterRemote,
|
|
165
|
+
env: input.env,
|
|
166
|
+
});
|
|
167
|
+
const {alsoRegistered} = resolveRegistration({
|
|
168
|
+
arbiterUrl: status.url,
|
|
169
|
+
config: input.config,
|
|
170
|
+
env: input.env,
|
|
171
|
+
});
|
|
172
|
+
return {participating: true, alsoRegistered};
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
/** Inputs to {@link resolveCwdSection}. */
|
|
176
|
+
export interface ResolveCwdSectionOptions {
|
|
177
|
+
/** The current working directory to inspect (the candidate cwd repo). */
|
|
178
|
+
cwd: string;
|
|
179
|
+
/** Resolved global config (for `workspacesDir` + per-repo `autoBuild`). */
|
|
180
|
+
config: Config;
|
|
181
|
+
/**
|
|
182
|
+
* The per-machine {@link ConfigOverrideMap}. Threaded into the local
|
|
183
|
+
* working-tree scan so the cwd section's eligibility reflects the per-machine
|
|
184
|
+
* override (consistent with the autopick / advance paths). Default: none.
|
|
185
|
+
*/
|
|
186
|
+
override?: ConfigOverrideMap;
|
|
187
|
+
/**
|
|
188
|
+
* The arbiter remote name to fetch + diff against (the SURFACE/divergence
|
|
189
|
+
* remote). Defaults to the same remote `status`'s arbiter section resolves
|
|
190
|
+
* (`arbiter`); the CLI passes the configured value.
|
|
191
|
+
*/
|
|
192
|
+
arbiterRemote?: string;
|
|
193
|
+
/**
|
|
194
|
+
* The COORDINATION arbiter remote where the per-item lock refs
|
|
195
|
+
* (`refs/dorfl/lock/*`) live — the remote the held-lock SUBTRACTION reads. This
|
|
196
|
+
* is the SAME remote `claim`/`do`/`complete` push locks to, which defaults to
|
|
197
|
+
* `origin` (NOT the `arbiter`-named DIVERGENCE remote above — a repo can use
|
|
198
|
+
* `origin` as its arbiter and have no `arbiter` remote at all, exactly this
|
|
199
|
+
* repo's shape). Decoupled so the held-lock read targets the real coordination
|
|
200
|
+
* arbiter even when the divergence remote is absent. Default `origin`.
|
|
201
|
+
*/
|
|
202
|
+
lockArbiterRemote?: string;
|
|
203
|
+
/** Sink for the fetch-first fall-back warning (warn + last-known, never error). */
|
|
204
|
+
warn?: (message: string) => void;
|
|
205
|
+
env?: NodeJS.ProcessEnv;
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
/**
|
|
209
|
+
* Resolve the cwd-local section for `scan`/`status`. Returns
|
|
210
|
+
* `{participating: false}` when the cwd is NOT a participating repo (the callers
|
|
211
|
+
* then render only the registry view, unchanged). When participating it:
|
|
212
|
+
*
|
|
213
|
+
* 1. FETCHES the cwd repo's arbiter first (warn + fall back to last-known on
|
|
214
|
+
* failure — never errors), then computes the divergence vs `<arbiter>/main`;
|
|
215
|
+
* 2. reads the COORDINATION arbiter's HELD-LOCK set (the remote where
|
|
216
|
+
* `refs/dorfl/lock/*` live, default `origin`; fail-closed: throws when that
|
|
217
|
+
* remote exists but is unreachable) to SUBTRACT in-flight items from the pool;
|
|
218
|
+
* 3. reads the cwd's `work/` lifecycle from the LOCAL WORKING TREE
|
|
219
|
+
* (`scanRepoPaths([cwd])`) with that held set subtracted;
|
|
220
|
+
* 4. de-dups against the registry (is the cwd's arbiter URL a registered
|
|
221
|
+
* mirror?).
|
|
222
|
+
*
|
|
223
|
+
* It MUTATES nothing but the arbiter fetch (a read refresh, same as the registry
|
|
224
|
+
* fetch-first); it never claims/moves/integrates.
|
|
225
|
+
*/
|
|
226
|
+
export async function resolveCwdSection(
|
|
227
|
+
options: ResolveCwdSectionOptions,
|
|
228
|
+
): Promise<CwdSection> {
|
|
229
|
+
const {cwd, config, warn, env} = options;
|
|
230
|
+
|
|
231
|
+
if (!isParticipatingRepo(cwd)) {
|
|
232
|
+
return {path: cwd, participating: false};
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
// 1. The cwd repo's arbiter + fetch-first divergence. We resolve the arbiter
|
|
236
|
+
// via the SAME `arbiterStatus` the dashboard's arbiter section uses; if it
|
|
237
|
+
// is configured we fetch it BEFORE diffing (the local tree is the least
|
|
238
|
+
// authoritative view) — warn + fall back to last-known on failure. Resolved
|
|
239
|
+
// FIRST (before the pool read) so the held-lock subtraction below reads that
|
|
240
|
+
// same arbiter's lock refs.
|
|
241
|
+
const arbiter = await resolveCwdArbiter({
|
|
242
|
+
cwd,
|
|
243
|
+
remote: options.arbiterRemote,
|
|
244
|
+
warn,
|
|
245
|
+
env,
|
|
246
|
+
});
|
|
247
|
+
|
|
248
|
+
// 2. The held-lock set to SUBTRACT from the cwd pool (the SELECTION fix). The
|
|
249
|
+
// lock refs live on the COORDINATION arbiter (`refs/dorfl/lock/*`) — the SAME
|
|
250
|
+
// remote `claim`/`do` use, default `origin` — NOT the `arbiter`-named
|
|
251
|
+
// DIVERGENCE remote resolved above (this repo has no `arbiter` remote; its
|
|
252
|
+
// arbiter IS `origin`). So we read the held set from the coordination remote
|
|
253
|
+
// and FAIL CLOSED on a read fault (`heldTaskSlugsStrict` throws): an offline /
|
|
254
|
+
// unreachable arbiter makes the eligible pool UNKNOWN, and we must NOT emit a
|
|
255
|
+
// confident-but-wrong pool (which CI would enumerate into doomed claim legs).
|
|
256
|
+
// A repo with NO coordination remote configured has nothing to subtract and
|
|
257
|
+
// nothing to fail against — it keeps the empty set.
|
|
258
|
+
const lockRemote = options.lockArbiterRemote ?? 'origin';
|
|
259
|
+
const hasLockRemote = remoteExists(cwd, lockRemote, env);
|
|
260
|
+
const heldSlugs = hasLockRemote
|
|
261
|
+
? await heldTaskSlugsStrict(cwd, lockRemote, env)
|
|
262
|
+
: new Set<string>();
|
|
263
|
+
|
|
264
|
+
// 3. The cwd's `work/` lifecycle from the LOCAL WORKING TREE (not a mirror ref),
|
|
265
|
+
// with the arbiter-read held set SUBTRACTED so in-flight (lock-held) items are
|
|
266
|
+
// not reported eligible. Thread the per-machine override so the cwd section's
|
|
267
|
+
// eligibility matches what `do`/`advance` autopick will actually select.
|
|
268
|
+
const localReport = scanRepoPaths([cwd], config, heldSlugs, options.override);
|
|
269
|
+
const repo = localReport.repos[0];
|
|
270
|
+
|
|
271
|
+
// 3b. The PER-ITEM LOCK in-flight SURFACE for the cwd (prd
|
|
272
|
+
// `ledger-status-per-item-lock-refs` US #8). The subtraction above removes a
|
|
273
|
+
// held slug from the eligible `items[]` pool; on its OWN that leaves a
|
|
274
|
+
// held/stuck cwd item in a BLIND SPOT — gone from every bucket with nothing
|
|
275
|
+
// explaining why (the regression this fixes). The registry/mirror `scan`
|
|
276
|
+
// attaches `lockHeld` to each `RepoReport` so a held item still shows up
|
|
277
|
+
// in-progress/stuck; the cwd `RepoReport` from `scanRepoPaths` did not. So we
|
|
278
|
+
// read the SAME held lock entries (action × state + reason/questions) via the
|
|
279
|
+
// SAME `listItemLockEntries` primitive the mirror path uses (NOT a second
|
|
280
|
+
// reader) and attach them, making `.cwd.repo.lockHeld` symmetric with
|
|
281
|
+
// `.repos[].lockHeld`.
|
|
282
|
+
//
|
|
283
|
+
// This is a SURFACE only, and it is INTENTIONALLY graceful (best-effort,
|
|
284
|
+
// empty on any fault — exactly as `listItemLockEntries` is on the mirror
|
|
285
|
+
// side): a read fault degrades to "no in-flight locks shown", it must NOT
|
|
286
|
+
// fail the section. The SELECTION subtraction above stays STRICT
|
|
287
|
+
// (`heldTaskSlugsStrict`, fail-closed) — the two reads have deliberately
|
|
288
|
+
// different fault models (selection fails closed; the surface degrades).
|
|
289
|
+
// Read from the SAME coordination remote the subtraction used. A repo with no
|
|
290
|
+
// coordination remote has no lock refs to read — empty surface.
|
|
291
|
+
if (repo !== undefined && hasLockRemote) {
|
|
292
|
+
const lockHeld = await listItemLockEntries(cwd, lockRemote, env);
|
|
293
|
+
if (lockHeld.length > 0) {
|
|
294
|
+
repo.lockHeld = lockHeld;
|
|
295
|
+
}
|
|
296
|
+
}
|
|
297
|
+
|
|
298
|
+
// 4. De-dup: is the cwd's arbiter URL a registered hub mirror? Compare the
|
|
299
|
+
// cwd's mirror KEY (from its arbiter URL) against the registry's keys.
|
|
300
|
+
const {alsoRegistered, registeredMirrorPath} = resolveRegistration({
|
|
301
|
+
arbiterUrl: arbiter?.url,
|
|
302
|
+
config,
|
|
303
|
+
env,
|
|
304
|
+
});
|
|
305
|
+
|
|
306
|
+
return {
|
|
307
|
+
path: cwd,
|
|
308
|
+
participating: true,
|
|
309
|
+
repo,
|
|
310
|
+
totalItems: localReport.totalItems,
|
|
311
|
+
totalEligible: localReport.totalEligible,
|
|
312
|
+
alsoRegistered,
|
|
313
|
+
...(registeredMirrorPath !== undefined ? {registeredMirrorPath} : {}),
|
|
314
|
+
...(arbiter !== undefined ? {arbiter} : {}),
|
|
315
|
+
};
|
|
316
|
+
}
|
|
317
|
+
|
|
318
|
+
/**
|
|
319
|
+
* Resolve the cwd repo's arbiter + divergence. Reuses `arbiterStatus` to find
|
|
320
|
+
* the arbiter remote/URL, FETCHES its `main` first (warn + fall back to
|
|
321
|
+
* last-known on failure — NEVER errors, ADR §5/§6), then reads the divergence of
|
|
322
|
+
* local `main` vs `<arbiter>/main` in both directions. Returns `undefined` when
|
|
323
|
+
* no arbiter remote is configured (no divergence line to show).
|
|
324
|
+
*/
|
|
325
|
+
async function resolveCwdArbiter(input: {
|
|
326
|
+
cwd: string;
|
|
327
|
+
remote?: string;
|
|
328
|
+
warn?: (message: string) => void;
|
|
329
|
+
env?: NodeJS.ProcessEnv;
|
|
330
|
+
}): Promise<CwdArbiter | undefined> {
|
|
331
|
+
const {cwd, env} = input;
|
|
332
|
+
const status = arbiterStatus({cwd, remote: input.remote, env});
|
|
333
|
+
if (!status.configured) {
|
|
334
|
+
return undefined;
|
|
335
|
+
}
|
|
336
|
+
const remote = status.remote;
|
|
337
|
+
|
|
338
|
+
// Fetch-first ALSO for the cwd (the maintainer's explicit ask): refresh the
|
|
339
|
+
// arbiter's `main` before diffing, reusing scan-status-fetch-first's
|
|
340
|
+
// fetch+warn+fallback. A failed fetch is NOT fatal — warn + last-known.
|
|
341
|
+
let fetched = false;
|
|
342
|
+
const fetch = await runAsync('git', ['fetch', '--quiet', remote], cwd, {env});
|
|
343
|
+
if (fetch.status === 0) {
|
|
344
|
+
fetched = true;
|
|
345
|
+
} else {
|
|
346
|
+
input.warn?.(
|
|
347
|
+
`could not fetch the cwd repo's arbiter '${remote}'; ` +
|
|
348
|
+
'computing local divergence from last-known (offline). ' +
|
|
349
|
+
fetch.stderr.trim(),
|
|
350
|
+
);
|
|
351
|
+
}
|
|
352
|
+
|
|
353
|
+
const {ahead, behind} = await localMainDivergence(cwd, remote, env);
|
|
354
|
+
return {
|
|
355
|
+
remote,
|
|
356
|
+
configured: true,
|
|
357
|
+
url: status.url,
|
|
358
|
+
fetched,
|
|
359
|
+
ahead,
|
|
360
|
+
behind,
|
|
361
|
+
};
|
|
362
|
+
}
|
|
363
|
+
|
|
364
|
+
/**
|
|
365
|
+
* De-dup helper: is the cwd repo (identified by its arbiter URL) ALSO registered
|
|
366
|
+
* in the registry? The registry keys a mirror off its arbiter URL via
|
|
367
|
+
* `encodeRepoKey`/`mirrorPath`, so we encode the cwd's arbiter URL the same way
|
|
368
|
+
* and look for a matching registered mirror (by key, robust to the lossy URL).
|
|
369
|
+
* Returns whether it is registered + the matching mirror path (so the registry
|
|
370
|
+
* view can drop that row). With no arbiter URL there is nothing to match.
|
|
371
|
+
*/
|
|
372
|
+
function resolveRegistration(input: {
|
|
373
|
+
arbiterUrl: string | undefined;
|
|
374
|
+
config: Config;
|
|
375
|
+
env?: NodeJS.ProcessEnv;
|
|
376
|
+
}): {alsoRegistered: boolean; registeredMirrorPath?: string} {
|
|
377
|
+
const {arbiterUrl, config, env} = input;
|
|
378
|
+
if (arbiterUrl === undefined || arbiterUrl.trim() === '') {
|
|
379
|
+
return {alsoRegistered: false};
|
|
380
|
+
}
|
|
381
|
+
const cwdKey = encodeRepoKey(arbiterUrl);
|
|
382
|
+
const cwdMirrorPath = mirrorPath(config.workspacesDir, arbiterUrl);
|
|
383
|
+
for (const mirror of listMirrors({
|
|
384
|
+
workspacesDir: config.workspacesDir,
|
|
385
|
+
env,
|
|
386
|
+
})) {
|
|
387
|
+
if (mirror.key === cwdKey || mirror.path === cwdMirrorPath) {
|
|
388
|
+
return {alsoRegistered: true, registeredMirrorPath: mirror.path};
|
|
389
|
+
}
|
|
390
|
+
}
|
|
391
|
+
return {alsoRegistered: false};
|
|
392
|
+
}
|
|
@@ -0,0 +1,272 @@
|
|
|
1
|
+
import {extractJsonObjectSpan} from './verdict-json.js';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* **The SHARED decision engine** (prd
|
|
5
|
+
* `agentic-question-resolution-retire-disposition-vocabulary` US #9, decision 3 +
|
|
6
|
+
* 13/14; task `decision-engine-shared-decide-seam`): the GENERALISED
|
|
7
|
+
* `decide(input, allowedOutcomes) → verdict` core every question-resolution
|
|
8
|
+
* decision is built on. It is the same `prompt → VERDICT → dispatch` shape
|
|
9
|
+
* `intake` already has, lifted into ONE outcome-AGNOSTIC engine so intake and the
|
|
10
|
+
* advance-apply rung share the machinery WITHOUT being forced to identical
|
|
11
|
+
* verdicts or inputs.
|
|
12
|
+
*
|
|
13
|
+
* Two things are parameters, NOT hard-coded into the engine:
|
|
14
|
+
*
|
|
15
|
+
* - **the INPUT-ADAPTER** ({@link DecisionDecider}'s `TInput`): each caller's
|
|
16
|
+
* front door reads a DIFFERENT thing (intake reads an issue + its comment
|
|
17
|
+
* thread; advance-apply reads an answered sidecar + its source item). The engine
|
|
18
|
+
* never knows that shape — it threads the caller's `input` opaquely to the
|
|
19
|
+
* injected decider, so the adapter boundary sits OUTSIDE the engine (decision 3:
|
|
20
|
+
* "the INPUT adapter differs per front door and is NOT forced to be shared").
|
|
21
|
+
* - **the ALLOWED-OUTCOME SET** ({@link decide}'s `allowedOutcomes`): each caller
|
|
22
|
+
* passes the SUBSET of {@link DecisionOutcome} it permits — advance-apply allows
|
|
23
|
+
* `{task | prd | adr | delete | ask}`, intake keeps its own `{task | prd | ask |
|
|
24
|
+
* bounce}` (intake is NOT refactored onto this engine here — decision 13). The
|
|
25
|
+
* engine never hard-codes which outcomes a caller permits; it only VALIDATES the
|
|
26
|
+
* returned verdict against the set and rejects (loudly) one outside it
|
|
27
|
+
* (decision 14: "the engine stays outcome-AGNOSTIC", so `adr` can be added to a
|
|
28
|
+
* caller later WITHOUT re-architecting).
|
|
29
|
+
*
|
|
30
|
+
* This module is the PURE engine + its types ONLY — no fs, no git, no seam ops, no
|
|
31
|
+
* wiring into `sidecar.ts` / `apply-persist.ts` / `intake.ts`. The keystone apply
|
|
32
|
+
* task (`agentic-apply-retire-disposition-vocabulary`) consumes it next; intake
|
|
33
|
+
* adopting `adr` is a separate decision (the engine being agnostic means it CAN
|
|
34
|
+
* be added later).
|
|
35
|
+
*/
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* The SUPERSET of outcomes the engine knows — a "verdict" is what an agent
|
|
39
|
+
* decides to DO with an input (the analogue of intake's {@link IntakeOutcome}):
|
|
40
|
+
*
|
|
41
|
+
* - **task** — mint a self-contained task from the input.
|
|
42
|
+
* - **spec** — mint a spec from the input.
|
|
43
|
+
* - **adr** — mint an adr from the input (NO caller wires this yet; the keystone's
|
|
44
|
+
* allowed set will, and `agentic-apply-mint-adr-route` adds the route — decision
|
|
45
|
+
* 14 keeps the engine agnostic so this is added without re-architecting).
|
|
46
|
+
* - **delete** — delete the SOURCE the input is about (a direct, git-recoverable
|
|
47
|
+
* removal — decision 12).
|
|
48
|
+
* - **ask** — ask the operator a follow-up (re-pause; the conversation
|
|
49
|
+
* accumulates — decision 5).
|
|
50
|
+
*
|
|
51
|
+
* No caller is forced to allow ALL of these: each passes its own SUBSET to
|
|
52
|
+
* {@link decide}. The engine is agnostic to which subset a caller permits.
|
|
53
|
+
*/
|
|
54
|
+
// MIGRATE step (prd `prd-to-spec-vocabulary-cutover-and-migration-command`): the
|
|
55
|
+
// parent-spec verdict outcome is `'spec'` (renamed from `'prd'`); the decider
|
|
56
|
+
// prompt emits it and the parser accepts it. This is a fresh per-call LLM verdict
|
|
57
|
+
// (nothing `'prd'`-valued is persisted), so the rename needs no on-disk alias.
|
|
58
|
+
export type DecisionOutcome = 'task' | 'spec' | 'adr' | 'delete' | 'ask';
|
|
59
|
+
|
|
60
|
+
/**
|
|
61
|
+
* The VERDICT the decider returns — the chosen {@link DecisionOutcome} plus the
|
|
62
|
+
* DRAFTED content for that outcome (the analogue of {@link IntakeVerdict}). Every
|
|
63
|
+
* content field is OPTIONAL on the shape: a given verdict only fills the channels
|
|
64
|
+
* its outcome consumes (a `task` fills the task channels, an `ask` fills
|
|
65
|
+
* `question`, a `delete` may carry only a `reason`). The dispatching CALLER
|
|
66
|
+
* decides which channels it requires for each outcome it allows — the engine only
|
|
67
|
+
* guards the `outcome` discriminator against the allowed set, never the content
|
|
68
|
+
* (it stays outcome-agnostic).
|
|
69
|
+
*/
|
|
70
|
+
export interface DecisionVerdict {
|
|
71
|
+
/** Which outcome the decider chose for the input. */
|
|
72
|
+
outcome: DecisionOutcome;
|
|
73
|
+
/** The drafted task's content-derived slug (`task` outcome). */
|
|
74
|
+
taskSlug?: string;
|
|
75
|
+
/** The drafted task's `title:` (`task` outcome). */
|
|
76
|
+
taskTitle?: string;
|
|
77
|
+
/**
|
|
78
|
+
* The drafted task BODY (`task` outcome) — the markdown AFTER the frontmatter.
|
|
79
|
+
* The dispatching caller writes the frontmatter; the agent never writes
|
|
80
|
+
* git-visible files (the in-band boundary intake already follows).
|
|
81
|
+
*/
|
|
82
|
+
taskBody?: string;
|
|
83
|
+
/** The drafted spec's content-derived slug (`spec` outcome). */
|
|
84
|
+
specSlug?: string;
|
|
85
|
+
/** The drafted spec's `title:` (`spec` outcome). */
|
|
86
|
+
specTitle?: string;
|
|
87
|
+
/** The drafted spec BODY (`spec` outcome) — the markdown AFTER the frontmatter. */
|
|
88
|
+
specBody?: string;
|
|
89
|
+
/** The drafted adr's content-derived slug (`adr` outcome). */
|
|
90
|
+
adrSlug?: string;
|
|
91
|
+
/** The drafted adr's `title:` (`adr` outcome). */
|
|
92
|
+
adrTitle?: string;
|
|
93
|
+
/** The drafted adr BODY (`adr` outcome) — the markdown AFTER the frontmatter. */
|
|
94
|
+
adrBody?: string;
|
|
95
|
+
/**
|
|
96
|
+
* The reason the source should be deleted (`delete` outcome) — the caller
|
|
97
|
+
* carries it into the revertible deletion's commit message (decision 12: the
|
|
98
|
+
* delete is git-recoverable, the reason in the commit message).
|
|
99
|
+
*/
|
|
100
|
+
deleteReason?: string;
|
|
101
|
+
/**
|
|
102
|
+
* The drafted follow-up question(s) (`ask` outcome) — the caller appends them
|
|
103
|
+
* to the conversation and re-pauses (decision 5: reuse the existing
|
|
104
|
+
* append/re-pause loop).
|
|
105
|
+
*/
|
|
106
|
+
question?: string;
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
/**
|
|
110
|
+
* The DECISION step: given the caller's `input` (whatever its input-adapter
|
|
111
|
+
* shaped), return a {@link DecisionVerdict}. This is the INJECTED, STUBBABLE seam
|
|
112
|
+
* — exactly like intake's `IntakeDecider`: production wires a harness/agent; tests
|
|
113
|
+
* inject a CANNED verdict (no model, no network). The engine is generic over
|
|
114
|
+
* `TInput` so the adapter boundary sits in the CALLER, never in the engine.
|
|
115
|
+
*/
|
|
116
|
+
export type DecisionDecider<TInput> = (
|
|
117
|
+
input: TInput,
|
|
118
|
+
) => Promise<DecisionVerdict>;
|
|
119
|
+
|
|
120
|
+
/**
|
|
121
|
+
* Thrown when a returned verdict's `outcome` is OUTSIDE the caller's
|
|
122
|
+
* `allowedOutcomes`. The engine NEVER silently coerces an out-of-set verdict — a
|
|
123
|
+
* caller that does not allow `adr` can never receive an `adr` verdict; it gets
|
|
124
|
+
* this loud rejection instead (the allowed-outcome guard).
|
|
125
|
+
*/
|
|
126
|
+
export class DisallowedOutcomeError extends Error {
|
|
127
|
+
/** The outcome the decider returned that was not permitted. */
|
|
128
|
+
readonly outcome: DecisionOutcome;
|
|
129
|
+
/** The set the caller allowed (the SUBSET it passed to {@link decide}). */
|
|
130
|
+
readonly allowed: readonly DecisionOutcome[];
|
|
131
|
+
constructor(outcome: DecisionOutcome, allowed: readonly DecisionOutcome[]) {
|
|
132
|
+
super(
|
|
133
|
+
`decision verdict 'outcome' ${JSON.stringify(outcome)} is not in the ` +
|
|
134
|
+
`caller's allowed set {${allowed.join(' | ')}}; the engine rejects an ` +
|
|
135
|
+
`out-of-set verdict rather than coercing it.`,
|
|
136
|
+
);
|
|
137
|
+
this.name = 'DisallowedOutcomeError';
|
|
138
|
+
this.outcome = outcome;
|
|
139
|
+
this.allowed = allowed;
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
/**
|
|
144
|
+
* Thrown when `allowedOutcomes` itself is EMPTY — a caller that allows no outcome
|
|
145
|
+
* can never receive a valid verdict, so this is a programming error caught up
|
|
146
|
+
* front rather than surfaced as a confusing per-verdict rejection.
|
|
147
|
+
*/
|
|
148
|
+
export class EmptyAllowedOutcomesError extends Error {
|
|
149
|
+
constructor() {
|
|
150
|
+
super(
|
|
151
|
+
'decide() was called with an EMPTY allowedOutcomes set; a caller must ' +
|
|
152
|
+
'allow at least one outcome.',
|
|
153
|
+
);
|
|
154
|
+
this.name = 'EmptyAllowedOutcomesError';
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
/**
|
|
159
|
+
* **The engine core.** Run the injected `decide`r over the caller's `input`, then
|
|
160
|
+
* VALIDATE the returned verdict's `outcome` against `allowedOutcomes` — the
|
|
161
|
+
* caller's permitted SUBSET of {@link DecisionOutcome}. Returns the verdict
|
|
162
|
+
* verbatim when it is in the set; throws {@link DisallowedOutcomeError} (loudly)
|
|
163
|
+
* when it is not. Throws {@link EmptyAllowedOutcomesError} when the set is empty.
|
|
164
|
+
*
|
|
165
|
+
* The engine is outcome-AGNOSTIC: it hard-codes NO caller's outcomes and inspects
|
|
166
|
+
* ONLY the `outcome` discriminator (never the per-outcome content channels — those
|
|
167
|
+
* are the dispatching caller's concern). The INPUT-ADAPTER boundary sits in the
|
|
168
|
+
* caller: `input` is threaded opaquely to the decider, so the engine never knows
|
|
169
|
+
* its shape.
|
|
170
|
+
*
|
|
171
|
+
* @param input the caller's adapter-shaped input (issue thread, answered sidecar
|
|
172
|
+
* + source item, …) — opaque to the engine.
|
|
173
|
+
* @param decide the INJECTED decision seam (tests pass a canned verdict; prod a
|
|
174
|
+
* harness-backed one).
|
|
175
|
+
* @param allowedOutcomes the caller's permitted subset (an array or any
|
|
176
|
+
* iterable). Order is preserved in the rejection message.
|
|
177
|
+
*/
|
|
178
|
+
export async function decide<TInput>(
|
|
179
|
+
input: TInput,
|
|
180
|
+
decide: DecisionDecider<TInput>,
|
|
181
|
+
allowedOutcomes: Iterable<DecisionOutcome>,
|
|
182
|
+
): Promise<DecisionVerdict> {
|
|
183
|
+
const allowed = [...allowedOutcomes];
|
|
184
|
+
if (allowed.length === 0) {
|
|
185
|
+
throw new EmptyAllowedOutcomesError();
|
|
186
|
+
}
|
|
187
|
+
const allowedSet = new Set(allowed);
|
|
188
|
+
const verdict = await decide(input);
|
|
189
|
+
if (!allowedSet.has(verdict.outcome)) {
|
|
190
|
+
throw new DisallowedOutcomeError(verdict.outcome, allowed);
|
|
191
|
+
}
|
|
192
|
+
return verdict;
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
/**
|
|
196
|
+
* Parse a decider's emitted VERDICT out of its (possibly prose-wrapped / fenced)
|
|
197
|
+
* textual output into a {@link DecisionVerdict} — the PRODUCTION-WIRE helper a
|
|
198
|
+
* harness-backed {@link DecisionDecider} uses to recover the verdict an agent
|
|
199
|
+
* emitted, modeled 1:1 on intake's `parseIntakeVerdict`. It pulls the first JSON
|
|
200
|
+
* object carrying an `"outcome"` field via the SHARED {@link extractJsonObjectSpan}
|
|
201
|
+
* (the same extractor every prompt→verdict→dispatch seam in this package uses —
|
|
202
|
+
* NOT a forked copy), `JSON.parse`s it, and validates the shape:
|
|
203
|
+
* `outcome ∈ {task,spec,adr,delete,ask}`.
|
|
204
|
+
*
|
|
205
|
+
* This validates the verdict is a WELL-FORMED member of the SUPERSET; the
|
|
206
|
+
* caller-specific allowed-outcome guard ({@link decide}) then rejects one outside
|
|
207
|
+
* the caller's SUBSET. The two checks are distinct: shape here, policy there.
|
|
208
|
+
*
|
|
209
|
+
* THROWS a clear error on: no JSON object present, invalid JSON, or an `outcome`
|
|
210
|
+
* not in the superset. A harness-backed decider lets the throw propagate so the
|
|
211
|
+
* caller maps it onto its own agent-failed path (a malformed verdict degrades
|
|
212
|
+
* honestly, never a crash and never a silent dispatch).
|
|
213
|
+
*/
|
|
214
|
+
export function parseDecisionVerdict(output: string): DecisionVerdict {
|
|
215
|
+
const span = extractJsonObjectSpan(output, 'outcome');
|
|
216
|
+
if (span === undefined) {
|
|
217
|
+
throw new Error(
|
|
218
|
+
'decision agent produced no parseable {outcome, …} verdict.',
|
|
219
|
+
);
|
|
220
|
+
}
|
|
221
|
+
let parsed: unknown;
|
|
222
|
+
try {
|
|
223
|
+
parsed = JSON.parse(output.slice(span.start, span.end));
|
|
224
|
+
} catch (err) {
|
|
225
|
+
throw new Error(
|
|
226
|
+
`decision verdict was not valid JSON: ${(err as Error).message}`,
|
|
227
|
+
);
|
|
228
|
+
}
|
|
229
|
+
if (typeof parsed !== 'object' || parsed === null) {
|
|
230
|
+
throw new Error('decision verdict was not an object.');
|
|
231
|
+
}
|
|
232
|
+
const obj = parsed as Record<string, unknown>;
|
|
233
|
+
const outcome = obj.outcome;
|
|
234
|
+
if (
|
|
235
|
+
outcome !== 'task' &&
|
|
236
|
+
outcome !== 'spec' &&
|
|
237
|
+
outcome !== 'adr' &&
|
|
238
|
+
outcome !== 'delete' &&
|
|
239
|
+
outcome !== 'ask'
|
|
240
|
+
) {
|
|
241
|
+
throw new Error(
|
|
242
|
+
`decision verdict 'outcome' was not one of task|spec|adr|delete|ask (got ` +
|
|
243
|
+
`${JSON.stringify(outcome)}).`,
|
|
244
|
+
);
|
|
245
|
+
}
|
|
246
|
+
// Map the per-outcome fields onto the verdict shape, keeping ONLY the strings
|
|
247
|
+
// the dispatcher consumes (a missing optional stays absent). Every field is
|
|
248
|
+
// optional on the type, so each outcome's content is carried verbatim when
|
|
249
|
+
// present — the engine never demands a channel (it stays outcome-agnostic).
|
|
250
|
+
const str = (v: unknown): string | undefined =>
|
|
251
|
+
typeof v === 'string' ? v : undefined;
|
|
252
|
+
return {
|
|
253
|
+
outcome,
|
|
254
|
+
...(str(obj.taskSlug) !== undefined ? {taskSlug: str(obj.taskSlug)} : {}),
|
|
255
|
+
...(str(obj.taskTitle) !== undefined
|
|
256
|
+
? {taskTitle: str(obj.taskTitle)}
|
|
257
|
+
: {}),
|
|
258
|
+
...(str(obj.taskBody) !== undefined ? {taskBody: str(obj.taskBody)} : {}),
|
|
259
|
+
...(str(obj.specSlug) !== undefined ? {specSlug: str(obj.specSlug)} : {}),
|
|
260
|
+
...(str(obj.specTitle) !== undefined
|
|
261
|
+
? {specTitle: str(obj.specTitle)}
|
|
262
|
+
: {}),
|
|
263
|
+
...(str(obj.specBody) !== undefined ? {specBody: str(obj.specBody)} : {}),
|
|
264
|
+
...(str(obj.adrSlug) !== undefined ? {adrSlug: str(obj.adrSlug)} : {}),
|
|
265
|
+
...(str(obj.adrTitle) !== undefined ? {adrTitle: str(obj.adrTitle)} : {}),
|
|
266
|
+
...(str(obj.adrBody) !== undefined ? {adrBody: str(obj.adrBody)} : {}),
|
|
267
|
+
...(str(obj.deleteReason) !== undefined
|
|
268
|
+
? {deleteReason: str(obj.deleteReason)}
|
|
269
|
+
: {}),
|
|
270
|
+
...(str(obj.question) !== undefined ? {question: str(obj.question)} : {}),
|
|
271
|
+
};
|
|
272
|
+
}
|