codebyplan 1.10.2 → 1.11.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/cli.js +719 -240
- package/package.json +1 -1
- package/templates/hooks/README.md +58 -16
- package/templates/hooks/cbp-statusline.mjs +385 -0
- package/templates/hooks/cbp-statusline.py +331 -0
- package/templates/hooks/cbp-statusline.sh +138 -82
- package/templates/hooks/cbp-subagent-statusline.mjs +200 -0
- package/templates/hooks/cbp-subagent-statusline.py +183 -0
- package/templates/hooks/cbp-subagent-statusline.sh +87 -39
- package/templates/skills/cbp-session-start/SKILL.md +38 -10
- package/templates/skills/cbp-session-start/qa-regression.md +51 -0
- package/templates/skills/cbp-todo/SKILL.md +77 -24
- package/templates/skills/cbp-todo/qa-regression.md +45 -0
|
@@ -7,47 +7,95 @@ effort: low
|
|
|
7
7
|
|
|
8
8
|
# Todo Command
|
|
9
9
|
|
|
10
|
-
Single
|
|
10
|
+
Single entry point after `/clear`: read the pure-read todo queue, gate on worktree ownership + checkpoint planning, load context, then trigger the next command. It ensures Claude always has full context — and never auto-routes into work locked to another worktree — before any command runs.
|
|
11
11
|
|
|
12
12
|
## Instructions
|
|
13
13
|
|
|
14
|
-
### Step 0: Resolve Caller
|
|
14
|
+
### Step 0: Resolve Caller Identity (worktree + user)
|
|
15
15
|
|
|
16
|
-
Before any MCP call,
|
|
16
|
+
Before any MCP call, resolve who and where the caller is.
|
|
17
|
+
|
|
18
|
+
**Worktree** — derive the caller `worktree_id` and any distress signal in one structured read:
|
|
17
19
|
|
|
18
20
|
```bash
|
|
19
|
-
|
|
21
|
+
npx codebyplan resolve-worktree --json # → {"worktree_id":"<uuid>|null","error_kind":null|"<kind>"}
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
- `error_kind` is `null` or `"tuple_miss"` → healthy. `WORKTREE_ID` = `worktree_id` (may be `null`: a legitimate main-repo or unregistered-worktree case — proceed to read the queue, but downstream hard-locks reject mutations on assigned rows).
|
|
25
|
+
- `error_kind` is `local_config_read_failed`, `local_config_write_failed`, `legacy_file_blocks_dir`, `api_failed`, `git_failed`, or `unhandled` → **broken local state**. Surface the distress line and STOP (skip Steps 1–4) — routing is unreliable when the resolver cannot read local state:
|
|
26
|
+
|
|
27
|
+
```
|
|
28
|
+
⚠ resolve-worktree: <error_kind> — local state is broken; routing is unreliable.
|
|
29
|
+
Run `npx codebyplan setup` from this directory to register/repair, then re-run /cbp-todo.
|
|
20
30
|
```
|
|
21
31
|
|
|
22
|
-
|
|
23
|
-
|
|
32
|
+
**User** — `get_todos` (Step 1) requires a `user_id`:
|
|
33
|
+
|
|
34
|
+
```bash
|
|
35
|
+
npx codebyplan whoami --json # → {"user_id":"<uuid>","email":"…"} or null
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
- A `user_id` is returned → use it in Step 1.
|
|
39
|
+
- `null` (CLI keychain empty — common in OAuth-MCP-only environments) → the queue cannot be scoped by user; skip Step 1 and use the Step 3 fallback. The Step 1.5 ownership gate still applies.
|
|
40
|
+
|
|
41
|
+
### Step 1: Read the Todo Queue (pure-read)
|
|
42
|
+
|
|
43
|
+
With `USER_ID` resolved, call MCP `get_todos({ repo_id, user_id, worktree_id })` (omit `worktree_id` when `WORKTREE_ID` is `null` or unresolved — that returns only unscoped rows). Take **`rows[0]`** as the queue head (ordered by `sort_order`).
|
|
24
44
|
|
|
25
|
-
|
|
45
|
+
- The head carries `command`, `instructions`, `state`, `metadata`, `worktree_id`, `checkpoint_id`, `task_id`.
|
|
46
|
+
- The routing context (checkpoint/task) lives in **`rows[0].metadata`**.
|
|
47
|
+
- `get_todos` is **pure-read** — `apps/todo-worker` is the sole regen authority. NEVER call `get_next_action` or `regenerate_todos_for_repo`.
|
|
48
|
+
- Empty array, or `USER_ID` unavailable → go to Step 3 (empty-queue fallback).
|
|
26
49
|
|
|
27
|
-
|
|
50
|
+
Queue `command` values may use the `/codebyplan:<name>` plugin-namespace form (e.g. `/codebyplan:round-start`); treat each as the matching `/cbp-<name>` skill for the Step 2 matrix.
|
|
28
51
|
|
|
29
|
-
### Step 1.5:
|
|
52
|
+
### Step 1.5: Resolve Target + Worktree-Ownership Gate
|
|
30
53
|
|
|
31
|
-
|
|
54
|
+
Resolve the routing target's checkpoint and gate on ownership BEFORE any auto-trigger — including the Step 1.6 planning hand-offs. Refuse to route into, plan, or start work locked to a different worktree.
|
|
32
55
|
|
|
33
|
-
|
|
56
|
+
Resolve the checkpoint from `rows[0].metadata` (or MCP `get_current_task`), then load its `worktree_id` + `plan` + `status` via MCP `get_checkpoints` and its task count via MCP `get_tasks(checkpoint_id)`. This single load is reused by the Step 1.6 planning gate. Skip this gate when the routing target has no checkpoint (idle — see Step 3) or the command is `/cbp-session-start`.
|
|
34
57
|
|
|
35
|
-
|
|
36
|
-
- **RULE B — planned-but-pending**: has tasks (or non-empty `plan.steps[]`) **BUT** `status === "pending"` (not yet activated) → the checkpoint is planned but not started. Suppress the Step-1 command; surface `Now starting CHK-NNN… handing off to /cbp-checkpoint-start` and auto-trigger `/cbp-checkpoint-start {NNN}` (a planned checkpoint must be started + claimed before task work).
|
|
37
|
-
- **Neither** (planned AND `active`) → fall through to Step 2 unchanged. No regression to the existing flow.
|
|
58
|
+
Two ownership signals:
|
|
38
59
|
|
|
39
|
-
|
|
60
|
+
1. **Server-detected conflict** — `rows[0].state === "worktree_conflict"` (command `/codebyplan:release-or-switch`): the todo-worker already detected the lock conflict. The owner is in `rows[0].metadata.conflicting_worktree_name` / `.conflicting_worktree_id`. Surface the mismatch message below and **STOP**. Do NOT auto-trigger the release-or-switch command and do NOT call `release_assignment` — switch worktrees rather than reassigning a lock to the caller.
|
|
61
|
+
2. **Checkpoint-ownership check** — take the target checkpoint's `worktree_id` (loaded above, keyed by `rows[0].checkpoint_id` / `metadata.checkpoint.id`) and compare with caller `WORKTREE_ID`:
|
|
62
|
+
- target `worktree_id` is `null` → **allow** (unassigned — any worktree may pick it up; covers the both-null main-repo case).
|
|
63
|
+
- target `worktree_id` === caller `WORKTREE_ID` → **allow**.
|
|
64
|
+
- target `worktree_id` non-null **AND** caller `WORKTREE_ID` is `null`/unresolved → **block** (deliberate safety: identity cannot be confirmed. This does not contradict Step 0 — reading the queue is fine, auto-triggering INTO assigned work is not. Run `npx codebyplan setup` to register this worktree).
|
|
65
|
+
- target `worktree_id` non-null and differs from a non-null caller → **block**.
|
|
66
|
+
|
|
67
|
+
On block, resolve the owning worktree's `name` + `path` via MCP `get_worktrees({ repo_id })` (match by id), then emit and STOP:
|
|
68
|
+
|
|
69
|
+
```
|
|
70
|
+
⚠ Work mismatch: CHK-<NNN> TASK-<N> is assigned to worktree <name> (<short-uuid>), not this one (<this-name> / <this-short-uuid>).
|
|
71
|
+
Options:
|
|
72
|
+
A) Switch to <owning-worktree-path> and resume there
|
|
73
|
+
B) Work on something else here — run /cbp-checkpoint-create or /cbp-task-create
|
|
74
|
+
C) /cbp-session-end
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
`<short-uuid>` = first 8 chars of the worktree UUID. Caller unresolved → render "this one" as `(unresolved / —)`. Name lookup miss → show the UUID alone. Wait for the user. NEVER propose reassigning the checkpoint to the caller worktree.
|
|
78
|
+
|
|
79
|
+
### Step 1.6: Checkpoint Planning Gate
|
|
80
|
+
|
|
81
|
+
Ownership passed (Step 1.5). Now gate on the checkpoint's planning + activation state — reusing the `plan` + `status` + task count loaded in Step 1.5 — so work never starts on a half-baked or un-activated checkpoint. Evaluate two rules in order (Rule A wins if both could match):
|
|
82
|
+
|
|
83
|
+
- **RULE A — unplanned**: empty `plan.steps[]` **AND** zero tasks → not planned. Suppress the head command; surface `Now planning CHK-NNN… handing off to /cbp-checkpoint-plan` and auto-trigger `/cbp-checkpoint-plan {NNN}`.
|
|
84
|
+
- **RULE B — planned-but-pending**: has tasks (or non-empty `plan.steps[]`) **BUT** `status === "pending"` (not yet activated) → planned, not started. Suppress the head command; surface `Now starting CHK-NNN… handing off to /cbp-checkpoint-start` and auto-trigger `/cbp-checkpoint-start {NNN}` (a planned checkpoint must be started + claimed before task work).
|
|
85
|
+
- **Neither** (planned AND `active`) → fall through to Step 2.
|
|
86
|
+
|
|
87
|
+
Skip this gate when the routing target has no checkpoint (idle — see Step 3) or the command is `/cbp-session-start`.
|
|
40
88
|
|
|
41
89
|
### Step 2: Load Context Based on Command
|
|
42
90
|
|
|
43
|
-
|
|
91
|
+
Once the gates pass, load the context the head command needs. This ensures `/clear` + `/cbp-todo` reliably restores full working context.
|
|
44
92
|
|
|
45
|
-
**Use the context loading matrix below.** Match the `command`
|
|
93
|
+
**Use the context loading matrix below.** Match the `command` (in its `/cbp-<name>` form) to determine what to load.
|
|
46
94
|
|
|
47
95
|
| Command Pattern | Context to Load |
|
|
48
96
|
|----------------|-----------------|
|
|
49
97
|
| `/cbp-session-start` | None — `/cbp-session-start` handles its own loading |
|
|
50
|
-
| `/cbp-checkpoint-create` | If checkpoint exists in
|
|
98
|
+
| `/cbp-checkpoint-create` | If checkpoint exists in `rows[0].metadata`: load checkpoint via MCP `get_checkpoints` (filter by number). Display checkpoint title, goal, ideas summary |
|
|
51
99
|
| `/cbp-checkpoint-plan` | Load checkpoint via MCP `get_checkpoints` (filter by number) + `get_tasks(checkpoint_id)`. Display checkpoint title, goal, ideas, existing task count |
|
|
52
100
|
| `/cbp-checkpoint-start` | Load checkpoint via MCP `get_checkpoints` + `get_tasks(checkpoint_id)`. Display checkpoint title, status, claim state, first pending task |
|
|
53
101
|
| `/cbp-task-start [N]` | Load via MCP `get_current_task`. Display checkpoint title + task title/requirements summary |
|
|
@@ -87,9 +135,13 @@ Display a brief context summary:
|
|
|
87
135
|
[Brief: what was done, what passed/failed]
|
|
88
136
|
```
|
|
89
137
|
|
|
90
|
-
### Step 3:
|
|
138
|
+
### Step 3: Empty Queue — Fallback, then Idle
|
|
139
|
+
|
|
140
|
+
Reached when `get_todos` returns `[]` or `USER_ID` was unavailable.
|
|
91
141
|
|
|
92
|
-
|
|
142
|
+
1. **Fallback discovery** (worktree-scoped): MCP `get_current_task({ repo_id, worktree_id })` and `get_checkpoints({ repo_id, worktree_id, status: 'active' })` to discover whether actionable work exists for this caller.
|
|
143
|
+
2. **Actionable work found** → treat the discovered checkpoint as the routing target and apply BOTH the Step 1.5 ownership gate and the Step 1.6 planning gate to it, using the `worktree_id` + `plan` + `status` returned by `get_checkpoints` (the fallback has no `rows[0]` — substitute the discovered checkpoint). If both gates pass, route via Step 2 → Step 4.
|
|
144
|
+
3. **Nothing actionable** → suggest ending the session:
|
|
93
145
|
|
|
94
146
|
```
|
|
95
147
|
No work remaining in the current checkpoint.
|
|
@@ -98,14 +150,15 @@ Run `/cbp-session-end` to finalize the session log and close out.
|
|
|
98
150
|
Or run `/cbp-checkpoint-create` to start new work.
|
|
99
151
|
```
|
|
100
152
|
|
|
101
|
-
Wait for the user. Do not auto-trigger `/cbp-session-end` — session wrap-up is a user-driven decision.
|
|
153
|
+
Wait for the user. Do not auto-trigger `/cbp-session-end` — session wrap-up is a user-driven decision. NEVER call `regenerate_todos_for_repo`; an empty queue is a legitimate "nothing scheduled" state (the todo-worker has not regenerated yet, or there is no actionable work).
|
|
102
154
|
|
|
103
155
|
### Step 4: Display and Auto-trigger
|
|
104
156
|
|
|
105
|
-
|
|
157
|
+
Reached only when the Step 1.5 ownership gate allowed routing to continue and the Step 1.6 planning gate fell through (no hand-off). Show `rows[0].instructions` (so the user sees what is happening), then auto-trigger `rows[0].command` (its `/cbp-<name>` form).
|
|
106
158
|
|
|
107
159
|
## Integration
|
|
108
160
|
|
|
109
161
|
- **Called by**: `/cbp-session-start`, `/cbp-task-complete`, `/cbp-checkpoint-complete`, manual, after `/clear`
|
|
110
|
-
- **
|
|
111
|
-
- **
|
|
162
|
+
- **Resolves**: `npx codebyplan resolve-worktree --json` (worktree id + distress signal), `npx codebyplan whoami --json` (user id)
|
|
163
|
+
- **Reads**: MCP `get_todos`, `get_current_task`, `get_rounds`, `get_checkpoints`, `get_tasks`, `get_worktrees`
|
|
164
|
+
- **Triggers**: `rows[0].command` (auto, after the Step 1.5 ownership gate); Step 1.6 overrides to `/cbp-checkpoint-plan` (unplanned) or `/cbp-checkpoint-start` (planned-but-pending)
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
---
|
|
2
|
+
scope: org-shared
|
|
3
|
+
name: cbp-todo-qa-regression
|
|
4
|
+
description: Manual regression procedure for the cbp-todo worktree-ownership gate + get_todos switch (CHK-137 TASK-2)
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
# cbp-todo — Worktree-Ownership Regression
|
|
8
|
+
|
|
9
|
+
Manual procedure verifying that `/cbp-todo` reads the pure-read `get_todos` queue and refuses to auto-route into work locked to another worktree. No automated harness exists for markdown skills; run these by hand (or read the queue with the MCP tools) whenever Step 0/1/1.5 of `SKILL.md` changes.
|
|
10
|
+
|
|
11
|
+
Repo under test: `2ff6d405-39c5-47b8-a6d1-59f998ac0537`. Resolve a real `user_id` with `npx codebyplan whoami --json`, or harvest a non-null `assigned_user_id` from `get_checkpoints`.
|
|
12
|
+
|
|
13
|
+
## Preconditions
|
|
14
|
+
|
|
15
|
+
- `get_todos` is the only Step 1 read — confirm no `get_next_action` / `regenerate_todos_for_repo` call remains (`grep -n 'get_next_action\|regenerate_todos_for_repo' SKILL.md` → no hits).
|
|
16
|
+
- Step 0 uses `resolve-worktree --json` and `whoami --json`.
|
|
17
|
+
|
|
18
|
+
## Scenario A — caller owns the work → auto-trigger
|
|
19
|
+
|
|
20
|
+
1. From a worktree that owns the active checkpoint (caller `WORKTREE_ID` === target checkpoint `worktree_id`, or target `worktree_id` is `null`).
|
|
21
|
+
2. `get_todos({ repo_id, user_id, worktree_id })` returns a head whose target checkpoint is owned by the caller (or unscoped).
|
|
22
|
+
3. **Expected**: Step 1.5 ownership gate allows, Step 1.6 planning gate falls through, Step 4 auto-triggers `rows[0].command` (mapped to its `/cbp-<name>` form).
|
|
23
|
+
|
|
24
|
+
## Scenario B1 — server-generated conflict head → halt
|
|
25
|
+
|
|
26
|
+
1. Caller `codebyplan-claude-2` (`38cd7dfa`). Active work assigned to `codebyplan-cli` (`016bd7f2`).
|
|
27
|
+
2. `get_todos` head is the server conflict todo: `state === "worktree_conflict"`, `command "/codebyplan:release-or-switch"`, `metadata.conflicting_worktree_name === "codebyplan-cli"`.
|
|
28
|
+
3. **MCP calls expected**: `get_todos`; `get_worktrees` (to resolve `016bd7f2` path for the message). NO `get_checkpoints` needed — the server already resolved the conflict.
|
|
29
|
+
4. **Expected**: Step 1.5 server-conflict branch blocks and STOPS. The "Work mismatch" message names `codebyplan-cli (016bd7f2)` vs `codebyplan-claude-2 (38cd7dfa)`, offers Switch (`/Users/merilyviks/codebyplan-cli`) / other-work / session-end. NO auto-trigger; NO `release_assignment` call (never reassign the lock to the caller).
|
|
30
|
+
|
|
31
|
+
## Scenario B2 — normal head, mismatched checkpoint owner → halt
|
|
32
|
+
|
|
33
|
+
1. Caller `codebyplan-claude-2` (`38cd7dfa`). `get_todos` head is a normal routing todo whose target checkpoint `worktree_id` is `016bd7f2`.
|
|
34
|
+
2. **MCP calls expected**: `get_todos`; `get_checkpoints` (Step 1.5 load, reads the target `worktree_id`); `get_worktrees` (resolve `016bd7f2` name + path).
|
|
35
|
+
3. **Expected**: Step 1.5 checkpoint-ownership branch blocks and STOPS with the same "Work mismatch" message. NO auto-trigger; the Step 1.6 planning gate never runs (ownership precedes it).
|
|
36
|
+
|
|
37
|
+
## Scenario C — empty queue + cross-worktree current task → halt
|
|
38
|
+
|
|
39
|
+
1. `get_todos` returns `[]` (or `whoami` returned `null`, so Step 1 was skipped).
|
|
40
|
+
2. Step 3 fallback: `get_current_task({ repo_id, worktree_id })` / `get_checkpoints({ repo_id, worktree_id, status: 'active' })` surface a checkpoint whose `worktree_id` differs from the caller.
|
|
41
|
+
3. **Expected**: the Step 1.5 ownership gate (applied to the fallback target) blocks the discovered work with the same "Work mismatch" message. NO auto-trigger. `regenerate_todos_for_repo` is never called.
|
|
42
|
+
|
|
43
|
+
## Edge — both null
|
|
44
|
+
|
|
45
|
+
Caller `WORKTREE_ID` empty AND target checkpoint `worktree_id` `null` → legitimate main-repo / unassigned work → auto-trigger allowed.
|