@afokapu/atdd-flow 0.3.65 → 0.3.66
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -1
- package/package.json +2 -2
- package/src/tasks.ts +9 -12
package/README.md
CHANGED
|
@@ -130,7 +130,7 @@ atdd-flow task review example-app runtime-rollout --by driver.runtime@example-ap
|
|
|
130
130
|
atdd-flow task done example-app runtime-rollout --by coordinator@example-app
|
|
131
131
|
```
|
|
132
132
|
|
|
133
|
-
Proof is a compact PR, CI run, report, commit range, deployment, or thread reference. Dependencies gate prerequisites; independent tasks are parallel-ready. A coordinator can staff an unassigned ready task with `atdd-flow task assign <project> <task-id> --assignee <address> --by <coordinator-address>`; assignment is allowed only once while the task is `todo`. Use `task block` only for a real external blocker, then checkpoint exact state and next action. Once the blocker is resolved, only that coordinator can clear it with `atdd-flow task unblock <project> <task-id> --by <coordinator-address>` while the task remains `in_progress`. For deliveries explicitly governed by the `workflow` ATDD Bun profile, `review → done` additionally requires a durable final behavioral-review result with decision `APPROVE` for the current clean delivery commit. For an idle driver’s final task, `task done ... --retire-assignee` delegates clean-and-merged worktree retirement to ATDD Bun. A driver whose assigned tasks are all already `done` is retired with `atdd-flow seat retire <address> --by <coordinator-or-main>`, using the same checks. When every assigned task is `done` and the recorded worktree is absent from disk and from `git worktree list`, `seat retire` records the retirement without running worktree finish, deleting the branch, or recreating the worktree; a missing worktree that Git still registers fails closed. Both paths fail closed on unfinished tasks or a dirty or unmerged worktree; on success they record `retired` and a checkpoint, then close the driver's Herdr workspace when `close_inactive` is enabled. `main@<project>` may likewise retire a coordinator seat (never main
|
|
133
|
+
Proof is a compact PR, CI run, report, commit range, deployment, or thread reference. Dependencies gate prerequisites; independent tasks are parallel-ready. A coordinator can staff an unassigned ready task with `atdd-flow task assign <project> <task-id> --assignee <address> --by <coordinator-address>`; assignment is allowed only once while the task is `todo`. Use `task block` only for a real external blocker, then checkpoint exact state and next action. Once the blocker is resolved, only that coordinator can clear it with `atdd-flow task unblock <project> <task-id> --by <coordinator-address>` while the task remains `in_progress`. For deliveries explicitly governed by the `workflow` ATDD Bun profile, `review → done` additionally requires a durable final behavioral-review result with decision `APPROVE` for the current clean delivery commit. For an idle driver’s final task, `task done ... --retire-assignee` delegates clean-and-merged worktree retirement to ATDD Bun. A driver whose assigned tasks are all already `done` is retired with `atdd-flow seat retire <address> --by <coordinator-or-main>`, using the same checks. When every assigned task is `done` and the recorded worktree is absent from disk and from `git worktree list`, `seat retire` records the retirement without running worktree finish, deleting the branch, or recreating the worktree; a missing worktree that Git still registers fails closed. Both paths fail closed on unfinished tasks or a dirty or unmerged worktree; on success they record `retired` and a checkpoint, then close the driver's Herdr workspace when `close_inactive` is enabled. `main@<project>` may likewise retire a coordinator seat (never main or the operator) once every task it coordinates or is assigned is `done`. A non-main coordinator sharing the primary checkout is retired as a Desk record without worktree finish; other coordinators use the same worktree-finish, absent-and-unregistered, and fail-closed paths. Retirement runs in the seat worktree with ATDD Bun from the primary checkout's `node_modules/.bin`, else the primary checkout's own source when it is the ATDD Bun package, else `PATH`; never the seat worktree's copy, which may pin an older toolkit.
|
|
134
134
|
|
|
135
135
|
At 80% context usage a seat writes a structured handover (template and process rules in the lifecycle convention), checks it with `atdd-flow handover <address> --check --file <path>`, and records it with `atdd-flow handover <address> --file <path>`. The seat keeps one durable `handover.yaml` beside its unchanged checkpoint. Recording rejects a missing header, Runtime line, or section, sections out of order, more than 150 lines, vague references such as `latest` or `that PR` without an exact ID, and a `supersedes` value that does not match the recorded handover id. A fresh session bound to the same seat reads it with `atdd-flow handover show <address>`.
|
|
136
136
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@afokapu/atdd-flow",
|
|
3
|
-
"version": "0.3.
|
|
3
|
+
"version": "0.3.66",
|
|
4
4
|
"description": "Filesystem-first Desk registry for projects, seats, tasks, threads, and handoffs.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -41,7 +41,7 @@
|
|
|
41
41
|
"bun": ">=1.3.0"
|
|
42
42
|
},
|
|
43
43
|
"devDependencies": {
|
|
44
|
-
"@afokapu/atdd-bun": "0.10.
|
|
44
|
+
"@afokapu/atdd-bun": "0.10.101"
|
|
45
45
|
},
|
|
46
46
|
"dependencies": {
|
|
47
47
|
"@typesafe-ai/sdk": "^0.6.0",
|
package/src/tasks.ts
CHANGED
|
@@ -242,7 +242,7 @@ async function retirementBun(root: string, projectName: string) {
|
|
|
242
242
|
return [required(Bun.which("atdd-bun") ?? undefined, "atdd-bun in the primary checkout node_modules/.bin or on PATH")];
|
|
243
243
|
}
|
|
244
244
|
|
|
245
|
-
async function retireDriver(root: string, projectName: string, assignee: string, id: string, allowAbsentWorktree = false) {
|
|
245
|
+
async function retireDriver(root: string, projectName: string, assignee: string, id: string, allowAbsentWorktree = false, allowPrimaryCheckout = false) {
|
|
246
246
|
const unfinished = (await allTasks(root, projectName))
|
|
247
247
|
.filter((entry) => entry.id !== id && (entry.task.assignee === assignee || entry.task.coordinator === assignee) && !terminal(entry.task))
|
|
248
248
|
.map((entry) => entry.id);
|
|
@@ -251,7 +251,10 @@ async function retireDriver(root: string, projectName: string, assignee: string,
|
|
|
251
251
|
const owner = await seat(root, assignee);
|
|
252
252
|
if (owner.retired) throw new Error(`Seat ${assignee} is already retired.`);
|
|
253
253
|
try {
|
|
254
|
-
const
|
|
254
|
+
const primary = (await project(root, projectName)).repository;
|
|
255
|
+
const primaryCheckout = allowPrimaryCheckout && primary && await canonicalPath(owner.worktree) === await canonicalPath(primary);
|
|
256
|
+
const summary = (primaryCheckout ? `Primary checkout ${owner.worktree} retained; retired without worktree finish.` : undefined)
|
|
257
|
+
?? (allowAbsentWorktree ? await absentUnregisteredWorktree(root, projectName, owner) : undefined)
|
|
255
258
|
?? await runOutput([...await retirementBun(root, projectName), "worktree", "finish", "--delete-branch", "--vcs", vcsMode(await project(root, projectName))], owner.worktree);
|
|
256
259
|
owner.retired = { task: `${projectName}/${id}`, completed_at: now(), summary };
|
|
257
260
|
await atomicYaml(paths(root).seatFile(assignee), owner);
|
|
@@ -276,18 +279,11 @@ async function retireDriver(root: string, projectName: string, assignee: string,
|
|
|
276
279
|
await closeRetiredDriverWorkspace(root, owner);
|
|
277
280
|
}
|
|
278
281
|
|
|
279
|
-
/**
|
|
280
|
-
* Only main retires a coordinator, and never one seated on the primary checkout; a driver may also be
|
|
281
|
-
* retired by the coordinator of every task assigned to it.
|
|
282
|
-
*/
|
|
282
|
+
/** Only main retires a coordinator; a driver may also be retired by the coordinator of every task assigned to it. */
|
|
283
283
|
async function assertRetireAuthority(root: string, owner: Seat, actor: string, owned: ListedTask[]) {
|
|
284
284
|
const main = `main@${owner.project}`;
|
|
285
285
|
if (owner.role === "coordinator") {
|
|
286
286
|
if (actor !== main) throw new Error(`Only ${main} may retire coordinator ${owner.address}.`);
|
|
287
|
-
const primary = (await project(root, owner.project)).repository;
|
|
288
|
-
if (primary && await canonicalPath(owner.worktree) === await canonicalPath(primary)) {
|
|
289
|
-
throw new Error(`Cannot retire ${owner.address}; its worktree is the primary checkout.`);
|
|
290
|
-
}
|
|
291
287
|
} else if (actor !== main && owned.some((entry) => entry.task.coordinator !== actor)) {
|
|
292
288
|
throw new Error(`Only ${main} or the coordinator of every task assigned to ${owner.address} may retire it.`);
|
|
293
289
|
}
|
|
@@ -295,7 +291,8 @@ async function assertRetireAuthority(root: string, owner: Seat, actor: string, o
|
|
|
295
291
|
|
|
296
292
|
/**
|
|
297
293
|
* Retires a driver whose assigned tasks are all terminal (done, superseded, or rejected), or, for main only, a coordinator
|
|
298
|
-
* (never main
|
|
294
|
+
* (never main) whose coordinated and assigned tasks are all terminal. A non-main coordinator on the
|
|
295
|
+
* primary checkout retires its record without invoking worktree finish.
|
|
299
296
|
*/
|
|
300
297
|
export async function retireSeat(root: string, address: string, args: string[]) {
|
|
301
298
|
const resolved = await canonicalAddress(root, address);
|
|
@@ -310,7 +307,7 @@ export async function retireSeat(root: string, address: string, args: string[])
|
|
|
310
307
|
const unfinished = owned.filter((entry) => !terminal(entry.task)).map((entry) => entry.id);
|
|
311
308
|
if (unfinished.length) throw new Error(`Cannot retire ${resolved}; it still owns unfinished tasks: ${unfinished.join(", ")}.`);
|
|
312
309
|
await assertRetireAuthority(root, owner, actor, owned);
|
|
313
|
-
await retireDriver(root, owner.project, resolved, owned.at(-1)!.id, true);
|
|
310
|
+
await retireDriver(root, owner.project, resolved, owned.at(-1)!.id, true, coordinator && resolved !== `main@${owner.project}`);
|
|
314
311
|
console.log(`${resolved} retired`);
|
|
315
312
|
}
|
|
316
313
|
|