@imfusion/web-ui 0.6.1-dev.27.gfc6e5abb → 0.6.1-dev.3.g5b432448
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,44 +1,50 @@
|
|
|
1
1
|
# Tooling
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
Dependency and configuration baseline for an ImFusion frontend; check before adding a dependency and before writing its
|
|
4
|
+
config.
|
|
4
5
|
|
|
5
6
|
## Topic-to-tool map
|
|
6
7
|
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
|
10
|
-
|
|
|
11
|
-
|
|
|
12
|
-
|
|
|
13
|
-
|
|
|
14
|
-
|
|
|
15
|
-
|
|
|
16
|
-
|
|
|
17
|
-
|
|
|
18
|
-
|
|
|
19
|
-
|
|
|
20
|
-
|
|
|
21
|
-
|
|
|
8
|
+
- Use the mapped tool for each topic; prefer typed config (`.ts` over `.json`) where the tool supports it.
|
|
9
|
+
|
|
10
|
+
| Topic | Tool |
|
|
11
|
+
| --------------------- | ----------------------------------------------------------------------------------------------------- |
|
|
12
|
+
| Build | [Vite](https://vite.dev) |
|
|
13
|
+
| Routing, URL state | [TanStack Router](https://tanstack.com/router) — file-based, type-safe search params |
|
|
14
|
+
| Server state | [TanStack Query](https://tanstack.com/query) — the pattern around it is [data.md](data.md) |
|
|
15
|
+
| Forms | [TanStack Form](https://tanstack.com/form) |
|
|
16
|
+
| Data grids | [TanStack Table](https://tanstack.com/table) + web-ui's styled `Table` parts |
|
|
17
|
+
| App-wide client state | [TanStack Store](https://tanstack.com/store) — last resort in the state ladder ([react.md](react.md)) |
|
|
18
|
+
| Schema validation | [Zod](https://zod.dev) — at the network boundary ([data.md](data.md)) |
|
|
19
|
+
| Styling | CSS Modules ([styling.md](styling.md)) |
|
|
20
|
+
| Test | [Vitest](https://vitest.dev) |
|
|
21
|
+
| Format | [Prettier](https://prettier.io) |
|
|
22
|
+
| Lint | [ESLint](https://eslint.org) flat config |
|
|
23
|
+
| Types | `tsc --noEmit` — own script, own CI step |
|
|
24
|
+
| Staged files | [lint-staged](https://github.com/lint-staged/lint-staged) (or nano-staged, drop-in) |
|
|
25
|
+
| Dead code | [Knip](https://knipjs.dev) via `verify:knip` — needs per-repo config |
|
|
22
26
|
|
|
23
27
|
## When a library owns a layer
|
|
24
28
|
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
29
|
+
- Adopt the library once you're rebuilding what it does — validation timing and cross-field rules (Form), caching and
|
|
30
|
+
refetching (Query), URL as source of truth (Router), sorting/pagination over rows (Table): adding it mid-project is cheap,
|
|
31
|
+
unpicking a hand-rolled version later is not.
|
|
28
32
|
|
|
29
33
|
## Devtools
|
|
30
34
|
|
|
31
|
-
|
|
32
|
-
devtools
|
|
35
|
+
- Every TanStack library with a devtools package gets it as a dev dependency, mounted in development only — Router's
|
|
36
|
+
`@tanstack/react-router-devtools` is a given; Query's goes in when Query does.
|
|
37
|
+
- Check for a `-devtools` sibling on every new TanStack dependency — not every library has one yet.
|
|
38
|
+
- Once several are in, host them in one panel via `@tanstack/devtools`.
|
|
33
39
|
|
|
34
40
|
## Docs over memory
|
|
35
41
|
|
|
36
|
-
|
|
37
|
-
TanStack
|
|
42
|
+
- `npx @tanstack/cli` for TanStack docs — never work from memory.
|
|
43
|
+
- Where `@tanstack/intent` is wired up, use it to reach and read the Agent Skills the TanStack dependencies ship.
|
|
38
44
|
|
|
39
45
|
## Prettier
|
|
40
46
|
|
|
41
|
-
|
|
47
|
+
- Config file shape is free (`.prettierrc`, `prettier.config.ts`); the values are not:
|
|
42
48
|
|
|
43
49
|
```ts
|
|
44
50
|
import type { Config } from "prettier";
|
|
@@ -53,36 +59,58 @@ const config: Config = {
|
|
|
53
59
|
singleQuote: false,
|
|
54
60
|
proseWrap: "always"
|
|
55
61
|
};
|
|
56
|
-
|
|
57
|
-
export default config;
|
|
58
62
|
```
|
|
59
63
|
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
+
- Never omit the config file — no file means defaults, and the values silently differ.
|
|
65
|
+
|
|
66
|
+
## ESLint
|
|
67
|
+
|
|
68
|
+
Flat config (`eslint.config.ts`):
|
|
69
|
+
|
|
70
|
+
- `strictTypeChecked` + `stylisticTypeChecked`, `projectService: true`
|
|
71
|
+
- `as` and `!` banned outside tests (`consistent-type-assertions`)
|
|
72
|
+
- `.gitignore` as the ignore source (`includeIgnoreFile` from `@eslint/compat`)
|
|
73
|
+
- `#/` alias enforced via `no-restricted-imports` banning `../*` — parent-relative paths error, siblings (`./`) stay relative
|
|
74
|
+
([project-structure.md](project-structure.md))
|
|
75
|
+
|
|
76
|
+
## tsconfig
|
|
77
|
+
|
|
78
|
+
```jsonc
|
|
79
|
+
{
|
|
80
|
+
"compilerOptions": {
|
|
81
|
+
"strict": true,
|
|
82
|
+
"moduleResolution": "bundler",
|
|
83
|
+
"verbatimModuleSyntax": true, // import type stays import type
|
|
84
|
+
"noUnusedLocals": true,
|
|
85
|
+
"noUnusedParameters": true,
|
|
86
|
+
"noFallthroughCasesInSwitch": true,
|
|
87
|
+
"noUncheckedSideEffectImports": true,
|
|
88
|
+
"skipLibCheck": true,
|
|
89
|
+
"paths": { "#/*": ["./src/*"] }
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
```
|
|
64
93
|
|
|
65
|
-
|
|
66
|
-
`import type` for type-only imports.
|
|
94
|
+
- `#/` → `src/` alias rationale: [project-structure.md](project-structure.md).
|
|
67
95
|
|
|
68
96
|
## Staged files
|
|
69
97
|
|
|
70
|
-
|
|
71
|
-
|
|
98
|
+
- Runner config (lint-staged or nano-staged) applies eslint `--fix` and prettier `--write` to staged files only.
|
|
99
|
+
- The pre-commit runner also invokes `verify:knip` when staged source or project config can change the reachability graph.
|
|
72
100
|
|
|
73
101
|
## CSS class names
|
|
74
102
|
|
|
75
|
-
|
|
76
|
-
|
|
103
|
+
- Generated CSS Module class names are readable in the DOM, `{prefix}-{file}-{local}`, never the default hash: a legible DOM
|
|
104
|
+
is what makes devtools and browser automation usable.
|
|
105
|
+
- The library ships the plugin; pass a short, app-scoped prefix:
|
|
77
106
|
|
|
78
107
|
```ts
|
|
79
|
-
import { defineConfig } from "vite";
|
|
80
|
-
import react from "@vitejs/plugin-react";
|
|
81
108
|
import { readableCssModuleNames } from "@imfusion/web-ui/build/vite-css-module-names";
|
|
82
109
|
|
|
83
110
|
export default defineConfig({
|
|
84
|
-
plugins: [react(), readableCssModuleNames({ prefix: "
|
|
111
|
+
plugins: [react(), readableCssModuleNames({ prefix: "acme" })]
|
|
85
112
|
});
|
|
86
113
|
```
|
|
87
114
|
|
|
88
|
-
|
|
115
|
+
- One pattern for dev, Storybook, and production: register the plugin in **every** tool that compiles the CSS — a compiler
|
|
116
|
+
left out generates different names for the same source, and its styles silently don't apply.
|
|
@@ -1,49 +1,73 @@
|
|
|
1
|
-
# TypeScript
|
|
1
|
+
# TypeScript & code style
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
Functional by default: pure functions over stateful classes, immutable data over in-place mutation, expressions over
|
|
4
|
+
statements, side effects at the edges (network, DOM, store).
|
|
4
5
|
|
|
5
6
|
## Types
|
|
6
7
|
|
|
7
|
-
-
|
|
8
|
-
- Infer
|
|
9
|
-
-
|
|
10
|
-
-
|
|
11
|
-
-
|
|
12
|
-
- Use one or two positional arguments. At three or more, pass a named object.
|
|
8
|
+
- No `any`. `unknown` at a boundary you can't type, narrowed before use.
|
|
9
|
+
- Infer locals; annotate contracts. Exported functions get an explicit return type.
|
|
10
|
+
- No temporal coupling — model the states instead of initialising `null` and filling in later.
|
|
11
|
+
- Avoid `as`. Fix the type. The honest exception: an untyped third-party boundary, kept at the boundary.
|
|
12
|
+
- Derive, don't duplicate:
|
|
13
13
|
|
|
14
14
|
```ts
|
|
15
15
|
const sizes = ["sm", "md", "lg"] as const;
|
|
16
16
|
type Size = (typeof sizes)[number];
|
|
17
17
|
|
|
18
|
-
const labels: Record<Size, string> = {
|
|
19
|
-
sm: "S",
|
|
20
|
-
md: "M",
|
|
21
|
-
lg: "L"
|
|
22
|
-
};
|
|
18
|
+
const labels: Record<Size, string> = { sm: "S", md: "M", lg: "L" }; // compiler breaks if `sizes` changes
|
|
23
19
|
```
|
|
24
20
|
|
|
25
|
-
|
|
21
|
+
- Same rule across boundaries: library props via `React.ComponentProps<typeof Button>`
|
|
22
|
+
([library-boundary.md](library-boundary.md)), untrusted data via a runtime schema and `z.infer`
|
|
23
|
+
([validation.md](validation.md)).
|
|
24
|
+
- Function signatures: 1–2 positional arguments; at 3+, one destructured object.
|
|
26
25
|
|
|
27
|
-
|
|
28
|
-
input. Use `toSorted` and `toReversed` instead of their mutating counterparts.
|
|
26
|
+
## Immutability & expressions
|
|
29
27
|
|
|
30
|
-
|
|
31
|
-
named intermediate values.
|
|
28
|
+
- Array methods before loops — `map`, `filter`, `find`, `some`, `flatMap` name what they do:
|
|
32
29
|
|
|
33
|
-
|
|
30
|
+
```ts
|
|
31
|
+
const activeNames = users.filter(u => u.isActive).map(u => u.name);
|
|
32
|
+
```
|
|
34
33
|
|
|
35
|
-
|
|
36
|
-
|
|
34
|
+
- Produce new values: spreads and `structuredClone` over in-place edits, `toSorted`/`toReversed` over `sort`/`reverse` (which
|
|
35
|
+
mutate their receiver).
|
|
36
|
+
- Allowed exceptions: a genuine early exit (`for` + `break`), a measured hot loop.
|
|
37
|
+
- Keep chains flat: 3–4 steps read well; longer wants named intermediates, and a `reduce` doing four things wants to be a
|
|
38
|
+
loop.
|
|
39
|
+
|
|
40
|
+
## Naming
|
|
37
41
|
|
|
38
|
-
|
|
42
|
+
- Say what it is, not what it's made of: `useUserQuery`, not `useUserHook`; `retryDelay`, not `num`.
|
|
43
|
+
- Booleans read as assertions: `isOpen`, `hasAccess`, `canSubmit`.
|
|
44
|
+
- Handlers: `onX` as props, `handleX` as implementations.
|
|
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:
|
|
39
48
|
|
|
40
49
|
```tsx
|
|
41
|
-
const search = Route.useSearch();
|
|
42
|
-
const user = useSuspenseQuery(context.api.user.getDetails());
|
|
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());
|
|
43
53
|
|
|
44
54
|
search.page;
|
|
45
55
|
user.data.name;
|
|
56
|
+
updateUser.mutate(values);
|
|
57
|
+
updateUser.isPending;
|
|
46
58
|
```
|
|
47
59
|
|
|
48
|
-
|
|
49
|
-
|
|
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
|
+
```
|
|
@@ -1,22 +1,20 @@
|
|
|
1
1
|
# Validation
|
|
2
2
|
|
|
3
|
-
Validate data
|
|
3
|
+
Validate where data crosses from untrusted representation into frontend-owned values; the schema is the single source of
|
|
4
|
+
truth for runtime check and TypeScript type.
|
|
4
5
|
|
|
5
6
|
## Boundaries
|
|
6
7
|
|
|
7
|
-
Validate once at the edge:
|
|
8
|
-
|
|
9
|
-
-
|
|
10
|
-
-
|
|
11
|
-
-
|
|
12
|
-
- user input when it becomes a submitted domain or request value.
|
|
13
|
-
|
|
14
|
-
After the boundary, use parsed values. A generic on a typed client only tells TypeScript what you hope the response looks
|
|
15
|
-
like; it does not validate it.
|
|
8
|
+
- Validate once, at the edge: network responses on entry; URL path and search params before business logic; persisted browser
|
|
9
|
+
data on read; user input becoming a submitted domain or request value.
|
|
10
|
+
- Inside the boundary: parsed values only, no repeated defensive shape checks.
|
|
11
|
+
- Outgoing requests built from already parsed domain values are serialized, not re-validated.
|
|
12
|
+
- A typed client's handwritten generic is not validation — it only asserts a type onto an untrusted response.
|
|
16
13
|
|
|
17
14
|
## Schema first, type derived
|
|
18
15
|
|
|
19
|
-
|
|
16
|
+
- Zod schema, type via `z.infer`; never a handwritten type beside its schema.
|
|
17
|
+
- Same rule for request and response shapes the frontend owns or consumes at runtime.
|
|
20
18
|
|
|
21
19
|
```ts
|
|
22
20
|
import { z } from "zod";
|
|
@@ -29,13 +27,17 @@ export const userSchema = z.object({
|
|
|
29
27
|
export type User = z.infer<typeof userSchema>;
|
|
30
28
|
```
|
|
31
29
|
|
|
32
|
-
Apply the same rule to request and response shapes the frontend owns at runtime.
|
|
33
|
-
|
|
34
30
|
## TanStack Router search params
|
|
35
31
|
|
|
36
|
-
|
|
32
|
+
- `validateSearch` takes a Zod v4 schema directly (TanStack Router v1) — no adapter or parsing wrapper.
|
|
33
|
+
- `Route.useSearch()` infers its type from `validateSearch`.
|
|
34
|
+
- `.catch()`: malformed URL input falls back without interrupting navigation.
|
|
35
|
+
- `.default()`: only for missing values; malformed values still follow the route's validation error path.
|
|
37
36
|
|
|
38
37
|
```tsx
|
|
38
|
+
import { createFileRoute } from "@tanstack/react-router";
|
|
39
|
+
import { z } from "zod";
|
|
40
|
+
|
|
39
41
|
const searchSchema = z.object({
|
|
40
42
|
page: z.number().int().positive().catch(1),
|
|
41
43
|
filter: z.string().catch("")
|
|
@@ -45,12 +47,16 @@ export const Route = createFileRoute("/users")({
|
|
|
45
47
|
validateSearch: searchSchema,
|
|
46
48
|
component: Users
|
|
47
49
|
});
|
|
48
|
-
```
|
|
49
50
|
|
|
50
|
-
|
|
51
|
+
function Users() {
|
|
52
|
+
const search = Route.useSearch(); // inferred: z.infer<typeof searchSchema>
|
|
53
|
+
return <UserList page={search.page} filter={search.filter} />;
|
|
54
|
+
}
|
|
55
|
+
```
|
|
51
56
|
|
|
52
57
|
## Failure handling
|
|
53
58
|
|
|
54
|
-
-
|
|
55
|
-
|
|
56
|
-
-
|
|
59
|
+
- `schema.parse`: invalid data is a contract failure on the normal error path (malformed backend response → route error
|
|
60
|
+
boundary).
|
|
61
|
+
- `schema.safeParse`: failure is expected and the caller handles the issues (submitted user input).
|
|
62
|
+
- Transforms and coercion live in the boundary schema — never scatter trimming, number conversion, or defaulting downstream.
|
|
@@ -1,68 +1,87 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: imf-web-ui-setup
|
|
3
3
|
description:
|
|
4
|
-
"Plan and, after explicit approval, bootstrap
|
|
5
|
-
|
|
6
|
-
|
|
4
|
+
"Plan and, after explicit approval, bootstrap an ImFusion frontend against the conventions baseline: library setup,
|
|
5
|
+
tooling, git, npm project, authentication, project structure, docs structure, data, testing, or agent tooling. Inspect
|
|
6
|
+
statically first and write only the approved files. Use imf-web-ui-audit for read-only health checks or topics with no
|
|
7
|
+
setup action."
|
|
7
8
|
argument-hint: "[full|library-setup|tooling|git|npm-project|authentication|project-structure|docs-structure|data|testing|agent-tooling]"
|
|
8
9
|
allowed-tools: Read Glob Grep Write
|
|
9
10
|
---
|
|
10
11
|
|
|
11
|
-
#
|
|
12
|
+
# imf-web-ui-setup
|
|
12
13
|
|
|
13
|
-
|
|
14
|
-
|
|
14
|
+
You are the frontend bootstrap planner. Inspect the repository statically, read the applicable `imf-web-ui-conventions`
|
|
15
|
+
topics, and prepare a complete proposal for every file you would create or change. The project wins where it already has a
|
|
16
|
+
working convention. This skill is plan-first: enter the host's plan mode before presenting the proposal, and do not create a
|
|
17
|
+
report file as a substitute for the host plan.
|
|
15
18
|
|
|
16
19
|
## Workflow
|
|
17
20
|
|
|
18
|
-
1. Resolve the argument. Bare means `full
|
|
19
|
-
|
|
20
|
-
|
|
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.
|
|
27
|
+
2. Enter the host's plan mode. If it is not already active, use the host plan-mode control before inspecting and planning.
|
|
21
28
|
3. Read the selected convention topics and inspect the repository with `Read`, `Glob`, and `Grep` only.
|
|
22
|
-
4.
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
29
|
+
4. Build the complete proposal in the host plan from the shared report contract at
|
|
30
|
+
[`../imf-web-ui-conventions/templates/REPORT.md`](../imf-web-ui-conventions/templates/REPORT.md). Include the concrete
|
|
31
|
+
content of every file the approved setup would create or change, with repository evidence for each decision.
|
|
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)).
|
|
28
43
|
|
|
29
|
-
|
|
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.
|
|
30
46
|
|
|
31
|
-
|
|
47
|
+
6. Keep the plan as the approval gate. After the host approves and exits plan mode, write only the listed files. Complete any
|
|
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.
|
|
32
51
|
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
- a minimal `AppShell` in `_app/`, unless the user says the product has no persistent authenticated navigation;
|
|
37
|
-
- an API topic folder for data shown by the first screen;
|
|
38
|
-
- the root provider and library wiring.
|
|
52
|
+
Installer and hook runs stay with the human: an `agent-tooling` proposal lists the `npx web-ui-install` commands as human
|
|
53
|
+
steps, applies the judgment from the topic (read existing registrations first, never stack a hook on a covered event), and
|
|
54
|
+
includes the topic's Codex trust follow-up whenever hooks are part of the plan.
|
|
39
55
|
|
|
40
|
-
|
|
56
|
+
## Checklist
|
|
41
57
|
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
not stack a hook on an event the project already covers. Include the Codex trust review when hooks are part of the plan.
|
|
58
|
+
The post-implementation audit uses the shared
|
|
59
|
+
[convention audit checklist](../imf-web-ui-conventions/templates/AUDIT_CHECKLIST.md) to verify the complete baseline, not
|
|
60
|
+
only the setup topic selected at the start.
|
|
46
61
|
|
|
47
62
|
## Safety
|
|
48
63
|
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
64
|
+
Use only static inspection: `Read`, `Glob`, and `Grep`. Do not use a shell or invoke Node, npm, npx, package scripts, hooks,
|
|
65
|
+
config imports, linters, tests, builds, Git commands, project binaries, installers, or package managers. Read config as text
|
|
66
|
+
and report runtime or machine-local state that cannot be established statically as unverified. After approval, `Write` is
|
|
67
|
+
limited to the files listed in the approved report; anything needing execution goes in the plan for the human.
|
|
68
|
+
|
|
69
|
+
## Setup topics
|
|
52
70
|
|
|
53
|
-
|
|
71
|
+
`full` covers every topic below. A one-topic run assesses only that topic.
|
|
54
72
|
|
|
55
|
-
| Topic |
|
|
56
|
-
| ------------------- |
|
|
57
|
-
| `library-setup` |
|
|
58
|
-
| `tooling` |
|
|
59
|
-
| `git` |
|
|
60
|
-
| `npm-project` |
|
|
61
|
-
| `authentication` |
|
|
62
|
-
| `project-structure` |
|
|
63
|
-
| `docs-structure` | README, AGENTS, docs index, and content boundaries
|
|
64
|
-
| `data` |
|
|
65
|
-
| `testing` |
|
|
66
|
-
| `agent-tooling` |
|
|
73
|
+
| Topic | Assess and plan |
|
|
74
|
+
| ------------------- | ------------------------------------------------------------------------------ |
|
|
75
|
+
| `library-setup` | styles import, `WebUIProvider`, and library package wiring |
|
|
76
|
+
| `tooling` | dependency selection, devtools, Prettier, ESLint, TypeScript, and verification |
|
|
77
|
+
| `git` | tracked hooks, verification scopes, and staleness wiring |
|
|
78
|
+
| `npm-project` | package metadata, scripts, pins, npm, and Node configuration |
|
|
79
|
+
| `authentication` | current-user query, public/app guards, login, and logout |
|
|
80
|
+
| `project-structure` | source tree, route groups, optional app shell, naming, and placement |
|
|
81
|
+
| `docs-structure` | README, AGENTS, docs index, and content boundaries |
|
|
82
|
+
| `data` | transport, schemas, query/mutation options, keys, and invalidation |
|
|
83
|
+
| `testing` | test boundaries and verification coverage |
|
|
84
|
+
| `agent-tooling` | vendored skills, AGENTS fence, lifecycle hooks, registrations, and staleness |
|
|
67
85
|
|
|
68
|
-
|
|
86
|
+
Setup has no file-creation action for `react`, `typescript`, `class-names`, `validation`, `components`, `styling`, `assets`,
|
|
87
|
+
`library-boundary`, or `tokens`; select those in `imf-web-ui-audit`.
|