dorfl 0.1.1 → 0.2.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 +3 -3
- package/dist/advance-ci-template.js +1 -1
- package/dist/advance-ci-template.js.map +1 -1
- package/dist/advance-classify.d.ts +5 -5
- package/dist/advance-classify.d.ts.map +1 -1
- package/dist/advance-classify.js +4 -4
- package/dist/advance-drivers.d.ts +8 -8
- package/dist/advance-drivers.d.ts.map +1 -1
- package/dist/advance-drivers.js +20 -8
- package/dist/advance-drivers.js.map +1 -1
- package/dist/advance-isolated.d.ts +3 -3
- package/dist/advance-isolated.d.ts.map +1 -1
- package/dist/advance-isolated.js +1 -1
- package/dist/advance-lifecycle-template.d.ts +2 -2
- package/dist/advance-lifecycle-template.d.ts.map +1 -1
- package/dist/advance-lifecycle-template.js +85 -13
- package/dist/advance-lifecycle-template.js.map +1 -1
- package/dist/advance-loop-driver.d.ts +3 -3
- package/dist/advance-loop-driver.d.ts.map +1 -1
- package/dist/advance-loop-driver.js +1 -1
- package/dist/advance-treeless-publish.d.ts +24 -1
- package/dist/advance-treeless-publish.d.ts.map +1 -1
- package/dist/advance-treeless-publish.js +41 -0
- package/dist/advance-treeless-publish.js.map +1 -1
- package/dist/advance.d.ts +69 -17
- package/dist/advance.d.ts.map +1 -1
- package/dist/advance.js +409 -102
- package/dist/advance.js.map +1 -1
- package/dist/advancing-lock.d.ts +31 -3
- package/dist/advancing-lock.d.ts.map +1 -1
- package/dist/advancing-lock.js +55 -5
- package/dist/advancing-lock.js.map +1 -1
- package/dist/agent-launch.d.ts +12 -0
- package/dist/agent-launch.d.ts.map +1 -1
- package/dist/agent-launch.js +22 -12
- package/dist/agent-launch.js.map +1 -1
- package/dist/agent-stop.d.ts +40 -2
- package/dist/agent-stop.d.ts.map +1 -1
- package/dist/agent-stop.js +30 -2
- package/dist/agent-stop.js.map +1 -1
- package/dist/apply-decide.d.ts +19 -5
- package/dist/apply-decide.d.ts.map +1 -1
- package/dist/apply-decide.js +38 -9
- package/dist/apply-decide.js.map +1 -1
- package/dist/apply-merge-action.d.ts +20 -8
- package/dist/apply-merge-action.d.ts.map +1 -1
- package/dist/apply-merge-action.js +44 -9
- package/dist/apply-merge-action.js.map +1 -1
- package/dist/apply-persist.d.ts +62 -31
- package/dist/apply-persist.d.ts.map +1 -1
- package/dist/apply-persist.js +173 -44
- package/dist/apply-persist.js.map +1 -1
- package/dist/apply-stuck-action.d.ts +151 -0
- package/dist/apply-stuck-action.d.ts.map +1 -0
- package/dist/apply-stuck-action.js +125 -0
- package/dist/apply-stuck-action.js.map +1 -0
- package/dist/brand.d.ts +12 -1
- package/dist/brand.d.ts.map +1 -1
- package/dist/brand.js +2 -1
- package/dist/brand.js.map +1 -1
- package/dist/buildable-body.d.ts +14 -14
- package/dist/buildable-body.js +9 -9
- package/dist/claim-cas.d.ts +3 -3
- package/dist/claim-cas.js +1 -1
- package/dist/claim-cas.js.map +1 -1
- package/dist/cli-spinner.d.ts +1 -1
- package/dist/cli-spinner.js +1 -1
- package/dist/cli.d.ts +10 -0
- package/dist/cli.d.ts.map +1 -1
- package/dist/cli.js +385 -128
- package/dist/cli.js.map +1 -1
- package/dist/close-job-template.d.ts +3 -3
- package/dist/close-job-template.js +9 -9
- package/dist/close-job.d.ts +8 -8
- package/dist/close-job.js +25 -25
- package/dist/close-job.js.map +1 -1
- package/dist/complete.d.ts +9 -6
- package/dist/complete.d.ts.map +1 -1
- package/dist/complete.js +99 -45
- package/dist/complete.js.map +1 -1
- package/dist/concurrency.d.ts +1 -1
- package/dist/concurrency.js +1 -1
- package/dist/config.d.ts +86 -40
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +61 -9
- package/dist/config.js.map +1 -1
- package/dist/continue-branch.d.ts +1 -1
- package/dist/continue-branch.d.ts.map +1 -1
- package/dist/continue-branch.js +23 -1
- package/dist/continue-branch.js.map +1 -1
- package/dist/cwd-section.js +1 -1
- package/dist/cwd-section.js.map +1 -1
- package/dist/decision-engine.d.ts +39 -11
- package/dist/decision-engine.d.ts.map +1 -1
- package/dist/decision-engine.js +10 -6
- package/dist/decision-engine.js.map +1 -1
- package/dist/do-autopick.d.ts +6 -6
- package/dist/do-autopick.d.ts.map +1 -1
- package/dist/do-autopick.js +16 -6
- package/dist/do-autopick.js.map +1 -1
- package/dist/do-config.d.ts +4 -4
- package/dist/do-config.js +3 -3
- package/dist/do-config.js.map +1 -1
- package/dist/do-remote-auto.d.ts +2 -2
- package/dist/do-remote-auto.js +1 -1
- package/dist/do.d.ts +74 -81
- package/dist/do.d.ts.map +1 -1
- package/dist/do.js +439 -50
- package/dist/do.js.map +1 -1
- package/dist/drop-source.d.ts +2 -2
- package/dist/env-config.d.ts.map +1 -1
- package/dist/env-config.js +19 -11
- package/dist/env-config.js.map +1 -1
- package/dist/failure-cause.d.ts +3 -2
- package/dist/failure-cause.d.ts.map +1 -1
- package/dist/failure-cause.js +28 -1
- package/dist/failure-cause.js.map +1 -1
- package/dist/format.d.ts +6 -6
- package/dist/format.d.ts.map +1 -1
- package/dist/format.js +13 -30
- package/dist/format.js.map +1 -1
- package/dist/frontmatter.d.ts +28 -15
- package/dist/frontmatter.d.ts.map +1 -1
- package/dist/frontmatter.js +38 -24
- package/dist/frontmatter.js.map +1 -1
- package/dist/gc.d.ts +65 -6
- package/dist/gc.d.ts.map +1 -1
- package/dist/gc.js +126 -9
- package/dist/gc.js.map +1 -1
- package/dist/github.d.ts +14 -0
- package/dist/github.d.ts.map +1 -1
- package/dist/github.js +73 -0
- package/dist/github.js.map +1 -1
- package/dist/harness.d.ts +25 -0
- package/dist/harness.d.ts.map +1 -1
- package/dist/harness.js.map +1 -1
- package/dist/index.d.ts +4 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -1
- package/dist/index.js.map +1 -1
- package/dist/install-ci-branch-protection.d.ts +133 -39
- package/dist/install-ci-branch-protection.d.ts.map +1 -1
- package/dist/install-ci-branch-protection.js +191 -49
- package/dist/install-ci-branch-protection.js.map +1 -1
- package/dist/install-ci-capabilities/advance-lifecycle.d.ts +1 -1
- package/dist/install-ci-capabilities/advance-lifecycle.js +1 -1
- package/dist/install-ci-capabilities/close-job.d.ts +1 -1
- package/dist/install-ci-capabilities/close-job.js +1 -1
- package/dist/install-ci-capabilities/example-noop.d.ts +1 -1
- package/dist/install-ci-capabilities/example-noop.js +1 -1
- package/dist/install-ci-capabilities/intake.d.ts +2 -2
- package/dist/install-ci-capabilities/intake.js +2 -2
- package/dist/install-ci-capabilities/verify.d.ts +1 -1
- package/dist/install-ci-capabilities/verify.js +1 -1
- package/dist/install-ci-core.d.ts +24 -4
- package/dist/install-ci-core.d.ts.map +1 -1
- package/dist/install-ci-core.js +12 -5
- package/dist/install-ci-core.js.map +1 -1
- package/dist/install-ci-github.d.ts +33 -1
- package/dist/install-ci-github.d.ts.map +1 -1
- package/dist/install-ci-github.js +74 -1
- package/dist/install-ci-github.js.map +1 -1
- package/dist/install-ci.d.ts +1 -1
- package/dist/install-ci.js +4 -4
- package/dist/install-ci.js.map +1 -1
- package/dist/install-skills.d.ts +123 -0
- package/dist/install-skills.d.ts.map +1 -0
- package/dist/install-skills.js +100 -0
- package/dist/install-skills.js.map +1 -0
- package/dist/intake-event.d.ts +6 -6
- package/dist/intake-event.js +6 -6
- package/dist/intake-marker.d.ts +3 -3
- package/dist/intake-marker.d.ts.map +1 -1
- package/dist/intake-triage.d.ts +1 -1
- package/dist/intake-triage.js +2 -2
- package/dist/intake-trigger-template.d.ts +8 -8
- package/dist/intake-trigger-template.d.ts.map +1 -1
- package/dist/intake-trigger-template.js +17 -17
- package/dist/intake-trigger-template.js.map +1 -1
- package/dist/intake.d.ts +65 -52
- package/dist/intake.d.ts.map +1 -1
- package/dist/intake.js +92 -76
- package/dist/intake.js.map +1 -1
- package/dist/integration-core.d.ts +27 -24
- package/dist/integration-core.d.ts.map +1 -1
- package/dist/integration-core.js +191 -77
- package/dist/integration-core.js.map +1 -1
- package/dist/integrator.d.ts +1 -1
- package/dist/integrator.d.ts.map +1 -1
- package/dist/integrator.js +19 -3
- package/dist/integrator.js.map +1 -1
- package/dist/isolation.d.ts +4 -4
- package/dist/isolation.d.ts.map +1 -1
- package/dist/isolation.js +9 -0
- package/dist/isolation.js.map +1 -1
- package/dist/issue-provider.d.ts +4 -4
- package/dist/issue-provider.js +1 -1
- package/dist/item-lock.d.ts +216 -149
- package/dist/item-lock.d.ts.map +1 -1
- package/dist/item-lock.js +345 -270
- package/dist/item-lock.js.map +1 -1
- package/dist/item-path.d.ts +2 -2
- package/dist/item-path.js +2 -2
- package/dist/ledger-lint.d.ts +9 -9
- package/dist/ledger-lint.js +9 -9
- package/dist/ledger-read.d.ts +57 -57
- package/dist/ledger-read.d.ts.map +1 -1
- package/dist/ledger-read.js +24 -24
- package/dist/ledger-read.js.map +1 -1
- package/dist/ledger-write.d.ts +33 -28
- package/dist/ledger-write.d.ts.map +1 -1
- package/dist/ledger-write.js +100 -122
- package/dist/ledger-write.js.map +1 -1
- package/dist/lifecycle-gather.d.ts +18 -1
- package/dist/lifecycle-gather.d.ts.map +1 -1
- package/dist/lifecycle-gather.js +23 -17
- package/dist/lifecycle-gather.js.map +1 -1
- package/dist/lifecycle-pools.d.ts +44 -7
- package/dist/lifecycle-pools.d.ts.map +1 -1
- package/dist/lifecycle-pools.js +27 -7
- package/dist/lifecycle-pools.js.map +1 -1
- package/dist/merge-question-surfacer.d.ts +18 -4
- package/dist/merge-question-surfacer.d.ts.map +1 -1
- package/dist/merge-question-surfacer.js +20 -5
- package/dist/merge-question-surfacer.js.map +1 -1
- package/dist/migrate-stuck-locks.d.ts +129 -0
- package/dist/migrate-stuck-locks.d.ts.map +1 -0
- package/dist/migrate-stuck-locks.js +355 -0
- package/dist/migrate-stuck-locks.js.map +1 -0
- package/dist/mint-adr.js +4 -4
- package/dist/mirror-pool-scan.d.ts +2 -2
- package/dist/mirror-pool-scan.js +3 -3
- package/dist/mirror-pool-scan.js.map +1 -1
- package/dist/needs-attention.d.ts +304 -27
- package/dist/needs-attention.d.ts.map +1 -1
- package/dist/needs-attention.js +542 -67
- package/dist/needs-attention.js.map +1 -1
- package/dist/orphan-sidecar.d.ts +10 -6
- package/dist/orphan-sidecar.d.ts.map +1 -1
- package/dist/orphan-sidecar.js +35 -2
- package/dist/orphan-sidecar.js.map +1 -1
- package/dist/pi-harness.d.ts +16 -0
- package/dist/pi-harness.d.ts.map +1 -1
- package/dist/pi-harness.js +82 -2
- package/dist/pi-harness.js.map +1 -1
- package/dist/placement.d.ts +8 -8
- package/dist/placement.js +3 -3
- package/dist/prd-to-spec.d.ts.map +1 -1
- package/dist/prd-to-spec.js +9 -5
- package/dist/prd-to-spec.js.map +1 -1
- package/dist/prompt.d.ts +16 -19
- package/dist/prompt.d.ts.map +1 -1
- package/dist/prompt.js +17 -19
- package/dist/prompt.js.map +1 -1
- package/dist/protocol/CLAIM-PROTOCOL.md +17 -10
- package/dist/protocol/REVIEW-PROTOCOL.md +4 -1
- package/dist/protocol/SURFACE-PROTOCOL.md +16 -2
- package/dist/protocol/TASKING-PROTOCOL.md +3 -1
- package/dist/protocol/WORK-CONTRACT.md +22 -18
- package/dist/protocol/task-template.md +1 -1
- package/dist/readiness.d.ts +1 -1
- package/dist/reap-branches.d.ts +12 -9
- package/dist/reap-branches.d.ts.map +1 -1
- package/dist/reap-branches.js +25 -7
- package/dist/reap-branches.js.map +1 -1
- package/dist/recover-isolated.d.ts +12 -0
- package/dist/recover-isolated.d.ts.map +1 -1
- package/dist/recover-isolated.js +6 -1
- package/dist/recover-isolated.js.map +1 -1
- package/dist/repo-config.d.ts +23 -2
- package/dist/repo-config.d.ts.map +1 -1
- package/dist/repo-config.js +64 -18
- package/dist/repo-config.js.map +1 -1
- package/dist/repo-mirror.d.ts.map +1 -1
- package/dist/repo-mirror.js +18 -2
- package/dist/repo-mirror.js.map +1 -1
- package/dist/review-gate.d.ts +3 -3
- package/dist/review-gate.d.ts.map +1 -1
- package/dist/review-gate.js +11 -10
- package/dist/review-gate.js.map +1 -1
- package/dist/review-verdict.d.ts +2 -2
- package/dist/review-verdict.d.ts.map +1 -1
- package/dist/review-verdict.js +2 -2
- package/dist/review-verdict.js.map +1 -1
- package/dist/run.d.ts +2 -2
- package/dist/run.d.ts.map +1 -1
- package/dist/run.js +58 -23
- package/dist/run.js.map +1 -1
- package/dist/scan.d.ts +26 -17
- package/dist/scan.d.ts.map +1 -1
- package/dist/scan.js +29 -15
- package/dist/scan.js.map +1 -1
- package/dist/select-order.d.ts +1 -1
- package/dist/select-priority.d.ts +14 -14
- package/dist/select-priority.d.ts.map +1 -1
- package/dist/select-priority.js +5 -5
- package/dist/select-priority.js.map +1 -1
- package/dist/sidecar-apply.js +1 -1
- package/dist/sidecar-apply.js.map +1 -1
- package/dist/sidecar.d.ts +47 -12
- package/dist/sidecar.d.ts.map +1 -1
- package/dist/sidecar.js +84 -4
- package/dist/sidecar.js.map +1 -1
- package/dist/skills/answer-questions/SKILL.md +89 -0
- package/dist/skills/capture-signal/SKILL.md +52 -0
- package/dist/skills/convert-from-prd-to-spec/SKILL.md +90 -0
- package/dist/skills/drive-tasks/SKILL.md +218 -0
- package/dist/skills/from-idea/SKILL.md +83 -0
- package/dist/skills/merge-prs/SKILL.md +70 -0
- package/dist/skills/orchestrate/SKILL.md +101 -0
- package/dist/skills/promote/SKILL.md +35 -0
- package/dist/skills/review/SKILL.md +16 -0
- package/dist/skills/setup/SKILL.md +258 -0
- package/dist/skills/setup/protocol/ADR-FORMAT.md +47 -0
- package/dist/skills/setup/protocol/CLAIM-PROTOCOL.md +224 -0
- package/dist/skills/setup/protocol/REVIEW-PROTOCOL.md +122 -0
- package/dist/skills/setup/protocol/SURFACE-PROTOCOL.md +135 -0
- package/dist/skills/setup/protocol/TASKING-PROTOCOL.md +124 -0
- package/dist/skills/setup/protocol/WORK-CONTRACT.md +280 -0
- package/dist/skills/setup/protocol/spec-template.md +71 -0
- package/dist/skills/setup/protocol/task-template.md +65 -0
- package/dist/skills/surface-questions/SKILL.md +16 -0
- package/dist/skills/to-spec/SKILL.md +34 -0
- package/dist/skills/to-task/SKILL.md +19 -0
- package/dist/skills/triage-observations/SKILL.md +78 -0
- package/dist/skills/work/SKILL.md +51 -0
- package/dist/slug-namespace.d.ts +6 -6
- package/dist/slug-namespace.js +8 -8
- package/dist/slug-namespace.js.map +1 -1
- package/dist/spec-complete.d.ts.map +1 -1
- package/dist/spec-complete.js +4 -5
- package/dist/spec-complete.js.map +1 -1
- package/dist/start.d.ts +1 -1
- package/dist/start.d.ts.map +1 -1
- package/dist/start.js +54 -60
- package/dist/start.js.map +1 -1
- package/dist/status.d.ts +3 -3
- package/dist/status.js +4 -4
- package/dist/status.js.map +1 -1
- package/dist/surface-gate.d.ts +2 -2
- package/dist/surface-gate.d.ts.map +1 -1
- package/dist/surface-gate.js +10 -3
- package/dist/surface-gate.js.map +1 -1
- package/dist/surface-persist.d.ts +2 -2
- package/dist/surface-persist.d.ts.map +1 -1
- package/dist/surface-persist.js +1 -1
- package/dist/surface-persist.js.map +1 -1
- package/dist/tasker-review-loop.d.ts +11 -10
- package/dist/tasker-review-loop.d.ts.map +1 -1
- package/dist/tasker-review-loop.js +8 -8
- package/dist/tasker-review-loop.js.map +1 -1
- package/dist/tasking-eligibility.d.ts +21 -21
- package/dist/tasking-eligibility.d.ts.map +1 -1
- package/dist/tasking-eligibility.js +10 -10
- package/dist/tasking-lock.d.ts +10 -10
- package/dist/tasking-lock.d.ts.map +1 -1
- package/dist/tasking-lock.js +69 -49
- package/dist/tasking-lock.js.map +1 -1
- package/dist/tasking.d.ts +73 -39
- package/dist/tasking.d.ts.map +1 -1
- package/dist/tasking.js +309 -95
- package/dist/tasking.js.map +1 -1
- package/dist/triage-gate.d.ts +1 -1
- package/dist/triage-persist.d.ts +15 -11
- package/dist/triage-persist.d.ts.map +1 -1
- package/dist/triage-persist.js +48 -18
- package/dist/triage-persist.js.map +1 -1
- package/dist/vendor/incur/agents.d.ts +58 -0
- package/dist/vendor/incur/agents.d.ts.map +1 -0
- package/dist/vendor/incur/agents.js +343 -0
- package/dist/vendor/incur/agents.js.map +1 -0
- package/dist/verify-workflow-template.d.ts +1 -1
- package/dist/verify-workflow-template.js +3 -3
- package/dist/watch-session.d.ts +11 -3
- package/dist/watch-session.d.ts.map +1 -1
- package/dist/watch-session.js +94 -7
- package/dist/watch-session.js.map +1 -1
- package/dist/work-layout.d.ts +15 -9
- package/dist/work-layout.d.ts.map +1 -1
- package/dist/work-layout.js +14 -9
- package/dist/work-layout.js.map +1 -1
- package/dist/workspace.d.ts +2 -2
- package/package.json +2 -2
- package/src/advance-ci-template.ts +4 -4
- package/src/advance-classify.ts +5 -5
- package/src/advance-drivers.ts +26 -13
- package/src/advance-isolated.ts +3 -3
- package/src/advance-lifecycle-template.ts +98 -13
- package/src/advance-loop-driver.ts +3 -3
- package/src/advance-treeless-publish.ts +46 -1
- package/src/advance.ts +495 -115
- package/src/advancing-lock.ts +102 -7
- package/src/agent-launch.ts +37 -12
- package/src/agent-stop.ts +60 -2
- package/src/apply-decide.ts +38 -9
- package/src/apply-merge-action.ts +49 -11
- package/src/apply-persist.ts +236 -62
- package/src/apply-stuck-action.ts +260 -0
- package/src/brand.ts +14 -2
- package/src/buildable-body.ts +14 -14
- package/src/claim-cas.ts +4 -4
- package/src/cli-spinner.ts +1 -1
- package/src/cli.ts +472 -141
- package/src/close-job-template.ts +9 -9
- package/src/close-job.ts +26 -26
- package/src/complete.ts +121 -63
- package/src/concurrency.ts +1 -1
- package/src/config.ts +143 -49
- package/src/continue-branch.ts +23 -1
- package/src/cwd-section.ts +1 -1
- package/src/decision-engine.ts +57 -19
- package/src/do-autopick.ts +21 -10
- package/src/do-config.ts +7 -7
- package/src/do-remote-auto.ts +2 -2
- package/src/do.ts +558 -85
- package/src/drop-source.ts +2 -2
- package/src/env-config.ts +19 -11
- package/src/failure-cause.ts +30 -1
- package/src/format.ts +13 -33
- package/src/frontmatter.ts +55 -35
- package/src/gc.ts +172 -9
- package/src/github.ts +78 -0
- package/src/harness.ts +25 -0
- package/src/index.ts +10 -0
- package/src/install-ci-branch-protection.ts +283 -58
- package/src/install-ci-capabilities/advance-lifecycle.ts +1 -1
- package/src/install-ci-capabilities/close-job.ts +1 -1
- package/src/install-ci-capabilities/example-noop.ts +1 -1
- package/src/install-ci-capabilities/intake.ts +2 -2
- package/src/install-ci-capabilities/verify.ts +1 -1
- package/src/install-ci-core.ts +34 -7
- package/src/install-ci-github.ts +87 -1
- package/src/install-ci.ts +4 -4
- package/src/install-skills.ts +166 -0
- package/src/intake-event.ts +6 -6
- package/src/intake-marker.ts +3 -3
- package/src/intake-triage.ts +2 -2
- package/src/intake-trigger-template.ts +18 -18
- package/src/intake.ts +138 -103
- package/src/integration-core.ts +234 -100
- package/src/integrator.ts +22 -9
- package/src/isolation.ts +13 -4
- package/src/issue-provider.ts +4 -4
- package/src/item-lock.ts +505 -361
- package/src/item-path.ts +2 -2
- package/src/ledger-lint.ts +9 -9
- package/src/ledger-read.ts +81 -81
- package/src/ledger-write.ts +137 -152
- package/src/lifecycle-gather.ts +45 -22
- package/src/lifecycle-pools.ts +71 -13
- package/src/merge-question-surfacer.ts +32 -8
- package/src/migrate-stuck-locks.ts +451 -0
- package/src/mint-adr.ts +4 -4
- package/src/mirror-pool-scan.ts +5 -5
- package/src/needs-attention.ts +877 -104
- package/src/orphan-sidecar.ts +49 -8
- package/src/pi-harness.ts +82 -2
- package/src/placement.ts +8 -8
- package/src/prd-to-spec.ts +13 -5
- package/src/prompt.ts +20 -25
- package/src/readiness.ts +1 -1
- package/src/reap-branches.ts +38 -14
- package/src/recover-isolated.ts +18 -1
- package/src/repo-config.ts +66 -17
- package/src/repo-mirror.ts +23 -1
- package/src/review-gate.ts +12 -11
- package/src/review-verdict.ts +3 -3
- package/src/run.ts +69 -23
- package/src/scan.ts +36 -22
- package/src/select-order.ts +1 -1
- package/src/select-priority.ts +15 -15
- package/src/sidecar-apply.ts +1 -1
- package/src/sidecar.ts +141 -14
- package/src/slug-namespace.ts +10 -10
- package/src/spec-complete.ts +4 -5
- package/src/start.ts +57 -63
- package/src/status.ts +7 -7
- package/src/surface-gate.ts +12 -5
- package/src/surface-persist.ts +3 -3
- package/src/tasker-review-loop.ts +18 -17
- package/src/tasking-eligibility.ts +21 -21
- package/src/tasking-lock.ts +75 -60
- package/src/tasking.ts +381 -135
- package/src/triage-gate.ts +1 -1
- package/src/triage-persist.ts +71 -27
- package/src/vendor/incur/LICENSE +21 -0
- package/src/vendor/incur/README.md +19 -0
- package/src/vendor/incur/agents.ts +392 -0
- package/src/verify-workflow-template.ts +3 -3
- package/src/watch-session.ts +102 -7
- package/src/work-layout.ts +14 -9
- package/src/workspace.ts +2 -2
package/src/triage-gate.ts
CHANGED
|
@@ -3,7 +3,7 @@ import {launchWithOptionalWatch} from './agent-launch.js';
|
|
|
3
3
|
import {extractJsonObjectSpan} from './verdict-json.js';
|
|
4
4
|
|
|
5
5
|
/**
|
|
6
|
-
* The **TRIAGE auto-disposition GATE** (
|
|
6
|
+
* The **TRIAGE auto-disposition GATE** (spec `advance-loop`, task
|
|
7
7
|
* `advance-rung-triage`, US #17) — the CONSERVATIVE, `observationTriage: 'auto'`-
|
|
8
8
|
* gated exception to the question-gated default. On `classify=triage-observation`
|
|
9
9
|
* AND `observationTriage` resolved to `'auto'`, the engine asks this gate whether
|
package/src/triage-persist.ts
CHANGED
|
@@ -10,9 +10,10 @@ import {
|
|
|
10
10
|
import {resolveSidecarIdentity, sidecarPathFor} from './sidecar.js';
|
|
11
11
|
import type {TriageAutoKind} from './triage-gate.js';
|
|
12
12
|
import {renderTaskBody, renderSpecBody} from './buildable-body.js';
|
|
13
|
+
import {setFrontmatterMarker} from './frontmatter.js';
|
|
13
14
|
|
|
14
15
|
/**
|
|
15
|
-
* The engine-owned TRIAGE PERSIST (
|
|
16
|
+
* The engine-owned TRIAGE PERSIST (spec `advance-loop`, task `advance-rung-triage`,
|
|
16
17
|
* US #16/17/24/30) — the half of the observation-triage rung the ENGINE owns (the
|
|
17
18
|
* triage gate JUDGES, the engine ACTS). It is the SIBLING of `surface-persist.ts`
|
|
18
19
|
* (the surface rung's persist) and `apply-persist.ts` (the apply rung's persist),
|
|
@@ -232,8 +233,8 @@ export interface PromoteObservationOptions {
|
|
|
232
233
|
* triage-local {@link createItemThroughCas} writer (one local commit through the
|
|
233
234
|
* CAS) — NOT intake's branch+integrate band — so the CAS-loser-backs-off
|
|
234
235
|
* guarantee and the same-commit note deletion are uniform across the two routes.
|
|
235
|
-
* MIGRATE step (
|
|
236
|
-
* produced VALUE is `'spec'` (the verdict outcome renamed from
|
|
236
|
+
* MIGRATE step (spec `prd-to-spec-vocabulary-cutover-and-migration-command`): the
|
|
237
|
+
* produced VALUE is `'spec'` (the verdict outcome renamed from ''prd'').
|
|
237
238
|
*/
|
|
238
239
|
artifact?: 'task' | 'spec';
|
|
239
240
|
/**
|
|
@@ -273,11 +274,20 @@ export interface PromoteObservationOptions {
|
|
|
273
274
|
export interface PromoteObservationResult {
|
|
274
275
|
/**
|
|
275
276
|
* `promoted` (the new item landed via the CAS + the observation+sidecar were
|
|
276
|
-
* deleted in the SAME commit), `
|
|
277
|
-
* the
|
|
278
|
-
*
|
|
277
|
+
* deleted in the SAME commit), `already-triaged` (the target task ALREADY exists
|
|
278
|
+
* on the arbiter AND was PROVABLY minted from THIS observation in a prior run — a
|
|
279
|
+
* TERMINAL, benign idempotency fact, exit 0; the observation is left intact but a
|
|
280
|
+
* retry can never succeed, so it is NOT loud), `lost` (a genuine concurrent-create
|
|
281
|
+
* race for a same-path NEW item was lost — the loser backs off, observation left
|
|
282
|
+
* INTACT, retry helps), or `contended` (the CAS push kept failing). Maps onto the
|
|
283
|
+
* claim-CAS exit codes.
|
|
279
284
|
*/
|
|
280
|
-
outcome:
|
|
285
|
+
outcome:
|
|
286
|
+
| 'promoted'
|
|
287
|
+
| 'already-triaged'
|
|
288
|
+
| 'lost'
|
|
289
|
+
| 'contended'
|
|
290
|
+
| 'usage-error';
|
|
281
291
|
exitCode: 0 | 1 | 2 | 3;
|
|
282
292
|
/** The new task's path (relative to repo root) on a WIN. */
|
|
283
293
|
newItemPath?: string;
|
|
@@ -287,22 +297,22 @@ export interface PromoteObservationResult {
|
|
|
287
297
|
|
|
288
298
|
/**
|
|
289
299
|
* Promote an ANSWERED observation to a NEW, SELF-CONTAINED artifact (US #1/#3/#8
|
|
290
|
-
* for the task route; US #4/#9 for the
|
|
300
|
+
* for the task route; US #4/#9 for the SPEC route): CAS-create the new item keyed
|
|
291
301
|
* on the NEW item's identity (its target path), with the observation note + its
|
|
292
302
|
* answered sidecar `git rm`-ed IN THE SAME atomic commit. Promote is ONE commit
|
|
293
303
|
* (create + delete).
|
|
294
304
|
*
|
|
295
305
|
* The artifact TYPE (`options.artifact`) selects the target + body shape: `'task'`
|
|
296
|
-
* (default) mints `work/tasks/ready/<slug>.md`; `'
|
|
297
|
-
* `work/
|
|
306
|
+
* (default) mints `work/tasks/ready/<slug>.md`; `'spec'` mints
|
|
307
|
+
* `work/specs/proposed/<slug>.md` (SPEC staging — a human later promotes it to
|
|
298
308
|
* `ready/`). BOTH routes use the SAME triage-local {@link createItemThroughCas}
|
|
299
309
|
* writer (NOT intake's `switchToWorkBranch`/`performIntegration` branch+integrate
|
|
300
310
|
* band, which is intake's standalone front door): one create/integrate surface for
|
|
301
|
-
* triage, the CAS-loser-backs-off guarantee uniform across task and
|
|
311
|
+
* triage, the CAS-loser-backs-off guarantee uniform across task and SPEC promotion.
|
|
302
312
|
*
|
|
303
313
|
* The minted body is built FROM the observation (see {@link buildPromotedBody}):
|
|
304
314
|
* its mechanism + fix prose is carried into the artifact's lead section (`## What
|
|
305
|
-
* to build` for a task, `## Problem Statement` for a
|
|
315
|
+
* to build` for a task, `## Problem Statement` for a SPEC), and its
|
|
306
316
|
* `## Open questions` scoping is transcribed into the new item's own
|
|
307
317
|
* `## Open questions` block with `needsAnswers` set when questions remain (cleared
|
|
308
318
|
* when none do) — so an agent can build from the artifact ALONE and no decision
|
|
@@ -340,11 +350,24 @@ export async function promoteObservation(
|
|
|
340
350
|
`${newSlug}.md`,
|
|
341
351
|
);
|
|
342
352
|
const by = options.by || resolveBy(cwd, env);
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
353
|
+
// Stamp the observation→task PROVENANCE back-reference `promotedFrom: <item>` into
|
|
354
|
+
// the minted body (task `observation-triage-already-triaged-benign-skip`). It is
|
|
355
|
+
// the PROVABLE LINK the create-CAS lost-race disambiguator reads to tell case A
|
|
356
|
+
// (this observation ALREADY minted this task — already triaged, benign skip) from
|
|
357
|
+
// case B (a genuine concurrent-create race with an UNRELATED same-path item — loud
|
|
358
|
+
// exit 2). Distinct from `origin:` (how BORN: human/issue) and `reviewOf:` (the
|
|
359
|
+
// review-nits back-pointer); this is the triage-promote lineage. Matching on this
|
|
360
|
+
// explicit field — not the slug — is what keeps an unrelated same-slug task from
|
|
361
|
+
// false-positiving into a benign skip.
|
|
362
|
+
const content = setFrontmatterMarker(
|
|
363
|
+
ensureTaskDispatchable(
|
|
364
|
+
artifact,
|
|
365
|
+
newSlug,
|
|
366
|
+
options.stubContent ??
|
|
367
|
+
buildPromotedBody(artifact, newSlug, readItem(cwd, itemPath, env)),
|
|
368
|
+
),
|
|
369
|
+
'promotedFrom',
|
|
370
|
+
item,
|
|
348
371
|
);
|
|
349
372
|
|
|
350
373
|
// The note + its answered sidecar `git rm` IN THE SAME create commit (promote =
|
|
@@ -359,6 +382,10 @@ export async function promoteObservation(
|
|
|
359
382
|
path: newItemPath,
|
|
360
383
|
content,
|
|
361
384
|
deletePaths: [itemPath, sidecarPath],
|
|
385
|
+
// The provenance disambiguator: on a LOST create-race, the CAS reads the
|
|
386
|
+
// existing file's `promotedFrom:` and, iff it equals THIS observation, reports
|
|
387
|
+
// the benign `already-exists-from-source` instead of the loud `lost`.
|
|
388
|
+
sourceItem: item,
|
|
362
389
|
cwd,
|
|
363
390
|
arbiter: options.arbiter,
|
|
364
391
|
by,
|
|
@@ -369,6 +396,23 @@ export async function promoteObservation(
|
|
|
369
396
|
? {contention: options.contention}
|
|
370
397
|
: {}),
|
|
371
398
|
});
|
|
399
|
+
// TERMINAL 'already triaged' (case A): the task this observation would mint
|
|
400
|
+
// ALREADY exists on the arbiter AND was provably minted from THIS observation in
|
|
401
|
+
// a prior run. A benign idempotency fact (exit 0) — the human already decided when
|
|
402
|
+
// they minted it — NOT a retry. The observation is left intact (a later
|
|
403
|
+
// discharge-by-deletion or a human deletes it); this leg does not red CI.
|
|
404
|
+
if (created.outcome === 'already-exists-from-source') {
|
|
405
|
+
const message =
|
|
406
|
+
`promote ${item}: ${newItemPath} was already minted FROM this observation ` +
|
|
407
|
+
`in a prior run (${created.message}) — already triaged. Benign skip, no retry.`;
|
|
408
|
+
note(message);
|
|
409
|
+
return {
|
|
410
|
+
outcome: 'already-triaged',
|
|
411
|
+
exitCode: 0,
|
|
412
|
+
newItemPath,
|
|
413
|
+
message,
|
|
414
|
+
};
|
|
415
|
+
}
|
|
372
416
|
if (created.exitCode !== 0) {
|
|
373
417
|
const message =
|
|
374
418
|
`promote ${item}: the new item ${newItemPath} ${created.outcome} the ` +
|
|
@@ -398,10 +442,10 @@ export async function promoteObservation(
|
|
|
398
442
|
*
|
|
399
443
|
* The artifact TYPE selects the frontmatter + lead heading: a `task` gets
|
|
400
444
|
* `## What to build` + `blockedBy: []` + a `## Prompt` (the buildable-task shape);
|
|
401
|
-
* a `
|
|
402
|
-
* a
|
|
445
|
+
* a `spec` gets `## Problem Statement` (the SPEC document shape, with no `blockedBy` —
|
|
446
|
+
* a SPEC is not a blockable task — and no `## Prompt`, since a SPEC is not
|
|
403
447
|
* dispatched by `do`/`run`). BOTH carry the SAME transcribed mechanism prose +
|
|
404
|
-
* open-question block, so a
|
|
448
|
+
* open-question block, so a SPEC minted into `proposed/` is just as self-contained
|
|
405
449
|
* as a task.
|
|
406
450
|
*
|
|
407
451
|
* The `## Prompt` (task only) is the STRUCTURAL dispatchability the validator
|
|
@@ -409,9 +453,9 @@ export async function promoteObservation(
|
|
|
409
453
|
* dispatched build throws "has no '## Prompt' section". The body BELOW the
|
|
410
454
|
* frontmatter (lead section + mechanism prose + optional `## Open questions` +
|
|
411
455
|
* the task-only `## Prompt`) is rendered by the SHARED owner of the
|
|
412
|
-
* buildable-task/
|
|
456
|
+
* buildable-task/SPEC schema, {@link renderTaskBody} / {@link renderSpecBody}
|
|
413
457
|
* (`buildable-body.ts`), so the producer and the consumer cannot drift apart
|
|
414
|
-
* (
|
|
458
|
+
* (spec `centralize-buildable-task-renderer-shared-by-intake-and-promotion`,
|
|
415
459
|
* US #3/#5/#6). This function owns only the FRONTMATTER writer; the section
|
|
416
460
|
* skeleton lives in the one renderer. The empty-mechanism `## Prompt` seed is
|
|
417
461
|
* passed EXPLICITLY (`Build the task '<slug>', described above.`) so promotion's
|
|
@@ -434,8 +478,8 @@ export async function promoteObservation(
|
|
|
434
478
|
* fails with `has no '## Prompt' section` (the `extractPromptSection`/`resolveTask`
|
|
435
479
|
* guard in `prompt.ts`). This is the robust backstop that closes that hole
|
|
436
480
|
* regardless of agent compliance: for a TASK, if the body has no `## Prompt`
|
|
437
|
-
* heading, append a seeded one (blockquoted, matching the renderer's shape). A
|
|
438
|
-
* is left UNTOUCHED — a
|
|
481
|
+
* heading, append a seeded one (blockquoted, matching the renderer's shape). A SPEC
|
|
482
|
+
* is left UNTOUCHED — a SPEC is a north-star doc, not dispatched by `do`/`run`, and carries no
|
|
439
483
|
* `## Prompt` by design.
|
|
440
484
|
*/
|
|
441
485
|
function ensureTaskDispatchable(
|
|
@@ -472,7 +516,7 @@ function buildPromotedBody(
|
|
|
472
516
|
`title: ${slug}`,
|
|
473
517
|
`slug: ${slug}`,
|
|
474
518
|
`needsAnswers: ${hasQuestions ? 'true' : 'false'}`,
|
|
475
|
-
// A
|
|
519
|
+
// A SPEC is a north-star doc, not a blockable task — only the task shape carries
|
|
476
520
|
// `blockedBy`.
|
|
477
521
|
...(artifact === 'spec' ? [] : ['blockedBy: []']),
|
|
478
522
|
'---',
|
|
@@ -488,8 +532,8 @@ function buildPromotedBody(
|
|
|
488
532
|
// no leading blank. Do NOT move the separator into the renderer.
|
|
489
533
|
const fenceToBody = frontmatter.join('\n') + '\n\n';
|
|
490
534
|
// The body BELOW the frontmatter is rendered by the SHARED schema owner so the
|
|
491
|
-
// section skeleton has one home, not two (
|
|
492
|
-
// `centralize-buildable-task-renderer-shared-by-intake-and-promotion`). A
|
|
535
|
+
// section skeleton has one home, not two (spec
|
|
536
|
+
// `centralize-buildable-task-renderer-shared-by-intake-and-promotion`). A SPEC
|
|
493
537
|
// goes through `renderSpecBody` (no `## Prompt`); a task through
|
|
494
538
|
// `renderTaskBody` (always a `## Prompt`).
|
|
495
539
|
if (artifact === 'spec') {
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025-present weth, LLC
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
# Vendored: `incur/src/internal/agents.ts` (MIT)
|
|
2
|
+
|
|
3
|
+
`agents.ts` here is a **verbatim** copy of `src/internal/agents.ts` from
|
|
4
|
+
[wevm/incur](https://github.com/wevm/incur) (MIT). See `LICENSE` beside it for the
|
|
5
|
+
required copyright + permission notice, which is also duplicated as a header
|
|
6
|
+
comment at the top of `agents.ts` itself so the file stays attribution-complete
|
|
7
|
+
in isolation.
|
|
8
|
+
|
|
9
|
+
We VENDOR rather than depend (see
|
|
10
|
+
`docs/adr/skill-install-vendors-incur-agents-map.md`): the harness-destination
|
|
11
|
+
map + copy/symlink logic are the one hard, drift-prone piece we need, and the
|
|
12
|
+
file is dependency-free (only `node:fs`/`os`/`path`). Keep it BYTE-CLOSE to
|
|
13
|
+
upstream so a future incur update is a mechanical re-copy — put all wrapper
|
|
14
|
+
code outside this directory (`../../install-skills.ts`).
|
|
15
|
+
|
|
16
|
+
To refresh: re-fetch `src/internal/agents.ts` from the upstream tag you want,
|
|
17
|
+
overwrite `agents.ts`, keep the small ATTRIBUTION HEADER block at the top
|
|
18
|
+
(above the original `import` lines) intact, and re-copy `LICENSE` if it
|
|
19
|
+
changed upstream.
|
|
@@ -0,0 +1,392 @@
|
|
|
1
|
+
// ---------------------------------------------------------------------------
|
|
2
|
+
// VENDORED FROM: https://github.com/wevm/incur
|
|
3
|
+
// Source: src/internal/agents.ts
|
|
4
|
+
// License: MIT (see ./LICENSE beside this file)
|
|
5
|
+
// Copyright: (c) 2025-present weth, LLC
|
|
6
|
+
//
|
|
7
|
+
// This file is a VERBATIM copy of the upstream `src/internal/agents.ts` from
|
|
8
|
+
// wevm/incur, preserved byte-close so future upstream updates are a mechanical
|
|
9
|
+
// re-copy. Do NOT edit it in place — put all dorfl wrapper code OUTSIDE this
|
|
10
|
+
// directory (see `../../install-skills.ts`). Only the block ABOVE this line is
|
|
11
|
+
// dorfl-authored (attribution header). See `./README.md` for provenance and
|
|
12
|
+
// the `docs/adr/skill-install-vendors-incur-agents-map.md` ADR for why we
|
|
13
|
+
// vendor rather than depend.
|
|
14
|
+
//
|
|
15
|
+
// MIT permission notice (required by upstream license, kept in-file so the
|
|
16
|
+
// attribution survives isolation from the sibling LICENSE):
|
|
17
|
+
//
|
|
18
|
+
// Permission is hereby granted, free of charge, to any person obtaining a
|
|
19
|
+
// copy of this software and associated documentation files (the "Software"),
|
|
20
|
+
// to deal in the Software without restriction, including without limitation
|
|
21
|
+
// the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
|
22
|
+
// and/or sell copies of the Software, and to permit persons to whom the
|
|
23
|
+
// Software is furnished to do so, subject to the following conditions:
|
|
24
|
+
//
|
|
25
|
+
// The above copyright notice and this permission notice shall be included
|
|
26
|
+
// in all copies or substantial portions of the Software.
|
|
27
|
+
//
|
|
28
|
+
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
|
|
29
|
+
// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
|
30
|
+
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
|
31
|
+
// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
|
32
|
+
// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
|
33
|
+
// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
|
34
|
+
// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
35
|
+
// ---------------------------------------------------------------------------
|
|
36
|
+
|
|
37
|
+
import * as fs from 'node:fs'
|
|
38
|
+
import * as os from 'node:os'
|
|
39
|
+
import * as path from 'node:path'
|
|
40
|
+
|
|
41
|
+
/** Agent configuration for skill installation. */
|
|
42
|
+
export type Agent = {
|
|
43
|
+
/** Display name. */
|
|
44
|
+
name: string
|
|
45
|
+
/** Absolute path to the global skills directory. */
|
|
46
|
+
globalSkillsDir: string
|
|
47
|
+
/** Project-relative skills directory path. */
|
|
48
|
+
projectSkillsDir: string
|
|
49
|
+
/** Whether this agent uses the canonical `.agents/skills` path. */
|
|
50
|
+
universal: boolean
|
|
51
|
+
/** Checks if the agent is installed on the system. */
|
|
52
|
+
detect(): boolean
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
const home = os.homedir()
|
|
56
|
+
const configHome = process.env.XDG_CONFIG_HOME || path.join(home, '.config')
|
|
57
|
+
const claudeHome = process.env.CLAUDE_CONFIG_DIR?.trim() || path.join(home, '.claude')
|
|
58
|
+
const codexHome = process.env.CODEX_HOME?.trim() || path.join(home, '.codex')
|
|
59
|
+
|
|
60
|
+
/** All known agent definitions. */
|
|
61
|
+
export const all: Agent[] = [
|
|
62
|
+
// Universal agents (project skillsDir = .agents/skills)
|
|
63
|
+
{
|
|
64
|
+
name: 'Amp',
|
|
65
|
+
globalSkillsDir: path.join(configHome, 'agents', 'skills'),
|
|
66
|
+
projectSkillsDir: '.agents/skills',
|
|
67
|
+
universal: true,
|
|
68
|
+
detect: () => fs.existsSync(path.join(configHome, 'amp')),
|
|
69
|
+
},
|
|
70
|
+
{
|
|
71
|
+
name: 'Cline',
|
|
72
|
+
globalSkillsDir: path.join(home, '.agents', 'skills'),
|
|
73
|
+
projectSkillsDir: '.agents/skills',
|
|
74
|
+
universal: true,
|
|
75
|
+
detect: () => fs.existsSync(path.join(home, '.cline')),
|
|
76
|
+
},
|
|
77
|
+
{
|
|
78
|
+
name: 'Codex',
|
|
79
|
+
globalSkillsDir: path.join(codexHome, 'skills'),
|
|
80
|
+
projectSkillsDir: '.agents/skills',
|
|
81
|
+
universal: true,
|
|
82
|
+
detect: () => fs.existsSync(codexHome),
|
|
83
|
+
},
|
|
84
|
+
{
|
|
85
|
+
name: 'Cursor',
|
|
86
|
+
globalSkillsDir: path.join(home, '.cursor', 'skills'),
|
|
87
|
+
projectSkillsDir: '.agents/skills',
|
|
88
|
+
universal: true,
|
|
89
|
+
detect: () => fs.existsSync(path.join(home, '.cursor')),
|
|
90
|
+
},
|
|
91
|
+
{
|
|
92
|
+
name: 'Gemini CLI',
|
|
93
|
+
globalSkillsDir: path.join(home, '.gemini', 'skills'),
|
|
94
|
+
projectSkillsDir: '.agents/skills',
|
|
95
|
+
universal: true,
|
|
96
|
+
detect: () => fs.existsSync(path.join(home, '.gemini')),
|
|
97
|
+
},
|
|
98
|
+
{
|
|
99
|
+
name: 'GitHub Copilot',
|
|
100
|
+
globalSkillsDir: path.join(home, '.copilot', 'skills'),
|
|
101
|
+
projectSkillsDir: '.agents/skills',
|
|
102
|
+
universal: true,
|
|
103
|
+
detect: () => fs.existsSync(path.join(home, '.copilot')),
|
|
104
|
+
},
|
|
105
|
+
{
|
|
106
|
+
name: 'Kimi CLI',
|
|
107
|
+
globalSkillsDir: path.join(configHome, 'agents', 'skills'),
|
|
108
|
+
projectSkillsDir: '.agents/skills',
|
|
109
|
+
universal: true,
|
|
110
|
+
detect: () => fs.existsSync(path.join(home, '.kimi')),
|
|
111
|
+
},
|
|
112
|
+
{
|
|
113
|
+
name: 'OpenCode',
|
|
114
|
+
globalSkillsDir: path.join(configHome, 'opencode', 'skills'),
|
|
115
|
+
projectSkillsDir: '.agents/skills',
|
|
116
|
+
universal: true,
|
|
117
|
+
detect: () => fs.existsSync(path.join(configHome, 'opencode')),
|
|
118
|
+
},
|
|
119
|
+
|
|
120
|
+
// Non-universal agents (need symlink from their skills dir to canonical)
|
|
121
|
+
{
|
|
122
|
+
name: 'Claude Code',
|
|
123
|
+
globalSkillsDir: path.join(claudeHome, 'skills'),
|
|
124
|
+
projectSkillsDir: '.claude/skills',
|
|
125
|
+
universal: false,
|
|
126
|
+
detect: () => fs.existsSync(claudeHome),
|
|
127
|
+
},
|
|
128
|
+
{
|
|
129
|
+
name: 'Windsurf',
|
|
130
|
+
globalSkillsDir: path.join(home, '.codeium', 'windsurf', 'skills'),
|
|
131
|
+
projectSkillsDir: '.windsurf/skills',
|
|
132
|
+
universal: false,
|
|
133
|
+
detect: () => fs.existsSync(path.join(home, '.codeium', 'windsurf')),
|
|
134
|
+
},
|
|
135
|
+
{
|
|
136
|
+
name: 'Continue',
|
|
137
|
+
globalSkillsDir: path.join(home, '.continue', 'skills'),
|
|
138
|
+
projectSkillsDir: '.continue/skills',
|
|
139
|
+
universal: false,
|
|
140
|
+
detect: () => fs.existsSync(path.join(home, '.continue')),
|
|
141
|
+
},
|
|
142
|
+
{
|
|
143
|
+
name: 'Roo',
|
|
144
|
+
globalSkillsDir: path.join(home, '.roo', 'skills'),
|
|
145
|
+
projectSkillsDir: '.roo/skills',
|
|
146
|
+
universal: false,
|
|
147
|
+
detect: () => fs.existsSync(path.join(home, '.roo')),
|
|
148
|
+
},
|
|
149
|
+
{
|
|
150
|
+
name: 'Kilo',
|
|
151
|
+
globalSkillsDir: path.join(home, '.kilocode', 'skills'),
|
|
152
|
+
projectSkillsDir: '.kilocode/skills',
|
|
153
|
+
universal: false,
|
|
154
|
+
detect: () => fs.existsSync(path.join(home, '.kilocode')),
|
|
155
|
+
},
|
|
156
|
+
{
|
|
157
|
+
name: 'Goose',
|
|
158
|
+
globalSkillsDir: path.join(configHome, 'goose', 'skills'),
|
|
159
|
+
projectSkillsDir: '.goose/skills',
|
|
160
|
+
universal: false,
|
|
161
|
+
detect: () => fs.existsSync(path.join(configHome, 'goose')),
|
|
162
|
+
},
|
|
163
|
+
{
|
|
164
|
+
name: 'Augment',
|
|
165
|
+
globalSkillsDir: path.join(home, '.augment', 'skills'),
|
|
166
|
+
projectSkillsDir: '.augment/skills',
|
|
167
|
+
universal: false,
|
|
168
|
+
detect: () => fs.existsSync(path.join(home, '.augment')),
|
|
169
|
+
},
|
|
170
|
+
{
|
|
171
|
+
name: 'Trae',
|
|
172
|
+
globalSkillsDir: path.join(home, '.trae', 'skills'),
|
|
173
|
+
projectSkillsDir: '.trae/skills',
|
|
174
|
+
universal: false,
|
|
175
|
+
detect: () => fs.existsSync(path.join(home, '.trae')),
|
|
176
|
+
},
|
|
177
|
+
{
|
|
178
|
+
name: 'Junie',
|
|
179
|
+
globalSkillsDir: path.join(home, '.junie', 'skills'),
|
|
180
|
+
projectSkillsDir: '.junie/skills',
|
|
181
|
+
universal: false,
|
|
182
|
+
detect: () => fs.existsSync(path.join(home, '.junie')),
|
|
183
|
+
},
|
|
184
|
+
{
|
|
185
|
+
name: 'Crush',
|
|
186
|
+
globalSkillsDir: path.join(configHome, 'crush', 'skills'),
|
|
187
|
+
projectSkillsDir: '.crush/skills',
|
|
188
|
+
universal: false,
|
|
189
|
+
detect: () => fs.existsSync(path.join(configHome, 'crush')),
|
|
190
|
+
},
|
|
191
|
+
{
|
|
192
|
+
name: 'Kiro CLI',
|
|
193
|
+
globalSkillsDir: path.join(home, '.kiro', 'skills'),
|
|
194
|
+
projectSkillsDir: '.kiro/skills',
|
|
195
|
+
universal: false,
|
|
196
|
+
detect: () => fs.existsSync(path.join(home, '.kiro')),
|
|
197
|
+
},
|
|
198
|
+
{
|
|
199
|
+
name: 'Qwen Code',
|
|
200
|
+
globalSkillsDir: path.join(home, '.qwen', 'skills'),
|
|
201
|
+
projectSkillsDir: '.qwen/skills',
|
|
202
|
+
universal: false,
|
|
203
|
+
detect: () => fs.existsSync(path.join(home, '.qwen')),
|
|
204
|
+
},
|
|
205
|
+
{
|
|
206
|
+
name: 'OpenHands',
|
|
207
|
+
globalSkillsDir: path.join(home, '.openhands', 'skills'),
|
|
208
|
+
projectSkillsDir: '.openhands/skills',
|
|
209
|
+
universal: false,
|
|
210
|
+
detect: () => fs.existsSync(path.join(home, '.openhands')),
|
|
211
|
+
},
|
|
212
|
+
]
|
|
213
|
+
|
|
214
|
+
/** Detects which agents are installed on the system. */
|
|
215
|
+
export function detect(): Agent[] {
|
|
216
|
+
return all.filter((a) => a.detect())
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
/**
|
|
220
|
+
* Installs skill directories to the canonical location and creates symlinks for
|
|
221
|
+
* detected non-universal agents.
|
|
222
|
+
*
|
|
223
|
+
* @param sourceDir - Directory containing skill subdirectories (each with a `SKILL.md`).
|
|
224
|
+
* @param options - Installation options.
|
|
225
|
+
* @returns Installed canonical paths.
|
|
226
|
+
*/
|
|
227
|
+
export function install(sourceDir: string, options: install.Options = {}): install.Result {
|
|
228
|
+
const isGlobal = options.global !== false
|
|
229
|
+
const cwd = options.cwd || process.cwd()
|
|
230
|
+
const base = isGlobal ? home : cwd
|
|
231
|
+
const canonicalBase = path.join(base, '.agents', 'skills')
|
|
232
|
+
const detected = options.agents ?? detect()
|
|
233
|
+
|
|
234
|
+
const paths: string[] = []
|
|
235
|
+
const agents: install.AgentInstall[] = []
|
|
236
|
+
|
|
237
|
+
for (const skill of discoverSkills(sourceDir)) {
|
|
238
|
+
const canonicalDir = path.join(canonicalBase, skill.name)
|
|
239
|
+
|
|
240
|
+
// Copy to canonical location
|
|
241
|
+
rmForce(canonicalDir)
|
|
242
|
+
fs.mkdirSync(canonicalDir, { recursive: true })
|
|
243
|
+
if (skill.root)
|
|
244
|
+
fs.copyFileSync(path.join(skill.dir, 'SKILL.md'), path.join(canonicalDir, 'SKILL.md'))
|
|
245
|
+
else fs.cpSync(skill.dir, canonicalDir, { recursive: true })
|
|
246
|
+
paths.push(canonicalDir)
|
|
247
|
+
|
|
248
|
+
// Create symlinks for non-universal agents
|
|
249
|
+
for (const agent of detected) {
|
|
250
|
+
if (agent.universal) continue
|
|
251
|
+
const agentSkillsDir = isGlobal
|
|
252
|
+
? agent.globalSkillsDir
|
|
253
|
+
: path.join(cwd, agent.projectSkillsDir)
|
|
254
|
+
const agentDir = path.join(agentSkillsDir, skill.name)
|
|
255
|
+
|
|
256
|
+
// Skip if agent dir resolves to canonical (no symlink needed)
|
|
257
|
+
if (agentDir === canonicalDir) continue
|
|
258
|
+
|
|
259
|
+
try {
|
|
260
|
+
rmForce(agentDir)
|
|
261
|
+
fs.mkdirSync(path.dirname(agentDir), { recursive: true })
|
|
262
|
+
// Resolve through any existing symlinks in parent directories
|
|
263
|
+
const realLinkDir = resolveParent(path.dirname(agentDir))
|
|
264
|
+
const realTarget = resolveParent(canonicalDir)
|
|
265
|
+
const rel = path.relative(realLinkDir, realTarget)
|
|
266
|
+
fs.symlinkSync(rel, agentDir)
|
|
267
|
+
agents.push({ agent: agent.name, path: agentDir, mode: 'symlink' })
|
|
268
|
+
} catch {
|
|
269
|
+
// Fallback to copy if symlink fails (e.g. Windows without permissions)
|
|
270
|
+
try {
|
|
271
|
+
fs.cpSync(canonicalDir, agentDir, { recursive: true })
|
|
272
|
+
agents.push({ agent: agent.name, path: agentDir, mode: 'copy' })
|
|
273
|
+
} catch {}
|
|
274
|
+
}
|
|
275
|
+
}
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
return { paths, agents }
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
export declare namespace install {
|
|
282
|
+
type Options = {
|
|
283
|
+
/** Override detected agents. */
|
|
284
|
+
agents?: Agent[] | undefined
|
|
285
|
+
/** Working directory for project-local installs. */
|
|
286
|
+
cwd?: string | undefined
|
|
287
|
+
/** Install globally. Defaults to `true`. */
|
|
288
|
+
global?: boolean | undefined
|
|
289
|
+
}
|
|
290
|
+
type Result = {
|
|
291
|
+
/** Canonical install paths. */
|
|
292
|
+
paths: string[]
|
|
293
|
+
/** Per-agent install details (non-universal agents only). */
|
|
294
|
+
agents: AgentInstall[]
|
|
295
|
+
}
|
|
296
|
+
type AgentInstall = {
|
|
297
|
+
/** Agent display name. */
|
|
298
|
+
agent: string
|
|
299
|
+
/** Installed path. */
|
|
300
|
+
path: string
|
|
301
|
+
/** Whether it was symlinked or copied. */
|
|
302
|
+
mode: 'symlink' | 'copy'
|
|
303
|
+
}
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
/**
|
|
307
|
+
* Removes a skill by name from the canonical location and all detected agent directories.
|
|
308
|
+
*/
|
|
309
|
+
export function remove(
|
|
310
|
+
skillName: string,
|
|
311
|
+
options: { global?: boolean | undefined; cwd?: string | undefined } = {},
|
|
312
|
+
) {
|
|
313
|
+
const isGlobal = options.global !== false
|
|
314
|
+
const cwd = options.cwd || process.cwd()
|
|
315
|
+
const base = isGlobal ? home : cwd
|
|
316
|
+
const canonicalDir = path.join(base, '.agents', 'skills', skillName)
|
|
317
|
+
rmForce(canonicalDir)
|
|
318
|
+
|
|
319
|
+
for (const agent of detect()) {
|
|
320
|
+
if (agent.universal) continue
|
|
321
|
+
const agentSkillsDir = isGlobal ? agent.globalSkillsDir : path.join(cwd, agent.projectSkillsDir)
|
|
322
|
+
const agentDir = path.join(agentSkillsDir, skillName)
|
|
323
|
+
rmForce(agentDir)
|
|
324
|
+
}
|
|
325
|
+
}
|
|
326
|
+
|
|
327
|
+
/** Recursively discovers skill directories (those containing a `SKILL.md`). */
|
|
328
|
+
function discoverSkills(rootDir: string): { name: string; dir: string; root?: boolean }[] {
|
|
329
|
+
const results: { name: string; dir: string; root?: boolean }[] = []
|
|
330
|
+
|
|
331
|
+
function visit(dir: string) {
|
|
332
|
+
let entries: fs.Dirent[]
|
|
333
|
+
try {
|
|
334
|
+
entries = fs.readdirSync(dir, { withFileTypes: true })
|
|
335
|
+
} catch {
|
|
336
|
+
return
|
|
337
|
+
}
|
|
338
|
+
for (const entry of entries) {
|
|
339
|
+
if (!entry.isDirectory()) continue
|
|
340
|
+
const subDir = path.join(dir, entry.name)
|
|
341
|
+
const skillPath = path.join(subDir, 'SKILL.md')
|
|
342
|
+
if (fs.existsSync(skillPath)) {
|
|
343
|
+
const content = fs.readFileSync(skillPath, 'utf8')
|
|
344
|
+
const nameMatch = content.match(/^name:\s*(.+)$/m)
|
|
345
|
+
results.push({ name: sanitizeName(nameMatch?.[1] ?? entry.name), dir: subDir })
|
|
346
|
+
}
|
|
347
|
+
visit(subDir)
|
|
348
|
+
}
|
|
349
|
+
}
|
|
350
|
+
|
|
351
|
+
visit(rootDir)
|
|
352
|
+
|
|
353
|
+
// Root-level SKILL.md (e.g. depth=0)
|
|
354
|
+
const rootSkill = path.join(rootDir, 'SKILL.md')
|
|
355
|
+
if (fs.existsSync(rootSkill)) {
|
|
356
|
+
const content = fs.readFileSync(rootSkill, 'utf8')
|
|
357
|
+
const nameMatch = content.match(/^name:\s*(.+)$/m)
|
|
358
|
+
const name = sanitizeName(nameMatch?.[1] ?? 'skill')
|
|
359
|
+
if (!results.some((r) => r.name === name)) results.push({ name, dir: rootDir, root: true })
|
|
360
|
+
}
|
|
361
|
+
|
|
362
|
+
return results
|
|
363
|
+
}
|
|
364
|
+
|
|
365
|
+
/** Sanitizes a skill name for use as a directory name. */
|
|
366
|
+
function sanitizeName(name: string): string {
|
|
367
|
+
return name.trim().replace(/[/\\]/g, '-').replace(/\.\./g, '').slice(0, 255)
|
|
368
|
+
}
|
|
369
|
+
|
|
370
|
+
/** Removes a file, directory, or symlink (including broken symlinks). */
|
|
371
|
+
function rmForce(target: string) {
|
|
372
|
+
try {
|
|
373
|
+
const stat = fs.lstatSync(target)
|
|
374
|
+
if (stat.isSymbolicLink()) fs.unlinkSync(target)
|
|
375
|
+
else fs.rmSync(target, { recursive: true, force: true })
|
|
376
|
+
} catch {}
|
|
377
|
+
}
|
|
378
|
+
|
|
379
|
+
/** Resolves parent directories through symlinks. */
|
|
380
|
+
function resolveParent(dir: string): string {
|
|
381
|
+
try {
|
|
382
|
+
return fs.realpathSync(dir)
|
|
383
|
+
} catch {
|
|
384
|
+
const parent = path.dirname(dir)
|
|
385
|
+
if (parent === dir) return dir
|
|
386
|
+
try {
|
|
387
|
+
return path.join(fs.realpathSync(parent), path.relative(parent, dir))
|
|
388
|
+
} catch {
|
|
389
|
+
return dir
|
|
390
|
+
}
|
|
391
|
+
}
|
|
392
|
+
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* The `install-ci` VERIFY-WORKFLOW capability (
|
|
2
|
+
* The `install-ci` VERIFY-WORKFLOW capability (spec
|
|
3
3
|
* `land-time-reverify-and-parallel-merge-ceiling`, task
|
|
4
4
|
* `install-ci-tier1-branch-protection`; Story 11 — the Tier-1 GitHub ceiling).
|
|
5
5
|
* Emits a small `verify.yml` workflow whose ONLY job is `verify` and runs on
|
|
@@ -49,7 +49,7 @@ export const VERIFY_WORKFLOW_PATH = 'workflows/verify.yml';
|
|
|
49
49
|
*/
|
|
50
50
|
export function generateVerifyWorkflow(_config: ResolvedCIConfig): string {
|
|
51
51
|
return `\
|
|
52
|
-
# dorfl — the VERIFY workflow (Tier-1 GitHub ceiling;
|
|
52
|
+
# dorfl — the VERIFY workflow (Tier-1 GitHub ceiling; spec
|
|
53
53
|
# land-time-reverify-and-parallel-merge-ceiling, task
|
|
54
54
|
# install-ci-tier1-branch-protection). EMITTED by \`dorfl install-ci\`; the
|
|
55
55
|
# human commits it. DO NOT hand-edit a copy — re-run install-ci to upgrade.
|
|
@@ -100,7 +100,7 @@ jobs:
|
|
|
100
100
|
${VERIFY_CHECK_CONTEXT}:
|
|
101
101
|
runs-on: ubuntu-latest
|
|
102
102
|
steps:
|
|
103
|
-
- uses: actions/checkout@
|
|
103
|
+
- uses: actions/checkout@v5
|
|
104
104
|
with:
|
|
105
105
|
fetch-depth: 0
|
|
106
106
|
- uses: ./.github/actions/dorfl-setup
|