codebyplan 1.13.43 → 1.13.45
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 +5079 -1556
- package/package.json +1 -1
- package/templates/agents/cbp-task-check.md +1 -3
- package/templates/agents/cbp-task-planner.md +8 -6
- package/templates/github-workflows/publish.yml +93 -21
- package/templates/hooks/cbp-auto-test-hooks.sh +1 -0
- package/templates/hooks/cbp-e2e-spec-patterns.sh +100 -0
- package/templates/hooks/cbp-lint-format-on-edit.sh +1 -0
- package/templates/hooks/cbp-maestro-yaml-validate.sh +1 -0
- package/templates/hooks/cbp-pre-commit-quality-gate.sh +1 -0
- package/templates/hooks/cbp-statusline.sh +0 -0
- package/templates/hooks/cbp-subagent-statusline.sh +0 -0
- package/templates/hooks/cbp-test-coverage-gate.sh +1 -0
- package/templates/hooks/cbp-test-hooks.sh +1 -0
- package/templates/hooks/hooks.json +4 -0
- package/templates/hooks/verify-parity.sh +20 -0
- package/templates/rules/parallel-waves.md +8 -3
- package/templates/rules/scope-vocabulary.md +4 -3
- package/templates/settings.project.base.json +22 -0
- package/templates/skills/cbp-build-cc-claude-file/SKILL.md +11 -1
- package/templates/skills/cbp-build-cc-claude-file/scripts/validate-claude-file.sh +72 -0
- package/templates/skills/cbp-build-cc-mode/SKILL.md +12 -16
- package/templates/skills/cbp-build-cc-rule/SKILL.md +11 -1
- package/templates/skills/cbp-build-cc-rule/scripts/validate-rule.sh +69 -0
- package/templates/skills/cbp-build-cc-settings/SKILL.md +2 -2
- package/templates/skills/cbp-build-cc-settings/scripts/validate-settings.sh +67 -0
- package/templates/skills/cbp-checkpoint-create/SKILL.md +12 -4
- package/templates/skills/cbp-checkpoint-end/SKILL.md +19 -11
- package/templates/skills/cbp-git-commit/SKILL.md +10 -12
- package/templates/skills/cbp-git-worktree-create/SKILL.md +7 -48
- package/templates/skills/cbp-git-worktree-remove/SKILL.md +23 -40
- package/templates/skills/cbp-map-architecture/SKILL.md +1 -0
- package/templates/skills/cbp-merge-main/SKILL.md +21 -26
- package/templates/skills/cbp-refresh-arch-map/SKILL.md +1 -0
- package/templates/skills/cbp-round-check/SKILL.md +37 -36
- package/templates/skills/cbp-round-execute/SKILL.md +9 -3
- package/templates/skills/cbp-session-end/SKILL.md +27 -47
- package/templates/skills/cbp-session-start/SKILL.md +35 -51
- package/templates/skills/cbp-standalone-task-start/SKILL.md +10 -19
- package/templates/skills/cbp-supabase-migrate/SKILL.md +24 -27
- package/templates/skills/cbp-task-start/SKILL.md +9 -21
- package/templates/skills/cbp-task-testing/SKILL.md +18 -10
|
@@ -30,7 +30,7 @@ Set `KIND` for the rest of this skill. MCP tool names vary by KIND:
|
|
|
30
30
|
|
|
31
31
|
# Round Check Command
|
|
32
32
|
|
|
33
|
-
Run automated checks independently with mandatory execution. Updates round QA. Hard fails if mandatory checks (
|
|
33
|
+
Run automated checks independently with mandatory execution. Updates round QA. Hard fails if mandatory checks (gate6/lint/typecheck/tests) fail.
|
|
34
34
|
|
|
35
35
|
## Instructions
|
|
36
36
|
|
|
@@ -41,80 +41,80 @@ Use Kind Detection above to set KIND. Then:
|
|
|
41
41
|
- **checkpoint KIND**: Read `.codebyplan/state/checkpoints/<checkpointId>/tasks/<taskId>.json` (local-first) to find active task, then read `.codebyplan/state/checkpoints/<checkpointId>/tasks/<taskId>/rounds/<roundId>.json` to find the in-progress round. If missing/stale, run `npx codebyplan sync` once and re-read. Break-glass fallback: MCP `get_current_task(repo_id)` + `get_rounds(task_id)` when state dir is absent and sync fails.
|
|
42
42
|
- **standalone KIND**: MCP `get_current_standalone_task(repo_id)` to find active task, then `get_standalone_rounds(standalone_task_id)` to find the in-progress round. (Standalone KIND still uses MCP until a later task.)
|
|
43
43
|
|
|
44
|
-
### Step 2:
|
|
44
|
+
### Step 2: Run Core Check Matrix
|
|
45
|
+
|
|
46
|
+
From the repo root, run:
|
|
45
47
|
|
|
46
|
-
Find the correct app directory:
|
|
47
48
|
```bash
|
|
48
|
-
|
|
49
|
+
codebyplan check --scope round --json
|
|
49
50
|
```
|
|
50
|
-
Identify app dir from project structure (e.g., `apps/web/` for Next.js).
|
|
51
51
|
|
|
52
|
-
|
|
52
|
+
Capture the JSON output. The runner is **whole-repo + baseline**: it runs `turbo run lint|typecheck|test` across every package and diffs each per-package result against the committed `.check-baseline.json`, so a pre-existing failure in an unrelated package does NOT fail the check — only a NEW failure does. The result shape is:
|
|
53
53
|
|
|
54
|
-
|
|
54
|
+
```json
|
|
55
|
+
{
|
|
56
|
+
"results": [
|
|
57
|
+
{"check": "gate6"|"lint"|"typecheck"|"tests"|"audit", "status": "pass"|"fail"|"skipped",
|
|
58
|
+
"exit_code": number|null, "command": string, "stdout": string, "stderr": string,
|
|
59
|
+
"executed": boolean, "new_failures"?: string[]}
|
|
60
|
+
],
|
|
61
|
+
"any_failed": boolean,
|
|
62
|
+
"hard_fail_checks": [ ...names of checks that FAILED ]
|
|
63
|
+
}
|
|
64
|
+
```
|
|
55
65
|
|
|
56
|
-
|
|
57
|
-
|-------|---------|-----------|
|
|
58
|
-
| **Build** | `cd {app_dir} && npm run build 2>&1` | YES |
|
|
59
|
-
| **Lint** | `cd {app_dir} && npm run lint 2>&1` | YES |
|
|
60
|
-
| **Types** | `cd {app_dir} && npx tsc --noEmit 2>&1` | YES |
|
|
66
|
+
Five checks run in order: `gate6` (sibling-identity parity — `node scripts/check-sibling-identity.mjs`), `lint`, `typecheck`, `tests`, `audit`. For the baselined checks (`lint`/`typecheck`/`tests`) `new_failures` lists the packages that newly fail (not in the baseline); `status` is `pass` when `new_failures` is empty **even if the underlying command exited non-zero** (those failures are pre-existing/baselined). `audit.new_failures` lists new GHSA advisory ids not in the allowlist. **`gate6` is ALWAYS hard-fail — it is never baselined**; its `new_failures` field is omitted (absent/`undefined` in the JSON, not `null`), and a sibling-parity divergence fails the round regardless of the baseline.
|
|
61
67
|
|
|
62
|
-
|
|
63
|
-
- Run the command via Bash tool
|
|
64
|
-
- Log `EXECUTED: <command>` or `FAILED: <command> (exit code: N)`
|
|
65
|
-
- If skipping (infrastructure-only changes): log `SKIPPED: <command> (reason: no app code changed)`
|
|
68
|
+
`hard_fail_checks` is dynamic — it lists only the checks that failed (`[]` when all pass; e.g. `["gate6"]` or `["typecheck","tests"]`), drawn from `results[].check`. The hard-fail checks for `--scope round` are `gate6`, `lint`, `typecheck`, and `tests` (`audit` is `--scope task` only). If `any_failed === true` (equivalently, `hard_fail_checks` is non-empty), this is a **hard fail** — surface each failing result's `stdout`/`stderr` (and `new_failures`) and stop.
|
|
66
69
|
|
|
67
|
-
### Step
|
|
70
|
+
### Step 3: Execute Conditional Checks
|
|
68
71
|
|
|
69
72
|
| Check | Command | Condition |
|
|
70
73
|
|-------|---------|-----------|
|
|
71
|
-
| **Tests** | `cd {app_dir} && npx vitest --run 2>&1` | Test files exist |
|
|
72
74
|
| **A11y** | Static check (aria, alt, focus) | UI files changed |
|
|
73
75
|
| **API Health** | `curl -s -o /dev/null -w "%{http_code}" http://localhost:{PORT}/` | API routes changed |
|
|
74
76
|
| **Visual** | Visual check flow (page-map + visual-check) | UI work + dev server running |
|
|
75
77
|
|
|
76
|
-
### Step
|
|
78
|
+
### Step 4: Analyze Output
|
|
77
79
|
|
|
78
|
-
Scan
|
|
80
|
+
Scan each runner result's `stdout`/`stderr` for:
|
|
79
81
|
- **Warnings** (not just errors)
|
|
80
82
|
- **Deprecation notices** (`grep -i "deprecat"` in output)
|
|
81
83
|
- **Console.log in changed files**: `grep -rn "console\.\(log\|debug\|info\)" {changed_files}` (exclude tests)
|
|
82
84
|
- **Bundle size warnings**
|
|
83
85
|
|
|
84
|
-
### Step
|
|
86
|
+
### Step 5: Save QA Results
|
|
85
87
|
|
|
86
88
|
Update round QA:
|
|
87
89
|
- **checkpoint KIND**: `codebyplan round update --id <round_id> --task-id <task_id> --checkpoint-id <checkpoint_id> --qa '<json>'` (CLI write-through: local state file + REST). Break-glass fallback: MCP `update_round(round_id, qa: ...)` when the CLI is unavailable.
|
|
88
90
|
- **standalone KIND**: MCP `update_standalone_round(standalone_round_id, qa: ...)`. (Standalone KIND still uses MCP until a later task.)
|
|
89
91
|
|
|
92
|
+
Map each runner result entry to a QA item:
|
|
93
|
+
|
|
90
94
|
```json
|
|
91
95
|
{
|
|
92
96
|
"items": [
|
|
93
|
-
{"type": "auto", "check": "
|
|
94
|
-
{"type": "auto", "check": "lint", "status": "
|
|
95
|
-
{"type": "auto", "check": "
|
|
96
|
-
{"type": "auto", "check": "tests", "status": "
|
|
97
|
+
{"type": "auto", "check": "gate6", "status": "pass", "ran_at": "...", "notes": null, "executed": true},
|
|
98
|
+
{"type": "auto", "check": "lint", "status": "pass", "ran_at": "...", "notes": null, "executed": true},
|
|
99
|
+
{"type": "auto", "check": "typecheck", "status": "fail", "ran_at": "...", "notes": "1 new failing package", "executed": true},
|
|
100
|
+
{"type": "auto", "check": "tests", "status": "pass", "ran_at": "...", "notes": "no new failures (baselined)", "executed": true}
|
|
97
101
|
]
|
|
98
102
|
}
|
|
99
103
|
```
|
|
100
104
|
|
|
101
|
-
### Step
|
|
105
|
+
### Step 6: Show Results
|
|
102
106
|
|
|
103
107
|
```
|
|
104
108
|
## Round Check Results
|
|
105
109
|
|
|
106
110
|
| Check | Status | Executed | Notes |
|
|
107
111
|
|-------|--------|----------|-------|
|
|
108
|
-
|
|
|
109
|
-
|
|
|
110
|
-
|
|
|
111
|
-
|
|
|
112
|
-
|
|
|
113
|
-
|
|
114
|
-
### Build Analysis
|
|
115
|
-
- Warnings: [N]
|
|
116
|
-
- Deprecations: [N]
|
|
117
|
-
- Console.logs in code: [N]
|
|
112
|
+
| gate6 | pass | yes | sibling-identity OK |
|
|
113
|
+
| lint | pass | yes | - |
|
|
114
|
+
| typecheck | fail | yes | 1 new failing package |
|
|
115
|
+
| tests | pass | yes | no new failures (baselined) |
|
|
116
|
+
| A11y | pass | yes | - |
|
|
117
|
+
| Visual| pass | yes | screenshots saved |
|
|
118
118
|
|
|
119
119
|
**Result**: [N] passed, [N] failed, [N] skipped
|
|
120
120
|
**Hard fail**: [yes/no]
|
|
@@ -129,4 +129,5 @@ If soft failures only: `Run /cbp-round-start to trigger auto-fix, or fix manuall
|
|
|
129
129
|
- **Reads (standalone KIND)**: MCP `get_current_standalone_task` / `get_standalone_rounds` (standalone KIND still uses MCP until a later task)
|
|
130
130
|
- **Writes (checkpoint KIND)**: `codebyplan round update` (qa field). Break-glass: MCP `update_round`.
|
|
131
131
|
- **Writes (standalone KIND)**: MCP `update_standalone_round` (qa field). (Standalone KIND still uses MCP until a later task.)
|
|
132
|
+
- **Runner**: `codebyplan check --scope round --json` (whole-repo + baseline via `turbo run`; runs gate6 + lint + typecheck + tests; `--files` is accepted but ignored in whole-repo mode)
|
|
132
133
|
- **Standalone**: Can be run independently at any time
|
|
@@ -178,7 +178,13 @@ Per-wave hard-fail signal — true when ANY hold:
|
|
|
178
178
|
|
|
179
179
|
- `testing_qa_output.totals.hard_fail === true`.
|
|
180
180
|
- For any framework `f` in `round.context.e2e_outputs`: `e2e_outputs[f].status === 'failed'` OR `e2e_outputs[f].test_results?.failed > 0`.
|
|
181
|
-
-
|
|
181
|
+
- **E2E deterministic gate** (replaces the former judgment-based `e2e_eligible_skipped` evaluation): when `round.context.e2e_eligible[]` is non-empty, first persist `e2e_eligible` / `e2e_outputs` to round context via MCP `update_round` (the Step 7 write, pulled forward — the CLI reads the round row from the DB), then run:
|
|
182
|
+
|
|
183
|
+
```bash
|
|
184
|
+
codebyplan e2e verify-round --round-id <round_id> --task-id <task_id>
|
|
185
|
+
```
|
|
186
|
+
|
|
187
|
+
Exit 0 = e2e pass. Exit 1 = one or more deterministic hard-fails — the stdout JSON's `failed_checks[]` identifies which (`e2e_eligible_skipped`, `zero_assertion_run`, `empty_gallery`); the `rules/e2e-mandatory.md` valid-skip list and the vscode-test empty-gallery exception are honored by the CLI. When `e2e_eligible[]` is empty, skip the CLI call — nothing to verify.
|
|
182
188
|
|
|
183
189
|
**All waves hard_fail: false** → proceed to Step 7. **Any wave hard_fail: true**:
|
|
184
190
|
|
|
@@ -197,9 +203,9 @@ When `cbp-testing-qa-agent` spawn fails OR the resolved `testing_profile` is `cl
|
|
|
197
203
|
|
|
198
204
|
`codebyplan round update --id <round-id> --task-id <uuid> --checkpoint-id <uuid> --context <json>` (CLI write-through: local state at `.codebyplan/state/checkpoints/<checkpointId>/tasks/<taskId>/rounds/<roundId>.json` + REST). Break-glass fallback: MCP `update_round` when the CLI is unavailable.
|
|
199
205
|
|
|
200
|
-
- `context`: { ...existing, executor_output, testing_qa_output, e2e_eligible, e2e_outputs, frontend_ui_review }
|
|
206
|
+
- `context`: { ...existing, executor_output, testing_qa_output, e2e_eligible, e2e_outputs, frontend_ui_review } — when e2e ran, `e2e_eligible` / `e2e_outputs` were already persisted by the Step 6 pull-forward write; re-include them in this merge payload (the `update_round` REPLACE contract requires re-sending every field that should remain — this is a consolidating merge, not a second write of new data).
|
|
201
207
|
|
|
202
|
-
`e2e_outputs` (a framework-keyed map of specialist outputs, e.g. `{ playwright: {...}, maestro: {...} }`)
|
|
208
|
+
`e2e_outputs` (a framework-keyed map of specialist outputs, e.g. `{ playwright: {...}, maestro: {...} }`) is present when ≥1 eligible framework ran. `frontend_ui_review` is present only when ≥1 eligible framework ran AND Step 5b ran (non-empty screenshots). `e2e_eligible[]` records which frameworks were eligible this round and drives the Step 6 E2E deterministic gate.
|
|
203
209
|
|
|
204
210
|
### Step 8: Auto-trigger Round End
|
|
205
211
|
|
|
@@ -56,15 +56,12 @@ Continuing Step 1:
|
|
|
56
56
|
|
|
57
57
|
Same rule as `/cbp-session-start` Step 5.7 — only commit files that are **not** part of an unfinished task.
|
|
58
58
|
|
|
59
|
-
1.
|
|
60
|
-
|
|
61
|
-
-
|
|
62
|
-
- If active task exists
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
3. `infra_files = changed_files − task_files`
|
|
66
|
-
4. Re-run `git status --porcelain` immediately before showing the commit-prompt (after Steps 1–1.3 have completed their round-trips). Recompute `infra_files` from the fresh listing — eliminates the race where files appear in the index only after network round-trips complete.
|
|
67
|
-
5. If `infra_files` is empty → skip. Otherwise present once:
|
|
59
|
+
1. Resolve the active task's round files (local-first):
|
|
60
|
+
- Read `.codebyplan/state/todos.json` (local-first; reuse the Step 1.3 result if already fetched) to identify the active task id. Break-glass fallback: MCP `get_current_task(repo_id)` when the state dir is absent and sync fails.
|
|
61
|
+
- If active task exists: read `.codebyplan/state/checkpoints/<checkpoint_id>/tasks/<task_id>/rounds/` and filter to rounds with status not in `completed` / `cancelled`; collect their `files[]` → `task_files` set. Break-glass fallback: MCP `get_rounds(task_id)`.
|
|
62
|
+
- If no active task exists, `task_files` is empty.
|
|
63
|
+
2. Run `codebyplan session infra-files --json --task-files "<csv>"` where `<csv>` is the comma-separated task files from step 1. Parse the JSON response (`{ infra_files: string[], task_files: string[], note?: string }`). The CLI re-runs `git status --porcelain` internally and applies the set-math deterministically — the race-safe recompute, reading the index after Steps 1–1.3 round-trips complete.
|
|
64
|
+
3. If `infra_files` is empty → skip. Otherwise present once:
|
|
68
65
|
|
|
69
66
|
```
|
|
70
67
|
Commit these non-task files before ending session?
|
|
@@ -73,7 +70,7 @@ Same rule as `/cbp-session-start` Step 5.7 — only commit files that are **not*
|
|
|
73
70
|
Reply: yes | no | select
|
|
74
71
|
```
|
|
75
72
|
|
|
76
|
-
|
|
73
|
+
4. On `yes`: `git add` the listed files, then trigger `/cbp-git-commit`.
|
|
77
74
|
On `no`: skip. On `select`: ask which subset.
|
|
78
75
|
|
|
79
76
|
Non-blocking — session end proceeds either way.
|
|
@@ -84,22 +81,11 @@ Keep this worktree's **home branch** rooted at the freshest production tip — n
|
|
|
84
81
|
|
|
85
82
|
Runs after Step 1.5 so any infra commits land first, and before Step 1.7 so the freshness gate's asset update operates on the freshest tree.
|
|
86
83
|
|
|
87
|
-
|
|
84
|
+
Run `codebyplan session home-ff` and parse the JSON output (`{ result: 'skipped'|'warn'|'fast_forwarded', reason?, warn? }`):
|
|
88
85
|
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
```
|
|
93
|
-
|
|
94
|
-
- **`$CURRENT` != `$FOLDER`** (a `feat/*` or any non-home branch): skip silently — no fetch, no output.
|
|
95
|
-
- **`$CURRENT` == `$FOLDER`** (home branch): fast-forward to `origin/$PRODUCTION`, warning once per failure and continuing:
|
|
96
|
-
|
|
97
|
-
```bash
|
|
98
|
-
git fetch origin "$PRODUCTION" 2>/dev/null \
|
|
99
|
-
|| echo "⚠ home-branch ff: fetch failed — staying on local $CURRENT"
|
|
100
|
-
git merge --ff-only "origin/$PRODUCTION" 2>/dev/null \
|
|
101
|
-
|| echo "⚠ home-branch ff: $CURRENT not fast-forwardable (ahead/diverged) — left untouched"
|
|
102
|
-
```
|
|
86
|
+
- **`result === 'skipped'`** (non-home branch or production mismatch): proceed silently.
|
|
87
|
+
- **`result === 'warn'`** (fast-forward attempt failed): surface the `warn` field as one line, then proceed silently.
|
|
88
|
+
- **`result === 'fast_forwarded'`** (home branch updated): proceed silently.
|
|
103
89
|
|
|
104
90
|
Never rebase, reset, force-push, or stash. A non-fast-forwardable home branch is a signal to reconcile manually, not to overwrite.
|
|
105
91
|
|
|
@@ -107,31 +93,25 @@ Never rebase, reset, force-push, or stash. A non-fast-forwardable home branch is
|
|
|
107
93
|
|
|
108
94
|
Check whether a newer `codebyplan` is published and safe to auto-install on this worktree's current branch, then run the local install + asset update. Runs after the Step 1.6 home-branch fast-forward (so any update lands on the freshest tree) and before Step 2. Fully non-blocking — the guard and skip branches proceed silently; any failure in the install/update commands warns once and continues to Step 2. session-end never halts.
|
|
109
95
|
|
|
110
|
-
|
|
111
|
-
VERSION_JSON=$(npx codebyplan version-status 2>/dev/null)
|
|
112
|
-
```
|
|
113
|
-
|
|
114
|
-
Parse `$VERSION_JSON` as JSON and branch on the result:
|
|
96
|
+
Run `codebyplan session freshness-gate` (WITHOUT `--halt-on-update`; session-end is continue-only) and parse the JSON output (`{ result: 'skipped'|'guarded'|'up_to_date'|'updated'|'error', ... }`):
|
|
115
97
|
|
|
116
|
-
- **Probe failed
|
|
117
|
-
- **`
|
|
118
|
-
- **`
|
|
119
|
-
- **`
|
|
120
|
-
|
|
121
|
-
2. Run `npx codebyplan claude update` to refresh the worktree's `.claude/` assets on the current branch. If `installCommand` (step 1) or this command exits non-zero, warn once and skip to Step 2 — this path is non-blocking.
|
|
122
|
-
3. Detect changes across BOTH asset directories in one pass: `git status --porcelain -- .claude/ .codebyplan/`. If non-empty, present a single combined offer (same pattern as Step 1.5):
|
|
98
|
+
- **Probe failed** — the command errored or output cannot be parsed as JSON. → **FAIL-SAFE SKIP**: proceed silently to Step 2. A best-effort freshness probe must never disrupt session-end.
|
|
99
|
+
- **`result === 'skipped'` / `'guarded'` / `'up_to_date'`** → skip silently, proceed to Step 2. Gate on the `result` field only. This guard prevents clobbering the canonical monorepo's ahead-of-published `.claude/` and blocks any update or commit on a protected branch.
|
|
100
|
+
- **`result === 'error'`** → fail-safe skip, proceed to Step 2.
|
|
101
|
+
- **`result === 'updated'`** → the CLI already ran the install + `npx codebyplan claude update`. Parse the JSON response:
|
|
102
|
+
- If `changed_files[]` is present and non-empty, present a single combined offer (same pattern as Step 1.5):
|
|
123
103
|
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
104
|
+
```
|
|
105
|
+
codebyplan updated. Commit these changes before ending the session?
|
|
106
|
+
[list of changed paths under .claude/ and .codebyplan/]
|
|
127
107
|
|
|
128
|
-
|
|
129
|
-
|
|
108
|
+
Reply: yes | no | select
|
|
109
|
+
```
|
|
130
110
|
|
|
131
|
-
|
|
132
|
-
|
|
111
|
+
On `yes`: `git add` the listed paths only (not the whole directories), then trigger `/cbp-git-commit`. On `no`: skip. On `select`: ask which subset.
|
|
112
|
+
- Continue to Step 2 — session-end does NOT halt. The update lands in the current worktree on its current branch; main/protected branches and the canonical source repo are already excluded by the `result !== 'guarded'` check above.
|
|
133
113
|
|
|
134
|
-
**Home branches are intentionally not guarded.** A worktree's folder-named home branch (e.g. `codebyplan-web`) is neither protected/main nor the canonical source, so
|
|
114
|
+
**Home branches are intentionally not guarded.** A worktree's folder-named home branch (e.g. `codebyplan-web`) is neither protected/main nor the canonical source, so the freshness gate returns `result !== 'guarded'` there and this gate runs the update exactly as on a feat branch — landing it on whichever branch the worktree currently rests on (the deliberate "update the branch they're on, except main/canonical" behavior).
|
|
135
115
|
|
|
136
116
|
Non-blocking — session end proceeds regardless of outcome.
|
|
137
117
|
|
|
@@ -170,9 +150,9 @@ You can close this window.
|
|
|
170
150
|
## Integration
|
|
171
151
|
|
|
172
152
|
- **Triggered by**: user invocation (prompted by `/cbp-todo` when no work remains)
|
|
173
|
-
- **Reads**: `.codebyplan/repo.json`, `.codebyplan/git.json` (`branch_config.production` for the Step 1.6 home-branch fast-forward); local-first reads (with `npx codebyplan sync` + MCP break-glass): `.codebyplan/state/session/current.json` (Step 1 resolve log), `.codebyplan/state/todos.json` (Step 1.3 handoff snapshot + Step 1.5 active-task lookup), `.codebyplan/state/checkpoints/<id>/tasks/<id>/rounds/` (Step 1.5 task-file resolution); `
|
|
153
|
+
- **Reads**: `.codebyplan/repo.json`, `.codebyplan/git.json` (`branch_config.production` for the Step 1.6 home-branch fast-forward); local-first reads (with `npx codebyplan sync` + MCP break-glass): `.codebyplan/state/session/current.json` (Step 1 resolve log), `.codebyplan/state/todos.json` (Step 1.3 handoff snapshot + Step 1.5 active-task lookup), `.codebyplan/state/checkpoints/<id>/tasks/<id>/rounds/` (Step 1.5 task-file resolution); `codebyplan session home-ff` (Step 1.6 home-branch fast-forward); `codebyplan session freshness-gate` (Step 1.7 package-freshness gate, without --halt-on-update); `codebyplan session infra-files --json --task-files <csv>` (Step 1.5 infra-file set math)
|
|
174
154
|
- **Writes**: `codebyplan session update-log --id <id> ...` (Step 1 finalize — CLI write-through to `.codebyplan/state/session/current.json`; break-glass: MCP `update_session_log`), `codebyplan session create-log` (Step 1 fallback when no log exists; break-glass: MCP `create_session_log`), `codebyplan session update-state --action deactivate` (Step 3 — CLI write-through to `.codebyplan/state/session/state.json`; break-glass: MCP `update_session_state`)
|
|
175
155
|
- **Spawns**: none
|
|
176
|
-
- **Triggers**: none at the skill-contract level. Step 1.5 may invoke `/cbp-git-commit` inline on user approval; Step 1.7 may invoke `/cbp-git-commit` on the `
|
|
156
|
+
- **Triggers**: none at the skill-contract level. Step 1.5 may invoke `/cbp-git-commit` inline on user approval; Step 1.7 may invoke `/cbp-git-commit` on the `result === 'updated'` path (committing changed `.claude/` and `.codebyplan/` paths).
|
|
177
157
|
- **Paired with**: `/cbp-session-start`
|
|
178
158
|
- **Pairs with**: `/cbp-session-start` Step 4.5 (handoff payload shape + freshness-gate contract; specified inline — no separate rule file)
|
|
@@ -55,22 +55,11 @@ Pass `WORKTREE_ID` to MCP tools that support it. Null `WORKTREE_ID` means the (d
|
|
|
55
55
|
|
|
56
56
|
Keep this worktree's **home branch** rooted at the freshest production tip — no prompt, fully non-blocking. Home branches are the folder-named placeholder branches each worktree rests on (e.g. `codebyplan-web`); `feat/*` branches are deliberately skipped — they integrate via `/cbp-merge-main` with QA, never an auto fast-forward.
|
|
57
57
|
|
|
58
|
-
|
|
58
|
+
Run `codebyplan session home-ff` and parse the JSON output (`{ result: 'skipped'|'warn'|'fast_forwarded', reason?, warn? }`):
|
|
59
59
|
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
```
|
|
64
|
-
|
|
65
|
-
- **`$CURRENT` != `$FOLDER`** (a `feat/*` or any non-home branch): skip silently — no fetch, no output.
|
|
66
|
-
- **`$CURRENT` == `$FOLDER`** (home branch): fast-forward to `origin/$PRODUCTION`, warning once per failure and continuing:
|
|
67
|
-
|
|
68
|
-
```bash
|
|
69
|
-
git fetch origin "$PRODUCTION" 2>/dev/null \
|
|
70
|
-
|| echo "⚠ home-branch ff: fetch failed — staying on local $CURRENT"
|
|
71
|
-
git merge --ff-only "origin/$PRODUCTION" 2>/dev/null \
|
|
72
|
-
|| echo "⚠ home-branch ff: $CURRENT not fast-forwardable (ahead/diverged) — left untouched"
|
|
73
|
-
```
|
|
60
|
+
- **`result === 'skipped'`** (non-home branch or production mismatch): proceed silently.
|
|
61
|
+
- **`result === 'warn'`** (fast-forward attempt failed): surface the `warn` field as one line, then proceed silently.
|
|
62
|
+
- **`result === 'fast_forwarded'`** (home branch updated): proceed silently.
|
|
74
63
|
|
|
75
64
|
Never rebase, reset, force-push, or stash. A non-fast-forwardable home branch is a signal to reconcile manually, not to overwrite.
|
|
76
65
|
|
|
@@ -123,40 +112,38 @@ binary simply yields a zero count and no line.
|
|
|
123
112
|
|
|
124
113
|
Check whether a newer `codebyplan` is published and safe to auto-install on this worktree's current branch. Runs AFTER the architecture-map drift check (Step 1.55) and BEFORE session activation (Step 3).
|
|
125
114
|
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
115
|
+
Run `codebyplan session freshness-gate --halt-on-update` and parse the JSON output (`{ result: 'skipped'|'guarded'|'up_to_date'|'updated'|'error', ... }`):
|
|
116
|
+
|
|
117
|
+
- **Probe failed** — the command errored or output cannot be parsed as JSON. → **FAIL-SAFE SKIP**: proceed silently to Step 3. Never disrupt a session over a best-effort freshness probe — the MCP gate (Step 0) is the only vital gate.
|
|
118
|
+
- **`result === 'skipped'` / `'guarded'` / `'up_to_date'`** → skip silently, proceed to Step 3. Gate on the `result` field only.
|
|
119
|
+
- **`result === 'error'`** → fail-safe skip, proceed to Step 3.
|
|
120
|
+
- **`result === 'updated'`** → the CLI already ran the install + `npx codebyplan claude update`. Parse the JSON response:
|
|
121
|
+
- If `changed_files[]` is present and non-empty, offer the same commit gate as Step 5.7:
|
|
131
122
|
|
|
132
|
-
|
|
123
|
+
```
|
|
124
|
+
codebyplan updated. Commit the resulting .claude/ and .codebyplan/ changes before exiting?
|
|
125
|
+
[list of changed paths under .claude/ and .codebyplan/]
|
|
133
126
|
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
- **`newer: false`** (already up to date) → skip silently, proceed to Step 3.
|
|
137
|
-
- **`newer: true` AND `guarded: false`** → run the update path:
|
|
138
|
-
1. Run the JSON's `installCommand` (e.g. `pnpm add codebyplan@latest`) to LOCALLY install `codebyplan@latest` via the repo's package manager. Never a global `-g` install.
|
|
139
|
-
2. Run `npx codebyplan claude update` to refresh the worktree's `.claude/` assets on the current branch.
|
|
140
|
-
3. Detect changes across BOTH asset directories in one pass: `git status --porcelain -- .claude/ .codebyplan/`. If non-empty, offer the same commit gate as Step 5.7:
|
|
127
|
+
Reply: yes | no | select
|
|
128
|
+
```
|
|
141
129
|
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
[list of changed paths under .claude/ and .codebyplan/]
|
|
130
|
+
On `yes`: `git add` the listed paths only, then trigger `/cbp-git-commit`. On `no`: skip. On `select`: ask which subset.
|
|
131
|
+
- **HALT** — do NOT proceed to Step 3. Print:
|
|
145
132
|
|
|
146
|
-
|
|
147
|
-
|
|
133
|
+
```
|
|
134
|
+
✓ codebyplan updated. Start a FRESH Claude Code session
|
|
135
|
+
(run /clear or open a new window) so the updated .claude/ takes effect.
|
|
136
|
+
```
|
|
148
137
|
|
|
149
|
-
|
|
150
|
-
4. **HALT** — do NOT proceed to Step 3. Print:
|
|
138
|
+
On this update-and-halt path the session is NOT continued: `update_session_state(activate)` is NOT called, `create_session_log` is NOT called, and `/cbp-todo` is NOT triggered.
|
|
151
139
|
|
|
152
|
-
|
|
153
|
-
✓ codebyplan updated to {latest}. Start a FRESH Claude Code session
|
|
154
|
-
(run /clear or open a new window) so the updated .claude/ takes effect.
|
|
155
|
-
```
|
|
140
|
+
**Home branches are intentionally not guarded.** A worktree's folder-named home branch (e.g. `codebyplan-web`) is neither protected/main nor the canonical source, so the freshness gate returns `result !== 'guarded'` there and this gate fires exactly as on a feat branch. That is deliberate — the update lands on whatever branch the worktree is currently resting on (the "update the branch they're on, except main/canonical" decision), not an accidental halt.
|
|
156
141
|
|
|
157
|
-
|
|
142
|
+
Populate the claude-status cache best-effort (pure cache population — never gates session-start):
|
|
158
143
|
|
|
159
|
-
|
|
144
|
+
```bash
|
|
145
|
+
npx codebyplan claude status --write-cache --quiet 2>/dev/null || true
|
|
146
|
+
```
|
|
160
147
|
|
|
161
148
|
### Step 1.7: LSP Binary Nudge
|
|
162
149
|
|
|
@@ -221,15 +208,12 @@ Probe the most-recent closed session log for a structured handoff payload (the h
|
|
|
221
208
|
|
|
222
209
|
Clean the working tree of leftover infra before the session begins. Only commit files that are **not** part of an unfinished task.
|
|
223
210
|
|
|
224
|
-
1.
|
|
225
|
-
2. Resolve **task-related files** (leave these uncommitted):
|
|
211
|
+
1. Resolve the active task's round files (local-first):
|
|
226
212
|
- Read `.codebyplan/state/todos.json` (local-first) to identify the active task id. If missing/stale, run `npx codebyplan sync` once and re-read. Break-glass fallback: MCP `get_current_task(repo_id)` when the state dir is absent and sync fails.
|
|
227
|
-
- If active task exists: read `.codebyplan/state/checkpoints/<checkpoint_id>/tasks/<task_id>/rounds/`
|
|
228
|
-
-
|
|
229
|
-
|
|
230
|
-
3. `infra_files
|
|
231
|
-
4. **Re-run `git status --porcelain` immediately before showing the commit-prompt** (after Steps 0–5 have completed all their round-trips). Eliminates the race where prior-session staged files appear in the index only after network round-trips complete. Recompute `infra_files` from the fresh listing.
|
|
232
|
-
5. If `infra_files` is empty → skip. Otherwise present once:
|
|
213
|
+
- If active task exists: read `.codebyplan/state/checkpoints/<checkpoint_id>/tasks/<task_id>/rounds/` and filter to rounds with status not in `completed` / `cancelled`; collect their `files[]` → `task_files` set. Break-glass fallback: MCP `get_rounds(task_id)`.
|
|
214
|
+
- If no active task exists, `task_files` is empty.
|
|
215
|
+
2. Run `codebyplan session infra-files --json --task-files "<csv>"` where `<csv>` is the comma-separated task files from step 1. Parse the JSON response (`{ infra_files: string[], task_files: string[], note?: string }`). The CLI re-runs `git status --porcelain` internally and applies the set-math deterministically — the race-safe recompute, reading the index after Steps 0–5 round-trips complete.
|
|
216
|
+
3. If `infra_files` is empty → skip. Otherwise present once:
|
|
233
217
|
|
|
234
218
|
```
|
|
235
219
|
Commit these non-task files before starting session?
|
|
@@ -238,7 +222,7 @@ Clean the working tree of leftover infra before the session begins. Only commit
|
|
|
238
222
|
Reply: yes | no | select
|
|
239
223
|
```
|
|
240
224
|
|
|
241
|
-
|
|
225
|
+
4. On `yes`: `git add` the listed files, then trigger `/cbp-git-commit` (it handles conventional message + commit).
|
|
242
226
|
On `no`: skip. On `select`: ask which subset.
|
|
243
227
|
|
|
244
228
|
Non-blocking — session start proceeds either way.
|
|
@@ -288,7 +272,7 @@ Three-branch gate using `owned_count` and `total_count` from Step 5.8:
|
|
|
288
272
|
|
|
289
273
|
- **Triggered by**: user invocation, `/clear` recovery
|
|
290
274
|
- **Resolves**: `npx codebyplan resolve-worktree --json` (worktree id + distress signal; non-tuple-miss distress is non-blocking at session-start)
|
|
291
|
-
- **Reads**: `.codebyplan/repo.json`, `.codebyplan/git.json` (`branch_config.production` for the Step 1.4 home-branch fast-forward), MCP `health_check` (Step 0 hard gate — stays MCP unconditionally); local-first reads (with `npx codebyplan sync` + MCP break-glass): `.codebyplan/state/session/current.json` (Step 4 previous log + Step 4.5 handoff probe), `.codebyplan/state/checkpoints/<id>.json` / `tasks/<id>.json` / `rounds/<id>.json` (Step 4.5 freshness probe), `.codebyplan/state/todos.json` (Step 5.7 active-task lookup); MCP `get_checkpoints({ repo_id, status: 'active' })` (Step 5.8 ownership partition — MCP only, no local mirror for active-filter query); `scripts/infra-drift.mjs` + a best-effort `git fetch` (Step 1.5 monorepo drift); `npx codebyplan arch-map drift` + `.codebyplan/architecture.json` presence (Step 1.55 architecture-map drift nudge, non-blocking); `
|
|
275
|
+
- **Reads**: `.codebyplan/repo.json`, `.codebyplan/git.json` (`branch_config.production` for the Step 1.4 home-branch fast-forward), MCP `health_check` (Step 0 hard gate — stays MCP unconditionally); local-first reads (with `npx codebyplan sync` + MCP break-glass): `.codebyplan/state/session/current.json` (Step 4 previous log + Step 4.5 handoff probe), `.codebyplan/state/checkpoints/<id>.json` / `tasks/<id>.json` / `rounds/<id>.json` (Step 4.5 freshness probe), `.codebyplan/state/todos.json` (Step 5.7 active-task lookup); MCP `get_checkpoints({ repo_id, status: 'active' })` (Step 5.8 ownership partition — MCP only, no local mirror for active-filter query); `scripts/infra-drift.mjs` + a best-effort `git fetch` (Step 1.5 monorepo drift); `npx codebyplan arch-map drift` + `.codebyplan/architecture.json` presence (Step 1.55 architecture-map drift nudge, non-blocking); `codebyplan session home-ff` (Step 1.4 home-branch fast-forward); `codebyplan session freshness-gate --halt-on-update` (Step 1.6 package-freshness gate); `codebyplan session infra-files --json --task-files <csv>` (Step 5.7 infra-file set math); `npx codebyplan lsp --check` (Step 1.7 LSP binary nudge — reads `.codebyplan/lsp.json`, non-blocking). Reads at Step 3 and later do NOT fire on a Step 0 MCP hard-fail or the Step 1.6 update-and-halt path
|
|
292
276
|
- **Writes**: `codebyplan session create-log` (Step 5 — CLI write-through; break-glass: MCP `create_session_log`), `codebyplan session update-state --action activate` (Step 3 — CLI write-through to `.codebyplan/state/session/state.json`; break-glass: MCP `update_session_state`) — both SKIPPED on a Step 0 MCP hard-fail and on the Step 1.6 update-and-halt path
|
|
293
277
|
- **Spawns**: none
|
|
294
278
|
- **Triggers**: `/cbp-git-commit` (conditional, on user approval at Step 5.7 or the Step 1.6 update path), `handoff.command` (on fresh handoff hit at Step 4.5), `/cbp-todo` (auto fall-through when owned_count >= 1 or total_count === 0; STOPS with no trigger when total_count >= 1 AND owned_count === 0; NOT triggered on a Step 0 hard-fail or the Step 1.6 update-and-halt path)
|
|
@@ -66,9 +66,7 @@ Compute `TARGET`:
|
|
|
66
66
|
| Task type | TARGET |
|
|
67
67
|
|-----------|--------|
|
|
68
68
|
| Standalone, `task.branch_name` set | `task.branch_name` |
|
|
69
|
-
| Standalone, `branch_name` null | `feat/standalone-TASK-{N}-{
|
|
70
|
-
|
|
71
|
-
Slug rules: lowercase, words joined by `-`, drop punctuation, truncate to 40 chars.
|
|
69
|
+
| Standalone, `branch_name` null | `feat/standalone-TASK-{N}-{slug}` where slug is computed via `codebyplan slug "{task title}"` |
|
|
72
70
|
|
|
73
71
|
#### 3.2 — Compare current branch
|
|
74
72
|
|
|
@@ -76,26 +74,19 @@ Run `git branch --show-current`. If `current == TARGET` → continue to Step 3b.
|
|
|
76
74
|
|
|
77
75
|
#### 3.3 — Switch automatically (no AskUserQuestion, no blocking)
|
|
78
76
|
|
|
77
|
+
Run the branch checkout via the deterministic CLI:
|
|
78
|
+
|
|
79
79
|
```bash
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
# (b) target exists on origin (track it)
|
|
85
|
-
elif git rev-parse --verify "origin/$TARGET" >/dev/null 2>&1; then
|
|
86
|
-
git checkout -t "origin/$TARGET"
|
|
87
|
-
|
|
88
|
-
# (c) target doesn't exist — create from production branch
|
|
89
|
-
else
|
|
90
|
-
git fetch origin "$PRODUCTION" 2>/dev/null || true
|
|
91
|
-
git checkout -b "$TARGET" "origin/$PRODUCTION" 2>/dev/null \
|
|
92
|
-
|| git checkout -b "$TARGET" "$PRODUCTION"
|
|
93
|
-
fi
|
|
80
|
+
RESULT=$(codebyplan branch checkout --target "$TARGET" --production "$PRODUCTION")
|
|
81
|
+
# Parse JSON: { action: "checked_out_local" | "checked_out_tracking" | "created_from_production" | "error", branch, previous?, error? }
|
|
82
|
+
ACTION=$(echo "$RESULT" | jq -r '.action')
|
|
94
83
|
```
|
|
95
84
|
|
|
96
|
-
|
|
85
|
+
**Interpreting the result:**
|
|
86
|
+
- `action === "error"`: surface the raw `error` field verbatim and stop.
|
|
87
|
+
- Otherwise (all success actions): branch is now `TARGET`. Continue to Step 3.4.
|
|
97
88
|
|
|
98
|
-
|
|
89
|
+
No `git stash`, ever (per `git-safety.md`). No `git add`, ever (per `git-workflow.md`).
|
|
99
90
|
|
|
100
91
|
#### 3.4 — Persist + verify
|
|
101
92
|
|
|
@@ -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(
|
|
6
|
+
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
|
|
7
7
|
effort: xhigh
|
|
8
8
|
---
|
|
9
9
|
|
|
@@ -99,16 +99,21 @@ skip.
|
|
|
99
99
|
|
|
100
100
|
### Guard 2 — DB-path / migration intent
|
|
101
101
|
|
|
102
|
-
|
|
103
|
-
|
|
102
|
+
Delegate the db_paths config + branch diff to the CLI (replaces the former `db_paths` jq +
|
|
103
|
+
`git diff` bash), and capture the parent project ref for the MCP calls below:
|
|
104
104
|
|
|
105
105
|
```bash
|
|
106
|
-
|
|
107
|
-
[ -z "$DB_PATHS" ] && DB_PATHS=$(printf '%s\n' 'supabase/**' 'apps/backend/**' 'packages/**/db/**')
|
|
106
|
+
codebyplan supabase resolve-preview
|
|
108
107
|
```
|
|
109
108
|
|
|
109
|
+
Parse its JSON `{ parent_ref, project_ref, db_changed, base }`. Capture `PARENT_REF=parent_ref`
|
|
110
|
+
(read from `.codebyplan/shipment.json` `.shipment.surfaces.supabase.project_ref` — used by the
|
|
111
|
+
list/create calls below, never a hardcoded literal). `db_changed` reflects the branch diff
|
|
112
|
+
against `origin/<base>` matched against the configured db_paths globs (default `supabase/**`,
|
|
113
|
+
`apps/backend/**`, `packages/**/db/**`).
|
|
114
|
+
|
|
110
115
|
Proceed when **either**:
|
|
111
|
-
-
|
|
116
|
+
- `db_changed === true`, **or**
|
|
112
117
|
- this invocation will create/adopt a migration — `$ARGUMENTS` is `--new <name>` or a `.sql`
|
|
113
118
|
path (the migration file may not exist on disk yet, so explicit migrate intent counts as a
|
|
114
119
|
DB change). The bare-picker case (Step 5 Case C) is treated as migrate intent.
|
|
@@ -125,11 +130,12 @@ already provisioned the branch. Capture it as `PREVIEW_PROJECT_REF` and jump str
|
|
|
125
130
|
|
|
126
131
|
### Idempotency check (list before create)
|
|
127
132
|
|
|
128
|
-
Call `mcp__supabase__list_branches` with the parent `project_id` `
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
and the branch target. Scan the returned list for an entry
|
|
132
|
-
`$BRANCH` (slashes included — `feat/CHK-144-...` is a valid
|
|
133
|
+
Call `mcp__supabase__list_branches` with the parent `project_id` `$PARENT_REF` (resolved by
|
|
134
|
+
`codebyplan supabase resolve-preview` in Guard 2 from `.codebyplan/shipment.json`
|
|
135
|
+
`.shipment.surfaces.supabase.project_ref` — never a hardcoded literal). Supabase uses that one
|
|
136
|
+
ref as both the project identifier and the branch target. Scan the returned list for an entry
|
|
137
|
+
whose `name` exactly equals `$BRANCH` (slashes included — `feat/CHK-144-...` is a valid
|
|
138
|
+
Supabase branch name).
|
|
133
139
|
|
|
134
140
|
- **Match found**: capture its `project_ref` as `PREVIEW_PROJECT_REF`. Skip creation; proceed
|
|
135
141
|
to "Record connection". This is the idempotent reuse path (covers a branch the GitHub
|
|
@@ -148,7 +154,7 @@ Cost confirmation is mandatory before creating a branch — never bypass it:
|
|
|
148
154
|
stays empty.
|
|
149
155
|
|
|
150
156
|
After cost is confirmed, call `mcp__supabase__create_branch`:
|
|
151
|
-
- `project_id`: `
|
|
157
|
+
- `project_id`: `$PARENT_REF` (parent project ref from `codebyplan supabase resolve-preview`)
|
|
152
158
|
- `name`: `$BRANCH` (verbatim — slashes included)
|
|
153
159
|
- `confirm_cost_id`: the same id from the `get_cost` response that was passed to `confirm_cost`
|
|
154
160
|
|
|
@@ -276,25 +282,16 @@ Parse `$ARGUMENTS`:
|
|
|
276
282
|
|
|
277
283
|
### Case A: `--new <name>`
|
|
278
284
|
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
```bash
|
|
282
|
-
ls supabase/migrations/ | sort | tail -1
|
|
283
|
-
```
|
|
284
|
-
|
|
285
|
-
Extract the numeric prefix from the `tail -1` output (e.g. `20260520000003` from `20260520000003_chk116_security_and_logging_fixes.sql`). Your `date -u +%Y%m%d%H%M%S` output must be strictly greater than that prefix. If two scaffolds happen in the same UTC second, append `_01`, `_02` to maintain monotonicity. Use the current wall-clock UTC time
|
|
286
|
-
via:
|
|
285
|
+
Scaffold the migration file with a guaranteed-monotonic timestamp via the CLI (replaces the
|
|
286
|
+
former `ls | tail` + `date` + `touch` bash):
|
|
287
287
|
|
|
288
288
|
```bash
|
|
289
|
-
|
|
289
|
+
codebyplan supabase new-migration "<name>"
|
|
290
290
|
```
|
|
291
291
|
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
TIMESTAMP=$(date -u +%Y%m%d%H%M%S)
|
|
296
|
-
touch "supabase/migrations/${TIMESTAMP}_<name>.sql"
|
|
297
|
-
```
|
|
292
|
+
Parse its JSON `{ path }`. The CLI creates an empty `supabase/migrations/<timestamp>_<slug>.sql`
|
|
293
|
+
whose timestamp is strictly greater than the latest existing migration's, appending `_01`/`_02`
|
|
294
|
+
on a same-second collision. Record the returned path as `MIGRATION_PATH`.
|
|
298
295
|
|
|
299
296
|
Open the file for editing — write the migration SQL now. Include both the intended change
|
|
300
297
|
and a comment block at the top:
|