codebyplan 1.13.3 → 1.13.4

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 CHANGED
@@ -14,7 +14,7 @@ var VERSION, PACKAGE_NAME;
14
14
  var init_version = __esm({
15
15
  "src/lib/version.ts"() {
16
16
  "use strict";
17
- VERSION = "1.13.3";
17
+ VERSION = "1.13.4";
18
18
  PACKAGE_NAME = "codebyplan";
19
19
  }
20
20
  });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "codebyplan",
3
- "version": "1.13.3",
3
+ "version": "1.13.4",
4
4
  "description": "CLI for CodeByPlan — AI-powered development planning and tracking",
5
5
  "type": "module",
6
6
  "bin": {
@@ -2,7 +2,7 @@
2
2
 
3
3
  The `codebyplan` npm package ships a small, portable set of Claude Code hooks. They run in your project, use only generic primitives (`git rev-parse`, `${CLAUDE_PROJECT_DIR}`, `${CLAUDE_PLUGIN_ROOT}`), and degrade gracefully (exit 0) when their preconditions aren't met.
4
4
 
5
- Hook registration lives in [`hooks/hooks.json`](./hooks.json) — PreToolUse, PostToolUse, and Notification events are wired. (`SessionStart`, `SessionEnd`, `Stop`, and `SubagentStop` are also schema-permitted but unused here.)
5
+ Hook registration lives in [`hooks/hooks.json`](./hooks.json) — PreToolUse and PostToolUse events are wired. (`Notification`, `SessionStart`, `SessionEnd`, `Stop`, and `SubagentStop` are also schema-permitted but unused here.)
6
6
 
7
7
  **`cbp-statusline.sh` is auto-wired via `settings.project.base.json`.** The `statusLine` block is shipped inside `templates/settings.project.base.json` and merged into the consumer's `.claude/settings.json` automatically by `codebyplan claude install` (and on every `codebyplan claude update`). No manual copy-paste is required.
8
8
 
@@ -176,22 +176,6 @@ Walks up from the edited file to the nearest `package.json` and uses that packag
176
176
 
177
177
  ---
178
178
 
179
- ### `notify.sh` — Notification, matcher `*`
180
-
181
- Sends a desktop notification when Claude Code emits a notification event (waiting for input, task complete, etc.). Title is `[<project-name>] Claude Code`; body is the notification message; clicking the notification focuses VS Code at the project directory (macOS only).
182
-
183
- **Cross-platform graceful skip**: exits 0 silently when `terminal-notifier` is not on `$PATH`. Linux, Windows, and macOS hosts without Homebrew see a no-op — no errors, no warnings.
184
-
185
- **VS Code click action**: only attached when running on macOS (`$OSTYPE` matches `darwin*`) AND the `code` CLI is on `$PATH`. On other hosts the notification still fires but is non-clickable.
186
-
187
- **Install hint** (macOS): `brew install terminal-notifier`. On other platforms the hook is a no-op — substitute your own notification mechanism via a settings.json override if desired.
188
-
189
- **Blocks vs warns**: never blocks — exit 0 always. Notification hooks must never block Claude.
190
-
191
- **Opt out**: settings.json override or plugin disable.
192
-
193
- ---
194
-
195
179
  ### `auto-test-hooks.sh` — PostToolUse, matcher `Edit|Write`
196
180
 
197
181
  Triggers `test-hooks.sh` automatically when any `*/hooks/*.sh` file is edited. Catches accidental breakage of the plugin's own hooks (or your project's `.claude/hooks/` if you author your own) at edit time, before the broken hook runs against future tool calls.
@@ -244,9 +228,9 @@ After a `complete_round` MCP call succeeds, reconciles the round's `files_change
244
228
 
245
229
  ### `test-hooks.sh` — invoked by `auto-test-hooks.sh`
246
230
 
247
- Test suite for the plugin's 10 registered hooks. Runs two passes:
231
+ Test suite for the plugin's 9 registered hooks. Runs two passes:
248
232
 
249
- 1. **Header check** — every registered hook (`lint-format-on-edit`, `test-coverage-gate`, `pre-commit-quality-gate`, `maestro-yaml-validate`, `notify`, `auto-test-hooks`, `mcp-migration-guard`, `validate-git-stash-deny`, `cbp-mcp-round-sync`) carries the required `# Hook:` and `# Purpose:` header comments. `statusline` uses its own `# Claude Code Status Line` marker.
233
+ 1. **Header check** — every registered hook (`lint-format-on-edit`, `test-coverage-gate`, `pre-commit-quality-gate`, `maestro-yaml-validate`, `auto-test-hooks`, `mcp-migration-guard`, `validate-git-stash-deny`, `cbp-mcp-round-sync`) carries the required `# Hook:` and `# Purpose:` header comments. `statusline` uses its own `# Claude Code Status Line` marker.
250
234
  2. **Functional smoke tests** — each hook is invoked with synthetic stdin matching its fast-path / graceful-degrade input; all must exit 0.
251
235
 
252
236
  Not in `hooks.json` — invoked indirectly via `auto-test-hooks.sh` on hook edits, or directly via `bash ${CLAUDE_PLUGIN_ROOT}/hooks/test-hooks.sh`.
@@ -62,7 +62,7 @@ for hook_file in "$HOOKS_DIR"/*.sh; do
62
62
 
63
63
  # Check for header comments (required for documentation generation).
64
64
  # Accept either marker convention used across the plugin's hooks:
65
- # - "# Hook:" + "# Purpose:" (used by notify, auto-test-hooks, etc.)
65
+ # - "# Hook:" + "# Purpose:" (used by auto-test-hooks, etc.)
66
66
  # - "# @event:" + a description line (used by maestro-yaml-validate, etc.)
67
67
  if (grep -q '^# Hook:' "$hook_file" && grep -q '^# Purpose:' "$hook_file") \
68
68
  || grep -q '^# @event:' "$hook_file"; then
@@ -77,14 +77,6 @@ echo ""
77
77
  # ===== FUNCTIONAL SMOKE TESTS =====
78
78
  echo "## Functional Smoke Tests"
79
79
 
80
- # cbp-notify.sh — graceful-degrade: exit 0 whether or not terminal-notifier is installed
81
- ACTUAL_EXIT=$(echo '{"message":"test","cwd":"/tmp"}' | bash "$HOOKS_DIR/cbp-notify.sh" >/dev/null 2>&1; echo $?)
82
- if [ "$ACTUAL_EXIT" = "0" ]; then
83
- test_result "cbp-notify.sh graceful-degrade exits 0" "passed" "passed"
84
- else
85
- test_result "cbp-notify.sh graceful-degrade exits 0" "passed" "failed"
86
- fi
87
-
88
80
  # cbp-lint-format-on-edit.sh — graceful-degrade: CLAUDE_PROJECT_DIR unset → exit 0
89
81
  if [ ! -f "$HOOKS_DIR/cbp-lint-format-on-edit.sh" ]; then
90
82
  test_result "cbp-lint-format-on-edit.sh present" "passed" "missing"
@@ -60,17 +60,6 @@
60
60
  }
61
61
  ]
62
62
  }
63
- ],
64
- "Notification": [
65
- {
66
- "matcher": "*",
67
- "hooks": [
68
- {
69
- "type": "command",
70
- "command": "bash ${CLAUDE_PLUGIN_ROOT}/hooks/cbp-notify.sh"
71
- }
72
- ]
73
- }
74
63
  ]
75
64
  }
76
65
  }
@@ -181,13 +181,14 @@ command + which apps still need their `eslint.config.mjs` generated.
181
181
  `reference/*.md`, never silently skip
182
182
  - `codebyplan eslint init` failure is non-fatal — print the manual command and still write eslint.json
183
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)
184
+ - Reference docs contain **only the official upstream ESLint setup** per stack (verbatim from each
185
+ tool's own docs) they are not CBP preset opinions. `codebyplan eslint init` generates from the DB
186
+ presets, which may differ; the reference docs are the canonical official guidance
186
187
 
187
188
  ## Additional resources
188
189
 
189
190
  - 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
+ - Next.js: [reference/nextjs.md](reference/nextjs.md) · React: [reference/react.md](reference/react.md)
191
192
  - Node / Hono / Express: [reference/node.md](reference/node.md) · NestJS: [reference/nestjs.md](reference/nestjs.md)
192
193
  - CLI tools: [reference/cli.md](reference/cli.md) · Tailwind CSS: [reference/tailwind.md](reference/tailwind.md)
193
194
  - React Native / Expo: [reference/react-native.md](reference/react-native.md)
@@ -1,82 +1,71 @@
1
- # base — TypeScript foundation (ESLint v10 flat config)
1
+ # base — TypeScript (official typescript-eslint setup)
2
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"]`).
3
+ > **Official source**: https://typescript-eslint.io/getting-started/ (+ typed-linting). Verified
4
+ > 2026-05-31. ESLint flat config (`eslint.config.mjs`). This is the typescript-eslint quickstart
5
+ > verbatim — no additions.
6
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.
7
+ The foundation for any TypeScript project.
10
8
 
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 |
9
+ ## Install
22
10
 
23
11
  ```bash
24
- pnpm add -D eslint @eslint/js typescript-eslint eslint-config-prettier \
25
- eslint-plugin-security eslint-plugin-no-secrets globals
12
+ npm install --save-dev eslint @eslint/js typescript typescript-eslint
26
13
  ```
27
14
 
28
- ## Flat config
15
+ ## eslint.config.mjs — quickstart (no type info)
29
16
 
30
17
  ```js
31
- // eslint.config.mjs
18
+ // @ts-check
19
+ import js from "@eslint/js";
32
20
  import { defineConfig } from "eslint/config";
21
+ import tseslint from "typescript-eslint";
22
+
23
+ export default defineConfig(
24
+ js.configs.recommended,
25
+ tseslint.configs.recommended,
26
+ );
27
+ ```
28
+
29
+ ## eslint.config.mjs — typed linting (recommended by typescript-eslint)
30
+
31
+ ```js
33
32
  import js from "@eslint/js";
33
+ import { defineConfig } from "eslint/config";
34
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
35
 
39
- export default defineConfig([
36
+ export default defineConfig(
40
37
  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 }] } },
38
+ tseslint.configs.recommended,
39
+ tseslint.configs.recommendedTypeChecked,
44
40
  {
45
41
  languageOptions: {
46
42
  parserOptions: {
47
- projectService: true, // current type-info mechanism
48
- tsconfigRootDir: import.meta.dirname,
43
+ projectService: true,
49
44
  },
50
45
  },
51
46
  },
52
- { rules: { "security/detect-object-injection": "off" } }, // famously noisy
53
- prettier, // MUST be last
54
- ]);
47
+ );
55
48
  ```
56
49
 
57
- ## Gotchas
50
+ ## Run
58
51
 
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.
52
+ ```bash
53
+ npx eslint .
54
+ ```
70
55
 
71
- ## CBP preset divergence
56
+ ## Notes (from the official docs)
72
57
 
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.
58
+ - The base recommended config is `js.configs.recommended` (from `@eslint/js`, imported as `js`)
59
+ **not** `eslint.configs.recommended`. `defineConfig` is imported from `eslint/config`.
60
+ - `tseslint.configs.recommendedTypeChecked` adds rules that **require type information**; enable it
61
+ with `parserOptions.projectService: true`.
62
+ - typescript-eslint *"strongly recommend[s] you do use type-aware linting,"* while noting it incurs a
63
+ performance penalty (TypeScript builds the project before ESLint lints).
64
+ - `// @ts-check` type-checks the config file itself (optional). Use `eslint.config.js` if
65
+ `package.json` has `"type": "module"`.
66
+ - Stricter presets are available: `strict` / `strictTypeChecked`, `stylistic` / `stylisticTypeChecked`.
77
67
 
78
- ## Official docs
68
+ ## Source
79
69
 
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/
70
+ - https://typescript-eslint.io/getting-started/
71
+ - https://typescript-eslint.io/getting-started/typed-linting/
@@ -1,56 +1,63 @@
1
- # cli — Node CLI tool overrides
1
+ # cli — Node CLI tool (convention — no official preset)
2
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"]`).
3
+ > **There is no official "CLI" ESLint config or preset.** Neither ESLint nor Node publishes one. A
4
+ > "CLI config" is a convention: a scoped `files` override inside your normal flat config that relaxes
5
+ > a few rules a CLI legitimately trips. Only the individual official rule/plugin docs below are
6
+ > authoritative (verified 2026-05-31).
6
7
 
7
- > **Verified 2026-05-31.** There is no "CLI" ESLint plugin — the convention is a scoped
8
- > rule-override block.
8
+ ## What a CLI override does
9
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)
10
+ A CLI prints to stdout/stderr and operates on user-supplied paths, so two official rules are commonly
11
+ relaxed **scoped to the CLI source**:
17
12
 
18
13
  ```js
19
- // eslint.config.mjs — appended after base + node + security configs
14
+ // eslint.config.mjs — appended after your base config
20
15
  export default [
21
- // ...base, node, security.configs.recommended, etc.
16
+ // ...your base config (e.g. typescript-eslint, see base.md)...
22
17
  {
23
- files: ["bin/**/*.{js,ts,mjs}", "src/cli/**/*.{js,ts}"],
18
+ files: ["bin/**", "src/cli/**"],
24
19
  rules: {
25
- "no-console": "off", // console output IS the CLI's UI
26
-
27
- // CLIs operate on user paths and dynamic keys by design:
20
+ "no-console": "off",
21
+ // only if eslint-plugin-security is installed (see below):
28
22
  "security/detect-non-literal-fs-filename": "off",
29
23
  "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
24
  },
34
25
  },
35
26
  ];
36
27
  ```
37
28
 
38
- ## Gotchas
29
+ ## Official sources for the individual rules
30
+
31
+ ### `no-console` (core ESLint rule)
32
+ Disallows `console` calls (treated as debugging output). It is **off** in `eslint:recommended`, so you
33
+ only need to turn it `off` if your base config enabled it. The rule page shows the inline form, e.g.:
34
+
35
+ ```js
36
+ /* eslint no-console: ["error", { allow: ["warn", "error"] }] */
37
+ ```
38
+
39
+ Source: https://eslint.org/docs/latest/rules/no-console
39
40
 
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.
41
+ ### `eslint-plugin-security` (official community plugin)
42
+ The `security/*` rules above exist only if this plugin is installed and registered:
43
+
44
+ ```bash
45
+ npm install --save-dev eslint-plugin-security
46
+ ```
47
+
48
+ ```js
49
+ const pluginSecurity = require('eslint-plugin-security');
50
+ module.exports = [pluginSecurity.configs.recommended];
51
+ ```
45
52
 
46
- ## CBP preset divergence
53
+ Its README notes the plugin *"finds a lot of false positives which need triage by a human"* — which is
54
+ why CLIs relax `detect-non-literal-fs-filename` / `detect-object-injection` on user-path code.
47
55
 
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.
56
+ Source: https://github.com/eslint-community/eslint-plugin-security
52
57
 
53
- ## Official docs
58
+ ## Notes
54
59
 
55
- - Convention (no upstream doc); rules: https://eslint.org/docs/latest/rules/no-console and
56
- https://github.com/eslint-community/eslint-plugin-security
60
+ - Keep the relaxations **narrowly scoped via `files`** — do not disable these repo-wide.
61
+ - If your project does not use `eslint-plugin-security`, only the `no-console: "off"` line applies.
62
+ - The ESLint `no-console` page does **not** ship a full standalone `eslint.config.mjs` example — only
63
+ the inline-comment and `rules`-object forms shown above.
@@ -1,68 +1,78 @@
1
- # e2e — Playwright / WebdriverIO / Mocha test rules
1
+ # e2e — Playwright / WebdriverIO / Mocha (official setups)
2
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**.
3
+ > **Official sources** (verified 2026-05-31):
4
+ > - Playwright https://github.com/mskelton/eslint-plugin-playwright
5
+ > - WebdriverIO https://github.com/webdriverio/webdriverio/tree/main/packages/eslint-plugin-wdio
6
+ > - Mocha — https://github.com/lo1tuma/eslint-plugin-mocha
7
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`.
8
+ Each E2E runner has its own official plugin. Use the one(s) matching your test runner.
10
9
 
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`) |
10
+ ## Playwright
18
11
 
19
12
  ```bash
20
- pnpm add -D eslint-plugin-playwright # web
21
- pnpm add -D eslint-plugin-wdio eslint-plugin-mocha # Tauri / WebdriverIO desktop
13
+ npm install -D eslint-plugin-playwright
22
14
  ```
23
15
 
24
- ## Flat config
25
-
26
16
  ```js
27
- // eslint.config.mjs
17
+ import { defineConfig } from "@eslint/config";
28
18
  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
19
 
32
- export default [
33
- // Playwright — scope to the web e2e dir
20
+ export default defineConfig([
34
21
  {
35
- ...playwright.configs["flat/recommended"],
36
- files: ["e2e/**", "**/*.e2e.{ts,js}"],
37
- rules: { ...playwright.configs["flat/recommended"].rules, "no-console": "off" },
22
+ files: ["tests/**"],
23
+ extends: [playwright.configs["flat/recommended"]],
24
+ rules: {
25
+ // Customize Playwright rules
26
+ },
38
27
  },
28
+ ]);
29
+ ```
30
+
31
+ Key: **`playwright.configs["flat/recommended"]`**. The README notes you may need to change `files` to
32
+ match your Playwright test patterns.
33
+
34
+ ## WebdriverIO
35
+
36
+ ```bash
37
+ npm install eslint-plugin-wdio --save-dev
38
+ ```
39
+
40
+ ```js
41
+ // eslint.config.mjs
42
+ import { configs as wdioConfig } from "eslint-plugin-wdio";
39
43
 
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}"] },
44
+ export default [
45
+ wdioConfig["flat/recommended"],
43
46
  ];
44
47
  ```
45
48
 
46
- ## Gotchas
49
+ Key: **`configs["flat/recommended"]`**. Requires ESLint v9 + flat config.
50
+
51
+ ## Mocha
52
+
53
+ ```bash
54
+ npm install --save-dev eslint-plugin-mocha
55
+ ```
56
+
57
+ ```js
58
+ import mochaPlugin from "eslint-plugin-mocha";
59
+
60
+ export default [
61
+ mochaPlugin.configs.recommended, // or `mochaPlugin.configs.all`
62
+ ];
63
+ ```
47
64
 
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/`.
65
+ Key (latest published v11.x): **`mochaPlugin.configs.recommended`** — **NOT** `configs.flat.recommended`
66
+ and **NOT** `configs["flat/recommended"]`. Plain dot-notation, no `flat` segment. Scope to your spec
67
+ files via a `{ files: [...], ...mochaPlugin.configs.recommended }` wrapper if needed.
57
68
 
58
- ## CBP preset divergence
69
+ ## Notes (from the official docs)
59
70
 
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.
71
+ - Scope each runner's config to its test directory via `files` so the rules don't bleed onto other
72
+ files.
73
+ - **No `flat/` prefix** on the key: Mocha (`configs.recommended`). **Bracketed `flat/` key**:
74
+ Playwright, WebdriverIO. Mocha's README is flat-config only (no legacy `.eslintrc` shown).
63
75
 
64
- ## Official docs
76
+ ## Source
65
77
 
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
78
+ See the three URLs above.
@@ -1,59 +1,43 @@
1
- # jest — Jest test-file rules
1
+ # jest — Jest test files (official eslint-plugin-jest setup)
2
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).
3
+ > **Official source**: https://github.com/jest-community/eslint-plugin-jest (verified 2026-05-31). This
4
+ > is the plugin's official flat-config usage.
6
5
 
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 |
6
+ ## Install
15
7
 
16
8
  ```bash
17
- pnpm add -D eslint-plugin-jest
9
+ npm install --save-dev eslint eslint-plugin-jest
18
10
  ```
19
11
 
20
- Peers: `eslint ^8.57 || ^9 || ^10`, `@typescript-eslint/eslint-plugin ^8`, `jest`.
21
-
22
- ## Flat config
12
+ ## eslint.config.mjs recommended config
23
13
 
24
14
  ```js
25
- // eslint.config.mjs
26
15
  import jest from "eslint-plugin-jest";
27
16
 
28
17
  export default [
29
18
  {
30
- files: ["**/*.{test,spec}.{ts,tsx,js,jsx}", "**/__tests__/**/*.{ts,tsx,js,jsx}"],
19
+ // update this to match your test files
20
+ files: ["**/*.spec.js", "**/*.test.js"],
31
21
  ...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
22
  },
40
23
  ];
41
24
  ```
42
25
 
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.
26
+ The README's manual-rules example registers globals explicitly:
27
+ `languageOptions: { globals: jest.environments.globals.globals }`.
51
28
 
52
- ## CBP preset divergence
29
+ ## Notes (from the official docs)
53
30
 
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.
31
+ - Config keys: **`jest.configs["flat/recommended"]`** and **`jest.configs["flat/style"]`** (the
32
+ `flat/`-prefixed keys are the flat-config ones; unprefixed keys are legacy `.eslintrc`).
33
+ - Rules assume test files, so the README says it's *"generally not suitable to include them in your
34
+ top-level configuration"* — scope with `files`/`ignores`.
35
+ - **Type-aware `unbound-method`**: the README notes *"`unbound-method` depends on
36
+ `@typescript-eslint/eslint-plugin`, as it extends the original `unbound-method` rule."* To use it you
37
+ need `@typescript-eslint/parser` with type info, and you turn off the base rule in favour of
38
+ `jest/unbound-method`.
39
+ - The README shows both legacy `.eslintrc` and flat config.
56
40
 
57
- ## Official docs
41
+ ## Source
58
42
 
59
- - eslint-plugin-jest: https://github.com/jest-community/eslint-plugin-jest
43
+ - https://github.com/jest-community/eslint-plugin-jest