create-hozu 0.5.0 → 0.6.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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "create-hozu",
3
- "version": "0.5.0",
3
+ "version": "0.6.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
@@ -34,9 +34,10 @@ npx hozu add feature items --page / --with auth,detail,toggle,filter,remove
34
34
  npx hozu map # outline with file:line
35
35
  npx hozu get / --select button --forms # a page, no server needed
36
36
  npx hozu post / --field title=A --next / # a no-JS form post, cookies shown
37
+ npx hozu browse / --do 'fill Search=a' --do 'click Save' # real browser: errors, widgets, text
37
38
  npx hozu docs views # one topic
38
39
  ```
39
- `get` / `post` replace a running server for checks; `npm start` runs the app. Relative imports end in `.ts`.
40
+ `get` / `post` / `browse` replace a running server for checks; `npm start` runs the app. Relative imports end in `.ts`.
40
41
 
41
42
  ## A feature in one screen
42
43
  ```ts
@@ -15,7 +15,7 @@ export const addItem = mutation({
15
15
  errors: { Duplicate: z.object({ title: z.string() }) }, // optional: declared failures
16
16
  invalidates: () => [itemsTag()], // refreshes queries with these tags
17
17
  })
18
- export const visible = fn({ // computation: pure JS, self-contained (no imports, no closures)
18
+ export const visible = fn({ // computation: pure JS, self-contained (no imports, no helpers outside impl: HZ047)
19
19
  input: z.object({ items: z.array(Item), show: Show }), output: z.array(Item),
20
20
  impl: ({ items, show }) => items.filter((i) => show === 'all' || !i.done),
21
21
  })
@@ -39,4 +39,5 @@ around the rule.
39
39
  | HZ044 | a feature file was loaded without the Hozu transform | run node with `--import @hozu/transform/register` (`npm start` does), or add `hozuTransform()` to Vite / Vitest |
40
40
  | HZ045 | `serve.ts` misses the widget bundle or the session store | add `widgets: await bundleWidgets(build)` / `session: sessionCookie(…)` |
41
41
  | HZ046 | an endpoint path is reserved, has params, or collides with a page, redirect or endpoint | use a static path such as `/api/…` (patch) |
42
+ | HZ047 | a `fn` body uses a helper or constant defined outside `impl` (it is sent to the browser as source) | write the helper inside `impl`, or pass the value as input |
42
43
  | HZ042 | `site.locales` empty / missing `site.lang` / not a canonical tag, or `ui.alternate` of an undeclared locale | fix the list (`'zh-TW'`, not `'zh_tw'`) |
@@ -6,6 +6,15 @@
6
6
  - Each step prints its status, redirect and `set-cookie` attributes (`HttpOnly`, `SameSite`); the session cookie
7
7
  is kept across `--next` steps. Two users: run two commands.
8
8
  - Endpoints: `hozu get '/api/items?x=1'`.
9
+ - **In a real browser, still without a server:** `hozu browse / --do 'fill Search=park' --do 'click Tech Park'`.
10
+ - It uses the installed Chrome / Chromium / Edge (`HOZU_CHROME=/path` to choose), loads the page, waits for
11
+ hydration and runs the steps in order: `fill <label>=<value>`, `select <label>=<option>`, `check <label>`,
12
+ `click <name>`, `press <key>`, `wait <ms>`, `goto <path>`. Labels and names are what a user reads (aria-label,
13
+ `<label>`, placeholder, button text, `title`).
14
+ - It prints the uncaught exceptions, `console.error`s and failed requests, every widget on the page (mounted,
15
+ failed, size, canvases), the visible text and `--select <css>` elements; exit code 1 when anything failed.
16
+ - `--screenshot shot.png` saves the viewport (open it to look); `--reduced-motion` emulates reduced motion.
17
+ - Use it once after client-side work (widgets, islands); `get` / `post` stay the fast checks.
9
18
  - In code: `const app = testApp({ build, resolvers })` from `@hozu/testing`; `await app.get('/')` →
10
19
  `{ status, headers, html, text, payload }`; `app.post(path, fields)` submits a native form.
11
20
  - Vitest: add `hozuTransform()` from `@hozu/transform/vite` to `plugins`.
@@ -23,3 +23,6 @@ export default implement<typeof Map>(({ el, props, emit, signal }) => {
23
23
  - `serve.ts` passes `widgets: await bundleWidgets(build)` (the server refuses to start without it; `hozu build` bundles
24
24
  them itself). A library's CSS goes in `app.css` (`@import "leaflet/dist/leaflet.css";`); a map or chart host needs a
25
25
  height class.
26
+ - Check it with `hozu browse /` (no server): each widget is listed as mounted / failed / not mounted with its size
27
+ and canvases, next to any error it threw. A mounted host carries `data-hozu-widget="<feature>.<Name>"` and
28
+ `data-hozu-widget-state="mounted"` for your own browser tests.
@@ -16,6 +16,7 @@ __RUN__ hozu check # after every change: types, rules, c
16
16
  __RUN__ hozu check --update-lock # only to accept a clean, intended behaviour change
17
17
  __RUN__ hozu get / --select button --forms # try pages without a server: text, attributes, forms
18
18
  __RUN__ hozu post / --field title=Ship --next / # submit a form like a browser
19
+ __RUN__ hozu browse / --do 'click Save' # real browser, no server: errors, widgets, text after steps
19
20
  ```
20
21
  __NOTE__
21
22
  ## Rules