codebyplan 1.13.44 → 1.13.46
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 +5038 -1551
- 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 +3 -5
- 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
package/package.json
CHANGED
|
@@ -82,9 +82,7 @@ Review all QA items across all rounds:
|
|
|
82
82
|
- **Auto items**: Verify all passed (build, lint, types, tests)
|
|
83
83
|
- **Default items**: Verify all resolved (pass or skipped with reason)
|
|
84
84
|
|
|
85
|
-
**E2E
|
|
86
|
-
|
|
87
|
-
**Committed-screenshot check**: For any round where `round.context.e2e_eligible[]` is non-empty, verify `round.context.e2e_gallery[]` is non-empty. Refuse a READY verdict when it is empty — verdict text: "E2E ran but produced zero committed screenshots — open a fix round per `rules/e2e-mandatory.md` § Committed-Screenshot Enforcement." Sole exception: when `vscode-test` is the ONLY eligible framework, an empty `e2e_gallery[]` is allowed (SD-3, behavior-only extensions).
|
|
85
|
+
**E2E deterministic gate**: For each round where `round.context.e2e_eligible[]` is non-empty, run `codebyplan e2e verify-round --round-id <round_id> --task-id <task_id>`. Exit 0 = pass. Exit 1 = hard-fail — refuse a READY verdict and surface the stdout JSON's `failed_checks[]` verbatim in the verdict text. The CLI deterministically evaluates all three e2e hard-fails that were previously judged manually: `e2e_eligible_skipped` (eligible framework with no specialist output and no valid skip reason), `zero_assertion_run` (`passed === 0 && skipped > 0` on a path touching `files_changed` — "E2E spec authored but assertions did not execute (skip-gated)"), and `empty_gallery` (eligible UI-touching run with zero committed screenshots, per `rules/e2e-mandatory.md` § Committed-Screenshot Enforcement; the sole vscode-test-only exception is honored by the CLI). On any exit-1, route to a fix round per `rules/e2e-mandatory.md`.
|
|
88
86
|
|
|
89
87
|
List any pending or failed items. Determine if they are blockers.
|
|
90
88
|
|
|
@@ -552,13 +552,15 @@ plan.waves:
|
|
|
552
552
|
|
|
553
553
|
If `files_to_modify[]` contains ≤5 files across a single app, skip decomposition and emit a single wave or omit `waves[]` entirely (single-wave default in `round-execute` handles this gracefully).
|
|
554
554
|
|
|
555
|
-
**Verification
|
|
555
|
+
**Verification** before finalising waves — invariants I (disjoint files), II (acyclic `depends_on` DAG), and III (3–15 files per wave, with the small-plan lower-bound exemption) are deterministic set/graph checks; run the validator instead of self-checking them in prose:
|
|
556
556
|
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
- [
|
|
557
|
+
```bash
|
|
558
|
+
printf '%s' "$PLAN_JSON" | codebyplan validate-waves --json
|
|
559
|
+
```
|
|
560
|
+
|
|
561
|
+
(`$PLAN_JSON` is the `{ "waves": [...] }` structure; pass a file path as the first argument instead of stdin if preferred.) Exit 0 = invariants I–III satisfied. Exit non-zero = one or more violations — the `--json` `violations[]` array names the failing invariant (`I`/`II`/`III`) and offending wave/file; fix the decomposition and re-run before emitting the plan. The validator does NOT check invariant IV (UI skill preloads) — that remains a manual step:
|
|
562
|
+
|
|
563
|
+
- [ ] UI-bearing waves have `frontend-design` + `frontend-a11y` in `skill_preloads[]` (invariant IV — not covered by `validate-waves`)
|
|
562
564
|
|
|
563
565
|
### Phase 6: Build Context Summary
|
|
564
566
|
|
|
@@ -93,8 +93,7 @@ jobs:
|
|
|
93
93
|
case "$VERSION" in
|
|
94
94
|
*-*)
|
|
95
95
|
# Prerelease — check if this exact version already exists on npm.
|
|
96
|
-
EXACT_OUT=$(npm view "codebyplan@${VERSION}" version 2>&1)
|
|
97
|
-
EXACT_EXIT=$?
|
|
96
|
+
EXACT_OUT=$(npm view "codebyplan@${VERSION}" version 2>&1) && EXACT_EXIT=0 || EXACT_EXIT=$?
|
|
98
97
|
if [ "$EXACT_EXIT" -eq 0 ]; then
|
|
99
98
|
echo "VERSION=${VERSION} already published — skipping (exact-version guard)."
|
|
100
99
|
echo "should_publish=false" >> "$GITHUB_OUTPUT"
|
|
@@ -134,8 +133,7 @@ jobs:
|
|
|
134
133
|
# Stable on main: compare committed version against the npm registry.
|
|
135
134
|
# Distinguish "never published" (E404 → first publish) from a transient
|
|
136
135
|
# registry/network error (abort rather than blindly publish).
|
|
137
|
-
NPM_OUT=$(npm view codebyplan version 2>&1)
|
|
138
|
-
NPM_EXIT=$?
|
|
136
|
+
NPM_OUT=$(npm view codebyplan version 2>&1) && NPM_EXIT=0 || NPM_EXIT=$?
|
|
139
137
|
if [ "$NPM_EXIT" -ne 0 ]; then
|
|
140
138
|
if echo "$NPM_OUT" | grep -q "E404"; then
|
|
141
139
|
echo "Package not yet published — first publish."
|
|
@@ -147,7 +145,7 @@ jobs:
|
|
|
147
145
|
fi
|
|
148
146
|
# Extract the first semver-looking line so a registry deprecation/advisory
|
|
149
147
|
# notice in NPM_OUT cannot corrupt the sort -V comparison below.
|
|
150
|
-
PUBLISHED=$(printf '%s\n' "$NPM_OUT" | grep -E '^[0-9]+\.[0-9]+\.[0-9]+' | head -n1)
|
|
148
|
+
PUBLISHED=$(printf '%s\n' "$NPM_OUT" | grep -E '^[0-9]+\.[0-9]+\.[0-9]+' | head -n1) || true
|
|
151
149
|
|
|
152
150
|
# sort -V: version-aware sort. If VERSION sorts AFTER PUBLISHED, it is greater.
|
|
153
151
|
GREATER=$(printf '%s\n%s\n' "$PUBLISHED" "$VERSION" | sort -V | tail -n1)
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# @scope: org-shared
|
|
3
|
+
# @event: PreToolUse
|
|
4
|
+
# @matcher: Edit|Write|MultiEdit
|
|
5
|
+
# Guard spec files against two patterns banned by rules/e2e-mandatory.md and
|
|
6
|
+
# context/testing/e2e.md:
|
|
7
|
+
#
|
|
8
|
+
# 1. In-spec env skip gates — test.skip(!process.env.X, ...) bypasses preflight,
|
|
9
|
+
# produces zero-assertion runs, and hides missing env vars behind a green check.
|
|
10
|
+
# (rules/e2e-mandatory.md § No In-Spec Env-Skip Gate)
|
|
11
|
+
#
|
|
12
|
+
# 2. waitForLoadState("networkidle") locators — networkidle is deprecated in
|
|
13
|
+
# Playwright and causes flaky / hanging tests; use load or domcontentloaded
|
|
14
|
+
# instead. (context/testing/e2e.md § locator hygiene)
|
|
15
|
+
#
|
|
16
|
+
# Only fires on spec files: file_path ending in .spec.ts OR containing /e2e/
|
|
17
|
+
# or starting with e2e/. All other file paths exit 0 immediately.
|
|
18
|
+
#
|
|
19
|
+
# Exit codes:
|
|
20
|
+
# 0 — no violation (or not a spec file)
|
|
21
|
+
# 2 — violation found; message on stderr
|
|
22
|
+
|
|
23
|
+
set -euo pipefail
|
|
24
|
+
|
|
25
|
+
INPUT_JSON="$(cat)"
|
|
26
|
+
TOOL_NAME="$(echo "$INPUT_JSON" | jq -r '.tool_name // empty')"
|
|
27
|
+
FILE_PATH="$(echo "$INPUT_JSON" | jq -r '.tool_input.file_path // empty')"
|
|
28
|
+
|
|
29
|
+
# ------------------------------------------------------------------
|
|
30
|
+
# Fast-path: only enforce on spec / e2e files
|
|
31
|
+
# ------------------------------------------------------------------
|
|
32
|
+
is_spec=0
|
|
33
|
+
case "$FILE_PATH" in
|
|
34
|
+
*.spec.ts) is_spec=1 ;;
|
|
35
|
+
*/e2e/*) is_spec=1 ;;
|
|
36
|
+
e2e/*) is_spec=1 ;;
|
|
37
|
+
esac
|
|
38
|
+
|
|
39
|
+
[ "$is_spec" -eq 0 ] && exit 0
|
|
40
|
+
|
|
41
|
+
# ------------------------------------------------------------------
|
|
42
|
+
# Extract content depending on tool type
|
|
43
|
+
# ------------------------------------------------------------------
|
|
44
|
+
NEW_CONTENT=""
|
|
45
|
+
if [ "$TOOL_NAME" = "Write" ]; then
|
|
46
|
+
NEW_CONTENT="$(echo "$INPUT_JSON" | jq -r '.tool_input.content // empty')"
|
|
47
|
+
elif [ "$TOOL_NAME" = "Edit" ]; then
|
|
48
|
+
NEW_CONTENT="$(echo "$INPUT_JSON" | jq -r '.tool_input.new_string // empty')"
|
|
49
|
+
elif [ "$TOOL_NAME" = "MultiEdit" ]; then
|
|
50
|
+
NEW_CONTENT="$(echo "$INPUT_JSON" | jq -r '[.tool_input.edits[].new_string // ""] | join("\n")')"
|
|
51
|
+
fi
|
|
52
|
+
|
|
53
|
+
[ -z "$NEW_CONTENT" ] && exit 0
|
|
54
|
+
|
|
55
|
+
# ------------------------------------------------------------------
|
|
56
|
+
# Check 1: in-spec env-skip gate (test.skip with process.env)
|
|
57
|
+
# Pattern: test.skip( followed by optional whitespace and optional !
|
|
58
|
+
# then process.env
|
|
59
|
+
# ------------------------------------------------------------------
|
|
60
|
+
if echo "$NEW_CONTENT" | grep -qE 'test\.skip\([[:space:]]*!?process\.env'; then
|
|
61
|
+
cat >&2 <<'EOF'
|
|
62
|
+
[hook] cbp-e2e-spec-patterns: in-spec env skip gate detected
|
|
63
|
+
|
|
64
|
+
Pattern: test.skip(!process.env.X, ...) or test.skip(process.env.X, ...)
|
|
65
|
+
|
|
66
|
+
This pattern is banned by rules/e2e-mandatory.md § "No In-Spec Env-Skip Gate":
|
|
67
|
+
"Spec files MUST NOT contain in-spec env skip gates such as
|
|
68
|
+
test.skip(!process.env.X, ...). They bypass preflight, produce
|
|
69
|
+
zero-assertion runs, and hide missing env vars behind a green check."
|
|
70
|
+
|
|
71
|
+
The only valid mechanism for env-conditional skipping is pre-flight
|
|
72
|
+
(context/testing/e2e.md Step 6.5.1). Configure missing env vars in
|
|
73
|
+
.codebyplan/e2e.json credential_vars and let the preflight block the run.
|
|
74
|
+
|
|
75
|
+
EOF
|
|
76
|
+
exit 2
|
|
77
|
+
fi
|
|
78
|
+
|
|
79
|
+
# ------------------------------------------------------------------
|
|
80
|
+
# Check 2: waitForLoadState("networkidle") locator
|
|
81
|
+
# networkidle is deprecated and causes flaky / hanging tests.
|
|
82
|
+
# ------------------------------------------------------------------
|
|
83
|
+
if echo "$NEW_CONTENT" | grep -qE 'waitForLoadState\(["'"'"']networkidle["'"'"']\)'; then
|
|
84
|
+
cat >&2 <<'EOF'
|
|
85
|
+
[hook] cbp-e2e-spec-patterns: waitForLoadState("networkidle") detected
|
|
86
|
+
|
|
87
|
+
This locator is banned by context/testing/e2e.md locator hygiene rules.
|
|
88
|
+
"networkidle" is deprecated in Playwright and causes flaky or hanging tests.
|
|
89
|
+
|
|
90
|
+
Use one of the stable alternatives:
|
|
91
|
+
await page.waitForLoadState("load"); // waits for load event
|
|
92
|
+
await page.waitForLoadState("domcontentloaded"); // waits for DOM ready
|
|
93
|
+
await page.waitForURL("..."); // waits for navigation
|
|
94
|
+
await expect(locator).toBeVisible(); // waits for element
|
|
95
|
+
|
|
96
|
+
EOF
|
|
97
|
+
exit 2
|
|
98
|
+
fi
|
|
99
|
+
|
|
100
|
+
exit 0
|
|
File without changes
|
|
File without changes
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
#!/bin/bash
|
|
2
|
+
# @scope: org-shared
|
|
2
3
|
# @hook: NOT-A-HOOK (test suite for plugin hooks; invoked by cbp-auto-test-hooks.sh)
|
|
3
4
|
# Purpose: Test suite for plugin's shipped hooks. Invoked by cbp-auto-test-hooks.sh whenever a
|
|
4
5
|
# plugin hook file is edited. Not a PreToolUse/PostToolUse/Notification hook itself —
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# @scope: org-shared
|
|
3
|
+
# @event: SessionStart
|
|
4
|
+
# Scope + sibling-parity sweep at session start. Calls `codebyplan claude verify-parity --warn-only`.
|
|
5
|
+
# Fires ONLY in the templates source monorepo (self-guards on templates/ presence); no-op for consumers.
|
|
6
|
+
# Always exits 0 — warn-mode, non-blocking.
|
|
7
|
+
|
|
8
|
+
set -u
|
|
9
|
+
REPO_ROOT=$(git rev-parse --show-toplevel 2>/dev/null)
|
|
10
|
+
[ -z "$REPO_ROOT" ] && exit 0
|
|
11
|
+
[ -d "$REPO_ROOT/packages/codebyplan-package/templates" ] || exit 0
|
|
12
|
+
|
|
13
|
+
# Prefer the installed binary (fast); fall back to npx for fresh checkouts /
|
|
14
|
+
# environments where the workspace bin is not on PATH (matches cbp-mcp-round-sync.sh).
|
|
15
|
+
if command -v codebyplan >/dev/null 2>&1; then
|
|
16
|
+
codebyplan claude verify-parity --warn-only 2>&1 || true
|
|
17
|
+
else
|
|
18
|
+
npx codebyplan claude verify-parity --warn-only 2>&1 || true
|
|
19
|
+
fi
|
|
20
|
+
exit 0
|
|
@@ -12,7 +12,7 @@ Authoritative expansion of `cbp-task-planner` Phase 5.6. The planner reads this
|
|
|
12
12
|
|
|
13
13
|
## Wave Schema
|
|
14
14
|
|
|
15
|
-
Each entry in `plan.waves[]` carries these fields (source: `.claude/agents/cbp-task-planner.md
|
|
15
|
+
Each entry in `plan.waves[]` carries these fields (source: `.claude/agents/cbp-task-planner.md` Phase 5.6 "Output" block):
|
|
16
16
|
|
|
17
17
|
```yaml
|
|
18
18
|
- name: string # short identifier, e.g. "web-ui", "backend", "db"
|
|
@@ -34,7 +34,7 @@ Each entry in `plan.waves[]` carries these fields (source: `.claude/agents/cbp-t
|
|
|
34
34
|
- Above 15: apply the proximity-split algorithm below.
|
|
35
35
|
- Sole exception — trivially small plans are exempt from the lower bound: a plan with fewer than 3 total files uses one single wave, and a single-app plan with ≤5 total files MAY skip decomposition entirely (one wave, or `waves[]` omitted — see `cbp-task-planner` Phase 5.6). Zero waves (omitted `waves[]`) trivially satisfies this invariant.
|
|
36
36
|
|
|
37
|
-
**(IV) UI skill preloads** — for each wave whose `files[]` contains UI-bearing paths (`*.tsx`, `*.jsx`, `*.scss`, etc.), add `"frontend-design"` and `"frontend-a11y"` to `skill_preloads[]` in that order (source: `.claude/agents/cbp-task-planner.md
|
|
37
|
+
**(IV) UI skill preloads** — for each wave whose `files[]` contains UI-bearing paths (`*.tsx`, `*.jsx`, `*.scss`, etc.), add `"frontend-design"` and `"frontend-a11y"` to `skill_preloads[]` in that order (source: `.claude/agents/cbp-task-planner.md` Phase 5.6 step "Populate `skill_preloads[]`").
|
|
38
38
|
|
|
39
39
|
## Proximity-Split Algorithm
|
|
40
40
|
|
|
@@ -52,8 +52,13 @@ When a wave would exceed 15 files, split it in priority order:
|
|
|
52
52
|
|
|
53
53
|
When no cross-app or cross-concern independence is found, the planner emits one wave covering all files. The 15-file cap applies to this single wave — if the total exceeds 15, apply the proximity-split algorithm even though the original decomposition was a single wave.
|
|
54
54
|
|
|
55
|
+
## Enforcement
|
|
56
|
+
|
|
57
|
+
Invariants I (disjoint files), II (acyclic `depends_on` DAG), and III (3–15 files per wave, with the small-plan lower-bound exemption) are enforced deterministically by `codebyplan validate-waves [--json]` (`packages/codebyplan-package/src/lib/validate-waves.ts`). The planner runs it at Phase 5.6 against the `{ "waves": [...] }` structure (file-path or stdin input); a non-zero exit lists the violated invariant + offending wave/file. Invariant IV (UI skill preloads) is out of the validator's scope and stays a planner manual step.
|
|
58
|
+
|
|
55
59
|
## Cross-References
|
|
56
60
|
|
|
57
|
-
- `agents/cbp-task-planner.md` Phase 5.6 — consumer of this rule; steps 1–6 and verification
|
|
61
|
+
- `agents/cbp-task-planner.md` Phase 5.6 — consumer of this rule; steps 1–6 and the `validate-waves` verification call.
|
|
62
|
+
- `packages/codebyplan-package/src/lib/validate-waves.ts` — deterministic enforcement of invariants I–III.
|
|
58
63
|
- `agents/cbp-round-executor.md` Step 2.6 — wave-mode skill preloads.
|
|
59
64
|
- `skills/cbp-round-execute/SKILL.md` Step 3 — per-wave executor dispatch.
|
|
@@ -4,7 +4,7 @@ scope: org-shared
|
|
|
4
4
|
|
|
5
5
|
# Scope Vocabulary
|
|
6
6
|
|
|
7
|
-
Canonical scope-marker enum for `.claude/` files. Every CBP-managed agent, skill, rule, and hook script must declare exactly one `scope:` value from the enum below. The marker is enforced by
|
|
7
|
+
Canonical scope-marker enum for `.claude/` files. Every CBP-managed agent, skill, rule, and hook script must declare exactly one `scope:` value from the enum below. The marker is enforced by four validators (cross-linked at the bottom of this file).
|
|
8
8
|
|
|
9
9
|
## Enum values
|
|
10
10
|
|
|
@@ -57,8 +57,9 @@ Used by `.sh` hook scripts and `.sh` tooling under `.claude/`. Place the marker
|
|
|
57
57
|
|
|
58
58
|
## Enforcement
|
|
59
59
|
|
|
60
|
-
|
|
60
|
+
Four validators enforce this enum. A file missing the marker (or carrying a non-enum value) fails validation:
|
|
61
61
|
|
|
62
|
-
- `.claude/hooks/validate-structure-scope.sh` — warns
|
|
62
|
+
- `.claude/hooks/validate-structure-scope.sh` — warns when a `.claude/` file being edited (PreToolUse `Edit|Write`) lacks a scope marker; sourced by `validate-structure.sh`; it is NOT a session-start sweep.
|
|
63
|
+
- `codebyplan claude verify-parity` — sweeps all `.claude/{rules,skills,agents,hooks}` for missing/non-enum scope markers AND runs the sibling-parity check against `templates/`; invoked automatically at session start via `.claude/hooks/verify-parity.sh` (monorepo only); run manually with `--json` for CI.
|
|
63
64
|
- `.claude/skills/cbp-build-cc-agent/scripts/validate-agent.sh` — blocks agent authoring when `scope:` is absent.
|
|
64
65
|
- `.claude/skills/cbp-build-cc-skill/scripts/validate-skill.sh` — blocks skill authoring when `scope:` is absent.
|
|
@@ -84,6 +84,8 @@
|
|
|
84
84
|
"Bash(npx codebyplan upgrade-auth:*)",
|
|
85
85
|
"Bash(codebyplan config:*)",
|
|
86
86
|
"Bash(npx codebyplan config:*)",
|
|
87
|
+
"Bash(codebyplan doctor:*)",
|
|
88
|
+
"Bash(npx codebyplan doctor:*)",
|
|
87
89
|
"Bash(codebyplan branch:*)",
|
|
88
90
|
"Bash(npx codebyplan branch:*)",
|
|
89
91
|
"Bash(codebyplan ship:*)",
|
|
@@ -178,12 +180,20 @@
|
|
|
178
180
|
"mcp__codebyplan__update_eslint_repo_config",
|
|
179
181
|
"mcp__codebyplan__update_server_config",
|
|
180
182
|
"mcp__codebyplan__update_task_template",
|
|
183
|
+
"Bash(codebyplan check:*)",
|
|
184
|
+
"Bash(npx codebyplan check:*)",
|
|
185
|
+
"Bash(codebyplan session:*)",
|
|
186
|
+
"Bash(npx codebyplan session:*)",
|
|
187
|
+
"Bash(codebyplan supabase:*)",
|
|
188
|
+
"Bash(npx codebyplan supabase:*)",
|
|
181
189
|
"Bash(codebyplan whoami:*)",
|
|
182
190
|
"Bash(npx codebyplan whoami:*)",
|
|
183
191
|
"Bash(codebyplan resolve-worktree:*)",
|
|
184
192
|
"Bash(npx codebyplan resolve-worktree:*)",
|
|
185
193
|
"Bash(codebyplan version-status:*)",
|
|
186
194
|
"Bash(npx codebyplan version-status:*)",
|
|
195
|
+
"Bash(codebyplan worktree:*)",
|
|
196
|
+
"Bash(npx codebyplan worktree:*)",
|
|
187
197
|
"Bash(codebyplan statusline:*)",
|
|
188
198
|
"Bash(npx codebyplan statusline:*)",
|
|
189
199
|
"Bash(codebyplan ports:*)",
|
|
@@ -214,6 +224,18 @@
|
|
|
214
224
|
"Bash(npx codebyplan bump:*)",
|
|
215
225
|
"Bash(codebyplan scaffold-publish-workflow:*)",
|
|
216
226
|
"Bash(npx codebyplan scaffold-publish-workflow:*)",
|
|
227
|
+
"Bash(codebyplan claude verify-parity:*)",
|
|
228
|
+
"Bash(npx codebyplan claude verify-parity:*)",
|
|
229
|
+
"Bash(codebyplan slug:*)",
|
|
230
|
+
"Bash(npx codebyplan slug:*)",
|
|
231
|
+
"Bash(codebyplan commit:*)",
|
|
232
|
+
"Bash(npx codebyplan commit:*)",
|
|
233
|
+
"Bash(codebyplan migration-collisions:*)",
|
|
234
|
+
"Bash(npx codebyplan migration-collisions:*)",
|
|
235
|
+
"Bash(codebyplan validate-waves:*)",
|
|
236
|
+
"Bash(npx codebyplan validate-waves:*)",
|
|
237
|
+
"Bash(codebyplan e2e:*)",
|
|
238
|
+
"Bash(npx codebyplan e2e:*)",
|
|
217
239
|
"Bash(codebyplan arch-map:*)",
|
|
218
240
|
"Bash(npx codebyplan arch-map:*)"
|
|
219
241
|
]
|
|
@@ -170,7 +170,17 @@ Other teams' CLAUDE.md files in the ancestor tree get picked up by default. Excl
|
|
|
170
170
|
|
|
171
171
|
Managed policy CLAUDE.md cannot be excluded.
|
|
172
172
|
|
|
173
|
-
### Step 9 —
|
|
173
|
+
### Step 9 — Validate
|
|
174
|
+
|
|
175
|
+
Run the validator:
|
|
176
|
+
|
|
177
|
+
```bash
|
|
178
|
+
bash "${CLAUDE_SKILL_DIR}/scripts/validate-claude-file.sh" "{path-to-claude-file}"
|
|
179
|
+
```
|
|
180
|
+
|
|
181
|
+
It checks: at least one H1 heading present, `@path` imports all resolve relative to the file's directory (or repo root), line count (warns at 200, errors at 400), warns if `scope:` marker appears in frontmatter, warns if filename is neither `CLAUDE.md` nor `CLAUDE.local.md`.
|
|
182
|
+
|
|
183
|
+
### Step 10 — Verify with `/memory`
|
|
174
184
|
|
|
175
185
|
Run `/memory` to confirm the file is loaded. The list shows all CLAUDE.md, CLAUDE.local.md, and rules files in effect.
|
|
176
186
|
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
# @scope: org-shared
|
|
3
|
+
# Validate a CLAUDE.md or CLAUDE.local.md file.
|
|
4
|
+
# Usage: validate-claude-file.sh <path-to-claude-file>
|
|
5
|
+
# Exit 0 = valid, exit 1 = invalid (errors printed to stderr).
|
|
6
|
+
|
|
7
|
+
set -euo pipefail
|
|
8
|
+
|
|
9
|
+
FILE="${1:?Usage: validate-claude-file.sh <path-to-claude-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
|
+
# Filename check — warn if not a known CLAUDE.md variant
|
|
20
|
+
fname=$(basename "$FILE")
|
|
21
|
+
if [ "$fname" != "CLAUDE.md" ] && [ "$fname" != "CLAUDE.local.md" ]; then
|
|
22
|
+
echo " WARN: unexpected filename '$fname' — expected CLAUDE.md or CLAUDE.local.md" >&2
|
|
23
|
+
fi
|
|
24
|
+
|
|
25
|
+
# At least one H1 heading must be present
|
|
26
|
+
if ! grep -qE '^# ' "$FILE"; then
|
|
27
|
+
err "missing H1 heading"
|
|
28
|
+
fi
|
|
29
|
+
|
|
30
|
+
# Line count thresholds
|
|
31
|
+
lines=$(wc -l < "$FILE")
|
|
32
|
+
if [ "$lines" -ge 400 ]; then
|
|
33
|
+
err "file is $lines lines (hard limit 400; split with @path imports or nested CLAUDE.md files)"
|
|
34
|
+
elif [ "$lines" -ge 200 ]; then
|
|
35
|
+
echo " WARN: file is $lines lines (recommended max 200; consider splitting)" >&2
|
|
36
|
+
fi
|
|
37
|
+
|
|
38
|
+
# @path import resolution — each @path token must resolve to an existing file.
|
|
39
|
+
# Tries both: relative to the file's directory, and relative to cwd (repo root).
|
|
40
|
+
filedir=$(dirname "$FILE")
|
|
41
|
+
while IFS= read -r imp; do
|
|
42
|
+
[ -z "$imp" ] && continue
|
|
43
|
+
ipath="${imp#@}"
|
|
44
|
+
if [ "${ipath:0:1}" = "/" ]; then
|
|
45
|
+
# absolute path
|
|
46
|
+
if [ ! -f "$ipath" ]; then
|
|
47
|
+
err "@import path '$ipath' does not exist"
|
|
48
|
+
fi
|
|
49
|
+
elif [ -f "$filedir/$ipath" ]; then
|
|
50
|
+
: # ok — resolves relative to the file's directory
|
|
51
|
+
elif [ -f "$ipath" ]; then
|
|
52
|
+
: # ok — resolves relative to cwd (repo root)
|
|
53
|
+
else
|
|
54
|
+
err "@import path '$ipath' does not exist (tried: $filedir/$ipath, $ipath)"
|
|
55
|
+
fi
|
|
56
|
+
done < <(grep -oE '^[[:space:]]*@[^[:space:]@]+' "$FILE" 2>/dev/null | sed 's/^[[:space:]]*//' 2>/dev/null || true)
|
|
57
|
+
|
|
58
|
+
# Warn if YAML frontmatter contains a scope: marker (CLAUDE.md is not a rule/skill/agent file)
|
|
59
|
+
if head -1 "$FILE" | grep -qE '^---[[:space:]]*$'; then
|
|
60
|
+
fm=$(awk '/^---[[:space:]]*$/{n++; next} n==1{print} n==2{exit}' "$FILE")
|
|
61
|
+
if grep -qE '^scope:[[:space:]]*' <<< "$fm"; then
|
|
62
|
+
echo " WARN: CLAUDE.md has a scope: frontmatter field — scope markers belong in rule/skill/agent files, not CLAUDE.md" >&2
|
|
63
|
+
fi
|
|
64
|
+
fi
|
|
65
|
+
|
|
66
|
+
if [ "$errors" -gt 0 ]; then
|
|
67
|
+
echo "validation FAILED ($errors issue(s)) for $FILE" >&2
|
|
68
|
+
exit 1
|
|
69
|
+
fi
|
|
70
|
+
|
|
71
|
+
echo "validation OK: $FILE"
|
|
72
|
+
exit 0
|
|
@@ -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)
|