@imfusion/web-ui 0.5.1-dev.40.gfb5bc73e → 0.5.1-dev.44.g02fbbc52

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
@@ -69,7 +69,7 @@ skill.
69
69
  | `/imf-web-ui-components` | Component reference — what exists and how it's meant to be used. |
70
70
  | `/imf-web-ui-ux` | UX guidance for building interfaces with the library. |
71
71
  | `/imf-web-ui-conventions` | The frontend conventions baseline, including the sanctioned styling seams. |
72
- | `/imf-web-ui-audit` | Read-only health check for a consumer project, with a reviewable audit report. |
72
+ | `/imf-web-ui-audit` | Read-only health check for a consumer project, ending in a plan you approve. |
73
73
  | `/imf-web-ui-update` | Update the library, skills, and optional hooks, then verify before committing. |
74
74
 
75
75
  Start at `/imf-web-ui` — it routes to the rest. Storybook's **User Guide → AI Agents** page covers the whole family.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@imfusion/web-ui",
3
- "version": "0.5.1-dev.40.gfb5bc73e",
3
+ "version": "0.5.1-dev.44.g02fbbc52",
4
4
  "description": "The official Web UI component library for ImFusion web apps",
5
5
  "author": "ImFusion GmbH",
6
6
  "license": "UNLICENSED",
@@ -4,49 +4,76 @@ description:
4
4
  "Read-only health check for an ImFusion frontend against the conventions baseline. Audit the full project or any topic,
5
5
  including library-setup, tooling, git, npm-project, authentication, project-structure, docs-structure, data, testing,
6
6
  React, TypeScript, class names, validation, components, styling, assets, library-boundary, and tokens. Reports broken
7
- pieces, missing pieces, working deviations, present evidence, and unverified state in AUDIT_REPORT.md."
7
+ pieces, missing pieces, working deviations, present evidence, and unverified state, then turns them into an actionable
8
+ plan."
8
9
  argument-hint: "[full|<topic>]"
9
10
  allowed-tools: Read Glob Grep
10
11
  ---
11
12
 
12
13
  # imf-web-ui-audit
13
14
 
14
- You are the frontend health-check auditor. Investigate the repository statically, record every supported conclusion in
15
- `AUDIT_REPORT.md`, and return the report path and a short verdict. Follow the applicable `imf-web-ui-conventions` topics,
16
- cite repository evidence, distinguish defects from working deviations, and never present the baseline as universal best
17
- practice.
15
+ You are the frontend health-check auditor, and you run as an orchestrator: one investigator per topic gathers the evidence,
16
+ you merge their findings and turn them into an actionable plan. Follow the applicable `imf-web-ui-conventions` topics, cite
17
+ repository evidence, distinguish defects from working deviations, and never present the baseline as universal best practice.
18
+
19
+ An audit belongs in plan mode: it ends in work to approve, not in files to write.
18
20
 
19
21
  ## Workflow
20
22
 
21
23
  1. Resolve the argument. Bare means `full`; a topic selects one row below. If no topic matches, list every available topic
22
24
  instead of guessing or widening the scope.
23
- 2. Read every applicable convention topic and inspect the repository with `Read`, `Glob`, and `Grep` only.
24
- 3. Work through the shared [convention audit checklist](../imf-web-ui-conventions/templates/AUDIT_CHECKLIST.md), checking
25
- every row for a full audit and the requested row plus dependencies for a scoped audit.
26
- 4. Check the complete installed skill bundle, version markers, AGENTS fence, lifecycle hooks, registrations, and staleness
27
- wiring when `agent-tooling` is in scope. Compare the declared version in `package.json`, the installed
28
- `node_modules/@imfusion/web-ui/package.json`, and every `.imf-web-ui-skill-version.json` marker. Report drift and point at
29
- `imf-web-ui-update`. The registry is unreachable from this audit, so a line saying that a newer version may exist is
30
- unverified.
31
- 5. Write or refresh `AUDIT_REPORT.md` from the shared report contract at
32
- [`../imf-web-ui-conventions/templates/REPORT.md`](../imf-web-ui-conventions/templates/REPORT.md), changing the mode label
33
- to `audit`. The template is the report contract. Preserve everything under `## Reviewer notes` verbatim.
25
+ 2. Enter the host's plan mode, unless one of the exceptions after step 5 applies. If plan mode is not already active, use the
26
+ host plan-mode control before dispatching anything.
27
+ 3. Dispatch one investigator per in-scope topic, using the host's subagent mechanism, as concurrently as the host allows.
28
+ Investigators are cheap and narrow: each one gets a single topic and reports back. A host with no subagent mechanism is
29
+ not a blocker — work the topics inline in this session, in the same order, to the same contract.
30
+ 4. Merge what comes back. Findings you did not gather yourself are the report; do not re-inspect files an investigator
31
+ covered. Reconcile conflicts by reading the cited evidence, and drop any finding whose citation does not hold.
32
+ 5. Deliver the merged report and the plan in the host plan, from the shared report contract at
33
+ [`../imf-web-ui-conventions/templates/REPORT.md`](../imf-web-ui-conventions/templates/REPORT.md), with the mode label
34
+ `audit`. The plan's ordered steps are the `Next action` lines of the findings, grouped by topic and cheapest-first;
35
+ `Present` findings produce no steps.
36
+
37
+ Some runs take the report somewhere other than a plan. When the human asks for the durable file, or the host has no plan
38
+ mode, write the same content to `AUDIT_REPORT.md` and preserve everything under `## Reviewer notes` verbatim. When another
39
+ skill invokes the audit as its verification step, report the findings to that caller and stay out of plan mode — the caller
40
+ owns the flow, and the human has usually just left plan mode to let its work happen.
41
+
42
+ ## Dispatching an investigator
43
+
44
+ Each investigator prompt carries, in full:
45
+
46
+ - the topic name and the path of its convention topic file;
47
+ - the topic's block from the shared [convention audit checklist](../imf-web-ui-conventions/templates/AUDIT_CHECKLIST.md), and
48
+ the instruction to check every box in it;
49
+ - the safety constraint below, verbatim — an investigator that reaches for a shell breaks the audit's only guarantee;
50
+ - the report contract's entry format, so findings arrive mergeable: severity, reference, short title, `path:line` evidence,
51
+ impact, next action;
52
+ - the instruction to report findings back as its result and write no files.
53
+
54
+ An investigator reports on its topic alone. Anything it notices outside that topic goes back as a note for the orchestrator
55
+ to route, not as a finding it rules on.
34
56
 
35
57
  ## Checklist
36
58
 
37
- Use the shared [convention audit checklist](../imf-web-ui-conventions/templates/AUDIT_CHECKLIST.md) as the working checklist.
38
- The report is not complete until the applicable rows have been inspected and their evidence is reflected in the report. The
59
+ The shared [convention audit checklist](../imf-web-ui-conventions/templates/AUDIT_CHECKLIST.md) is the working checklist: a
60
+ full audit covers every block, a scoped audit covers the requested block plus its dependencies. The audit is not complete
61
+ until every in-scope box has been checked by the investigator that owns it and its evidence appears in the report. The
39
62
  checklist itself is not edited during an audit.
40
63
 
41
64
  ## Safety
42
65
 
43
66
  Use only static inspection: Read, Glob, Grep, and equivalent non-executing search tools. Do not use a shell or invoke Node,
44
67
  npm, npx, package scripts, hooks, config imports, linters, tests, builds, Git commands, or project binaries. Read config as
45
- text and report runtime or machine-local state that cannot be established statically as unverified.
68
+ text and report runtime or machine-local state that cannot be established statically as unverified. This binds every
69
+ investigator too — a dispatched agent inherits the audit's constraint, not the host's default freedom, so the prompt that
70
+ dispatches it repeats this paragraph verbatim.
46
71
 
47
- Only `AUDIT_REPORT.md` may be written. Write is intentionally not pre-approved in `allowed-tools`; the report follows the
48
- host's ordinary write approval. Host-managed hooks may run after that write; the skill neither invokes nor suppresses them,
49
- but it does report broken or unexpected hook behavior found during static inspection.
72
+ An audit writes at most one file: `AUDIT_REPORT.md`, in the two cases named in the workflow. Investigators write nothing.
73
+ Neither Write nor the host's dispatch tool is pre-approved in `allowed-tools` — `allowed-tools` names what an audit needs on
74
+ every run, and both of these follow the host's ordinary approval when a run needs them. Host-managed hooks may run after that
75
+ write; the skill neither invokes nor suppresses them, but it does report broken or unexpected hook behavior found during
76
+ static inspection.
50
77
 
51
78
  ## Topics
52
79
 
@@ -83,5 +110,10 @@ three injection hooks, the stop gate, plus `baseline-staleness.sh` — are drift
83
110
  `baseline-staleness.sh`. Read files and settings as text—do not run installers, hooks, or local config queries during
84
111
  assessment.
85
112
 
113
+ Version drift is part of this topic: compare the declared version in `package.json`, the installed
114
+ `node_modules/@imfusion/web-ui/package.json`, and every `.imf-web-ui-skill-version.json` marker, then report the drift and
115
+ point at `imf-web-ui-update`. The registry is unreachable from a static audit, so a line saying that a newer version may
116
+ exist is unverified.
117
+
86
118
  Use the shared report template as the report contract. It defines the headings, ordering, empty-section marker, evidence
87
119
  format, and reviewer-note preservation rules; do not duplicate that contract here.
@@ -11,7 +11,7 @@ project-owned — no provider is prescribed or named.
11
11
 
12
12
  ```text
13
13
  src/
14
- api/auth/ # getCurrentUser query options, query-key.ts, types.ts, index.ts barrel
14
+ api/auth/ # getUser query options, keys.ts, types.ts, index.ts barrel
15
15
  lib/auth/
16
16
  login-url.ts # pure login navigation helper; not an API topic file
17
17
  login-url.test.ts # focused helper tests
@@ -25,10 +25,10 @@ src/
25
25
 
26
26
  - One identity source of truth: a server-backed current-user query; never copy session credentials or access tokens into
27
27
  React state.
28
- - The auth topic follows the default [data.md](data.md) shape: `getCurrentUser` in `api/auth/auth.ts`, key leading with the
28
+ - The auth topic follows the default [data.md](data.md) shape: `getUser` in `api/auth/queries.ts`, key leading with the
29
29
  `auth` topic, schema in `types.ts`.
30
30
  - `lib/auth/login-url.ts`: project-owned navigation helper, not an options factory; tests colocated.
31
- - Reached as `context.api.auth.getCurrentUser()`; returns query options, never a hook or a user value — callers pick
31
+ - Reached as `context.api.auth.getUser()`; returns query options, never a hook or a user value — callers pick
32
32
  `ensureQueryData` or a query hook.
33
33
  - Never infer authentication from local storage, a decoded token, a route flag, or permission-gated chrome — stale or
34
34
  forgeable; the server response and its schema define the current user.
@@ -7,9 +7,11 @@ the boundary principles — validate at the edge, errors as values — not this
7
7
 
8
8
  - One folder per API topic: options factories, key factory, Zod schemas together, so a query key is never spelled out at a
9
9
  call site.
10
- - Default topic shape `<topic>.ts` + `query-key.ts` + `types.ts`; the reference project's GraphQL transport expands to
11
- `keys.ts`, `queries.ts`/`queryFns.ts`, `mutations.ts`/`mutationFns.ts`, `index.ts` — GraphQL-specific, not a transport
12
- requirement.
10
+ - Name a file for what it holds, never for the topic it sits in — the folder already says that: `keys.ts`, not `<topic>.ts`
11
+ or `query-key.ts` (it holds mutation keys too).
12
+ - A file appears only when the topic needs it: a topic with only queries has no `mutations.ts`, and vice versa.
13
+ - A GraphQL (or similarly document-based) transport may split `queries.ts`/`mutations.ts` further into
14
+ `queryFns.ts`/`mutationFns.ts`; that's an elaboration of the same options-vs-mutations split, not its origin.
13
15
  - Transport code (base client, error normalisation): `http/` and nowhere else.
14
16
  - Topic helpers: `lib/`, framework-free, tested beside themselves (`build-query-string.ts` + its test) — never inside the
15
17
  topic folder.
@@ -19,8 +21,13 @@ src/
19
21
  api/
20
22
  topics.ts # one topic registry, reused by keys and namespaces
21
23
  index.ts # topic barrels composed as api.<topic>
22
- user/ # expanded topic (used in the examples): index.ts barrel, keys.ts, queries.ts, mutations.ts
23
- <topic>/ # default shape: <topic>.ts, query-key.ts, types.ts
24
+ <topic>/
25
+ index.ts # barrel: named re-exports of what other modules call
26
+ keys.ts # createApiKeys — query and mutation keys
27
+ queries.ts # query options factories — present when the topic has queries
28
+ mutations.ts # mutation options factories — present when the topic has mutations
29
+ types.ts # Zod schemas + z.infer types
30
+ types.test.ts # schema cases, when the schema encodes product behaviour
24
31
  http/ # transport: client, error normalisation — the only transport-aware place
25
32
  lib/ # framework-free helpers shared by API topics and other callers
26
33
  ```
@@ -94,6 +101,8 @@ export type API = typeof api;
94
101
  - No topic prefix, no `Options` suffix: `context.api.<topic>.<fn>()` carries both.
95
102
  - Queries `get*` (`getAll`, `getById`, `getBySlug`, `getDetails`, `getActive`, `getFiltered`); mutations bare verbs
96
103
  (`update`, `login`, `addItem`, `deleteAddress`, `setShippingMethod`).
104
+ - Same suffix-free naming applies to the local binding a query or mutation resolves to —
105
+ [typescript.md](typescript.md#naming).
97
106
 
98
107
  ```ts
99
108
  // api/user/queries.ts — returns options; keys come from the factory
@@ -166,13 +175,13 @@ export const Route = createFileRoute("/user")({
166
175
 
167
176
  function UserPage() {
168
177
  const context = Route.useRouteContext();
169
- const { data: user } = useSuspenseQuery(context.api.user.getDetails());
178
+ const user = useSuspenseQuery(context.api.user.getDetails());
170
179
  const updateUser = useMutation(
171
180
  context.api.user.update({
172
181
  onSuccess: () => context.queryClient.invalidateQueries({ queryKey: context.api.orders.keys.topic })
173
182
  })
174
183
  );
175
- return <input defaultValue={user.name} onBlur={e => updateUser.mutate({ name: e.target.value })} />;
184
+ return <input defaultValue={user.data.name} onBlur={e => updateUser.mutate({ name: e.target.value })} />;
176
185
  }
177
186
  ```
178
187
 
@@ -44,9 +44,9 @@ function UserCard({ name, role, onEdit }: { name: string; role: string; onEdit:
44
44
  ```tsx
45
45
  // Smart — knows where data comes from, renders the dumb component
46
46
  function UserCardContainer({ userId }: { userId: string }) {
47
- const { data } = useUserQuery(userId);
47
+ const user = useUserQuery(userId);
48
48
  const openEditor = useEditorNavigation(userId);
49
- return <UserCard name={data.name} role={data.role} onEdit={openEditor} />;
49
+ return <UserCard name={user.data.name} role={user.data.role} onEdit={openEditor} />;
50
50
  }
51
51
  ```
52
52
 
@@ -95,6 +95,8 @@ useEffect(
95
95
  );
96
96
  ```
97
97
 
98
+ - A dependency sourced from a hook or query return: destructure the primitive first — [typescript.md](typescript.md#naming).
99
+
98
100
  ## Reading list
99
101
 
100
102
  Consult while building; each is the authority for its topic:
@@ -43,3 +43,31 @@ const activeNames = users.filter(u => u.isActive).map(u => u.name);
43
43
  - Booleans read as assertions: `isOpen`, `hasAccess`, `canSubmit`.
44
44
  - Handlers: `onX` as props, `handleX` as implementations.
45
45
  - Match the vocabulary the product and the API already use — no synonyms for terms the backend named.
46
+ - Keep the object a hook or query returns as a namespace instead of destructuring it, and drop the `Query`/`Mutation` suffix
47
+ from the local binding — the binding reads as the domain name, and every field access shows where it came from:
48
+
49
+ ```tsx
50
+ const search = Route.useSearch(); // not const { page, filter } = ...
51
+ const user = useSuspenseQuery(context.api.user.getDetails()); // not const { data } = ...
52
+ const updateUser = useMutation(context.api.user.update());
53
+
54
+ search.page;
55
+ user.data.name;
56
+ updateUser.mutate(values);
57
+ updateUser.isPending;
58
+ ```
59
+
60
+ - Exception: a `useEffect` dependency array needs a stable primitive, since deps compare by identity — destructure the
61
+ primitive out first rather than listing the object or a deep path into it:
62
+
63
+ ```tsx
64
+ const user = useSuspenseQuery(context.api.auth.getUser());
65
+ const { name } = user.data; // destructure for the dep array
66
+
67
+ useEffect(
68
+ function syncDocumentTitle() {
69
+ document.title = name;
70
+ },
71
+ [name]
72
+ );
73
+ ```
@@ -18,20 +18,36 @@ report file as a substitute for the host plan.
18
18
 
19
19
  ## Workflow
20
20
 
21
- 1. Resolve the argument. Bare means `full`; a topic selects one supported setup topic. For an unsupported topic, list the
22
- available setup topics and point the human to `imf-web-ui-audit` for a read-only report.
21
+ 1. Resolve the argument, not the prose. Bare means `full`; a topic argument selects one supported setup topic. A prompt that
22
+ merely _mentions_ one area ("wire up the tooling", "get the project set up") is still a `full` run — the words describe a
23
+ starting point, not a scope that excludes the rest. For a greenfield `full` run the application boundary (router, route
24
+ groups, current-user query, AppShell) is part of the deliverable even when the prompt never names it; propose it and let
25
+ the human remove it, never silently defer it as "out of scope." For an unsupported topic argument, list the available
26
+ setup topics and point the human to `imf-web-ui-audit` for a read-only report.
23
27
  2. Enter the host's plan mode. If it is not already active, use the host plan-mode control before inspecting and planning.
24
28
  3. Read the selected convention topics and inspect the repository with `Read`, `Glob`, and `Grep` only.
25
29
  4. Build the complete proposal in the host plan from the shared report contract at
26
30
  [`../imf-web-ui-conventions/templates/REPORT.md`](../imf-web-ui-conventions/templates/REPORT.md). Include the concrete
27
31
  content of every file the approved setup would create or change, with repository evidence for each decision.
28
- 5. For a greenfield project, propose the minimal branded `AppShell` in the authenticated route group by default. If the human
29
- explicitly says the product has no persistent authenticated navigation, ask whether to omit the shell before finalizing
30
- the proposal; keep the `_app/` boundary either way. Existing projects keep their working shell choice. This ticket
31
- documents the starter shape but does not copy a full starter template.
32
+ 5. A greenfield `full` setup proposes the whole starter skeleton, not just tooling — tooling without the application boundary
33
+ is an unfinished setup. Include, as concrete files in the plan:
34
+ - the TanStack Router **package added to `package.json`** (with its router devtools as a dev dependency), not just
35
+ imported — code that imports an uninstalled package is an incomplete setup
36
+ ([project-structure.md](../imf-web-ui-conventions/topics/project-structure.md));
37
+ - pathless `_public/` and `_app/` route groups behind one server-backed current-user boundary
38
+ ([authentication.md](../imf-web-ui-conventions/topics/authentication.md));
39
+ - the minimal branded `AppShell` in `_app/` by default — omit the shell only when the human explicitly says the product
40
+ has no persistent authenticated navigation (ask first), but keep the `_app/` boundary either way;
41
+ - a per-topic `api/` folder for any data the first screen shows, never an inline fixture in the component
42
+ ([data.md](../imf-web-ui-conventions/topics/data.md)).
43
+
44
+ The plan documents this starter shape as concrete file content; it does not copy a full external starter template.
45
+ Existing projects keep their working choices — propose only the gaps.
46
+
32
47
  6. Keep the plan as the approval gate. After the host approves and exits plan mode, write only the listed files. Complete any
33
- immediately requested bootstrap work covered by that approved plan, then invoke `imf-web-ui-audit full` and review its
34
- `AUDIT_REPORT.md` before declaring the setup complete.
48
+ immediately requested bootstrap work covered by that approved plan, then invoke `imf-web-ui-audit full` as a verification
49
+ step and review the findings it reports back before declaring the setup complete. The audit stays out of plan mode here —
50
+ the human has just left it to let this work happen.
35
51
 
36
52
  Installer and hook runs stay with the human: an `agent-tooling` proposal lists the `npx web-ui-install` commands as human
37
53
  steps, applies the judgment from the topic (read existing registrations first, never stack a hook on a covered event), and
@@ -135,8 +135,8 @@ If no findings exist, report that the installed update has no detected compatibi
135
135
  candidates. Do not create an empty migration commit.
136
136
 
137
137
  Whatever the migration outcome, close the phase by asking whether to run `imf-web-ui-audit full`: an update can shift the
138
- baseline (new components, hooks, conventions), and the audit report shows where the project now stands against it. Run it
139
- only on an explicit yes.
138
+ baseline (new components, hooks, conventions), and the audit shows where the project now stands against it. Run it only on an
139
+ explicit yes.
140
140
 
141
141
  ## Migration approval
142
142