@imfusion/web-ui 0.6.1-dev.27.gfc6e5abb → 0.6.1-dev.3.g8b2855c3
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 +169 -102
- package/dist/{code-C_56u-Vk.js → code-Blo48PGr.js} +2 -2
- package/dist/components/stack/stack.d.ts +1 -1
- package/dist/icons/icon-config-provider.d.ts +8 -0
- package/dist/icons/icon-context.d.ts +4 -0
- package/dist/{icons-Cy1HAosO.js → icons-wBmF0U2x.js} +1 -1
- package/dist/icons.js +1 -1
- package/dist/index.d.ts +0 -1
- package/dist/index.js +830 -1009
- package/dist/integrations/code-highlight/highlighter.d.ts +0 -24
- package/dist/integrations/code-highlight.js +47 -80
- package/dist/integrations/image-display-options.js +2 -2
- package/dist/provider/web-ui-provider.d.ts +3 -3
- package/dist/style.css +1 -1
- package/dist/{tabs-DIe1Utiy.js → tabs-CMKvMF4E.js} +0 -2
- package/package.json +4 -5
- package/src/docgen/doc.gen.json +1 -389
- package/src/llms/install-templates/AGENTS.md +18 -15
- package/src/llms/llms.gen.txt +33 -39
- package/src/llms/skills/imf-web-ui/SKILL.md +39 -30
- package/src/llms/skills/imf-web-ui-audit/SKILL.md +102 -50
- package/src/llms/skills/imf-web-ui-components/SKILL.md +104 -47
- package/src/llms/skills/imf-web-ui-conventions/SKILL.md +52 -44
- package/src/llms/skills/imf-web-ui-conventions/templates/AUDIT_CHECKLIST.md +0 -1
- package/src/llms/skills/imf-web-ui-conventions/topics/agent-tooling.md +62 -40
- package/src/llms/skills/imf-web-ui-conventions/topics/assets.md +12 -11
- package/src/llms/skills/imf-web-ui-conventions/topics/authentication.md +46 -31
- package/src/llms/skills/imf-web-ui-conventions/topics/class-names.md +23 -18
- package/src/llms/skills/imf-web-ui-conventions/topics/components.md +69 -20
- package/src/llms/skills/imf-web-ui-conventions/topics/data.md +146 -50
- package/src/llms/skills/imf-web-ui-conventions/topics/docs-structure.md +23 -17
- package/src/llms/skills/imf-web-ui-conventions/topics/git.md +20 -15
- package/src/llms/skills/imf-web-ui-conventions/topics/library-boundary.md +19 -28
- package/src/llms/skills/imf-web-ui-conventions/topics/library-setup.md +16 -20
- package/src/llms/skills/imf-web-ui-conventions/topics/npm-project.md +42 -28
- package/src/llms/skills/imf-web-ui-conventions/topics/project-structure.md +30 -28
- package/src/llms/skills/imf-web-ui-conventions/topics/react.md +74 -28
- package/src/llms/skills/imf-web-ui-conventions/topics/styling.md +62 -65
- package/src/llms/skills/imf-web-ui-conventions/topics/testing.md +14 -12
- package/src/llms/skills/imf-web-ui-conventions/topics/tokens.md +4 -9
- package/src/llms/skills/imf-web-ui-conventions/topics/tooling.md +68 -40
- package/src/llms/skills/imf-web-ui-conventions/topics/typescript.md +50 -26
- package/src/llms/skills/imf-web-ui-conventions/topics/validation.md +25 -19
- package/src/llms/skills/imf-web-ui-setup/SKILL.md +64 -45
- package/src/llms/skills/imf-web-ui-update/SKILL.md +114 -48
- package/src/llms/skills/imf-web-ui-ux/SKILL.md +92 -64
- package/src/llms/skills/imf-web-ui-ux/references/forms.md +36 -16
- package/src/llms/skills/imf-web-ui-ux/references/usability-heuristics.md +27 -14
- package/src/llms/skills/imf-web-ui-ux/references/visual-design.md +38 -22
- package/src/llms/tokens.gen.json +5 -5
- package/dist/codegen/gen-code-highlight-theme.d.ts +0 -1
- package/dist/components/toast/index.d.ts +0 -2
- package/dist/components/toast/toast.d.ts +0 -200
- package/dist/components/toast/toast.meta.d.ts +0 -2
- package/dist/icons/icon-config.d.ts +0 -12
|
@@ -1,62 +1,113 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: imf-web-ui-components
|
|
3
3
|
description:
|
|
4
|
-
"Look up @imfusion/web-ui component APIs
|
|
5
|
-
|
|
6
|
-
|
|
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)."
|
|
7
7
|
allowed-tools: Bash
|
|
8
8
|
---
|
|
9
9
|
|
|
10
|
-
#
|
|
10
|
+
# imf-web-ui-components
|
|
11
11
|
|
|
12
|
-
|
|
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:
|
|
13
14
|
|
|
14
|
-
|
|
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.
|
|
15
21
|
|
|
16
|
-
|
|
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.
|
|
17
25
|
|
|
18
|
-
|
|
19
|
-
cat node_modules/@imfusion/web-ui/src/llms/llms.gen.txt
|
|
20
|
-
```
|
|
26
|
+
## The lookup, in two hops
|
|
21
27
|
|
|
22
|
-
|
|
28
|
+
**Hop 1 — find the component.** Read the whole index; it's small (~13KB for the full library) and safe to load in full:
|
|
23
29
|
|
|
24
|
-
|
|
30
|
+
```sh
|
|
31
|
+
cat node_modules/@imfusion/web-ui/src/llms/llms.gen.txt
|
|
32
|
+
```
|
|
25
33
|
|
|
26
|
-
|
|
27
|
-
jq '.button' node_modules/@imfusion/web-ui/src/docgen/doc.gen.json
|
|
28
|
-
```
|
|
34
|
+
Each entry looks like this:
|
|
29
35
|
|
|
30
|
-
|
|
31
|
-
|
|
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
|
+
```
|
|
32
43
|
|
|
33
|
-
|
|
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:
|
|
34
46
|
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
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
|
+
```
|
|
38
62
|
|
|
39
|
-
|
|
40
|
-
|
|
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.
|
|
41
65
|
|
|
42
|
-
|
|
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.
|
|
43
70
|
|
|
44
|
-
|
|
45
|
-
|
|
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`.
|
|
46
77
|
|
|
47
78
|
## Icons
|
|
48
79
|
|
|
49
|
-
When the task
|
|
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:
|
|
50
84
|
|
|
51
85
|
```sh
|
|
52
86
|
node -e '
|
|
53
87
|
const q = process.argv[1].toLowerCase();
|
|
54
|
-
const icons = JSON.parse(
|
|
55
|
-
|
|
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
|
+
);
|
|
56
106
|
' "add"
|
|
57
107
|
```
|
|
58
108
|
|
|
59
|
-
Import the glyph and `Icon` from
|
|
109
|
+
Import the chosen glyph and `Icon` from `@imfusion/web-ui/icons`. Render it through `Icon`, including when it inherits the
|
|
110
|
+
surrounding color:
|
|
60
111
|
|
|
61
112
|
```tsx
|
|
62
113
|
import { ArrowRight, Icon } from "@imfusion/web-ui/icons";
|
|
@@ -64,33 +115,39 @@ import { ArrowRight, Icon } from "@imfusion/web-ui/icons";
|
|
|
64
115
|
<Icon glyph={ArrowRight} aria-hidden />;
|
|
65
116
|
```
|
|
66
117
|
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
## Compound components
|
|
70
|
-
|
|
71
|
-
A non-empty `subComponents` array means the component is a namespace:
|
|
118
|
+
Use `Icon` for every rendered icon. Pass the component reference, not a rendered element:
|
|
72
119
|
|
|
73
120
|
```tsx
|
|
74
|
-
import {
|
|
121
|
+
import { ArrowRight, Icon } from "@imfusion/web-ui/icons";
|
|
75
122
|
|
|
76
|
-
<
|
|
77
|
-
<Drawer.Trigger>Open</Drawer.Trigger>
|
|
78
|
-
<Drawer.Content>…</Drawer.Content>
|
|
79
|
-
</Drawer.Root>;
|
|
123
|
+
<Icon glyph={ArrowRight} size={16} variant="primary" aria-label="Continue" role="img" />;
|
|
80
124
|
```
|
|
81
125
|
|
|
82
|
-
|
|
126
|
+
Never import `iconoir-react` or another icon package directly.
|
|
127
|
+
|
|
128
|
+
## Compound components
|
|
83
129
|
|
|
84
|
-
|
|
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.
|
|
85
134
|
|
|
86
|
-
|
|
87
|
-
|
|
135
|
+
## Integrations (own-entry components)
|
|
136
|
+
|
|
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.:
|
|
88
139
|
|
|
89
140
|
```tsx
|
|
90
141
|
import { Code } from "@imfusion/web-ui/integrations/code-highlight";
|
|
91
142
|
```
|
|
92
143
|
|
|
93
|
-
|
|
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)
|
|
94
149
|
|
|
95
|
-
|
|
96
|
-
|
|
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.
|
|
@@ -1,49 +1,57 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: imf-web-ui-conventions
|
|
3
3
|
description:
|
|
4
|
-
"
|
|
5
|
-
|
|
6
|
-
|
|
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."
|
|
7
10
|
---
|
|
8
11
|
|
|
9
|
-
#
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
|
25
|
-
|
|
|
26
|
-
| [
|
|
27
|
-
| [
|
|
28
|
-
| [
|
|
29
|
-
| [
|
|
30
|
-
| [
|
|
31
|
-
| [
|
|
32
|
-
| [
|
|
33
|
-
| [
|
|
34
|
-
| [
|
|
35
|
-
| [
|
|
36
|
-
| [
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
##
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
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.
|
|
@@ -58,7 +58,6 @@ 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
|
|
62
61
|
- [ ] Responsive styling
|
|
63
62
|
|
|
64
63
|
## Tokens — `tokens`
|
|
@@ -1,60 +1,82 @@
|
|
|
1
1
|
# Agent tooling
|
|
2
2
|
|
|
3
|
-
`npx web-ui-install`
|
|
4
|
-
|
|
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.
|
|
5
5
|
|
|
6
6
|
## The skill bundle
|
|
7
7
|
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
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.
|
|
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.
|
|
20
14
|
|
|
21
15
|
## The hooks
|
|
22
16
|
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
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"]
|
|
27
44
|
```
|
|
28
45
|
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
-
|
|
35
|
-
- `
|
|
36
|
-
|
|
37
|
-
-
|
|
38
|
-
|
|
39
|
-
|
|
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.
|
|
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.
|
|
44
57
|
|
|
45
58
|
## Codex trust
|
|
46
59
|
|
|
47
|
-
Codex runs project hooks only
|
|
48
|
-
|
|
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.
|
|
49
68
|
|
|
50
69
|
## Dependency-shipped skills
|
|
51
70
|
|
|
52
|
-
|
|
71
|
+
- npm packages can ship Agent Skills of their own; TanStack does — [tooling.md](./tooling.md) covers TanStack Intent and its
|
|
72
|
+
allowlist.
|
|
53
73
|
|
|
54
74
|
## Hook docs
|
|
55
75
|
|
|
56
|
-
|
|
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.
|
|
57
78
|
|
|
58
|
-
- [Claude Code hooks](https://code.claude.com/docs/en/hooks)
|
|
59
|
-
|
|
60
|
-
- [Codex
|
|
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]`
|
|
@@ -2,25 +2,26 @@
|
|
|
2
2
|
|
|
3
3
|
## Importing
|
|
4
4
|
|
|
5
|
-
Import
|
|
6
|
-
|
|
5
|
+
- Import everything from `src/assets/` so the bundler fingerprints and bundles it. Never reference an image by public-path
|
|
6
|
+
string.
|
|
7
7
|
|
|
8
|
-
## Photographs
|
|
8
|
+
## Photographs — WebP
|
|
9
9
|
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
```sh
|
|
10
|
+
```bash
|
|
13
11
|
magick source.png -resize 2000x -quality 80 -define webp:method=6 src/assets/name.webp
|
|
14
12
|
```
|
|
15
13
|
|
|
16
|
-
|
|
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.
|
|
17
18
|
|
|
18
19
|
## Other formats
|
|
19
20
|
|
|
20
|
-
|
|
21
|
-
`currentColor` and follows the theme.
|
|
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.
|
|
22
23
|
|
|
23
24
|
## Scope
|
|
24
25
|
|
|
25
|
-
|
|
26
|
-
|
|
26
|
+
- Rules apply to assets as they're added or touched. Existing assets in another format are not findings to sweep — convert
|
|
27
|
+
opportunistically.
|
|
@@ -1,50 +1,65 @@
|
|
|
1
1
|
# Authentication
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
owned
|
|
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.
|
|
5
5
|
|
|
6
6
|
## Starter shape
|
|
7
7
|
|
|
8
|
-
-
|
|
9
|
-
-
|
|
10
|
-
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
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
|
+
```
|
|
15
23
|
|
|
16
24
|
## One current-user query
|
|
17
25
|
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
-
|
|
21
|
-
|
|
22
|
-
-
|
|
23
|
-
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
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.
|
|
27
35
|
|
|
28
36
|
## The two route groups
|
|
29
37
|
|
|
30
|
-
Both
|
|
38
|
+
Both resolve the current-user query in `beforeLoad` when they need the answer; only the meaning of a 401 differs:
|
|
31
39
|
|
|
32
|
-
| Group | 401
|
|
33
|
-
| ---------- |
|
|
34
|
-
| `_app/` |
|
|
35
|
-
| `_public/` |
|
|
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` |
|
|
36
44
|
|
|
37
|
-
The `_app
|
|
38
|
-
|
|
39
|
-
into `_app/`.
|
|
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.
|
|
40
49
|
|
|
41
50
|
## Login and logout
|
|
42
51
|
|
|
43
|
-
Follow the
|
|
44
|
-
|
|
45
|
-
|
|
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.
|
|
46
58
|
|
|
47
59
|
## App shell
|
|
48
60
|
|
|
49
|
-
`AppShell` is authenticated chrome, not the authentication mechanism.
|
|
50
|
-
|
|
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.
|