@skyf0xx/hedgehog 4.2.0 → 4.2.2

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 (44) hide show
  1. package/README.md +20 -0
  2. package/bin/cli.mjs +12 -0
  3. package/package.json +2 -2
  4. package/src/agents/backend-eng.md +30 -16
  5. package/src/agents/front-end-eng.md +29 -12
  6. package/src/db/next.mjs +46 -8
  7. package/src/golden-cores/full-stack-app/apps/api/package.json +19 -1
  8. package/src/golden-cores/full-stack-app/apps/api/src/app/app.module.spec.ts +15 -0
  9. package/src/golden-cores/full-stack-app/apps/api/src/app/app.module.ts +6 -1
  10. package/src/golden-cores/full-stack-app/apps/api/src/app/feature-modules.ts +8 -0
  11. package/src/golden-cores/full-stack-app/apps/api/tsconfig.app.json +3 -0
  12. package/src/golden-cores/full-stack-app/apps/api/tsconfig.json +3 -0
  13. package/src/golden-cores/full-stack-app/apps/api/tsconfig.spec.json +36 -0
  14. package/src/golden-cores/full-stack-app/apps/api/vitest.config.mts +18 -0
  15. package/src/golden-cores/full-stack-app/apps/web/src/components/theme-toggle.spec.tsx +20 -0
  16. package/src/golden-cores/full-stack-app/apps/web/src/test-setup.ts +1 -0
  17. package/src/golden-cores/full-stack-app/apps/web/tsconfig.json +6 -0
  18. package/src/golden-cores/full-stack-app/apps/web/tsconfig.spec.json +37 -0
  19. package/src/golden-cores/full-stack-app/apps/web/vitest.config.mts +27 -0
  20. package/src/golden-cores/full-stack-app/nx.json +4 -1
  21. package/src/golden-cores/full-stack-app/package.json +8 -0
  22. package/src/golden-cores/full-stack-app/pnpm-lock.yaml +8735 -2907
  23. package/src/golden-cores/full-stack-app/tools/generate-feature-modules.cjs +104 -0
  24. package/src/golden-cores/full-stack-app/tools/generators/contract/generator.ts +283 -0
  25. package/src/golden-cores/full-stack-app/tools/generators/contract/schema.json +20 -0
  26. package/src/golden-cores/full-stack-app/tools/generators/controller/generator.ts +323 -0
  27. package/src/golden-cores/full-stack-app/tools/generators/controller/schema.json +20 -0
  28. package/src/golden-cores/full-stack-app/tools/generators/fields.ts +126 -0
  29. package/src/golden-cores/full-stack-app/tools/generators/generators.json +42 -0
  30. package/src/golden-cores/full-stack-app/tools/generators/hook/generator.ts +274 -0
  31. package/src/golden-cores/full-stack-app/tools/generators/hook/schema.json +19 -0
  32. package/src/golden-cores/full-stack-app/tools/generators/lib-shell.ts +124 -0
  33. package/src/golden-cores/full-stack-app/tools/generators/naming.ts +84 -0
  34. package/src/golden-cores/full-stack-app/tools/generators/package.json +6 -0
  35. package/src/golden-cores/full-stack-app/tools/generators/repository/generator.ts +298 -0
  36. package/src/golden-cores/full-stack-app/tools/generators/repository/schema.json +15 -0
  37. package/src/golden-cores/full-stack-app/tools/generators/schema/generator.ts +169 -0
  38. package/src/golden-cores/full-stack-app/tools/generators/schema/schema.json +20 -0
  39. package/src/golden-cores/full-stack-app/tools/generators/screen/generator.ts +218 -0
  40. package/src/golden-cores/full-stack-app/tools/generators/screen/schema.json +15 -0
  41. package/src/golden-cores/full-stack-app/tools/generators/service/generator.ts +194 -0
  42. package/src/golden-cores/full-stack-app/tools/generators/service/schema.json +15 -0
  43. package/src/skills/hedgehog-bootstrap-full-stack-app-core/SKILL.md +67 -6
  44. package/src/skills/hedgehog-loop/SKILL.md +119 -53
@@ -87,10 +87,12 @@ stop — an operation that seems to want async processing on a Queue-off
87
87
  project is a signal to revisit that add-on decision with `planner`, not
88
88
  to build a one-off queue outside the add-on's scaffolding.
89
89
 
90
- Standard Nx generators (`@nx/nest`, `@nx/next`, `@nx/expo`, `@nx/js`)
91
- scaffold the app/lib shell. Each step's actual content (schema, contract,
92
- repository, service, controller, hook) is hand-built, following this
93
- sequence.
90
+ Every layer scaffolds from its own generator in `tools/generators/` (see
91
+ "Scaffolding a layer" below) — package shell, tags, files, barrel wiring,
92
+ and the layer's conventional shape all land in one deterministic step.
93
+ What's authored on top is the entity-specific delta: the field list and
94
+ its types, the module's business rules, and the UX intent behind its
95
+ screen.
94
96
 
95
97
  ## Domain Module — Backend Steps (Phase A, every module in scope)
96
98
 
@@ -211,6 +213,102 @@ Correction Protocol. Valid task statuses are `planned`, `ready`,
211
213
  also carries a `blocked_reason` (`scope_violation`, `verification_failed`,
212
214
  or `lease_expired`).
213
215
 
216
+ ## Scaffolding a layer
217
+
218
+ `tools/generators/` holds one Nx generator per layer, and every layer
219
+ starts from its own:
220
+
221
+ ```bash
222
+ nx g ./tools/generators:schema --module=<module> --fields='<name:type,...>'
223
+ nx g ./tools/generators:contract --module=<module> --fields='<name:type,...>'
224
+ nx g ./tools/generators:repository --module=<module>
225
+ nx g ./tools/generators:service --module=<module>
226
+ nx g ./tools/generators:controller --module=<module> --fields='<name:type,...>'
227
+ nx g ./tools/generators:hook --module=<module> [--toggleField=<boolField>]
228
+ nx g ./tools/generators:screen --module=<module>
229
+ ```
230
+
231
+ `--module` is the domain module's plural kebab-case name (`tasks`,
232
+ `order-items`). `--fields` is a comma-separated list of `name:type` pairs
233
+ over `string`, `text`, `boolean`, `integer`, and `timestamp`, with a
234
+ trailing `?` marking the column nullable
235
+ (`--fields='title:string,done:boolean,dueDate:timestamp?'`); `contract`
236
+ and `controller` take the same list the module's `schema` was generated
237
+ with. `hook`'s optional `--toggleField` names a boolean field from the
238
+ schema to expose as a dedicated toggle mutation.
239
+
240
+ Each generator lands the whole conventional shape of its layer in one
241
+ deterministic step — the package shell (`package.json`, `tsconfig*.json`,
242
+ `vitest.config.mts`, `src/index.ts`) where the layer creates one, the
243
+ `nx.tags` pair `packages/config/eslint-base.js`'s `depConstraints` keys
244
+ on, the port-discipline file suffixes lint checks for, the Nest module
245
+ and controller pair with `@Controller()` left bare (the ts-rest contract
246
+ already encodes full route paths), and every barrel export the new files
247
+ need. Hand-copying a sibling module's files invites exactly the drift
248
+ `hedgehog verify`'s lint step then has to catch: missing tags, missing
249
+ project references, a doubled route prefix.
250
+
251
+ What the generator lands is the layer's skeleton, not the layer. Author
252
+ the entity-specific delta on top: the module's business rules in
253
+ `service`, its domain-error mapping in `controller`, and — for `screen`,
254
+ which is skeleton-only by design — the layout, information hierarchy, and
255
+ interaction pattern from `ux-planner`'s rationale, over the placeholders
256
+ the generator leaves for the list, filter shell, empty state, and form.
257
+
258
+ Registration inside `apps/api` is automatic and stays that way:
259
+ `apps/api/src/app/feature-modules.ts` globs
260
+ `apps/api/src/app/*/*.module.ts` and is regenerated by the
261
+ `generate-feature-modules` Nx target that `build`/`typecheck`/`test`
262
+ depend on. Never register a module by editing `app.module.ts` — a shared
263
+ file no module-scoped task can safely touch. Validation is ts-rest + Zod,
264
+ so this core has no Nest DTOs and no class-validator.
265
+
266
+ **A new package needs wiring into the workspace before `hedgehog verify`
267
+ runs on it.** A package that exists on disk isn't yet part of the
268
+ workspace:
269
+
270
+ ```bash
271
+ pnpm install # link the new workspace:* deps
272
+ pnpm nx sync # regenerate TypeScript project references
273
+ ```
274
+
275
+ `pnpm-workspace.yaml` already globs `packages/*`, `apps/*` and `libs/*/*`,
276
+ so a package under any of those needs no edit there. This is the common
277
+ case, not an edge case: any layer that is the first arrival in a package
278
+ (`contract`, `hook`, each module's `repository` and `service`) or that
279
+ wires a new package into an existing one (`controller`, adding the
280
+ module's `contracts`/`repository`/`service` packages to `apps/api`) needs
281
+ it — on a module's first pass through Phase A/B that is most of the
282
+ layers, not an occasional one.
283
+
284
+ The building agent runs `pnpm install` / `pnpm nx sync` and reports back
285
+ which shared files changed (typically `pnpm-lock.yaml`, root
286
+ `tsconfig.json`, and — on a `controller` layer — `apps/api/package.json`,
287
+ `apps/api/tsconfig.app.json`), because it has the shell access to run
288
+ them, but it never commits: no agent reporting success moves a task or
289
+ touches git, only `hedgehog verify`'s passing exit code does (see the
290
+ building agents' own Workflow step on this). Committing those shared
291
+ files is the orchestrating session's job, done between dispatch and
292
+ `hedgehog verify` on every layer where the agent flagged a change: expect
293
+ it, don't wait to be reminded.
294
+
295
+ ```bash
296
+ git add pnpm-lock.yaml tsconfig.json # plus apps/*/package.json,
297
+ # apps/*/tsconfig.app.json on a
298
+ # controller layer
299
+ git commit -m "chore(workspace): sync project references"
300
+ ```
301
+
302
+ These files are mechanically derived by `pnpm install` and `pnpm nx
303
+ sync`, not authored content, and sit outside every module-scoped layer's
304
+ scope — they belong to no layer, and no override covers them. Committing
305
+ them separately, before `hedgehog verify` runs, keeps the layer's own
306
+ commit exactly the layer.
307
+
308
+ This is the orchestrating session's step rather than a verify post-step
309
+ on purpose: `hedgehog verify` gates the tree it's handed, and a gate that
310
+ mutates that tree would manufacture the scope violation it then reports.
311
+
214
312
  ## First arrival in a package
215
313
 
216
314
  Every layer scope names a directory *inside* a package
@@ -223,15 +321,25 @@ sit on disk uncommitted until the `join` layer's `**` scope sweeps them in,
223
321
  so `git log -- packages/contracts/` shows source with no buildable package
224
322
  behind it for the whole middle of the build.
225
323
 
324
+ A generator can also drop shared, package-wide source at the `src/` root
325
+ alongside the module's own files on that same first pass — the `contract`
326
+ generator's `timestamp.ts` is one (a shared Zod util every module in the
327
+ package imports, written once, sibling to `src/index.ts`). That file needs
328
+ the same widening as the shell itself.
329
+
226
330
  Widen that one task, before building it:
227
331
 
228
332
  ```bash
229
333
  hedgehog override add TASKS-CONTRACT \
230
334
  --scope 'packages/contracts/*' \
231
- --scope 'packages/contracts/src/index.ts' \
335
+ --scope 'packages/contracts/src/*' \
232
336
  --reason 'first module through the contract layer also creates the package shell'
233
337
  ```
234
338
 
339
+ `packages/contracts/src/*` is non-recursive, so it covers `src/index.ts`
340
+ and `src/timestamp.ts` without also granting the module subdirectory the
341
+ layer's own `packages/contracts/src/{module}/**` scope already covers.
342
+
235
343
  `.hedgehog/overrides/*.json` is additive, per-task, committed, and replayed
236
344
  by `plan`, `--recompile` and `db rebuild` alike, so the exception survives a
237
345
  rebuild and stays reviewable in the diff — unlike a hand-edited task row,
@@ -245,57 +353,15 @@ module's `repository` and `service`, since `libs/{module}/repository` and
245
353
  `libs/{module}/service` are new libs per module — there, the layer's own
246
354
  `libs/{module}/repository/**` glob already covers the package root, so no
247
355
  override is needed. `packages/db` and `packages/config` ship with core, so
248
- `schema` never needs one.
356
+ `schema` never needs one. `controller` never needs one either — `apps/api`
357
+ ships with core, and its `apps/api/src/app/{module}/**` scope already
358
+ covers the module's generated directory.
249
359
 
250
360
  Never widen a scope to route around a violation the Correction Protocol
251
361
  should handle — this is for a package shell the layer genuinely creates,
252
- nothing else.
253
-
254
- **Generate the shell — never hand-author it.** `@nx/js:lib` produces a
255
- correct, non-buildable, Vitest-wired `package.json`/`tsconfig*.json`/
256
- `vitest.config.mts`/`src/index.ts` in one deterministic step; hand-copying
257
- a sibling package invites exactly the kind of drift (missing `nx.tags`,
258
- missing project references) `hedgehog verify`'s lint step then has to
259
- catch. Run the generator for the layer that's first-arriving, then add its
260
- tags — the pair `eslint-base.js`'s `depConstraints` expects (see its own
261
- tag reference table) — to the generated `package.json`'s `"nx".tags`:
262
-
263
- ```bash
264
- # contract — first module through this layer only
265
- npx nx g @nx/js:lib packages/contracts --bundler=none --unitTestRunner=vitest
266
- # then set "nx": { "tags": ["scope:contracts", "type:contract"] } in packages/contracts/package.json
267
-
268
- # hook — first module through this layer only
269
- npx nx g @nx/js:lib packages/hooks --bundler=none --unitTestRunner=vitest
270
- # then set "nx": { "tags": ["scope:hooks", "type:hook"] } in packages/hooks/package.json
271
-
272
- # repository — every module, new lib each time
273
- npx nx g @nx/js:lib libs/{module}/repository --bundler=none --unitTestRunner=vitest
274
- # then set "nx": { "tags": ["scope:{module}", "type:adapter"] } in libs/{module}/repository/package.json
275
-
276
- # service — every module, new lib each time
277
- npx nx g @nx/js:lib libs/{module}/service --bundler=none --unitTestRunner=vitest
278
- # then set "nx": { "tags": ["scope:{module}", "type:service"] } in libs/{module}/service/package.json
279
- ```
280
-
281
- **Wire the new package in before reporting the layer done.** A package
282
- that exists on disk isn't yet part of the workspace:
283
-
284
- ```bash
285
- pnpm install # link the new workspace:* deps
286
- pnpm nx sync # regenerate TypeScript project references
287
- ```
288
-
289
- `pnpm-workspace.yaml` already globs `packages/*`, `apps/*` and `libs/*/*`,
290
- so a package under any of those needs no edit there. `nx sync` writes root
291
- `tsconfig.json`, which sits outside every module-scoped layer's scope — it
292
- belongs to no layer and is not part of the override above. Commit it
293
- separately as `chore(workspace): sync project references`, before
294
- `hedgehog verify` runs, so the layer's own commit stays exactly the layer.
295
-
296
- This is the building agent's step rather than a verify post-step on
297
- purpose: `hedgehog verify` gates the tree it's handed, and a gate that
298
- mutates that tree would manufacture the scope violation it then reports.
362
+ nothing else. The shell itself comes from the layer's generator
363
+ ("Scaffolding a layer" above), which is also where the workspace wiring a
364
+ new package needs lives.
299
365
 
300
366
  ## Intra-step conventions
301
367