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
|
@@ -39,11 +39,12 @@ A skill that carries a `model:` line is a **gap** — remove it unless a deliber
|
|
|
39
39
|
|
|
40
40
|
### Agents — `model:` + `effort:`
|
|
41
41
|
|
|
42
|
-
Default `model: sonnet` + `effort: xhigh`. Fifteen of the
|
|
42
|
+
Default `model: sonnet` + `effort: xhigh`. Fifteen of the 17 authoring agents take the default (`cbp-cc-executor`, `cbp-database-agent`, `cbp-improve-claude`, `cbp-improve-round`, `cbp-research`, `cbp-round-executor`, `cbp-security-agent`, `cbp-task-check`, `cbp-task-planner`, `cbp-testing-qa-agent`, `cbp-e2e-playwright`, `cbp-e2e-maestro`, `cbp-e2e-tauri`, `cbp-e2e-vscode`, `cbp-e2e-xcuitest`). The other two are exceptions:
|
|
43
43
|
|
|
44
|
-
| agent | model
|
|
45
|
-
| -------------------- |
|
|
46
|
-
| cbp-mechanical-edits | haiku
|
|
44
|
+
| agent | model | effort | reason |
|
|
45
|
+
| -------------------- | ------ | ------ | ----------------------------------------------------------------------------------- |
|
|
46
|
+
| cbp-mechanical-edits | haiku | low | Mechanical rename/substitution/frontmatter-edit subagent; no judgment, pure dispatch |
|
|
47
|
+
| cbp-map-architecture | sonnet | high | Read-only module analyzer; bounded structured-map generation, lighter than xhigh |
|
|
47
48
|
|
|
48
49
|
`model: inherit` is NOT permitted for agents — pin an explicit alias (`sonnet` / `haiku`) or a full ID.
|
|
49
50
|
|
|
@@ -53,18 +54,13 @@ A skill's `effort:` applies to the inline-running turn (the orchestrator turn th
|
|
|
53
54
|
|
|
54
55
|
## Audit Mode
|
|
55
56
|
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
4. Emit one pipe-delimited line per file: `path | current_model/current_effort | expected | status`.
|
|
64
|
-
5. Status values:
|
|
65
|
-
- `ok` — matches the convention.
|
|
66
|
-
- `gap` — a skill that carries a `model:` line, a skill missing `effort:`, an agent missing/incorrect `model:`, or any missing/invalid `effort:`.
|
|
67
|
-
6. Print a summary: total audited, count `ok`, count `gap`.
|
|
57
|
+
Run `codebyplan claude audit-mode` — it scans `packages/codebyplan-package/templates/agents/*.md` and `packages/codebyplan-package/templates/skills/*/SKILL.md`, applies the convention from the matrix above, and emits a pipe-delimited table:
|
|
58
|
+
|
|
59
|
+
```
|
|
60
|
+
path | surface | model/effort | expected | status
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
Plus a summary line: `N audited, N ok, N gaps`. Exits 0 when all files comply; exits 1 on any gap. Pass `--json` for a machine-readable entries array.
|
|
68
64
|
|
|
69
65
|
The audit is read-only.
|
|
70
66
|
|
|
@@ -153,7 +153,17 @@ ln -s ~/company-standards/security.md .claude/rules/security.md
|
|
|
153
153
|
|
|
154
154
|
Claude Code resolves symlinks normally. Circular symlinks are detected.
|
|
155
155
|
|
|
156
|
-
### Step 8 —
|
|
156
|
+
### Step 8 — Validate
|
|
157
|
+
|
|
158
|
+
Run the validator:
|
|
159
|
+
|
|
160
|
+
```bash
|
|
161
|
+
bash "${CLAUDE_SKILL_DIR}/scripts/validate-rule.sh" "{scope-path}/{name}.md"
|
|
162
|
+
```
|
|
163
|
+
|
|
164
|
+
It checks: YAML frontmatter present, `scope:` field present and valid enum value, H1 heading present and its kebab-case form matches the filename, `paths:` field (warns if absent — unconditional rules burn context on every session), line count (warns at 100, errors at 200).
|
|
165
|
+
|
|
166
|
+
### Step 9 — Verify loading
|
|
157
167
|
|
|
158
168
|
Run `/memory` in a fresh Claude Code session to confirm the rule is listed. If path-scoped, open a file matching the glob to confirm it triggers.
|
|
159
169
|
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
# @scope: org-shared
|
|
3
|
+
# Validate a Claude Code rule file at .claude/rules/{name}.md.
|
|
4
|
+
# Usage: validate-rule.sh <path-to-rule-file>
|
|
5
|
+
# Exit 0 = valid, exit 1 = invalid (errors printed to stderr).
|
|
6
|
+
|
|
7
|
+
set -euo pipefail
|
|
8
|
+
|
|
9
|
+
FILE="${1:?Usage: validate-rule.sh <path-to-rule-file>}"
|
|
10
|
+
|
|
11
|
+
if [ ! -f "$FILE" ]; then
|
|
12
|
+
echo "ERROR: file not found: $FILE" >&2
|
|
13
|
+
exit 1
|
|
14
|
+
fi
|
|
15
|
+
|
|
16
|
+
errors=0
|
|
17
|
+
err() { echo " - $1" >&2; errors=$((errors + 1)); }
|
|
18
|
+
|
|
19
|
+
# Frontmatter must be present
|
|
20
|
+
if ! head -1 "$FILE" | grep -qE '^---[[:space:]]*$'; then
|
|
21
|
+
err "missing YAML frontmatter opener '---'"
|
|
22
|
+
fi
|
|
23
|
+
|
|
24
|
+
# Extract frontmatter block
|
|
25
|
+
fm=$(awk '/^---[[:space:]]*$/{n++; next} n==1{print} n==2{exit}' "$FILE")
|
|
26
|
+
|
|
27
|
+
# scope: field required + must match enum
|
|
28
|
+
if ! grep -qE '^scope:[[:space:]]*' <<< "$fm"; then
|
|
29
|
+
err "missing CBP required field: scope (org-shared|project-shared|repo-only:<repo-name>)"
|
|
30
|
+
else
|
|
31
|
+
scope_val=$(grep -E '^scope:' <<< "$fm" | head -1 | sed -E 's/^scope:[[:space:]]*//; s/[[:space:]]*$//')
|
|
32
|
+
if ! [[ "$scope_val" =~ ^(org-shared|project-shared|repo-only:[a-z0-9]([a-z0-9-]*[a-z0-9])?)$ ]]; then
|
|
33
|
+
err "scope value '$scope_val' is not a valid enum value (org-shared|project-shared|repo-only:<slug>)"
|
|
34
|
+
fi
|
|
35
|
+
fi
|
|
36
|
+
|
|
37
|
+
# H1 heading must be present and its kebab-case form must match the filename (sans .md)
|
|
38
|
+
h1=$(grep -m1 '^# ' "$FILE" | sed 's/^# //' || true)
|
|
39
|
+
if [ -z "$h1" ]; then
|
|
40
|
+
err "missing H1 heading"
|
|
41
|
+
else
|
|
42
|
+
# Convert H1 to kebab-case: lowercase, spaces→hyphens, strip non-alnum chars (except hyphens)
|
|
43
|
+
h1_kebab=$(echo "$h1" | tr '[:upper:]' '[:lower:]' | sed 's/ /-/g; s/_/-/g; s/[^a-z0-9-]//g')
|
|
44
|
+
fname=$(basename "$FILE" .md)
|
|
45
|
+
if [ "$h1_kebab" != "$fname" ]; then
|
|
46
|
+
err "H1 '$h1' (kebab: '$h1_kebab') does not match filename '$(basename "$FILE")'"
|
|
47
|
+
fi
|
|
48
|
+
fi
|
|
49
|
+
|
|
50
|
+
# paths: warning only — unconditional rules load at every session start (use sparingly)
|
|
51
|
+
if ! grep -qE '^paths:[[:space:]]*' <<< "$fm"; then
|
|
52
|
+
echo " WARN: no paths: field — rule loads unconditionally at session start; use sparingly" >&2
|
|
53
|
+
fi
|
|
54
|
+
|
|
55
|
+
# Line count thresholds (matches cbp-build-cc-rule hook: warn ≥ 100, error ≥ 200)
|
|
56
|
+
lines=$(wc -l < "$FILE")
|
|
57
|
+
if [ "$lines" -ge 200 ]; then
|
|
58
|
+
err "rule file is $lines lines (hard limit 200; split on topic)"
|
|
59
|
+
elif [ "$lines" -ge 100 ]; then
|
|
60
|
+
echo " WARN: rule file is $lines lines (recommended max 100; consider splitting)" >&2
|
|
61
|
+
fi
|
|
62
|
+
|
|
63
|
+
if [ "$errors" -gt 0 ]; then
|
|
64
|
+
echo "validation FAILED ($errors issue(s)) for $FILE" >&2
|
|
65
|
+
exit 1
|
|
66
|
+
fi
|
|
67
|
+
|
|
68
|
+
echo "validation OK: $FILE"
|
|
69
|
+
exit 0
|
|
@@ -183,8 +183,8 @@ Applied to every session. Full env-var catalogue: the official Claude Code env-v
|
|
|
183
183
|
### Step 9 — Validate and verify
|
|
184
184
|
|
|
185
185
|
```bash
|
|
186
|
-
#
|
|
187
|
-
|
|
186
|
+
# Validate structure, $schema, and permission-rule syntax
|
|
187
|
+
bash "${CLAUDE_SKILL_DIR}/scripts/validate-settings.sh" "{scope-path}/settings.json"
|
|
188
188
|
|
|
189
189
|
# Ask Claude Code itself
|
|
190
190
|
# (inside a session)
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
# @scope: org-shared
|
|
3
|
+
# Validate a Claude Code settings*.json file.
|
|
4
|
+
# Usage: validate-settings.sh <path-to-settings-file>
|
|
5
|
+
# Exit 0 = valid, exit 1 = invalid (errors printed to stderr).
|
|
6
|
+
|
|
7
|
+
set -euo pipefail
|
|
8
|
+
|
|
9
|
+
FILE="${1:?Usage: validate-settings.sh <path-to-settings-file>}"
|
|
10
|
+
|
|
11
|
+
if [ ! -f "$FILE" ]; then
|
|
12
|
+
echo "ERROR: file not found: $FILE" >&2
|
|
13
|
+
exit 1
|
|
14
|
+
fi
|
|
15
|
+
|
|
16
|
+
errors=0
|
|
17
|
+
err() { echo " - $1" >&2; errors=$((errors + 1)); }
|
|
18
|
+
|
|
19
|
+
# Requires jq
|
|
20
|
+
if ! command -v jq &>/dev/null; then
|
|
21
|
+
echo "ERROR: jq is required but not found in PATH" >&2
|
|
22
|
+
exit 1
|
|
23
|
+
fi
|
|
24
|
+
|
|
25
|
+
# Must be valid JSON
|
|
26
|
+
if ! jq -e . "$FILE" > /dev/null 2>&1; then
|
|
27
|
+
echo "validation FAILED (invalid JSON) for $FILE" >&2
|
|
28
|
+
exit 1
|
|
29
|
+
fi
|
|
30
|
+
|
|
31
|
+
# $schema key recommended
|
|
32
|
+
if ! jq -e '."$schema"' "$FILE" > /dev/null 2>&1; then
|
|
33
|
+
echo " WARN: no \$schema key — add \"https://json.schemastore.org/claude-code-settings.json\" for editor validation" >&2
|
|
34
|
+
fi
|
|
35
|
+
|
|
36
|
+
# Permission entry syntax: Tool or Tool(specifier) — e.g. Bash(git diff *), Read, mcp__foo__bar
|
|
37
|
+
PERM_PATTERN='^[A-Za-z_][A-Za-z0-9_]*(\(.*\))?$'
|
|
38
|
+
|
|
39
|
+
for tier in allow ask deny; do
|
|
40
|
+
while IFS= read -r entry; do
|
|
41
|
+
[ -z "$entry" ] && continue
|
|
42
|
+
if ! [[ "$entry" =~ $PERM_PATTERN ]]; then
|
|
43
|
+
err "permissions.$tier entry '$entry' does not match 'Tool' or 'Tool(specifier)' syntax"
|
|
44
|
+
fi
|
|
45
|
+
done < <(jq -r --arg tier "$tier" '.permissions[$tier][]? // empty' "$FILE" 2>/dev/null || true)
|
|
46
|
+
done
|
|
47
|
+
|
|
48
|
+
# No entry may appear in BOTH allow and ask (allow wins; having it in both is misleading)
|
|
49
|
+
allow_list=$(jq -r '.permissions.allow[]? // empty' "$FILE" 2>/dev/null || true)
|
|
50
|
+
ask_list=$(jq -r '.permissions.ask[]? // empty' "$FILE" 2>/dev/null || true)
|
|
51
|
+
|
|
52
|
+
if [ -n "$allow_list" ] && [ -n "$ask_list" ]; then
|
|
53
|
+
while IFS= read -r entry; do
|
|
54
|
+
[ -z "$entry" ] && continue
|
|
55
|
+
if printf '%s\n' "$ask_list" | grep -qxF "$entry"; then
|
|
56
|
+
err "permission '$entry' appears in both allow and ask (allow wins; remove from ask)"
|
|
57
|
+
fi
|
|
58
|
+
done <<< "$allow_list"
|
|
59
|
+
fi
|
|
60
|
+
|
|
61
|
+
if [ "$errors" -gt 0 ]; then
|
|
62
|
+
echo "validation FAILED ($errors issue(s)) for $FILE" >&2
|
|
63
|
+
exit 1
|
|
64
|
+
fi
|
|
65
|
+
|
|
66
|
+
echo "validation OK: $FILE"
|
|
67
|
+
exit 0
|
|
@@ -88,14 +88,22 @@ This is the first identity-stamping point — when claiming, passing `worktree_i
|
|
|
88
88
|
|
|
89
89
|
Read `.codebyplan/git.json` `branch_config.production` (default `"main"`) as `BASE`. codebyplan repos are main-only — never create or branch from a `development`/integration branch.
|
|
90
90
|
|
|
91
|
+
Compute the slug deterministically:
|
|
92
|
+
|
|
93
|
+
```bash
|
|
94
|
+
SLUG=$(codebyplan slug "{checkpoint title}")
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
Then create and push the branch:
|
|
98
|
+
|
|
91
99
|
```bash
|
|
92
100
|
git fetch origin "$BASE" 2>/dev/null || true
|
|
93
|
-
git checkout -b "feat/CHK-{NNN}
|
|
94
|
-
|| git checkout -b "feat/CHK-{NNN}
|
|
95
|
-
git push -u origin "feat/CHK-{NNN}
|
|
101
|
+
git checkout -b "feat/CHK-{NNN}-$SLUG" "origin/$BASE" 2>/dev/null \
|
|
102
|
+
|| git checkout -b "feat/CHK-{NNN}-$SLUG" "$BASE"
|
|
103
|
+
git push -u origin "feat/CHK-{NNN}-$SLUG"
|
|
96
104
|
```
|
|
97
105
|
|
|
98
|
-
|
|
106
|
+
Persist the branch via `codebyplan checkpoint update --id <checkpoint-id> --branch-name "feat/CHK-{NNN}-$SLUG"` (CLI write-through; break-glass: MCP `update_checkpoint`). (The dedicated `/cbp-git-branch-feat-create` skill is the canonical config-driven helper if you prefer to delegate.)
|
|
99
107
|
|
|
100
108
|
**Note — Supabase preview branch**: no Supabase branch is created here. Creation is lazy — it happens on the first DB change when `/cbp-supabase-migrate` runs on this feat branch, which provisions a Supabase branch named identically to the git branch. See `cbp-supabase-migrate` Step 2.3 for the creation protocol.
|
|
101
109
|
|
|
@@ -166,12 +166,19 @@ Only after both the local and remote git delete above succeed, run a conditional
|
|
|
166
166
|
|
|
167
167
|
> Lifecycle contract: see [[supabase-branch-lifecycle]].
|
|
168
168
|
|
|
169
|
-
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
169
|
+
- Resolve the parent project ref and apply the lifecycle guard in one deterministic call:
|
|
170
|
+
|
|
171
|
+
```bash
|
|
172
|
+
codebyplan supabase teardown-preview "$BRANCH"
|
|
173
|
+
```
|
|
174
|
+
|
|
175
|
+
Parse its JSON `{ status, parent_ref, project_ref, reason }`. The command never deletes anything — it reads the parent ref from `.codebyplan/shipment.json` (`.shipment.surfaces.supabase.project_ref`) and applies the protected / production / parent-ref guard from [[supabase-branch-lifecycle]].
|
|
176
|
+
- If `status === "rejected"`: STOP the teardown for this branch and surface `reason` — never delete a production / protected / integration branch or one whose preview ref equals the parent.
|
|
177
|
+
- Otherwise (`allowed` or `not_found`), use `parent_ref` for the live existence check — `mcp__supabase__list_branches` with `project_id: <parent_ref>`, then scan for an entry whose `name` exactly equals `$BRANCH`:
|
|
178
|
+
- If found: call `mcp__supabase__delete_branch` with its `branch_id`. Record the branch name in `SUPABASE_BRANCHES_DELETED[]`.
|
|
179
|
+
- If not found: no-op silently — the GitHub integration may have already removed it on PR close; not-found is success, NOT an error.
|
|
180
|
+
- If the `list_branches` call itself fails (network, auth, or a non-success response — distinct from a successful lookup that returns no match): emit a non-blocking warning that the Supabase preview branch for `$BRANCH` may still exist and should be verified in the dashboard. Do not treat an API failure as a not-found success.
|
|
181
|
+
- Never delete the parent project (`parent_ref` from `codebyplan supabase teardown-preview`) itself or any persistent/production branch — the `teardown-preview` guard enforces this.
|
|
175
182
|
|
|
176
183
|
Accumulate all Supabase branch names removed across the loop in `SUPABASE_BRANCHES_DELETED`.
|
|
177
184
|
|
|
@@ -198,11 +205,12 @@ git push origin --delete "$FEAT_BRANCH"
|
|
|
198
205
|
|
|
199
206
|
After the feat branch git delete, run the same conditional Supabase teardown for `$FEAT_BRANCH`:
|
|
200
207
|
|
|
201
|
-
-
|
|
202
|
-
-
|
|
203
|
-
-
|
|
204
|
-
- If
|
|
205
|
-
- If
|
|
208
|
+
- Run `codebyplan supabase teardown-preview "$FEAT_BRANCH"` and parse its JSON `{ status, parent_ref, project_ref, reason }` (reads the parent ref from `.codebyplan/shipment.json`, applies the lifecycle guard, never deletes).
|
|
209
|
+
- If `status === "rejected"`: STOP the teardown and surface `reason` — never delete a production / protected / integration branch or one whose preview ref equals the parent.
|
|
210
|
+
- Otherwise (`allowed` or `not_found`), use `parent_ref` for the live existence check — `mcp__supabase__list_branches` with `project_id: <parent_ref>`, then scan for an entry whose `name` exactly equals `$FEAT_BRANCH`:
|
|
211
|
+
- If found: call `mcp__supabase__delete_branch` with its `branch_id`. Add `$FEAT_BRANCH` to `SUPABASE_BRANCHES_DELETED[]`.
|
|
212
|
+
- If not found: no-op silently — idempotent, not-found is success.
|
|
213
|
+
- If the `list_branches` call itself fails (network, auth, or a non-success response — distinct from a successful lookup that returns no match): emit a non-blocking warning that the Supabase preview branch for `$FEAT_BRANCH` may still exist and should be verified in the dashboard. Do not treat an API failure as a not-found success.
|
|
206
214
|
|
|
207
215
|
### Step 10: Save Shipment Results and Summary
|
|
208
216
|
|
|
@@ -108,21 +108,19 @@ REPO_PATH="$(git rev-parse --show-toplevel)"
|
|
|
108
108
|
|
|
109
109
|
**If `--files` provided:** Use the manual file list.
|
|
110
110
|
|
|
111
|
-
**If `--scope-task`:** Resolve via
|
|
111
|
+
**If `--scope-task`:** Resolve via the deterministic CLI.
|
|
112
|
+
|
|
113
|
+
First, read `task.files_changed[].path` (local-first from `.codebyplan/state/checkpoints/*/tasks/*.json`; on miss run `npx codebyplan sync` once, then re-read; MCP `get_current_task` as documented break-glass when the state dir is absent and sync fails) and format as a CSV string. Then compute the intersection:
|
|
112
114
|
|
|
113
115
|
```bash
|
|
114
|
-
#
|
|
115
|
-
|
|
116
|
-
#
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
# 2. Read staged paths
|
|
120
|
-
staged_paths=$(git diff --cached --name-only)
|
|
121
|
-
# 3. Compute intersection
|
|
122
|
-
intersect=$(comm -12 <(echo "$task_paths" | sort) <(echo "$staged_paths" | sort))
|
|
116
|
+
TASK_FILES_CSV="path1,path2,path3" # CSV string of task.files_changed[].path (local-first)
|
|
117
|
+
SCOPE_RESULT=$(codebyplan commit --scope-task --task-files "$TASK_FILES_CSV")
|
|
118
|
+
# Parse JSON: { files: string[], count: number }
|
|
119
|
+
FILES=$(echo "$SCOPE_RESULT" | jq -r '.files[]')
|
|
120
|
+
COUNT=$(echo "$SCOPE_RESULT" | jq -r '.count')
|
|
123
121
|
```
|
|
124
122
|
|
|
125
|
-
If `
|
|
123
|
+
If `COUNT === 0` (empty `files[]`): emit error and STOP.
|
|
126
124
|
|
|
127
125
|
```
|
|
128
126
|
## Error: No Task Files Staged
|
|
@@ -135,7 +133,7 @@ Options:
|
|
|
135
133
|
- Or use --all to commit the foreign-staged files instead.
|
|
136
134
|
```
|
|
137
135
|
|
|
138
|
-
If
|
|
136
|
+
If `COUNT > 0`: use `FILES` as the file list for Step 5.
|
|
139
137
|
|
|
140
138
|
**If `--task`, `--all`, or no scope:** No filtering — all staged files committed.
|
|
141
139
|
|
|
@@ -159,59 +159,18 @@ If the main repo has no `.codebyplan/e2e.env` yet, provision it after setup by r
|
|
|
159
159
|
cd "$WORKTREE_PATH" && git push -u origin "$BRANCH_NAME"
|
|
160
160
|
```
|
|
161
161
|
|
|
162
|
-
### Step 9: Register Worktree
|
|
162
|
+
### Step 9: Register Worktree and Write `.codebyplan/` Config
|
|
163
163
|
|
|
164
|
-
|
|
164
|
+
Run `codebyplan worktree create "$BRANCH_NAME" --path "$WORKTREE_PATH"` and parse the JSON output (`{ worktree_files_written: boolean, mcp_registered: boolean, worktree_id?, warn? }`):
|
|
165
165
|
|
|
166
|
-
|
|
166
|
+
- If `warn` is present: surface it as a non-blocking warning.
|
|
167
|
+
- Save the returned `worktree_id` for reference (if present).
|
|
167
168
|
|
|
168
|
-
|
|
169
|
-
MCP create_worktree:
|
|
170
|
-
repo_id: [repo-id from CLAUDE.md]
|
|
171
|
-
name: $BRANCH_NAME
|
|
172
|
-
path: $WORKTREE_PATH
|
|
173
|
-
status: "active"
|
|
174
|
-
```
|
|
175
|
-
|
|
176
|
-
Save the returned `worktree_id` for reference.
|
|
177
|
-
|
|
178
|
-
### Step 10: Write `.codebyplan/` directory
|
|
179
|
-
|
|
180
|
-
Create the `.codebyplan/` directory in the worktree root and write per-concern config stubs:
|
|
181
|
-
|
|
182
|
-
```bash
|
|
183
|
-
mkdir -p "$WORKTREE_PATH/.codebyplan"
|
|
184
|
-
```
|
|
185
|
-
|
|
186
|
-
Write `.codebyplan/repo.json` with the correct `repo_id`:
|
|
187
|
-
|
|
188
|
-
```json
|
|
189
|
-
{
|
|
190
|
-
"repo_id": "[repo-id from CLAUDE.md]"
|
|
191
|
-
}
|
|
192
|
-
```
|
|
193
|
-
|
|
194
|
-
Write stubs for the other per-concern files (populated by `npx codebyplan sync` on first run):
|
|
195
|
-
|
|
196
|
-
```bash
|
|
197
|
-
# .codebyplan/server.json — server port and type config
|
|
198
|
-
echo '{}' > "$WORKTREE_PATH/.codebyplan/server.json"
|
|
199
|
-
|
|
200
|
-
# .codebyplan/git.json — branch config
|
|
201
|
-
echo '{}' > "$WORKTREE_PATH/.codebyplan/git.json"
|
|
202
|
-
|
|
203
|
-
# .codebyplan/shipment.json — surface shipment config
|
|
204
|
-
echo '{}' > "$WORKTREE_PATH/.codebyplan/shipment.json"
|
|
205
|
-
|
|
206
|
-
# .codebyplan/vendor.json — vendor docs path
|
|
207
|
-
echo '{}' > "$WORKTREE_PATH/.codebyplan/vendor.json"
|
|
208
|
-
```
|
|
209
|
-
|
|
210
|
-
The `.codebyplan/device.local.json` file is created by `npx codebyplan setup` on the device (gitignored). The `worktree_id` is never COMMITTED; it may be cached per-device in the gitignored `.codebyplan/worktree.local.json` (branch-keyed, re-derivable via `codebyplan resolve-worktree --cache`), otherwise resolved at runtime from the `(device_id, repo path, branch)` tuple via `npx codebyplan resolve-worktree`.
|
|
169
|
+
The CLI atomically writes the `.codebyplan/` directory with per-concern config stubs and registers the worktree in the CodeByPlan database. The `.codebyplan/device.local.json` file is created by `npx codebyplan setup` on the device (gitignored). The `worktree_id` is never COMMITTED; it may be cached per-device in the gitignored `.codebyplan/worktree.local.json` (branch-keyed, re-derivable via `codebyplan resolve-worktree --cache`), otherwise resolved at runtime from the `(device_id, repo path, branch)` tuple via `npx codebyplan resolve-worktree`.
|
|
211
170
|
|
|
212
171
|
No need to mark as `skip-worktree` — the committed files are merge-safe per CHK-108 and CHK-120.
|
|
213
172
|
|
|
214
|
-
### Step
|
|
173
|
+
### Step 10: Show Result
|
|
215
174
|
|
|
216
175
|
```
|
|
217
176
|
## Worktree Created
|
|
@@ -238,4 +197,4 @@ No need to mark as `skip-worktree` — the committed files are merge-safe per CH
|
|
|
238
197
|
## Integration
|
|
239
198
|
|
|
240
199
|
- **Related**: `/cbp-git-worktree-remove` (cleanup and deregister)
|
|
241
|
-
- **
|
|
200
|
+
- **CLI**: `codebyplan worktree create <name> --path <abs>` (Step 9 — writes `.codebyplan/` config and registers worktree)
|
|
@@ -49,31 +49,17 @@ Set:
|
|
|
49
49
|
- `WORKTREE_PATH` = resolved path
|
|
50
50
|
- `BRANCH_NAME` = branch checked out in that worktree
|
|
51
51
|
|
|
52
|
-
### Step 4: Look Up Worktree in CodeByPlan
|
|
52
|
+
### Step 4: Look Up and Deregister Worktree in CodeByPlan
|
|
53
53
|
|
|
54
|
-
|
|
54
|
+
Run `codebyplan worktree remove "$BRANCH_NAME"` and parse the JSON output (`{ mcp_deregistered: boolean, warn? }`):
|
|
55
55
|
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
MCP get_worktrees:
|
|
60
|
-
repo_id: [repo-id from CLAUDE.md]
|
|
61
|
-
status: "active"
|
|
62
|
-
```
|
|
63
|
-
|
|
64
|
-
Match by `name` = `$BRANCH_NAME` or `path` = `$WORKTREE_PATH`.
|
|
65
|
-
|
|
66
|
-
Set `WORKTREE_ID` = matched worktree's `id`.
|
|
67
|
-
|
|
68
|
-
If not found in CodeByPlan, note it and continue with local removal.
|
|
56
|
+
- If `warn` is present: surface it as a non-blocking warning. The worktree was not found in CodeByPlan or deregistration failed, but local removal will proceed.
|
|
57
|
+
- If `mcp_deregistered === true`: worktree was successfully deregistered.
|
|
58
|
+
- If `mcp_deregistered === false`: worktree was not registered or deregistration failed; continue with local removal.
|
|
69
59
|
|
|
70
60
|
### Step 5: Check for Assigned Checkpoints
|
|
71
61
|
|
|
72
|
-
If
|
|
73
|
-
|
|
74
|
-
```
|
|
75
|
-
⚠ This worktree has [N] checkpoint(s) assigned. They will become unassigned.
|
|
76
|
-
```
|
|
62
|
+
If the worktree was successfully deregistered in Step 4 (`mcp_deregistered === true`), any checkpoints that were assigned to it will become unassigned. This is expected behavior and requires no additional action.
|
|
77
63
|
|
|
78
64
|
### Step 6: Confirm with User
|
|
79
65
|
|
|
@@ -92,16 +78,7 @@ Ask:
|
|
|
92
78
|
2. Remove worktree and delete branch
|
|
93
79
|
3. Cancel
|
|
94
80
|
|
|
95
|
-
### Step 7:
|
|
96
|
-
|
|
97
|
-
If `WORKTREE_ID` was found, delete the worktree record:
|
|
98
|
-
|
|
99
|
-
```
|
|
100
|
-
MCP delete_worktree:
|
|
101
|
-
worktree_id: [worktree-id]
|
|
102
|
-
```
|
|
103
|
-
|
|
104
|
-
### Step 8: Remove Git Worktree
|
|
81
|
+
### Step 7: Remove Git Worktree
|
|
105
82
|
|
|
106
83
|
```bash
|
|
107
84
|
git worktree remove "$WORKTREE_PATH"
|
|
@@ -114,7 +91,7 @@ git worktree remove --force "$WORKTREE_PATH"
|
|
|
114
91
|
|
|
115
92
|
Only use `--force` if the user confirms.
|
|
116
93
|
|
|
117
|
-
### Step
|
|
94
|
+
### Step 8: Delete Branch (if requested)
|
|
118
95
|
|
|
119
96
|
**Protected branch check:** Read the protected set from `.codebyplan/git.json`:
|
|
120
97
|
```bash
|
|
@@ -135,15 +112,21 @@ After the git branch delete succeeds, run a conditional Supabase preview-branch
|
|
|
135
112
|
|
|
136
113
|
> Lifecycle contract: see [[supabase-branch-lifecycle]].
|
|
137
114
|
|
|
138
|
-
- Resolve the parent project ref
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
115
|
+
- Resolve the parent project ref and apply the lifecycle guard in one deterministic call:
|
|
116
|
+
|
|
117
|
+
```bash
|
|
118
|
+
codebyplan supabase teardown-preview "$BRANCH_NAME"
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
Parse its JSON `{ status, parent_ref, project_ref, reason }`. The command never deletes anything — it reads the parent ref from `.codebyplan/shipment.json` (`.shipment.surfaces.supabase.project_ref`) and applies the protected / production / parent-ref guard from [[supabase-branch-lifecycle]].
|
|
122
|
+
- If `status === "rejected"`: STOP the teardown and surface `reason` — never delete a production / protected / integration branch or one whose preview ref equals the parent.
|
|
123
|
+
- Otherwise (`allowed` or `not_found`), use `parent_ref` for the live existence check — `mcp__supabase__list_branches` with `project_id: <parent_ref>`, then scan for an entry whose `name` exactly equals `$BRANCH_NAME`:
|
|
124
|
+
- If found: call `mcp__supabase__delete_branch` with its `branch_id`. Report "Supabase preview branch deleted: `$BRANCH_NAME`".
|
|
125
|
+
- If not found: no-op silently — the GitHub integration may have already removed it on PR close; not-found is success, NOT an error.
|
|
126
|
+
- If the `list_branches` call itself fails (network, auth, or a non-success response — distinct from a successful lookup that returns no match): emit a non-blocking warning that the Supabase preview branch for `$BRANCH_NAME` may still exist and should be verified in the dashboard. Do not treat an API failure as a not-found success.
|
|
127
|
+
- Never delete the parent project (`parent_ref` from `codebyplan supabase teardown-preview`) itself or any persistent/production branch — the `teardown-preview` guard enforces this.
|
|
145
128
|
|
|
146
|
-
### Step
|
|
129
|
+
### Step 9: Show Result
|
|
147
130
|
|
|
148
131
|
```
|
|
149
132
|
## Worktree Removed
|
|
@@ -159,4 +142,4 @@ After the git branch delete succeeds, run a conditional Supabase preview-branch
|
|
|
159
142
|
## Integration
|
|
160
143
|
|
|
161
144
|
- **Related**: `/cbp-git-worktree-create` (create and register)
|
|
162
|
-
- **
|
|
145
|
+
- **CLI**: `codebyplan worktree remove <name>` (Step 4 — deregister from CodeByPlan)
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
scope: org-shared
|
|
3
3
|
name: cbp-map-architecture
|
|
4
|
+
effort: xhigh
|
|
4
5
|
description: Orchestrate architecture map generation for one or all modules. Spawns the cbp-map-architecture agent per module, writes per-module .md files to .claude/architecture/, regenerates INDEX.md and graph.md, and stamps each module via the CLI. Idempotent — safe to re-run.
|
|
5
6
|
argument-hint: '[--module <path>] [--deep <path,...>]'
|
|
6
7
|
allowed-tools: Read, Write, Edit, Glob, Grep, Bash, Task
|
|
@@ -69,36 +69,24 @@ Triggered by `/cbp-task-start` (Step 3.6, optional stale-check), `/cbp-task-comp
|
|
|
69
69
|
|
|
70
70
|
Supabase migrations are version-keyed by their numeric filename prefix. Two files sharing a prefix break `supabase db push`: the schema_migrations table records ONE version per prefix, the second file at the same prefix becomes orphaned, and every subsequent migration stalls — surfacing as the Supabase Preview check failing with `MIGRATIONS_FAILED`. Catch this BEFORE committing the merge, while a clean rollback is one `git merge --abort` away.
|
|
71
71
|
|
|
72
|
-
1. Probe both sides of the would-be merge
|
|
72
|
+
1. Probe both sides of the would-be merge via the deterministic CLI:
|
|
73
73
|
|
|
74
74
|
```bash
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
| sed 's|.*/||' | sort > /tmp/cbp-merge-their-names.txt
|
|
75
|
+
PROBE=$(codebyplan migration-collisions --base "$BASE" --json)
|
|
76
|
+
# Parse JSON: { base, collisions: [{ prefix, ours: string[], theirs: string[] }] }
|
|
77
|
+
COLLISIONS=$(echo "$PROBE" | jq '.collisions')
|
|
79
78
|
```
|
|
80
79
|
|
|
81
|
-
2.
|
|
80
|
+
2. If `COLLISIONS` is empty (`[]`), proceed silently to Step 2.
|
|
82
81
|
|
|
83
|
-
|
|
84
|
-
# Files unique to each side (same-named files are NOT collisions)
|
|
85
|
-
comm -23 /tmp/cbp-merge-our-names.txt /tmp/cbp-merge-their-names.txt > /tmp/cbp-merge-only-ours.txt
|
|
86
|
-
comm -13 /tmp/cbp-merge-our-names.txt /tmp/cbp-merge-their-names.txt > /tmp/cbp-merge-only-theirs.txt
|
|
87
|
-
# True collision: a prefix in only-ours also appears in only-theirs (same prefix, different basename)
|
|
88
|
-
COLLISIONS=$(cat /tmp/cbp-merge-only-ours.txt /tmp/cbp-merge-only-theirs.txt \
|
|
89
|
-
| sed 's|_.*||' | sort | uniq -d)
|
|
90
|
-
```
|
|
91
|
-
|
|
92
|
-
3. If `COLLISIONS` is empty, proceed silently to Step 2.
|
|
93
|
-
|
|
94
|
-
4. If `COLLISIONS` is non-empty, for each colliding prefix list both file paths (one from `HEAD`, one from `origin/{BASE}`) and surface via AskUserQuestion:
|
|
82
|
+
3. If `COLLISIONS` is non-empty, for each colliding prefix in the array (each element has `prefix`, `ours[]`, `theirs[]`) surface via AskUserQuestion:
|
|
95
83
|
|
|
96
84
|
- **Rename HEAD-side (Recommended when a main migration is already applied to a shared remote)** — rename the local file to a fresh, sequential timestamp that respects existing apply-order dependencies (probe `supabase migration list --db-url <preview>` if a preview branch exists, or inspect FK references in surrounding migrations). The orchestrator runs `git mv <old> <new>` itself; the rename lands in the git index and is picked up by the re-probe at step 5.
|
|
97
85
|
- **Rename main-side (manual, OUT-OF-SKILL)** — only when the main file definitely has not been applied anywhere yet AND the user has write access to `{BASE}`. This skill does NOT touch the main branch: it runs on a feat branch (Step 0 enforces this) and the Key Rules below forbid any push from this skill. The user must, in a separate terminal: `git checkout {BASE} && git mv <old> <new> && git commit -m "fix(migration): rename to resolve collision with feat/..." && git push origin {BASE}`. After that push is confirmed remote-side, re-invoke `/cbp-merge-main` — Step 1 will fetch the updated main tip and Step 1.5 will re-probe with the rename in place.
|
|
98
86
|
- **Defer to a new task in the active checkpoint** — `git merge --abort` is unnecessary because Step 2 has not started. Create a CHK-bound task per `cbp-round-end` reference `findings-presentation.md` "Infra Issue Absorption Contract — Resolve-in-Current-Scope by Default" and STOP `/cbp-merge-main`. Resume after the task completes.
|
|
99
87
|
- **Abort merge** — STOP the skill. User decides later.
|
|
100
88
|
|
|
101
|
-
|
|
89
|
+
4. After any HEAD-side rename action, re-execute Step 1.5 (collisions may chain — fixing one can expose another). The CLI probes the HEAD side via `git ls-files` (so staged renames are visible), matching the documented re-probe behavior. Main-side renames require a fresh `/cbp-merge-main` invocation (the user manually fetched and re-ran per option 2 above), not an in-skill loop.
|
|
102
90
|
|
|
103
91
|
This check is intentionally placed BEFORE Step 2's `git merge`: catching collisions pre-merge means no merge commit to revert, no conflict-resolution work to throw away, no Supabase Preview poll to fail.
|
|
104
92
|
|
|
@@ -165,27 +153,34 @@ This check is intentionally placed BEFORE Step 2's `git merge`: catching collisi
|
|
|
165
153
|
|
|
166
154
|
Run a scoped subset of the testing-qa check matrix INLINE (no agent spawn — this skill stays lightweight):
|
|
167
155
|
|
|
168
|
-
1.
|
|
156
|
+
1. From the repo root, run:
|
|
157
|
+
|
|
158
|
+
```bash
|
|
159
|
+
codebyplan check --scope merged --json
|
|
160
|
+
```
|
|
161
|
+
|
|
162
|
+
`--scope merged` runs `gate6`, `lint`, `typecheck`, and `tests` (no `audit` — that is `task` scope only). The runner is **whole-repo + baseline**: it runs `turbo run lint|typecheck|test` across every package and diffs against the committed `.check-baseline.json`, so only NEW per-package failures fail a check (`status: 'fail'` with a non-empty `new_failures`). `gate6` (sibling-identity parity) is ALWAYS hard-fail and never baselined. Capture the JSON result.
|
|
163
|
+
|
|
164
|
+
2. For each result entry where `status === 'fail'`, surface its `stdout`/`stderr` and present an AskUserQuestion:
|
|
169
165
|
- **Continue (commit-as-is)** — leave the merge committed; flag QA failure in output.
|
|
170
166
|
- **Abort merge** — `git reset --hard HEAD~1` to revert just the merge commit. Stop the skill.
|
|
171
167
|
- **Skip (mark warn)** — leave the merge committed; treat as warn, not fail.
|
|
172
168
|
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
3. `pnpm test --run` — only if any merged file matches typical source globs (`src/**`, `apps/**/src/**`, `packages/**/src/**`). Same three-option prompt on failure.
|
|
176
|
-
|
|
177
|
-
4. Build a `qa_summary` object:
|
|
169
|
+
3. Build a `qa_summary` object from the runner's results array:
|
|
178
170
|
|
|
179
171
|
```
|
|
180
172
|
{
|
|
173
|
+
"gate6": "pass" | "fail" | "warn" | "skipped",
|
|
181
174
|
"lint": "pass" | "fail" | "warn" | "skipped",
|
|
182
|
-
"
|
|
175
|
+
"typecheck": "pass" | "fail" | "warn" | "skipped",
|
|
183
176
|
"tests": "pass" | "fail" | "warn" | "skipped",
|
|
184
177
|
"merged_files_count": N,
|
|
185
178
|
"user_choice_on_failure": "continue" | "abort" | "skip" | null
|
|
186
179
|
}
|
|
187
180
|
```
|
|
188
181
|
|
|
182
|
+
Map runner `status` values: `"pass"` → `"pass"`, `"skipped"` → `"skipped"`, `"fail"` → `"fail"` or `"warn"` per the user's choice above.
|
|
183
|
+
|
|
189
184
|
Do NOT auto-revert without user consent. User-driven gating is the contract.
|
|
190
185
|
|
|
191
186
|
### Step 5: Output
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
scope: org-shared
|
|
3
3
|
name: cbp-refresh-arch-map
|
|
4
|
+
effort: high
|
|
4
5
|
description: Drift-scoped refresh of the .claude/architecture/ map — re-runs the cbp-map-architecture agent for ONLY the modules whose stamped git SHA has changed, regenerates INDEX.md + graph.md, and re-stamps. Idempotent; no-op when no module has drifted.
|
|
5
6
|
argument-hint: '[--module <path>]'
|
|
6
7
|
allowed-tools: Read, Write, Edit, Glob, Grep, Bash, Task
|