codebyplan 1.12.0 → 1.13.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cli.js +50 -71
- package/package.json +1 -1
- package/templates/hooks/README.md +1 -13
- package/templates/hooks/cbp-test-coverage-gate.sh +8 -0
- package/templates/hooks/cbp-test-hooks.sh +0 -42
- package/templates/hooks/hooks.json +0 -9
- package/templates/skills/cbp-checkpoint-start/SKILL.md +2 -2
- package/templates/skills/cbp-session-start/SKILL.md +1 -1
- package/templates/skills/{cbp-e2e-setup → cbp-setup-e2e}/SKILL.md +1 -1
- package/templates/skills/cbp-setup-eslint/SKILL.md +199 -0
- package/templates/skills/cbp-setup-eslint/reference/base.md +82 -0
- package/templates/skills/cbp-setup-eslint/reference/cli.md +56 -0
- package/templates/skills/cbp-setup-eslint/reference/e2e.md +68 -0
- package/templates/skills/cbp-setup-eslint/reference/jest.md +59 -0
- package/templates/skills/cbp-setup-eslint/reference/nestjs.md +69 -0
- package/templates/skills/cbp-setup-eslint/reference/nextjs.md +63 -0
- package/templates/skills/cbp-setup-eslint/reference/node.md +74 -0
- package/templates/skills/cbp-setup-eslint/reference/react-native.md +60 -0
- package/templates/skills/cbp-setup-eslint/reference/react.md +82 -0
- package/templates/skills/cbp-setup-eslint/reference/tailwind.md +64 -0
- package/templates/skills/cbp-setup-eslint/reference/testing-react.md +57 -0
- package/templates/skills/cbp-setup-eslint/reference/vitest.md +62 -0
- package/templates/skills/cbp-task-complete/SKILL.md +1 -3
- package/templates/skills/cbp-task-start/SKILL.md +3 -3
- package/templates/hooks/cbp-mcp-worktree-inject.sh +0 -76
- /package/templates/skills/{cbp-e2e-setup → cbp-setup-e2e}/reference/maestro.md +0 -0
- /package/templates/skills/{cbp-e2e-setup → cbp-setup-e2e}/reference/playwright.md +0 -0
- /package/templates/skills/{cbp-e2e-setup → cbp-setup-e2e}/reference/tauri.md +0 -0
- /package/templates/skills/{cbp-e2e-setup → cbp-setup-e2e}/reference/vscode.md +0 -0
- /package/templates/skills/{cbp-e2e-setup → cbp-setup-e2e}/reference/xcuitest.md +0 -0
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
# tailwind — Tailwind CSS class linting
|
|
2
|
+
|
|
3
|
+
For apps using Tailwind CSS (the CBP `tarkur` repo uses Tailwind + shadcn/ui). **Gap stack —
|
|
4
|
+
no CBP DB preset.** Adds class-sorting / validation rules on top of the app's base config.
|
|
5
|
+
|
|
6
|
+
> **Verified 2026-05-31.** Use **`eslint-plugin-better-tailwindcss`** — it is the only plugin
|
|
7
|
+
> with first-class **Tailwind v4** + ESLint 9/10 flat-config support. The original
|
|
8
|
+
> `eslint-plugin-tailwindcss` only handles v4 on an unstable alpha — **avoid it for v4.**
|
|
9
|
+
|
|
10
|
+
## Packages
|
|
11
|
+
|
|
12
|
+
| Package | Latest | Tailwind v4? | Verdict |
|
|
13
|
+
| ------- | ------ | ------------ | ------- |
|
|
14
|
+
| `eslint-plugin-better-tailwindcss` | `4.5.0` | **yes (stable)** | **use this** |
|
|
15
|
+
| `eslint-plugin-tailwindcss` | `3.18.3` (v4 only on `4.0.0-alpha`) | beta/as-is | avoid for v4 |
|
|
16
|
+
|
|
17
|
+
```bash
|
|
18
|
+
pnpm add -D eslint-plugin-better-tailwindcss
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
Peer deps: `eslint ^7 || ^8 || ^9 || ^10`, `tailwindcss ^3.3.0 || ^4.1.17`. Node ≥ 20.19.
|
|
22
|
+
|
|
23
|
+
## Flat config
|
|
24
|
+
|
|
25
|
+
```js
|
|
26
|
+
// eslint.config.mjs
|
|
27
|
+
import { defineConfig } from "eslint/config";
|
|
28
|
+
import betterTailwind from "eslint-plugin-better-tailwindcss";
|
|
29
|
+
|
|
30
|
+
export default defineConfig([
|
|
31
|
+
{
|
|
32
|
+
extends: [betterTailwind.configs["recommended"]],
|
|
33
|
+
settings: {
|
|
34
|
+
"better-tailwindcss": {
|
|
35
|
+
// Tailwind v4: path to the CSS file with `@import "tailwindcss"`
|
|
36
|
+
entryPoint: "src/app/globals.css",
|
|
37
|
+
// Tailwind v3 ONLY (omit for v4):
|
|
38
|
+
// tailwindConfig: "tailwind.config.js",
|
|
39
|
+
},
|
|
40
|
+
},
|
|
41
|
+
},
|
|
42
|
+
]);
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
## Gotchas
|
|
46
|
+
|
|
47
|
+
- **`settings.entryPoint` is REQUIRED for Tailwind v4** — it points at the global CSS file
|
|
48
|
+
containing `@import "tailwindcss"` (v4 has no JS config file). For v3, use `tailwindConfig`
|
|
49
|
+
instead.
|
|
50
|
+
- **Monorepo**: set `settings["better-tailwindcss"].cwd` per file-group so the plugin resolves
|
|
51
|
+
`tailwindcss` + the config from the correct project dir when ESLint runs from the repo root.
|
|
52
|
+
- Config presets: `recommended`, `correctness` (errors), `stylistic` (warnings); severity
|
|
53
|
+
suffixes `-error` / `-warn`.
|
|
54
|
+
- Non-JSX file types (Svelte/Vue/Astro/HTML) need the matching `languageOptions.parser`.
|
|
55
|
+
|
|
56
|
+
## CBP preset divergence
|
|
57
|
+
|
|
58
|
+
There is **no** CBP `tailwind` DB preset — Tailwind linting is entirely manual. `tarkur`
|
|
59
|
+
currently has no Tailwind ESLint rules; add the block above to lint class order/validity.
|
|
60
|
+
|
|
61
|
+
## Official docs
|
|
62
|
+
|
|
63
|
+
- eslint-plugin-better-tailwindcss: https://github.com/schoero/eslint-plugin-better-tailwindcss
|
|
64
|
+
- Settings: https://github.com/schoero/eslint-plugin-better-tailwindcss/blob/main/docs/settings/settings.md
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
# testing-react — Testing Library + jest-dom rules
|
|
2
|
+
|
|
3
|
+
For React component tests (Testing Library assertions). Layers a **test-scoped** override on
|
|
4
|
+
top of [base](base.md) + the test-runner doc ([vitest](vitest.md) or [jest](jest.md)). Maps to
|
|
5
|
+
the CBP **`testing-react`** DB preset
|
|
6
|
+
(`tech_match.requires: ["React", "Vitest"]`, `requires_capabilities: ["jsx"]`).
|
|
7
|
+
|
|
8
|
+
> **Verified 2026-05-31.** Both plugins use bracketed `configs['flat/...']` keys and each
|
|
9
|
+
> spreads its own plugin registration — keep them as **separate array entries**.
|
|
10
|
+
|
|
11
|
+
## Packages
|
|
12
|
+
|
|
13
|
+
| Package | Latest | Purpose |
|
|
14
|
+
| ------- | ------ | ------- |
|
|
15
|
+
| `eslint-plugin-testing-library` | `7.16.2` | Testing Library best-practices |
|
|
16
|
+
| `eslint-plugin-jest-dom` | `5.5.0` | `@testing-library/jest-dom` matchers |
|
|
17
|
+
|
|
18
|
+
```bash
|
|
19
|
+
pnpm add -D eslint-plugin-testing-library eslint-plugin-jest-dom
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
## Flat config
|
|
23
|
+
|
|
24
|
+
```js
|
|
25
|
+
// eslint.config.mjs
|
|
26
|
+
import testingLibrary from "eslint-plugin-testing-library";
|
|
27
|
+
import jestDom from "eslint-plugin-jest-dom";
|
|
28
|
+
|
|
29
|
+
const TEST_GLOBS = ["**/*.{test,spec}.{ts,tsx,js,jsx}", "**/__tests__/**/*.{ts,tsx,js,jsx}"];
|
|
30
|
+
|
|
31
|
+
export default [
|
|
32
|
+
{ files: TEST_GLOBS, ...testingLibrary.configs["flat/react"] }, // 'flat/dom' for non-React
|
|
33
|
+
{ files: TEST_GLOBS, ...jestDom.configs["flat/recommended"] },
|
|
34
|
+
];
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
## Gotchas
|
|
38
|
+
|
|
39
|
+
- Keep the two as **separate array entries** — each `...config` spread re-declares its own
|
|
40
|
+
`plugins`. Merging them into one object means you must hand-combine `plugins` + `rules`.
|
|
41
|
+
- `eslint-plugin-testing-library` framework presets: `flat/react`, `flat/dom` (agnostic),
|
|
42
|
+
`flat/vue`, `flat/angular`, `flat/svelte`, `flat/marko` — pick **one**.
|
|
43
|
+
- Scope to the **same test globs** as your runner override so the rules don't bleed onto
|
|
44
|
+
production code.
|
|
45
|
+
- Don't let Playwright e2e specs hit `testing-library/*` rules (e.g.
|
|
46
|
+
`prefer-screen-queries` mis-fires on Playwright's `page.getByRole`) — scope to `src/**`
|
|
47
|
+
unit tests, not the e2e dir (see [e2e.md](e2e.md)).
|
|
48
|
+
|
|
49
|
+
## CBP preset divergence
|
|
50
|
+
|
|
51
|
+
The CBP `testing-react` preset matches this (`eslint-plugin-testing-library: ^7.0.0`,
|
|
52
|
+
`eslint-plugin-jest-dom: ^5.0.0`, `flat/react` + `flat/recommended`). No divergence.
|
|
53
|
+
|
|
54
|
+
## Official docs
|
|
55
|
+
|
|
56
|
+
- testing-library: https://github.com/testing-library/eslint-plugin-testing-library
|
|
57
|
+
- jest-dom: https://github.com/testing-library/eslint-plugin-jest-dom
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
# vitest — Vitest test-file rules
|
|
2
|
+
|
|
3
|
+
For apps that test with Vitest (CBP web + CLI + most repos). Layers a **test-scoped** override
|
|
4
|
+
on top of [base](base.md). Maps to the CBP **`testing`** DB preset
|
|
5
|
+
(`tech_match.requires: ["Vitest"]`).
|
|
6
|
+
|
|
7
|
+
> **Verified 2026-05-31.** The package was **renamed** to the scoped
|
|
8
|
+
> **`@vitest/eslint-plugin`** (the old `eslint-plugin-vitest` is the deprecated name). Its
|
|
9
|
+
> flat-config key is plain **`configs.recommended`** — there is **no `flat/` prefix**.
|
|
10
|
+
|
|
11
|
+
## Packages
|
|
12
|
+
|
|
13
|
+
| Package | Latest | Purpose |
|
|
14
|
+
| ------- | ------ | ------- |
|
|
15
|
+
| `@vitest/eslint-plugin` | `1.6.18` | Vitest rules (scoped pkg) |
|
|
16
|
+
|
|
17
|
+
```bash
|
|
18
|
+
pnpm add -D @vitest/eslint-plugin
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
## Flat config
|
|
22
|
+
|
|
23
|
+
```js
|
|
24
|
+
// eslint.config.mjs
|
|
25
|
+
import vitest from "@vitest/eslint-plugin";
|
|
26
|
+
|
|
27
|
+
export default [
|
|
28
|
+
{
|
|
29
|
+
files: ["**/*.{test,spec}.{ts,tsx,js,jsx}"],
|
|
30
|
+
plugins: { vitest },
|
|
31
|
+
rules: {
|
|
32
|
+
...vitest.configs.recommended.rules,
|
|
33
|
+
// tests are I/O-heavy + mock-heavy — relax type-safety on test files:
|
|
34
|
+
"@typescript-eslint/no-explicit-any": "off",
|
|
35
|
+
"@typescript-eslint/no-unsafe-assignment": "off",
|
|
36
|
+
"@typescript-eslint/no-unsafe-member-access": "off",
|
|
37
|
+
"@typescript-eslint/no-unsafe-call": "off",
|
|
38
|
+
"@typescript-eslint/no-unsafe-argument": "off",
|
|
39
|
+
"@typescript-eslint/no-unsafe-return": "off",
|
|
40
|
+
},
|
|
41
|
+
settings: { vitest: { typecheck: true } }, // only if using Vitest type-testing
|
|
42
|
+
},
|
|
43
|
+
];
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
## Gotchas
|
|
47
|
+
|
|
48
|
+
- The key is **`vitest.configs.recommended`** (plain) — NOT `configs['flat/recommended']`.
|
|
49
|
+
Other plugins use the bracketed `flat/` form; Vitest does not.
|
|
50
|
+
- When you spread only `.rules`, register `plugins: { vitest }` yourself. Alternatively spread
|
|
51
|
+
the whole `...vitest.configs.recommended` (carries the plugin registration).
|
|
52
|
+
- The `no-unsafe-*` / `no-explicit-any` opt-outs are CBP convention — production code keeps
|
|
53
|
+
them at `error`; test surfaces relax them because mocks produce `any`-typed values.
|
|
54
|
+
|
|
55
|
+
## CBP preset divergence
|
|
56
|
+
|
|
57
|
+
The CBP `testing` preset matches this (the six `no-unsafe-*`/`no-explicit-any` opt-outs,
|
|
58
|
+
`@vitest/eslint-plugin: ^1.0.0`). No divergence.
|
|
59
|
+
|
|
60
|
+
## Official docs
|
|
61
|
+
|
|
62
|
+
- @vitest/eslint-plugin: https://github.com/vitest-dev/eslint-plugin-vitest
|
|
@@ -137,9 +137,7 @@ Skip the push only when nothing was committed in Step 5 AND `/cbp-merge-main` re
|
|
|
137
137
|
|
|
138
138
|
### Step 7: Complete Task
|
|
139
139
|
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
**When calling `complete_task`**: pass `caller_worktree_id` resolved from `npx codebyplan resolve-worktree`. The MCP server's pre-guard rejects mutations from non-matching worktrees; supplying `caller_worktree_id` ensures legitimate completion succeeds. The server auto-clears `assigned_user_id` + `assigned_worktree_id` on the task; if this was the last sibling task, it also clears the parent checkpoint's assignment. (Per CHK-104 TASK-2 hard-lock.)
|
|
140
|
+
Call `complete_task(task_id)`. The server resolves the caller's worktree identity from the JWT/ctx and enforces the mutate-lock (CHK-140 TASK-3 — `caller_worktree_id` input field removed). The server auto-clears `assigned_user_id` + `assigned_worktree_id` on the task; if this was the last sibling task, it also clears the parent checkpoint's assignment. (Per CHK-104 hard-lock.)
|
|
143
141
|
|
|
144
142
|
### Step 7.5: Standalone Task Branch Merge
|
|
145
143
|
|
|
@@ -160,9 +160,9 @@ See `dependency-vulnerability-fixes.md` "Audit Sweep at Task Start" for the sour
|
|
|
160
160
|
|
|
161
161
|
### Step 3.5: Worktree-Match Verification
|
|
162
162
|
|
|
163
|
-
Before activating the task, verify the caller's worktree matches the assigned worktree on the target row. (Per CHK-104
|
|
163
|
+
Before activating the task, verify the caller's worktree matches the assigned worktree on the target row. (Per CHK-104 — DB-level hard-lock prevents cross-worktree mutations; the server resolves caller identity from the JWT/ctx.)
|
|
164
164
|
|
|
165
|
-
1. Read caller worktree: `CALLER_WT=$(npx codebyplan resolve-worktree 2>/dev/null)`.
|
|
165
|
+
1. Read caller worktree: `CALLER_WT=$(npx codebyplan resolve-worktree 2>/dev/null)`.
|
|
166
166
|
2. Determine target worktree:
|
|
167
167
|
- **Checkpoint-bound tasks**: `TARGET_WT = checkpoint.worktree_id` (read from MCP `get_checkpoints`). Note: checkpoint-bound tasks may have a NULL `task.assigned_worktree_id` because the lock lives on the parent checkpoint — fall through to `checkpoint.worktree_id`.
|
|
168
168
|
- **Standalone tasks**: `TARGET_WT = task.assigned_worktree_id`.
|
|
@@ -222,7 +222,7 @@ Display context summary:
|
|
|
222
222
|
|
|
223
223
|
Use MCP `update_task(task_id, status: "in_progress")`.
|
|
224
224
|
|
|
225
|
-
If worktree_id present, include `claim_worktree_id` to auto-claim the checkpoint
|
|
225
|
+
If worktree_id present, include `claim_worktree_id` to auto-claim the checkpoint. The server resolves the caller's worktree identity from the JWT/ctx (CHK-140 TASK-3 — `caller_worktree_id` input field removed).
|
|
226
226
|
|
|
227
227
|
### Step 6: Auto-trigger Round Start
|
|
228
228
|
|
|
@@ -1,76 +0,0 @@
|
|
|
1
|
-
#!/bin/bash
|
|
2
|
-
# @scope: org-shared
|
|
3
|
-
# Hook: PreToolUse mcp__codebyplan__(update_task|complete_task|complete_round|update_checkpoint)
|
|
4
|
-
# Purpose: Auto-inject caller_worktree_id into MCP mutation calls when not already
|
|
5
|
-
# present. Uses the PreToolUse hookSpecificOutput.updatedInput contract
|
|
6
|
-
# (Claude Code v2.1 — see hooks.md "PreToolUse decision control"):
|
|
7
|
-
# - Output JSON with hookSpecificOutput.permissionDecision="allow" and
|
|
8
|
-
# hookSpecificOutput.updatedInput containing the full modified tool_input.
|
|
9
|
-
# This hook NEVER exits non-zero — it is a no-op on all failure paths.
|
|
10
|
-
#
|
|
11
|
-
# Fallback chain:
|
|
12
|
-
# 1. caller_worktree_id already present in tool_input → passthrough (no-op)
|
|
13
|
-
# 2. Primary: npx codebyplan resolve-worktree → UUID found → inject
|
|
14
|
-
# 3. Secondary: npx codebyplan resolve-worktree --fallback-from-branch → UUID found → inject
|
|
15
|
-
# 4. Both empty → passthrough (server pre-guard skips when absent)
|
|
16
|
-
#
|
|
17
|
-
# NEVER exit non-zero — backwards-compat passthrough when resolver is broken.
|
|
18
|
-
|
|
19
|
-
INPUT=$(cat)
|
|
20
|
-
|
|
21
|
-
TOOL_NAME=$(echo "$INPUT" | jq -r '.tool_name // empty' 2>/dev/null)
|
|
22
|
-
|
|
23
|
-
# Only intercept matching MCP mutation tools
|
|
24
|
-
case "$TOOL_NAME" in
|
|
25
|
-
mcp__codebyplan__update_task|\
|
|
26
|
-
mcp__codebyplan__complete_task|\
|
|
27
|
-
mcp__codebyplan__complete_round|\
|
|
28
|
-
mcp__codebyplan__update_checkpoint) ;;
|
|
29
|
-
*) exit 0 ;;
|
|
30
|
-
esac
|
|
31
|
-
|
|
32
|
-
# If caller_worktree_id is already present, pass through unchanged
|
|
33
|
-
EXISTING=$(echo "$INPUT" | jq -r '.tool_input.caller_worktree_id // empty' 2>/dev/null)
|
|
34
|
-
if [ -n "$EXISTING" ]; then
|
|
35
|
-
exit 0
|
|
36
|
-
fi
|
|
37
|
-
|
|
38
|
-
# Try primary resolver
|
|
39
|
-
UUID=$(npx --yes codebyplan resolve-worktree 2>/dev/null)
|
|
40
|
-
|
|
41
|
-
# Try fallback if primary returned empty
|
|
42
|
-
if [ -z "$UUID" ]; then
|
|
43
|
-
UUID=$(npx --yes codebyplan resolve-worktree --fallback-from-branch 2>/dev/null)
|
|
44
|
-
fi
|
|
45
|
-
|
|
46
|
-
# If no UUID resolved, passthrough unchanged
|
|
47
|
-
if [ -z "$UUID" ]; then
|
|
48
|
-
exit 0
|
|
49
|
-
fi
|
|
50
|
-
|
|
51
|
-
# Extract tool_input and guard against null before merging
|
|
52
|
-
TOOL_INPUT=$(echo "$INPUT" | jq -c '.tool_input' 2>/dev/null)
|
|
53
|
-
if [ -z "$TOOL_INPUT" ] || [ "$TOOL_INPUT" = "null" ]; then
|
|
54
|
-
# No tool_input to mutate — output original input unchanged
|
|
55
|
-
echo "$INPUT"
|
|
56
|
-
exit 0
|
|
57
|
-
fi
|
|
58
|
-
|
|
59
|
-
MERGED_TOOL_INPUT=$(echo "$TOOL_INPUT" | jq -c --arg uuid "$UUID" '. + {caller_worktree_id: $uuid}' 2>/dev/null)
|
|
60
|
-
if [ -z "$MERGED_TOOL_INPUT" ] || [ "$MERGED_TOOL_INPUT" = "null" ]; then
|
|
61
|
-
echo "$INPUT"
|
|
62
|
-
exit 0
|
|
63
|
-
fi
|
|
64
|
-
|
|
65
|
-
# Output PreToolUse hookSpecificOutput with updatedInput
|
|
66
|
-
jq -n \
|
|
67
|
-
--argjson updated "$MERGED_TOOL_INPUT" \
|
|
68
|
-
'{
|
|
69
|
-
hookSpecificOutput: {
|
|
70
|
-
hookEventName: "PreToolUse",
|
|
71
|
-
permissionDecision: "allow",
|
|
72
|
-
updatedInput: $updated
|
|
73
|
-
}
|
|
74
|
-
}'
|
|
75
|
-
|
|
76
|
-
exit 0
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|