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,337 @@
|
|
|
1
|
+
import {NullHarness, type Harness} from './harness.js';
|
|
2
|
+
import {launchWithOptionalWatch} from './agent-launch.js';
|
|
3
|
+
import {boundaryLine} from './watch-session.js';
|
|
4
|
+
import {extractJsonObjectSpan} from './verdict-json.js';
|
|
5
|
+
import {parseableJsonContractPrompt} from './review-verdict.js';
|
|
6
|
+
import type {NewQuestion} from './sidecar.js';
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* The **SURFACE gate** (prd `advance-loop`, task `advance-rung-surface`,
|
|
10
|
+
* US #32/33) — the surface-question rung's fresh-context spawn, the DIRECT mirror
|
|
11
|
+
* of the PR/code review gate ({@link import('./review-gate.js')}). On
|
|
12
|
+
* `classify=surface`, the advance engine spawns a FRESH-CONTEXT agent with the
|
|
13
|
+
* `surface-questions` SKILL loaded (`skills/surface-questions/SKILL.md`); the
|
|
14
|
+
* skill GATHERS the item's open-judgement residue and EMITS questions and writes
|
|
15
|
+
* NOTHING (doc-shaped, like `review`). The ENGINE then ITSELF persists them to
|
|
16
|
+
* the sidecar CAS-atomically + sets `needsAnswers:true` (task
|
|
17
|
+
* `advance-rung-surface`'s persist half) — **the skill JUDGES, the engine
|
|
18
|
+
* PERSISTS.**
|
|
19
|
+
*
|
|
20
|
+
* This module is the SEAM (the {@link SurfaceGate} function type) + its
|
|
21
|
+
* production harness-backed implementation ({@link harnessSurfaceGate}), exactly
|
|
22
|
+
* as `review-gate.ts` is the seam + `harnessReviewGate`. The seam is injectable:
|
|
23
|
+
* tests stub a canned emitted-questions list (no real model); production launches
|
|
24
|
+
* the `surface-questions` agent through the EXISTING harness seam
|
|
25
|
+
* ({@link Harness}/`LaunchInput`), routing an optional `surfaceModel` override
|
|
26
|
+
* through `LaunchInput.model` — NOT a new model/launch mechanism (the §13
|
|
27
|
+
* model-routing intent). It mirrors `harnessReviewGate` byte-for-byte in shape;
|
|
28
|
+
* only the PROMPT ({@link buildSurfacePrompt}) and the parsed payload
|
|
29
|
+
* ({@link parseSurfaceEmit}, a `{questions}` list rather than a `{verdict}`)
|
|
30
|
+
* differ.
|
|
31
|
+
*
|
|
32
|
+
* ALWAYS-allowed: there is NO gate check before surfacing — surfacing a question
|
|
33
|
+
* is never gated, even with every autonomy flag off (the "question loop with zero
|
|
34
|
+
* autonomy" case, US #23). The expensive (agent/model) work is POST-lock,
|
|
35
|
+
* winner-only — but that sequencing is the ENGINE's job (`advance.ts`); this
|
|
36
|
+
* module is only the spawn→emit→parse.
|
|
37
|
+
*/
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* One question the `surface-questions` skill EMITS — the THREE authoring fields of
|
|
41
|
+
* the sidecar entry shape (`skills/surface-questions/SKILL.md` → "The emitted
|
|
42
|
+
* question shape"). It maps 1:1 onto {@link NewQuestion} (what the engine appends
|
|
43
|
+
* to the sidecar), so the engine persists with ZERO translation. The skill does
|
|
44
|
+
* NOT assign `id`/`answered`/`answer`/`allAnswered` — those are the sidecar's
|
|
45
|
+
* machine-owned fields the engine owns. A surfaced question is a PLAIN question:
|
|
46
|
+
* there is NO `disposition` token any more (task
|
|
47
|
+
* `agentic-apply-retire-disposition-vocabulary`) — what to DO with the answered
|
|
48
|
+
* signal is decided by the AGENTIC apply decision, not stamped on the question.
|
|
49
|
+
*/
|
|
50
|
+
export interface SurfaceQuestion {
|
|
51
|
+
/** The question, verbatim. */
|
|
52
|
+
question: string;
|
|
53
|
+
/** Inline context so the human need not open the item. */
|
|
54
|
+
context?: string;
|
|
55
|
+
/** Optional suggested default (the humility aid; NEVER a decision). */
|
|
56
|
+
default?: string;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
/**
|
|
60
|
+
* What the `surface-questions` SKILL emits (and this gate parses): the item's
|
|
61
|
+
* identity (orientation only) + an ORDERED list of questions. An EMPTY list is a
|
|
62
|
+
* valid, honest result ("no open judgement") — the engine writes no sidecar.
|
|
63
|
+
*/
|
|
64
|
+
export interface SurfaceEmit {
|
|
65
|
+
/** The namespaced identity the skill surfaced for (orientation; advisory). */
|
|
66
|
+
item?: string;
|
|
67
|
+
/** The ordered emitted questions (possibly empty). */
|
|
68
|
+
questions: SurfaceQuestion[];
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
/** What the surface gate needs to launch a fresh-context surface of one item. */
|
|
72
|
+
export interface SurfaceGateInput {
|
|
73
|
+
/** The namespaced identity the surface is for (`task:foo` / `prd:bar` / `observation:baz`). */
|
|
74
|
+
item: string;
|
|
75
|
+
/** The working clone/checkout the gate runs in. */
|
|
76
|
+
cwd: string;
|
|
77
|
+
/**
|
|
78
|
+
* The model the SURFACE agent runs on. `undefined` ⇒ no forced model (the
|
|
79
|
+
* harness's own default). Flows to the launch through `LaunchInput.model`.
|
|
80
|
+
*/
|
|
81
|
+
surfaceModel?: string;
|
|
82
|
+
/** Environment for the surface-agent launch. */
|
|
83
|
+
env?: NodeJS.ProcessEnv;
|
|
84
|
+
/** `--watch`: tail the surface agent's pi session live (pure observer). */
|
|
85
|
+
watch?: boolean;
|
|
86
|
+
/** Where the tailed surface lines are written (defaults to stderr). */
|
|
87
|
+
watchSink?: (line: string) => void;
|
|
88
|
+
/** Emit ANSI colour in the tailed surface lines (the caller's TTY decision). */
|
|
89
|
+
color?: boolean;
|
|
90
|
+
/** The HOST-ONLY sessions root the surface session FILE is generated under. */
|
|
91
|
+
sessionsDir?: string;
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
/**
|
|
95
|
+
* The surface-gate SEAM: run a fresh-context surface of the item and return the
|
|
96
|
+
* parsed emitted questions. Injected by tests (a canned list, no real model);
|
|
97
|
+
* production uses {@link harnessSurfaceGate}. Mirrors `review-gate.ts`'s
|
|
98
|
+
* `ReviewGate` seam shape so the engine wiring is testable as pure logic.
|
|
99
|
+
*/
|
|
100
|
+
export type SurfaceGate = (input: SurfaceGateInput) => Promise<SurfaceEmit>;
|
|
101
|
+
|
|
102
|
+
/** Raised when the surface agent ran but produced no parseable emit. */
|
|
103
|
+
export class SurfaceParseError extends Error {}
|
|
104
|
+
|
|
105
|
+
/**
|
|
106
|
+
* Parse the `surface-questions` SKILL's emitted questions out of the surface
|
|
107
|
+
* agent's textual output. The skill emits a `{item, questions:[…]}` JSON object
|
|
108
|
+
* (the agent may wrap it in prose / a fenced block), so we extract the first JSON
|
|
109
|
+
* object carrying a `questions` field and validate its shape. An EMPTY
|
|
110
|
+
* `questions` list is VALID (the honest "no open judgement" result). Throws
|
|
111
|
+
* {@link SurfaceParseError} when no valid emit is present (the caller treats an
|
|
112
|
+
* unparseable emit as an error — never a silent "surfaced nothing").
|
|
113
|
+
*
|
|
114
|
+
* The emit MAY also carry a free-prose `note` field (the surface counterpart of
|
|
115
|
+
* the verdict's `review`): a HOME inside the object for the agent's reasoning /
|
|
116
|
+
* findings so it never needs to write prose AROUND the JSON (the cause of the
|
|
117
|
+
* "no parseable {questions}" trailing-chatter failure — observation
|
|
118
|
+
* `surface-rung-agent-emits-no-parseable-questions`). The engine does not
|
|
119
|
+
* persist `note`, so it is simply IGNORED here (like every unrecognised field);
|
|
120
|
+
* the prompt's job is to give the prose a place to go, not the parser's to keep
|
|
121
|
+
* it.
|
|
122
|
+
*/
|
|
123
|
+
export function parseSurfaceEmit(output: string): SurfaceEmit {
|
|
124
|
+
const span = extractJsonObjectSpan(output, 'questions');
|
|
125
|
+
if (span === undefined) {
|
|
126
|
+
throw new SurfaceParseError(
|
|
127
|
+
'surface agent produced no parseable {questions} result',
|
|
128
|
+
);
|
|
129
|
+
}
|
|
130
|
+
let parsed: unknown;
|
|
131
|
+
try {
|
|
132
|
+
parsed = JSON.parse(output.slice(span.start, span.end));
|
|
133
|
+
} catch (err) {
|
|
134
|
+
throw new SurfaceParseError(
|
|
135
|
+
`surface emit was not valid JSON: ${(err as Error).message}`,
|
|
136
|
+
);
|
|
137
|
+
}
|
|
138
|
+
return validateEmit(parsed);
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
/** Validate a parsed object is a `{item?, questions:[…]}` shape; normalise it. */
|
|
142
|
+
function validateEmit(parsed: unknown): SurfaceEmit {
|
|
143
|
+
if (typeof parsed !== 'object' || parsed === null) {
|
|
144
|
+
throw new SurfaceParseError('surface emit was not an object');
|
|
145
|
+
}
|
|
146
|
+
const obj = parsed as Record<string, unknown>;
|
|
147
|
+
if (!Array.isArray(obj.questions)) {
|
|
148
|
+
throw new SurfaceParseError(
|
|
149
|
+
'surface emit had no `questions` array (an empty array is valid; absence is not)',
|
|
150
|
+
);
|
|
151
|
+
}
|
|
152
|
+
const questions: SurfaceQuestion[] = obj.questions.map((q) => {
|
|
153
|
+
const item = (typeof q === 'object' && q !== null ? q : {}) as Record<
|
|
154
|
+
string,
|
|
155
|
+
unknown
|
|
156
|
+
>;
|
|
157
|
+
const question: SurfaceQuestion = {
|
|
158
|
+
question: typeof item.question === 'string' ? item.question : '',
|
|
159
|
+
};
|
|
160
|
+
if (typeof item.context === 'string' && item.context !== '') {
|
|
161
|
+
question.context = item.context;
|
|
162
|
+
}
|
|
163
|
+
if (typeof item.default === 'string' && item.default !== '') {
|
|
164
|
+
question.default = item.default;
|
|
165
|
+
}
|
|
166
|
+
return question;
|
|
167
|
+
});
|
|
168
|
+
return {
|
|
169
|
+
...(typeof obj.item === 'string' ? {item: obj.item} : {}),
|
|
170
|
+
// A question with an EMPTY `question` string carries no judgement — drop it
|
|
171
|
+
// (the agent may have emitted a placeholder), so an all-empty list is the
|
|
172
|
+
// same honest "no open judgement" as an empty array.
|
|
173
|
+
questions: questions.filter((q) => q.question.trim() !== ''),
|
|
174
|
+
};
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
/**
|
|
178
|
+
* Convert the emitted questions to the {@link NewQuestion} shape the engine
|
|
179
|
+
* appends to the sidecar — a 1:1 field map (the emit shape IS the sidecar
|
|
180
|
+
* authoring shape, by design), so the engine persists with ZERO translation.
|
|
181
|
+
*/
|
|
182
|
+
export function toNewQuestions(emit: SurfaceEmit): NewQuestion[] {
|
|
183
|
+
return emit.questions.map((q) => {
|
|
184
|
+
const nq: NewQuestion = {question: q.question};
|
|
185
|
+
if (q.context !== undefined) {
|
|
186
|
+
nq.context = q.context;
|
|
187
|
+
}
|
|
188
|
+
if (q.default !== undefined) {
|
|
189
|
+
nq.default = q.default;
|
|
190
|
+
}
|
|
191
|
+
return nq;
|
|
192
|
+
});
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
/**
|
|
196
|
+
* Render the surface-agent PROMPT: instruct a fresh-context agent to apply the
|
|
197
|
+
* **surface-questions discipline** (`work/protocol/SURFACE-PROTOCOL.md`) to ONE
|
|
198
|
+
* `work/` item and to EMIT a single `{item, questions}` JSON object (so
|
|
199
|
+
* {@link parseSurfaceEmit} can read it). The discipline body (the two laws —
|
|
200
|
+
* GATHER-only / PERSIST-NEVER — the humility rule, the composed sources, the
|
|
201
|
+
* emitted-question shape) lives in `SURFACE-PROTOCOL.md` — NOT inlined here
|
|
202
|
+
* (task `surface-protocol-doc-and-prompt`). The shape's source of truth is
|
|
203
|
+
* {@link parseSurfaceEmit}; the doc DESCRIBES it (D2).
|
|
204
|
+
*
|
|
205
|
+
* This builder owns ONLY the PER-BUILDER framing: who you are (a fresh-context
|
|
206
|
+
* question-surfacer, the engine's surface-question rung), what you are
|
|
207
|
+
* surfacing (ONE namespaced item), and the required JSON output shape. It
|
|
208
|
+
* MIRRORS {@link buildReviewPrompt}: a fresh-context agent that EDITS nothing
|
|
209
|
+
* and EMITS a single structured object the ENGINE routes/persists.
|
|
210
|
+
*/
|
|
211
|
+
export function buildSurfacePrompt(item: string): string {
|
|
212
|
+
return [
|
|
213
|
+
`You are a FRESH-CONTEXT question-surfacer for the work/ item "${item}".`,
|
|
214
|
+
`Apply the surface-questions discipline defined in`,
|
|
215
|
+
`\`work/protocol/SURFACE-PROTOCOL.md\` (the in-band, protocol-native`,
|
|
216
|
+
`surface-questions protocol every set-up repo carries; the human-facing`,
|
|
217
|
+
`pointer is \`skills/surface-questions/SKILL.md\`) to this ONE item:`,
|
|
218
|
+
`formulate its open questions and EMIT them. Its two laws, its humility`,
|
|
219
|
+
`aid, the composed sources you draw from, and the emitted-question shape`,
|
|
220
|
+
`ALL live in that doc — read them there.`,
|
|
221
|
+
`The skill JUDGES; the engine PERSISTS.`,
|
|
222
|
+
``,
|
|
223
|
+
`Do NOT edit any files, run no git — you EMIT questions only.`,
|
|
224
|
+
``,
|
|
225
|
+
`Your investigation may be substantial (you compose review's verdict, you`,
|
|
226
|
+
`probe an observation against current reality). Put ANY explanation,`,
|
|
227
|
+
`reasoning, or "here is what I found" prose IN the \`note\` field of the JSON`,
|
|
228
|
+
`below — that is its home. This MIRRORS Gate-2's verdict, which carries its`,
|
|
229
|
+
`human-readable prose in a \`review\` field for exactly this reason: with a`,
|
|
230
|
+
`channel for prose INSIDE the object, you never need to write anything`,
|
|
231
|
+
`around it.`,
|
|
232
|
+
``,
|
|
233
|
+
`The single JSON object below MUST be your FINAL and ONLY output. Do NOT`,
|
|
234
|
+
`narrate your process ("Let me check…"), do NOT add any remark, summary, or`,
|
|
235
|
+
`sign-off BEFORE or AFTER it, and do NOT take any further turn once you have`,
|
|
236
|
+
`emitted it — emitting the object is how you finish. A trailing chatty turn`,
|
|
237
|
+
`after the object strands the run (the reader sees only your last turn).`,
|
|
238
|
+
``,
|
|
239
|
+
`Output ONLY a single JSON object of this exact shape (no prose OUTSIDE it;`,
|
|
240
|
+
`see \`SURFACE-PROTOCOL.md\` → "The emitted question shape" for the`,
|
|
241
|
+
`prose-described contract this mirrors). The example below is EXPANDED over`,
|
|
242
|
+
`several lines for READABILITY, but you MUST emit it MINIFIED — ONE single`,
|
|
243
|
+
`line, no newlines between the keys:`,
|
|
244
|
+
``,
|
|
245
|
+
'```json',
|
|
246
|
+
`{"item": "${item}",`,
|
|
247
|
+
` "questions": [`,
|
|
248
|
+
` {"question": "…",`,
|
|
249
|
+
` "context": "…",`,
|
|
250
|
+
` "default": "… (optional; omit if none)"}`,
|
|
251
|
+
` ],`,
|
|
252
|
+
` "note": "… (optional; your reasoning / findings prose lives HERE, not outside the object)"}`,
|
|
253
|
+
'```',
|
|
254
|
+
``,
|
|
255
|
+
`An EMPTY \`questions\` array is a VALID, honest result (no open judgement) —`,
|
|
256
|
+
`emit the object with \`"questions": []\` (put WHY in \`note\`); do NOT replace`,
|
|
257
|
+
`it with a prose explanation. Absence of the field is NOT valid.`,
|
|
258
|
+
``,
|
|
259
|
+
// The SHARED defensive-JSON contract (the same hardening Gate-2's verdict
|
|
260
|
+
// prompt carries) — the surface rung hit the IDENTICAL unparseable-emit
|
|
261
|
+
// failure the verdict gate did, so it reuses the one contract rather than
|
|
262
|
+
// staying the lone un-hardened seam. The longest field is `note` (the free
|
|
263
|
+
// prose channel, the surface counterpart of the verdict's `review`).
|
|
264
|
+
parseableJsonContractPrompt('result', 'note'),
|
|
265
|
+
].join('\n');
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
/** What a harness-backed surface gate needs to launch the surface agent. */
|
|
269
|
+
export interface HarnessSurfaceGateOptions {
|
|
270
|
+
/** The harness seam used to launch the fresh-context surface agent. */
|
|
271
|
+
harness?: Harness;
|
|
272
|
+
/** The agent command the null/shell adapter shells out to (`{model}`-aware). */
|
|
273
|
+
agentCmd?: string;
|
|
274
|
+
/**
|
|
275
|
+
* Read the surface agent's textual output for parsing. Production reads
|
|
276
|
+
* `launched.output` (the ANSWER channel, distinct from `detail`); tests inject
|
|
277
|
+
* `readOutput` to stub a canned emit string.
|
|
278
|
+
*/
|
|
279
|
+
readOutput?: (output: string | undefined) => string;
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
/**
|
|
283
|
+
* The PRODUCTION surface gate: launch the `surface-questions` SKILL as a
|
|
284
|
+
* fresh-context agent through the EXISTING harness seam, routing the
|
|
285
|
+
* `surfaceModel` override via `LaunchInput.model` (the §13 model-routing intent —
|
|
286
|
+
* NOT a new mechanism), then parse the emitted `{item, questions}`. It is the
|
|
287
|
+
* DIRECT mirror of `harnessReviewGate`: a SEPARATE harness launch (fresh context
|
|
288
|
+
* = not the engine's session) in the same checkout `cwd`, fed
|
|
289
|
+
* {@link buildSurfacePrompt}; the model flows through `LaunchInput.model`, which
|
|
290
|
+
* each adapter injects natively. The surface uses a DISTINCT session id
|
|
291
|
+
* (`<item>-surface`) so its session never collides with a build/review session.
|
|
292
|
+
*/
|
|
293
|
+
export function harnessSurfaceGate(
|
|
294
|
+
options: HarnessSurfaceGateOptions = {},
|
|
295
|
+
): SurfaceGate {
|
|
296
|
+
const harness = options.harness ?? new NullHarness();
|
|
297
|
+
const readOutput = options.readOutput ?? ((output) => output ?? '');
|
|
298
|
+
return async (input: SurfaceGateInput): Promise<SurfaceEmit> => {
|
|
299
|
+
if (input.watch === true) {
|
|
300
|
+
const sink =
|
|
301
|
+
input.watchSink ??
|
|
302
|
+
((line: string) => process.stderr.write(`${line}\n`));
|
|
303
|
+
sink(
|
|
304
|
+
boundaryLine(
|
|
305
|
+
`surface — gathering questions for ${input.item}…`,
|
|
306
|
+
input.color ?? false,
|
|
307
|
+
),
|
|
308
|
+
);
|
|
309
|
+
}
|
|
310
|
+
// A safe session-id stem (the namespaced identity has a `:` that is not a
|
|
311
|
+
// valid path stem). The same `:`→`-` convention the sidecar/lock identity uses.
|
|
312
|
+
const sessionId = `${input.item.replace(/:/g, '-')}-surface`;
|
|
313
|
+
const launched = await launchWithOptionalWatch({
|
|
314
|
+
harness,
|
|
315
|
+
dir: input.cwd,
|
|
316
|
+
slug: input.item,
|
|
317
|
+
command: options.agentCmd ?? '',
|
|
318
|
+
prompt: buildSurfacePrompt(input.item),
|
|
319
|
+
model: input.surfaceModel,
|
|
320
|
+
sessionId,
|
|
321
|
+
sessionsDir: input.sessionsDir,
|
|
322
|
+
watch: input.watch,
|
|
323
|
+
watchSink: input.watchSink,
|
|
324
|
+
color: input.color,
|
|
325
|
+
env: input.env,
|
|
326
|
+
});
|
|
327
|
+
if (!launched.ok) {
|
|
328
|
+
throw new SurfaceParseError(
|
|
329
|
+
`surface agent launch failed${launched.detail ? `: ${launched.detail}` : ''}`,
|
|
330
|
+
);
|
|
331
|
+
}
|
|
332
|
+
// Read the emit from the agent's ANSWER channel (`output`), NOT `detail`
|
|
333
|
+
// (empty on success). An empty/absent output → parseSurfaceEmit throws → the
|
|
334
|
+
// engine surfaces nothing and reports it (never a silent success).
|
|
335
|
+
return parseSurfaceEmit(readOutput(launched.output));
|
|
336
|
+
};
|
|
337
|
+
}
|
|
@@ -0,0 +1,241 @@
|
|
|
1
|
+
import {existsSync, mkdirSync, readFileSync, writeFileSync} from 'node:fs';
|
|
2
|
+
import {dirname, join} from 'node:path';
|
|
3
|
+
import {run, type RunResult} from './git.js';
|
|
4
|
+
import {parseFrontmatter, setNeedsAnswersMarker} from './frontmatter.js';
|
|
5
|
+
import {
|
|
6
|
+
appendQuestions,
|
|
7
|
+
newSidecar,
|
|
8
|
+
parseSidecar,
|
|
9
|
+
serialiseSidecar,
|
|
10
|
+
sidecarPathFor,
|
|
11
|
+
type NewQuestion,
|
|
12
|
+
type SidecarModel,
|
|
13
|
+
} from './sidecar.js';
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* The engine-owned SURFACE PERSIST (prd `advance-loop`, task
|
|
17
|
+
* `advance-rung-surface`, US #15/33) — the half of the surface rung the ENGINE
|
|
18
|
+
* owns (the skill JUDGES, the engine PERSISTS). Given the questions the
|
|
19
|
+
* `surface-questions` skill EMITTED (gathered by `surface-gate.ts`'s spawn), the
|
|
20
|
+
* engine writes them to the sidecar `work/questions/<type>-<slug>.md` and sets
|
|
21
|
+
* `needsAnswers:true` on the item body — in ONE commit, exactly as the review
|
|
22
|
+
* gate persists a verdict and `applyAtomic` resolves an answer batch in one
|
|
23
|
+
* commit.
|
|
24
|
+
*
|
|
25
|
+
* It is the SIBLING of {@link import('./sidecar-apply.js').applyAtomic}: that is
|
|
26
|
+
* the APPLY rung's one-commit primitive (resolve/re-pause); this is the SURFACE
|
|
27
|
+
* rung's one-commit primitive (append-or-create + set `needsAnswers`). Kept in a
|
|
28
|
+
* SEPARATE module so the surface rung's persist and the apply rung's persist stay
|
|
29
|
+
* file-orthogonal (the rung bodies land in different tasks).
|
|
30
|
+
*
|
|
31
|
+
* The load-bearing rules (the task's acceptance criteria):
|
|
32
|
+
*
|
|
33
|
+
* - **Append-never-overwrite (US #15).** When a sidecar ALREADY exists, the new
|
|
34
|
+
* questions are APPENDED ({@link appendQuestions} mints `qN+1…`), NEVER
|
|
35
|
+
* overwriting an existing (answered or unanswered) entry. A re-surface that
|
|
36
|
+
* adds questions to a previously-all-answered sidecar FLIPS it back to
|
|
37
|
+
* not-all-answered (the appended entries are pending).
|
|
38
|
+
* - **Set `needsAnswers:true` atomically (invariant 1).** The item body's
|
|
39
|
+
* `needsAnswers` flag is set to `true` in the SAME commit the sidecar is
|
|
40
|
+
* written, so the `needsAnswers:true ⟺ active sidecar` invariant holds the
|
|
41
|
+
* instant the commit lands.
|
|
42
|
+
* - **Identity-keyed sidecar path.** The sidecar path derives PURELY from the
|
|
43
|
+
* item's namespaced identity ({@link sidecarPathFor}) — it survives the item's
|
|
44
|
+
* `git mv`s with no lock-step move.
|
|
45
|
+
*
|
|
46
|
+
* This is the LOCAL one-commit primitive over a working tree (the
|
|
47
|
+
* throwaway-git-repo test pattern the apply/lock tests use). The `advancing` CAS
|
|
48
|
+
* lock that makes this WINNER-ONLY is held by `performAdvance` BEFORE this is
|
|
49
|
+
* called — so the expensive spawn + this persist are both POST-lock. This module
|
|
50
|
+
* does NOT race the arbiter; that is the lock's job.
|
|
51
|
+
*/
|
|
52
|
+
|
|
53
|
+
export interface SurfacePersistOptions {
|
|
54
|
+
/** Working clone/worktree the persist commits in. */
|
|
55
|
+
cwd: string;
|
|
56
|
+
/** The namespaced item identity (`task:foo` / `prd:bar` / `observation:baz`). */
|
|
57
|
+
item: string;
|
|
58
|
+
/**
|
|
59
|
+
* The item file path RELATIVE to `cwd` (e.g. `work/backlog/foo.md`). The
|
|
60
|
+
* `needsAnswers:true` flag is set on THIS file; the sidecar path is derived
|
|
61
|
+
* from the identity, NOT from this path.
|
|
62
|
+
*/
|
|
63
|
+
itemPath: string;
|
|
64
|
+
/** The questions the `surface-questions` skill emitted (engine appends them). */
|
|
65
|
+
questions: NewQuestion[];
|
|
66
|
+
/** Advisory committer id for the commit subject. Defaults to git user.name. */
|
|
67
|
+
by?: string;
|
|
68
|
+
/** Environment for child git processes. */
|
|
69
|
+
env?: NodeJS.ProcessEnv;
|
|
70
|
+
/** Sink for human-readable progress notes. */
|
|
71
|
+
note?: (message: string) => void;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
export interface SurfacePersistResult {
|
|
75
|
+
/** `surfaced` (questions written + needsAnswers set) or `nothing` (empty emit). */
|
|
76
|
+
outcome: 'surfaced' | 'nothing';
|
|
77
|
+
/** The commit sha the persist produced (`undefined` on a `nothing` no-op). */
|
|
78
|
+
commit?: string;
|
|
79
|
+
/** The sidecar path (relative to `cwd`) the persist touched. */
|
|
80
|
+
sidecarPath: string;
|
|
81
|
+
/** How many entries the sidecar carries after this persist. */
|
|
82
|
+
entryCount: number;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
/** Raised for usage errors (a missing repo, an unreadable item). */
|
|
86
|
+
export class SurfacePersistError extends Error {
|
|
87
|
+
constructor(message: string) {
|
|
88
|
+
super(message);
|
|
89
|
+
this.name = 'SurfacePersistError';
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
function gitSoft(
|
|
94
|
+
args: string[],
|
|
95
|
+
cwd: string,
|
|
96
|
+
env: NodeJS.ProcessEnv | undefined,
|
|
97
|
+
): RunResult {
|
|
98
|
+
return run('git', args, cwd, {env});
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
function gitHard(
|
|
102
|
+
args: string[],
|
|
103
|
+
cwd: string,
|
|
104
|
+
env: NodeJS.ProcessEnv | undefined,
|
|
105
|
+
): RunResult {
|
|
106
|
+
const result = run('git', args, cwd, {env});
|
|
107
|
+
if (result.status !== 0) {
|
|
108
|
+
throw new SurfacePersistError(
|
|
109
|
+
`git ${args.join(' ')} failed (exit ${result.status}): ${result.stderr.trim()}`,
|
|
110
|
+
);
|
|
111
|
+
}
|
|
112
|
+
return result;
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
function resolveBy(cwd: string, env: NodeJS.ProcessEnv | undefined): string {
|
|
116
|
+
const name = gitSoft(['config', 'user.name'], cwd, env);
|
|
117
|
+
if (name.status === 0 && name.stdout.trim() !== '') {
|
|
118
|
+
return name.stdout.trim();
|
|
119
|
+
}
|
|
120
|
+
const e = env ?? process.env;
|
|
121
|
+
return e.USER ?? e.USERNAME ?? '';
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
/**
|
|
125
|
+
* Persist the SURFACED questions ATOMICALLY: APPEND them to the existing sidecar
|
|
126
|
+
* (or CREATE it first-pass), and set `needsAnswers:true` on the item body — ONE
|
|
127
|
+
* commit. An EMPTY question set is a clean NO-OP (no sidecar written, the item
|
|
128
|
+
* untouched): the honest "no open judgement" result the skill is allowed to
|
|
129
|
+
* emit; nothing to commit, so `needsAnswers` is NOT set.
|
|
130
|
+
*
|
|
131
|
+
* Append-never-overwrite: when a sidecar exists, the new questions are APPENDED
|
|
132
|
+
* (never mutating an answered entry); a re-surface flips a previously-all-answered
|
|
133
|
+
* sidecar back to not-all-answered. Returns the produced commit + the resulting
|
|
134
|
+
* entry count.
|
|
135
|
+
*/
|
|
136
|
+
export function persistSurfacedQuestions(
|
|
137
|
+
options: SurfacePersistOptions,
|
|
138
|
+
): SurfacePersistResult {
|
|
139
|
+
const {cwd, item, itemPath, questions, env} = options;
|
|
140
|
+
const note = options.note ?? (() => {});
|
|
141
|
+
|
|
142
|
+
if (gitSoft(['rev-parse', '--git-dir'], cwd, env).status !== 0) {
|
|
143
|
+
throw new SurfacePersistError('not inside a git repository');
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
const sidecarPath = sidecarPathFor(item);
|
|
147
|
+
const sidecarAbs = join(cwd, sidecarPath);
|
|
148
|
+
|
|
149
|
+
// Build the post-persist sidecar model: APPEND to an existing one (never
|
|
150
|
+
// overwrite), else CREATE first-pass. Read the current sidecar from the tree
|
|
151
|
+
// so the append is over the COMMITTED history (identity-keyed, folder-agnostic).
|
|
152
|
+
let model: SidecarModel;
|
|
153
|
+
const existing = readExistingSidecar(sidecarAbs);
|
|
154
|
+
if (existing !== undefined) {
|
|
155
|
+
model = appendQuestions(existing, questions);
|
|
156
|
+
} else {
|
|
157
|
+
model = newSidecar(item, questions);
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
// An empty emit ⇒ the sidecar would carry no entries: surface NOTHING (the
|
|
161
|
+
// honest result). Do NOT write a sidecar or set `needsAnswers` — a sidecar with
|
|
162
|
+
// no open questions should not exist (it keeps invariant 1 + the "pending ⇒
|
|
163
|
+
// NO-OP" classifier honest).
|
|
164
|
+
if (model.entries.length === 0) {
|
|
165
|
+
const message = `surface ${item}: no open judgement — nothing surfaced (no sidecar written).`;
|
|
166
|
+
note(message);
|
|
167
|
+
return {outcome: 'nothing', sidecarPath, entryCount: 0};
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
// Set `needsAnswers:true` on the item body (the only in-body signal — the
|
|
171
|
+
// sidecar path is identity-derived, no back-pointer). The item file may not
|
|
172
|
+
// have a `needsAnswers` line yet (and may be fence-less — observations are born
|
|
173
|
+
// that way); `setNeedsAnswersMarker` prepends a fence when needed and is
|
|
174
|
+
// idempotent otherwise.
|
|
175
|
+
const itemAbs = join(cwd, itemPath);
|
|
176
|
+
const itemBody = readItem(itemAbs, cwd, itemPath, env);
|
|
177
|
+
const flagged = setNeedsAnswersMarker(itemBody, true);
|
|
178
|
+
|
|
179
|
+
// DEFENSE IN DEPTH (the `sidecar-without-needsAnswers` guard): the surface
|
|
180
|
+
// commit is only atomic if the flag ACTUALLY landed. If — for any reason — the
|
|
181
|
+
// flag did not parse back as `true` (e.g. a degenerate body the marker writer
|
|
182
|
+
// cannot annotate), ABORT BEFORE writing the sidecar, so we never produce the
|
|
183
|
+
// torn invariant (sidecar present, flag absent) a later tick refuses to advance.
|
|
184
|
+
if (parseFrontmatter(flagged).needsAnswers !== true) {
|
|
185
|
+
throw new SurfacePersistError(
|
|
186
|
+
`surface ${item}: could not set needsAnswers:true on '${itemPath}' ` +
|
|
187
|
+
`(the item body could not be annotated) — refusing to write the sidecar ` +
|
|
188
|
+
`without the flag (that would tear the needsAnswers ⟺ sidecar invariant).`,
|
|
189
|
+
);
|
|
190
|
+
}
|
|
191
|
+
writeFileSync(itemAbs, flagged);
|
|
192
|
+
|
|
193
|
+
// Write the appended/created sidecar.
|
|
194
|
+
mkdirSync(dirname(sidecarAbs), {recursive: true});
|
|
195
|
+
writeFileSync(sidecarAbs, serialiseSidecar(model));
|
|
196
|
+
|
|
197
|
+
// Stage exactly the two paths and commit them TOGETHER (one atomic commit) —
|
|
198
|
+
// the sidecar write + the `needsAnswers:true` flip land in the SAME commit, so
|
|
199
|
+
// `needsAnswers:true ⟺ active sidecar` holds the instant it lands.
|
|
200
|
+
const by = options.by || resolveBy(cwd, env);
|
|
201
|
+
gitHard(['add', '--', itemPath, sidecarPath], cwd, env);
|
|
202
|
+
const subject = `advance: surface ${item} (${model.entries.length} question(s), by ${by})`;
|
|
203
|
+
gitHard(['commit', '--quiet', '-m', subject], cwd, env);
|
|
204
|
+
const commit = gitHard(['rev-parse', 'HEAD'], cwd, env).stdout.trim();
|
|
205
|
+
note(subject);
|
|
206
|
+
|
|
207
|
+
return {
|
|
208
|
+
outcome: 'surfaced',
|
|
209
|
+
commit,
|
|
210
|
+
sidecarPath,
|
|
211
|
+
entryCount: model.entries.length,
|
|
212
|
+
};
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
/** Read + parse the existing sidecar (from the tree, then the working file). */
|
|
216
|
+
function readExistingSidecar(sidecarAbs: string): SidecarModel | undefined {
|
|
217
|
+
if (!existsSync(sidecarAbs)) {
|
|
218
|
+
return undefined;
|
|
219
|
+
}
|
|
220
|
+
return parseSidecar(readFileSync(sidecarAbs, 'utf8'));
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
/** Read the item body from the tree (committed) then the working-tree file. */
|
|
224
|
+
function readItem(
|
|
225
|
+
itemAbs: string,
|
|
226
|
+
cwd: string,
|
|
227
|
+
itemPath: string,
|
|
228
|
+
env: NodeJS.ProcessEnv | undefined,
|
|
229
|
+
): string {
|
|
230
|
+
const show = gitSoft(['show', `:${itemPath}`], cwd, env);
|
|
231
|
+
if (show.status === 0) {
|
|
232
|
+
return show.stdout;
|
|
233
|
+
}
|
|
234
|
+
try {
|
|
235
|
+
return readFileSync(itemAbs, 'utf8');
|
|
236
|
+
} catch {
|
|
237
|
+
throw new SurfacePersistError(
|
|
238
|
+
`cannot read item body for '${itemPath}' (the surface rung needs the item file)`,
|
|
239
|
+
);
|
|
240
|
+
}
|
|
241
|
+
}
|