@afokapu/atdd-flow 0.3.1 → 0.3.3

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 CHANGED
@@ -130,7 +130,7 @@ atdd-flow behavioral-review launch resolver-os runtime-rollout --by coordinator@
130
130
  atdd-flow task done resolver-os runtime-rollout --by coordinator@resolver-os
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. Use `task block` only for a real external blocker, then checkpoint exact state and next action. 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.
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. 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.
134
134
 
135
135
  ## Communicate and hand over
136
136
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@afokapu/atdd-flow",
3
- "version": "0.3.1",
3
+ "version": "0.3.3",
4
4
  "description": "Filesystem-first Desk registry for projects, seats, tasks, threads, and handoffs.",
5
5
  "type": "module",
6
6
  "bin": {
package/src/cli.ts CHANGED
@@ -19,7 +19,7 @@ Usage:
19
19
  atdd-flow desk migrate
20
20
  atdd-flow project init <project>
21
21
  atdd-flow spawn <project> <role> <name> [--worktree <path>] [--branch <branch>] [--agent <legacy-executable>]
22
- atdd-flow bind <address> [--application <application>] --address <native-address> [--agent <executable>] [--wake host|native]
22
+ atdd-flow bind <address> [--application <application>] --address <native-address> [--agent <executable>] [--worktree <path>] [--wake host|native]
23
23
  atdd-flow attach <address> [--application <application>] [--wake host|native]
24
24
  atdd-flow pi extension-path
25
25
  atdd-flow launch <address> --application <application> --placement <native-container-address>
@@ -27,6 +27,7 @@ Usage:
27
27
  atdd-flow describe <address> --purpose <one-line responsibility>
28
28
  atdd-flow checkpoint <address> --summary <text> --next <text> [--status active|standby|blocked|complete|unverified]
29
29
  atdd-flow task add <project> <task-id> --title <text> --coordinator <address> [--assignee <address>] [--body <text>] [--source <reference>] [--depends-on <task-id,...>] --done-when <text> [--done-when <text> ...]
30
+ atdd-flow task assign <project> <task-id> --assignee <address> --by <coordinator-address>
30
31
  atdd-flow task amend <project> <task-id> [--title <text>] [--body <text>] [--source <reference>] [--depends-on <task-id,...>]
31
32
  atdd-flow task import <project> <task-id> --proof <reference> [--proof <reference> ...] [--done-when <text> ...] [--source <reference>]
32
33
  atdd-flow task start|review|return <project> <task-id> --by <address>
@@ -88,6 +89,7 @@ async function main() {
88
89
  task: async () => {
89
90
  const [subcommand, projectName, taskId, ...tail] = rest;
90
91
  if (subcommand === "add") return tasks.add(root, required(projectName, "project"), required(taskId, "task id"), tail);
92
+ if (subcommand === "assign") return tasks.assign(root, required(projectName, "project"), required(taskId, "task id"), tail);
91
93
  if (subcommand === "amend") return tasks.amend(root, required(projectName, "project"), required(taskId, "task id"), tail);
92
94
  if (subcommand === "import") return tasks.importCompleted(root, required(projectName, "project"), required(taskId, "task id"), tail);
93
95
  if (subcommand === "start") return tasks.start(root, required(projectName, "project"), required(taskId, "task id"), tail);
@@ -98,7 +100,7 @@ async function main() {
98
100
  if (subcommand === "block") return tasks.block(root, required(projectName, "project"), required(taskId, "task id"), tail);
99
101
  if (subcommand === "list") return tasks.list(root, required(projectName, "project"), rest.slice(2));
100
102
  if (subcommand === "open") return tasks.open(root, required(projectName, "project"), required(taskId, "task id"));
101
- throw new Error("Use `atdd-flow task add|amend|import|start|prove|review|return|done|block|list|open`.");
103
+ throw new Error("Use `atdd-flow task add|assign|amend|import|start|prove|review|return|done|block|list|open`.");
102
104
  },
103
105
  thread: async () => {
104
106
  const [subcommand, ...tail] = rest;
package/src/seats.ts CHANGED
@@ -99,6 +99,7 @@ export async function bind(root: string, address: string, args: string[], select
99
99
  const config = await desk(root);
100
100
  const application = words(args, "--application") ?? config.application;
101
101
  const requestedAgent = words(args, "--agent");
102
+ const requestedWorktree = words(args, "--worktree");
102
103
  const requestedWake = words(args, "--wake");
103
104
  if (requestedWake && requestedWake !== "host" && requestedWake !== "native") throw new Error("Wake must be host or native.");
104
105
  const selectedWake = wake ?? requestedWake as Runtime["wake"] | undefined;
@@ -116,6 +117,11 @@ export async function bind(root: string, address: string, args: string[], select
116
117
  // Legacy Desks use this field as the executable chosen by a later `launch`.
117
118
  // Keep it aligned when an existing seat is deliberately re-homed to Pi.
118
119
  if (requestedAgent) record.agent = requestedAgent;
120
+ if (requestedWorktree) {
121
+ const worktree = resolve(requestedWorktree);
122
+ if (!existsSync(worktree)) throw new Error(`Worktree does not exist: ${worktree}`);
123
+ record.worktree = worktree;
124
+ }
119
125
  await atomicYaml(paths(root).seatFile(resolved), record);
120
126
  console.log(`Bound ${resolved} to ${application}:${nativeAddress}`);
121
127
  }
package/src/tasks.ts CHANGED
@@ -116,6 +116,19 @@ export async function add(root: string, projectName: string, id: string, args: s
116
116
  console.log(id);
117
117
  }
118
118
 
119
+ export async function assign(root: string, projectName: string, id: string, args: string[]) {
120
+ const task = await readTask(root, projectName, taskId(id));
121
+ const actor = await canonicalAddress(root, required(words(args, "--by"), "--by"));
122
+ if (actor !== task.coordinator) throw new Error(`Only ${task.coordinator} may assign task ${id}.`);
123
+ if (task.status !== "todo") throw new Error(`Task ${id} can only be assigned while todo.`);
124
+ if (task.assignee) throw new Error(`Task ${id} is already assigned to ${task.assignee}.`);
125
+ const assignee = await canonicalAddress(root, required(words(args, "--assignee"), "--assignee"));
126
+ await seat(root, assignee);
127
+ task.assignee = assignee;
128
+ await writeTask(root, projectName, id, task);
129
+ console.log(`${id} assigned ${assignee}`);
130
+ }
131
+
119
132
  export async function amend(root: string, projectName: string, id: string, args: string[]) {
120
133
  const task = await readTask(root, projectName, taskId(id));
121
134
  const title = words(args, "--title");