codebyplan 1.11.2 → 1.12.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.
@@ -3,7 +3,7 @@ scope: org-shared
3
3
  name: cbp-supabase-migrate
4
4
  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.
5
5
  argument-hint: "[--new <name> | <path-to-sql>]"
6
- allowed-tools: Read, Edit, Write, 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
6
+ allowed-tools: Read, Edit, Write, 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
7
7
  model: sonnet
8
8
  effort: xhigh
9
9
  ---
@@ -61,11 +61,139 @@ Parse the output for:
61
61
  - `POSTGRES_URL_NON_POOLING` — direct connection string for the preview DB
62
62
  - `project_ref` — the Supabase project ref for this branch's environment
63
63
 
64
- Capture both values. The `project_ref` is used in Steps 3, 4, 6, 7, and 8. (Step 5.5 resolves its own separate dry-run branch `project_ref` — see [reference/preflight-dry-run.md](reference/preflight-dry-run.md).)
64
+ Capture both values. The `project_ref` is used from Step 3 onward; Step 2.3 may replace it with a `PREVIEW_PROJECT_REF` when it lazily provisions the branch. (Step 5.5 resolves its own separate dry-run branch `project_ref` — see [reference/preflight-dry-run.md](reference/preflight-dry-run.md).)
65
+
66
+ ## Step 2.3 — Ensure Supabase Branch Exists
67
+
68
+ Couples the Supabase preview branch lifecycle to the git branch: when this skill runs on a
69
+ feat branch that touches the database, a Supabase branch named **exactly** the current git
70
+ branch is guaranteed to exist before any migration is applied. Naming it identically to the
71
+ git branch is the linchpin that lets the GitHub branching integration reconcile to the same
72
+ branch (no duplicate).
73
+
74
+ > Lifecycle contract: see [[supabase-branch-lifecycle]].
75
+
76
+ This step runs **before** Step 2.5: it lazily provisions the branch so that an empty
77
+ `project_ref` from Step 2 gets filled in. Step 2.5 then fires only when `project_ref` is
78
+ **still** empty after this step (i.e. this step was skipped or creation was declined).
79
+
80
+ ### Guard 1 — feat-branch only
81
+
82
+ Read branch config from `.codebyplan/git.json`:
83
+
84
+ ```bash
85
+ PRODUCTION=$(jq -r '.branch_config.production // "main"' .codebyplan/git.json)
86
+ PROTECTED=$(jq -r '.branch_config.protected[]? // empty' .codebyplan/git.json)
87
+ INTEGRATION=$(jq -r '.branch_config.integration // empty' .codebyplan/git.json)
88
+ ```
89
+
90
+ If `$BRANCH` equals `$PRODUCTION` or appears in `$PROTECTED`, skip this entire step — never
91
+ provision a Supabase branch for the production/protected branch. On `$PRODUCTION` the
92
+ `project_ref` from Step 2 is the parent project itself; Step 3's main-project guard handles
93
+ that case. (A standalone task pinned to the production branch is covered by this same check,
94
+ since its `$BRANCH` equals `$PRODUCTION`.)
95
+
96
+ If `$INTEGRATION` is non-empty and `$BRANCH` equals `$INTEGRATION`, skip this step — the
97
+ integration branch uses a persistent Supabase branch provisioned by `cbp-supabase-setup`,
98
+ not a lazy ephemeral one. Do NOT default or write `$INTEGRATION` to any value; only read and
99
+ skip.
100
+
101
+ ### Guard 2 — DB-path / migration intent
102
+
103
+ Reuse the db_paths detection so the step proceeds only when this invocation actually touches
104
+ the database. Read the globs (default `supabase/**`, `apps/backend/**`, `packages/**/db/**`):
105
+
106
+ ```bash
107
+ DB_PATHS=$(jq -r '.shipment.surfaces.supabase.db_paths[]? // empty' .codebyplan/shipment.json 2>/dev/null)
108
+ [ -z "$DB_PATHS" ] && DB_PATHS=$(printf '%s\n' 'supabase/**' 'apps/backend/**' 'packages/**/db/**')
109
+ ```
110
+
111
+ Proceed when **either**:
112
+ - the branch diff against `origin/$PRODUCTION` touches any `DB_PATHS` glob, **or**
113
+ - this invocation will create/adopt a migration — `$ARGUMENTS` is `--new <name>` or a `.sql`
114
+ path (the migration file may not exist on disk yet, so explicit migrate intent counts as a
115
+ DB change). The bare-picker case (Step 5 Case C) is treated as migrate intent.
116
+
117
+ If neither holds (no DB-path changes and no migrate intent), skip this step silently and let
118
+ Step 2.5 / the normal flow handle the empty `project_ref` — do not provision or prompt for
119
+ cost on a branch that touches no database paths.
120
+
121
+ ### Already-provisioned reuse
122
+
123
+ If `project_ref` from Step 2 is already non-empty, the GitHub integration (or a prior run)
124
+ already provisioned the branch. Capture it as `PREVIEW_PROJECT_REF` and jump straight to
125
+ "Record connection" below — idempotent, no creation.
126
+
127
+ ### Idempotency check (list before create)
128
+
129
+ Call `mcp__supabase__list_branches` with the parent `project_id` `rrvtrumtkhrsbhcyrwvf`. The
130
+ parent `project_id` for MCP calls is the same ref string stored in `.codebyplan/shipment.json`
131
+ `surfaces.supabase.project_ref` — Supabase uses that one ref as both the project identifier
132
+ and the branch target. Scan the returned list for an entry whose `name` exactly equals
133
+ `$BRANCH` (slashes included — `feat/CHK-144-...` is a valid Supabase branch name).
134
+
135
+ - **Match found**: capture its `project_ref` as `PREVIEW_PROJECT_REF`. Skip creation; proceed
136
+ to "Record connection". This is the idempotent reuse path (covers a branch the GitHub
137
+ integration auto-created between Step 2 and now).
138
+ - **No match**: proceed to "Cost confirmation and creation".
139
+
140
+ ### Cost confirmation and creation
141
+
142
+ Cost confirmation is mandatory before creating a branch — never bypass it:
143
+
144
+ 1. Call `mcp__supabase__get_cost` with `type: "branch"`. Display the returned estimate to the
145
+ user, capturing the returned `confirm_cost_id`.
146
+ 2. Call `mcp__supabase__confirm_cost` with that `confirm_cost_id`.
147
+ 3. On user cancellation or cost-confirm rejection: emit a warning and continue in
148
+ scaffold-only mode (jump to Step 5 write-only path; skip Steps 5.5 and 6). `project_ref`
149
+ stays empty.
150
+
151
+ After cost is confirmed, call `mcp__supabase__create_branch`:
152
+ - `project_id`: `rrvtrumtkhrsbhcyrwvf` (parent project ref)
153
+ - `name`: `$BRANCH` (verbatim — slashes included)
154
+ - `confirm_cost_id`: the same id from the `get_cost` response that was passed to `confirm_cost`
155
+
156
+ After the create call returns, poll `mcp__supabase__list_branches` every 10 s until an entry
157
+ with `name == $BRANCH` appears (up to 60 s / 6 polls). Capture its `project_ref` as
158
+ `PREVIEW_PROJECT_REF`. If polling times out:
159
+
160
+ ```
161
+ Supabase branch creation for <BRANCH> did not settle within 60 s.
162
+ Check the Supabase dashboard: Branches — then re-run /cbp-supabase-migrate.
163
+ ```
164
+
165
+ Stop.
166
+
167
+ ### Record connection
168
+
169
+ Record the branch so cleanup (see `cbp-checkpoint-end`, `cbp-git-worktree-remove`) and other
170
+ skills can discover it. Phrase any context payload as prose — the MCP edge rejects raw
171
+ uppercase database keywords (Cloudflare WAF).
172
+
173
+ 1. **Checkpoint / task context** — call `mcp__codebyplan__update_checkpoint` (or
174
+ `mcp__codebyplan__update_task` for a standalone task) to add to `context.discoveries`:
175
+
176
+ ```json
177
+ { "topic": "supabase_preview_branch", "finding": "branch <BRANCH> -> project_ref <PREVIEW_PROJECT_REF>" }
178
+ ```
179
+
180
+ 2. **`.codebyplan/shipment.json`** — read-merge-write (the `preview_branches` array may not
181
+ exist yet — create it if absent; never clobber the rest of the file). Under
182
+ `surfaces.supabase.preview_branches`, first check for an existing entry whose `branch`
183
+ equals `$BRANCH`: if present, update its `project_ref` only if it differs (no duplicate
184
+ append); if absent, append:
185
+
186
+ ```json
187
+ { "branch": "<BRANCH>", "project_ref": "<PREVIEW_PROJECT_REF>", "created_at": "<ISO timestamp>" }
188
+ ```
189
+
190
+ Set `project_ref = $PREVIEW_PROJECT_REF` so Steps 3 onward target this branch's project.
65
191
 
66
192
  ## Step 2.5 — Empty project_ref Handling
67
193
 
68
- If `project_ref` is empty after Step 2, AskUserQuestion:
194
+ If `project_ref` is **still** empty after Step 2.3 (no branch was provisioned — e.g. no
195
+ DB-path changes / no migrate intent, or this is a protected branch, or cost confirmation was
196
+ declined), AskUserQuestion:
69
197
 
70
198
  ```
71
199
  Could not resolve a Supabase project_ref for branch: <BRANCH>
@@ -88,12 +216,14 @@ On (C): stop silently.
88
216
 
89
217
  ## Step 3 — Main-Project Guard
90
218
 
91
- If `project_ref` is empty (scaffold-only mode chosen in Step 2.5), skip Steps 3 and 4 entirely and jump directly to Step 5.
219
+ If `project_ref` is empty, skip Steps 3 and 4 entirely and jump directly to Step 5. (Normally
220
+ Step 2.3 has already populated `project_ref` for a feat branch, or scaffold-only mode was
221
+ chosen in Step 2.5; this remains a defensive guard for the scaffold-only path.)
92
222
 
93
- Read `.codebyplan.json`:
223
+ Read `.codebyplan/shipment.json`:
94
224
 
95
225
  ```bash
96
- MAIN_PROJECT_REF=$(jq -r '.shipment.surfaces.supabase.project_ref' .codebyplan.json)
226
+ MAIN_PROJECT_REF=$(jq -r '.shipment.surfaces.supabase.project_ref' .codebyplan/shipment.json)
97
227
  ```
98
228
 
99
229
  `MAIN_PROJECT_REF` is consumed by Step 5.5's dry-run CLI calls (`branches create` and `branches get`) to pin those calls to the parent project rather than any linked preview branch.
@@ -274,16 +404,16 @@ severity level. Hard-block enforcement at ship time is owned by `cbp-supabase-br
274
404
 
275
405
  ## Step 8 — Regenerate TypeScript Types
276
406
 
277
- Read the types output path from `.codebyplan.json`:
407
+ Read the types output path from `.codebyplan/shipment.json`:
278
408
 
279
409
  ```bash
280
- jq -r '.shipment.surfaces.supabase.types_path' .codebyplan.json
410
+ jq -r '.shipment.surfaces.supabase.types_path' .codebyplan/shipment.json
281
411
  ```
282
412
 
283
413
  If the field is missing or empty, AskUserQuestion:
284
414
 
285
415
  ```
286
- types_path not found in .codebyplan.json under shipment.surfaces.supabase.types_path.
416
+ types_path not found in .codebyplan/shipment.json under surfaces.supabase.types_path.
287
417
  Enter the path where TypeScript types should be written (e.g., apps/web/src/lib/database.types.ts):
288
418
  ```
289
419
 
@@ -12,7 +12,7 @@ The dry-run uses ONE persistent branch per feature branch — created on first u
12
12
 
13
13
  DRY_RUN_BRANCH="${BRANCH}-cbp-migrate-dryrun"
14
14
 
15
- The CLI `branches` sub-commands act on the project the CLI is *linked* to — mid-development that is often a preview branch, not the parent project. Pin every `branches` call to the parent with `--project-ref "$MAIN_PROJECT_REF"`, where `MAIN_PROJECT_REF` is the parent `project_ref` SKILL.md Step 3 already resolves from `.codebyplan.json` (`.shipment.surfaces.supabase.project_ref`). `mcp__supabase__list_branches` and `reset_branch` need no such flag — the MCP server is already bound to the parent project.
15
+ The CLI `branches` sub-commands act on the project the CLI is *linked* to — mid-development that is often a preview branch, not the parent project. Pin every `branches` call to the parent with `--project-ref "$MAIN_PROJECT_REF"`, where `MAIN_PROJECT_REF` is the parent `project_ref` SKILL.md Step 3 already resolves from `.codebyplan/shipment.json` (`.shipment.surfaces.supabase.project_ref`). `mcp__supabase__list_branches` and `reset_branch` need no such flag — the MCP server is already bound to the parent project.
16
16
 
17
17
  1. Call `mcp__supabase__list_branches`. Look for an entry whose name equals `DRY_RUN_BRANCH`. If found, capture its `id` field as `DRY_RUN_BRANCH_ID` — `reset_branch` and every status poll below act on the branch id, not the name.
18
18
  2. **If absent** — run `supabase --experimental branches create "$DRY_RUN_BRANCH" --project-ref "$MAIN_PROJECT_REF" --yes`. The `--yes` flag is required: branch creation prompts for cost confirmation and the skill runs non-interactively, so the prompt would otherwise hang. The CLI create command is asynchronous and returns a human-readable message (not JSON with an `id`). After the CLI call, poll `mcp__supabase__list_branches` until an entry whose name equals `DRY_RUN_BRANCH` appears, then capture its `id` as `DRY_RUN_BRANCH_ID`. This poll both confirms the create succeeded and yields the id. Creation clones at `git_ref=main` and replays main's migration chain as a baseline — skip the reset in step 4 and go straight to step 5 (the initial provisioning already gave a main baseline).
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  scope: org-shared
3
3
  name: cbp-supabase-setup
4
- 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.json.
4
+ 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.
5
5
  argument-hint: "[--force]"
6
6
  allowed-tools: Read, Edit, Bash(supabase *), Bash(jq *), Bash(mv *), Bash(date *), Bash(test *), Bash(which *)
7
7
  effort: xhigh
@@ -41,13 +41,19 @@ first, then re-invoke /cbp-supabase-setup.
41
41
  Read `supabase/config.toml` to extract the linked `project_id` (under `[api]` or the top-level
42
42
  `project_id` field, depending on CLI version).
43
43
 
44
- Read `.codebyplan.json`:
44
+ Read `.codebyplan/git.json` and `.codebyplan/shipment.json`:
45
45
 
46
46
  ```bash
47
- jq '.branch_config.integration // empty' .codebyplan.json
48
- jq '.shipment.surfaces.supabase.branching_configured // empty' .codebyplan.json
47
+ jq '.branch_config.integration // empty' .codebyplan/git.json
48
+ jq '.shipment.surfaces.supabase.branching_configured // empty' .codebyplan/shipment.json
49
49
  ```
50
50
 
51
+ > **Note — Two distinct Supabase branching models**: This skill performs a ONE-TIME
52
+ > persistent setup of the GitHub branching integration (the OAuth link, required-status-check
53
+ > rules, and optional persistent integration branch). It is separate from the PER-FEATURE
54
+ > explicit Supabase branches that `cbp-supabase-migrate` creates lazily on first DB change
55
+ > for each feat branch. See [[supabase-branch-lifecycle]] for the per-feature lifecycle.
56
+
51
57
  Track per-item done state:
52
58
  - `github_app_installed` — true if `branching_configured.github_app_installed` is already true
53
59
  - `required_check_enforced` — true if `branching_configured.required_check_enforced` is already true
@@ -82,7 +88,7 @@ Set `github_app_installed = true` in the idempotency tracker (persisted at Step
82
88
 
83
89
  ## Step 4 — GitHub repo: required status check (manual checklist)
84
90
 
85
- Read `branch_config.integration` from `.codebyplan.json`. Determine branches to protect:
91
+ Read `branch_config.integration` from `.codebyplan/git.json`. Determine branches to protect:
86
92
 
87
93
  - Always: `main`
88
94
  - Also: `branch_config.integration` (when set and !== 'main')
@@ -193,7 +199,7 @@ sql_paths = ["./seed.sql"]
193
199
 
194
200
  Reference: [reference/branching-setup.md § 4](reference/branching-setup.md)
195
201
 
196
- ## Step 7 — Write idempotency marker to `.codebyplan.json`
202
+ ## Step 7 — Write idempotency marker to `.codebyplan/shipment.json`
197
203
 
198
204
  Generate the ISO timestamp in the shell first (jq can't produce wall-clock time natively),
199
205
  then merge the marker under `shipment.surfaces.supabase.branching_configured`:
@@ -204,7 +210,7 @@ jq --arg now "$NOW" '.shipment.surfaces.supabase.branching_configured = {
204
210
  enabled_at: $now,
205
211
  github_app_installed: true,
206
212
  required_check_enforced: true
207
- }' .codebyplan.json > .codebyplan.json.tmp && mv .codebyplan.json.tmp .codebyplan.json
213
+ }' .codebyplan/shipment.json > .codebyplan/shipment.json.tmp && mv .codebyplan/shipment.json.tmp .codebyplan/shipment.json
208
214
  ```
209
215
 
210
216
  The three sub-fields:
@@ -26,7 +26,7 @@ Verify: the integration tile now shows the connected repository name.
26
26
  Protect both `main` AND the integration branch (e.g., `development`) so PRs cannot be merged
27
27
  until the Supabase Preview environment passes.
28
28
 
29
- For each branch (`main`, then the integration branch from `.codebyplan.json`
29
+ For each branch (`main`, then the integration branch from `.codebyplan/git.json`
30
30
  `branch_config.integration`):
31
31
 
32
32
  1. **GitHub → Repository → Settings → Branches → Add branch protection rule**.
@@ -94,7 +94,7 @@ migration push.
94
94
 
95
95
  ## 5. Idempotency Marker
96
96
 
97
- After setup completes, `/cbp-supabase-setup` writes to `.codebyplan.json`:
97
+ After setup completes, `/cbp-supabase-setup` writes to `.codebyplan/shipment.json`:
98
98
 
99
99
  ```json
100
100
  {
@@ -115,6 +115,8 @@ fi
115
115
 
116
116
  **If `git checkout` exits non-zero** (typically "would clobber" because a tracked file has unstaged changes that conflict with target's version): surface the raw git error verbatim, stop, do NOT attempt recovery. The user resolves and re-invokes. This is the only case where `/cbp-task-start` halts on branch state.
117
117
 
118
+ **Note — Supabase preview branch**: no Supabase branch is created at this point. Creation is lazy — it happens on the first DB change when `/cbp-supabase-migrate` runs on the feat branch, which provisions a Supabase branch named identically to the git branch. See `cbp-supabase-migrate` Step 2.3 for the creation protocol.
119
+
118
120
  #### 3.4 — Persist + verify
119
121
 
120
122
  After successful switch: