@imfusion/web-ui 0.5.1-dev.24.g5b275132 → 0.5.1-dev.28.g1156ad00
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 +1 -1
- package/bin/install.test.ts +31 -0
- package/package.json +1 -1
- package/src/llms/skills/imf-web-ui-agent-setup/SKILL.md +14 -3
- package/src/llms/skills/imf-web-ui-agent-setup/templates/hooks/post-tool-use.sh +19 -7
- package/src/llms/skills/imf-web-ui-components/SKILL.md +1 -0
- package/src/llms/skills/imf-web-ui-frontend-conventions/SKILL.md +6 -5
- package/src/llms/skills/imf-web-ui-frontend-conventions/references/data.md +16 -11
- package/src/llms/skills/imf-web-ui-frontend-conventions/references/react.md +4 -2
- package/src/llms/skills/imf-web-ui-frontend-conventions/references/testing.md +3 -1
- package/src/llms/skills/imf-web-ui-frontend-conventions/references/typescript.md +2 -1
- package/src/llms/skills/imf-web-ui-frontend-conventions/references/validation.md +88 -0
- package/src/llms/skills/imf-web-ui-frontend-setup/SKILL.md +58 -81
- package/src/llms/skills/imf-web-ui-frontend-setup/templates/FRONTEND_SETUP_REPORT.md +45 -0
- package/src/llms/skills/imf-web-ui-update/SKILL.md +1 -0
package/README.md
CHANGED
|
@@ -60,7 +60,7 @@ the directories it already installed into, without asking again — `--reconfigu
|
|
|
60
60
|
| `/imf-web-ui-components` | Component reference — what exists and how it's meant to be used. |
|
|
61
61
|
| `/imf-web-ui-ux` | UX guidance for building interfaces with the library. |
|
|
62
62
|
| `/imf-web-ui-frontend-conventions` | The frontend conventions baseline, including the sanctioned styling seams. |
|
|
63
|
-
| `/imf-web-ui-frontend-setup` |
|
|
63
|
+
| `/imf-web-ui-frontend-setup` | Assess an ImFusion frontend and write a reviewable setup report. |
|
|
64
64
|
| `/imf-web-ui-agent-setup` | Install or update the vendored skills, agent hooks, and TanStack Intent. |
|
|
65
65
|
| `/imf-web-ui-update` | Update the library, skills, and optional hooks, then verify before committing. |
|
|
66
66
|
|
package/bin/install.test.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { beforeEach, describe, expect, it } from "vitest";
|
|
2
2
|
import { spawnSync } from "node:child_process";
|
|
3
3
|
import {
|
|
4
|
+
chmodSync,
|
|
4
5
|
existsSync,
|
|
5
6
|
lstatSync,
|
|
6
7
|
mkdirSync,
|
|
@@ -150,6 +151,36 @@ describe("web-ui-install", () => {
|
|
|
150
151
|
expect(staleness.stdout).toBe("");
|
|
151
152
|
});
|
|
152
153
|
|
|
154
|
+
it("runs post-edit checks from the package containing the edited file", () => {
|
|
155
|
+
runInstall(consumer, "--hooks");
|
|
156
|
+
|
|
157
|
+
const frontend = join(consumer, "frontend");
|
|
158
|
+
const source = join(frontend, "src", "example.ts");
|
|
159
|
+
const binDir = join(frontend, "node_modules", ".bin");
|
|
160
|
+
const log = join(consumer, "hook.log");
|
|
161
|
+
mkdirSync(join(frontend, "src"), { recursive: true });
|
|
162
|
+
mkdirSync(binDir, { recursive: true });
|
|
163
|
+
writeFileSync(join(frontend, "package.json"), JSON.stringify({ private: true }));
|
|
164
|
+
writeFileSync(source, "export const example = true;\n");
|
|
165
|
+
|
|
166
|
+
for (const tool of ["eslint", "prettier"]) {
|
|
167
|
+
const path = join(binDir, tool);
|
|
168
|
+
writeFileSync(path, '#!/usr/bin/env sh\nprintf "%s|%s\\n" "$PWD" "$*" >> "$HOOK_LOG"\n');
|
|
169
|
+
chmodSync(path, 0o755);
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
const result = spawnSync("sh", [join(consumer, ".agents", "hooks", "imf-web-ui", "post-tool-use.sh")], {
|
|
173
|
+
cwd: consumer,
|
|
174
|
+
env: { ...process.env, HOOK_LOG: log },
|
|
175
|
+
input: JSON.stringify({ tool_input: { file_path: source } }),
|
|
176
|
+
encoding: "utf-8"
|
|
177
|
+
});
|
|
178
|
+
|
|
179
|
+
expect(result.status).toBe(0);
|
|
180
|
+
const calls = readFileSync(log, "utf-8").trim().split("\n");
|
|
181
|
+
expect(calls).toEqual([`${frontend}|--cache ${source}`, `${frontend}|--check ${source}`]);
|
|
182
|
+
});
|
|
183
|
+
|
|
153
184
|
it("warns from the staleness script when skill markers lag the package", () => {
|
|
154
185
|
runInstall(consumer, "--skills", "--hooks", "--target", "agents");
|
|
155
186
|
const pkgDir = join(consumer, "node_modules", "@imfusion", "web-ui");
|
package/package.json
CHANGED
|
@@ -8,6 +8,7 @@ description:
|
|
|
8
8
|
consumer app, when skills are stale, when hooks should be installed or adapted, or when asked to set up TanStack Intent or
|
|
9
9
|
dependency-shipped Agent Skills. Not for project tooling (imf-web-ui-frontend-setup) or library wiring
|
|
10
10
|
(imf-web-ui-library-setup)."
|
|
11
|
+
allowed-tools: Read Bash
|
|
11
12
|
---
|
|
12
13
|
|
|
13
14
|
# imf-web-ui-agent-setup
|
|
@@ -29,8 +30,9 @@ Three agent lifecycle hooks ship as templates in [`templates/hooks/`](templates/
|
|
|
29
30
|
- **SessionStart** — once per session: the conventions baseline is vendored, load it before writing.
|
|
30
31
|
- **UserPromptSubmit** — a one-line conventions reminder per prompt. Per-prompt, not per-tool-call: a PreToolUse reminder
|
|
31
32
|
would re-inject the same text on every edit.
|
|
32
|
-
- **PostToolUse** (advisory) — file-scope checks on the touched file after every Edit/Write, failures fed straight back.
|
|
33
|
-
|
|
33
|
+
- **PostToolUse** (advisory) — file-scope checks on the touched file after every Edit/Write, failures fed straight back. It
|
|
34
|
+
resolves the nearest package from the edited file, so a frontend nested below a monorepo root uses its own config and
|
|
35
|
+
dependencies. Never exits non-zero.
|
|
34
36
|
- **`baseline-staleness.sh`** — not registered as an agent hook; the repo's pre-commit calls it
|
|
35
37
|
([`git.md`](../imf-web-ui-frontend-conventions/references/git.md), Staleness at commit time).
|
|
36
38
|
|
|
@@ -42,6 +44,14 @@ Three agent lifecycle hooks ship as templates in [`templates/hooks/`](templates/
|
|
|
42
44
|
it. Use the template as a starting point instead: fold the missing behaviour into the repo's existing script, or adapt the
|
|
43
45
|
template and register that. Surface the situation and let the human pick.
|
|
44
46
|
|
|
47
|
+
## Assessment reference
|
|
48
|
+
|
|
49
|
+
A static frontend setup assessment checks that the complete consumer skill bundle and version markers match the declared
|
|
50
|
+
`@imfusion/web-ui` version; the AGENTS fence exists; SessionStart, UserPromptSubmit, and PostToolUse behavior is installed
|
|
51
|
+
and registered or consciously adapted; PostToolUse resolves the edited file's package and its tools in monorepos; and the
|
|
52
|
+
tracked pre-commit path calls `baseline-staleness.sh`. Read files and settings as text—do not run installers, hooks, or local
|
|
53
|
+
config queries during assessment.
|
|
54
|
+
|
|
45
55
|
## Dependency-shipped skills
|
|
46
56
|
|
|
47
57
|
Some libraries ship Agent Skills inside their npm package; TanStack does across much of the suite.
|
|
@@ -67,5 +77,6 @@ guidance you have: use `npx @tanstack/cli` for TanStack docs, and never guess at
|
|
|
67
77
|
|
|
68
78
|
## Not this skill
|
|
69
79
|
|
|
70
|
-
- Project tooling, docs structure, the audit checklist → `imf-web-ui-frontend-setup` (which
|
|
80
|
+
- Project tooling, docs structure, the audit checklist → `imf-web-ui-frontend-setup` (which reads this skill as its
|
|
81
|
+
agent-tooling assessment contract)
|
|
71
82
|
- Library wiring (styles import, provider) → `imf-web-ui-library-setup`
|
|
@@ -1,21 +1,33 @@
|
|
|
1
1
|
#!/usr/bin/env sh
|
|
2
2
|
# PostToolUse (Edit|Write): advisory file-scope checks on the touched file. Never exits
|
|
3
|
-
# non-zero, so a mid-flight refactor can't trap the agent. Resolve the
|
|
4
|
-
# file, not cwd, which
|
|
5
|
-
FILE=$(
|
|
3
|
+
# non-zero, so a mid-flight refactor can't trap the agent. Resolve the package from the
|
|
4
|
+
# edited file, not cwd or the Git root, which may belong to a parent monorepo.
|
|
5
|
+
FILE=$(sed -n 's/.*"file_path"[[:space:]]*:[[:space:]]*"\([^"]*\)".*/\1/p' | head -n1)
|
|
6
6
|
[ -f "$FILE" ] || exit 0
|
|
7
7
|
|
|
8
|
-
|
|
9
|
-
|
|
8
|
+
FILE_DIR=$(cd "$(dirname "$FILE")" && pwd) || exit 0
|
|
9
|
+
FILE="$FILE_DIR/$(basename "$FILE")"
|
|
10
|
+
PACKAGE_ROOT=$FILE_DIR
|
|
11
|
+
while [ "$PACKAGE_ROOT" != "/" ] && [ ! -f "$PACKAGE_ROOT/package.json" ]; do
|
|
12
|
+
PACKAGE_ROOT=$(dirname "$PACKAGE_ROOT")
|
|
13
|
+
done
|
|
14
|
+
[ -f "$PACKAGE_ROOT/package.json" ] || exit 0
|
|
15
|
+
|
|
16
|
+
TOOL_ROOT=$PACKAGE_ROOT
|
|
17
|
+
while [ "$TOOL_ROOT" != "/" ] && [ ! -d "$TOOL_ROOT/node_modules/.bin" ]; do
|
|
18
|
+
TOOL_ROOT=$(dirname "$TOOL_ROOT")
|
|
19
|
+
done
|
|
20
|
+
[ -d "$TOOL_ROOT/node_modules/.bin" ] || exit 0
|
|
21
|
+
cd "$PACKAGE_ROOT" || exit 0
|
|
10
22
|
|
|
11
23
|
case "$FILE" in
|
|
12
24
|
*.ts | *.tsx | *.js | *.jsx)
|
|
13
|
-
[ -x
|
|
25
|
+
[ -x "$TOOL_ROOT/node_modules/.bin/eslint" ] && "$TOOL_ROOT/node_modules/.bin/eslint" --cache "$FILE" 2>&1
|
|
14
26
|
;;
|
|
15
27
|
esac
|
|
16
28
|
case "$FILE" in
|
|
17
29
|
*.ts | *.tsx | *.js | *.jsx | *.css | *.json | *.md)
|
|
18
|
-
[ -x
|
|
30
|
+
[ -x "$TOOL_ROOT/node_modules/.bin/prettier" ] && "$TOOL_ROOT/node_modules/.bin/prettier" --check "$FILE" 2>&1
|
|
19
31
|
;;
|
|
20
32
|
esac
|
|
21
33
|
exit 0
|
|
@@ -4,6 +4,7 @@ description:
|
|
|
4
4
|
"Look up @imfusion/web-ui component APIs without reading their source: the two-hop lookup (identity index -> prop data),
|
|
5
5
|
compound components, and integrations. Load when you need the props, sub-components, or defaults of a specific component —
|
|
6
6
|
not for choosing between components (imf-web-ui-ux) or first-time setup (imf-web-ui-library-setup)."
|
|
7
|
+
allowed-tools: Bash
|
|
7
8
|
---
|
|
8
9
|
|
|
9
10
|
# imf-web-ui-components
|
|
@@ -2,10 +2,10 @@
|
|
|
2
2
|
name: imf-web-ui-frontend-conventions
|
|
3
3
|
description:
|
|
4
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 boundary, React, components, TypeScript, styling, data
|
|
6
|
-
project structure, testing, stack, npm project, tooling config, git, assets, docs structure. Load when writing
|
|
7
|
-
components, custom UI, styling beyond the defaults, adding new files to a consumer app,
|
|
8
|
-
config, or choosing any dependency."
|
|
5
|
+
who likes them. A router over topic references: library boundary, React, components, TypeScript, styling, validation, data
|
|
6
|
+
layer, project structure, testing, stack, npm project, tooling config, git, assets, docs structure. Load when writing
|
|
7
|
+
wrapper components, custom UI, styling beyond the defaults, validating external data, adding new files to a consumer app,
|
|
8
|
+
writing repo docs, touching tool config, or choosing any dependency."
|
|
9
9
|
---
|
|
10
10
|
|
|
11
11
|
# imf-web-ui-frontend-conventions
|
|
@@ -32,7 +32,8 @@ Each topic lives in one reference. Read the one whose moment you're in; starting
|
|
|
32
32
|
| [typescript.md](references/typescript.md) | functional style, types, naming | writing any code |
|
|
33
33
|
| [styling.md](references/styling.md) | native CSS Modules, tokens, the override contract | writing CSS or styling beyond the defaults |
|
|
34
34
|
| [class-names.md](references/class-names.md) | CVA variants, `cx`, merging the incoming `className` | writing a component with variants or a `className` prop |
|
|
35
|
-
| [
|
|
35
|
+
| [validation.md](references/validation.md) | runtime schemas, boundary parsing, schema-derived types | accepting data the frontend does not own |
|
|
36
|
+
| [data.md](references/data.md) | `api/`+`http/` shape, query/mutation patterns and invalidation | adding an API topic, a fetch, or a mutation |
|
|
36
37
|
| [project-structure.md](references/project-structure.md) | the `src/` tree, file naming, imports | adding files rather than editing existing ones |
|
|
37
38
|
| [testing.md](references/testing.md) | what's worth testing and what isn't | writing or reviewing tests |
|
|
38
39
|
| [stack.md](references/stack.md) | the topic→tool map, when a library owns a layer | choosing or adding any dependency |
|
|
@@ -20,12 +20,9 @@ transport-level (base client, error normalisation) lives in `http/` and nowhere
|
|
|
20
20
|
|
|
21
21
|
## The network boundary validates
|
|
22
22
|
|
|
23
|
-
The
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
The transport in `http/` is deliberately untyped: it returns `unknown` and leaves the parse to the caller, so no call site
|
|
28
|
-
can accidentally skip validation.
|
|
23
|
+
The transport in `http/` returns `unknown`; the topic schema parses the response in its query or mutation function before the
|
|
24
|
+
value enters the app. The schema is also the source of its TypeScript type. The full boundary, type-derivation, and failure
|
|
25
|
+
handling rules are [validation.md](validation.md).
|
|
29
26
|
|
|
30
27
|
## Errors are values
|
|
31
28
|
|
|
@@ -65,7 +62,8 @@ export const userQueryOptions = () =>
|
|
|
65
62
|
```
|
|
66
63
|
|
|
67
64
|
Components consume query options directly with `useSuspenseQuery` (prefetched routes) or `useQuery` (secondary data). No
|
|
68
|
-
wrapper hooks — the options function is the reusable unit.
|
|
65
|
+
wrapper hooks — the options function is the reusable unit. Call sites may spread the returned options only to add
|
|
66
|
+
component-specific callbacks or overrides.
|
|
69
67
|
|
|
70
68
|
Mutations follow the same shape with `mutationOptions`, the dirtied topic first in the `mutationKey`:
|
|
71
69
|
|
|
@@ -132,8 +130,8 @@ function MePage() {
|
|
|
132
130
|
}
|
|
133
131
|
```
|
|
134
132
|
|
|
135
|
-
Mutations use `useMutation` with the options factory
|
|
136
|
-
(see below):
|
|
133
|
+
Mutations use `useMutation` with the options factory instead of reconstructing `mutationKey` and `mutationFn` at the call
|
|
134
|
+
site. Manual invalidation is unnecessary when automatic invalidation is on (see below):
|
|
137
135
|
|
|
138
136
|
```tsx
|
|
139
137
|
// components/user-settings.tsx
|
|
@@ -189,8 +187,15 @@ targeted optimistic update), and invalidate precisely through the key factory in
|
|
|
189
187
|
[query invalidation](https://tanstack.com/query/latest/docs/framework/react/guides/query-invalidation) and
|
|
190
188
|
[automatic invalidation after mutations](https://tkdodo.eu/blog/automatic-query-invalidation-after-mutations).
|
|
191
189
|
|
|
190
|
+
## Audit
|
|
191
|
+
|
|
192
|
+
Inspect the complete path, not the presence of TanStack Query alone: transport returns `unknown`; topic schemas parse
|
|
193
|
+
responses; API types derive from those schemas; keys come from topic factories; API topics expose reusable `queryOptions` and
|
|
194
|
+
`mutationOptions`; hooks consume those options with only local overrides; mutation keys match the configured invalidation
|
|
195
|
+
strategy.
|
|
196
|
+
|
|
192
197
|
## Testing the data layer
|
|
193
198
|
|
|
194
199
|
Stub the network at the `fetch` boundary and let the real query client run: the test then exercises the same parse and error
|
|
195
|
-
path production does. Schemas, clients, and query options are where behaviour worth asserting lives —
|
|
196
|
-
is [testing.md](testing.md).
|
|
200
|
+
path production does. Schemas, clients, and query options are where behaviour worth asserting lives — schema cases are in
|
|
201
|
+
[validation.md](validation.md), and the general philosophy is [testing.md](testing.md).
|
|
@@ -58,7 +58,8 @@ components. When state must be shared between siblings, lift it to the nearest c
|
|
|
58
58
|
State comes in kinds, and each kind has an owner. Work down this list and stop at the first match:
|
|
59
59
|
|
|
60
60
|
1. **URL state** — shareable via the address bar (filters, sort, pagination, active tab) → TanStack Router search params.
|
|
61
|
-
Back button and copied links are UX features you get for free.
|
|
61
|
+
Back button and copied links are UX features you get for free. URL values cross an external boundary; parse them according
|
|
62
|
+
to [validation.md](validation.md).
|
|
62
63
|
2. **Server state** — comes from an API → TanStack Query's cache ([data.md](data.md)). Never copy server data into `useState`
|
|
63
64
|
— that's how stale-UI bugs are born.
|
|
64
65
|
3. **Subtree state** — scoped to a subtree, resets on leave (wizard progress) → React context.
|
|
@@ -66,7 +67,8 @@ State comes in kinds, and each kind has an owner. Work down this list and stop a
|
|
|
66
67
|
5. **Local state** — one component's own (input value, open/closed) → `useState`.
|
|
67
68
|
|
|
68
69
|
`useState` is the right tool for local UI state, and most state is local: whether a panel is open, which tab is active, a
|
|
69
|
-
draft value being typed, a hover flag. Keep those in the component and don't reach for a library.
|
|
70
|
+
draft value being typed, a hover flag. Keep those in the component and don't reach for a library. When a form turns drafts
|
|
71
|
+
into a submitted domain value, validate that boundary as described in [validation.md](validation.md).
|
|
70
72
|
|
|
71
73
|
Most frontends need far less of tier 4 than they think; tiers 1–2 usually dissolve the "we need a store" instinct. For
|
|
72
74
|
structuring the state itself, [Choosing the State Structure](https://react.dev/learn/choosing-the-state-structure) is the
|
|
@@ -11,6 +11,8 @@ Test the **decisions**, not the rendering.
|
|
|
11
11
|
- **Extract the decision out of a hook and test that.** A hook whose interesting part is a plain function is easier to test
|
|
12
12
|
as a plain function than through a render harness. A hook that only wraps a browser API has no decision to extract.
|
|
13
13
|
|
|
14
|
-
The data layer has its own recipe — stub `fetch`, run the real query client — in [data.md](data.md).
|
|
14
|
+
The data layer has its own recipe — stub `fetch`, run the real query client — in [data.md](data.md). A schema whose
|
|
15
|
+
constraints or transforms encode product behavior gets focused accepted, rejected, and transformed cases; see
|
|
16
|
+
[validation.md](validation.md).
|
|
15
17
|
|
|
16
18
|
The measure isn't coverage percentage. It's whether a test failing tells you something you didn't already know.
|
|
@@ -19,7 +19,8 @@ const labels: Record<Size, string> = { sm: "S", md: "M", lg: "L" }; // compiler
|
|
|
19
19
|
```
|
|
20
20
|
|
|
21
21
|
Across boundaries the same rule: library props via `React.ComponentProps<typeof Button>`
|
|
22
|
-
([library-boundary.md](library-boundary.md)),
|
|
22
|
+
([library-boundary.md](library-boundary.md)), untrusted data via a runtime schema and `z.infer`
|
|
23
|
+
([validation.md](validation.md)).
|
|
23
24
|
|
|
24
25
|
- Function signatures: 1–2 positional arguments; at 3+, one destructured object.
|
|
25
26
|
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
# Validation
|
|
2
|
+
|
|
3
|
+
Runtime validation belongs where data crosses from an untrusted representation into frontend-owned values. The schema is the
|
|
4
|
+
single source of truth for both the runtime check and the TypeScript type.
|
|
5
|
+
|
|
6
|
+
## Boundaries
|
|
7
|
+
|
|
8
|
+
Validate once, at the edge:
|
|
9
|
+
|
|
10
|
+
- network responses when they enter the frontend;
|
|
11
|
+
- URL path and search parameters before business logic uses them;
|
|
12
|
+
- persisted browser data when it is read;
|
|
13
|
+
- user input when it becomes a submitted domain value or request value.
|
|
14
|
+
|
|
15
|
+
Code inside that boundary receives parsed values and does not repeat defensive shape checks. An outgoing request built from
|
|
16
|
+
an already parsed domain value is serialized, not validated a second time. A typed client returning a handwritten generic is
|
|
17
|
+
not validation: it only asserts that an untrusted response has the requested type.
|
|
18
|
+
|
|
19
|
+
## Schema first, type derived
|
|
20
|
+
|
|
21
|
+
Use Zod for the runtime schema and derive the type with `z.infer`:
|
|
22
|
+
|
|
23
|
+
```ts
|
|
24
|
+
import { z } from "zod";
|
|
25
|
+
|
|
26
|
+
export const userSchema = z.object({
|
|
27
|
+
id: z.string(),
|
|
28
|
+
email: z.email()
|
|
29
|
+
});
|
|
30
|
+
|
|
31
|
+
export type User = z.infer<typeof userSchema>;
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
Do not maintain a handwritten `User` beside `userSchema`. Request and response shapes follow the same rule when the frontend
|
|
35
|
+
owns or consumes their runtime representation.
|
|
36
|
+
|
|
37
|
+
## TanStack Router search params
|
|
38
|
+
|
|
39
|
+
TanStack Router v1 accepts a Zod v4 schema directly in `validateSearch`; no adapter or parsing wrapper is needed:
|
|
40
|
+
|
|
41
|
+
```tsx
|
|
42
|
+
import { createFileRoute } from "@tanstack/react-router";
|
|
43
|
+
import { z } from "zod";
|
|
44
|
+
|
|
45
|
+
const searchSchema = z.object({
|
|
46
|
+
page: z.number().int().positive().catch(1),
|
|
47
|
+
filter: z.string().catch("")
|
|
48
|
+
});
|
|
49
|
+
|
|
50
|
+
type UserSearch = z.infer<typeof searchSchema>;
|
|
51
|
+
|
|
52
|
+
export const Route = createFileRoute("/users")({
|
|
53
|
+
validateSearch: searchSchema,
|
|
54
|
+
component: Users
|
|
55
|
+
});
|
|
56
|
+
|
|
57
|
+
function Users() {
|
|
58
|
+
const search = Route.useSearch();
|
|
59
|
+
return <UserList page={search.page} filter={search.filter} />;
|
|
60
|
+
}
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
`Route.useSearch()` returns `UserSearch` by inference from `validateSearch`. Use `.catch()` when malformed URL input should
|
|
64
|
+
fall back without interrupting navigation. Use `.default()` only when a missing value gets a default while malformed values
|
|
65
|
+
should still follow the route's validation error path.
|
|
66
|
+
|
|
67
|
+
## Failure handling
|
|
68
|
+
|
|
69
|
+
Use `schema.parse(value)` when invalid data is a contract failure that should follow the normal error path, such as a
|
|
70
|
+
malformed backend response reaching a route error boundary. Use `schema.safeParse(value)` when failure is expected and the
|
|
71
|
+
caller must render or otherwise handle validation issues, such as submitted user input.
|
|
72
|
+
|
|
73
|
+
Transforms and coercion belong in the boundary schema when they are part of entering the domain. Do not scatter trimming,
|
|
74
|
+
number conversion, or defaulting through downstream components.
|
|
75
|
+
|
|
76
|
+
## Audit
|
|
77
|
+
|
|
78
|
+
A boundary is aligned when:
|
|
79
|
+
|
|
80
|
+
- the untrusted source is represented as `unknown` until parsed;
|
|
81
|
+
- a Zod schema parses it at the point of entry;
|
|
82
|
+
- exported TypeScript types use `z.infer<typeof schema>`;
|
|
83
|
+
- downstream code consumes the parsed value without duplicate checks or assertions;
|
|
84
|
+
- parse failures reach the intended error or user-feedback path;
|
|
85
|
+
- behavior-changing schemas have focused tests for accepted, rejected, and transformed values.
|
|
86
|
+
|
|
87
|
+
TanStack Query placement is in [data.md](data.md), general type derivation in [typescript.md](typescript.md), URL and form
|
|
88
|
+
ownership in [react.md](react.md), and test selection in [testing.md](testing.md).
|
|
@@ -1,89 +1,66 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: imf-web-ui-frontend-setup
|
|
3
3
|
description:
|
|
4
|
-
"
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
itself (imf-web-ui-library-setup)."
|
|
4
|
+
"Assess an ImFusion frontend against the project baseline and write a reviewable FRONTEND_SETUP_REPORT.md: new-project
|
|
5
|
+
setup needs, existing-project gaps, alignment migrations, or one named topic (for example data, lifecycle hooks, CSS class
|
|
6
|
+
names, or Prettier). Covers stack, package scripts, tooling, verification, project shape, data, docs, and agent wiring.
|
|
7
|
+
House conventions, not industry standards. This skill inspects and plans; approved implementation is a separate task. Not
|
|
8
|
+
for wiring the library itself (imf-web-ui-library-setup)."
|
|
10
9
|
argument-hint: "[new|audit|align|<topic>]"
|
|
10
|
+
allowed-tools: Read Glob Grep
|
|
11
11
|
---
|
|
12
12
|
|
|
13
13
|
# imf-web-ui-frontend-setup
|
|
14
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
|
-
|
|
50
|
-
|
|
|
51
|
-
|
|
|
52
|
-
|
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
Judge existing docs only against `docs-structure.md`: repo-unique content stays, restated baseline becomes a pointer,
|
|
68
|
-
deviations get named as deviations. Don't rewrite a repo's docs uninvited — report, and let the human pick.
|
|
69
|
-
|
|
70
|
-
## Agent tooling
|
|
71
|
-
|
|
72
|
-
The agent side — vendored skills and their freshness, the lifecycle hooks, the settings registrations — is
|
|
73
|
-
`imf-web-ui-agent-setup`. Delegate to it: in a new project after the docs step, in an audit as one checklist row (skills
|
|
74
|
-
present and current, hooks wired or consciously adapted). Findings it produces report here like any other.
|
|
75
|
-
|
|
76
|
-
## Optional
|
|
77
|
-
|
|
78
|
-
Recommend when the shape calls for it; absence is not a finding.
|
|
79
|
-
|
|
80
|
-
- **knip** — once several people delete things independently.
|
|
81
|
-
- **`eslint-plugin-jsx-a11y`** — anything user-facing.
|
|
82
|
-
|
|
83
|
-
Out of scope, project-specific: CI, env and secrets, error tracking, deploy, dependency updates.
|
|
84
|
-
|
|
85
|
-
## Not this skill
|
|
86
|
-
|
|
87
|
-
- Library wiring (styles import, provider) → `imf-web-ui-library-setup`
|
|
88
|
-
- The conventions themselves → `imf-web-ui-frontend-conventions` and its references — this skill checks the structure exists,
|
|
89
|
-
that skill owns what goes inside it
|
|
15
|
+
You are the frontend setup auditor. Investigate the repository statically, record every supported conclusion in
|
|
16
|
+
`FRONTEND_SETUP_REPORT.md`, then stop for human review. You must follow the applicable `imf-web-ui-frontend-conventions`
|
|
17
|
+
references, cite repository evidence, distinguish defects from working deviations, and never present the baseline as
|
|
18
|
+
universal best practice.
|
|
19
|
+
|
|
20
|
+
## Workflow
|
|
21
|
+
|
|
22
|
+
1. Resolve the requested mode and scope.
|
|
23
|
+
2. Read every applicable convention reference below. For agent tooling, also read the vendored
|
|
24
|
+
`imf-web-ui-agent-setup/SKILL.md` and its templates.
|
|
25
|
+
3. Inspect the repository and write or refresh `FRONTEND_SETUP_REPORT.md` from
|
|
26
|
+
[`templates/FRONTEND_SETUP_REPORT.md`](templates/FRONTEND_SETUP_REPORT.md). The template is the report contract. Preserve
|
|
27
|
+
everything under `## Reviewer notes` verbatim.
|
|
28
|
+
4. Return the report path and a short verdict. Change nothing else; implementation is a separate, approved task.
|
|
29
|
+
|
|
30
|
+
## Safety
|
|
31
|
+
|
|
32
|
+
Use only static inspection: Read, Glob, Grep, and equivalent non-executing search tools. Do not use a shell or invoke Node,
|
|
33
|
+
npm, npx, package scripts, hooks, config imports, linters, tests, builds, Git commands, or project binaries. Read config as
|
|
34
|
+
text and report runtime or machine-local state that cannot be established statically as unverified.
|
|
35
|
+
|
|
36
|
+
Only `FRONTEND_SETUP_REPORT.md` may be written. Write is intentionally not pre-approved in `allowed-tools`; the report
|
|
37
|
+
follows the host's ordinary write approval. Host-managed hooks may run after that write; the skill neither invokes nor
|
|
38
|
+
suppresses them, but it does report broken or unexpected hook behavior found during static inspection.
|
|
39
|
+
|
|
40
|
+
## Modes
|
|
41
|
+
|
|
42
|
+
- **New** — record what exists and what setup work is needed.
|
|
43
|
+
- **Audit** — report broken and missing pieces. A working project convention wins; differences are deviations, not defects.
|
|
44
|
+
- **Align** — use the same evidence, but make deviations explicit migration proposals.
|
|
45
|
+
- **One topic** — resolve any other argument to matching rows below and assess only those. If none match, list the available
|
|
46
|
+
rows instead of guessing or widening scope.
|
|
47
|
+
|
|
48
|
+
## References
|
|
49
|
+
|
|
50
|
+
| Reference | Assess |
|
|
51
|
+
| --------------------------------- | ------------------------------------------------------------------------- |
|
|
52
|
+
| `stack.md` | dependencies, dead-code detection, and matching devtools |
|
|
53
|
+
| `npm-project.md` | package metadata, scripts, pins, npm and Node config |
|
|
54
|
+
| `tooling.md` | Prettier, ESLint, TypeScript, staged files, CSS class names |
|
|
55
|
+
| `git.md` | tracked hooks, verification scopes, staleness wiring |
|
|
56
|
+
| `project-structure.md` | source tree, naming, imports |
|
|
57
|
+
| `components.md` | component folders and colocation |
|
|
58
|
+
| `styling.md` | CSS Modules, tokens, prohibited styling systems |
|
|
59
|
+
| `validation.md` | runtime schemas, boundary parsing, derived types |
|
|
60
|
+
| `data.md` | transport, query/mutation options, keys, invalidation |
|
|
61
|
+
| `docs-structure.md` | README, AGENTS, docs index and content boundaries |
|
|
62
|
+
| `imf-web-ui-agent-setup/SKILL.md` | installed skills, AGENTS fence, lifecycle hooks, registrations, staleness |
|
|
63
|
+
|
|
64
|
+
Knip is required for dead-code detection. `eslint-plugin-jsx-a11y` remains a recommendation when the project is user-facing;
|
|
65
|
+
its absence is not a finding. CI, env and secrets, error tracking, deploy, dependency updates, and library wiring are out of
|
|
66
|
+
scope.
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
# Frontend Setup Report
|
|
2
|
+
|
|
3
|
+
Mode: `<new|audit|align|topic>` Scope: `<all applicable references or resolved topic references>`
|
|
4
|
+
|
|
5
|
+
<!--
|
|
6
|
+
This template is the report contract. Keep every H2 below once and in this order.
|
|
7
|
+
Use `None.` for an empty section.
|
|
8
|
+
|
|
9
|
+
Broken, Missing, Deviations, and Unverified entries use:
|
|
10
|
+
- **[high|medium|low] reference-or-agent-tooling — Short title**
|
|
11
|
+
- Evidence: `path:line`
|
|
12
|
+
- Impact: concrete consequence
|
|
13
|
+
- Next action: smallest selectable follow-up
|
|
14
|
+
|
|
15
|
+
Present entries name the reference and evidence path. Deviations are selectable follow-up work, not defects; in align mode,
|
|
16
|
+
their next actions are migration proposals. Optional tools are not missing findings.
|
|
17
|
+
-->
|
|
18
|
+
|
|
19
|
+
## Verdict
|
|
20
|
+
|
|
21
|
+
<One short assessment of the current frontend setup.>
|
|
22
|
+
|
|
23
|
+
## Broken
|
|
24
|
+
|
|
25
|
+
None.
|
|
26
|
+
|
|
27
|
+
## Missing
|
|
28
|
+
|
|
29
|
+
None.
|
|
30
|
+
|
|
31
|
+
## Deviations
|
|
32
|
+
|
|
33
|
+
None.
|
|
34
|
+
|
|
35
|
+
## Present
|
|
36
|
+
|
|
37
|
+
None.
|
|
38
|
+
|
|
39
|
+
## Unverified
|
|
40
|
+
|
|
41
|
+
None.
|
|
42
|
+
|
|
43
|
+
## Reviewer notes
|
|
44
|
+
|
|
45
|
+
<!-- Human-owned. Preserve everything under this heading verbatim when refreshing the report. -->
|
|
@@ -5,6 +5,7 @@ description:
|
|
|
5
5
|
lifecycle hooks, verify the base update, then audit and optionally migrate affected or custom consumer components in a
|
|
6
6
|
separate approved commit."
|
|
7
7
|
argument-hint: "[--dry-run] [optional version or reason]"
|
|
8
|
+
allowed-tools: Bash Read Grep
|
|
8
9
|
---
|
|
9
10
|
|
|
10
11
|
# imf-web-ui-update
|