create-warlock 5.30.0 → 5.32.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (88) hide show
  1. package/CHANGELOG.md +43 -2
  2. package/README.md +89 -15
  3. package/esm/commands/create-new-app/index.mjs +20 -17
  4. package/esm/commands/create-new-app/index.mjs.map +1 -1
  5. package/esm/commands/create-new-app/types.d.mts +14 -8
  6. package/esm/commands/create-warlock-app/index.mjs +2 -1
  7. package/esm/commands/create-warlock-app/index.mjs.map +1 -1
  8. package/esm/features/agent-kit-targets.mjs +1 -1
  9. package/esm/features/agent-kit-targets.mjs.map +1 -1
  10. package/esm/features/database-drivers.mjs +1 -1
  11. package/esm/features/database-drivers.mjs.map +1 -1
  12. package/esm/features/features-map.mjs +12 -12
  13. package/esm/features/features-map.mjs.map +1 -1
  14. package/esm/flags/assert-package-manager.mjs +1 -1
  15. package/esm/flags/assert-package-manager.mjs.map +1 -1
  16. package/esm/flags/definitions.mjs +6 -1
  17. package/esm/flags/definitions.mjs.map +1 -1
  18. package/esm/flags/seed-from-flags.mjs +2 -1
  19. package/esm/flags/seed-from-flags.mjs.map +1 -1
  20. package/esm/helpers/app.mjs +63 -6
  21. package/esm/helpers/app.mjs.map +1 -1
  22. package/esm/helpers/exec.mjs +1 -1
  23. package/esm/helpers/exec.mjs.map +1 -1
  24. package/esm/helpers/insert-import.mjs +1 -1
  25. package/esm/helpers/insert-import.mjs.map +1 -1
  26. package/esm/helpers/package-manager.mjs.map +1 -1
  27. package/esm/helpers/paths.mjs.map +1 -1
  28. package/esm/helpers/pnpm-build-approvals.mjs.map +1 -1
  29. package/esm/helpers/project-builder-helpers.mjs.map +1 -1
  30. package/esm/helpers/warlock-versions.mjs +1 -1
  31. package/esm/helpers/warlock-versions.mjs.map +1 -1
  32. package/esm/index.d.mts +3 -5
  33. package/esm/index.mjs +6 -4
  34. package/esm/index.mjs.map +1 -1
  35. package/esm/prompts/ask-agent-targets.mjs.map +1 -1
  36. package/esm/prompts/ask-ai-features.mjs.map +1 -1
  37. package/esm/prompts/ask-features.mjs +53 -0
  38. package/esm/prompts/ask-features.mjs.map +1 -0
  39. package/esm/prompts/ask-lint-toolchain.mjs +21 -0
  40. package/esm/prompts/ask-lint-toolchain.mjs.map +1 -0
  41. package/esm/prompts/fit-to-terminal.mjs.map +1 -1
  42. package/esm/summary.mjs +12 -2
  43. package/esm/summary.mjs.map +1 -1
  44. package/esm/ui/banner.mjs +115 -47
  45. package/esm/ui/banner.mjs.map +1 -1
  46. package/esm/ui/report.mjs.map +1 -1
  47. package/esm/ui/spinners.mjs.map +1 -1
  48. package/esm/ui/wrap-text.mjs +55 -0
  49. package/esm/ui/wrap-text.mjs.map +1 -0
  50. package/llms-full.txt +110 -25
  51. package/package.json +3 -3
  52. package/skills/create-a-warlock-project/SKILL.md +110 -25
  53. package/templates/toolchains/oxc/.oxfmtrc.json +15 -0
  54. package/templates/toolchains/oxc/.oxlintrc.json +24 -0
  55. package/templates/toolchains/oxc/.vscode/extensions.json +3 -0
  56. package/templates/toolchains/oxc/.vscode/settings.json +35 -0
  57. package/templates/warlock/.prettierrc.json +3 -1
  58. package/templates/warlock/AGENTS.md +22 -2
  59. package/templates/warlock/README.md +18 -3
  60. package/templates/warlock/package.json +8 -6
  61. package/templates/warlock/skills/api-design/SKILL.md +2 -2
  62. package/templates/warlock/skills/code-standards/SKILL.md +18 -4
  63. package/templates/warlock/skills/security-baseline/SKILL.md +12 -1
  64. package/templates/warlock/skills/testing-strategy/SKILL.md +17 -0
  65. package/templates/warlock/src/app/auth/controllers/login.controller.ts +1 -1
  66. package/templates/warlock/src/app/auth/routes.ts +25 -5
  67. package/templates/warlock/src/app/auth/utils/types.ts +6 -1
  68. package/templates/warlock/src/app/contact/controllers/contact.controller.ts +1 -1
  69. package/templates/warlock/src/app/contact/routes.ts +1 -1
  70. package/templates/warlock/src/app/locale/controllers/locale.controller.ts +1 -1
  71. package/templates/warlock/src/app/locale/routes.ts +1 -1
  72. package/templates/warlock/src/app/posts/controllers/create-new-post.controller.ts +1 -1
  73. package/templates/warlock/src/app/posts/controllers/update-post.controller.ts +1 -1
  74. package/templates/warlock/src/app/posts/models/post/post.model.ts +1 -1
  75. package/templates/warlock/src/app/posts/schema/create-post.schema.ts +1 -1
  76. package/templates/warlock/src/app/posts/schema/update-post.schema.ts +1 -1
  77. package/templates/warlock/src/app/users/controllers/create-new-user.controller.ts +1 -1
  78. package/templates/warlock/src/app/users/controllers/list-users.controller.ts +10 -2
  79. package/templates/warlock/src/app/users/models/user/user.model.ts +1 -1
  80. package/templates/warlock/src/app/users/schema/create-user.schema.ts +1 -1
  81. package/templates/warlock/src/app/users/schema/list-users.schema.ts +15 -0
  82. package/templates/warlock/src/config/storage.ts +1 -1
  83. package/templates/warlock/src/config/tests.ts +8 -0
  84. package/templates/warlock/src/web/404.css +2 -6
  85. package/templates/warlock/src/web/assets.d.ts +2 -0
  86. package/templates/warlock/src/web/home/components/contact-form-controls.tsx +1 -1
  87. package/templates/warlock/src/web/home/components/hero-section.tsx +1 -0
  88. package/templates/warlock/tsconfig.json +1 -1
package/llms-full.txt CHANGED
@@ -40,7 +40,7 @@ The first positional argument is the project name; it also becomes the directory
40
40
 
41
41
  1. **Default (a TTY, no `--yes`, no `--interactive`)** — asks the project name (if not already given), API-only or full-stack web (`--stack`), then a database unless `--db` or `--no-db` already supplied it. The stack is the only choice that changes the generated app's shape.
42
42
  2. **`--yes` (or no TTY at all — CI, a script, an agent harness)** — fully headless. Every answer comes from a flag or its default; nothing is ever prompted, and stdin is never read.
43
- 3. **`--interactive` (alias `--customize`)** — the full long-form wizard: project name, package manager, database driver, features, AI providers, git, JWT — one prompt after another, exactly like earlier `create-warlock` releases.
43
+ 3. **`--interactive` (alias `--customize`)** — the full long-form wizard: project name, package manager, database driver, features, AI providers, lint/format toolchain, git, JWT — one prompt after another, exactly like earlier `create-warlock` releases.
44
44
 
45
45
  **Without a terminal, `--yes` is not required.** When stdin is not a TTY — CI, a
46
46
  script, a container, an agent harness — the scaffolder does not try to prompt,
@@ -54,7 +54,7 @@ that is just the project name, the one required answer with no default:
54
54
  ```
55
55
  A project name is required and no terminal is available to ask for one. Pass it as
56
56
  the first argument or --name=<name>. Non-interactive flags: --yes, --pm=<npm|yarn|pnpm>,
57
- --db=<driver>|--no-db, --features=<list>, --ai=<list>, --git|--no-git, --jwt|--no-jwt.
57
+ --db=<driver>|--no-db, --features=<list>, --ai=<list>, --lint=<oxc|eslint>, --git|--no-git, --jwt|--no-jwt.
58
58
  ```
59
59
 
60
60
  ## After scaffolding: the decisions summary
@@ -63,26 +63,30 @@ Because almost every choice defaults silently, `create-warlock` prints what it
63
63
  decided right after scaffolding, e.g.:
64
64
 
65
65
  ```
66
- Using npm · database: none · agent-kit targets: claude
66
+ Using npm · database: none · lint: oxc · agent-kit targets: claude
67
+ Features: none
67
68
  change these — package manager: --pm, database: --db/--no-db, agents: --agents,
68
- features: --features, ai: --ai, git: --git/--no-git, jwt: --jwt/--no-jwt — or
69
+ features: --features, ai: --ai, lint: --lint, git: --git/--no-git, jwt: --jwt/--no-jwt — or
69
70
  re-run with --interactive for the full wizard.
70
71
  ```
71
72
 
72
73
  ## Flags
73
74
 
74
- | Flag | Takes value | Default | Purpose |
75
- | --------------------------- | ----------- | -------------- | ------------------------------------------------------------------- |
76
- | `<positional>` / `--name` | yes | — (required) | Project name + target directory. |
77
- | `--stack` | yes | `api` | `api` or `web` — the structural choice; `web` seeds the `web` feature by default. |
78
- | `--db` | yes | `mongodb` | Database driver key (`mongodb`, `postgres`, or `none`). |
79
- | `--no-db` | no | — | Opt out of a database — shorthand for `--db=none`. |
80
- | `--pm` | yes | inferred (`npm_config_user_agent` / system) | Package manager — must be one of `npm` / `yarn` / `pnpm` / `bun`; anything else is rejected before scaffolding starts. |
81
- | `--features` | yes (CSV) | none, or `["web"]` when `--stack=web` and `--features` is not given | Comma-separated optional feature keys. An explicit `--features` always wins over the `--stack` default. |
82
- | `--ai` | yes (CSV) | none | Comma-separated AI provider keys (auto-pulls `@warlock.js/ai`). |
83
- | `--agents` | yes (CSV) | `claude` | Comma-separated `agent-kit` targets — see below. |
84
- | `--git` / `--no-git` | no | off | Initialize a Git repo (`git init` + `main` branch + initial commit).|
85
- | `--jwt` / `--no-jwt` | no | off | Generate JWT secrets via the project's `jwt` script. |
75
+ | Flag | Takes value | Default | Purpose |
76
+ | ------------------------------ | ----------- | ------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------- |
77
+ | `<positional>` / `--name` | yes | — (required) | Project name + target directory. |
78
+ | `--stack` | yes | `api` | `api` or `web` — the structural choice; `web` seeds the `web` feature by default. |
79
+ | `--db` | yes | `mongodb` | Database driver key (`mongodb`, `postgres`, or `none`). |
80
+ | `--no-db` | no | — | Opt out of a database — shorthand for `--db=none`. |
81
+ | `--pm` | yes | inferred (`npm_config_user_agent` / system) | Package manager — must be one of `npm` / `yarn` / `pnpm` / `bun`; anything else is rejected before scaffolding starts. |
82
+ | `--features` | yes (CSV) | none, or `["web"]` when `--stack=web` and `--features` is not given | Comma-separated optional feature keys. An explicit `--features` always wins over the `--stack` default. |
83
+ | `--lint` | yes | `oxc` | `oxc` (Oxlint/Oxfmt) or `eslint` (ESLint/Prettier); unknown or missing values fail before writes. |
84
+ | `--ai` | yes (CSV) | none | Comma-separated AI provider keys (auto-pulls `@warlock.js/ai`). |
85
+ | `--agents` | yes (CSV) | `claude` | Comma-separated `agent-kit` targets — see below. |
86
+ | `--git` / `--no-git` | no | off | Initialize a Git repo (`git init` + `main` branch + initial commit). |
87
+ | `--jwt` / `--no-jwt` | no | off | Generate JWT secrets via the project's `jwt` script. |
88
+ | `--yes` / `-y` | no | off | Fully headless mode. |
89
+ | `--interactive`, `--customize` | no | off | Restore the full long-form wizard. |
86
90
 
87
91
  With `--pm=pnpm`, the scaffold reads `pnpm --version` and records install-script
88
92
  approvals (esbuild, and Sharp when the `image` feature is selected) where that
@@ -93,10 +97,8 @@ no workspace file (those versions reject one without `packages:`) but
93
97
  retained. If selected feature dependencies do
94
98
  not install, JWT generation is skipped and reported rather than retried through
95
99
  the package manager.
96
- | `--yes` / `-y` | no | off | Fully headless mode. |
97
- | `--interactive`, `--customize` | no | off | Restore the full long-form wizard. |
98
100
 
99
- Value flags accept either `--db=postgres` or `--db postgres`. Unknown `--features` / `--ai` / `--agents` keys fail fast before any install.
101
+ Value flags accept either `--db=postgres` or `--db postgres`. Unknown `--pm` / `--db` / `--features` / `--ai` / `--agents` / `--lint` values fail fast before any write or install.
100
102
 
101
103
  `--help`/`-h` and `--version`/`-v` short-circuit before anything else — no prompt, filesystem write, or network call, and `--help` wins even over a positional project name. `--version` prints the installed `create-warlock` version. `--help` lists every flag above together with its default.
102
104
 
@@ -110,18 +112,18 @@ fallback that always works — even fully offline. Any other target
110
112
  `goose`, …) is validated against the list published at
111
113
  https://mongez.js.org/agent-kit/llms.txt, fetched once and cached locally. If
112
114
  that fetch fails for an explicitly requested non-default target, the run fails
113
- visibly and names every target it *could* determine — it never silently
115
+ visibly and names every target it _could_ determine — it never silently
114
116
  guesses.
115
117
 
116
118
  ## Valid keys
117
119
 
118
120
  **Database drivers** (`--db`):
119
121
 
120
- | Key | Default port | Status |
121
- | ---------- | ------------ | ----------- |
122
- | `mongodb` | 27017 | available |
123
- | `postgres` | 5432 | available |
124
- | `mysql` | 3306 | coming soon (disabled in the wizard) |
122
+ | Key | Default port | Status |
123
+ | ---------- | ------------ | ------------------------------------------------------------------------ |
124
+ | `mongodb` | 27017 | available |
125
+ | `postgres` | 5432 | available |
126
+ | `mysql` | 3306 | coming soon (disabled in the wizard) |
125
127
  | `none` | — | opt out — no driver, no driver package, `src/config/database.ts` removed |
126
128
 
127
129
  **Features** (`--features`): `react`, `react-email`, `mail`, `ses`, `image`, `s3`, `redis`, `scheduler`, `herald`, `socket`, `test`, `access`, `web`, `tailwind`, `shadcn`, `notifications`.
@@ -191,4 +193,87 @@ Failures surface the error and halt; there is no rollback. After it finishes, `c
191
193
  - The `create-module` topic of the `warlock-js-core` skill — generate a new module inside the project.
192
194
  - The `add-connector` topic of the `warlock-js-core` skill — what `warlock add` wires when a feature pulls a connector.
193
195
 
196
+ The project-ready summary wraps the complete feature list to your terminal width.
197
+ Terminals narrower than 50 columns get a plain list; piped output uses 80 columns.
198
+
199
+ ## Custom feature groups
200
+
201
+ `--customize` opens a section menu for optional features. Open a section to edit
202
+ its checklist; **Select all** includes the remaining features while preserving
203
+ items you explicitly unticked. The category cursor stays on the last edited
204
+ section. Section
205
+ counts update when returning to the menu, and **Continue** keeps the selection.
206
+ Flags preselect their existing feature keys. Both menus and checklists retain
207
+ terminal paging. The decisions overview previews up to six feature/AI keys with
208
+ a total count; the success screen shows the complete list.
209
+
210
+ ## Choose the linter and formatter
211
+
212
+ `--lint=oxc` is the default. It also accepts `--lint oxc` and installs exact
213
+ `oxlint@1.88.0` and `oxfmt@0.73.0` versions, emits `.oxlintrc.json` and
214
+ `.oxfmtrc.json`, and removes the template's ESLint/Prettier configs and dependencies.
215
+ Pass `--lint=eslint` to opt in to ESLint/Prettier. The custom wizard prompts for
216
+ the same choice; a flag preselects it.
217
+
218
+ ```bash
219
+ # Default: Oxlint + Oxfmt, TypeScript 7.0.2
220
+ npm create warlock@latest my-app -- --yes
221
+
222
+ # Explicit opt-in: ESLint + Prettier, TypeScript 6.0.3
223
+ npm create warlock@latest my-eslint-app -- --lint=eslint --yes
224
+ ```
225
+
226
+ Both choices provide `lint`/`format` and non-mutating `lint:check`/`format:check`
227
+ scripts. Oxc projects also configure VS Code format-on-save with the official
228
+ `oxc.oxc-vscode` formatter, use `source.fixAll.oxc` for lint fixes and recommend
229
+ that extension. The ESLint toolchain retains its Prettier/ESLint editor settings.
230
+ Oxc config enables `devServer.healthCheckers: { eslint: false, oxlint: true }` and
231
+ leaves TypeScript health checks enabled. Style matches the template's 100-column,
232
+ double-quote, semicolon and trailing-comma settings. Import sorting is on in
233
+ `.oxfmtrc.json`, kept to one block like the ESLint toolchain's
234
+ `@ianvs/prettier-plugin-sort-imports`:
235
+
236
+ ```json
237
+ { "sortImports": { "newlinesBetween": false, "internalPattern": ["app/", "web/", "@shared/"] } }
238
+ ```
239
+
240
+ `format` (`oxfmt --write ./src`) orders built-ins, packages, internal aliases,
241
+ then relative imports. Neither formatter deletes unused imports. ESLint reports
242
+ them through `unused-imports/no-unused-imports`; Oxlint uses `no-unused-vars`.
243
+ Scripts in both toolchains call local binaries
244
+ (`eslint --fix ./src --max-warnings=0`, `tsc --noEmit`), never `npx`.
245
+
246
+ ## TypeScript 7 in 5.32
247
+
248
+ Default Oxlint/Oxfmt projects pin `typescript` to `7.0.2`; `tsc` is the native Go compiler.
249
+ The template uses `module: "ESNext"`, `moduleResolution: "bundler"`, explicit
250
+ Node types, and `paths` relative to its tsconfig, without `baseUrl`.
251
+ Existing apps must remove `baseUrl`, rebase alias targets, and replace
252
+ `moduleResolution: "node"` / `"node10"` before typechecking.
253
+
254
+ Explicit `--lint=eslint` projects pin `typescript` to **6.0.3**, the newest version
255
+ supported by typescript-eslint. Its parser requires the JavaScript compiler API
256
+ removed in TypeScript 7, and its declared peer range is `>=4.8.4 <6.1.0`
257
+ ([parser package metadata](https://registry.npmjs.org/@typescript-eslint/parser/8.71.2)).
258
+ Both modes use the same tsconfig settings above, which are valid in TypeScript 6.
259
+ ESLint mode prints a compatibility notice when chosen and is planned for
260
+ deprecation in 5.33 and removal in 5.34. Both modes install with every supported package manager.
261
+
262
+ ### Prettier import order in ESLint mode
263
+
264
+ The ESLint scaffold’s `@ianvs/prettier-plugin-sort-imports` uses Babel instead of
265
+ the compiler API. Keep these options in `.prettierrc.json`:
266
+
267
+ ```json
268
+ {
269
+ "plugins": ["@ianvs/prettier-plugin-sort-imports"],
270
+ "importOrder": ["<BUILTIN_MODULES>", "<THIRD_PARTY_MODULES>", "^(app|web|@shared)/", "^[.]"],
271
+ "importOrderParserPlugins": ["typescript", "jsx", "decorators"]
272
+ }
273
+ ```
274
+
275
+ Leave `importOrderTypeScriptVersion` at its default to keep type and value imports
276
+ separate. Run `npm run format`, then `npm run lint:check`; formatting preserves
277
+ unused imports, and `npm run lint` can apply ESLint’s unused-import fixes.
278
+
194
279
 
package/package.json CHANGED
@@ -13,16 +13,16 @@
13
13
  "dependencies": {
14
14
  "@clack/prompts": "^0.8.2",
15
15
  "@mongez/copper": "^2.1.3",
16
- "@warlock.js/fs": "5.30.0",
16
+ "@warlock.js/fs": "5.32.0",
17
17
  "@mongez/reinforcements": "^4.0.2",
18
18
  "cross-spawn": "^7.0.3",
19
19
  "rimraf": "^6.0.1",
20
20
  "which-pm-runs": "^1.1.0"
21
21
  },
22
22
  "engines": {
23
- "node": ">=22.13"
23
+ "node": ">=22.15"
24
24
  },
25
- "version": "5.30.0",
25
+ "version": "5.32.0",
26
26
  "type": "module",
27
27
  "main": "./esm/index.mjs",
28
28
  "module": "./esm/index.mjs",
@@ -32,7 +32,7 @@ The first positional argument is the project name; it also becomes the directory
32
32
 
33
33
  1. **Default (a TTY, no `--yes`, no `--interactive`)** — asks the project name (if not already given), API-only or full-stack web (`--stack`), then a database unless `--db` or `--no-db` already supplied it. The stack is the only choice that changes the generated app's shape.
34
34
  2. **`--yes` (or no TTY at all — CI, a script, an agent harness)** — fully headless. Every answer comes from a flag or its default; nothing is ever prompted, and stdin is never read.
35
- 3. **`--interactive` (alias `--customize`)** — the full long-form wizard: project name, package manager, database driver, features, AI providers, git, JWT — one prompt after another, exactly like earlier `create-warlock` releases.
35
+ 3. **`--interactive` (alias `--customize`)** — the full long-form wizard: project name, package manager, database driver, features, AI providers, lint/format toolchain, git, JWT — one prompt after another, exactly like earlier `create-warlock` releases.
36
36
 
37
37
  **Without a terminal, `--yes` is not required.** When stdin is not a TTY — CI, a
38
38
  script, a container, an agent harness — the scaffolder does not try to prompt,
@@ -46,7 +46,7 @@ that is just the project name, the one required answer with no default:
46
46
  ```
47
47
  A project name is required and no terminal is available to ask for one. Pass it as
48
48
  the first argument or --name=<name>. Non-interactive flags: --yes, --pm=<npm|yarn|pnpm>,
49
- --db=<driver>|--no-db, --features=<list>, --ai=<list>, --git|--no-git, --jwt|--no-jwt.
49
+ --db=<driver>|--no-db, --features=<list>, --ai=<list>, --lint=<oxc|eslint>, --git|--no-git, --jwt|--no-jwt.
50
50
  ```
51
51
 
52
52
  ## After scaffolding: the decisions summary
@@ -55,26 +55,30 @@ Because almost every choice defaults silently, `create-warlock` prints what it
55
55
  decided right after scaffolding, e.g.:
56
56
 
57
57
  ```
58
- Using npm · database: none · agent-kit targets: claude
58
+ Using npm · database: none · lint: oxc · agent-kit targets: claude
59
+ Features: none
59
60
  change these — package manager: --pm, database: --db/--no-db, agents: --agents,
60
- features: --features, ai: --ai, git: --git/--no-git, jwt: --jwt/--no-jwt — or
61
+ features: --features, ai: --ai, lint: --lint, git: --git/--no-git, jwt: --jwt/--no-jwt — or
61
62
  re-run with --interactive for the full wizard.
62
63
  ```
63
64
 
64
65
  ## Flags
65
66
 
66
- | Flag | Takes value | Default | Purpose |
67
- | --------------------------- | ----------- | -------------- | ------------------------------------------------------------------- |
68
- | `<positional>` / `--name` | yes | — (required) | Project name + target directory. |
69
- | `--stack` | yes | `api` | `api` or `web` — the structural choice; `web` seeds the `web` feature by default. |
70
- | `--db` | yes | `mongodb` | Database driver key (`mongodb`, `postgres`, or `none`). |
71
- | `--no-db` | no | — | Opt out of a database — shorthand for `--db=none`. |
72
- | `--pm` | yes | inferred (`npm_config_user_agent` / system) | Package manager — must be one of `npm` / `yarn` / `pnpm` / `bun`; anything else is rejected before scaffolding starts. |
73
- | `--features` | yes (CSV) | none, or `["web"]` when `--stack=web` and `--features` is not given | Comma-separated optional feature keys. An explicit `--features` always wins over the `--stack` default. |
74
- | `--ai` | yes (CSV) | none | Comma-separated AI provider keys (auto-pulls `@warlock.js/ai`). |
75
- | `--agents` | yes (CSV) | `claude` | Comma-separated `agent-kit` targets — see below. |
76
- | `--git` / `--no-git` | no | off | Initialize a Git repo (`git init` + `main` branch + initial commit).|
77
- | `--jwt` / `--no-jwt` | no | off | Generate JWT secrets via the project's `jwt` script. |
67
+ | Flag | Takes value | Default | Purpose |
68
+ | ------------------------------ | ----------- | ------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------- |
69
+ | `<positional>` / `--name` | yes | — (required) | Project name + target directory. |
70
+ | `--stack` | yes | `api` | `api` or `web` — the structural choice; `web` seeds the `web` feature by default. |
71
+ | `--db` | yes | `mongodb` | Database driver key (`mongodb`, `postgres`, or `none`). |
72
+ | `--no-db` | no | — | Opt out of a database — shorthand for `--db=none`. |
73
+ | `--pm` | yes | inferred (`npm_config_user_agent` / system) | Package manager — must be one of `npm` / `yarn` / `pnpm` / `bun`; anything else is rejected before scaffolding starts. |
74
+ | `--features` | yes (CSV) | none, or `["web"]` when `--stack=web` and `--features` is not given | Comma-separated optional feature keys. An explicit `--features` always wins over the `--stack` default. |
75
+ | `--lint` | yes | `oxc` | `oxc` (Oxlint/Oxfmt) or `eslint` (ESLint/Prettier); unknown or missing values fail before writes. |
76
+ | `--ai` | yes (CSV) | none | Comma-separated AI provider keys (auto-pulls `@warlock.js/ai`). |
77
+ | `--agents` | yes (CSV) | `claude` | Comma-separated `agent-kit` targets — see below. |
78
+ | `--git` / `--no-git` | no | off | Initialize a Git repo (`git init` + `main` branch + initial commit). |
79
+ | `--jwt` / `--no-jwt` | no | off | Generate JWT secrets via the project's `jwt` script. |
80
+ | `--yes` / `-y` | no | off | Fully headless mode. |
81
+ | `--interactive`, `--customize` | no | off | Restore the full long-form wizard. |
78
82
 
79
83
  With `--pm=pnpm`, the scaffold reads `pnpm --version` and records install-script
80
84
  approvals (esbuild, and Sharp when the `image` feature is selected) where that
@@ -85,10 +89,8 @@ no workspace file (those versions reject one without `packages:`) but
85
89
  retained. If selected feature dependencies do
86
90
  not install, JWT generation is skipped and reported rather than retried through
87
91
  the package manager.
88
- | `--yes` / `-y` | no | off | Fully headless mode. |
89
- | `--interactive`, `--customize` | no | off | Restore the full long-form wizard. |
90
92
 
91
- Value flags accept either `--db=postgres` or `--db postgres`. Unknown `--features` / `--ai` / `--agents` keys fail fast before any install.
93
+ Value flags accept either `--db=postgres` or `--db postgres`. Unknown `--pm` / `--db` / `--features` / `--ai` / `--agents` / `--lint` values fail fast before any write or install.
92
94
 
93
95
  `--help`/`-h` and `--version`/`-v` short-circuit before anything else — no prompt, filesystem write, or network call, and `--help` wins even over a positional project name. `--version` prints the installed `create-warlock` version. `--help` lists every flag above together with its default.
94
96
 
@@ -102,18 +104,18 @@ fallback that always works — even fully offline. Any other target
102
104
  `goose`, …) is validated against the list published at
103
105
  https://mongez.js.org/agent-kit/llms.txt, fetched once and cached locally. If
104
106
  that fetch fails for an explicitly requested non-default target, the run fails
105
- visibly and names every target it *could* determine — it never silently
107
+ visibly and names every target it _could_ determine — it never silently
106
108
  guesses.
107
109
 
108
110
  ## Valid keys
109
111
 
110
112
  **Database drivers** (`--db`):
111
113
 
112
- | Key | Default port | Status |
113
- | ---------- | ------------ | ----------- |
114
- | `mongodb` | 27017 | available |
115
- | `postgres` | 5432 | available |
116
- | `mysql` | 3306 | coming soon (disabled in the wizard) |
114
+ | Key | Default port | Status |
115
+ | ---------- | ------------ | ------------------------------------------------------------------------ |
116
+ | `mongodb` | 27017 | available |
117
+ | `postgres` | 5432 | available |
118
+ | `mysql` | 3306 | coming soon (disabled in the wizard) |
117
119
  | `none` | — | opt out — no driver, no driver package, `src/config/database.ts` removed |
118
120
 
119
121
  **Features** (`--features`): `react`, `react-email`, `mail`, `ses`, `image`, `s3`, `redis`, `scheduler`, `herald`, `socket`, `test`, `access`, `web`, `tailwind`, `shadcn`, `notifications`.
@@ -182,3 +184,86 @@ Failures surface the error and halt; there is no rollback. After it finishes, `c
182
184
  - The `run-app` topic of the `warlock-js-core` skill — `warlock dev` / `build` / `start` once the project exists.
183
185
  - The `create-module` topic of the `warlock-js-core` skill — generate a new module inside the project.
184
186
  - The `add-connector` topic of the `warlock-js-core` skill — what `warlock add` wires when a feature pulls a connector.
187
+
188
+ The project-ready summary wraps the complete feature list to your terminal width.
189
+ Terminals narrower than 50 columns get a plain list; piped output uses 80 columns.
190
+
191
+ ## Custom feature groups
192
+
193
+ `--customize` opens a section menu for optional features. Open a section to edit
194
+ its checklist; **Select all** includes the remaining features while preserving
195
+ items you explicitly unticked. The category cursor stays on the last edited
196
+ section. Section
197
+ counts update when returning to the menu, and **Continue** keeps the selection.
198
+ Flags preselect their existing feature keys. Both menus and checklists retain
199
+ terminal paging. The decisions overview previews up to six feature/AI keys with
200
+ a total count; the success screen shows the complete list.
201
+
202
+ ## Choose the linter and formatter
203
+
204
+ `--lint=oxc` is the default. It also accepts `--lint oxc` and installs exact
205
+ `oxlint@1.88.0` and `oxfmt@0.73.0` versions, emits `.oxlintrc.json` and
206
+ `.oxfmtrc.json`, and removes the template's ESLint/Prettier configs and dependencies.
207
+ Pass `--lint=eslint` to opt in to ESLint/Prettier. The custom wizard prompts for
208
+ the same choice; a flag preselects it.
209
+
210
+ ```bash
211
+ # Default: Oxlint + Oxfmt, TypeScript 7.0.2
212
+ npm create warlock@latest my-app -- --yes
213
+
214
+ # Explicit opt-in: ESLint + Prettier, TypeScript 6.0.3
215
+ npm create warlock@latest my-eslint-app -- --lint=eslint --yes
216
+ ```
217
+
218
+ Both choices provide `lint`/`format` and non-mutating `lint:check`/`format:check`
219
+ scripts. Oxc projects also configure VS Code format-on-save with the official
220
+ `oxc.oxc-vscode` formatter, use `source.fixAll.oxc` for lint fixes and recommend
221
+ that extension. The ESLint toolchain retains its Prettier/ESLint editor settings.
222
+ Oxc config enables `devServer.healthCheckers: { eslint: false, oxlint: true }` and
223
+ leaves TypeScript health checks enabled. Style matches the template's 100-column,
224
+ double-quote, semicolon and trailing-comma settings. Import sorting is on in
225
+ `.oxfmtrc.json`, kept to one block like the ESLint toolchain's
226
+ `@ianvs/prettier-plugin-sort-imports`:
227
+
228
+ ```json
229
+ { "sortImports": { "newlinesBetween": false, "internalPattern": ["app/", "web/", "@shared/"] } }
230
+ ```
231
+
232
+ `format` (`oxfmt --write ./src`) orders built-ins, packages, internal aliases,
233
+ then relative imports. Neither formatter deletes unused imports. ESLint reports
234
+ them through `unused-imports/no-unused-imports`; Oxlint uses `no-unused-vars`.
235
+ Scripts in both toolchains call local binaries
236
+ (`eslint --fix ./src --max-warnings=0`, `tsc --noEmit`), never `npx`.
237
+
238
+ ## TypeScript 7 in 5.32
239
+
240
+ Default Oxlint/Oxfmt projects pin `typescript` to `7.0.2`; `tsc` is the native Go compiler.
241
+ The template uses `module: "ESNext"`, `moduleResolution: "bundler"`, explicit
242
+ Node types, and `paths` relative to its tsconfig, without `baseUrl`.
243
+ Existing apps must remove `baseUrl`, rebase alias targets, and replace
244
+ `moduleResolution: "node"` / `"node10"` before typechecking.
245
+
246
+ Explicit `--lint=eslint` projects pin `typescript` to **6.0.3**, the newest version
247
+ supported by typescript-eslint. Its parser requires the JavaScript compiler API
248
+ removed in TypeScript 7, and its declared peer range is `>=4.8.4 <6.1.0`
249
+ ([parser package metadata](https://registry.npmjs.org/@typescript-eslint/parser/8.71.2)).
250
+ Both modes use the same tsconfig settings above, which are valid in TypeScript 6.
251
+ ESLint mode prints a compatibility notice when chosen and is planned for
252
+ deprecation in 5.33 and removal in 5.34. Both modes install with every supported package manager.
253
+
254
+ ### Prettier import order in ESLint mode
255
+
256
+ The ESLint scaffold’s `@ianvs/prettier-plugin-sort-imports` uses Babel instead of
257
+ the compiler API. Keep these options in `.prettierrc.json`:
258
+
259
+ ```json
260
+ {
261
+ "plugins": ["@ianvs/prettier-plugin-sort-imports"],
262
+ "importOrder": ["<BUILTIN_MODULES>", "<THIRD_PARTY_MODULES>", "^(app|web|@shared)/", "^[.]"],
263
+ "importOrderParserPlugins": ["typescript", "jsx", "decorators"]
264
+ }
265
+ ```
266
+
267
+ Leave `importOrderTypeScriptVersion` at its default to keep type and value imports
268
+ separate. Run `npm run format`, then `npm run lint:check`; formatting preserves
269
+ unused imports, and `npm run lint` can apply ESLint’s unused-import fixes.
@@ -0,0 +1,15 @@
1
+ {
2
+ "$schema": "./node_modules/oxfmt/configuration_schema.json",
3
+ "semi": true,
4
+ "tabWidth": 2,
5
+ "printWidth": 100,
6
+ "singleQuote": false,
7
+ "arrowParens": "always",
8
+ "trailingComma": "all",
9
+ "endOfLine": "lf",
10
+ "sortImports": {
11
+ "newlinesBetween": false,
12
+ "internalPattern": ["app/", "web/", "@shared/"]
13
+ },
14
+ "ignorePatterns": ["node_modules/", "dist/"]
15
+ }
@@ -0,0 +1,24 @@
1
+ {
2
+ "$schema": "./node_modules/oxlint/configuration_schema.json",
3
+ "plugins": ["typescript", "import", "react"],
4
+ "env": { "node": true, "es2021": true },
5
+ "categories": { "correctness": "off" },
6
+ "rules": {
7
+ "typescript/no-explicit-any": "off",
8
+ "no-unused-vars": [
9
+ "warn",
10
+ {
11
+ "vars": "all",
12
+ "varsIgnorePattern": "^_",
13
+ "args": "after-used",
14
+ "argsIgnorePattern": "^_"
15
+ }
16
+ ],
17
+ "typescript/explicit-member-accessibility": ["error", { "accessibility": "explicit" }],
18
+ "typescript/consistent-type-imports": [
19
+ "error",
20
+ { "prefer": "type-imports", "disallowTypeAnnotations": false }
21
+ ]
22
+ },
23
+ "ignorePatterns": ["node_modules/", "dist/"]
24
+ }
@@ -0,0 +1,3 @@
1
+ {
2
+ "recommendations": ["oxc.oxc-vscode"]
3
+ }
@@ -0,0 +1,35 @@
1
+ {
2
+ "editor.defaultFormatter": "oxc.oxc-vscode",
3
+ "editor.formatOnSave": true,
4
+ "editor.codeActionsOnSave": {
5
+ "source.fixAll.oxc": "explicit",
6
+ "source.organizeImports": "never"
7
+ },
8
+ "[typescript]": {
9
+ "editor.defaultFormatter": "oxc.oxc-vscode",
10
+ "editor.formatOnSave": true
11
+ },
12
+ "[typescriptreact]": {
13
+ "editor.defaultFormatter": "oxc.oxc-vscode",
14
+ "editor.formatOnSave": true
15
+ },
16
+ "[javascript]": {
17
+ "editor.defaultFormatter": "oxc.oxc-vscode",
18
+ "editor.formatOnSave": true
19
+ },
20
+ "[javascriptreact]": {
21
+ "editor.defaultFormatter": "oxc.oxc-vscode",
22
+ "editor.formatOnSave": true
23
+ },
24
+ "[json]": {
25
+ "editor.defaultFormatter": "oxc.oxc-vscode",
26
+ "editor.formatOnSave": true
27
+ },
28
+ "[css]": {
29
+ "editor.defaultFormatter": "oxc.oxc-vscode",
30
+ "editor.formatOnSave": true
31
+ },
32
+ "oxc.enable.oxlint": true,
33
+ "oxc.enable.oxfmt": true,
34
+ "oxc.requireConfig": true
35
+ }
@@ -6,5 +6,7 @@
6
6
  "arrowParens": "always",
7
7
  "trailingComma": "all",
8
8
  "endOfLine": "lf",
9
- "plugins": ["prettier-plugin-organize-imports"]
9
+ "plugins": ["@ianvs/prettier-plugin-sort-imports"],
10
+ "importOrder": ["<BUILTIN_MODULES>", "<THIRD_PARTY_MODULES>", "^(app|web|@shared)/", "^[.]"],
11
+ "importOrderParserPlugins": ["typescript", "jsx", "decorators"]
10
12
  }
@@ -80,8 +80,8 @@ automatically on `postinstall`).
80
80
  - `yarn start` — start the production server (`warlock start`)
81
81
  - `yarn migrate` / `yarn migrate.fresh` / `yarn migrate.list` — run migrations
82
82
  - `yarn seed` — run database seeders
83
- - `yarn lint` / `yarn format` / `yarn tsc` — lint (eslint --fix), format
84
- (prettier), and type-check (`tsc --noEmit`)
83
+ - `yarn lint` / `yarn format` / `yarn tsc` — lint and format with the selected toolchain, and type-check (`tsc --noEmit`)
84
+ - `npx warlock check` — verify a change: typecheck, lint, the affected tests and the framework's conventions in one report (`--changed` for only what changed); run it after every change and loop until it exits 0
85
85
  - `yarn skills:sync` — re-sync skills from `node_modules` and regenerate the
86
86
  derived per-agent files from this `AGENTS.md`
87
87
 
@@ -98,6 +98,13 @@ suffixes, and JSDoc on the public surface. The bar is senior-level clean code, n
98
98
 
99
99
  - Respect **module-boundaries** — do not reach across module internals.
100
100
  - Never weaken the **security-baseline** — always validate input at boundaries.
101
+ - `npx warlock check` enforces these rules whichever linter the project uses:
102
+ pass `request.validated()` (never `request.all()`) to queries and services
103
+ (`WL9005`), give every POST/PUT/PATCH/DELETE route auth middleware or an
104
+ explicit `public: true` (`WL9006`), wrap request-supplied redirect targets in
105
+ `safeRedirect()` (`WL9007`), keep raw emails, tokens and request bodies out of
106
+ logs (`WL9008`) and bound regexes that run on request input (`WL9009`). Each
107
+ problem carries its fix; `npx warlock explain <CODE>` prints it again.
101
108
  - Follow **git-workflow** for commits and branches; do not commit or push unless
102
109
  explicitly asked.
103
110
  - When you are unsure how a package or feature works, **stop and read its skill**
@@ -122,3 +129,16 @@ Three things that trip everyone up on a fresh app:
122
129
  instance does not expose its columns as direct properties — `post.title` is
123
130
  `undefined` at runtime and a type error. Use `post.get("title")`, or
124
131
  `post.toJSON()` in a page loader (resources are the serialization gate).
132
+
133
+ ## This app (generated)
134
+
135
+ `warlock dev` rewrites everything between the two markers below from the
136
+ running app — modules, routes, models, installed skills and the commands to
137
+ verify a change. Edit outside the markers; turn it off with
138
+ `devServer.agentsMd: false` in `warlock.config.ts`.
139
+
140
+ <!-- warlock:generated:start -->
141
+
142
+ Run `npx warlock dev` (or `npx warlock agents-md --write`) to fill this section.
143
+
144
+ <!-- warlock:generated:end -->
@@ -7,7 +7,7 @@ Full documentation: [warlock.js.org](https://warlock.js.org).
7
7
 
8
8
  ## Requirements
9
9
 
10
- - Node.js **22.13** or newer
10
+ - Node.js **22.15** or newer
11
11
  - The database you picked when scaffolding (MongoDB or PostgreSQL), running and
12
12
  reachable with the settings in `.env` — skip this if you scaffolded with no
13
13
  database
@@ -40,8 +40,10 @@ It restarts on file changes.
40
40
  | `npm run seed` | Run the database seeders |
41
41
  | `npm run jwt` | Generate a JWT secret into `.env` |
42
42
  | `npm run tsc` | Type-check without building |
43
- | `npm run lint` | ESLint, auto-fixing what it can |
44
- | `npm run format` | Prettier over `src/` |
43
+ | `npm run lint` | The configured linter, auto-fixing what it can |
44
+ | `npm run format` | The configured formatter over `src/` |
45
+ | `npm run lint:check` | Lint without changing files |
46
+ | `npm run format:check` | Check formatting without changing files |
45
47
  | `npm run skills:sync` | Refresh the AI agent skills (see below) |
46
48
 
47
49
  The `warlock` CLI has more than the scripts expose — run `npx warlock --help`
@@ -146,3 +148,16 @@ This project ships instructions and skills for AI coding agents:
146
148
 
147
149
  - [Documentation](https://warlock.js.org)
148
150
  - [Changelog](https://warlock.js.org/changelog)
151
+
152
+ ## TypeScript 7 in 5.32
153
+
154
+ New projects pin `typescript` to `7.0.2`; `tsc` is the native Go compiler.
155
+ The template uses `module: "ESNext"`, `moduleResolution: "bundler"`, explicit
156
+ Node types, and `paths` relative to its tsconfig, without `baseUrl`.
157
+ Existing apps must remove `baseUrl`, rebase alias targets, and replace
158
+ `moduleResolution: "node"` / `"node10"` before typechecking.
159
+
160
+ Use the Oxlint/Oxfmt lint mode with TS7. The optional ESLint scaffold is retained,
161
+ but typescript-eslint's parser requires the removed JavaScript compiler API and
162
+ does not support TS7. ESLint mode is scheduled for deprecation in 5.33 and removal
163
+ in 5.34. A parser's bundled older TypeScript is separate from the app's native `tsc`.
@@ -19,12 +19,14 @@
19
19
  "gen.mig": "warlock generate.migration",
20
20
  "gen.r": "warlock generate.repository",
21
21
  "gen.rs": "warlock generate.resource",
22
- "lint": "npx eslint --fix ./src --max-warnings=0",
23
- "format": "npx prettier --write ./src/**/*.{js,jsx,ts,tsx,css,md,json} --config ./.prettierrc.json",
24
- "tsc": "warlock generate.typings && npx tsc --noEmit",
22
+ "lint": "eslint --fix ./src --max-warnings=0",
23
+ "format": "prettier --write \"./src/**/*.{js,jsx,ts,tsx,css,md,json}\" --config ./.prettierrc.json",
24
+ "tsc": "warlock generate.typings && tsc --noEmit",
25
25
  "postinstall": "agent-kit init && agent-kit sync || echo \"warning: AI agent skills were NOT synced, so coding agents will not see the @warlock.js skills. Run the skills:sync script.\"",
26
26
  "skills:sync": "agent-kit sync",
27
- "skills:watch": "agent-kit watch"
27
+ "skills:watch": "agent-kit watch",
28
+ "lint:check": "eslint ./src --max-warnings=0",
29
+ "format:check": "prettier --check \"./src/**/*.{js,jsx,ts,tsx,css,md,json}\" --config ./.prettierrc.json"
28
30
  },
29
31
  "dependencies": {
30
32
  "@mongez/reinforcements": "^4.0.2",
@@ -41,6 +43,7 @@
41
43
  "dayjs": "^1.11.19"
42
44
  },
43
45
  "devDependencies": {
46
+ "@ianvs/prettier-plugin-sort-imports": "^4.7.1",
44
47
  "@mongez/agent-kit": "^1.3.1",
45
48
  "@types/node": "^25.0.3",
46
49
  "@types/prettier": "^3.0.0",
@@ -51,8 +54,7 @@
51
54
  "eslint-plugin-prettier": "^5.5.4",
52
55
  "eslint-plugin-unused-imports": "^4.3.0",
53
56
  "prettier": "^3.7.4",
54
- "prettier-plugin-organize-imports": "^4.3.0",
55
- "typescript": "^5.9.3",
57
+ "typescript": "7.0.2",
56
58
  "vitest": "4.0.5"
57
59
  }
58
60
  }
@@ -24,8 +24,8 @@ The list lands under the **plural name of the module's resource** — `users`, `
24
24
 
25
25
  ```typescript
26
26
  // ✅ list-users.controller.ts
27
- export const listUsersController: RequestHandler = async (request, response) => {
28
- const { data, pagination } = await listUsersService(request.all());
27
+ export const listUsersController: RequestHandler = async ({ request, response }) => {
28
+ const { data, pagination } = await listUsersService(request.validated());
29
29
 
30
30
  return response.success({
31
31
  users: data,