create-hozu 0.1.0 → 0.3.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.
package/README.md CHANGED
@@ -1,3 +1,5 @@
1
+ <img src="https://raw.githubusercontent.com/olevatorr/Hozu/main/docs/assets/logo.png" alt="Hozu logo" width="72">
2
+
1
3
  # create-hozu
2
4
 
3
5
  Create a Hozu app, set up for Claude Code or for agents that read AGENTS.md.
package/dist/index.d.ts CHANGED
@@ -33,6 +33,7 @@ export declare const packageJson: (name: string, version: string) => {
33
33
  };
34
34
  devDependencies: {
35
35
  '@hozu/cli': string;
36
+ '@hozu/testing': string;
36
37
  '@types/node': string;
37
38
  typescript: string;
38
39
  };
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAIA,MAAM,MAAM,KAAK,GAAG,QAAQ,GAAG,QAAQ,GAAG,MAAM,CAAA;AAChD,MAAM,MAAM,MAAM,GAAG,WAAW,GAAG,KAAK,GAAG,MAAM,GAAG,MAAM,CAAA;AAE1D,eAAO,MAAM,MAAM,EAAE,SAAS,KAAK,EAAiC,CAAA;AAGpE,eAAO,MAAM,YAAY,QAAsB,CAAA;AAiB/C,eAAO,MAAM,QAAQ,cAAe,MAAM,GAAG,SAAS,KAAG,MAGxD,CAAA;AAWD,MAAM,WAAW,YAAY;IAC3B,IAAI,EAAE,MAAM,CAAA;IACZ,MAAM,EAAE,MAAM,CAAA;IACd,WAAW,CAAC,EAAE,MAAM,CAAA;CACrB;AAED,wBAAsB,eAAe,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,KAAK,EAAE,OAAO,EAAE,YAAY,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC,CAwBzG;AAYD,MAAM,WAAW,aAAc,SAAQ,YAAY;IACjD,KAAK,EAAE,KAAK,CAAA;IACZ,OAAO,EAAE,MAAM,CAAA;CAChB;AAED,eAAO,MAAM,WAAW,SAAU,MAAM,WAAW,MAAM;;;;;QAKrD,KAAK;QACL,KAAK;QACL,KAAK;;;QAGL,oBAAoB;QACpB,YAAY;QACZ,WAAW;QACX,YAAY;QACZ,sBAAsB;QACtB,kBAAkB;QAClB,GAAG;;;QAGH,WAAW;QACX,aAAa;QACb,UAAU;;;QAED,IAAI;;CACf,CAAA;AAEF,wBAAsB,SAAS,CAAC,GAAG,EAAE,MAAM,EAAE,OAAO,EAAE,aAAa,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC,CAmBtF"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAIA,MAAM,MAAM,KAAK,GAAG,QAAQ,GAAG,QAAQ,GAAG,MAAM,CAAA;AAChD,MAAM,MAAM,MAAM,GAAG,WAAW,GAAG,KAAK,GAAG,MAAM,GAAG,MAAM,CAAA;AAE1D,eAAO,MAAM,MAAM,EAAE,SAAS,KAAK,EAAiC,CAAA;AAGpE,eAAO,MAAM,YAAY,QAAsB,CAAA;AAiB/C,eAAO,MAAM,QAAQ,cAAe,MAAM,GAAG,SAAS,KAAG,MAGxD,CAAA;AAWD,MAAM,WAAW,YAAY;IAC3B,IAAI,EAAE,MAAM,CAAA;IACZ,MAAM,EAAE,MAAM,CAAA;IACd,WAAW,CAAC,EAAE,MAAM,CAAA;CACrB;AAED,wBAAsB,eAAe,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,KAAK,EAAE,OAAO,EAAE,YAAY,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC,CAwBzG;AAYD,MAAM,WAAW,aAAc,SAAQ,YAAY;IACjD,KAAK,EAAE,KAAK,CAAA;IACZ,OAAO,EAAE,MAAM,CAAA;CAChB;AAED,eAAO,MAAM,WAAW,SAAU,MAAM,WAAW,MAAM;;;;;QAKrD,KAAK;QACL,KAAK;QACL,KAAK;;;QAGL,oBAAoB;QACpB,YAAY;QACZ,WAAW;QACX,YAAY;QACZ,sBAAsB;QACtB,kBAAkB;QAClB,GAAG;;;QAGH,WAAW;QACX,eAAe;QACf,aAAa;QACb,UAAU;;;QAED,IAAI;;CACf,CAAA;AAEF,wBAAsB,SAAS,CAAC,GAAG,EAAE,MAAM,EAAE,OAAO,EAAE,aAAa,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC,CAmBtF"}
package/dist/index.js CHANGED
@@ -64,7 +64,7 @@ export const packageJson = (name, version) => ({
64
64
  private: true,
65
65
  type: 'module',
66
66
  scripts: {
67
- check: 'tsc --noEmit -p . && hozu validate',
67
+ check: 'hozu check',
68
68
  start: 'node serve.ts',
69
69
  build: 'hozu build',
70
70
  },
@@ -79,6 +79,7 @@ export const packageJson = (name, version) => ({
79
79
  },
80
80
  devDependencies: {
81
81
  '@hozu/cli': `^${version}`,
82
+ '@hozu/testing': `^${version}`,
82
83
  '@types/node': '^22.20.4',
83
84
  typescript: '^7.0.2',
84
85
  },
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "create-hozu",
3
- "version": "0.1.0",
3
+ "version": "0.3.0",
4
4
  "description": "Create a Hozu app, set up for Claude Code or for agents that read AGENTS.md",
5
5
  "keywords": [
6
6
  "hozu",
package/skill/SKILL.md CHANGED
@@ -5,9 +5,10 @@ description: Build or change an app with the Hozu framework (packages @hozu/*, f
5
5
 
6
6
  # Hozu authoring guide
7
7
 
8
- Hozu is not in your training data. These files are the whole API; do not read `node_modules/@hozu`.
8
+ Hozu is not in your training data. These files are the whole API; skip `node_modules/@hozu`.
9
9
  - **Changing an app:** read `changing.md` first, then only the app's own files.
10
- - **Building an app:** read this file and `patterns.md`, then copy the shape of `example/` (a verified app).
10
+ - **Building an app:** read this file, run `hozu add feature <name> --page / --with auth,detail,toggle,filter,remove`
11
+ (auth = sign-in, per-user data) and edit the texts it lists; don't print the generated files.
11
12
  - **`reference.md`** when the task needs it: routes, DOM fields, no-JS forms, `head`, 404/500, field errors,
12
13
  sessions, languages, env, HTTP, Markdown, images, preview, PWA, page tests, deployment.
13
14
  - **A diagnostic you do not understand:** `diagnostics.md`.
@@ -26,25 +27,27 @@ Hozu is not in your training data. These files are the whole API; do not read `n
26
27
 
27
28
  ## Files
28
29
  ```
29
- hozu.config.ts project(): schema adapter, site, routes, pages, features
30
- routes.ts route() declarations
31
- server.ts resolvers(project, implement => [...]): query/mutation implementations
32
- serve.ts createServer({ build, styles, resolvers }).listen(PORT)
33
- app.css @import "tailwindcss";
30
+ hozu.config.ts project(): schema adapter, site, routes, pages, features
31
+ routes.ts route() declarations
32
+ server.ts resolvers(project, implement => [...]): query/mutation implementations
33
+ serve.ts createServer({ build, styles, resolvers }).listen(PORT)
34
+ app.css @import "tailwindcss";
34
35
  features/<name>/
35
- model.ts schemas, events, query / mutation / tag / fn, the machine
36
- views.ts views, contracts, feature()
36
+ model.ts schemas, events, query / mutation / tag / fn, the machine
37
+ views.ts views, contracts, feature()
37
38
  ```
38
- Relative imports end in `.ts`. Any other split works too.
39
39
 
40
- ## Checks (from the app directory)
40
+ ## Commands (from the app directory)
41
41
  ```
42
- pnpm exec tsc --noEmit -p . # types
43
- pnpm exec hozu validate # all rules + contracts; --json adds patches
44
- pnpm exec hozu validate --update-lock # accept a clean, intended behaviour change
45
- PORT=4700 node serve.ts & echo $! # run it; stop it with kill <pid>, not pkill -f
42
+ pnpm exec hozu check # after every edit: types, rules, contracts
43
+ pnpm exec hozu check --update-lock # accept an intended behaviour change
44
+ pnpm exec hozu add feature items --page / --with detail,toggle # a working feature, wired in
45
+ pnpm exec hozu map # outline of the app with file:line
46
+ pnpm exec hozu get / --select button --forms # pages without a server: text, attributes, forms
47
+ pnpm exec hozu post / --field title=A --next 'POST / title=a' --next / # submit a form like a browser
46
48
  ```
47
- Each diagnostic has a `file:line`, a cause and a fix: apply the fix, do not work around the rule.
49
+ Diagnostics give `file:line`, cause and fix: apply the fix. `get` / `post` start from fresh in-memory data;
50
+ chain steps with `--next`. Run `node serve.ts` only to use the app. Relative imports end in `.ts`.
48
51
 
49
52
  ## model.ts
50
53
  ```ts
@@ -125,12 +128,11 @@ export const Board = ui.view({
125
128
  ]),
126
129
  })
127
130
  ```
128
- - `ui.<tag>(attrs, children)`; attribute values are literals, references or guards.
131
+ - `ui.<tag>(attrs, children)`; values are literals, references or guards. `ui.each(list, 'id', (item) => node)`.
129
132
  - `class` is a static string of Tailwind classes that must exist (HZ026). Conditional classes:
130
133
  `toggle: { 'bg-indigo-600 text-white': op.eq(ctx.tab, t) }`. CSS variables: `vars: { '--hue': item.hue }`.
131
134
  - Events: `on: { click: ui.send(Event, payload) }`. Payload fields: literals, references, `ui.dom.value`,
132
135
  `ui.dom.form('name')`, `ui.dom.checked`, `ui.dom.valueAsNumber`, `ui.dom.key`.
133
- - `ui.each(list, 'id', (item) => node)` (key `null` for primitives).
134
136
  - Links: `ui.link(route, params, search)`, never a string path (HZ032). The third argument exists only when the
135
137
  route declares `search` (`null` = all defaults). Filters that belong in the URL are `search` links, not context.
136
138
  - A form whose submit reads only `ui.dom.form(...)`, literals, context, params and search also works without JS.
@@ -165,14 +167,9 @@ Every declaration goes in `declarations` once, under its name. Optional: `import
165
167
  `exports: [Event, query, …]` (all other features may use), `styles: [new URL('./x.css', import.meta.url)]`.
166
168
 
167
169
  ## hozu.config.ts
170
+ `project({ schema: zodAdapter, styles, site: { url, name, lang }, routes: { home, itemPage }, pages, features })`;
171
+ `hozu add feature --page` adds static pages. A page with params:
168
172
  ```ts
169
- export default project({
170
- schema: zodAdapter,
171
- styles: new URL('./app.css', import.meta.url),
172
- site: { url: 'http://localhost:3000', name: 'Items', lang: 'en' },
173
- routes: { home, itemPage },
174
- pages: [
175
- ui.page(home, { views: [Board], head: { render: () => ({ title: 'Items', description: 'All items.' }) } }),
176
173
  ui.page(itemPage, {
177
174
  views: [Detail],
178
175
  head: {
@@ -182,9 +179,6 @@ export default project({
182
179
  },
183
180
  entries: { query: listItems, input: {}, params: (item) => ({ id: item.id }) }, // sitemap
184
181
  }),
185
- ],
186
- features: [items],
187
- })
188
182
  ```
189
183
  ```ts
190
184
  // routes.ts
@@ -193,10 +187,6 @@ export const itemPage = route({ path: '/items/:id', params: z.object({ id: z.str
193
187
  ```
194
188
 
195
189
  ## server.ts
196
- ```ts
197
- export const createResolvers = () => resolvers(project, (implement) => [
198
- implement(getItem, ({ id }, { fail }) => items.find((i) => i.id === id) ?? fail('NotFound', { id })),
199
- implement(addItem, ({ title }, { fail }) => /* … */ fail('Duplicate', { title })), // → failed.Duplicate
200
- ])
201
- ```
202
- Input failing its schema returns the error `Invalid` (`{ message, fields }`; see `reference.md`).
190
+ `export const createResolvers = () => resolvers(project, (implement) => [...])`, one
191
+ `implement(getItem, ({ id }, { fail }) => item ?? fail('NotFound', { id }))` per query / mutation. `hozu add feature` puts a feature's resolvers in `features/<name>/server.ts`.
192
+ Input failing its schema returns `Invalid` (`{ message, fields }`; `reference.md`).
package/skill/changing.md CHANGED
@@ -1,40 +1,94 @@
1
1
  # Changing a Hozu app
2
2
 
3
- Keep the loop short: read once, edit everything, check once, verify once.
3
+ Keep the loop short: map once, edit everything, check once, verify once.
4
4
 
5
5
  ## 1. Read
6
6
  - The change request.
7
- - The app: `features/<name>/*.ts`, `server.ts`, `routes.ts`, `hozu.config.ts`. Below, *model* is where the
8
- app keeps schemas, events, effects and the machine (`model.ts` in the recommended layout), and *views* is
9
- where it keeps views, contracts and `feature()`.
10
- - Nothing else. The API is in `SKILL.md`; open `patterns.md` only for a pattern you have not seen in the app,
11
- and `reference.md` only for a topic it lists.
12
-
13
- ## 2. Where each kind of change goes
14
- | Change | Touch, in this order |
7
+ - `pnpm exec hozu map`: every route, query, mutation, event, state, view and contract, each with its `file:line`.
8
+ Open only the lines the change touches. Below, *model* is where the app keeps schemas, events, effects and
9
+ the machine (`model.ts`), and *views* where it keeps views, contracts and `feature()`.
10
+ - The API is in `SKILL.md`. Use a recipe below when one fits; open `patterns.md` / `reference.md` only for
11
+ something else.
12
+
13
+ ## 2. Recipes
14
+ Names follow `hozu add feature items`: `Item`, `NewItem`, `Add`, `addItem`, `itemsMachine`, `ItemsBoard`.
15
+
16
+ ### A field chosen in the add form (an enum)
17
+ - **model:**
18
+ - `export const Priority = z.enum(['low', 'normal', 'high'])`;
19
+ - add `priority: Priority` to `Item`, `NewItem` and the `Add` payload;
20
+ - context: `priority: Priority`, with `priority: 'normal'` in `initialContext`;
21
+ - `fields` gets `priority: z.string().nullable()`, with `priority: null` in `initialContext` and in the `Add`
22
+ assign that resets it;
23
+ - the `Add` assign also gets `op.set(ctx.priority, e.priority)`, and the add `invoke` input becomes
24
+ `{ title: ctx.draft, priority: ctx.priority }`.
25
+ - **views:**
26
+ - the form's submit sends `{ title: ui.dom.form('title'), priority: ui.dom.form('priority') }`;
27
+ - inside the form add
28
+ `ui.select({ name: 'priority', 'aria-label': 'Priority', class: 'rounded border px-2' }, ['low', 'normal', 'high'].map((p) => ui.option({ value: p, selected: p === 'normal' }, [p])))`;
29
+ - in the item: `ui.span({ class: 'text-xs' }, [item.priority])`.
30
+ - **Contracts:**
31
+ - add `priority: 'normal'` to every `Add` payload, to the add effect's input, and to the `done` result;
32
+ - `rejectsInvalid`'s `data.fields` and `changes.fields` get `priority: null`.
33
+ - **server:** store `priority` (seed items included) and return it.
34
+
35
+ ### An action button that works on many items (e.g. "Clear done")
36
+ - **model:**
37
+ - `export const ClearDone = event({ payload: z.object({}) })`;
38
+ - `export const clearDone = mutation({ input: z.object({}), output: z.object({ removed: z.number() }), invalidates: () => [itemsTag()] })`;
39
+ - in `idle`: `on(ClearDone, { target: 'clearing', assign: () => [op.set(ctx.error, null)] })`;
40
+ - a state
41
+ `clearing: { ignore: [...], invoke: invoke(clearDone, { input: {}, done: [{ target: 'idle' }], failed: { Unexpected: [{ target: 'idle', assign: (e) => [op.set(ctx.error, e.message)] }] } }) }`;
42
+ - add `ClearDone` to every busy state's `ignore`, and give `clearing` the same list.
43
+ - **views:** the control
44
+ `ui.form({ on: { submit: ui.send(ClearDone, {}) } }, [ui.button({ type: 'submit', class: 'text-sm underline' }, ['Clear done'])])`.
45
+ - **Contracts:**
46
+ - `given: { state: 'idle' }`, when `[{ send: ClearDone, payload: {} }, { done: clearDone, result: { removed: 1 } }]`,
47
+ expect `{ state: 'idle', effects: [{ effect: clearDone, input: {} }] }`;
48
+ - a second one for `failed … 'Unexpected'` from `clearing`;
49
+ - add `ClearDone`, `clearDone` and both contracts to `declarations`.
50
+ - **server:**
51
+ `implement(clearDone, () => { const before = items.length; items.splice(0, items.length, ...items.filter((i) => !i.done)); return { removed: before - items.length } })`.
52
+ - **Try it:** `hozu post / --button 'Clear done' --next /`.
53
+
54
+ ### A field shown on the detail page
55
+ In the detail view's `ready`: `ui.p({}, ['Priority: ', item.priority])`. The detail query already returns the whole
56
+ item.
57
+
58
+ ### A detail page, when the feature has none
59
+ Run a fresh scaffold into a scratch app with `--with detail`, and copy the parts it prints:
60
+ - the route with params;
61
+ - the `get` query and its resolver;
62
+ - the detail view;
63
+ - the link in the list;
64
+ - `ui.page(...)` with `head` and `entries`.
65
+
66
+ ### Other changes
67
+ | Change | Touch |
15
68
  |---|---|
16
- | New data field (e.g. `priority`) | model: the domain and input schemas → `server.ts` (seed data, store it) → views: show it, also in the detail view if there is one. If the user picks it in a form: a `<select name="…">` inside the form, sent with the submit as `ui.dom.form('…')` (HZ033 checks the options), plus the matching field in the event payload and the mutation input. |
17
- | New server action (e.g. "clear done") | model: a `mutation` with `invalidates`, an event, and `on(Event)` into a new busy state that `invoke`s the mutation, with `done` and every `failed` handled and the same `ignore` list as the other busy states → views: the control, the contracts, and both new declarations in `feature({ declarations })` → `server.ts`: `implement(...)` it. |
18
- | New UI-only state (a filter, a tab) | model: the context field, its initial value, an event and an `on` that `op.set`s it (add the event to every busy state's `ignore`) → views: the control, a contract, the event in `declarations`. |
19
- | New page | `routes.ts` (`params`, `search`) → a view with `route`, added to `declarations` → `ui.page(...)` in `hozu.config.ts` (with `head`, and `entries` when the route has params). |
20
- | New filter / sort / page number that should be in the URL | the route's `search` schema (with a default) → links with `ui.link(route, params, { key: value })` → read `search.key` in the view. No machine change. |
69
+ | New UI-only state (a tab) | model: the context field and its initial value, an event, an `on` that `op.set`s it (add the event to every busy state's `ignore`) → views: the control, a contract, the event in `declarations`. |
70
+ | Filter / sort / page in the URL | the route's `search` schema (with a default) → links with `ui.link(route, params, { key: value })` → read `search.key` in the view. No machine change. |
71
+ | New page | `routes.ts` → a view with `route`, in `declarations` → `ui.page(...)` in `hozu.config.ts` (`head`, and `entries` when the route has params). |
21
72
 
22
73
  Whenever the machine changes:
23
- - Add one contract per new transition; HZ016 prints each missing one ready to paste. A new context field needs
24
- no change to existing contracts: `given` defaults to the initial context and `changes` lists only what changes.
25
- - Every busy state `ignore`s every event its visible controls can send. HZ005 prints the missing `ignore` entries.
74
+ - Add one contract per new transition; HZ016 prints each missing one ready to paste.
75
+ - Every busy state `ignore`s every event its visible controls can send; HZ005 prints the missing entries.
26
76
 
27
77
  ## 3. Check (once, after all edits)
28
78
  ```
29
- pnpm exec tsc --noEmit -p . && pnpm exec hozu validate
79
+ pnpm exec hozu check
30
80
  ```
31
- Fix what they report. When the behaviour change is intended and everything is clean, run
32
- `pnpm exec hozu validate --update-lock`. HZ018 asks for this.
33
-
34
- ## 4. Verify (once)
35
- Start the server with `PORT=4700 node serve.ts & echo $!`, then use one curl script:
36
- - pages: `curl -s localhost:4700/…`;
37
- - mutations:
38
- `curl -s -X POST localhost:4700/_hozu/effect -H 'content-type: application/json' -d '{"effect":"<feature>.<mutation>","input":{…},"keys":[]}'`.
81
+ Fix what it reports. When the behaviour change is intended and everything is clean, run
82
+ `pnpm exec hozu check --update-lock`. HZ018 asks for this.
39
83
 
40
- Stop the server with `kill <pid>`, not `pkill -f` (that kills your own shell).
84
+ ## 4. Verify (once, no server needed)
85
+ - **Pages:** `pnpm exec hozu get / /items/i1` prints the status, title, alerts and visible text.
86
+ - **Attributes and forms:** `--select button` (or `'[role=alert]'`, `a[href]`, `#id`) prints elements with their
87
+ attributes, e.g. `aria-pressed`; `--forms` lists each form's fields and buttons. Never start a server for this.
88
+ - **Forms:** `pnpm exec hozu post / --field title=A --field priority=high --next /items` fills the form like a
89
+ browser (other fields keep their defaults). It follows the redirect, then runs the next steps in the same
90
+ process.
91
+ - **Chaining:** chain what must share data, e.g. `--next 'POST / title=a'` (fields as `a=1&b=2`) or
92
+ `--next /items/i3`.
93
+ - **A form with only a button:** `--button 'Clear done'`, or `--next 'POST / @Clear done'`. With one form per item,
94
+ `--field id=t2` picks the item's form.
package/skill/patterns.md CHANGED
@@ -1,6 +1,7 @@
1
1
  # Hozu patterns
2
2
 
3
- Patterns marked *(example)* are used in `example/`, next to this file.
3
+ Patterns marked *(example)* are used in `example/features/bookmarks/model.ts` and `views.ts`, next to this file;
4
+ read only the part you need.
4
5
 
5
6
  - **Form with a server-side error** *(example)*:
6
7
  - `ui.form({ on: { submit: ui.send(Add, { title: ui.dom.form('title') }) } }, [label, input, button])`.
@@ -51,6 +51,10 @@ Every mutation also has the framework error `Invalid` = `{ message, fields }`: o
51
51
  (see `patterns.md`).
52
52
 
53
53
  ## Sessions
54
+ - **Start from the scaffold:** `hozu add feature notes --page / --with auth` writes `features/account`
55
+ (sign-in page, sign-out, `me`), the session cookie in `serve.ts`, per-user resolvers, and a redirect to `/login`
56
+ when signed out. Replace the name-only sign-in with real credentials before production; set `SESSION_SECRET`
57
+ (and `SESSION_SECURE=true` behind HTTPS).
54
58
  - `project({ session: z.object({ user: z.string() }) })` declares the identity. Queries with `scope: 'user'` and
55
59
  mutations receive `session`; public resolvers never do.
56
60
  - `createServer({ session: (request) => value })`, or `sessionCookie({ name, secret })` from
@@ -122,7 +126,8 @@ shown when the network is down; a service worker is generated (HZ043: no params,
122
126
 
123
127
  ## Testing rendered pages
124
128
  `const app = testApp({ build, resolvers })` from `@hozu/testing`; `await app.get('/')` gives
125
- `{ status, headers, html, text, payload }`; `app.post(path, fields)` submits a native form.
129
+ `{ status, headers, html, text, payload }`; `app.post(path, fields)` submits a native form. In a browser test (Playwright),
130
+ wait for `html[data-hozu-ready]` before clicking: it is set when the page has hydrated.
126
131
 
127
132
  ## Deployment
128
133
  `hozu build` writes `dist/public/` (static files for any host or CDN) and `dist/manifest.json`. On Node:
@@ -7,14 +7,19 @@ A web app built with Hozu (`@hozu/*`). Hozu is not in your training data.
7
7
  - Changing existing code: read `__SKILL__/changing.md` first.
8
8
  - The files in `__SKILL__/` are the whole API. Do not read the framework source in `node_modules/@hozu`.
9
9
 
10
- ## Checks (run after every change)
10
+ ## The loop
11
11
  ```
12
- __RUN__ tsc --noEmit -p .
13
- __RUN__ hozu validate
14
- __RUN__ hozu validate --update-lock # only to accept a clean, intended behaviour change
12
+ __RUN__ hozu add feature tasks --page / --with detail,toggle,filter,remove # then edit the texts it lists
13
+ # add auth to the list for sign-in and per-user data
14
+ __RUN__ hozu map # outline of the app with file:line, before a change
15
+ __RUN__ hozu check # after every change: types, rules, contracts
16
+ __RUN__ hozu check --update-lock # only to accept a clean, intended behaviour change
17
+ __RUN__ hozu get / --select button --forms # try pages without a server: text, attributes, forms
18
+ __RUN__ hozu post / --field title=Ship --next / # submit a form like a browser
15
19
  ```
16
20
  __NOTE__
17
21
  ## Rules
22
+ - After `hozu add feature`, do not print the generated files: edit the texts it lists; `hozu map` shows the rest.
18
23
  - Apply the fix each diagnostic gives; do not work around a rule.
19
24
  - Every behaviour change comes with a contract change.
20
25
  - Do not edit `__SKILL__/`: `__RUN__ hozu skill` rewrites it for the installed Hozu version.