dorfl 0.1.2 → 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-drivers.d.ts +1 -1
- package/dist/advance-drivers.d.ts.map +1 -1
- package/dist/advance-drivers.js +15 -3
- package/dist/advance-drivers.js.map +1 -1
- package/dist/advance-lifecycle-template.d.ts.map +1 -1
- package/dist/advance-lifecycle-template.js +76 -4
- package/dist/advance-lifecycle-template.js.map +1 -1
- package/dist/advance-treeless-publish.d.ts +23 -0
- 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 +59 -7
- package/dist/advance.d.ts.map +1 -1
- package/dist/advance.js +389 -82
- package/dist/advance.js.map +1 -1
- package/dist/advancing-lock.d.ts +30 -2
- package/dist/advancing-lock.d.ts.map +1 -1
- package/dist/advancing-lock.js +50 -0
- 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 +17 -3
- package/dist/apply-decide.d.ts.map +1 -1
- package/dist/apply-decide.js +36 -7
- package/dist/apply-decide.js.map +1 -1
- package/dist/apply-merge-action.d.ts +17 -5
- package/dist/apply-merge-action.d.ts.map +1 -1
- package/dist/apply-merge-action.js +43 -8
- package/dist/apply-merge-action.js.map +1 -1
- package/dist/apply-persist.d.ts +57 -26
- package/dist/apply-persist.d.ts.map +1 -1
- package/dist/apply-persist.js +166 -37
- 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/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 +320 -63
- package/dist/cli.js.map +1 -1
- package/dist/close-job-template.js +1 -1
- package/dist/complete.d.ts +6 -3
- package/dist/complete.d.ts.map +1 -1
- package/dist/complete.js +91 -37
- package/dist/complete.js.map +1 -1
- package/dist/config.d.ts +55 -9
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +56 -4
- package/dist/config.js.map +1 -1
- package/dist/continue-branch.d.ts.map +1 -1
- package/dist/continue-branch.js +22 -0
- package/dist/continue-branch.js.map +1 -1
- package/dist/decision-engine.d.ts +38 -10
- 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.map +1 -1
- package/dist/do-autopick.js +11 -1
- package/dist/do-autopick.js.map +1 -1
- package/dist/do-config.d.ts +1 -1
- package/dist/do.d.ts +49 -56
- package/dist/do.d.ts.map +1 -1
- package/dist/do.js +419 -30
- package/dist/do.js.map +1 -1
- package/dist/env-config.d.ts.map +1 -1
- package/dist/env-config.js +12 -4
- 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 +10 -27
- package/dist/format.js.map +1 -1
- package/dist/frontmatter.d.ts +16 -4
- package/dist/frontmatter.d.ts.map +1 -1
- package/dist/frontmatter.js +27 -1
- 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 +132 -38
- package/dist/install-ci-branch-protection.d.ts.map +1 -1
- package/dist/install-ci-branch-protection.js +190 -48
- package/dist/install-ci-branch-protection.js.map +1 -1
- package/dist/install-ci-core.d.ts +21 -1
- package/dist/install-ci-core.d.ts.map +1 -1
- package/dist/install-ci-core.js +10 -3
- package/dist/install-ci-core.js.map +1 -1
- package/dist/install-ci-github.d.ts +32 -0
- package/dist/install-ci-github.d.ts.map +1 -1
- package/dist/install-ci-github.js +73 -0
- package/dist/install-ci-github.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-trigger-template.js +1 -1
- package/dist/intake.d.ts +17 -4
- package/dist/intake.d.ts.map +1 -1
- package/dist/intake.js +23 -7
- package/dist/intake.js.map +1 -1
- package/dist/integration-core.d.ts +10 -7
- package/dist/integration-core.d.ts.map +1 -1
- package/dist/integration-core.js +174 -60
- 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 +2 -2
- package/dist/isolation.d.ts.map +1 -1
- package/dist/isolation.js +9 -0
- package/dist/isolation.js.map +1 -1
- package/dist/item-lock.d.ts +196 -129
- package/dist/item-lock.d.ts.map +1 -1
- package/dist/item-lock.js +329 -254
- package/dist/item-lock.js.map +1 -1
- package/dist/ledger-write.d.ts +31 -26
- 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 +17 -0
- package/dist/lifecycle-gather.d.ts.map +1 -1
- package/dist/lifecycle-gather.js +7 -1
- package/dist/lifecycle-gather.js.map +1 -1
- package/dist/lifecycle-pools.d.ts +40 -3
- package/dist/lifecycle-pools.d.ts.map +1 -1
- package/dist/lifecycle-pools.js +26 -6
- package/dist/lifecycle-pools.js.map +1 -1
- package/dist/merge-question-surfacer.d.ts +15 -1
- package/dist/merge-question-surfacer.d.ts.map +1 -1
- package/dist/merge-question-surfacer.js +18 -3
- 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/needs-attention.d.ts +293 -16
- package/dist/needs-attention.d.ts.map +1 -1
- package/dist/needs-attention.js +532 -57
- package/dist/needs-attention.js.map +1 -1
- package/dist/orphan-sidecar.d.ts +8 -4
- 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 +3 -3
- package/dist/placement.js +1 -1
- 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/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/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 +5 -0
- 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 +53 -7
- 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-verdict.js +1 -1
- package/dist/review-verdict.js.map +1 -1
- package/dist/run.d.ts +1 -1
- package/dist/run.d.ts.map +1 -1
- package/dist/run.js +54 -19
- package/dist/run.js.map +1 -1
- package/dist/scan.d.ts +17 -8
- package/dist/scan.d.ts.map +1 -1
- package/dist/scan.js +22 -8
- package/dist/scan.js.map +1 -1
- package/dist/select-priority.d.ts +2 -2
- package/dist/select-priority.js +1 -1
- 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 +45 -10
- package/dist/sidecar.d.ts.map +1 -1
- package/dist/sidecar.js +82 -2
- 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 +5 -5
- package/dist/slug-namespace.js +5 -5
- package/dist/slug-namespace.js.map +1 -1
- package/dist/spec-complete.d.ts.map +1 -1
- package/dist/spec-complete.js +2 -3
- package/dist/spec-complete.js.map +1 -1
- package/dist/start.d.ts.map +1 -1
- package/dist/start.js +51 -57
- package/dist/start.js.map +1 -1
- 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.js +1 -1
- package/dist/surface-persist.js.map +1 -1
- package/dist/tasker-review-loop.d.ts +4 -3
- package/dist/tasker-review-loop.d.ts.map +1 -1
- package/dist/tasker-review-loop.js.map +1 -1
- package/dist/tasking-lock.d.ts +2 -2
- package/dist/tasking-lock.d.ts.map +1 -1
- package/dist/tasking-lock.js +53 -32
- package/dist/tasking-lock.js.map +1 -1
- package/dist/tasking.d.ts +40 -6
- package/dist/tasking.d.ts.map +1 -1
- package/dist/tasking.js +224 -12
- package/dist/tasking.js.map +1 -1
- package/dist/triage-persist.d.ts +10 -6
- package/dist/triage-persist.d.ts.map +1 -1
- package/dist/triage-persist.js +34 -4
- 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.js +1 -1
- 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 +7 -3
- package/dist/work-layout.d.ts.map +1 -1
- package/dist/work-layout.js +6 -3
- package/dist/work-layout.js.map +1 -1
- package/dist/workspace.d.ts +1 -1
- package/package.json +2 -2
- package/src/advance-drivers.ts +16 -3
- package/src/advance-lifecycle-template.ts +89 -4
- package/src/advance-treeless-publish.ts +45 -0
- package/src/advance.ts +467 -87
- package/src/advancing-lock.ts +96 -1
- package/src/agent-launch.ts +37 -12
- package/src/agent-stop.ts +60 -2
- package/src/apply-decide.ts +36 -7
- package/src/apply-merge-action.ts +45 -7
- package/src/apply-persist.ts +228 -54
- package/src/apply-stuck-action.ts +260 -0
- package/src/brand.ts +14 -2
- package/src/cli-spinner.ts +1 -1
- package/src/cli.ts +401 -70
- package/src/close-job-template.ts +1 -1
- package/src/complete.ts +110 -52
- package/src/config.ts +107 -13
- package/src/continue-branch.ts +22 -0
- package/src/decision-engine.ts +55 -17
- package/src/do-autopick.ts +12 -1
- package/src/do-config.ts +1 -1
- package/src/do.ts +511 -38
- package/src/env-config.ts +12 -4
- package/src/failure-cause.ts +30 -1
- package/src/format.ts +10 -30
- package/src/frontmatter.ts +35 -5
- 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 +282 -57
- package/src/install-ci-core.ts +30 -3
- package/src/install-ci-github.ts +86 -0
- package/src/install-skills.ts +166 -0
- package/src/intake-trigger-template.ts +1 -1
- package/src/intake.ts +46 -11
- package/src/integration-core.ts +199 -65
- package/src/integrator.ts +22 -9
- package/src/isolation.ts +11 -2
- package/src/item-lock.ts +485 -341
- package/src/ledger-write.ts +135 -150
- package/src/lifecycle-gather.ts +29 -6
- package/src/lifecycle-pools.ts +67 -9
- package/src/merge-question-surfacer.ts +28 -4
- package/src/migrate-stuck-locks.ts +451 -0
- package/src/needs-attention.ts +857 -84
- package/src/orphan-sidecar.ts +47 -6
- package/src/pi-harness.ts +82 -2
- package/src/placement.ts +3 -3
- package/src/prd-to-spec.ts +13 -5
- package/src/reap-branches.ts +38 -14
- package/src/recover-isolated.ts +17 -0
- package/src/repo-config.ts +55 -6
- package/src/repo-mirror.ts +23 -1
- package/src/review-verdict.ts +1 -1
- package/src/run.ts +64 -18
- package/src/scan.ts +22 -8
- package/src/select-priority.ts +3 -3
- package/src/sidecar-apply.ts +1 -1
- package/src/sidecar.ts +138 -11
- package/src/slug-namespace.ts +7 -7
- package/src/spec-complete.ts +2 -3
- package/src/start.ts +53 -59
- package/src/surface-gate.ts +10 -3
- package/src/surface-persist.ts +1 -1
- package/src/tasker-review-loop.ts +4 -3
- package/src/tasking-lock.ts +52 -36
- package/src/tasking.ts +261 -17
- package/src/triage-persist.ts +56 -12
- 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 +1 -1
- package/src/watch-session.ts +102 -7
- package/src/work-layout.ts +6 -3
- package/src/workspace.ts +1 -1
package/src/start.ts
CHANGED
|
@@ -122,7 +122,8 @@ class StartUsageError extends Error {}
|
|
|
122
122
|
/**
|
|
123
123
|
* Raised for a deliberate REFUSAL (exit 1, outcome 'refused') — distinct from a
|
|
124
124
|
* usage/environment error. Used when the item exists but start declines to act
|
|
125
|
-
* (an in-progress item without --resume). The decision is
|
|
125
|
+
* (an in-progress item without --resume). The decision is LOCK-based (a held
|
|
126
|
+
* `active` per-item lock), not a `work/in-progress/` folder read.
|
|
126
127
|
*/
|
|
127
128
|
class StartRefusal extends Error {}
|
|
128
129
|
|
|
@@ -262,11 +263,11 @@ async function dispatchFolder(
|
|
|
262
263
|
if (!inPool) {
|
|
263
264
|
return folder;
|
|
264
265
|
}
|
|
265
|
-
// In the pool/staging: claimed-ness
|
|
266
|
+
// In the pool/staging: claimed-ness is the per-item lock (not the folder).
|
|
267
|
+
// Post-`retire-stuck-lock-state` there is no `stuck` state — a parked item is
|
|
268
|
+
// a `needsAnswers:true` pool item on `main` (rendered by status/scan and
|
|
269
|
+
// drained by the apply rung), NEVER a lock re-key.
|
|
266
270
|
const lock = await readItemLock({item: `task:${slug}`, cwd, arbiter, env});
|
|
267
|
-
if (lock && lock.state === 'stuck') {
|
|
268
|
-
return 'needs-attention';
|
|
269
|
-
}
|
|
270
271
|
if (lock && lock.state === 'active') {
|
|
271
272
|
return 'in-progress';
|
|
272
273
|
}
|
|
@@ -404,7 +405,7 @@ async function continueConflictResult(params: {
|
|
|
404
405
|
}
|
|
405
406
|
const message =
|
|
406
407
|
`Could not continue '${params.slug}': the kept work branch did not rebase ` +
|
|
407
|
-
`cleanly onto ${params.arbiter}/main;
|
|
408
|
+
`cleanly onto ${params.arbiter}/main; marked stuck on its per-item lock ` +
|
|
408
409
|
'(surfaced by status). Resolve against the latest main, or `requeue --reset` ' +
|
|
409
410
|
'to discard and start fresh.';
|
|
410
411
|
return {
|
|
@@ -438,8 +439,8 @@ async function continuePushFailureResult(params: {
|
|
|
438
439
|
}
|
|
439
440
|
const message =
|
|
440
441
|
`Could not continue '${params.slug}': publishing the rebased work branch to ` +
|
|
441
|
-
`${params.arbiter} failed terminally (${params.pushFailure});
|
|
442
|
-
'
|
|
442
|
+
`${params.arbiter} failed terminally (${params.pushFailure}); marked stuck ` +
|
|
443
|
+
'on its per-item lock (surfaced by status), the kept branch left intact on ' +
|
|
443
444
|
'the arbiter (recoverable). `requeue` to retry once the churn settles.';
|
|
444
445
|
return {
|
|
445
446
|
exitCode: 1,
|
|
@@ -465,42 +466,17 @@ async function startFromNeedsAttention(params: {
|
|
|
465
466
|
}): Promise<StartResult> {
|
|
466
467
|
const {slug, arbiter, cwd, env, note} = params;
|
|
467
468
|
|
|
468
|
-
//
|
|
469
|
-
//
|
|
470
|
-
//
|
|
471
|
-
//
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
if (stuck?.questions && stuck.questions.length > 0) {
|
|
479
|
-
note('Surfaced questions:');
|
|
480
|
-
for (const q of stuck.questions) {
|
|
481
|
-
note(` - ${q}`);
|
|
482
|
-
}
|
|
483
|
-
}
|
|
484
|
-
|
|
485
|
-
// Resume the lock `stuck → active` THROUGH the write seam (a pure lock amend, NO
|
|
486
|
-
// `main` write, NO temp checkout — the body already rests in `backlog/` and the
|
|
487
|
-
// work stays on the kept `work/<slug>` branch), then onboard onto work/<slug>.
|
|
488
|
-
const resolved = await ledgerWrite.applyResolveNeedsAttentionTransition({
|
|
489
|
-
cwd,
|
|
490
|
-
slug,
|
|
491
|
-
arbiter,
|
|
492
|
-
env,
|
|
493
|
-
note,
|
|
494
|
-
});
|
|
495
|
-
if (!resolved.moved) {
|
|
496
|
-
throw new StartUsageError(
|
|
497
|
-
resolved.reasonNotMoved ??
|
|
498
|
-
`could not resolve '${slug}' from needs-attention.`,
|
|
499
|
-
);
|
|
500
|
-
}
|
|
469
|
+
// Post-`retire-stuck-lock-state`: the `stuck` lock state is gone; a parked
|
|
470
|
+
// item is a `needsAnswers:true` pool item on `main` drained by the apply
|
|
471
|
+
// rung (answer the sidecar). This branch fires only when a LEGACY
|
|
472
|
+
// `needs-attention/` folder body still exists on `<arbiter>/main` (no
|
|
473
|
+
// live path lands one). Onboard the human onto the kept work branch — no
|
|
474
|
+
// lock amend, no reason/questions read from the lock (those live on the
|
|
475
|
+
// surfaced sidecar now).
|
|
476
|
+
note(
|
|
477
|
+
`'${slug}' is in the legacy needs-attention/ folder — onboarding onto its work branch; answer any question sidecar on main to drain it.`,
|
|
478
|
+
);
|
|
501
479
|
|
|
502
|
-
// The lock is back to active (the human owns it). Onboard onto the work branch:
|
|
503
|
-
// CONTINUE from a kept arbiter work/<slug> when present, else fresh off main.
|
|
504
480
|
const switched = await switchToWorkBranch({slug, arbiter, cwd, env, note});
|
|
505
481
|
if (switched.rebaseConflict) {
|
|
506
482
|
return continueConflictResult({slug, arbiter, cwd, env, note});
|
|
@@ -522,10 +498,14 @@ async function startFromNeedsAttention(params: {
|
|
|
522
498
|
}
|
|
523
499
|
|
|
524
500
|
/**
|
|
525
|
-
* In-progress → already claimed (
|
|
526
|
-
* apply). Refuse by default. With --resume the human explicitly asserts
|
|
501
|
+
* In-progress → already claimed (the per-item LOCK is held `active`, so the CAS
|
|
502
|
+
* cannot apply). Refuse by default. With --resume the human explicitly asserts
|
|
527
503
|
* ownership, so we switch to the work branch WITHOUT claiming. The decision is
|
|
528
|
-
*
|
|
504
|
+
* LOCK-based: `dispatchFolder` reaches here only when the lock is held `active`
|
|
505
|
+
* (the body rests in the pool/staging, NOT a `work/in-progress/` folder file —
|
|
506
|
+
* the folder cutover retired that path,
|
|
507
|
+
* `finish-in-progress-folder-cutover-remove-legacy-recovery-readers`). We never
|
|
508
|
+
* read the advisory `claimed_by` to guess ownership.
|
|
529
509
|
*/
|
|
530
510
|
async function startFromInProgress(params: {
|
|
531
511
|
slug: string;
|
|
@@ -538,10 +518,11 @@ async function startFromInProgress(params: {
|
|
|
538
518
|
const {slug, arbiter, cwd, env, resume, note} = params;
|
|
539
519
|
|
|
540
520
|
if (!resume) {
|
|
541
|
-
// The
|
|
542
|
-
//
|
|
543
|
-
// message; whoever holds it is read from git
|
|
544
|
-
// (`git log work/
|
|
521
|
+
// The held LOCK drove the decision (the per-item lock is the source of truth
|
|
522
|
+
// for liveness now — the body stays in the pool, no `work/in-progress/` file).
|
|
523
|
+
// We do NOT name the claimer in the message; whoever holds it is read from git
|
|
524
|
+
// history (`git log` over the item's `work/tasks/ready/<slug>.md` + the lock
|
|
525
|
+
// ref history).
|
|
545
526
|
throw new StartRefusal(
|
|
546
527
|
`'${slug}' is already in-progress; see \`git log\` for who claimed it; ` +
|
|
547
528
|
'if this is your own work, re-run with --resume.',
|
|
@@ -816,8 +797,9 @@ function surfaceUnmovedStartResult(params: {
|
|
|
816
797
|
* TREE-LESS (`#89` mechanism), the SAME-PROFILE sibling of
|
|
817
798
|
* {@link routeContinuePushFailure}: the rebase was ABORTED, so the REAL continued
|
|
818
799
|
* `work/<slug>` is already on the arbiter from the prior requeue, untouched
|
|
819
|
-
* (after-commit, durable, recoverable). The surface is PURELY the
|
|
820
|
-
* `
|
|
800
|
+
* (after-commit, durable, recoverable). The surface is PURELY the lock amend to
|
|
801
|
+
* `state: stuck` with the reason (post lock-cutover — no `in-progress/ →
|
|
802
|
+
* needs-attention/` folder move) — we publish it via
|
|
821
803
|
* the tree-less surface CAS (the SAME no-checkout primitive `requeue` uses for the
|
|
822
804
|
* reverse direction), NO temp-branch switch/restore, NO `pushBranch`, NO worktree.
|
|
823
805
|
*/
|
|
@@ -831,8 +813,10 @@ async function routeContinueConflict(params: {
|
|
|
831
813
|
const {slug, arbiter, cwd, env, note} = params;
|
|
832
814
|
const reason =
|
|
833
815
|
`continuing the kept ${arbiter}/${workBranchRef('task', slug)}: rebase onto ` +
|
|
834
|
-
`${arbiter}/main conflicted (aborted, never auto-resolved) —
|
|
835
|
-
'
|
|
816
|
+
`${arbiter}/main conflicted (aborted, never auto-resolved) — run ` +
|
|
817
|
+
'`requeue --reconcile` to non-destructively re-sync the mirror and retry ' +
|
|
818
|
+
'the rebase (keeps the work). Last resort: `requeue --reset` ' +
|
|
819
|
+
'DESTRUCTIVELY discards the branch and starts fresh.';
|
|
836
820
|
note(reason);
|
|
837
821
|
// PROPAGATE the {moved, reasonNotMoved} result to the caller so a `moved:false`
|
|
838
822
|
// (the surface did NOT reach main — lost the CAS race) is surfaced honestly
|
|
@@ -857,8 +841,9 @@ async function routeContinueConflict(params: {
|
|
|
857
841
|
* TREE-LESS (`#89` mechanism): the recoverable artifact — the kept `work/<slug>`
|
|
858
842
|
* — is ALREADY on the arbiter from the prior requeue (our local rebased tip is
|
|
859
843
|
* what FAILED to push, so it is not the cross-machine truth), and the work is
|
|
860
|
-
* already committed. So the surface is PURELY the
|
|
861
|
-
*
|
|
844
|
+
* already committed. So the surface is PURELY the lock amend to `state: stuck`
|
|
845
|
+
* with the reason (post lock-cutover — no `in-progress/ → needs-attention/`
|
|
846
|
+
* folder move): we publish it via the tree-less
|
|
862
847
|
* surface CAS (the SAME no-checkout primitive `requeue` uses for the reverse
|
|
863
848
|
* direction) — NO temp-branch switch/restore, NO `pushBranch`, NO worktree. A
|
|
864
849
|
* `requeue` then continues from the kept arbiter tip.
|
|
@@ -875,8 +860,10 @@ async function routeContinuePushFailure(params: {
|
|
|
875
860
|
const reason =
|
|
876
861
|
`continuing the kept ${arbiter}/${workBranchRef('task', slug)}: publishing ` +
|
|
877
862
|
`the rebased work branch to ${arbiter} failed terminally (${pushFailure}) — ` +
|
|
878
|
-
'the kept branch is left intact on the arbiter (recoverable); `requeue
|
|
879
|
-
'
|
|
863
|
+
'the kept branch is left intact on the arbiter (recoverable); `requeue ' +
|
|
864
|
+
'--reconcile` to non-destructively re-sync the mirror and retry once the ' +
|
|
865
|
+
'churn settles (keeps the work). Last resort: `requeue --reset` ' +
|
|
866
|
+
'DESTRUCTIVELY discards the branch and starts fresh.';
|
|
880
867
|
note(reason);
|
|
881
868
|
// PROPAGATE the {moved, reasonNotMoved} result to the caller so a `moved:false`
|
|
882
869
|
// (the surface did NOT reach main — lost the CAS race) is surfaced honestly
|
|
@@ -936,7 +923,14 @@ async function folderOnArbiterMain(
|
|
|
936
923
|
)[] = [
|
|
937
924
|
'tasks-ready',
|
|
938
925
|
...(allowBacklog ? (['tasks-backlog'] as const) : []),
|
|
939
|
-
|
|
926
|
+
// NOTE: `work/in-progress/` is NOT probed (task
|
|
927
|
+
// `finish-in-progress-folder-cutover-remove-legacy-recovery-readers`): the
|
|
928
|
+
// per-item-lock cutover moved claim OFF writing that folder, so nothing lands a
|
|
929
|
+
// body there. A claimed-and-in-flight item RESTS in the pool/staging on `main`
|
|
930
|
+
// with the held lock as its liveness — `dispatchFolder` re-keys THAT to the
|
|
931
|
+
// `in-progress` dispatch off the LOCK (`state: active`), never a folder read.
|
|
932
|
+
// (`needs-attention/` is likewise the lock `state: stuck`; its retained probe is
|
|
933
|
+
// a separate cutover's concern, left untouched here.)
|
|
940
934
|
'needs-attention',
|
|
941
935
|
'done',
|
|
942
936
|
];
|
package/src/surface-gate.ts
CHANGED
|
@@ -252,9 +252,16 @@ export function buildSurfacePrompt(item: string): string {
|
|
|
252
252
|
` "note": "… (optional; your reasoning / findings prose lives HERE, not outside the object)"}`,
|
|
253
253
|
'```',
|
|
254
254
|
``,
|
|
255
|
-
`
|
|
256
|
-
`
|
|
257
|
-
|
|
255
|
+
`RULE — empty is VALID, absence is NOT. When there is nothing to ask (no open`,
|
|
256
|
+
`judgement to surface), you MUST STILL emit the JSON object, with`,
|
|
257
|
+
`\`"questions": []\` (an empty array); put any explanation of WHY in the`,
|
|
258
|
+
`\`note\` field INSIDE the object. Do NOT replace the object with a prose`,
|
|
259
|
+
`sentence like "no open questions", do NOT skip the emit, and do NOT drop the`,
|
|
260
|
+
`\`questions\` field. The parser (\`parseSurfaceEmit\`) enforces this: an empty`,
|
|
261
|
+
`\`questions\` array is a valid, honest "no open judgement" result; ABSENCE of`,
|
|
262
|
+
`the \`questions\` field is rejected as an unparseable emit — that failure is`,
|
|
263
|
+
`what strands the surface rung. Emitting \`{"questions": [], "note": "…"}\` is`,
|
|
264
|
+
`ALWAYS the safe, honest close for a nothing-to-ask item.`,
|
|
258
265
|
``,
|
|
259
266
|
// The SHARED defensive-JSON contract (the same hardening Gate-2's verdict
|
|
260
267
|
// prompt carries) — the surface rung hit the IDENTICAL unparseable-emit
|
package/src/surface-persist.ts
CHANGED
|
@@ -192,7 +192,7 @@ export function persistSurfacedQuestions(
|
|
|
192
192
|
|
|
193
193
|
// Write the appended/created sidecar.
|
|
194
194
|
mkdirSync(dirname(sidecarAbs), {recursive: true});
|
|
195
|
-
writeFileSync(sidecarAbs, serialiseSidecar(model));
|
|
195
|
+
writeFileSync(sidecarAbs, serialiseSidecar(model, {repoRoot: cwd}));
|
|
196
196
|
|
|
197
197
|
// Stage exactly the two paths and commit them TOGETHER (one atomic commit) —
|
|
198
198
|
// the sidecar write + the `needsAnswers:true` flip land in the SAME commit, so
|
|
@@ -52,7 +52,7 @@ export {parseReviewVerdict as parseTaskReviewVerdict} from './review-verdict.js'
|
|
|
52
52
|
* applyEdits(…to disk…) }` — ONE agent LAUNCH per pass, the runner writing the
|
|
53
53
|
* agent's edits to the candidate task FILES (`work/tasks/backlog/`) between passes, the
|
|
54
54
|
* next pass's agent re-reading the edited files. Accumulation is via DISK +
|
|
55
|
-
* re-launch, NOT one agent retaining context. `
|
|
55
|
+
* re-launch, NOT one agent retaining context. `spec/review.md` §Shape 2 is internally
|
|
56
56
|
* contradictory on this (single-context headline vs "edit the files" operative spec);
|
|
57
57
|
* this code implements the operative reading. See
|
|
58
58
|
* `work/findings/review-edit-loop-single-context-is-unbuilt-aspiration-vs-per-pass-disk-impl.md`.
|
|
@@ -75,8 +75,9 @@ export {parseReviewVerdict as parseTaskReviewVerdict} from './review-verdict.js'
|
|
|
75
75
|
* - **a specific uncertain task** → emit it `needsAnswers: true` with the
|
|
76
76
|
* questions in its body (created, not agent-buildable until a human answers).
|
|
77
77
|
* - **the whole decomposition unclear / `taskerLoopMax` exhausted with blockers** →
|
|
78
|
-
*
|
|
79
|
-
* reason,
|
|
78
|
+
* mark the spec stuck on its per-item lock (post lock-cutover — `state: stuck`
|
|
79
|
+
* with the questions as the reason, no `work/needs-attention/` folder write),
|
|
80
|
+
* emitting NO guessed tasks.
|
|
80
81
|
*
|
|
81
82
|
* The verdict sink itself (the git transitions for those three outcomes) is the
|
|
82
83
|
* caller's (`tasking.ts`): this module decides WHICH outcome and prepares the
|
package/src/tasking-lock.ts
CHANGED
|
@@ -1,9 +1,6 @@
|
|
|
1
1
|
import {runAsync, type RunResult} from './git.js';
|
|
2
|
-
import {
|
|
3
|
-
|
|
4
|
-
releaseItemLock,
|
|
5
|
-
markStuckItemLock,
|
|
6
|
-
} from './item-lock.js';
|
|
2
|
+
import {acquireItemLock, releaseItemLock, readItemLock} from './item-lock.js';
|
|
3
|
+
import {surfaceStuckToNeedsAttention} from './needs-attention.js';
|
|
7
4
|
import {workItemRel} from './work-layout.js';
|
|
8
5
|
|
|
9
6
|
/**
|
|
@@ -35,9 +32,10 @@ import {workItemRel} from './work-layout.js';
|
|
|
35
32
|
* read-stability backstop). A dry-run takes no lock (it mutates nothing).
|
|
36
33
|
*
|
|
37
34
|
* - **Release** ({@link releaseTaskingLock}) DELETES the unified lock ref. It
|
|
38
|
-
* moves NO lifecycle file: the durable `
|
|
39
|
-
* by the integrate band (`tasking.ts`/`integration-core.ts`), and there
|
|
40
|
-
* `tasking/ →
|
|
35
|
+
* moves NO lifecycle file: the durable `specs/ready → specs/tasked` success move
|
|
36
|
+
* is owned by the integrate band (`tasking.ts`/`integration-core.ts`), and there
|
|
37
|
+
* is no `tasking/ → specs/ready/` abort bounce anymore (the body never left
|
|
38
|
+
* `specs/ready/`). When
|
|
41
39
|
* `routeToNeedsAttention` is set (the tasker review/edit loop's
|
|
42
40
|
* decomposition-unclear verdict, or the task-SET acceptance gate's `block`),
|
|
43
41
|
* release amends the lock `active → stuck` with the reason on the entry INSTEAD
|
|
@@ -57,7 +55,7 @@ import {workItemRel} from './work-layout.js';
|
|
|
57
55
|
*
|
|
58
56
|
* This module provides the lock PRIMITIVES only. The orchestrating `do spec:<slug>`
|
|
59
57
|
* tasking command (`tasking.ts`) acquires, drives the agent's tasking, integrates
|
|
60
|
-
* the emitted tasks + the durable `
|
|
58
|
+
* the emitted tasks + the durable `specs/ready → specs/tasked` move, and releases. The
|
|
61
59
|
* human path (no contention) may task on `main` directly without the lock.
|
|
62
60
|
*/
|
|
63
61
|
|
|
@@ -188,9 +186,9 @@ async function runAcquire(
|
|
|
188
186
|
// a lock is dead via `release-lock` + `gc --ledger`).
|
|
189
187
|
// Spec `prd-to-spec-vocabulary-cutover-and-migration-command`: the parent-spec
|
|
190
188
|
// item identity is `spec:<slug>`, so the unified per-item lock ref is
|
|
191
|
-
// `refs/dorfl/lock/spec-<slug>`. HARD CUTOVER: the legacy
|
|
192
|
-
// is GONE — the resolver no longer treats
|
|
193
|
-
//
|
|
189
|
+
// `refs/dorfl/lock/spec-<slug>`. HARD CUTOVER: the legacy ''prd:<slug>'' identity
|
|
190
|
+
// is GONE — the resolver no longer treats ''prd:'' as the spec namespace (a
|
|
191
|
+
// ''prd:<slug>'' arg is a bare literal task slug now).
|
|
194
192
|
const lock = await acquireItemLock({
|
|
195
193
|
item: `spec:${slug}`,
|
|
196
194
|
action: 'task',
|
|
@@ -273,9 +271,9 @@ export interface ReleaseTaskingLockResult {
|
|
|
273
271
|
/**
|
|
274
272
|
* Release the tasking lock for `slug`: DELETE the unified `action: task` lock ref
|
|
275
273
|
* (idempotent — an already-absent ref is a clean `released`). It moves NO lifecycle
|
|
276
|
-
* file: the durable `
|
|
274
|
+
* file: the durable `specs/ready → specs/tasked` success move is owned by the integrate band,
|
|
277
275
|
* and the spec body never left `work/specs/ready/` under the lock, so there is no
|
|
278
|
-
* `tasking/ →
|
|
276
|
+
* `tasking/ → specs/ready/` restore.
|
|
279
277
|
*
|
|
280
278
|
* When `routeToNeedsAttention` is set (the tasker decomposition-unclear verdict /
|
|
281
279
|
* the task-SET acceptance gate `block`), the lock is AMENDED `active → stuck`
|
|
@@ -325,33 +323,51 @@ async function runRelease(
|
|
|
325
323
|
);
|
|
326
324
|
}
|
|
327
325
|
|
|
328
|
-
// DECOMPOSITION-UNCLEAR / TASK-GATE BLOCK:
|
|
329
|
-
//
|
|
330
|
-
//
|
|
331
|
-
//
|
|
326
|
+
// DECOMPOSITION-UNCLEAR / TASK-GATE BLOCK: surface the spec as a `stuck`-kind
|
|
327
|
+
// sidecar + `needsAnswers:true` on the spec body in ONE commit on
|
|
328
|
+
// `<arbiter>/main`, THEN release the tasking lock (PR-2b, spec
|
|
329
|
+
// `surface-stuck-as-questions-and-retire-stuck-lock-state`, decision #1). The
|
|
330
|
+
// spec body stays in `work/specs/ready/` (or `work/specs/proposed/` — the D1
|
|
331
|
+
// probe finds it); the surfaced question keeps the spec out of the taskable
|
|
332
|
+
// pool via `needsAnswers:true` (eligibility `false`) until a human answers.
|
|
332
333
|
if (options.routeToNeedsAttention !== undefined) {
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
// `wrong-state` (already stuck) is a tolerated idempotent re-surface.
|
|
343
|
-
const message = `Routed the tasking of '${slug}' to needs-attention (per-item lock marked stuck).`;
|
|
334
|
+
const item = `spec:${slug}`;
|
|
335
|
+
// Detect a genuinely NOT-HELD lock BEFORE the surface (so a bounce of an
|
|
336
|
+
// unlocked spec still returns the exit-2 `lost` contract). The surface itself
|
|
337
|
+
// is idempotent, but without this pre-check a not-held spec would surface
|
|
338
|
+
// silently on main with no lock to release — losing the caller-visible
|
|
339
|
+
// "nothing to route" signal.
|
|
340
|
+
const held = await readItemLock({item, cwd, arbiter, env});
|
|
341
|
+
if (held === undefined) {
|
|
342
|
+
const message = `'${slug}' is not locked for tasking — nothing to route to needs-attention.`;
|
|
344
343
|
note(message);
|
|
345
|
-
return {exitCode:
|
|
344
|
+
return {exitCode: 2, outcome: 'lost', message};
|
|
346
345
|
}
|
|
347
|
-
|
|
348
|
-
const
|
|
346
|
+
try {
|
|
347
|
+
const surfaced = await surfaceStuckToNeedsAttention({
|
|
348
|
+
cwd,
|
|
349
|
+
slug,
|
|
350
|
+
item,
|
|
351
|
+
reason: options.routeToNeedsAttention.reason,
|
|
352
|
+
arbiter,
|
|
353
|
+
env,
|
|
354
|
+
note,
|
|
355
|
+
});
|
|
356
|
+
if (surfaced.surfaced || surfaced.bodyAbsent) {
|
|
357
|
+
const message = surfaced.surfaced
|
|
358
|
+
? `Routed the tasking of '${slug}' to needs-attention (surfaced on ${arbiter}/main; tasking lock released).`
|
|
359
|
+
: `Routed the tasking of '${slug}' to needs-attention (no spec body on ${arbiter}/main — clean no-op surface; tasking lock released).`;
|
|
360
|
+
note(message);
|
|
361
|
+
return {exitCode: 0, outcome: 'released', message};
|
|
362
|
+
}
|
|
363
|
+
const message = `could not surface '${item}' on ${arbiter}/main (${surfaced.reasonNotSurfaced ?? 'unknown'}).`;
|
|
349
364
|
note(message);
|
|
350
|
-
return {exitCode:
|
|
365
|
+
return {exitCode: 1, outcome: 'usage-error', message};
|
|
366
|
+
} catch (err) {
|
|
367
|
+
const message = `could not surface '${item}' on ${arbiter}/main (${err instanceof Error ? err.message : String(err)}).`;
|
|
368
|
+
note(message);
|
|
369
|
+
return {exitCode: 1, outcome: 'usage-error', message};
|
|
351
370
|
}
|
|
352
|
-
const message = `could not mark the per-item lock for '${slug}' stuck (${stuck.outcome}: ${stuck.message}).`;
|
|
353
|
-
note(message);
|
|
354
|
-
return {exitCode: 1, outcome: 'usage-error', message};
|
|
355
371
|
}
|
|
356
372
|
|
|
357
373
|
// NORMAL release: delete the lock ref (idempotent).
|