@imfusion/web-ui 0.6.1-dev.9.g317bd6f2 → 0.6.2-dev.1.gf73fc5d3

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 (63) hide show
  1. package/LICENSE.txt +30 -0
  2. package/README.md +99 -173
  3. package/THIRD_PARTY_NOTICES.md +34 -0
  4. package/bin/install.js +28 -10
  5. package/dist/code-BFMQnmu9.js +147 -0
  6. package/dist/codegen/gen-code-highlight-theme.d.ts +1 -0
  7. package/dist/components/code/code.d.ts +5 -4
  8. package/dist/components/stack/stack.d.ts +1 -1
  9. package/dist/components/toast/index.d.ts +2 -0
  10. package/dist/components/toast/toast.d.ts +200 -0
  11. package/dist/components/toast/toast.meta.d.ts +2 -0
  12. package/dist/components/typo/typo.d.ts +23 -22
  13. package/dist/icons/icon-config.d.ts +12 -0
  14. package/dist/{icons-wBmF0U2x.js → icons-Cy1HAosO.js} +1 -1
  15. package/dist/icons.js +1 -1
  16. package/dist/index.d.ts +1 -0
  17. package/dist/index.js +1278 -1069
  18. package/dist/integrations/code-highlight/highlighter.d.ts +24 -0
  19. package/dist/integrations/code-highlight.js +80 -47
  20. package/dist/integrations/image-display-options.js +2 -2
  21. package/dist/provider/web-ui-provider.d.ts +3 -3
  22. package/dist/style.css +1 -1
  23. package/dist/{tabs-CMKvMF4E.js → tabs-DIe1Utiy.js} +2 -0
  24. package/docs/assets/imfusion-banner.svg +16 -0
  25. package/package.json +10 -8
  26. package/src/docgen/doc.gen.json +515 -1
  27. package/src/llms/install-templates/AGENTS.md +15 -18
  28. package/src/llms/llms.gen.txt +39 -33
  29. package/src/llms/skills/imf-web-ui/SKILL.md +30 -39
  30. package/src/llms/skills/imf-web-ui-audit/SKILL.md +50 -102
  31. package/src/llms/skills/imf-web-ui-components/SKILL.md +47 -104
  32. package/src/llms/skills/imf-web-ui-conventions/SKILL.md +44 -52
  33. package/src/llms/skills/imf-web-ui-conventions/templates/AUDIT_CHECKLIST.md +1 -0
  34. package/src/llms/skills/imf-web-ui-conventions/topics/agent-tooling.md +40 -62
  35. package/src/llms/skills/imf-web-ui-conventions/topics/assets.md +11 -12
  36. package/src/llms/skills/imf-web-ui-conventions/topics/authentication.md +31 -46
  37. package/src/llms/skills/imf-web-ui-conventions/topics/class-names.md +18 -23
  38. package/src/llms/skills/imf-web-ui-conventions/topics/components.md +20 -69
  39. package/src/llms/skills/imf-web-ui-conventions/topics/data.md +50 -146
  40. package/src/llms/skills/imf-web-ui-conventions/topics/docs-structure.md +17 -23
  41. package/src/llms/skills/imf-web-ui-conventions/topics/git.md +15 -20
  42. package/src/llms/skills/imf-web-ui-conventions/topics/library-boundary.md +28 -19
  43. package/src/llms/skills/imf-web-ui-conventions/topics/library-setup.md +20 -16
  44. package/src/llms/skills/imf-web-ui-conventions/topics/npm-project.md +28 -42
  45. package/src/llms/skills/imf-web-ui-conventions/topics/project-structure.md +28 -30
  46. package/src/llms/skills/imf-web-ui-conventions/topics/react.md +28 -74
  47. package/src/llms/skills/imf-web-ui-conventions/topics/styling.md +65 -62
  48. package/src/llms/skills/imf-web-ui-conventions/topics/testing.md +12 -14
  49. package/src/llms/skills/imf-web-ui-conventions/topics/tokens.md +9 -4
  50. package/src/llms/skills/imf-web-ui-conventions/topics/tooling.md +40 -68
  51. package/src/llms/skills/imf-web-ui-conventions/topics/typescript.md +26 -50
  52. package/src/llms/skills/imf-web-ui-conventions/topics/validation.md +19 -25
  53. package/src/llms/skills/imf-web-ui-setup/SKILL.md +45 -64
  54. package/src/llms/skills/imf-web-ui-update/SKILL.md +48 -114
  55. package/src/llms/skills/imf-web-ui-ux/SKILL.md +64 -92
  56. package/src/llms/skills/imf-web-ui-ux/references/forms.md +16 -36
  57. package/src/llms/skills/imf-web-ui-ux/references/usability-heuristics.md +14 -27
  58. package/src/llms/skills/imf-web-ui-ux/references/visual-design.md +22 -38
  59. package/src/llms/tokens.gen.json +5 -5
  60. package/bin/install.test.ts +0 -329
  61. package/dist/code-Blo48PGr.js +0 -136
  62. package/dist/icons/icon-config-provider.d.ts +0 -8
  63. package/dist/icons/icon-context.d.ts +0 -4
@@ -1,113 +1,62 @@
1
1
  ---
2
2
  name: imf-web-ui-components
3
3
  description:
4
- "Look up @imfusion/web-ui component APIs and icon glyphs without reading source. Load when you need a component's props,
5
- sub-components, defaults, or a supplied icon — not for choosing between components (imf-web-ui-ux) or first-time setup
6
- (imf-web-ui-setup library-setup)."
4
+ "Look up @imfusion/web-ui component APIs, compound parts, defaults, and icon glyphs without reading source. Use this
5
+ whenever a consumer task names a Web UI component or icon and you need to choose a prop, part, default, or glyph. Do not
6
+ use it to choose between components or bootstrap a project."
7
7
  allowed-tools: Bash
8
8
  ---
9
9
 
10
- # imf-web-ui-components
10
+ # Look up components
11
11
 
12
- `@imfusion/web-ui` ships two generated files inside `node_modules` so an agent can discover and use its components without
13
- reading source or checking out the library's repo:
12
+ Use the generated package indexes. They are smaller and more reliable than reading the library source.
14
13
 
15
- - **`node_modules/@imfusion/web-ui/src/llms/llms.gen.txt`** — an identity index: every component's name, category, status,
16
- and a one-sentence description of what it's for and what else it's called.
17
- - **`node_modules/@imfusion/web-ui/src/docgen/doc.gen.json`** — full prop tables (name, type, default, description) for every
18
- component, keyed by kebab-case folder name.
19
- - **`node_modules/@imfusion/web-ui/src/llms/icon-catalog.gen.json`** — searchable icon names, styles, categories, and tags.
20
- Read it only when the task needs an icon.
14
+ ## Component lookup
21
15
 
22
- Neither file is reachable through the package's pretty import paths (`@imfusion/web-ui/llms.txt`,
23
- `@imfusion/web-ui/docgen.json`) — those are Node module-resolution aliases, meaningless to `cat`/`jq`/`grep` reading files
24
- off disk. Use the `node_modules/...` paths above directly.
16
+ 1. Read the identity index:
25
17
 
26
- ## The lookup, in two hops
18
+ ```sh
19
+ cat node_modules/@imfusion/web-ui/src/llms/llms.gen.txt
20
+ ```
27
21
 
28
- **Hop 1 — find the component.** Read the whole index; it's small (~13KB for the full library) and safe to load in full:
22
+ It lists each component's name, category, status, purpose, and docgen entry.
29
23
 
30
- ```sh
31
- cat node_modules/@imfusion/web-ui/src/llms/llms.gen.txt
32
- ```
24
+ 2. Read only the matching entry from docgen:
33
25
 
34
- Each entry looks like this:
26
+ ```sh
27
+ jq '.button' node_modules/@imfusion/web-ui/src/docgen/doc.gen.json
28
+ ```
35
29
 
36
- ```
37
- ## Button
38
- - category: Buttons, status: stable
39
- Triggers an action — submit, confirm, cancel, navigate, or destructive operations. Six semantic variants ...
40
- - props: node_modules/@imfusion/web-ui/src/docgen/doc.gen.json -> .button (jq: jq '.button' node_modules/@imfusion/web-ui/src/docgen/doc.gen.json)
41
- - further reading (usage/anatomy, not props): https://base-ui.com/react/components/button.md
42
- ```
30
+ Replace `.button` with the kebab-case key from the identity index. The result contains `root` and `subComponents`, with
31
+ each prop's type, default, and description.
43
32
 
44
- **Hop 2 — pull that component's props.** Don't read the whole docgen file (~500KB across all components) — slice out just the
45
- one entry with the exact command the index gave you:
33
+ If `jq` is unavailable, use Node without loading the whole file into the conversation:
46
34
 
47
- ```sh
48
- jq '.button' node_modules/@imfusion/web-ui/src/docgen/doc.gen.json
49
- ```
50
-
51
- That returns `{ root: { name, description, props: [...] }, subComponents: [...] }`. `root` is the primary export (`Button`);
52
- `subComponents` holds compound parts (e.g. `Drawer.Root`, `Drawer.Trigger`, `Drawer.Content` all live under the `drawer`
53
- key). Match the sub-component you need by its dotted `name`.
54
-
55
- **`jq` may not be installed.** Check with `which jq` before relying on it. If it's missing, do **not** fall back to reading
56
- the whole `doc.gen.json` file — that defeats the entire point of the two-hop design (~500KB across all components vs. one
57
- ~9KB entry) and will burn your context budget for no reason. Use whatever's actually available instead:
58
-
59
- ```sh
60
- node -e "console.log(JSON.stringify(JSON.parse(require('fs').readFileSync('node_modules/@imfusion/web-ui/src/docgen/doc.gen.json','utf8')).button, null, 2))"
61
- ```
35
+ ```sh
36
+ node -e "console.log(JSON.stringify(JSON.parse(require('fs').readFileSync('node_modules/@imfusion/web-ui/src/docgen/doc.gen.json','utf8')).button, null, 2))"
37
+ ```
62
38
 
63
- (Node ships everywhere this package can be installed, so this always works as a fallback.) Or ask the user to install `jq` if
64
- you expect to look up several components in one session.
39
+ Use `doc.gen.json` for Web UI props. A linked upstream page is useful for behavior, composition, and accessibility, but its
40
+ prop table is not authoritative for this package.
65
41
 
66
- **"Further reading" links, if present, are not a props source.** They point at the upstream library's (usually Base UI's) own
67
- documentation for composition, anatomy, keyboard/focus behavior, and accessibility notes docgen can't express. Props always
68
- come from `doc.gen.json` — never treat the linked page's prop table as authoritative for a web-ui component; web-ui may add,
69
- remove, or default differently.
42
+ ## If the component is missing
70
43
 
71
- ## A component not found in the index?
72
-
73
- The index is regenerated on every `@imfusion/web-ui` release; it should be exhaustive. If a component you expect is missing,
74
- don't guess at an API — that's a real gap to report, not something to work around by inventing props. Tell the web-ui
75
- maintainer, or file it in the [WEBSDK Jira project](https://imfusion.atlassian.net/browse/WEBSDK) if you have access. If the
76
- gap is about _which_ component to use rather than a missing one, that's a design question: open `imf-web-ui-ux`.
44
+ Treat a missing identity-index entry as a real gap. Do not invent an API or silently import the upstream component. Report
45
+ the gap to the Web UI maintainer. If the question is which existing component fits, use `imf-web-ui-ux` instead.
77
46
 
78
47
  ## Icons
79
48
 
80
- When the task mentions an icon, glyph, symbol, or `@imfusion/web-ui/icons`, query the icon catalog before choosing a name. Do
81
- not load it for ordinary component work.
82
-
83
- Search one relevant term at a time, then read only the matching records:
49
+ When the task needs an icon, search the generated catalog before choosing a name:
84
50
 
85
51
  ```sh
86
52
  node -e '
87
53
  const q = process.argv[1].toLowerCase();
88
- const icons = JSON.parse(
89
- require("fs").readFileSync(
90
- "node_modules/@imfusion/web-ui/src/llms/icon-catalog.gen.json",
91
- "utf8"
92
- )
93
- );
94
- console.log(
95
- JSON.stringify(
96
- icons
97
- .filter(icon => [icon.name, icon.category, ...icon.tags]
98
- .join(" ")
99
- .toLowerCase()
100
- .includes(q))
101
- .slice(0, 20),
102
- null,
103
- 2
104
- )
105
- );
54
+ const icons = JSON.parse(require("fs").readFileSync("node_modules/@imfusion/web-ui/src/llms/icon-catalog.gen.json", "utf8"));
55
+ console.log(JSON.stringify(icons.filter(icon => [icon.name, icon.category, ...icon.tags].join(" ").toLowerCase().includes(q)).slice(0, 20), null, 2));
106
56
  ' "add"
107
57
  ```
108
58
 
109
- Import the chosen glyph and `Icon` from `@imfusion/web-ui/icons`. Render it through `Icon`, including when it inherits the
110
- surrounding color:
59
+ Import the glyph and `Icon` from the Web UI icons entry. Always render the glyph through `Icon`:
111
60
 
112
61
  ```tsx
113
62
  import { ArrowRight, Icon } from "@imfusion/web-ui/icons";
@@ -115,39 +64,33 @@ import { ArrowRight, Icon } from "@imfusion/web-ui/icons";
115
64
  <Icon glyph={ArrowRight} aria-hidden />;
116
65
  ```
117
66
 
118
- Use `Icon` for every rendered icon. Pass the component reference, not a rendered element:
67
+ Do not import `iconoir-react` or another icon package directly.
119
68
 
120
- ```tsx
121
- import { ArrowRight, Icon } from "@imfusion/web-ui/icons";
69
+ ## Compound components
122
70
 
123
- <Icon glyph={ArrowRight} size={16} variant="primary" aria-label="Continue" role="img" />;
124
- ```
71
+ A non-empty `subComponents` array means the component is a namespace:
125
72
 
126
- Never import `iconoir-react` or another icon package directly.
73
+ ```tsx
74
+ import { Drawer } from "@imfusion/web-ui";
127
75
 
128
- ## Compound components
76
+ <Drawer.Root>
77
+ <Drawer.Trigger>Open</Drawer.Trigger>
78
+ <Drawer.Content>…</Drawer.Content>
79
+ </Drawer.Root>;
80
+ ```
129
81
 
130
- A component whose docgen entry has a non-empty `subComponents` array is used as a namespace, not a single import — e.g.
131
- `import { Drawer } from "@imfusion/web-ui"` then `<Drawer.Root>`, `<Drawer.Trigger>`, `<Drawer.Content>`. The index's
132
- category/description covers the whole family; look at `subComponents` in the docgen entry to see which parts exist and what
133
- each one's own props are.
82
+ Use the identity index for the family description and the docgen entry for each part's props.
134
83
 
135
- ## Integrations (own-entry components)
84
+ ## Integrations
136
85
 
137
- A description mentioning "Imported from `@imfusion/web-ui/integrations/<name>`" is a signal this component isn't in the
138
- default import — e.g.:
86
+ A component whose identity entry says it comes from `@imfusion/web-ui/integrations/*` is not in the main import. Install the
87
+ listed optional peer explicitly, then import from that path:
139
88
 
140
89
  ```tsx
141
90
  import { Code } from "@imfusion/web-ui/integrations/code-highlight";
142
91
  ```
143
92
 
144
- These exist because their behavior depends on an optional peer dependency (e.g. `@tanstack/highlight` for `CodeHighlight`)
145
- that most consumers shouldn't be forced to install. Check the component's description for which peer to add, and add it
146
- explicitly to your own `package.json` — web-ui does not install it for you.
147
-
148
- ## Data grids (Table + a headless library)
93
+ ## Data grids
149
94
 
150
- For a data grid, drive the styled `Table` parts with a headless table library you install yourself. **TanStack Table**
151
- (`@tanstack/react-table`) is recommended. Map your `useReactTable` instance onto `Table.Root` / `Table.Header` / `Table.Row`
152
- / `Table.Cell`, and use `Table.SortableHeaderCell` for sortable columns — it carries the `aria-sort` state and the sort
153
- indicator. See the Table primitive's Storybook docs for the pairing.
95
+ `Table` supplies styled table parts, not sorting or pagination. Pair them with a headless table library installed by the
96
+ consumer. TanStack Table is the recommended choice. Use `Table.SortableHeaderCell` for sortable columns.
@@ -1,57 +1,49 @@
1
1
  ---
2
2
  name: imf-web-ui-conventions
3
3
  description:
4
- "The ImFusion frontend conventions baseline — in-house conventions, valid in every ImFusion frontend and usable by anyone
5
- who likes them. A router over topic references: library setup, library boundary, React, components, TypeScript, styling,
6
- tokens, validation, data layer, authentication, project structure, testing, tooling, npm project, git, agent tooling,
7
- assets, and docs structure. Load when writing wrapper components, custom UI, styling beyond the defaults, validating
8
- external data, adding new files to a consumer app, writing repo docs, touching tool config, choosing any dependency, or
9
- installing the vendored skills and lifecycle hooks."
4
+ "Apply the ImFusion frontend conventions to consumer code. Use this whenever a task writes a wrapper or custom UI, CSS,
5
+ TypeScript, data fetching, validation, tests, project files, configuration, documentation, dependencies, or agent tooling
6
+ in a project that uses @imfusion/web-ui. Read only the topic references that match the task."
10
7
  ---
11
8
 
12
- # imf-web-ui-conventions
13
-
14
- The ImFusion frontend baseline. In-house conventions, not industry claims — they encode how ImFusion frontends are built, and
15
- anyone else is welcome to them.
16
-
17
- **The project wins.** These defaults fill vacuums: if the host project already has a convention — a styling system, a state
18
- library, a folder shape — that stands. They are not a license to refactor a consumer codebase toward this document.
19
-
20
- When a project has an established convention, it wins. The audit skill records a working difference as a deviation; the setup
21
- skill proposes only the changes the project asks it to make.
22
-
23
- ## The topics
24
-
25
- Each topic lives in one reference. Read the one whose moment you're in; starting a new feature usually wants several.
26
-
27
- | Reference | Covers | Read when |
28
- | --------------------------------------------------- | ------------------------------------------------------------------- | ------------------------------------------------------- |
29
- | [library-setup.md](topics/library-setup.md) | styles import, `WebUIProvider`, and broken library wiring | installing or repairing library wiring |
30
- | [library-boundary.md](topics/library-boundary.md) | staying behind `@imfusion/web-ui`, wrappers, type derivation, peers | touching anything that renders library components |
31
- | [authentication.md](topics/authentication.md) | current-user source, public/app guards, login and logout | setting up or reviewing route protection |
32
- | [react.md](topics/react.md) | component roles, state kinds and owners, effects discipline | writing new screens, components, or wrappers |
33
- | [components.md](topics/components.md) | component anatomy on disk: grouping, folders, colocation | adding a component file |
34
- | [typescript.md](topics/typescript.md) | functional style, types, naming | writing any code |
35
- | [styling.md](topics/styling.md) | native CSS Modules, tokens, the override contract | writing CSS or styling beyond the defaults |
36
- | [tokens.md](topics/tokens.md) | shipped CSS-variable names grouped by family | choosing a design token |
37
- | [class-names.md](topics/class-names.md) | CVA variants, `cx`, merging the incoming `className` | writing a component with variants or a `className` prop |
38
- | [validation.md](topics/validation.md) | runtime schemas, boundary parsing, schema-derived types | accepting data the frontend does not own |
39
- | [data.md](topics/data.md) | `api/`+`http/` shape, query/mutation patterns and invalidation | adding an API topic, a fetch, or a mutation |
40
- | [project-structure.md](topics/project-structure.md) | the `src/` tree, route groups, file naming, imports | adding files rather than editing existing ones |
41
- | [testing.md](topics/testing.md) | what's worth testing and what isn't | writing or reviewing tests |
42
- | [tooling.md](topics/tooling.md) | the topic→tool map, tool configuration, and verification | choosing a dependency or touching tool config |
43
- | [npm-project.md](topics/npm-project.md) | `package.json`, the `verify:*` script set, dependency pinning | running or adding a script, adding a dependency |
44
- | [git.md](topics/git.md) | `git:config`, verify scopes, staleness at commit time | wiring hooks or the commit path |
45
- | [agent-tooling.md](topics/agent-tooling.md) | vendored skills, lifecycle hooks, registrations, Codex trust | installing or reviewing the shipped agent tooling |
46
- | [assets.md](topics/assets.md) | image formats, the WebP recipe | adding images or other static assets |
47
- | [docs-structure.md](topics/docs-structure.md) | what a repo documents, where, how it's written | writing or restructuring repo docs |
48
-
49
- ## Topic format
50
-
51
- Topics are manifests, not essays: `##` sections group rule bullets, and each section is one auditable unit. A rule is one
52
- imperative bullet; only a pushback-prone rule carries a one-line why. Snippets illustrate rules, prose never replaces them.
53
- Each topic's `##` sections map 1:1 to its block in [templates/AUDIT_CHECKLIST.md](templates/AUDIT_CHECKLIST.md) — add,
54
- remove, or rename a section and the checklist follows in the same change.
55
-
56
- `imf-web-ui-setup` proposes approved bootstrap changes, while `imf-web-ui-audit` reports the current state against this
57
- baseline.
9
+ # Frontend conventions
10
+
11
+ These are ImFusion defaults, not claims about every frontend. A host project's working choice wins. Use these topics to fill
12
+ a gap or to make a deliberate deviation visible; do not refactor a project just to match the baseline.
13
+
14
+ ## Choose a topic
15
+
16
+ | Topic | Read when |
17
+ | ------------------------------------------------ | --------------------------------------------------------------- |
18
+ | [library-setup](topics/library-setup.md) | Installing or repairing stylesheet and provider wiring. |
19
+ | [library-boundary](topics/library-boundary.md) | Rendering Web UI components, wrapping them, or choosing a peer. |
20
+ | [authentication](topics/authentication.md) | Protecting routes or defining login and logout. |
21
+ | [react](topics/react.md) | Designing component roles, state ownership, or effects. |
22
+ | [components](topics/components.md) | Adding files or deciding component anatomy. |
23
+ | [typescript](topics/typescript.md) | Writing TypeScript or naming values. |
24
+ | [styling](topics/styling.md) | Writing CSS or customizing Web UI. |
25
+ | [tokens](topics/tokens.md) | Choosing an exact token name. |
26
+ | [class-names](topics/class-names.md) | Mapping variants and `className` to CSS. |
27
+ | [validation](topics/validation.md) | Accepting data from outside the frontend. |
28
+ | [data](topics/data.md) | Adding API queries, mutations, or invalidation. |
29
+ | [project-structure](topics/project-structure.md) | Adding files or routes. |
30
+ | [testing](topics/testing.md) | Deciding what to test. |
31
+ | [tooling](topics/tooling.md) | Adding a dependency or configuring a tool. |
32
+ | [npm-project](topics/npm-project.md) | Changing `package.json`, scripts, pins, or Node. |
33
+ | [git](topics/git.md) | Configuring hooks or choosing verification scope. |
34
+ | [agent-tooling](topics/agent-tooling.md) | Installing skills or lifecycle hooks. |
35
+ | [assets](topics/assets.md) | Adding images, icons, or other static files. |
36
+ | [docs-structure](topics/docs-structure.md) | Writing or reorganizing repository docs. |
37
+
38
+ ## How to use the topics
39
+
40
+ Read the relevant file instead of loading the whole set. Each topic is a short checklist: follow its rules, use its examples
41
+ as patterns, and keep any exception explicit in the host project.
42
+
43
+ `imf-web-ui-setup` uses these topics to plan approved project changes. `imf-web-ui-audit` uses them to report the current
44
+ state without changing files.
45
+
46
+ ## Documentation
47
+
48
+ Invoke `/documentation-writer` for new or updated documentation. Use the `docs-structure` topic for repository-specific
49
+ boundaries and conventions; it supplies context for the writer and does not replace the writer's workflow.
@@ -58,6 +58,7 @@ sections one to one — change a topic's sections and this file follows in the s
58
58
  - [ ] Build custom UI from tokens
59
59
  - [ ] Override through the sanctioned seams
60
60
  - [ ] The color system
61
+ - [ ] Browser floor
61
62
  - [ ] Responsive styling
62
63
 
63
64
  ## Tokens — `tokens`
@@ -1,82 +1,60 @@
1
1
  # Agent tooling
2
2
 
3
- How a consumer repo carries the `@imfusion/web-ui` agent tooling; `npx web-ui-install` does the mechanics, this topic carries
4
- the judgment.
3
+ `npx web-ui-install` manages the Web UI skills and optional lifecycle hooks in a consumer project. This topic explains the
4
+ choices around that installer.
5
5
 
6
6
  ## The skill bundle
7
7
 
8
- - `npx web-ui-install` installs or refreshes the vendored `imf-web-ui-*` skills, refreshes the
9
- `<!-- imf-web-ui:begin/end -->` fence in an existing `AGENTS.md`, and removes skills dropped from the bundle.
10
- - Target: remembered first-run choice — `.claude/skills/`, vendor-neutral `.agents/skills/`, or both (`.agents/` real copy,
11
- `.claude/` symlink); `--reconfigure` re-opens it, `--target claude|agents` selects non-interactively.
12
- - Staleness: per-skill `.imf-web-ui-skill-version.json`; a marker older than the installed package means re-run the binary —
13
- never hand-diff or hand-edit vendored skill contents.
8
+ Run:
9
+
10
+ ```sh
11
+ npx web-ui-install
12
+ ```
13
+
14
+ It installs or refreshes the `imf-web-ui-*` skills, updates the managed `AGENTS.md` fence, and removes skills that the
15
+ package no longer ships. The installer remembers `.claude/skills/`, `.agents/skills/`, or both. Use `--target claude|agents`
16
+ to choose explicitly and `--reconfigure` to choose again.
17
+
18
+ Skill version markers (`.imf-web-ui-skill-version.json`) show which package version installed each skill. Refresh them with
19
+ the installer; do not hand-edit the vendored files.
14
20
 
15
21
  ## The hooks
16
22
 
17
- - `npx web-ui-install --hooks` adds three injection hooks and a turn-end gate.
18
- - Scripts in `.agents/hooks/imf-web-ui/` are installer-owned: refreshed wholesale each run, retired scripts pruned with their
19
- registrations.
20
- - Registrations merge idempotently into `.claude/settings.json` (Claude Code) and `.codex/hooks.json` (Codex), never touching
21
- entries the installer didn't write.
22
-
23
- - **SessionStart** — once per session: points the agent at the `imf-web-ui` skills router.
24
- - **SubagentStart** — the same line, byte for byte, for each spawned subagent; subagents don't reliably inherit the parent
25
- session's context.
26
- - **UserPromptSubmit** — one line per prompt naming the companion skills to consult.
27
- - **Stop** — the verify gate: when the turn edited source files, it blocks the agent from finishing once, with the
28
- instruction to run the project's verification and fix what it reports. Re-entry is detected from the payload, so the gate
29
- can never loop; a turn that edited nothing passes untouched.
30
-
31
- ```mermaid
32
- flowchart LR
33
- SS(["SessionStart<br/>once per session"]) --> ss["session-start.sh"]
34
- SA(["SubagentStart<br/>per spawned subagent"]) --> sa["subagent-start.sh"]
35
- UP(["UserPromptSubmit<br/>every prompt"]) --> up["user-prompt-submit.sh"]
36
- ST(["Stop<br/>turn ends after edits"]) --> st["stop.sh"]
37
- ss --> router["injects the router pointer:<br/>start at imf-web-ui"]
38
- sa --> router
39
- up --> hints["injects the per-task hints:<br/>components · conventions · ux"]
40
- st --> gate["blocks once:<br/>run verification first"]
41
- router --> agent["agent routes to the right<br/>companion skill"]
42
- hints --> agent
43
- gate --> agent2["agent verifies,<br/>then finishes"]
23
+ Install the optional lifecycle hooks with:
24
+
25
+ ```sh
26
+ npx web-ui-install --hooks
44
27
  ```
45
28
 
46
- - Each injection hook echoes one fixed line and exits 0; the router does the task-sorting a shell script can't — why a hint
47
- on every prompt isn't noise.
48
- - `baseline-staleness.sh` ships alongside but is not an agent hook; the repo's pre-commit calls it ([git.md](./git.md),
49
- staleness at commit time).
50
- - Never edit an installed script — the next install overwrites it; adapt in the repo's own hooks.
51
- - Registration entries are yours: the installer matches by script name and keeps edited commands across re-runs. Monorepo:
52
- the Codex commands anchor at `$(git rev-parse --show-toplevel)` — adjust their paths once after installing when the
53
- frontend isn't the git toplevel.
54
- - **Read the registration files before installing**; per event: nothing registered → install as shipped; already covered by
55
- the repo (its own session reminder, say) → don't stack a second hook — fold the missing line into the repo's script, or
56
- adapt the shipped one and register that; surface it and let the human pick.
29
+ The installer owns the scripts under `.agents/hooks/imf-web-ui/` and merges its registrations into Claude Code and Codex
30
+ settings. It refreshes scripts and removes retired registrations without replacing unrelated entries.
31
+
32
+ The shipped events are:
33
+
34
+ - `SessionStart`: point the agent at the Web UI router once per session.
35
+ - `SubagentStart`: provide the same pointer to spawned agents.
36
+ - `UserPromptSubmit`: name the companion skills relevant to the prompt.
37
+ - `Stop`: ask for project verification after a turn edits source files.
38
+
39
+ Read existing registrations first. If the project already covers an event, do not stack a second hook; adapt the existing
40
+ registration and keep the missing behavior.
41
+
42
+ `baseline-staleness.sh` is a pre-commit check, not an agent hook. It compares installed skill markers with the installed
43
+ package version.
57
44
 
58
45
  ## Codex trust
59
46
 
60
- - Codex runs a project's hooks only when two trust gates hold: the project itself is trusted, and each hook script has been
61
- trusted via the `/hooks` review, which keys trust to the script's hash.
62
- - Until then hooks are skipped, and skipped silently — from outside, a skipped hook and a hook that ran and said nothing look
63
- identical.
64
- - After installing or updating hooks, tell the user to trust the project and review `/hooks` in Codex, and again after any
65
- hook script changes.
66
- - When a hint doesn't show up, check trust before debugging the script.
67
- - Claude Code has no trust gate for project hooks.
47
+ Codex runs project hooks only after the project is trusted and each script is approved through `/hooks`. Revisit that review
48
+ after a hook script changes. Claude Code has no equivalent project-hook trust gate.
68
49
 
69
50
  ## Dependency-shipped skills
70
51
 
71
- - npm packages can ship Agent Skills of their own; TanStack does — [tooling.md](./tooling.md) covers TanStack Intent and its
72
- allowlist.
52
+ Dependencies can ship their own skills. TanStack is one example; its docs and allowlist determine how it is used.
73
53
 
74
54
  ## Hook docs
75
55
 
76
- Both hosts move fast; read the current references before adapting or adding a hook — payloads and stdout rules differ per
77
- host and per event.
56
+ Read the current host documentation before adding or adapting a hook:
78
57
 
79
- - [Claude Code: hooks reference](https://code.claude.com/docs/en/hooks) — event list, JSON input and output, exit codes,
80
- `disableAllHooks`
81
- - [Codex: hooks](https://learn.chatgpt.com/docs/hooks) — events, the `hooks.json` schema, trust, `/hooks`
82
- - [Codex: config reference](https://learn.chatgpt.com/docs/config-file/config-reference) — `[features]` and `[hooks.state]`
58
+ - [Claude Code hooks](https://code.claude.com/docs/en/hooks)
59
+ - [Codex hooks](https://learn.chatgpt.com/docs/hooks)
60
+ - [Codex configuration](https://learn.chatgpt.com/docs/config-file/config-reference)
@@ -2,26 +2,25 @@
2
2
 
3
3
  ## Importing
4
4
 
5
- - Import everything from `src/assets/` so the bundler fingerprints and bundles it. Never reference an image by public-path
6
- string.
5
+ Import files from `src/assets/` so the bundler fingerprints and includes them. Do not reference an asset through a
6
+ public-path string.
7
7
 
8
- ## Photographs — WebP
8
+ ## Photographs: WebP
9
9
 
10
- ```bash
10
+ Convert photographs to WebP before adding them:
11
+
12
+ ```sh
11
13
  magick source.png -resize 2000x -quality 80 -define webp:method=6 src/assets/name.webp
12
14
  ```
13
15
 
14
- - Quality 80 — visually lossless on photos, routinely an order of magnitude smaller.
15
- - `method=6` — densest encoding; a one-off cost at conversion time, so take the smaller file.
16
- - Long edge ≤ 2000px — nothing on the market resolves more in a content image.
17
- - No `<picture>` fallback — WebP is supported everywhere since 2020.
16
+ Keep the long edge at 2000px or less. WebP is supported by the browser floor.
18
17
 
19
18
  ## Other formats
20
19
 
21
- - Alpha, or pixels that must stay exact → PNG, optimized with `oxipng` or `pngquant`.
22
- - Icons, logos, line art → inline SVG component, so it inherits `currentColor` and follows the theme.
20
+ Use PNG when the image needs alpha or exact pixels. Use an inline SVG component for icons, logos, and line art so it inherits
21
+ `currentColor` and follows the theme.
23
22
 
24
23
  ## Scope
25
24
 
26
- - Rules apply to assets as they're added or touched. Existing assets in another format are not findings to sweep — convert
27
- opportunistically.
25
+ Apply these rules to assets you add or touch. Existing files do not need a format migration just because they use another
26
+ format.
@@ -1,65 +1,50 @@
1
1
  # Authentication
2
2
 
3
- One route-protection shape for every frontend; provider, session mechanism, endpoint paths, and login/logout transport stay
4
- project-owned — no provider is prescribed or named.
3
+ Use one route boundary for authentication. The provider, session mechanism, endpoint paths, and login/logout transport stay
4
+ owned by the application.
5
5
 
6
6
  ## Starter shape
7
7
 
8
- - Authentication sits at the route-group boundary, before child routes render.
9
- - `_public/` and `_app/`: pathless TanStack Router groups — guards and layouts without `public`/`app` in the URL.
10
- - The authenticated group keeps this shape even without an `AppShell`.
11
-
12
- ```text
13
- src/
14
- api/auth/ # getUser query options, keys.ts, types.ts, index.ts barrel
15
- lib/auth/
16
- login-url.ts # pure login navigation helper; not an API topic file
17
- login-url.test.ts # focused helper tests
18
- routes/
19
- __root.tsx # global Outlet and error/not-found boundaries; no auth guard
20
- _public/route.tsx # anonymous route group
21
- _app/route.tsx # authenticated route group
22
- ```
8
+ - Keep public routes under a pathless `_public/` group.
9
+ - Keep authenticated routes under a pathless `_app/` group.
10
+ - Guard `_app/` before its children render.
11
+ - Keep the root route neutral: it owns the outlet and global error/not-found boundaries.
12
+ - A greenfield app starts `_app/` with a minimal `AppShell` unless it has no persistent authenticated navigation.
13
+
14
+ The file layout is in [project-structure.md](project-structure.md).
23
15
 
24
16
  ## One current-user query
25
17
 
26
- - One identity source of truth: a server-backed current-user query; never copy session credentials or access tokens into
27
- React state.
28
- - The auth topic follows the default [data.md](data.md) shape: `getUser` in `api/auth/queries.ts`, key leading with the
29
- `auth` topic, schema in `types.ts`.
30
- - `lib/auth/login-url.ts`: project-owned navigation helper, not an options factory; tests colocated.
31
- - Reached as `context.api.auth.getUser()`; returns query options, never a hook or a user value — callers pick
32
- `ensureQueryData` or a query hook.
33
- - Never infer authentication from local storage, a decoded token, a route flag, or permission-gated chrome — stale or
34
- forgeable; the server response and its schema define the current user.
18
+ Use one server-backed current-user query as the identity source:
19
+
20
+ - Put it in `api/auth/queries.ts` and define its key and schema with the [data.md](data.md) pattern.
21
+ - Expose query options as `context.api.auth.getUser()`.
22
+ - Call `ensureQueryData` in a loader or a query hook in a component.
23
+ - Keep credentials and access tokens out of React state.
24
+ - Do not infer authentication from local storage, decoded tokens, route flags, or permission-gated UI.
25
+
26
+ The server response, parsed at the network boundary, is the source of truth.
35
27
 
36
28
  ## The two route groups
37
29
 
38
- Both resolve the current-user query in `beforeLoad` when they need the answer; only the meaning of a 401 differs:
30
+ Both groups may resolve the current-user query in `beforeLoad`. They handle a 401 differently:
39
31
 
40
- | Group | 401 means | Result |
41
- | ---------- | ----------------- | ------------------------------------------- |
42
- | `_app/` | not logged in | navigate to the server-owned login endpoint |
43
- | `_public/` | anonymous visitor | continue with `user: null` |
32
+ | Group | 401 result |
33
+ | ---------- | -------------------------------------------- |
34
+ | `_app/` | Navigate to the server-owned login endpoint. |
35
+ | `_public/` | Continue as an anonymous user. |
44
36
 
45
- - The `_app/route.tsx` guard awaits the query before children render, converts only an authentication 401 into login
46
- navigation, rethrows router redirects, and lets 5xx, connection failures, and schema mismatches reach the error boundary.
47
- - A public landing route may redirect an authenticated user into `_app/`.
48
- - The root route stays neutral: global `Outlet` and error/not-found boundaries, no public/authenticated decision.
37
+ The `_app/` guard should navigate only for the authentication 401. Rethrow redirects, server failures, connection failures,
38
+ and schema errors so the normal error boundary can handle them. A public route may redirect an already-authenticated user
39
+ into `_app/`.
49
40
 
50
41
  ## Login and logout
51
42
 
52
- - Follow the project's documented transport. Server-owned flow: login is a browser navigation, not a Query fetch; logout is
53
- the server's documented state-changing action, not an ad-hoc client request.
54
- - Preserve a validated same-origin return path when the server supports returning to the interrupted route.
55
- - Never hard-code an endpoint shape or provider into shared frontend conventions.
56
- - No intermediate login route when the server owns the flow.
57
- - A failed API request is an auth failure only when its typed error is specifically a 401.
43
+ Follow the application's documented server flow. Login is a browser navigation when the server owns the session; it is not a
44
+ Query fetch. Logout uses the server's documented state-changing action. Preserve a validated same-origin return path when the
45
+ server supports one. Do not invent an endpoint shape in this shared baseline.
58
46
 
59
47
  ## App shell
60
48
 
61
- - `AppShell` is authenticated chrome, not the authentication mechanism.
62
- - Greenfield default: propose a minimal shell — ImFusion logo, route navigation, stable session action area around the
63
- `_app/` outlet.
64
- - An explicit no-persistent-navigation decision may omit the shell; the `_app/` guard stays.
65
- - An established project keeps its working choice; public pages may use a small branded header.
49
+ `AppShell` is authenticated chrome, not the authentication mechanism. It can hold the logo, navigation, and session action
50
+ around the `_app/` outlet. An established project keeps its working shell or header choice.