codebyplan 1.13.61 → 1.13.63
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 +1140 -2065
- package/package.json +1 -1
- package/templates/agents/cbp-e2e-maestro.md +1 -1
- package/templates/agents/cbp-e2e-playwright.md +11 -11
- package/templates/agents/cbp-e2e-tauri.md +1 -1
- package/templates/agents/cbp-e2e-vscode.md +1 -1
- package/templates/agents/cbp-e2e-xcuitest.md +1 -1
- package/templates/hooks/cbp-mcp-round-sync.sh +4 -15
- package/templates/hooks/cbp-test-hooks.sh +0 -81
- package/templates/hooks/hooks.json +0 -9
- package/templates/rules/cbp-operating-gotchas.md +8 -10
- package/templates/rules/effort-and-ultracode.md +70 -0
- package/templates/rules/model-invocation-convention.md +1 -0
- package/templates/rules/supabase-branch-lifecycle.md +2 -2
- package/templates/rules/todo-backend.md +11 -8
- package/templates/rules/workflow-orchestration.md +59 -0
- package/templates/settings.project.base.json +0 -5
- package/templates/skills/cbp-build-cc-agent/SKILL.md +1 -0
- package/templates/skills/cbp-build-cc-claude-file/SKILL.md +1 -0
- package/templates/skills/cbp-build-cc-mode/SKILL.md +25 -17
- package/templates/skills/cbp-build-cc-rule/SKILL.md +1 -0
- package/templates/skills/cbp-build-cc-settings/SKILL.md +1 -0
- package/templates/skills/cbp-build-cc-settings/reference/cbp-permission-policy.md +1 -1
- package/templates/skills/cbp-build-cc-settings/reference/settings-fields.md +1 -1
- package/templates/skills/cbp-build-cc-skill/SKILL.md +2 -1
- package/templates/skills/cbp-build-cc-skill/reference/frontmatter-fields.md +1 -1
- package/templates/skills/cbp-build-cc-skill/scripts/validate-skill.sh +12 -9
- package/templates/skills/cbp-checkpoint-check/SKILL.md +5 -0
- package/templates/skills/cbp-checkpoint-complete/SKILL.md +1 -0
- package/templates/skills/cbp-checkpoint-create/SKILL.md +13 -22
- package/templates/skills/cbp-checkpoint-end/SKILL.md +42 -0
- package/templates/skills/cbp-checkpoint-plan/SKILL.md +15 -8
- package/templates/skills/cbp-checkpoint-start/SKILL.md +28 -19
- package/templates/skills/cbp-checkpoint-update/SKILL.md +3 -2
- package/templates/skills/cbp-clear-continue/SKILL.md +2 -1
- package/templates/skills/cbp-clear-prep/SKILL.md +2 -1
- package/templates/skills/cbp-finalize/SKILL.md +3 -2
- package/templates/skills/cbp-frontend-design/SKILL.md +1 -0
- package/templates/skills/cbp-frontend-ui/SKILL.md +2 -1
- package/templates/skills/cbp-frontend-ux/SKILL.md +2 -1
- package/templates/skills/cbp-git-branch-feat-create/SKILL.md +1 -0
- package/templates/skills/cbp-git-commit/SKILL.md +1 -0
- package/templates/skills/cbp-map-architecture/SKILL.md +5 -0
- package/templates/skills/cbp-merge-main/SKILL.md +1 -0
- package/templates/skills/cbp-refresh-arch-map/SKILL.md +1 -0
- package/templates/skills/cbp-round-build/SKILL.md +5 -0
- package/templates/skills/cbp-round-complete/SKILL.md +4 -24
- package/templates/skills/cbp-round-plan/SKILL.md +6 -1
- package/templates/skills/cbp-session-end/SKILL.md +42 -31
- package/templates/skills/cbp-session-start/SKILL.md +8 -7
- package/templates/skills/cbp-session-start/qa-regression.md +32 -25
- package/templates/skills/cbp-setup-cd/SKILL.md +2 -1
- package/templates/skills/cbp-setup-ci/SKILL.md +2 -1
- package/templates/skills/cbp-setup-e2e/SKILL.md +2 -1
- package/templates/skills/cbp-setup-eslint/SKILL.md +2 -1
- package/templates/skills/cbp-ship/SKILL.md +5 -0
- package/templates/skills/cbp-ship-configure/SKILL.md +2 -1
- package/templates/skills/cbp-ship-main/SKILL.md +1 -0
- package/templates/skills/cbp-standalone-task-check/SKILL.md +1 -0
- package/templates/skills/cbp-standalone-task-complete/SKILL.md +3 -5
- package/templates/skills/cbp-standalone-task-create/SKILL.md +7 -14
- package/templates/skills/cbp-standalone-task-start/SKILL.md +12 -11
- package/templates/skills/cbp-standalone-task-testing/SKILL.md +2 -1
- package/templates/skills/cbp-stripe/SKILL.md +2 -1
- package/templates/skills/cbp-supabase-branch-check/SKILL.md +2 -1
- package/templates/skills/cbp-supabase-migrate/SKILL.md +1 -0
- package/templates/skills/cbp-supabase-setup/SKILL.md +2 -1
- package/templates/skills/cbp-task-create/SKILL.md +3 -2
- package/templates/skills/cbp-task-start/SKILL.md +11 -10
- package/templates/skills/cbp-todo/SKILL.md +25 -39
- package/templates/skills/cbp-todo/qa-regression.md +21 -27
- package/templates/skills/cbp-verify/SKILL.md +5 -0
- package/templates/skills/cbp-verify/reference/round-scope.md +1 -2
- package/templates/skills/supabase/SKILL.md +2 -0
- package/templates/skills/supabase-postgres-best-practices/SKILL.md +2 -0
- package/templates/hooks/cbp-mcp-caller-worktree-inject.sh +0 -78
|
@@ -3,6 +3,7 @@ scope: repo-only:codebyplan
|
|
|
3
3
|
name: cbp-standalone-task-complete
|
|
4
4
|
description: Complete a standalone task — ship feat branch to production via PR and mark done
|
|
5
5
|
argument-hint: [task] # e.g. `45` (standalone TASK-45)
|
|
6
|
+
model: inherit
|
|
6
7
|
effort: xhigh
|
|
7
8
|
---
|
|
8
9
|
|
|
@@ -10,7 +11,7 @@ effort: xhigh
|
|
|
10
11
|
|
|
11
12
|
Complete a standalone task. Auto-triggered by `/cbp-standalone-task-testing` when all tests pass. Can also be run manually.
|
|
12
13
|
|
|
13
|
-
This skill is gated by an `ask`-tier `Skill(cbp-standalone-task-complete)` permission rule in `settings.json` (shipped templates). **The permission prompt IS the user confirmation** — there is NO completion-confirmation AskUserQuestion inside this skill
|
|
14
|
+
This skill is gated by an `ask`-tier `Skill(cbp-standalone-task-complete)` permission rule in `settings.json` (shipped templates). **The permission prompt IS the user confirmation** — there is NO completion-confirmation AskUserQuestion inside this skill. A declined permission is a clean no-op (nothing committed, merged, pushed, or completed).
|
|
14
15
|
|
|
15
16
|
## Instructions
|
|
16
17
|
|
|
@@ -226,9 +227,7 @@ Complete via the CLI (wraps the `complete_standalone_task` MCP tool):
|
|
|
226
227
|
codebyplan standalone-task complete --id <standalone_task.id>
|
|
227
228
|
```
|
|
228
229
|
|
|
229
|
-
The
|
|
230
|
-
|
|
231
|
-
If the CLI exits 1 with a "could not resolve caller_worktree_id" message, run `npx codebyplan setup` (or `codebyplan resolve-worktree --cache`) from this worktree, then re-run the command.
|
|
230
|
+
The server keys on the JWT user (`ctx.userId`) — no worktree param is needed. The server auto-clears `assigned_user_id` on the task on success.
|
|
232
231
|
|
|
233
232
|
### Step 8: Run Cleanup + Migration (inline)
|
|
234
233
|
|
|
@@ -265,7 +264,6 @@ Do NOT use AskUserQuestion for routing. Do NOT use the Skill tool to auto-trigge
|
|
|
265
264
|
|
|
266
265
|
## Key Rules
|
|
267
266
|
|
|
268
|
-
- **`caller_worktree_id` is REQUIRED** for `complete_standalone_task`
|
|
269
267
|
- **Branch shipping lives here** (not in checkpoint-end) — standalone tasks self-ship to production via `codebyplan ship`
|
|
270
268
|
- **Single-directive routing** — no menus, no auto-triggers via Skill tool
|
|
271
269
|
- **No checkpoint** — never check `checkpoint_id`, always treat task as standalone
|
|
@@ -2,7 +2,8 @@
|
|
|
2
2
|
scope: repo-only:codebyplan
|
|
3
3
|
name: cbp-standalone-task-create
|
|
4
4
|
description: Creates a standalone task (not checkpoint-bound) via create_standalone_task MCP tool
|
|
5
|
-
|
|
5
|
+
model: inherit
|
|
6
|
+
effort: high
|
|
6
7
|
---
|
|
7
8
|
|
|
8
9
|
# Standalone Task Create Command
|
|
@@ -87,28 +88,20 @@ To create the best task definition, I need to clarify:
|
|
|
87
88
|
|
|
88
89
|
Skip if requirements are already clear from Step 1.
|
|
89
90
|
|
|
90
|
-
### Step 6:
|
|
91
|
+
### Step 6: Create Standalone Task
|
|
91
92
|
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
- If non-empty: pass as `assigned_worktree_id` in Step 7. This engages the hard-lock from creation.
|
|
95
|
-
- If empty: warn the user that the task will be unassigned and offer to run `npx codebyplan setup` from the current directory first. After setup, re-resolve and proceed. If the user declines, create without `assigned_worktree_id`.
|
|
96
|
-
|
|
97
|
-
### Step 7: Create Standalone Task
|
|
98
|
-
|
|
99
|
-
Create via the CLI (wraps the `create_standalone_task` MCP tool; auto-resolves `caller_worktree_id`):
|
|
93
|
+
Create via the CLI (wraps the `create_standalone_task` MCP tool):
|
|
100
94
|
|
|
101
95
|
```bash
|
|
102
96
|
codebyplan standalone-task create \
|
|
103
97
|
--title "<concise task title>" \
|
|
104
98
|
--number <next number from Step 3> \
|
|
105
99
|
--requirements "<numbered requirements list>" \
|
|
106
|
-
--context '<JSON: decisions from Q&A + source findings>'
|
|
107
|
-
--assigned-worktree-id <from Step 6, if resolved>
|
|
100
|
+
--context '<JSON: decisions from Q&A + source findings>'
|
|
108
101
|
```
|
|
109
102
|
|
|
110
103
|
- `--repo-id` is optional — the CLI reads it from `.codebyplan/repo.json`.
|
|
111
|
-
-
|
|
104
|
+
- Task assignment is user-based — the server stamps `assigned_user_id` from the JWT on creation; no worktree param is needed.
|
|
112
105
|
- On success the CLI prints the created row JSON (including `.id`) to stdout.
|
|
113
106
|
|
|
114
107
|
```
|
|
@@ -126,7 +119,7 @@ codebyplan standalone-task create \
|
|
|
126
119
|
- Files likely touched: [relevant paths]
|
|
127
120
|
```
|
|
128
121
|
|
|
129
|
-
### Step
|
|
122
|
+
### Step 7: Route
|
|
130
123
|
|
|
131
124
|
```
|
|
132
125
|
Standalone TASK-[N] created successfully.
|
|
@@ -3,7 +3,8 @@ scope: repo-only:codebyplan
|
|
|
3
3
|
name: cbp-standalone-task-start
|
|
4
4
|
description: Start a standalone task, load context from DB
|
|
5
5
|
argument-hint: [task] # e.g. `45` (standalone TASK-45)
|
|
6
|
-
|
|
6
|
+
model: inherit
|
|
7
|
+
effort: high
|
|
7
8
|
---
|
|
8
9
|
|
|
9
10
|
# Standalone Task Start Command
|
|
@@ -105,20 +106,20 @@ If `current` is still in `branch_config.protected`, block with a hard error citi
|
|
|
105
106
|
1. Run `git status --short` to check for uncommitted files.
|
|
106
107
|
2. If uncommitted files exist → commit them with `chore: clean slate for task start`. Prefer `git add -A && git commit -m "..."`.
|
|
107
108
|
|
|
108
|
-
### Step 3.5:
|
|
109
|
+
### Step 3.5: User-Match Verification
|
|
109
110
|
|
|
110
|
-
Before activating, verify the
|
|
111
|
+
Before activating, verify the current user is allowed to claim/edit the standalone task row.
|
|
111
112
|
|
|
112
|
-
1. `
|
|
113
|
-
2. `
|
|
114
|
-
3. If `
|
|
113
|
+
1. Resolve the current user: `CURRENT_USER=$(npx codebyplan whoami --json 2>/dev/null)` → parse `user_id` and `email` from the JSON. If the command fails or returns null/empty, `CURRENT_USER_ID` is null (anonymous session).
|
|
114
|
+
2. `TARGET_USER = task.assigned_user_id`.
|
|
115
|
+
3. If `TARGET_USER IS NOT NULL AND TARGET_USER != CURRENT_USER_ID`, surface error and abort:
|
|
115
116
|
|
|
116
117
|
```
|
|
117
|
-
Standalone TASK-N is assigned to
|
|
118
|
-
Use the release_assignment MCP tool (requires maintainer role) if
|
|
118
|
+
Standalone TASK-N is assigned to user {TARGET_EMAIL} ({TARGET_USER}); you are logged in as {CURRENT_EMAIL} ({CURRENT_USER_ID}).
|
|
119
|
+
Use the release_assignment MCP tool (requires maintainer role) if that user is no longer active, then re-run /cbp-standalone-task-start.
|
|
119
120
|
```
|
|
120
121
|
|
|
121
|
-
4. If `
|
|
122
|
+
4. If `TARGET_USER IS NULL` or matches `CURRENT_USER_ID`, proceed.
|
|
122
123
|
|
|
123
124
|
### Step 3.6: Main-Drift Check (optional)
|
|
124
125
|
|
|
@@ -149,13 +150,13 @@ Load context from DB:
|
|
|
149
150
|
|
|
150
151
|
### Step 5: Set Task Status
|
|
151
152
|
|
|
152
|
-
Set status via the CLI (wraps `update_standalone_task
|
|
153
|
+
Set status via the CLI (wraps `update_standalone_task`):
|
|
153
154
|
|
|
154
155
|
```bash
|
|
155
156
|
codebyplan standalone-task update --id <task.id> --status in_progress
|
|
156
157
|
```
|
|
157
158
|
|
|
158
|
-
`--id` is the standalone task UUID resolved in Step 2. The
|
|
159
|
+
`--id` is the standalone task UUID resolved in Step 2. The server keys on the JWT user for authz — no worktree or caller params are needed or accepted; all worktree-identity flags are deprecated and silently ignored server-side.
|
|
159
160
|
|
|
160
161
|
### Step 6: Auto-trigger Round Start
|
|
161
162
|
|
|
@@ -4,7 +4,8 @@ name: cbp-standalone-task-testing
|
|
|
4
4
|
description: Run comprehensive task-level testing after /cbp-standalone-task-check passes
|
|
5
5
|
argument-hint: [task] # e.g. `45` (standalone TASK-45)
|
|
6
6
|
triggers: [cbp-standalone-task-complete]
|
|
7
|
-
|
|
7
|
+
model: inherit
|
|
8
|
+
effort: high
|
|
8
9
|
---
|
|
9
10
|
|
|
10
11
|
# Standalone Task Testing Command
|
|
@@ -2,7 +2,8 @@
|
|
|
2
2
|
scope: org-shared
|
|
3
3
|
name: cbp-stripe
|
|
4
4
|
description: "Stripe integration guidance — load when implementing or reviewing payments, Checkout, subscriptions/billing, webhooks, Connect, Tax, or Treasury. Encodes the API-selection routing table, the no-payment_method_types rule, restricted-key security, and Stripe SDK conventions."
|
|
5
|
-
|
|
5
|
+
model: inherit
|
|
6
|
+
effort: high
|
|
6
7
|
---
|
|
7
8
|
|
|
8
9
|
# Stripe Integration (CBP)
|
|
@@ -3,7 +3,8 @@ name: cbp-supabase-branch-check
|
|
|
3
3
|
description: Gate skill called by /cbp-ship-main (pre-merge) to verify the Supabase preview branch health check is green before allowing a PR to be merged; skips when no DB-path changes are detected.
|
|
4
4
|
argument-hint: "[--mode pre_pr_create|pre_merge] [--target integration|production]"
|
|
5
5
|
allowed-tools: Bash(git *), Bash(gh *), Bash(jq *), Bash(supabase *), Bash(sleep *), Bash(echo *), Read, mcp__supabase__list_branches, mcp__supabase__get_logs
|
|
6
|
-
|
|
6
|
+
model: inherit
|
|
7
|
+
effort: high
|
|
7
8
|
---
|
|
8
9
|
|
|
9
10
|
# Supabase Branch Check
|
|
@@ -3,6 +3,7 @@ name: cbp-supabase-migrate
|
|
|
3
3
|
description: Scaffold or adopt a Supabase migration for the current PR branch, apply to the branch's preview DB, run advisor checks, regenerate TypeScript types. Includes a fresh-branch dry-run pre-flight that uses one persistent dry-run ephemeral branch per feature branch.
|
|
4
4
|
argument-hint: "[--new <name> | <path-to-sql>]"
|
|
5
5
|
allowed-tools: Read, Edit, Write, Bash(codebyplan supabase *), Bash(npx codebyplan supabase *), Bash(npx codebyplan checkpoint update *), Bash(npx codebyplan task update *), Bash(git *), Bash(supabase *), Bash(jq *), Bash(date *), Bash(which *), Bash(cp *), Bash(mv *), Bash(test *), Bash(ls *), mcp__supabase__apply_migration, mcp__supabase__list_migrations, mcp__supabase__get_advisors, mcp__supabase__generate_typescript_types, mcp__supabase__reset_branch, mcp__supabase__list_branches, mcp__supabase__create_branch, mcp__supabase__get_cost, mcp__supabase__confirm_cost, mcp__codebyplan__update_checkpoint, mcp__codebyplan__update_task
|
|
6
|
+
model: inherit
|
|
6
7
|
effort: xhigh
|
|
7
8
|
---
|
|
8
9
|
|
|
@@ -3,7 +3,8 @@ name: cbp-supabase-setup
|
|
|
3
3
|
description: Enable Supabase GitHub branching integration — GitHub app authorization, required-status-check enforcement on main + integration branch, persistent branch creation, and idempotency marker in .codebyplan/shipment.json.
|
|
4
4
|
argument-hint: "[--force]"
|
|
5
5
|
allowed-tools: Read, Edit, Bash(supabase *), Bash(jq *), Bash(mv *), Bash(date *), Bash(test *), Bash(which *)
|
|
6
|
-
|
|
6
|
+
model: inherit
|
|
7
|
+
effort: high
|
|
7
8
|
---
|
|
8
9
|
|
|
9
10
|
# Supabase Branching Setup
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: cbp-task-create
|
|
3
3
|
description: Create a new task within the active checkpoint
|
|
4
|
-
|
|
4
|
+
model: inherit
|
|
5
|
+
effort: high
|
|
5
6
|
---
|
|
6
7
|
|
|
7
8
|
# Task Create Command
|
|
@@ -145,7 +146,7 @@ Use `codebyplan task create --checkpoint-id <id> ...` (CLI write-through) to cre
|
|
|
145
146
|
- **requirements**: Numbered requirements list
|
|
146
147
|
- **context**: Include decisions from Q&A, dependencies, source findings
|
|
147
148
|
|
|
148
|
-
**For checkpoint-bound tasks**,
|
|
149
|
+
**For checkpoint-bound tasks**, assignment is user-based — the task's `assigned_user_id` is stamped server-side from the JWT; no caller-worktree param is needed.
|
|
149
150
|
|
|
150
151
|
```
|
|
151
152
|
## Task Created
|
|
@@ -3,6 +3,7 @@ name: cbp-task-start
|
|
|
3
3
|
description: Start a task, load context from DB
|
|
4
4
|
triggers: [cbp-round-plan]
|
|
5
5
|
argument-hint: [chk-task] # e.g. `108-1` (CHK-108 TASK-1)
|
|
6
|
+
model: inherit
|
|
6
7
|
effort: xhigh
|
|
7
8
|
---
|
|
8
9
|
|
|
@@ -156,21 +157,21 @@ Skip this step if the task title and requirements contain no CVE ID (`CVE-YYYY-N
|
|
|
156
157
|
|
|
157
158
|
See `dependency-vulnerability-fixes.md` "Audit Sweep at Task Start" for the source rule.
|
|
158
159
|
|
|
159
|
-
### Step 3.5:
|
|
160
|
+
### Step 3.5: User-Match Verification
|
|
160
161
|
|
|
161
|
-
Before activating the task, verify the
|
|
162
|
+
Before activating the task, verify the current user is allowed to claim/edit the checkpoint row.
|
|
162
163
|
|
|
163
|
-
1.
|
|
164
|
-
2. Determine target
|
|
165
|
-
- **Checkpoint-bound tasks**: `
|
|
166
|
-
3. If `
|
|
164
|
+
1. Resolve the current user: `CURRENT_USER=$(npx codebyplan whoami --json 2>/dev/null)` → parse `user_id` and `email` from the JSON. If the command fails or returns null/empty, `CURRENT_USER_ID` is null (anonymous session).
|
|
165
|
+
2. Determine the target owner:
|
|
166
|
+
- **Checkpoint-bound tasks**: `TARGET_USER = checkpoint.assigned_user_id` (read from the local checkpoint file already loaded in Step 2). Note: checkpoint-bound tasks may have a null `task.assigned_user_id`; the lock lives on the parent checkpoint — fall through to `checkpoint.assigned_user_id`.
|
|
167
|
+
3. If `TARGET_USER IS NOT NULL AND TARGET_USER != CURRENT_USER_ID`, surface this error and abort:
|
|
167
168
|
|
|
168
169
|
```
|
|
169
|
-
TASK-N is assigned to
|
|
170
|
-
Use the release_assignment MCP tool (requires maintainer role) if
|
|
170
|
+
TASK-N is assigned to user {TARGET_EMAIL} ({TARGET_USER}); you are logged in as {CURRENT_EMAIL} ({CURRENT_USER_ID}).
|
|
171
|
+
Use the release_assignment MCP tool (requires maintainer role) if that user is no longer active, then re-run /cbp-task-start.
|
|
171
172
|
```
|
|
172
173
|
|
|
173
|
-
4. If `
|
|
174
|
+
4. If `TARGET_USER IS NULL` or matches `CURRENT_USER_ID`, proceed.
|
|
174
175
|
|
|
175
176
|
### Step 3.6: Main-Drift Check (optional)
|
|
176
177
|
|
|
@@ -217,7 +218,7 @@ Display context summary:
|
|
|
217
218
|
|
|
218
219
|
### Step 5: Set Task Status
|
|
219
220
|
|
|
220
|
-
`codebyplan task update --id <taskId> --checkpoint-id <checkpointId> --status in_progress` (CLI write-through: local state file + REST).
|
|
221
|
+
`codebyplan task update --id <taskId> --checkpoint-id <checkpointId> --status in_progress` (CLI write-through: local state file + REST). The server keys on the JWT user for authz — no worktree or claim params are needed or accepted. Break-glass fallback: MCP `update_task(task_id, status: "in_progress")` when the CLI is unavailable — all worktree-identity params are deprecated and silently ignored server-side; omit them.
|
|
221
222
|
|
|
222
223
|
### Step 6: Auto-trigger Round Start
|
|
223
224
|
|
|
@@ -1,32 +1,19 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: cbp-todo
|
|
3
3
|
description: Entry point - what to work on next
|
|
4
|
-
|
|
4
|
+
model: inherit
|
|
5
|
+
effort: medium
|
|
5
6
|
---
|
|
6
7
|
|
|
7
8
|
# Todo Command
|
|
8
9
|
|
|
9
|
-
Single entry point after `/clear`: read the pure-read todo queue, gate on
|
|
10
|
+
Single entry point after `/clear`: read the pure-read todo queue, gate on user 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 user — before any command runs.
|
|
10
11
|
|
|
11
12
|
## Instructions
|
|
12
13
|
|
|
13
|
-
### Step 0: Resolve Caller Identity (
|
|
14
|
+
### Step 0: Resolve Caller Identity (user)
|
|
14
15
|
|
|
15
|
-
Before any MCP call, resolve who
|
|
16
|
-
|
|
17
|
-
**Worktree** — derive the caller `worktree_id` and any distress signal in one structured read:
|
|
18
|
-
|
|
19
|
-
```bash
|
|
20
|
-
npx codebyplan resolve-worktree --json # → {"worktree_id":"<uuid>|null","error_kind":null|"<kind>"}
|
|
21
|
-
```
|
|
22
|
-
|
|
23
|
-
- `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).
|
|
24
|
-
- `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:
|
|
25
|
-
|
|
26
|
-
```
|
|
27
|
-
⚠ resolve-worktree: <error_kind> — local state is broken; routing is unreliable.
|
|
28
|
-
Run `npx codebyplan setup` from this directory to register/repair, then re-run /cbp-todo.
|
|
29
|
-
```
|
|
16
|
+
Before any MCP call, resolve who the caller is.
|
|
30
17
|
|
|
31
18
|
**User** — `get_todos` (Step 1) requires a `user_id`:
|
|
32
19
|
|
|
@@ -35,45 +22,44 @@ npx codebyplan whoami --json # → {"user_id":"<uuid>","email":"…"} or null
|
|
|
35
22
|
```
|
|
36
23
|
|
|
37
24
|
- A `user_id` is returned → use it in Step 1.
|
|
38
|
-
- `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.
|
|
25
|
+
- `null` or empty `user_id` (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.
|
|
39
26
|
|
|
40
27
|
### Step 1: Read the Todo Queue (pure-read)
|
|
41
28
|
|
|
42
|
-
With `USER_ID` resolved, read `.codebyplan/state/todos.json` (local-first). If missing or stale (`_cursor.json` absent or `sync_status !== "synced"`), run `npx codebyplan sync` once and re-read. Break-glass fallback: MCP `get_todos({ repo_id, user_id
|
|
29
|
+
With `USER_ID` resolved, read `.codebyplan/state/todos.json` (local-first). If missing or stale (`_cursor.json` absent or `sync_status !== "synced"`), run `npx codebyplan sync` once and re-read. Break-glass fallback: MCP `get_todos({ repo_id, user_id })` when the state dir is absent and sync fails. Filter by `user_id`. Take **`rows[0]`** as the queue head (ordered by `sort_order`).
|
|
43
30
|
|
|
44
|
-
- The head carries `command`, `instructions`, `state`, `metadata`, `
|
|
31
|
+
- The head carries `command`, `instructions`, `state`, `metadata`, `checkpoint_id`, `task_id`.
|
|
45
32
|
- The routing context (checkpoint/task) lives in **`rows[0].metadata`**.
|
|
46
33
|
- `get_todos` is **pure-read** — `apps/todo-worker` is the sole regen authority. NEVER call `get_next_action` or `regenerate_todos_for_repo`.
|
|
47
34
|
- Empty array, or `USER_ID` unavailable → go to Step 3 (empty-queue fallback).
|
|
48
35
|
|
|
49
36
|
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.
|
|
50
37
|
|
|
51
|
-
### Step 1.5: Resolve Target +
|
|
38
|
+
### Step 1.5: Resolve Target + User-Ownership Gate
|
|
52
39
|
|
|
53
|
-
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
|
|
40
|
+
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 user.
|
|
54
41
|
|
|
55
|
-
Resolve the checkpoint from `rows[0].metadata` (or read `.codebyplan/state/session/current.json` for the active task, falling back to MCP `get_current_task`), then load its `
|
|
42
|
+
Resolve the checkpoint from `rows[0].metadata` (or read `.codebyplan/state/session/current.json` for the active task, falling back to MCP `get_current_task`), then load its `assigned_user_id` + `plan` + `status` from `.codebyplan/state/checkpoints/<id>.json` (falling back to MCP `get_checkpoints`) and its task count from `.codebyplan/state/checkpoints/<id>/tasks/` files (falling back to 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`.
|
|
56
43
|
|
|
57
44
|
Two ownership signals:
|
|
58
45
|
|
|
59
|
-
1. **Server-detected conflict** — `rows[0].state === "worktree_conflict"` (command `/codebyplan:release-or-switch`): the todo-worker already detected the lock conflict.
|
|
60
|
-
2. **Checkpoint-ownership check** — take the target checkpoint's `
|
|
61
|
-
- target `
|
|
62
|
-
- target `
|
|
63
|
-
- target `
|
|
64
|
-
- target `worktree_id` non-null and differs from a non-null caller → **block**.
|
|
46
|
+
1. **Server-detected conflict** — `rows[0].state === "worktree_conflict"` (command `/codebyplan:release-or-switch`): the todo-worker already detected the lock conflict. (`worktree_conflict` is the worker's current state-value name — it now reflects a user-level lock conflict and is renamed alongside the web-UI/schema work in a later task.) Surface the mismatch message below and **STOP**. Do NOT auto-trigger the release-or-switch command and do NOT call `release_assignment` — the user who owns the lock must release it or a maintainer must use `release_assignment`.
|
|
47
|
+
2. **Checkpoint-ownership check** — take the target checkpoint's `assigned_user_id` (loaded above) and compare with caller `USER_ID`:
|
|
48
|
+
- target `assigned_user_id` is `null` → **allow** (unassigned — any user may pick it up).
|
|
49
|
+
- target `assigned_user_id` === caller `USER_ID` → **allow**.
|
|
50
|
+
- target `assigned_user_id` non-null AND differs from caller `USER_ID` → **block**.
|
|
65
51
|
|
|
66
|
-
On block,
|
|
52
|
+
On block, emit and STOP (show the owner email if resolvable from the whoami context, otherwise the `assigned_user_id` UUID):
|
|
67
53
|
|
|
68
54
|
```
|
|
69
|
-
⚠ Work mismatch: CHK-<NNN> TASK-<N> is assigned to
|
|
55
|
+
⚠ Work mismatch: CHK-<NNN> TASK-<N> is assigned to user <email-or-uuid>, not you.
|
|
70
56
|
Options:
|
|
71
|
-
A)
|
|
72
|
-
B)
|
|
57
|
+
A) Work on something else — run /cbp-checkpoint-create or /cbp-task-create
|
|
58
|
+
B) Ask the owner to release the assignment, or a maintainer can use release_assignment, then re-run /cbp-todo
|
|
73
59
|
C) /cbp-session-end
|
|
74
60
|
```
|
|
75
61
|
|
|
76
|
-
|
|
62
|
+
Wait for the user. NEVER propose reassigning the checkpoint to the caller.
|
|
77
63
|
|
|
78
64
|
### Step 1.55: Stale-Entity Guard
|
|
79
65
|
|
|
@@ -169,8 +155,8 @@ Display a brief context summary:
|
|
|
169
155
|
|
|
170
156
|
Reached when `get_todos` returns `[]` or `USER_ID` was unavailable.
|
|
171
157
|
|
|
172
|
-
1. **Fallback discovery
|
|
173
|
-
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 `
|
|
158
|
+
1. **Fallback discovery**: read `.codebyplan/state/session/current.json` and scan `.codebyplan/state/checkpoints/` for active checkpoints (fallback: MCP `get_current_task` + `get_checkpoints`) to discover whether actionable work exists for this caller.
|
|
159
|
+
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 `assigned_user_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.
|
|
174
160
|
3. **Nothing actionable** → suggest ending the session:
|
|
175
161
|
|
|
176
162
|
```
|
|
@@ -189,6 +175,6 @@ Reached only when the Step 1.5 ownership gate allowed routing to continue, the S
|
|
|
189
175
|
## Integration
|
|
190
176
|
|
|
191
177
|
- **Called by**: `/cbp-session-start`, `/cbp-finalize`, `/cbp-checkpoint-complete`, manual, after `/clear`
|
|
192
|
-
- **Resolves**: `npx codebyplan
|
|
193
|
-
- **Reads**: `.codebyplan/state/todos.json`, `session/current.json`, `checkpoints/<id>.json`, `checkpoints/<id>/tasks/<id>.json`, `checkpoints/<id>/tasks/<id>/rounds/<id>.json
|
|
178
|
+
- **Resolves**: `npx codebyplan whoami --json` (user id)
|
|
179
|
+
- **Reads**: `.codebyplan/state/todos.json`, `session/current.json`, `checkpoints/<id>.json`, `checkpoints/<id>/tasks/<id>.json`, `checkpoints/<id>/tasks/<id>/rounds/<id>.json`. If missing/stale, run `npx codebyplan sync` once and re-read. Break-glass: MCP `get_todos`, `get_current_task`, `get_rounds`, `get_checkpoints`, `get_tasks` when state dir absent and sync fails.
|
|
194
180
|
- **Triggers**: `rows[0].command` (auto, after the Step 1.5 ownership gate and Step 1.55 stale-entity guard pass, and the Step 1.6 planning gate falls through); Step 1.55 overrides to STOP (stale completed/cancelled entity); Step 1.6 overrides to `/cbp-checkpoint-plan` (unplanned) or `/cbp-checkpoint-start` (planned-but-pending)
|
|
@@ -1,51 +1,45 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: cbp-todo-qa-regression
|
|
3
|
-
description: Manual regression procedure for the cbp-todo
|
|
3
|
+
description: Manual regression procedure for the cbp-todo user-ownership gate + get_todos switch (CHK-225 TASK-5)
|
|
4
4
|
---
|
|
5
5
|
|
|
6
|
-
# cbp-todo —
|
|
6
|
+
# cbp-todo — User-Ownership Regression
|
|
7
7
|
|
|
8
|
-
Manual procedure verifying that `/cbp-todo` reads the pure-read `get_todos` queue and refuses to auto-route into work locked to another
|
|
8
|
+
Manual procedure verifying that `/cbp-todo` reads the pure-read `get_todos` queue and refuses to auto-route into work locked to another user. 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.
|
|
9
9
|
|
|
10
10
|
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`.
|
|
11
11
|
|
|
12
12
|
## Preconditions
|
|
13
13
|
|
|
14
14
|
- `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).
|
|
15
|
-
- Step 0 uses `
|
|
15
|
+
- Step 0 uses `whoami --json` only — no worktree-resolution CLI verb appears in SKILL.md (verify by grepping the banned token list against SKILL.md; zero hits expected).
|
|
16
16
|
- Step 1.55 (Stale-Entity Guard) must NOT call `get_next_action` or `regenerate_todos_for_repo` when rejecting a stale head — it reuses the checkpoint `status` + task statuses already loaded in Step 1.5 (the same grep above covers it).
|
|
17
17
|
|
|
18
|
-
## Scenario A —
|
|
18
|
+
## Scenario A — current user owns the work → auto-trigger
|
|
19
19
|
|
|
20
|
-
1.
|
|
21
|
-
2. `get_todos({ repo_id, user_id
|
|
20
|
+
1. `npx codebyplan whoami --json` returns `user_id` matching the target checkpoint's `assigned_user_id` (or `assigned_user_id` is `null` — open queue).
|
|
21
|
+
2. `get_todos({ repo_id, user_id })` returns a head whose target checkpoint is owned by the caller (or unassigned).
|
|
22
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
23
|
|
|
24
|
-
## Scenario
|
|
24
|
+
## Scenario B — checkpoint assigned to a DIFFERENT user → halt
|
|
25
25
|
|
|
26
|
-
1.
|
|
27
|
-
2. `get_todos` head is
|
|
28
|
-
3. **MCP calls expected**: `get_todos`; `
|
|
29
|
-
4. **Expected**: Step 1.5
|
|
26
|
+
1. `whoami` returns user A. Target checkpoint `assigned_user_id` is user B (non-null, different).
|
|
27
|
+
2. `get_todos` head is a normal routing todo whose target checkpoint `assigned_user_id` is user B's UUID.
|
|
28
|
+
3. **MCP calls expected**: `get_todos`; `get_checkpoints` (Step 1.5 load, reads the target `assigned_user_id`). Owner is identified by `assigned_user_id` directly (email from whoami context if resolvable, else the UUID) — no worktree-lookup MCP call is needed.
|
|
29
|
+
4. **Expected**: Step 1.5 checkpoint-ownership branch blocks and STOPS with the "Work mismatch" message naming the owner email-or-uuid. NO auto-trigger; the Step 1.6 planning gate never runs (ownership precedes it). NEVER propose reassigning the checkpoint to the caller.
|
|
30
30
|
|
|
31
|
-
## Scenario
|
|
31
|
+
## Scenario C — empty queue / anonymous caller → fallback
|
|
32
32
|
|
|
33
|
-
1.
|
|
34
|
-
2.
|
|
35
|
-
3. **Expected**: Step 1.5
|
|
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.
|
|
33
|
+
1. `get_todos` returns `[]` OR `whoami` returned `null`/empty `user_id`, so Step 1 was skipped.
|
|
34
|
+
2. Step 3 fallback: `get_current_task` / `get_checkpoints` surface a checkpoint whose `assigned_user_id` differs from the caller (or caller is anonymous).
|
|
35
|
+
3. **Expected**: the Step 1.5 ownership gate (applied to the fallback target) blocks the discovered work with the "Work mismatch" message when the user differs, or routes to the idle suggestion when the caller is anonymous and no open work is found. NO auto-trigger. `regenerate_todos_for_repo` is never called.
|
|
42
36
|
|
|
43
37
|
## Scenario D — stale queue head for a completed/cancelled entity → halt
|
|
44
38
|
|
|
45
|
-
1. Caller
|
|
46
|
-
2. Step 1.5 loads the target checkpoint `status` +
|
|
47
|
-
3. **Expected**: Step 1.55 rejects the auto-trigger — target checkpoint `status` is `completed`/`cancelled` (or every task is `completed`/`cancelled`) — surfaces the "Stale queue head" message naming the command + `CHK-NNN`[
|
|
39
|
+
1. Caller's `user_id` matches the target checkpoint's `assigned_user_id` (ownership passes), but the todo-worker queue is lagging — `health_check.todos_freshness_ok === false`. The `get_todos` head targets a checkpoint (or task) that has since been completed or cancelled.
|
|
40
|
+
2. Step 1.5 loads the target checkpoint `status` + task statuses (already required for the ownership/planning gates — no extra reads).
|
|
41
|
+
3. **Expected**: Step 1.55 rejects the auto-trigger — target checkpoint `status` is `completed`/`cancelled` (or every task is `completed`/`cancelled`) — surfaces the "Stale queue head" message naming the command + `CHK-NNN`[`TASK-N`] + status, and STOPS. NO auto-trigger. NO `get_next_action` / `regenerate_todos_for_repo` call.
|
|
48
42
|
|
|
49
|
-
## Edge —
|
|
43
|
+
## Edge — null assigned_user_id (open work)
|
|
50
44
|
|
|
51
|
-
|
|
45
|
+
`assigned_user_id` is `null` on the target checkpoint AND caller has a valid `user_id` → open/unassigned work → auto-trigger allowed (proceeds to Step 1.6 planning gate).
|
|
@@ -3,6 +3,7 @@ name: cbp-verify
|
|
|
3
3
|
description: Unified verify stage — deterministic gates, real-execution proof, and a fresh-context diff review at round or task scope. Auto-triggered by cbp-round-build; escalates to task scope on the last clean round.
|
|
4
4
|
argument-hint: [chk-task[-round] | task[-round]]
|
|
5
5
|
triggers: [cbp-round-plan, cbp-round-complete, cbp-finalize]
|
|
6
|
+
model: inherit
|
|
6
7
|
effort: xhigh
|
|
7
8
|
---
|
|
8
9
|
|
|
@@ -98,6 +99,10 @@ Triage the returned findings: in-scope mechanical fixes the orchestrator applies
|
|
|
98
99
|
(`Edit`/`Write`); blocking out-of-scope findings → `/cbp-round-plan` fix round. A baseline
|
|
99
100
|
regression is a **blocking user-accept gate** — never auto-accepted.
|
|
100
101
|
|
|
102
|
+
#### Orchestration (optional)
|
|
103
|
+
|
|
104
|
+
When a finding warrants adversarial confirmation, Phase 4's `cbp-verify-reviewer` spawn MAY be expressed as a `Workflow(...)` script — e.g. N independent multi-vote reviewers — instead of a single ad-hoc spawn. This is opt-in (ultracode session or explicit user request); the single-spawn flow above stays the DEFAULT and is unchanged. See `rules/workflow-orchestration.md`.
|
|
105
|
+
|
|
101
106
|
### PHASE 5 — VERDICT + ROUTE (single directive, never an A/B/C menu)
|
|
102
107
|
|
|
103
108
|
Combine Phase 2 + 3 + 4. Route on one directive (`feedback-close-out-routing.md`):
|
|
@@ -58,5 +58,4 @@ human confirmation — do not add an AskUserQuestion in cbp-verify at round scop
|
|
|
58
58
|
|
|
59
59
|
`codebyplan round update --id <round_id> --task-id <uuid> --checkpoint-id <uuid> --context '<json>'`
|
|
60
60
|
(merge `verify_manifest` into existing context; the REPLACE contract requires the full object).
|
|
61
|
-
Break-glass: MCP `update_round` (checkpoint KIND) / `update_standalone_round` (standalone KIND)
|
|
62
|
-
pass `caller_worktree_id` on locked feat rows.
|
|
61
|
+
Break-glass: MCP `update_round` (checkpoint KIND) / `update_standalone_round` (standalone KIND).
|
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: supabase
|
|
3
3
|
description: "Use when doing ANY task involving Supabase. Triggers: Supabase products (Database, Auth, Edge Functions, Realtime, Storage, Vectors, Cron, Queues); client libraries and SSR integrations (supabase-js, @supabase/ssr) in Next.js, React, SvelteKit, Astro, Remix; auth issues (login, logout, sessions, JWT, cookies, getSession, getUser, getClaims, RLS); Supabase CLI or MCP server; schema changes, migrations, security audits, Postgres extensions (pg_graphql, pg_cron, pg_vector)."
|
|
4
|
+
model: inherit
|
|
5
|
+
effort: medium
|
|
4
6
|
metadata:
|
|
5
7
|
author: supabase
|
|
6
8
|
version: "0.1.2"
|
|
@@ -2,6 +2,8 @@
|
|
|
2
2
|
name: supabase-postgres-best-practices
|
|
3
3
|
description: Postgres performance optimization and best practices from Supabase. Use this skill when writing, reviewing, or optimizing Postgres queries, schema designs, or database configurations.
|
|
4
4
|
license: MIT
|
|
5
|
+
model: inherit
|
|
6
|
+
effort: low
|
|
5
7
|
metadata:
|
|
6
8
|
author: supabase
|
|
7
9
|
version: "1.1.1"
|
|
@@ -1,78 +0,0 @@
|
|
|
1
|
-
#!/bin/bash
|
|
2
|
-
# @hook: PreToolUse mcp__codebyplan__(update_checkpoint|complete_checkpoint|update_task|complete_task|add_round|update_round|complete_round|create_standalone_task|update_standalone_task|complete_standalone_task|add_standalone_round|update_standalone_round|complete_standalone_round|update_standalone_file_change)
|
|
3
|
-
# Hook: PreToolUse for MCP write tools
|
|
4
|
-
#
|
|
5
|
-
# Purpose: Inject caller_worktree_id into MCP mutation tool inputs when the
|
|
6
|
-
# field is absent. Reads the worktree.local.json branch-keyed cache
|
|
7
|
-
# first (fast path); falls back to `codebyplan resolve-worktree --cache`.
|
|
8
|
-
#
|
|
9
|
-
# Fail-open: ALL exit paths exit 0. A hook failure must never block a tool call.
|
|
10
|
-
# Use explicit guards rather than set -euo pipefail (which would exit
|
|
11
|
-
# non-zero on the first failing command before the final exit 0).
|
|
12
|
-
|
|
13
|
-
# C0 — require jq; if absent, emit nothing and exit 0 (fail-open).
|
|
14
|
-
if ! command -v jq > /dev/null 2>&1; then
|
|
15
|
-
exit 0
|
|
16
|
-
fi
|
|
17
|
-
|
|
18
|
-
# Read stdin once into a variable.
|
|
19
|
-
INPUT=$(cat)
|
|
20
|
-
|
|
21
|
-
# C6 — if caller_worktree_id is already a non-empty string, do not overwrite.
|
|
22
|
-
# (jq '// empty' already maps JSON null to an empty string, so a plain -n test suffices.)
|
|
23
|
-
EXISTING=$(echo "$INPUT" | jq -r '.tool_input.caller_worktree_id // empty' 2>/dev/null)
|
|
24
|
-
if [ -n "$EXISTING" ]; then
|
|
25
|
-
# Already populated — plain allow (exit 0 with no output).
|
|
26
|
-
exit 0
|
|
27
|
-
fi
|
|
28
|
-
|
|
29
|
-
# C5 — resolve worktree id, fast path first.
|
|
30
|
-
RESOLVED_WT=""
|
|
31
|
-
|
|
32
|
-
# Determine repo root: prefer $CLAUDE_PROJECT_DIR, fall back to PWD.
|
|
33
|
-
REPO_ROOT="${CLAUDE_PROJECT_DIR:-$PWD}"
|
|
34
|
-
CACHE_FILE="$REPO_ROOT/.codebyplan/worktree.local.json"
|
|
35
|
-
|
|
36
|
-
if [ -f "$CACHE_FILE" ]; then
|
|
37
|
-
CACHED_WT=$(jq -r '.worktree_id // empty' "$CACHE_FILE" 2>/dev/null)
|
|
38
|
-
CACHED_BRANCH=$(jq -r '.branch // empty' "$CACHE_FILE" 2>/dev/null)
|
|
39
|
-
|
|
40
|
-
if [ -n "$CACHED_WT" ] && [ "$CACHED_WT" != "null" ] && \
|
|
41
|
-
[ -n "$CACHED_BRANCH" ] && [ "$CACHED_BRANCH" != "null" ]; then
|
|
42
|
-
# Validate branch matches current git branch.
|
|
43
|
-
CURRENT_BRANCH=$(git rev-parse --abbrev-ref HEAD 2>/dev/null)
|
|
44
|
-
if [ -n "$CURRENT_BRANCH" ] && [ "$CURRENT_BRANCH" = "$CACHED_BRANCH" ]; then
|
|
45
|
-
RESOLVED_WT="$CACHED_WT"
|
|
46
|
-
fi
|
|
47
|
-
fi
|
|
48
|
-
fi
|
|
49
|
-
|
|
50
|
-
# Fallback to CLI resolution if cache miss or branch mismatch.
|
|
51
|
-
if [ -z "$RESOLVED_WT" ]; then
|
|
52
|
-
RESOLVED_WT=$(codebyplan resolve-worktree --cache 2>/dev/null \
|
|
53
|
-
|| npx --no-install codebyplan resolve-worktree --cache 2>/dev/null \
|
|
54
|
-
|| true)
|
|
55
|
-
fi
|
|
56
|
-
|
|
57
|
-
# UUID guard — accept only a canonical UUID (8-4-4-4-12 hex).
|
|
58
|
-
UUID_PATTERN='^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}$'
|
|
59
|
-
if [ -z "$RESOLVED_WT" ] || ! echo "$RESOLVED_WT" | grep -qE "$UUID_PATTERN"; then
|
|
60
|
-
# Unresolved or invalid — plain allow, no updatedInput.
|
|
61
|
-
exit 0
|
|
62
|
-
fi
|
|
63
|
-
|
|
64
|
-
# C3 — emit updatedInput as the FULL tool_input with caller_worktree_id added.
|
|
65
|
-
# Claude Code's PreToolUse updatedInput REPLACES tool_input wholesale (it is not a
|
|
66
|
-
# partial merge), so we must echo back every existing field merged with the new
|
|
67
|
-
# caller_worktree_id — otherwise the tool loses round_id/duration_minutes/etc.
|
|
68
|
-
echo "$INPUT" | jq \
|
|
69
|
-
--arg wt "$RESOLVED_WT" \
|
|
70
|
-
'{
|
|
71
|
-
hookSpecificOutput: {
|
|
72
|
-
hookEventName: "PreToolUse",
|
|
73
|
-
permissionDecision: "allow",
|
|
74
|
-
updatedInput: (.tool_input + { caller_worktree_id: $wt })
|
|
75
|
-
}
|
|
76
|
-
}'
|
|
77
|
-
|
|
78
|
-
exit 0
|