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,199 @@
1
+ ---
2
+ scope: org-shared
3
+ name: cbp-setup-eslint
4
+ description: Detect each app's tech stack, resolve matching DB ESLint presets, confirm which to enable per app, run `codebyplan eslint init` to generate eslint.config.mjs, and write/refresh .codebyplan/eslint.json. Interactive, idempotent.
5
+ argument-hint: "[--force]"
6
+ model: sonnet
7
+ effort: xhigh
8
+ allowed-tools: Read, Write, Edit, Bash(cat *), Bash(jq *), Bash(test *), Bash(ls *), Bash(mkdir *), Bash(cp *), Bash(echo *), Bash(mv *), Bash(npx codebyplan eslint *), AskUserQuestion, mcp__codebyplan__get_repos, mcp__codebyplan__get_eslint_presets
9
+ ---
10
+
11
+ # ESLint Setup
12
+
13
+ Configure ESLint flat config (`eslint.config.mjs`) across the repo's apps: detect each
14
+ app's tech stack, resolve the DB ESLint presets that match it, generate per-app configs via
15
+ `codebyplan eslint init`, and record the enabled presets in `.codebyplan/eslint.json` so the
16
+ setup is reproducible and refreshes idempotently.
17
+
18
+ Invoke at any time. Already-configured apps are preserved unless `--force` is passed.
19
+ Pass `--force` to re-ask every app and re-resolve presets from scratch.
20
+
21
+ The DB ESLint presets are the source of truth for rule bodies; `.codebyplan/eslint.json`
22
+ only records *which* presets are enabled per app (the rules live in the generated
23
+ `eslint.config.mjs` and the DB). See `reference/*.md` for the latest official flat-config
24
+ setup per stack — including stacks that have **no preset yet** (manual-config guidance).
25
+
26
+ ## Arguments
27
+
28
+ Inspect `$ARGUMENTS` for `--force`. If present, set `force_mode = true`.
29
+ Absent: idempotent mode — preserve existing `apps[*]` entries in `.codebyplan/eslint.json`,
30
+ skip re-asking already-configured apps.
31
+
32
+ ## Step 1 — Detect apps + per-app tech
33
+
34
+ Run two detection signals and merge:
35
+
36
+ **Signal A — DB tech_stack** via `mcp__codebyplan__get_repos` (match `repo_id` from
37
+ `.codebyplan/repo.json`). Read the repo's `tech_stack`:
38
+ - `tech_stack.apps[]` — each `{ name, path, stack[] }` is one app/package (monorepo).
39
+ - `tech_stack.flat[]` — the deduped repo-wide stack (single-app repos, or when `apps[]` is empty).
40
+
41
+ **Signal B — Filesystem fallback** (when `apps[]` is empty or stale). Discover workspaces the
42
+ same way `tech-detect.ts` does, then probe each app's `package.json`:
43
+
44
+ ```bash
45
+ # workspace globs → app dirs that contain a package.json
46
+ cat pnpm-workspace.yaml 2>/dev/null # packages: [...] globs
47
+ jq -r '.workspaces[]?' package.json 2>/dev/null # or package.json#workspaces
48
+ ```
49
+
50
+ For each app dir, read `package.json` dependencies to infer the stack (next → Next.js,
51
+ react → React, @nestjs/* → NestJS, vitest → Vitest, jest → Jest, @playwright/test →
52
+ Playwright, tailwindcss → Tailwind, expo → Expo, etc.). A single-app repo is one target
53
+ with `source_path: "."` and `app: "root"`.
54
+
55
+ **Signal C — Read existing `.codebyplan/eslint.json`** for the idempotent merge:
56
+
57
+ ```bash
58
+ cat .codebyplan/eslint.json 2>/dev/null || echo '{}'
59
+ ```
60
+
61
+ An app already present under `apps[<source_path>]` is "configured"; in non-`--force` mode it
62
+ is skipped in Step 3 (presets preserved verbatim).
63
+
64
+ ## Step 2 — Resolve matched presets
65
+
66
+ Call `mcp__codebyplan__get_eslint_presets` with `repo_id`. The response gives:
67
+ - `presets[]` — all system presets (base, nextjs, react, node, cli, testing, testing-react, testing-e2e).
68
+ - `matched[]` — the subset whose `tech_match` (requires / excludes / requires_capabilities) the
69
+ repo's DB tech_stack satisfies. **Use this — do not re-implement the matching client-side.**
70
+
71
+ `matched[]` is repo-wide. Attribute presets to apps by intersecting each app's detected tech
72
+ with each preset's `tech_match.requires` (e.g. `nextjs` → apps with Next.js; `node`/`cli` →
73
+ the Node/CLI packages; `testing-e2e` → apps with Playwright). The `base` preset applies to
74
+ every TypeScript app.
75
+
76
+ **Gap stacks have NO preset.** NestJS, React Native/Expo, Jest, Tailwind, and
77
+ WebdriverIO/Mocha are real stacks with no system preset. When an app's tech includes one,
78
+ flag it in Step 3 and point at its `reference/*.md` for manual setup — never silently drop it.
79
+
80
+ ## Step 3 — Confirm presets per app
81
+
82
+ For each detected app NOT already configured (or every app in `--force` mode), present its
83
+ matched presets and ask via AskUserQuestion (one batch per app, matched pre-checked):
84
+
85
+ ```
86
+ App: apps/web (Next.js + React + SCSS + Playwright + Vitest)
87
+ Enable which ESLint presets?
88
+ [x] base (TypeScript + security + Prettier)
89
+ [x] nextjs (Core Web Vitals + jsx-a11y + import order)
90
+ [x] testing (Vitest)
91
+ [x] testing-react (Testing Library + jest-dom)
92
+ [x] testing-e2e (Playwright)
93
+ Gap stacks with no preset (manual setup — see reference/):
94
+ · tailwind → reference/tailwind.md (if this app uses Tailwind)
95
+ ```
96
+
97
+ Record the confirmed preset-name list per app. Toggling is allowed; an app may opt out of a
98
+ matched preset or in to an unmatched one.
99
+
100
+ ## Step 4 — Generate config (`codebyplan eslint init`)
101
+
102
+ Offer to run the CLI, which detects tech, resolves presets, generates each
103
+ `eslint.config.mjs`, installs missing deps, and saves the DB config:
104
+
105
+ ```bash
106
+ npx codebyplan eslint init
107
+ ```
108
+
109
+ **Degrade gracefully.** The CLI is sometimes unavailable (OAuth/MCP env, stale bin). If it
110
+ errors or is absent, do NOT hard-fail — print the command for the user to run manually and
111
+ continue to Step 5 (the `.codebyplan/eslint.json` record is written regardless). For gap
112
+ stacks, point the user at the matching `reference/*.md` to hand-author the config.
113
+
114
+ ## Step 5 — Write `.codebyplan/eslint.json`
115
+
116
+ Build the payload conforming to the `EslintLocalConfig` schema
117
+ (`packages/codebyplan-package/src/lib/types.ts`): an `apps` map keyed by `source_path`, each
118
+ value an `EslintAppConfig` `{ app, enabled_presets[], rule_overrides?, config_path, reference_docs? }`.
119
+
120
+ Idempotency rule: deep-merge the new per-app entries onto the existing `apps` map so apps
121
+ skipped by the Step 3 gate keep their prior entry. Assemble in the shell, then write
122
+ atomically (tmp + mv) so the file is never left partial:
123
+
124
+ ```bash
125
+ EXISTING_APPS=$(jq -c '.apps // {}' .codebyplan/eslint.json 2>/dev/null || echo '{}')
126
+ APPS_JSON=$(echo "$EXISTING_APPS" | jq -c --argjson new "$NEW_APPS_JSON" '. * $new')
127
+ jq -n --argjson apps "$APPS_JSON" '{apps: $apps}' \
128
+ > .codebyplan/eslint.json.tmp && mv .codebyplan/eslint.json.tmp .codebyplan/eslint.json
129
+ ```
130
+
131
+ Example populated entry:
132
+
133
+ ```json
134
+ {
135
+ "apps": {
136
+ "apps/web": {
137
+ "app": "web",
138
+ "enabled_presets": ["base", "nextjs", "testing", "testing-react", "testing-e2e"],
139
+ "config_path": "apps/web/eslint.config.mjs",
140
+ "reference_docs": ["base", "nextjs", "testing-react", "e2e"]
141
+ }
142
+ }
143
+ }
144
+ ```
145
+
146
+ Only the `apps` field is written — `EslintLocalConfig` defines no other. Never store rule
147
+ bodies here; they live in the DB presets and the generated `eslint.config.mjs`.
148
+
149
+ ## Step 6 — Verify and report
150
+
151
+ Re-read `.codebyplan/eslint.json` and emit a per-app summary:
152
+
153
+ ```
154
+ ESLint Setup — Complete
155
+
156
+ App | Presets | Config | Gaps
157
+ ---------------------------- | ------------------------------------ | ------------------- | --------
158
+ apps/web | base, nextjs, testing, testing-react | apps/web/eslint…mjs | —
159
+ packages/codebyplan-package | base, node, cli, testing | …/eslint.config.mjs | —
160
+
161
+ eslint.json written to .codebyplan/eslint.json
162
+
163
+ Per-stack setup references — see reference docs:
164
+ base/typescript → reference/base.md nextjs → reference/nextjs.md
165
+ react → reference/react.md node → reference/node.md
166
+ nestjs → reference/nestjs.md cli → reference/cli.md
167
+ tailwind → reference/tailwind.md expo → reference/react-native.md
168
+ vitest → reference/vitest.md jest → reference/jest.md
169
+ testing-react → reference/testing-react.md e2e → reference/e2e.md
170
+ ```
171
+
172
+ If `codebyplan eslint init` was skipped (CLI unavailable), say so and restate the manual
173
+ command + which apps still need their `eslint.config.mjs` generated.
174
+
175
+ ## Key Rules
176
+
177
+ - DB presets are the source of truth for rule bodies — `.codebyplan/eslint.json` records only
178
+ which presets are enabled per app
179
+ - `get_eslint_presets` `matched[]` drives preset resolution — never re-implement tech matching
180
+ - Gap stacks (NestJS, Expo, Jest, Tailwind, WebdriverIO/Mocha) have no preset — point at
181
+ `reference/*.md`, never silently skip
182
+ - `codebyplan eslint init` failure is non-fatal — print the manual command and still write eslint.json
183
+ - Atomic write (tmp + mv) — never leave eslint.json partial
184
+ - Reference docs track the **latest official** flat-config setup and flag where CBP's DB
185
+ presets diverge (e.g. ESLint v10 + `eslint-plugin-react-hooks@7` bundled compiler rules)
186
+
187
+ ## Additional resources
188
+
189
+ - TypeScript foundation (ESLint v10 flat config): [reference/base.md](reference/base.md)
190
+ - Next.js: [reference/nextjs.md](reference/nextjs.md) · React (+ Storybook): [reference/react.md](reference/react.md)
191
+ - Node / Hono / Express: [reference/node.md](reference/node.md) · NestJS: [reference/nestjs.md](reference/nestjs.md)
192
+ - CLI tools: [reference/cli.md](reference/cli.md) · Tailwind CSS: [reference/tailwind.md](reference/tailwind.md)
193
+ - React Native / Expo: [reference/react-native.md](reference/react-native.md)
194
+ - Vitest: [reference/vitest.md](reference/vitest.md) · Jest: [reference/jest.md](reference/jest.md)
195
+ - Testing Library + jest-dom: [reference/testing-react.md](reference/testing-react.md)
196
+ - E2E (Playwright / WebdriverIO / Mocha): [reference/e2e.md](reference/e2e.md)
197
+ - ESLint local-config schema: `packages/codebyplan-package/src/lib/types.ts` (`EslintLocalConfig`)
198
+ - DB presets + generator: `mcp__codebyplan__get_eslint_presets`, `codebyplan eslint init`
199
+ - VS Code extension lint is not yet covered by a reference doc — use `reference/base.md` + `reference/node.md`.
@@ -0,0 +1,82 @@
1
+ # base — TypeScript foundation (ESLint v10 flat config)
2
+
3
+ The foundation every TypeScript app shares: ESLint flat config, type-checked
4
+ `typescript-eslint` rules, security scanning, and Prettier. Maps to the CBP **`base`** DB
5
+ preset (`tech_match.requires: ["TypeScript"]`).
6
+
7
+ > **Verified 2026-05-31.** ESLint is on **v10** — flat config (`eslint.config.mjs`) is the
8
+ > only native format (legacy `.eslintrc*` was removed). `defineConfig` from `eslint/config`
9
+ > is the canonical wrapper for every stack below.
10
+
11
+ ## Packages
12
+
13
+ | Package | Latest | Purpose |
14
+ | ------- | ------ | ------- |
15
+ | `eslint` | `10.4.1` | the linter (flat config only) |
16
+ | `@eslint/js` | `10.0.1` | `js.configs.recommended` |
17
+ | `typescript-eslint` | `8.60.0` | unified parser + plugin + presets |
18
+ | `eslint-config-prettier` | `10.x` | turns off formatting rules (subpath `/flat`) |
19
+ | `eslint-plugin-security` | `^3` | OWASP-style heuristics |
20
+ | `eslint-plugin-no-secrets` | `^2.1` | high-entropy string detection |
21
+ | `globals` | `17.6.0` | env global definitions |
22
+
23
+ ```bash
24
+ pnpm add -D eslint @eslint/js typescript-eslint eslint-config-prettier \
25
+ eslint-plugin-security eslint-plugin-no-secrets globals
26
+ ```
27
+
28
+ ## Flat config
29
+
30
+ ```js
31
+ // eslint.config.mjs
32
+ import { defineConfig } from "eslint/config";
33
+ import js from "@eslint/js";
34
+ import tseslint from "typescript-eslint";
35
+ import security from "eslint-plugin-security";
36
+ import noSecrets from "eslint-plugin-no-secrets";
37
+ import prettier from "eslint-config-prettier/flat";
38
+
39
+ export default defineConfig([
40
+ js.configs.recommended,
41
+ ...tseslint.configs.recommendedTypeChecked, // type-aware: no-floating-promises, etc.
42
+ security.configs.recommended,
43
+ { plugins: { "no-secrets": noSecrets }, rules: { "no-secrets/no-secrets": ["warn", { tolerance: 4.5 }] } },
44
+ {
45
+ languageOptions: {
46
+ parserOptions: {
47
+ projectService: true, // current type-info mechanism
48
+ tsconfigRootDir: import.meta.dirname,
49
+ },
50
+ },
51
+ },
52
+ { rules: { "security/detect-object-injection": "off" } }, // famously noisy
53
+ prettier, // MUST be last
54
+ ]);
55
+ ```
56
+
57
+ ## Gotchas
58
+
59
+ - **`recommended` vs `recommendedTypeChecked`.** The type-checked preset is what enables the
60
+ genuinely valuable rules (`no-floating-promises`, `no-misused-promises`, `no-unsafe-*`) but
61
+ needs type info and is **much slower** — scope it to `**/*.ts`/`**/*.tsx` and disable on JS
62
+ config files with `tseslint.configs.disableTypeChecked`.
63
+ - **`projectService: true`** replaces the old `project: "./tsconfig.json"`. It auto-finds the
64
+ nearest `tsconfig.json` per file and lints out-of-project files (like `eslint.config.mjs`)
65
+ without a `tsconfig.eslint.json`. Always pair it with `tsconfigRootDir: import.meta.dirname`.
66
+ - **`tseslint.config()` is deprecated** in favour of core `defineConfig` from `eslint/config`
67
+ (a near-exact clone). The `tseslint.configs.*` presets are unchanged.
68
+ - **Prettier last.** `eslint-config-prettier/flat` must come after every rule-defining config
69
+ so it can switch off conflicting stylistic rules.
70
+
71
+ ## CBP preset divergence
72
+
73
+ CBP's `base` DB preset currently pins `eslint: ^9.0.0` / `typescript-eslint: ^8.0.0` and
74
+ keeps several `@typescript-eslint/no-unsafe-*` rules at `warn`. The setup above reflects the
75
+ **latest** (`eslint@10`); both are flat-config and interoperate. Bumping the preset to v10 is
76
+ out of scope for the skill (no DB/preset changes) — adopt v10 per-repo when you regenerate.
77
+
78
+ ## Official docs
79
+
80
+ - Configuration files: https://eslint.org/docs/latest/use/configure/configuration-files
81
+ - Typed linting: https://typescript-eslint.io/getting-started/typed-linting/
82
+ - `projectService`: https://typescript-eslint.io/blog/project-service/
@@ -0,0 +1,56 @@
1
+ # cli — Node CLI tool overrides
2
+
3
+ For Node CLI packages with a `bin` (the CBP `codebyplan` package). Layers a small **override
4
+ block** on top of [base](base.md) + [node](node.md). Maps to the CBP **`cli`** DB preset
5
+ (`tech_match.requires_capabilities: ["cli-bin"]`).
6
+
7
+ > **Verified 2026-05-31.** There is no "CLI" ESLint plugin — the convention is a scoped
8
+ > rule-override block.
9
+
10
+ ## What it does
11
+
12
+ A CLI legitimately (a) talks to the user via `console`, and (b) operates on user-supplied
13
+ filesystem paths and dynamic keys — so the `eslint-plugin-security` heuristics that flag those
14
+ produce noise, not findings. Relax them, **scoped narrowly** to the CLI surface.
15
+
16
+ ## Flat config (override block)
17
+
18
+ ```js
19
+ // eslint.config.mjs — appended after base + node + security configs
20
+ export default [
21
+ // ...base, node, security.configs.recommended, etc.
22
+ {
23
+ files: ["bin/**/*.{js,ts,mjs}", "src/cli/**/*.{js,ts}"],
24
+ rules: {
25
+ "no-console": "off", // console output IS the CLI's UI
26
+
27
+ // CLIs operate on user paths and dynamic keys by design:
28
+ "security/detect-non-literal-fs-filename": "off",
29
+ "security/detect-object-injection": "off",
30
+
31
+ // optional, if eslint-plugin-n is in use (CLIs call process.exit):
32
+ // "n/no-process-exit": "off",
33
+ },
34
+ },
35
+ ];
36
+ ```
37
+
38
+ ## Gotchas
39
+
40
+ - **Scope via `files`** — do NOT disable these repo-wide; the same rules are valuable in
41
+ server/library code.
42
+ - The two `security/*` lines require `eslint-plugin-security` to be installed and registered
43
+ (otherwise ESLint errors "rule not found"). If the project has no security plugin, only the
44
+ `no-console: "off"` line applies.
45
+
46
+ ## CBP preset divergence
47
+
48
+ The CBP `cli` preset matches the rule set above exactly (`no-console`,
49
+ `security/detect-non-literal-fs-filename`, `security/detect-object-injection` all off) and is
50
+ capability-gated on `cli-bin`. The repo's own `packages/codebyplan-package/eslint.config.mjs`
51
+ already applies this. No divergence — this doc just documents the convention.
52
+
53
+ ## Official docs
54
+
55
+ - Convention (no upstream doc); rules: https://eslint.org/docs/latest/rules/no-console and
56
+ https://github.com/eslint-community/eslint-plugin-security
@@ -0,0 +1,68 @@
1
+ # e2e — Playwright / WebdriverIO / Mocha test rules
2
+
3
+ For end-to-end specs. Three runners appear across CBP repos: **Playwright** (web), **WebdriverIO**
4
+ (Tauri desktop), and **Mocha** (the framework WDIO drives). Each is a **directory-scoped**
5
+ override. Playwright maps to the CBP **`testing-e2e`** preset
6
+ (`tech_match.requires: ["Playwright"]`); WebdriverIO + Mocha are **gap stacks — no preset**.
7
+
8
+ > **Verified 2026-05-31.** Version traps: Playwright is **2.10.4** (not the 0.15.x search
9
+ > sometimes returns); Mocha 11.x uses **`configs.recommended`** — NOT `configs.flat.recommended`.
10
+
11
+ ## Packages
12
+
13
+ | Package | Latest | Flat key |
14
+ | ------- | ------ | -------- |
15
+ | `eslint-plugin-playwright` | `2.10.4` | `configs['flat/recommended']` |
16
+ | `eslint-plugin-wdio` | `9.27.2` | `configs['flat/recommended']` |
17
+ | `eslint-plugin-mocha` | `11.3.0` | `configs.recommended` (NOT `.flat`) |
18
+
19
+ ```bash
20
+ pnpm add -D eslint-plugin-playwright # web
21
+ pnpm add -D eslint-plugin-wdio eslint-plugin-mocha # Tauri / WebdriverIO desktop
22
+ ```
23
+
24
+ ## Flat config
25
+
26
+ ```js
27
+ // eslint.config.mjs
28
+ import playwright from "eslint-plugin-playwright";
29
+ // desktop: import { configs as wdioConfigs } from "eslint-plugin-wdio";
30
+ // desktop: import mocha from "eslint-plugin-mocha";
31
+
32
+ export default [
33
+ // Playwright — scope to the web e2e dir
34
+ {
35
+ ...playwright.configs["flat/recommended"],
36
+ files: ["e2e/**", "**/*.e2e.{ts,js}"],
37
+ rules: { ...playwright.configs["flat/recommended"].rules, "no-console": "off" },
38
+ },
39
+
40
+ // WebdriverIO + Mocha (Tauri desktop) — scope to the wdio spec dir
41
+ // { ...wdioConfigs["flat/recommended"], files: ["test/**", "e2e/**"] },
42
+ // { ...mocha.configs.recommended, files: ["test/**/*.{ts,js}"] },
43
+ ];
44
+ ```
45
+
46
+ ## Gotchas
47
+
48
+ - **Scope every e2e override via `files`** — Playwright/WDIO/Mocha rules false-positive on
49
+ unit tests, and Testing-Library rules false-positive on e2e specs.
50
+ - **Mocha 11.x = `mocha.configs.recommended`** — `mocha.configs.flat.recommended` is
51
+ `undefined` in 11.x (it only exists on the unreleased 12.x main branch) and crashes config
52
+ load. Don't copy a `.flat.recommended` example.
53
+ - **WebdriverIO**: `eslint-plugin-wdio@9` requires ESLint 9+; when `typescript-eslint` is
54
+ present its recommended config auto-swaps `wdio/await-expect` → `wdio/no-floating-promise`.
55
+ - The CBP web app keeps Playwright specs in `e2e/**` with a Vitest sibling override for
56
+ `e2e/**/__tests__/**` — mirror that split if you co-locate unit tests under `e2e/`.
57
+
58
+ ## CBP preset divergence
59
+
60
+ CBP's `testing-e2e` preset covers **Playwright only** (`eslint-plugin-playwright: ^2.0.0`,
61
+ `no-console: off`). There is **no** preset for WebdriverIO or Mocha — the Tauri desktop e2e
62
+ config is manual. The skill does not add presets for the gap runners.
63
+
64
+ ## Official docs
65
+
66
+ - Playwright: https://github.com/mskelton/eslint-plugin-playwright
67
+ - WebdriverIO: https://github.com/webdriverio/webdriverio/tree/main/packages/eslint-plugin-wdio
68
+ - Mocha: https://github.com/lo1tuma/eslint-plugin-mocha
@@ -0,0 +1,59 @@
1
+ # jest — Jest test-file rules
2
+
3
+ For apps that test with Jest (CBP `apps/backend` NestJS specs, `livebyplan` Expo). **Gap
4
+ stack — no CBP DB preset** (the `testing` preset is Vitest-only). Layers a test-scoped
5
+ override on top of [base](base.md).
6
+
7
+ > **Verified 2026-05-31.** `eslint-plugin-jest` uses the **bracketed** flat-config keys
8
+ > `configs['flat/recommended']` / `['flat/style']` (the un-prefixed keys are legacy eslintrc).
9
+
10
+ ## Packages
11
+
12
+ | Package | Latest | Purpose |
13
+ | ------- | ------ | ------- |
14
+ | `eslint-plugin-jest` | `29.15.2` | Jest rules |
15
+
16
+ ```bash
17
+ pnpm add -D eslint-plugin-jest
18
+ ```
19
+
20
+ Peers: `eslint ^8.57 || ^9 || ^10`, `@typescript-eslint/eslint-plugin ^8`, `jest`.
21
+
22
+ ## Flat config
23
+
24
+ ```js
25
+ // eslint.config.mjs
26
+ import jest from "eslint-plugin-jest";
27
+
28
+ export default [
29
+ {
30
+ files: ["**/*.{test,spec}.{ts,tsx,js,jsx}", "**/__tests__/**/*.{ts,tsx,js,jsx}"],
31
+ ...jest.configs["flat/recommended"],
32
+ rules: {
33
+ ...jest.configs["flat/recommended"].rules,
34
+ ...jest.configs["flat/style"].rules, // optional stylistic rules
35
+ // type-aware: hand the unbound-method check to the jest-aware version
36
+ "@typescript-eslint/unbound-method": "off",
37
+ "jest/unbound-method": "error",
38
+ },
39
+ },
40
+ ];
41
+ ```
42
+
43
+ ## Gotchas
44
+
45
+ - Keys are **`configs['flat/recommended']`** / **`['flat/style']`** (bracketed) — the
46
+ unprefixed `configs.recommended` is the legacy eslintrc preset.
47
+ - **`jest/unbound-method`** extends `@typescript-eslint/unbound-method`; turn the base rule
48
+ off on test files and enable the jest version (needs `@typescript-eslint/parser` + type
49
+ info). Type-aware jest rules safely no-op when type info is absent.
50
+ - Avoid pinning `flat/all` long-term — it enables every rule and can break on minor releases.
51
+
52
+ ## CBP preset divergence
53
+
54
+ There is **no** CBP `testing-jest` preset. NestJS/Expo Jest specs are currently linted only by
55
+ the base rules. Add the override above per-repo; the skill does not add a preset.
56
+
57
+ ## Official docs
58
+
59
+ - eslint-plugin-jest: https://github.com/jest-community/eslint-plugin-jest
@@ -0,0 +1,69 @@
1
+ # nestjs — NestJS back-end flat config
2
+
3
+ For NestJS apps (the CBP `apps/backend`). **Gap stack — no CBP DB preset.** Use this doc to
4
+ hand-author `eslint.config.mjs`; the `base` + `node` presets cover most of it, but the
5
+ official Nest starter has a specific shape worth matching.
6
+
7
+ > **Verified 2026-05-31.** There is **no first-party NestJS ESLint plugin** — the official
8
+ > `nest new` starter uses plain type-checked `typescript-eslint` + Prettier.
9
+
10
+ ## Packages
11
+
12
+ | Package | Latest | Purpose |
13
+ | ------- | ------ | ------- |
14
+ | `typescript-eslint` | `8.60.0` | parser + type-checked preset |
15
+ | `@eslint/js` | `10.0.1` | `eslint.configs.recommended` |
16
+ | `eslint-plugin-prettier` | `^5` | `/recommended` subpath |
17
+ | `globals` | `17.6.0` | `globals.node`, `globals.jest` |
18
+
19
+ ```bash
20
+ pnpm add -D typescript-eslint @eslint/js eslint-plugin-prettier eslint-config-prettier globals
21
+ ```
22
+
23
+ ## Flat config (official `nest new` starter, verbatim)
24
+
25
+ ```js
26
+ // @ts-check
27
+ import eslint from "@eslint/js";
28
+ import eslintPluginPrettierRecommended from "eslint-plugin-prettier/recommended";
29
+ import globals from "globals";
30
+ import tseslint from "typescript-eslint";
31
+
32
+ export default tseslint.config(
33
+ { ignores: ["eslint.config.mjs"] },
34
+ eslint.configs.recommended,
35
+ ...tseslint.configs.recommendedTypeChecked,
36
+ eslintPluginPrettierRecommended,
37
+ {
38
+ languageOptions: {
39
+ globals: { ...globals.node, ...globals.jest },
40
+ sourceType: "commonjs", // "module" for an ESM Nest app
41
+ parserOptions: { projectService: true, tsconfigRootDir: import.meta.dirname },
42
+ },
43
+ },
44
+ {
45
+ rules: {
46
+ "@typescript-eslint/no-explicit-any": "off",
47
+ "@typescript-eslint/no-floating-promises": "warn",
48
+ "@typescript-eslint/no-unsafe-argument": "warn",
49
+ "prettier/prettier": ["error", { endOfLine: "auto" }],
50
+ },
51
+ },
52
+ );
53
+ ```
54
+
55
+ ## Gotchas
56
+
57
+ - Nest relaxes three type-checked rules (`no-explicit-any` off; `no-floating-promises` and
58
+ `no-unsafe-argument` to `warn`) because its DI/decorator patterns trip them. Keep these.
59
+ - `{ ignores: ["eslint.config.mjs"] }` keeps type-aware linting off the config file itself.
60
+ - `sourceType: "commonjs"` matches Nest's default CJS build — flip to `"module"` for ESM.
61
+ - The starter still uses `tseslint.config(...)`; you may swap it for `defineConfig` from
62
+ `eslint/config` (deprecation note in [base.md](base.md)) — the presets are identical.
63
+ - Optional community add-on: `@darraghor/eslint-plugin-nestjs-typed` adds
64
+ decorator/Swagger/DTO-aware rules. Not part of the official starter.
65
+ - Nest tests use **Jest** — add the [jest.md](jest.md) override scoped to `**/*.spec.ts`.
66
+
67
+ ## Official docs
68
+
69
+ - Starter config: https://github.com/nestjs/typescript-starter/blob/master/eslint.config.mjs
@@ -0,0 +1,63 @@
1
+ # nextjs — Next.js (App Router) flat config
2
+
3
+ For Next.js apps. Layers on top of [base](base.md). Maps to the CBP **`nextjs`** DB preset
4
+ (`tech_match.requires: ["Next.js"]`, `requires_capabilities: ["jsx"]`).
5
+
6
+ > **Verified 2026-05-31.** As of **Next.js 16**, `eslint-config-next` ships **native flat
7
+ > config**, `next lint` is **removed** (run `eslint .` directly), and the `eslint` key in
8
+ > `next.config.js` is gone. No `FlatCompat` shim is needed.
9
+
10
+ ## Packages
11
+
12
+ | Package | Latest | Purpose |
13
+ | ------- | ------ | ------- |
14
+ | `eslint-config-next` | `16.2.6` | bundles `@next/eslint-plugin-next` + react/react-hooks/import |
15
+
16
+ ```bash
17
+ pnpm add -D eslint-config-next
18
+ ```
19
+
20
+ ## Flat config
21
+
22
+ `eslint-config-next` exposes spreadable **array** subpath exports:
23
+
24
+ ```js
25
+ // eslint.config.mjs
26
+ import { defineConfig, globalIgnores } from "eslint/config";
27
+ import nextVitals from "eslint-config-next/core-web-vitals";
28
+ import nextTs from "eslint-config-next/typescript";
29
+
30
+ export default defineConfig([
31
+ ...nextVitals, // base + Core-Web-Vitals rules promoted warn→error
32
+ ...nextTs, // typescript-eslint rules (based on @typescript-eslint/recommended)
33
+ globalIgnores([".next/**", "out/**", "build/**", "next-env.d.ts"]),
34
+ ]);
35
+ ```
36
+
37
+ Subpath exports:
38
+ - `eslint-config-next` — base (Next + react + react-hooks recommended).
39
+ - `eslint-config-next/core-web-vitals` — base + CWV rules at error (**recommended default**).
40
+ - `eslint-config-next/typescript` — adds typescript-eslint rules; spread alongside a base.
41
+
42
+ ## Gotchas
43
+
44
+ - **`globalIgnores([...])` is required** when you spread the config — re-assert the default
45
+ ignores (`.next/`, etc.) per the official docs example.
46
+ - **Monorepo**: point the plugin at the app with `settings: { next: { rootDir: "apps/web" } }`
47
+ (path, glob, or array).
48
+ - **Prettier**: add `import prettier from "eslint-config-prettier/flat"` last.
49
+ - `next lint` removal landed in Next 16.0.0 — old `.eslintrc.json` configs should migrate to
50
+ `eslint.config.mjs` (a codemod exists).
51
+
52
+ ## CBP preset divergence
53
+
54
+ CBP's `nextjs` preset pins `eslint-config-next: ^15.0.0` and registers
55
+ `eslint-plugin-react-compiler` explicitly (see [react.md](react.md) — that plugin is now
56
+ **superseded**). The repo's own `apps/web/eslint.config.mjs` already uses the
57
+ `createRequire` + `eslint-config-next/core-web-vitals` + `eslint-config-next/typescript`
58
+ pattern. Adopt the native spread form above when regenerating; presets are not changed by
59
+ this skill.
60
+
61
+ ## Official docs
62
+
63
+ - ESLint config: https://nextjs.org/docs/app/api-reference/config/eslint
@@ -0,0 +1,74 @@
1
+ # node — Node/TypeScript service (Hono, Express, plain Node) flat config
2
+
3
+ For Node back-end services and server-side packages (the CBP MCP server uses Hono; any
4
+ `node-server` capability). Layers on [base](base.md). Maps to the CBP **`node`** DB preset
5
+ (`tech_match.requires: ["Node.js"]`, `requires_capabilities: ["node-server"]`).
6
+
7
+ > **Verified 2026-05-31.** The valuable async-safety rules (`no-floating-promises`,
8
+ > `no-misused-promises`) are **typescript-eslint** rules that need type info — they come from
9
+ > `recommendedTypeChecked`, not from a node plugin.
10
+
11
+ ## Packages
12
+
13
+ | Package | Latest | Purpose |
14
+ | ------- | ------ | ------- |
15
+ | `globals` | `17.6.0` | `globals.node` |
16
+ | `typescript-eslint` | `8.60.0` | type-aware promise rules |
17
+ | `eslint-plugin-n` | `18.0.1` | **optional** — unsupported-Node-API / import / engines checks |
18
+
19
+ ```bash
20
+ pnpm add -D globals typescript-eslint
21
+ # optional (libraries / dual ESM-CJS packages):
22
+ pnpm add -D eslint-plugin-n
23
+ ```
24
+
25
+ ## Flat config
26
+
27
+ ```js
28
+ // eslint.config.mjs
29
+ import { defineConfig } from "eslint/config";
30
+ import js from "@eslint/js";
31
+ import tseslint from "typescript-eslint";
32
+ import globals from "globals";
33
+ // optional: import n from "eslint-plugin-n";
34
+
35
+ export default defineConfig([
36
+ js.configs.recommended,
37
+ ...tseslint.configs.recommendedTypeChecked, // enables the promise rules below
38
+ {
39
+ files: ["**/*.{ts,mts,cts}"],
40
+ languageOptions: {
41
+ globals: globals.node,
42
+ sourceType: "module", // "commonjs" for a CJS service
43
+ parserOptions: { projectService: true, tsconfigRootDir: import.meta.dirname },
44
+ },
45
+ rules: {
46
+ "@typescript-eslint/no-floating-promises": "error",
47
+ "@typescript-eslint/no-misused-promises": "error",
48
+ },
49
+ },
50
+ // optional eslint-plugin-n:
51
+ // { files: ["**/*.{ts,mts,cts}"], plugins: { n }, extends: ["n/recommended-module"] },
52
+ ]);
53
+ ```
54
+
55
+ ## Gotchas
56
+
57
+ - **`eslint-plugin-n` is optional.** For a pure internal TS service you can skip it — its main
58
+ value is catching unsupported Node APIs, missing imports, and `package.json#engines` issues
59
+ in **libraries** and dual ESM/CJS packages. Pick the right preset: `n/recommended-module`
60
+ (ESM), `n/recommended-script` (CJS), `n/recommended` (mixed).
61
+ - The promise rules **require** a type-checked config + `projectService` — they silently do
62
+ nothing without type info.
63
+ - A CJS service uses `sourceType: "commonjs"`; an ESM service uses `"module"`.
64
+
65
+ ## CBP preset divergence
66
+
67
+ CBP's `node` preset ships only the two `@typescript-eslint` promise rules at `error` (no
68
+ `eslint-plugin-n`). The repo's MCP server / CLI configs follow this minimal shape. Add
69
+ `eslint-plugin-n` per-repo if you publish a library; the skill does not modify the preset.
70
+
71
+ ## Official docs
72
+
73
+ - eslint-plugin-n: https://github.com/eslint-community/eslint-plugin-n
74
+ - no-floating-promises: https://typescript-eslint.io/rules/no-floating-promises/