codebyplan 1.12.0 → 1.13.3

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.
Files changed (39) hide show
  1. package/dist/cli.js +2648 -2033
  2. package/package.json +2 -2
  3. package/templates/github-workflows/publish.yml +207 -0
  4. package/templates/hooks/README.md +1 -13
  5. package/templates/hooks/cbp-test-coverage-gate.sh +8 -0
  6. package/templates/hooks/cbp-test-hooks.sh +0 -42
  7. package/templates/hooks/hooks.json +0 -9
  8. package/templates/settings.project.base.json +154 -3
  9. package/templates/skills/cbp-build-cc-settings/SKILL.md +2 -0
  10. package/templates/skills/cbp-build-cc-settings/reference/cbp-permission-policy.md +48 -0
  11. package/templates/skills/cbp-checkpoint-end/SKILL.md +7 -0
  12. package/templates/skills/cbp-checkpoint-start/SKILL.md +2 -2
  13. package/templates/skills/cbp-session-start/SKILL.md +1 -1
  14. package/templates/skills/{cbp-e2e-setup → cbp-setup-e2e}/SKILL.md +1 -1
  15. package/templates/skills/cbp-setup-eslint/SKILL.md +199 -0
  16. package/templates/skills/cbp-setup-eslint/reference/base.md +82 -0
  17. package/templates/skills/cbp-setup-eslint/reference/cli.md +56 -0
  18. package/templates/skills/cbp-setup-eslint/reference/e2e.md +68 -0
  19. package/templates/skills/cbp-setup-eslint/reference/jest.md +59 -0
  20. package/templates/skills/cbp-setup-eslint/reference/nestjs.md +69 -0
  21. package/templates/skills/cbp-setup-eslint/reference/nextjs.md +63 -0
  22. package/templates/skills/cbp-setup-eslint/reference/node.md +74 -0
  23. package/templates/skills/cbp-setup-eslint/reference/react-native.md +60 -0
  24. package/templates/skills/cbp-setup-eslint/reference/react.md +82 -0
  25. package/templates/skills/cbp-setup-eslint/reference/tailwind.md +64 -0
  26. package/templates/skills/cbp-setup-eslint/reference/testing-react.md +57 -0
  27. package/templates/skills/cbp-setup-eslint/reference/vitest.md +62 -0
  28. package/templates/skills/cbp-ship/reference/versioning.md +31 -3
  29. package/templates/skills/cbp-ship-configure/SKILL.md +16 -36
  30. package/templates/skills/cbp-ship-configure/reference/npm-package.md +15 -6
  31. package/templates/skills/cbp-ship-main/SKILL.md +4 -0
  32. package/templates/skills/cbp-task-complete/SKILL.md +1 -3
  33. package/templates/skills/cbp-task-start/SKILL.md +3 -3
  34. package/templates/hooks/cbp-mcp-worktree-inject.sh +0 -76
  35. /package/templates/skills/{cbp-e2e-setup → cbp-setup-e2e}/reference/maestro.md +0 -0
  36. /package/templates/skills/{cbp-e2e-setup → cbp-setup-e2e}/reference/playwright.md +0 -0
  37. /package/templates/skills/{cbp-e2e-setup → cbp-setup-e2e}/reference/tauri.md +0 -0
  38. /package/templates/skills/{cbp-e2e-setup → cbp-setup-e2e}/reference/vscode.md +0 -0
  39. /package/templates/skills/{cbp-e2e-setup → cbp-setup-e2e}/reference/xcuitest.md +0 -0
@@ -0,0 +1,60 @@
1
+ # react-native — React Native / Expo flat config
2
+
3
+ For Expo / React Native apps (the CBP `livebyplan` mobile app). **Gap stack — no CBP DB
4
+ preset.** Use Expo's official lint config.
5
+
6
+ > **Verified 2026-05-31.** `eslint-config-expo` is the official config and ships **flat config
7
+ > by default from Expo SDK 53** onward (SDK 52 and earlier use legacy `.eslintrc`).
8
+
9
+ ## Packages
10
+
11
+ | Package | Latest | Purpose |
12
+ | ------- | ------ | ------- |
13
+ | `eslint-config-expo` | `56.0.4` | Expo's flat config (`/flat` subpath) |
14
+
15
+ ```bash
16
+ npx expo lint # installs eslint + eslint-config-expo and scaffolds eslint.config.js
17
+ ```
18
+
19
+ `eslint-config-expo` bundles `eslint-plugin-expo`, `eslint-plugin-react`,
20
+ `eslint-plugin-react-hooks`, `eslint-plugin-import`, and `@typescript-eslint/*`. It does **not**
21
+ bundle `eslint-plugin-react-native` (that's a separate optional add-on, `@5.0.0`).
22
+
23
+ ## Flat config
24
+
25
+ Expo's template is **CommonJS `eslint.config.js`** (not `.mjs`):
26
+
27
+ ```js
28
+ // eslint.config.js
29
+ const { defineConfig } = require("eslint/config");
30
+ const expoConfig = require("eslint-config-expo/flat");
31
+ const eslintPluginPrettierRecommended = require("eslint-plugin-prettier/recommended");
32
+
33
+ module.exports = defineConfig([
34
+ expoConfig,
35
+ eslintPluginPrettierRecommended,
36
+ { ignores: ["dist/*"] },
37
+ ]);
38
+ ```
39
+
40
+ Minimal form (no Prettier): just `expoConfig` in the array.
41
+
42
+ ## Gotchas
43
+
44
+ - RN platform support comes from RN global variables + platform file extensions
45
+ (`.android.ts`, `.ios.ts`, `.web.ts`) and `eslint-plugin-expo` — **not** from
46
+ `eslint-plugin-react-native`. Add `eslint-plugin-react-native@5.0.0` manually only if you
47
+ want RN-specific rules (`no-inline-styles`, `no-unused-styles`).
48
+ - Run linting with `npx expo lint` (it wires the config the first time).
49
+ - Expo apps test with **Jest** — add the [jest.md](jest.md) override.
50
+
51
+ ## CBP preset divergence
52
+
53
+ There is **no** CBP `react-native`/`expo` DB preset, and the `react` preset `excludes`
54
+ nothing for RN but is browser-globals oriented. Use `eslint-config-expo/flat` directly; the
55
+ skill does not add a preset for this stack.
56
+
57
+ ## Official docs
58
+
59
+ - Using ESLint in Expo: https://docs.expo.dev/guides/using-eslint/
60
+ - eslint-config-expo: https://github.com/expo/expo/tree/main/packages/eslint-config-expo
@@ -0,0 +1,82 @@
1
+ # react — standalone React (Vite, Tauri) flat config
2
+
3
+ For React apps that are **not** Next.js (Vite SPA, Tauri desktop webview). Layers on
4
+ [base](base.md). Maps to the CBP **`react`** DB preset
5
+ (`tech_match.requires: ["React"]`, `excludes: ["Next.js"]`, `requires_capabilities: ["jsx"]`).
6
+
7
+ > **Verified 2026-05-31.** **Do NOT install `eslint-plugin-react-compiler`** — it is
8
+ > superseded. React Compiler v1.0 (Oct 2025) merged the compiler lint rules into
9
+ > **`eslint-plugin-react-hooks@7`** under `configs.flat["recommended-latest"]`.
10
+
11
+ ## Packages
12
+
13
+ | Package | Latest | Purpose |
14
+ | ------- | ------ | ------- |
15
+ | `eslint-plugin-react` | `7.37.5` | React rules + JSX parsing (`configs.flat.*`) |
16
+ | `eslint-plugin-react-hooks` | `7.1.1` | hooks rules **+ bundled React Compiler rules** |
17
+ | `eslint-plugin-jsx-a11y` | `6.10.2` | accessibility (`flatConfigs.*` — note plural) |
18
+
19
+ ```bash
20
+ pnpm add -D eslint-plugin-react eslint-plugin-react-hooks eslint-plugin-jsx-a11y globals
21
+ ```
22
+
23
+ ## Flat config
24
+
25
+ ```js
26
+ // eslint.config.mjs
27
+ import { defineConfig } from "eslint/config";
28
+ import react from "eslint-plugin-react";
29
+ import reactHooks from "eslint-plugin-react-hooks";
30
+ import jsxA11y from "eslint-plugin-jsx-a11y";
31
+ import globals from "globals";
32
+
33
+ export default defineConfig([
34
+ react.configs.flat.recommended, // namespaced react/, enables JSX parsing
35
+ react.configs.flat["jsx-runtime"], // React 17+ automatic JSX transform
36
+ reactHooks.configs.flat["recommended-latest"], // hooks + React Compiler rules
37
+ jsxA11y.flatConfigs.strict, // or flatConfigs.recommended
38
+ {
39
+ files: ["**/*.{js,jsx,ts,tsx}"],
40
+ languageOptions: { globals: globals.browser },
41
+ settings: { react: { version: "detect" } },
42
+ },
43
+ ]);
44
+ ```
45
+
46
+ ## Gotchas
47
+
48
+ - **`eslint-plugin-react` flat configs do not set `files` or globals** — add your own
49
+ `files`/`globals.browser`/`settings.react.version` object (shown above) or you'll get the
50
+ "React version not specified" warning and no JSX globals.
51
+ - **`eslint-plugin-react-hooks` v7 keys** live under `configs.flat.*`:
52
+ `recommended` (standard hooks) vs `recommended-latest` (hooks **+ compiler** rules — use
53
+ this for React 19 + the compiler).
54
+ - **`jsx-a11y` uses `flatConfigs` (plural)** — `jsxA11y.flatConfigs.strict`, a different
55
+ namespace from react's `configs.flat`.
56
+
57
+ ## Storybook (bonus)
58
+
59
+ If the app uses Storybook, add `eslint-plugin-storybook@10.4.1`:
60
+
61
+ ```js
62
+ import storybook from "eslint-plugin-storybook";
63
+ // ...spread into the array:
64
+ ...storybook.configs["flat/recommended"],
65
+ ```
66
+
67
+ The standalone plugin repo was archived (2025-11); it now lives in the Storybook monorepo but
68
+ the npm name `eslint-plugin-storybook` is unchanged.
69
+
70
+ ## CBP preset divergence
71
+
72
+ CBP's `react` preset still depends on `eslint-plugin-react-compiler: ^19.0.0` and registers
73
+ `react-compiler/react-compiler`. The latest guidance removes that plugin and relies on
74
+ `eslint-plugin-react-hooks@7`'s `recommended-latest`. Adopt that when regenerating; the skill
75
+ does not modify the preset.
76
+
77
+ ## Official docs
78
+
79
+ - eslint-plugin-react: https://github.com/jsx-eslint/eslint-plugin-react
80
+ - react-hooks: https://react.dev/reference/eslint-plugin-react-hooks
81
+ - React Compiler v1.0: https://react.dev/blog/2025/10/07/react-compiler-1
82
+ - jsx-a11y: https://github.com/jsx-eslint/eslint-plugin-jsx-a11y
@@ -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
@@ -2,11 +2,12 @@
2
2
 
3
3
  How `/cbp-ship` decides which version a surface ships at.
4
4
 
5
- ## Three modes (per surface, configured per-package)
5
+ ## Four modes (per surface, configured per-package)
6
6
 
7
7
  | Mode | Trigger | Best for |
8
8
  |---|---|---|
9
9
  | `manual` | User bumps `package.json` / `tauri.conf.json` / `app.json` version themselves before checkpoint shipment | Apps with infrequent releases; small teams |
10
+ | `in-branch-bump` | `codebyplan ship` detects changed workspace packages via `git diff <base>...HEAD`, patch-bumps each one, and commits a `chore(release): bump versions` commit on the feat branch BEFORE push + PR creation — so the bump rides the same feat→main PR | npm/CLI packages in a pnpm monorepo using the codebyplan CLI; never-missed patch bumps |
10
11
  | `release-please` | GH Actions opens version-bump PRs based on conventional commit messages on the watched branch; merge the PR before shipment | npm packages with frequent releases; multi-contributor repos |
11
12
  | `changesets` | Devs add `.changeset/*.md` entries in feature branches; an aggregator PR collects them | Monorepos with many independent packages |
12
13
 
@@ -16,7 +17,7 @@ Mode is set per-surface in `.codebyplan/shipment.json`:
16
17
  {
17
18
  "surfaces": {
18
19
  "npm-package": {
19
- "packages/codebyplan-package": { "versioning": "release-please" }
20
+ "packages/codebyplan-package": { "versioning": "in-branch-bump" }
20
21
  },
21
22
  "tauri-desktop": { "versioning": "manual" },
22
23
  "expo-mobile": { "versioning": "auto-build-number" }
@@ -59,6 +60,32 @@ Conventional Commits are the trigger:
59
60
 
60
61
  The release-please workflow lives at `.github/workflows/release-please.yml` (scaffolded by `/cbp-ship-configure`).
61
62
 
63
+ > **Retired in this repo.** CodeByPlan itself no longer uses release-please — its `release-please.yml`, `release-please-config.json`, and `.release-please-manifest.json` were removed in favour of the **publish-on-main model** (see in-branch-bump conventions below). `package.json` `version` is the sole version-of-record. The release-please workflow + config templates remain available under `templates/skills/cbp-ship/templates/` for consuming repos that prefer the conventional-commit Release-PR flow.
64
+
65
+ ## in-branch-bump conventions
66
+
67
+ `codebyplan ship` (the CLI behind `/cbp-ship-main` and `/cbp-checkpoint-end`) runs the bump engine as part of shipping — no separate release PR, no conventional-commit parsing:
68
+
69
+ 1. **When** — after the main-sync merge (`/cbp-merge-main`) and the clean-tree check, BEFORE `git push` + PR creation. The bump therefore rides the same feat→main PR.
70
+ 2. **What changed** — `git diff <base>...HEAD` (base from `.codebyplan/git.json`, preferring `origin/<base>`) maps changed files to their owning workspace packages via the `pnpm-workspace.yaml` globs.
71
+ 3. **Bump** — every changed package/app is patch-bumped (`x.y.z → x.y.(z+1)`) in its version file (`package.json`, `src-tauri/tauri.conf.json`, Expo `app.json`), and a CHANGELOG entry is prepended where a `CHANGELOG.md` already exists.
72
+ 4. **Commit** — the bumped files are committed as `chore(release): bump versions` on the feat branch.
73
+ 5. **Idempotent** — a package whose working-tree version already exceeds its base version is skipped, so re-running ship never double-bumps.
74
+
75
+ `codebyplan ship` is a non-interactive pipeline (bump → push → PR → checks → merge), so there is no confirm-before-merge prompt. To preview the planned bumps WITHOUT committing, run `codebyplan ship --dry-run` (or `codebyplan bump --dry-run`); opt a single real ship out of bumping with `codebyplan ship --no-bump`. The bumps committed on the feat branch are reported in the ship summary (and in `--json` as `bumps[]`). On merge to the production branch, version-change detection publishes each surface whose committed version now exceeds its published version (retiring the release-please Release-PR trigger).
76
+
77
+ ### publish-on-main model
78
+
79
+ The bump is only half the loop — publishing is the other half. On every push to the production branch, `.github/workflows/publish.yml` closes it:
80
+
81
+ 1. **check-version** — reads the committed `package.json` `version` and compares it to the live `npm view <pkg> version`. Publish proceeds only when the committed version is strictly greater (semver-aware, via `sort -V`); an unchanged or lower version is a no-op. A never-published package is treated as publishable (first release).
82
+ 2. **publish** — builds and runs `npm publish --access public` via OIDC Trusted Publishing (no `NPM_TOKEN`; requires npm ≥ 11.5.1). `workflow_dispatch` keeps a manual recovery path (always publishes the current version) plus a `dry_run` input that prints the decision without publishing.
83
+ 3. **tag + release** — only after a successful publish, creates the `v{version}` git tag + a GitHub release (idempotent — skipped if the tag already exists, so no orphan tags on a failed publish).
84
+
85
+ There is **no separate Release PR** — the version committed in the feat branch is the version that ships, so `package.json` is the sole version-of-record. The desktop surface keeps its own `release-desktop.yml` (tauri version vs `desktop-v{version}` tag), which the in-branch `tauri.conf.json` bump feeds automatically.
86
+
87
+ Other repos inherit this workflow via `codebyplan scaffold-publish-workflow`, which writes `templates/github-workflows/publish.yml` into their `.github/workflows/`. (`.github/` is outside the `codebyplan claude install` target — which only writes under `.claude/` — so the publish workflow has its own scaffold command.)
88
+
62
89
  ## changesets conventions
63
90
 
64
91
  A changeset is a markdown file describing the change:
@@ -98,7 +125,7 @@ When multiple surfaces ship together, bumps may need to coordinate:
98
125
 
99
126
  ## What NOT to do
100
127
 
101
- - Don't manually edit `package.json` version inside `/cbp-ship` — versioning happens before shipment, not during
128
+ - Don't hand-edit `package.json` version mid-shipment in `manual` / `release-please` / `changesets` modes — versioning happens before shipment, not during. (`in-branch-bump` inverts this: `codebyplan ship` bumps + commits automatically, after the main-sync merge and before PR creation, so the bump rides the single feat→main PR.)
102
129
  - Don't auto-bump in `manual` mode without confirmation — the user owns the bump
103
130
  - Don't squash changeset commits — release-please / changesets need each conventional commit visible
104
131
  - Don't tag a Tauri release before the version commit is on PRODUCTION branch — the tag locks the shipped version
@@ -107,6 +134,7 @@ When multiple surfaces ship together, bumps may need to coordinate:
107
134
 
108
135
  | Question | If yes |
109
136
  |---|---|
137
+ | Is this an npm/CLI package in a pnpm monorepo shipped via the codebyplan CLI? | in-branch-bump |
110
138
  | Is this an npm package with multiple authors? | release-please |
111
139
  | Is this a monorepo with 3+ published packages? | changesets |
112
140
  | Is this a single app with infrequent releases? | manual |
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  scope: org-shared
3
3
  name: cbp-ship-configure
4
- description: Configure shipment for one or more surfaces in the current repo — Vercel link, EAS project + eas.json scaffold, Apple credentials probe, npm publish auth check (including `codebyplan` asset-publish automation via release-please), Railway project link, Supabase access token verify; Supabase GitHub branching integration via /cbp-supabase-setup. Interactive step-by-step; never stores credentials in the repo.
4
+ description: Configure shipment for one or more surfaces in the current repo — Vercel link, EAS project + eas.json scaffold, Apple credentials probe, npm publish auth check (including `codebyplan` asset-publish automation via the publish-on-main workflow), Railway project link, Supabase access token verify; Supabase GitHub branching integration via /cbp-supabase-setup. Interactive step-by-step; never stores credentials in the repo.
5
5
  argument-hint: [--surface=<id>]
6
6
  allowed-tools: Read, Write, Edit, Bash(which *), Bash(vercel *), Bash(eas *), Bash(npm *), Bash(railway *), Bash(jq *), Bash(mkdir *), Bash(cp *), Bash(echo *), Skill(cbp-supabase-setup)
7
7
  effort: xhigh
@@ -152,22 +152,23 @@ If multiple surfaces were configured, list each one's status. If any failed, lis
152
152
 
153
153
  Re-running on an already-configured surface re-runs the probe (CLI installed? logged in? token still valid?) and refreshes the `.codebyplan/shipment.json` block. It does NOT replace credentials — those stay where the CLI keeps them. This is the primary path for "I rotated my npm token, does shipment still work?" — re-run, the probe catches the bad token immediately.
154
154
 
155
- ## Special case: opt-in to release-please
155
+ ## Special case: versioning mode (npm-package)
156
156
 
157
- `release-please` is one of three versioning modes (manual, release-please, changesets). Opt-in is part of npm-package configure:
157
+ Picking a versioning mode is part of npm-package configure:
158
158
 
159
159
  ```
160
160
  Step N/M: Versioning mode
161
161
  A) Manual — bump package.json version yourself before /cbp-ship
162
- B) release-pleaseGH Action opens version-bump PRs based on conventional commits (recommended for npm packages)
163
- C) changesetsmanual changeset entries; tooling aggregates into version PRs (recommended for monorepos with many published packages)
162
+ B) in-branch-bump`codebyplan ship` patch-bumps changed packages in the feat branch; merge to main auto-publishes via the publish-on-main workflow (recommended for codebyplan-CLI repos)
163
+ C) release-pleaseGH Action opens version-bump PRs based on conventional commits
164
+ D) changesets — manual changeset entries; tooling aggregates into version PRs (recommended for monorepos with many published packages)
164
165
  ```
165
166
 
166
- If B or C, the skill scaffolds the GitHub Actions workflow + config file (`templates/workflows/release-please.yml` or `.changeset/config.json`).
167
+ If B, the skill scaffolds the publish-on-main workflow via `codebyplan scaffold-publish-workflow` (see the `codebyplan` asset-publish automation section below). If C or D, the skill scaffolds the GitHub Actions workflow + config file (`templates/workflows/release-please.yml` or `.changeset/config.json`). See [../ship/reference/versioning.md](../ship/reference/versioning.md) for the full mode comparison.
167
168
 
168
169
  ## Special case: `codebyplan` asset-publish automation
169
170
 
170
- The canonical-owner repo publishes the `codebyplan` npm package — the distribution mechanism for `scope: org-shared` skills/agents/hooks (via its `claude install|update|uninstall` subcommand group). Sibling repos consume it via `npx codebyplan claude update` (the merged CLI; package path `packages/codebyplan-package/`). This branch handles the once-per-repo setup so release-please can autopublish on merge to main. (CHK-132 consolidated the prior standalone `@codebyplan/claude` package into `codebyplan`; the legacy `@codebyplan/claude` package on npm stays un-deprecated at its last published version for backward-compat, but receives no further updates.)
171
+ The canonical-owner repo publishes the `codebyplan` npm package — the distribution mechanism for `scope: org-shared` skills/agents/hooks (via its `claude install|update|uninstall` subcommand group). Sibling repos consume it via `npx codebyplan claude update` (the merged CLI; package path `packages/codebyplan-package/`). This branch handles the once-per-repo setup so the package autopublishes on merge to main via the publish-on-main workflow. (CHK-132 consolidated the prior standalone `@codebyplan/claude` package into `codebyplan`; the legacy `@codebyplan/claude` package on npm stays un-deprecated at its last published version for backward-compat, but receives no further updates.)
171
172
 
172
173
  When the user picks `--surface=npm-package` AND the detected package is `packages/codebyplan-package`, the walkthrough runs these extra probes / scaffolds in addition to the standard npm-package configurator (see [reference/npm-package.md](reference/npm-package.md)):
173
174
 
@@ -190,38 +191,17 @@ Confirms the logged-in account has read on the `@codebyplan` org scope. If 404 /
190
191
  - Either the user does not belong to the `@codebyplan` org → STOP, request invitation from org owner
191
192
  - Or the scope is unclaimed → user creates the org at https://www.npmjs.com/org/create (org name `codebyplan`, free public-packages tier)
192
193
 
193
- ### Scaffold 1 release-please workflow
194
+ ### Scaffold — publish-on-main workflow
194
195
 
195
- If `.github/workflows/release-please.yml` is absent:
196
+ The package autopublishes via `.github/workflows/publish.yml` (the publish-on-main model — version-change detection on merge to main, no Release PR). Scaffold it with the CLI:
196
197
 
197
198
  ```bash
198
- mkdir -p .github/workflows
199
- cp "${CLAUDE_SKILL_DIR}/../ship/templates/workflow-release-please.yml" .github/workflows/release-please.yml
200
- # Then replace REPLACE_WITH_INTEGRATION_BRANCH with the production branch from .codebyplan/git.json branch_config.production (typically `main`)
199
+ codebyplan scaffold-publish-workflow
201
200
  ```
202
201
 
203
- The mechanics + commit-prefix bump-tier mapping live in [../ship/reference/release-please-overview.md](../ship/reference/release-please-overview.md).
202
+ This writes `templates/github-workflows/publish.yml` into `.github/workflows/publish.yml` (idempotent — re-running on an identical file is a no-op; pass `--force` to overwrite a divergent one, `--dry-run` to preview). `.github/` is outside the `codebyplan claude install` target (which only writes under `.claude/`), so the publish workflow has its own scaffold command rather than riding `claude install`.
204
203
 
205
- ### Scaffold 2 — release-please-config.json at repo root
206
-
207
- If `release-please-config.json` is absent:
208
-
209
- ```bash
210
- cp "${CLAUDE_SKILL_DIR}/../ship/templates/release-please-config.json" release-please-config.json
211
- # Then replace REPLACE_WITH_PACKAGE_NAME with codebyplan
212
- # Confirm `packages."."` block is replaced with `packages."packages/codebyplan-package"`
213
- ```
214
-
215
- ### Scaffold 3 — .release-please-manifest.json at repo root
216
-
217
- If `.release-please-manifest.json` is absent:
218
-
219
- ```bash
220
- VERSION=$(jq -r '.version' packages/codebyplan-package/package.json)
221
- echo "{\"packages/codebyplan-package\": \"${VERSION}\"}" > .release-please-manifest.json
222
- ```
223
-
224
- (Bootstrap version reads from `packages/codebyplan-package/package.json` `version` field at scaffold time.)
204
+ The workflow needs no per-bump editing: it reads `package.json` `version` at run time, compares it to `npm view`, and publishes only when the committed version is greater. `package.json` is the sole version-of-record there is no `release-please-config.json` / `.release-please-manifest.json`. (Repos that prefer the conventional-commit Release-PR flow can still scaffold release-please from `../ship/templates/` instead — see [../ship/reference/release-please-overview.md](../ship/reference/release-please-overview.md).)
225
205
 
226
206
  ### Verify — publishConfig.access on the package
227
207
 
@@ -249,8 +229,8 @@ Required value: `public`. If `missing` or `restricted`, instruct the user to add
249
229
  "packages/codebyplan-package": {
250
230
  "package_name": "codebyplan",
251
231
  "bin_name": "codebyplan",
252
- "versioning": "release-please",
253
- "publish_mode": "release-please-on-merge-to-main",
232
+ "versioning": "in-branch-bump",
233
+ "publish_mode": "publish-on-main",
254
234
  "access": "public"
255
235
  }
256
236
  }
@@ -258,7 +238,7 @@ Required value: `public`. If `missing` or `restricted`, instruct the user to add
258
238
  }
259
239
  ```
260
240
 
261
- After this branch completes, every merge to main with `feat:` / `fix:` / `feat!:` Conventional Commits will trigger release-please to open a version-bump PR. When the maintainer merges that PR, release-please tags the release and `npm publish` runs from the workflow (auth via `NODE_AUTH_TOKEN` GH secret or OIDC trusted publishing see [../ship/reference/npm-publish-oidc-trusted.md](../ship/reference/npm-publish-oidc-trusted.md)). Siblings then pick up the new asset content via `npx codebyplan claude update`.
241
+ After this branch completes, the publish loop is fully automatic: `codebyplan ship` patch-bumps the package in the feat branch (rides the single feat→main PR), and on merge to main `publish.yml` detects the committed version exceeds the npm-published version and runs `npm publish` via OIDC trusted publishing (see [../ship/reference/npm-publish-oidc-trusted.md](../ship/reference/npm-publish-oidc-trusted.md)), then tags `v{version}` + cuts a GitHub release. No separate Release PR. Siblings then pick up the new asset content via `npx codebyplan claude update`.
262
242
 
263
243
  ## Special case: Apple credentials for TestFlight
264
244
 
@@ -2,7 +2,7 @@
2
2
 
3
3
  Walkthrough for first-time npm publish setup.
4
4
 
5
- > **Special case** — when the package being configured is `packages/codebyplan-package` (i.e., the `codebyplan` npm package that ships `scope: org-shared` skills/agents/hooks via its `claude` asset subcommand group), the parent SKILL.md "Special case: `codebyplan` asset-publish automation" section runs additional probes (npm whoami, npm publish auth) and scaffolds (`release-please-config.json`, `.release-please-manifest.json` at repo root) on top of the generic walkthrough below. See SKILL.md for the full extra flow. (CHK-132 consolidated the prior `@codebyplan/claude` package into `codebyplan`.)
5
+ > **Special case** — when the package being configured is `packages/codebyplan-package` (i.e., the `codebyplan` npm package that ships `scope: org-shared` skills/agents/hooks via its `claude` asset subcommand group), the parent SKILL.md "Special case: `codebyplan` asset-publish automation" section runs additional probes (npm whoami, npm publish auth) and scaffolds the publish-on-main workflow (`.github/workflows/publish.yml` via `codebyplan scaffold-publish-workflow`) on top of the generic walkthrough below. See SKILL.md for the full extra flow. (CHK-132 consolidated the prior `@codebyplan/claude` package into `codebyplan`.)
6
6
 
7
7
  ## Prerequisites
8
8
 
@@ -85,11 +85,20 @@ Surface any errors/warnings; offer to fix obvious ones (missing `files`, wrong `
85
85
 
86
86
  ```
87
87
  A) Manual — bump package.json version yourself before each release
88
- B) release-pleaseGH Action opens version-bump PRs based on conventional commits (recommended)
89
- C) changesetsmanual changeset entries; aggregator PR (recommended for monorepos)
88
+ B) in-branch-bump`codebyplan ship` patch-bumps changed packages in the feat branch; merge to main auto-publishes via the publish-on-main workflow (recommended for codebyplan-CLI repos)
89
+ C) release-pleaseGH Action opens version-bump PRs based on conventional commits
90
+ D) changesets — manual changeset entries; aggregator PR (recommended for monorepos)
90
91
  ```
91
92
 
92
- If B, scaffold:
93
+ If B, scaffold the publish-on-main workflow (idempotent; `--force` overwrites, `--dry-run` previews):
94
+
95
+ ```bash
96
+ codebyplan scaffold-publish-workflow
97
+ ```
98
+
99
+ `package.json` is the sole version-of-record — no `release-please-config.json` / `.release-please-manifest.json`. See [../../ship/reference/versioning.md](../../ship/reference/versioning.md) for the full model.
100
+
101
+ If C, scaffold:
93
102
 
94
103
  ```bash
95
104
  cp ${CLAUDE_PLUGIN_ROOT}/skills/ship/templates/workflow-release-please.yml .github/workflows/release-please.yml
@@ -97,7 +106,7 @@ cp ${CLAUDE_PLUGIN_ROOT}/skills/ship/templates/release-please-config.json releas
97
106
  echo '{".":"<current version>"}' > .release-please-manifest.json
98
107
  ```
99
108
 
100
- If C:
109
+ If D:
101
110
 
102
111
  ```bash
103
112
  cd "$REPO_ROOT"
@@ -134,7 +143,7 @@ The workflow uses `permissions: id-token: write` and runs `npm publish --provena
134
143
  "configured_at": "<now>",
135
144
  "packages/codebyplan-package": {
136
145
  "package_name": "codebyplan",
137
- "versioning": "release-please",
146
+ "versioning": "in-branch-bump",
138
147
  "publish_mode": "oidc",
139
148
  "access": "public"
140
149
  }
@@ -48,10 +48,14 @@ codebyplan ship --body-file /tmp/cbp-ship-main-body.md --json${DRY_RUN:+ --dry-r
48
48
 
49
49
  Pass `--dry-run` through if the skill was invoked with a dry-run arg.
50
50
 
51
+ `codebyplan ship` patch-bumps every changed workspace package and commits `chore(release): bump versions` on the feat branch BEFORE creating the PR, so the bump rides this same feat→main PR (see `cbp-ship/reference/versioning.md`, `in-branch-bump` mode). Pass `--no-bump` to skip for a single ship.
52
+
51
53
  ### Step 4: Report
52
54
 
53
55
  Parse JSON from Step 3. Report `pr_url`, `merge_commit`, `branch_deleted`. If `checks_failed: true`, surface `checks_failure_reason` and stop.
54
56
 
57
+ If `bumps[]` is present with any non-skipped entry, surface a **Version bumps** line per package — `<name>: <currentVersion> → <nextVersion>` — so the user sees what this PR will publish on merge.
58
+
55
59
  If `branch_deleted === true`, run a conditional Supabase preview-branch teardown for the feat branch that was just merged:
56
60
 
57
61
  > Lifecycle contract: see [[supabase-branch-lifecycle]].
@@ -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
- If `CALLER_WT` is non-empty, call `complete_task(task_id, caller_worktree_id: CALLER_WT)`. Otherwise call `complete_task(task_id)` with no worktree id the pre-guard is skipped (backwards-compat).
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 TASK-2 — DB-level hard-lock prevents cross-worktree mutations.)
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)`. If empty, the `caller_worktree_id` parameter is omitted from the MCP call entirely — the pre-guard is skipped and the update proceeds without a worktree check (backwards-compat).
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 AND `caller_worktree_id: CALLER_WT` so the MCP server's pre-guard accepts the call (CHK-104 TASK-2 hard-lock).
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