@imfusion/web-ui 0.6.1-dev.3.g5b432448 → 0.6.1-dev.33.g665111df

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (60) hide show
  1. package/README.md +102 -169
  2. package/bin/install.js +28 -10
  3. package/bin/install.test.ts +19 -0
  4. package/dist/code-BFMQnmu9.js +147 -0
  5. package/dist/codegen/gen-code-highlight-theme.d.ts +1 -0
  6. package/dist/components/code/code.d.ts +5 -4
  7. package/dist/components/stack/stack.d.ts +1 -1
  8. package/dist/components/toast/index.d.ts +2 -0
  9. package/dist/components/toast/toast.d.ts +200 -0
  10. package/dist/components/toast/toast.meta.d.ts +2 -0
  11. package/dist/components/typo/typo.d.ts +23 -22
  12. package/dist/icons/icon-config.d.ts +12 -0
  13. package/dist/{icons-wBmF0U2x.js → icons-Cy1HAosO.js} +1 -1
  14. package/dist/icons.js +1 -1
  15. package/dist/index.d.ts +1 -0
  16. package/dist/index.js +1278 -1069
  17. package/dist/integrations/code-highlight/highlighter.d.ts +24 -0
  18. package/dist/integrations/code-highlight.js +80 -47
  19. package/dist/integrations/image-display-options.js +2 -2
  20. package/dist/provider/web-ui-provider.d.ts +3 -3
  21. package/dist/style.css +1 -1
  22. package/dist/{tabs-CMKvMF4E.js → tabs-DIe1Utiy.js} +2 -0
  23. package/package.json +5 -4
  24. package/src/docgen/doc.gen.json +515 -1
  25. package/src/llms/install-templates/AGENTS.md +15 -18
  26. package/src/llms/llms.gen.txt +39 -33
  27. package/src/llms/skills/imf-web-ui/SKILL.md +30 -39
  28. package/src/llms/skills/imf-web-ui-audit/SKILL.md +50 -102
  29. package/src/llms/skills/imf-web-ui-components/SKILL.md +47 -104
  30. package/src/llms/skills/imf-web-ui-conventions/SKILL.md +44 -52
  31. package/src/llms/skills/imf-web-ui-conventions/templates/AUDIT_CHECKLIST.md +1 -0
  32. package/src/llms/skills/imf-web-ui-conventions/topics/agent-tooling.md +40 -62
  33. package/src/llms/skills/imf-web-ui-conventions/topics/assets.md +11 -12
  34. package/src/llms/skills/imf-web-ui-conventions/topics/authentication.md +31 -46
  35. package/src/llms/skills/imf-web-ui-conventions/topics/class-names.md +18 -23
  36. package/src/llms/skills/imf-web-ui-conventions/topics/components.md +20 -69
  37. package/src/llms/skills/imf-web-ui-conventions/topics/data.md +50 -146
  38. package/src/llms/skills/imf-web-ui-conventions/topics/docs-structure.md +17 -23
  39. package/src/llms/skills/imf-web-ui-conventions/topics/git.md +15 -20
  40. package/src/llms/skills/imf-web-ui-conventions/topics/library-boundary.md +28 -19
  41. package/src/llms/skills/imf-web-ui-conventions/topics/library-setup.md +20 -16
  42. package/src/llms/skills/imf-web-ui-conventions/topics/npm-project.md +28 -42
  43. package/src/llms/skills/imf-web-ui-conventions/topics/project-structure.md +28 -30
  44. package/src/llms/skills/imf-web-ui-conventions/topics/react.md +28 -74
  45. package/src/llms/skills/imf-web-ui-conventions/topics/styling.md +65 -62
  46. package/src/llms/skills/imf-web-ui-conventions/topics/testing.md +12 -14
  47. package/src/llms/skills/imf-web-ui-conventions/topics/tokens.md +9 -4
  48. package/src/llms/skills/imf-web-ui-conventions/topics/tooling.md +40 -68
  49. package/src/llms/skills/imf-web-ui-conventions/topics/typescript.md +26 -50
  50. package/src/llms/skills/imf-web-ui-conventions/topics/validation.md +19 -25
  51. package/src/llms/skills/imf-web-ui-setup/SKILL.md +45 -64
  52. package/src/llms/skills/imf-web-ui-update/SKILL.md +48 -114
  53. package/src/llms/skills/imf-web-ui-ux/SKILL.md +64 -92
  54. package/src/llms/skills/imf-web-ui-ux/references/forms.md +16 -36
  55. package/src/llms/skills/imf-web-ui-ux/references/usability-heuristics.md +14 -27
  56. package/src/llms/skills/imf-web-ui-ux/references/visual-design.md +22 -38
  57. package/src/llms/tokens.gen.json +5 -5
  58. package/dist/code-Blo48PGr.js +0 -136
  59. package/dist/icons/icon-config-provider.d.ts +0 -8
  60. package/dist/icons/icon-context.d.ts +0 -4
package/README.md CHANGED
@@ -1,227 +1,160 @@
1
- # Web UI
1
+ # @imfusion/web-ui
2
2
 
3
- `@imfusion/web-ui` — the official shared Web UI library for ImFusion web apps, built on Base UI.
3
+ The shared React UI library for ImFusion web apps. It provides accessible primitives, ImFusion tokens, and one public import
4
+ surface. Base UI supplies behavior for the primitives that need it; consumers do not depend on Base UI directly.
4
5
 
5
- - [Usage](#usage) — install, wire up, and keep the version current
6
- - [Documentation](#documentation) — Storybook and the developer docs
7
- - [Development](#development) — working on the library itself, including the Agent Skills
8
- - [Releasing](#releasing) — how versions are derived and how to cut one
6
+ - [Use the library](#use-the-library)
7
+ - [Read the docs](#read-the-docs)
8
+ - [Work on the library](#work-on-the-library)
9
+ - [Release it](#release-it)
9
10
 
10
- ## Usage
11
+ ## Use the library
11
12
 
12
- The packages are private on npmjs.com.
13
+ The package is private. Get the Web SDK npm token from the
14
+ [Test Licenses page](https://imfusion.atlassian.net/wiki/spaces/DEV/pages/255590402/Test+Licenses), then save it in your
15
+ user-level npm config:
13
16
 
14
- To install them, get the Web SDK npm token from the
15
- [Test Licenses](https://imfusion.atlassian.net/wiki/spaces/DEV/pages/255590402/Test+Licenses) page on Confluence and add it
16
- to your user-level `.npmrc`:
17
-
18
- ```bash
17
+ ```sh
19
18
  npm config set //registry.npmjs.org/:_authToken=<token> --location=user
20
19
  ```
21
20
 
22
- Then:
21
+ Install the latest release:
23
22
 
24
- ```bash
23
+ ```sh
25
24
  npm install @imfusion/web-ui
26
25
  ```
27
26
 
28
- Or if you want to install the latest CI build from master:
27
+ To follow builds from `master`, use the `dev` dist-tag:
29
28
 
30
- ```bash
29
+ ```sh
31
30
  npm install @imfusion/web-ui@dev
32
31
  ```
33
32
 
34
- Import the stylesheet and wrap your app root once:
33
+ Import the stylesheet and mount the provider once at your app root:
35
34
 
36
35
  ```tsx
37
36
  import "@imfusion/web-ui/styles.css";
38
37
  import { WebUIProvider } from "@imfusion/web-ui";
39
- ```
40
-
41
- ### LLM integration
42
38
 
43
- The `web-ui` package does offer first-class support for LLMs, but it's not wired up by default.
44
-
45
- To install the skills, run this command after the package is installed:
46
-
47
- ```bash
48
- npx web-ui-install
39
+ export function App() {
40
+ return <WebUIProvider>{/* app */}</WebUIProvider>;
41
+ }
49
42
  ```
50
43
 
51
- The binary asks which LLM client you use and installs everything it needs. Run it again after a version bump and it refreshes
52
- the directories it already installed into, without asking again — `--reconfigure` re-opens that choice.
53
-
54
- The optional `--hooks` flag also installs the agent lifecycle hooks and registers them for both hosts, in
55
- `.claude/settings.json` (Claude Code) and `.codex/hooks.json` (Codex). Three hooks inject one fixed line each: `SessionStart`
56
- and `SubagentStart` point the agent at the `imf-web-ui` skills router, and `UserPromptSubmit` names the companion skills to
57
- consult per task. A fourth, the `Stop` gate, blocks a turn that edited source files once, until the agent has addressed the
58
- project's verification. Re-running the installer refreshes the scripts and prunes retired ones along with their
59
- registrations. Without `--hooks`, the skills are still available but no lifecycle hook runs. The full flow is documented in
60
- the shipped [`agent-tooling` topic](./src/llms/skills/imf-web-ui-conventions/topics/agent-tooling.md) of the conventions
61
- skill.
62
-
63
- **Available consumer skills - `/imf-web-ui-*`**
64
-
65
- | Skill | What it does |
66
- | ------------------------- | ------------------------------------------------------------------------------ |
67
- | `/imf-web-ui` | The router: decides whether guidance is needed, then which companion to open. |
68
- | `/imf-web-ui-setup` | Plan and, after approval, bootstrap a consumer project by topic. |
69
- | `/imf-web-ui-components` | Component and icon reference — what exists and how it's meant to be used. |
70
- | `/imf-web-ui-ux` | UX guidance for building interfaces with the library. |
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, ending in a plan you approve. |
73
- | `/imf-web-ui-update` | Update the library, skills, and optional hooks, then verify before committing. |
74
-
75
- Start at `/imf-web-ui` — it routes to the rest. Storybook's **User Guide → AI Agents** page covers the whole family.
76
-
77
- ### Versions and updates
78
-
79
- Every merge to master publishes a new build under the `dev` dist-tag. Which spec you install decides how you pick those up:
80
-
81
- | Spec in `package.json` | Gets | Update with |
82
- | ---------------------------------- | -------------------------- | ------------------------------ |
83
- | `"@imfusion/web-ui": "^0.5.0"` | matching releases | `npm update @imfusion/web-ui` |
84
- | `"@imfusion/web-ui": "latest"` | the newest release | `npm update @imfusion/web-ui` |
85
- | `"@imfusion/web-ui": "dev"` | the newest build of master | `npm update @imfusion/web-ui` |
86
- | `"@imfusion/web-ui": "file:….tgz"` | a packed tarball, frozen | re-pack and re-install by hand |
87
-
88
- - **Two dist-tags.** `latest` moves when a release is tagged, `dev` on every build of master (and onto the release when one
89
- is cut).
90
- - **A range like `^0.5.0` is the usual choice.** It tracks releases and states which major you expect; bare `latest` follows
91
- releases across majors, breaking changes included.
92
- - **Dist-tag specs stay literal.** npm keeps `dev` or `latest` as-is in `package.json` and re-resolves on every `npm update`.
93
- The concrete version lands in `package-lock.json`, so builds stay reproducible until you update.
94
- - **Track `dev` while building against the library**, to get new components as they land. Use a release spec for anything you
95
- cut a production release from, since `dev` moves whenever someone merges.
96
- - **A `file:` tarball never updates.** npm copies the archive into `node_modules` and re-copies the same one on every
97
- install. Switch to `dev` or a version range to get updates.
98
-
99
- ## Documentation
100
-
101
- **[Storybook](https://storybook.js.org/)** is the documentation platform — the component catalog, every prop, and the setup
102
- guides. It isn't hosted yet, so run it locally:
103
-
104
- ```bash
105
- npm run dev # builds the library, then Storybook + a rebuild watcher
106
- ```
107
-
108
- See the [Developer Docs](./docs/README.md).
109
-
110
- ## Development
44
+ ### Agent skills
111
45
 
112
- Install the deps and configure git:
46
+ The package can install optional skills for agents working in a consumer project:
113
47
 
114
- ```bash
115
- npm install
116
- npm run git:config # hooks path + rebase-only pull/merge
48
+ ```sh
49
+ npx web-ui-install
117
50
  ```
118
51
 
119
- **Try out **`/web-ui-dev-getting-started`** for an ai assisted start.**
52
+ Run the command again after updating the package. It refreshes the skills already installed in the project. Use
53
+ `--reconfigure` to choose a different target. Add `--hooks` to install the lifecycle hooks for Claude Code and Codex.
120
54
 
121
- ### LLM integration
55
+ Start with `/imf-web-ui`. It routes a task to the companion skills it needs, or tells the agent to work without extra
56
+ guidance.
122
57
 
123
- Web UI development skills use a `/web-ui-dev-*` prefix. `documentation-writer` comes from `npx skills`; it is not a native
124
- Web UI skill.
58
+ | Skill | Use it for |
59
+ | ------------------------- | ------------------------------------------------------------ |
60
+ | `/imf-web-ui` | Route UI work to the right companion. |
61
+ | `/imf-web-ui-setup` | Plan library wiring, project setup, or tooling changes. |
62
+ | `/imf-web-ui-components` | Look up component and icon APIs. |
63
+ | `/imf-web-ui-ux` | Choose components and shape screens and flows. |
64
+ | `/imf-web-ui-conventions` | Follow the frontend conventions and token seams. |
65
+ | `/imf-web-ui-audit` | Inspect an existing frontend without changing it. |
66
+ | `/imf-web-ui-update` | Update the package, skills, and hooks in a consumer project. |
125
67
 
126
- | Skill | What it does |
127
- | ----------------------------------------- | ----------------------------------------------------------------------------------------------------------------------- |
128
- | `/documentation-writer` | External `npx skills` workflow for Diátaxis documentation. |
129
- | `/web-ui-dev-getting-started` | Interactive intro — gauges your experience, works out your goal, routes you. |
130
- | `/web-ui-dev-start` | Starting ritual for any task: Jira context, `master` vs. a worktree, context summary. |
131
- | `/web-ui-dev-new-component` | Scaffolds an architecture-compliant primitive (adapted or absorbed). |
132
- | `/web-ui-dev-update-component` | Pointers to every file a prop, variant, or sub-component change touches. |
133
- | `/web-ui-dev-design-component` | Brand design pass for a component that works but isn't styled yet. |
134
- | `/web-ui-dev-story` | Author or update a Storybook story. |
135
- | `/web-ui-dev-commit` | Commit workflow: changelog skill, staged docs audit, CI-parity checks, house commit format. |
136
- | `/web-ui-dev-release` | Prepare release notes, commit them, and ship the approved release. |
137
- | `/web-ui-dev-changelog` | Generate and validate the required one-line CHANGELOG.md entry for a web-ui change, including direct commits to master. |
138
- | `/web-ui-dev-audit-docs` | Audit docs against staged or recent changes for staleness, gaps, and drift. |
139
- | `/web-ui-dev-audit-pass-through-defaults` | Check `@default` annotations on pass-through props against Base UI upstream. |
140
- | `/web-ui-dev-teardown-worktree` | Tear down a worktree, wherever it lives — merging its branch first or dropping it. |
141
- | `/web-ui-dev-refresh-design-reference` | Refresh the committed brand snapshots in `design/` from the Figma styleguide. |
142
- | `/web-ui-dev-mcp` | Set up or recover Storybook, DevTools, Atlassian, or Figma MCP access. |
68
+ The shipped [`agent-tooling` topic](./src/llms/skills/imf-web-ui-conventions/topics/agent-tooling.md) explains the hook
69
+ installation and Codex trust step.
143
70
 
144
- ## Releasing
71
+ ### Versions
145
72
 
146
- Release-facing changes are recorded as one-line entries in [`CHANGELOG.md`](./CHANGELOG.md) under `## [Unreleased]`. The
147
- commit workflow requires an entry for pull-request commits and direct commits to `master`, with only narrow mechanical
148
- exceptions. Each entry ends with its author as ` — Name <email>`, taken from the committer's git config.
73
+ Use a release version or range for production and `dev` while building against the library:
149
74
 
150
- The published version is derived from git tags, not from `package.json`.
75
+ | Dependency spec | Resolves to | Update with |
76
+ | --------------- | -------------------------------- | ----------------------------- |
77
+ | `^0.6.0` | compatible releases | `npm update @imfusion/web-ui` |
78
+ | `latest` | newest release | `npm update @imfusion/web-ui` |
79
+ | `dev` | newest build of `master` | `npm update @imfusion/web-ui` |
80
+ | `file:…tgz` | the packed archive you installed | pack and install again |
151
81
 
152
- The `version` field stays at `0.0.0` in the repository and he CI computes the real number with
153
- [`scripts/version.ts`](./scripts/version.ts) and writes it into `package.json` on the build agent just before publishing.
82
+ `latest` and `dev` are dist-tags. npm records the resolved version in `package-lock.json`; the tag stays in `package.json`
83
+ until you update it. A bare `latest` can cross major versions, while a range keeps the expected major. A file tarball is a
84
+ copy, so it never updates by itself.
154
85
 
155
- That working copy is thrown away, so nothing is committed back.
86
+ ## Read the docs
156
87
 
157
- `scripts/version.ts` reads `git describe` and applies two rules:
158
-
159
- Given the tag `web-ui/v0.5.0`:
160
-
161
- | Where HEAD sits | Published version | dist-tag |
162
- | -------------------------- | ----------------------- | -------- |
163
- | Exactly on `web-ui/v0.5.0` | `0.5.0` | `latest` |
164
- | 5 commits after that tag | `0.5.1-dev.5.gb4de52d7` | `dev` |
165
-
166
- The off-tag string breaks down as:
88
+ [Storybook](https://storybook.js.org/) is the public documentation site. It contains the setup guide, usage patterns, token
89
+ reference, and component examples. It is not hosted yet; run it locally from this repository:
167
90
 
168
- ```
169
- 0.5.1-dev.5.gb4de52d7
170
- └─┬─┘ └┬┘ │ └───┬────┘
171
- │ │ │ └── commit hash, abbreviated; the leading g means "git"
172
- │ │ └──────── commits since the tag
173
- │ └─────────── pre-release marker, which is what puts it on the dev tag
174
- └──────────────── the tag's version, patch bumped
91
+ ```sh
92
+ npm run dev
175
93
  ```
176
94
 
177
- Bumping the patch is what makes a dev build sort above the release it follows and below the next one.
95
+ The source for the contributor docs is [`docs/README.md`](./docs/README.md). Start there if you are changing the library.
178
96
 
179
- Every build of `master` publishes a `dev` version automatically. To check what the current checkout would publish:
97
+ ## Work on the library
180
98
 
181
- ```bash
182
- npx tsx scripts/version.ts # prints, changes nothing
99
+ ```sh
100
+ npm install
101
+ npm run git:config
183
102
  ```
184
103
 
185
- ### Cutting a release
104
+ `git:config` sets the tracked hooks path, enables rebase pulls, and requires fast-forward merges. The
105
+ [`web-ui-dev-getting-started`](./.agents/skills/web-ui-dev-getting-started/SKILL.md) skill can route a first task.
186
106
 
187
- The release skill prepares the dated release section from detailed Unreleased entries and commits it through the normal
188
- approval gate. Then ship that prepared commit:
107
+ The main development skills are:
189
108
 
190
- ```bash
191
- npm run release
192
- ```
109
+ | Skill | Use it for |
110
+ | ----------------------------------------- | ------------------------------------------------ |
111
+ | `/web-ui-dev-getting-started` | Route a first task based on experience and goal. |
112
+ | `/web-ui-dev-start` | Establish task context and working location. |
113
+ | `/web-ui-dev-new-component` | Add a primitive. |
114
+ | `/web-ui-dev-update-component` | Change an existing primitive. |
115
+ | `/web-ui-dev-design-component` | Apply the ImFusion brand to a component. |
116
+ | `/web-ui-dev-story` | Author a Storybook story. |
117
+ | `/web-ui-dev-commit` | Verify and commit a change. |
118
+ | `/web-ui-dev-release` | Prepare and ship a release. |
119
+ | `/web-ui-dev-audit-docs` | Check docs for drift before a commit. |
120
+ | `/web-ui-dev-audit-pass-through-defaults` | Check adapted prop defaults against Base UI. |
121
+ | `/web-ui-dev-refresh-design-reference` | Refresh the committed brand snapshots. |
122
+ | `/web-ui-dev-teardown-worktree` | Remove a finished worktree. |
123
+ | `/web-ui-dev-mcp` | Recover one optional MCP capability. |
193
124
 
194
- The command reads the prepared version from `CHANGELOG.md`, requires a clean working tree, runs full verification, creates
195
- `web-ui/v0.5.1`, and pushes the tag. TeamCity builds that tag, publishes `0.5.1` as `latest`, and points `dev` at the same
196
- version. The release skill uses the optional `teamcity` CLI when it is installed and authenticated to check the tagged build
197
- and publish log; otherwise it directs you to the same checks in TeamCity.
125
+ ## Release it
198
126
 
199
- The tag name must match `web-ui/vX.Y.Z` exactly. Both the version script's `--match` and the TeamCity branch filter in
200
- [`.teamcity/settings.kts`](./.teamcity/settings.kts) key off that shape; a tag in any other form publishes nothing.
127
+ The published version comes from git tags. The repository keeps `package.json` at `0.0.0`; CI writes the real version into
128
+ the build copy.
201
129
 
202
- ### Optional TeamCity CLI
130
+ For a tag such as `web-ui/v0.6.0`:
203
131
 
204
- The release skill can verify the tagged build and npm publish with the
205
- [official TeamCity CLI](https://www.jetbrains.com/help/teamcity/2026.1/teamcity-cli.html#installing). It is optional:
206
- TeamCity still builds and publishes releases when the CLI is absent.
132
+ | HEAD is | Published version | Tag |
133
+ | --------------------- | --------------------- | -------- |
134
+ | `web-ui/v0.6.0` | `0.6.0` | `latest` |
135
+ | five commits after it | `0.6.1-dev.5.g<hash>` | `dev` |
207
136
 
208
- ```bash
209
- brew install jetbrains/utils/teamcity
210
- # or: npm install -g @jetbrains/teamcity-cli
137
+ Check the version for the current checkout without changing files:
211
138
 
212
- teamcity auth login --server https://ci.imfusion.com
213
- teamcity auth status
139
+ ```sh
140
+ npx tsx scripts/version.ts
214
141
  ```
215
142
 
216
- `teamcity auth login` opens the browser for TeamCity's PKCE authorization flow and stores the resulting token in the system
217
- keyring. Use `teamcity auth login --no-browser` when browser login is unavailable.
143
+ Use `/web-ui-dev-release <version>` to prepare release notes and get the release commit approved. The final command is:
218
144
 
219
- ### Building locally with a real version
145
+ ```sh
146
+ npm run release
147
+ ```
220
148
 
221
- A local `npm run build` stamps `dist` with `0.0.0`. When you need the true version in a local artifact:
149
+ It requires a clean tree, runs the full verification, creates `web-ui/v<version>`, and pushes the tag. TeamCity builds that
150
+ tag and publishes npm. The tag must match that shape exactly.
222
151
 
223
- ```bash
224
- npx tsx scripts/version.ts --write # writes it into package.json
152
+ To build a local tarball with a real version:
153
+
154
+ ```sh
155
+ npx tsx scripts/version.ts --write
225
156
  npm run build
226
- git checkout package.json # discard the write
157
+ git checkout package.json
227
158
  ```
159
+
160
+ The release skill covers the optional TeamCity CLI checks and the publication verification.
package/bin/install.js CHANGED
@@ -13,10 +13,9 @@
13
13
  // .claude/skills/ symlinks it (this repo's own convention) so the two
14
14
  // can't drift apart.
15
15
  //
16
- // Flags: bare = skills only; --hooks adds the agent lifecycle hooks after the
17
- // consumer checks the repo's existing hooks and still installs the skills.
18
- // --target claude|agents
19
- // (repeatable) selects scripted install targets,
16
+ // Flags: bare = help; --hooks adds the agent lifecycle hooks after the consumer
17
+ // checks the repo's existing hooks and still installs the skills.
18
+ // --target claude|agents|all (repeatable) selects scripted install targets,
20
19
  // --reconfigure to re-open the target prompt on an existing install.
21
20
 
22
21
  import {
@@ -285,26 +284,45 @@ function upsertAgentsBlock() {
285
284
  return existing ? "updated" : "added";
286
285
  }
287
286
 
288
- // --target claude|agents (repeatable) selects targets without the
287
+ // --target claude|agents|all (repeatable) selects targets without the
289
288
  // interactive prompt — for CI and scripted installs.
290
289
  function parseTargetFlags(argv) {
291
290
  const targets = [];
292
291
  for (let i = 0; i < argv.length; i++) {
293
292
  if (argv[i] !== "--target") continue;
294
293
  const value = argv[i + 1];
295
- if (!value || !(value in TARGETS)) {
296
- console.error(`--target expects one of: ${Object.keys(TARGETS).join(", ")}`);
294
+ if (!value || (value !== "all" && !(value in TARGETS))) {
295
+ console.error(`--target expects one of: ${Object.keys(TARGETS).join(", ")}, all`);
297
296
  process.exit(1);
298
297
  }
299
- targets.push(value);
298
+ targets.push(...(value === "all" ? ["agents", "claude"] : [value]));
300
299
  i++;
301
300
  }
302
- return targets;
301
+ return [...new Set(targets)];
302
+ }
303
+
304
+ function printHelp() {
305
+ console.log(`Usage: web-ui-install [options]
306
+
307
+ Install @imfusion/web-ui agent skills into a consumer project.
308
+
309
+ Options:
310
+ --target agents|claude|all Install into selected skill target(s).
311
+ Repeat --target to select multiple targets.
312
+ --hooks Install agent lifecycle hooks.
313
+ --reconfigure Re-open target selection prompt.
314
+ -h, --help Show this help.
315
+ `);
303
316
  }
304
317
 
305
318
  async function main() {
306
- const skills = discoverSkills();
307
319
  const argv = process.argv.slice(2);
320
+ if (argv.length === 0 || argv.includes("-h") || argv.includes("--help")) {
321
+ printHelp();
322
+ return;
323
+ }
324
+
325
+ const skills = discoverSkills();
308
326
  const flagTargets = parseTargetFlags(argv);
309
327
  const reconfigure = argv.includes("--reconfigure");
310
328
  // Every install includes the skill bundle. Hooks are opt-in via --hooks —
@@ -41,6 +41,25 @@ beforeEach(() => {
41
41
  });
42
42
 
43
43
  describe("web-ui-install", () => {
44
+ it("prints help and makes no changes without arguments", () => {
45
+ const result = spawnSync("node", [installer], { cwd: consumer, encoding: "utf-8" });
46
+
47
+ expect(result.status).toBe(0);
48
+ expect(result.stdout).toContain("Usage: web-ui-install [options]");
49
+ expect(existsSync(join(consumer, ".agents"))).toBe(false);
50
+ expect(existsSync(join(consumer, ".claude"))).toBe(false);
51
+ });
52
+
53
+ it("uses all as an alias for both installation targets", () => {
54
+ runInstall(consumer, "--target", "all");
55
+
56
+ const installed = readdirSync(join(consumer, ".agents", "skills"));
57
+ expect(installed).toHaveLength(7);
58
+ for (const name of installed) {
59
+ expect(lstatSync(join(consumer, ".claude", "skills", name)).isSymbolicLink()).toBe(true);
60
+ }
61
+ });
62
+
44
63
  it("installs skills into both targets with version markers", () => {
45
64
  runInstall(consumer, "--skills", "--target", "agents", "--target", "claude");
46
65
 
@@ -0,0 +1,147 @@
1
+ import { t as e } from "./chunk-DmhlhrBa.js";
2
+ import { t } from "./meta-CySnRuVp.js";
3
+ import { Ma as n, Qt as r, Xo as i, hn as a, r as o } from "./icons-Cy1HAosO.js";
4
+ import { cx as s } from "class-variance-authority";
5
+ import { Fragment as c, jsx as l, jsxs as u } from "react/jsx-runtime";
6
+ import { useCallback as d, useEffect as f, useRef as p, useState as m } from "react";
7
+ import { mergeProps as h } from "@base-ui/react/merge-props";
8
+ import { useRender as g } from "@base-ui/react/use-render";
9
+ //#region src/hooks/use-clipboard.ts
10
+ function _({ timeout: e = 1500 } = {}) {
11
+ let [t, n] = m(!1), r = p(void 0);
12
+ return f(() => () => clearTimeout(r.current), []), {
13
+ copied: t,
14
+ copy: d((t) => {
15
+ navigator.clipboard.writeText(t).then(() => {
16
+ n(!0), clearTimeout(r.current), r.current = setTimeout(() => n(!1), e);
17
+ });
18
+ }, [e])
19
+ };
20
+ }
21
+ var v = {
22
+ block: "imf-ui-code-module-block",
23
+ copy: "imf-ui-code-module-copy",
24
+ icon: "imf-ui-code-module-icon",
25
+ inline: "imf-ui-code-module-inline",
26
+ inlineCopy: "imf-ui-code-module-inlineCopy",
27
+ inlineLink: "imf-ui-code-module-inlineLink",
28
+ language: "imf-ui-code-module-language",
29
+ pre: "imf-ui-code-module-pre",
30
+ separator: "imf-ui-code-module-separator"
31
+ }, y = /* @__PURE__ */ e({
32
+ Block: () => S,
33
+ Inline: () => b,
34
+ InlineLink: () => x
35
+ });
36
+ function b({ className: e, copyable: t = !1, children: r, render: a, ...d }) {
37
+ let { copied: f, copy: m } = _(), y = p(null), b = f ? n : i;
38
+ return g({
39
+ defaultTagName: "code",
40
+ render: a,
41
+ props: {
42
+ ...h(d, {
43
+ className: s(v.inline, e),
44
+ children: /* @__PURE__ */ u(c, { children: [
45
+ /* @__PURE__ */ l("span", {
46
+ ref: y,
47
+ children: r
48
+ }),
49
+ t && /* @__PURE__ */ l("span", { className: v.separator }),
50
+ t && /* @__PURE__ */ l("button", {
51
+ type: "button",
52
+ className: v.inlineCopy,
53
+ "data-copied": f || void 0,
54
+ "aria-label": f ? "Copied" : "Copy",
55
+ onClick: () => m(y.current?.textContent ?? ""),
56
+ children: /* @__PURE__ */ l(o, {
57
+ glyph: b,
58
+ size: 12,
59
+ strokeWidth: 2,
60
+ "aria-hidden": !0
61
+ })
62
+ })
63
+ ] })
64
+ }),
65
+ "data-imf-ui-component": "Code.Inline"
66
+ }
67
+ });
68
+ }
69
+ b.displayName = "Code.Inline";
70
+ function x({ className: e, kind: t = "external", children: n, render: i, ...d }) {
71
+ let f = t === "external" ? a : r;
72
+ return g({
73
+ defaultTagName: "a",
74
+ render: i,
75
+ props: {
76
+ ...h(t === "external" ? {
77
+ target: "_blank",
78
+ rel: "noreferrer"
79
+ } : {}, d, {
80
+ className: s(v.inline, v.inlineLink, e),
81
+ children: /* @__PURE__ */ u(c, { children: [
82
+ n,
83
+ /* @__PURE__ */ l("span", { className: v.separator }),
84
+ /* @__PURE__ */ l("span", {
85
+ className: v.icon,
86
+ "aria-hidden": !0,
87
+ children: /* @__PURE__ */ l(o, {
88
+ glyph: f,
89
+ size: 12,
90
+ strokeWidth: 2
91
+ })
92
+ })
93
+ ] })
94
+ }),
95
+ "data-imf-ui-component": "Code.InlineLink",
96
+ "data-kind": t
97
+ }
98
+ });
99
+ }
100
+ x.displayName = "Code.InlineLink";
101
+ function S({ className: e, language: t, hideCopy: r = !1, children: a, ...c }) {
102
+ let { copied: d, copy: f } = _(), m = p(null), h = d ? n : i;
103
+ return /* @__PURE__ */ u("div", {
104
+ "data-imf-ui-component": "Code.Block",
105
+ className: s(v.block, e),
106
+ children: [
107
+ t != null && /* @__PURE__ */ l("span", {
108
+ className: v.language,
109
+ children: t
110
+ }),
111
+ !r && /* @__PURE__ */ l("button", {
112
+ type: "button",
113
+ className: v.copy,
114
+ "data-copied": d || void 0,
115
+ "aria-label": d ? "Copied" : "Copy",
116
+ onClick: () => f(m.current?.textContent ?? ""),
117
+ children: /* @__PURE__ */ l(o, {
118
+ glyph: h,
119
+ size: 12,
120
+ strokeWidth: 2,
121
+ "aria-hidden": !0
122
+ })
123
+ }),
124
+ /* @__PURE__ */ l("pre", {
125
+ ...c,
126
+ className: v.pre,
127
+ children: /* @__PURE__ */ l("code", {
128
+ ref: m,
129
+ children: a
130
+ })
131
+ })
132
+ ]
133
+ });
134
+ }
135
+ S.displayName = "Code.Block";
136
+ //#endregion
137
+ //#region src/components/code/code.meta.ts
138
+ var C = {
139
+ name: "Code",
140
+ category: t.display,
141
+ status: "stable",
142
+ namespace: !0,
143
+ description: "Displays source code inline or in a block, with optional language labels and copying. Also called a code snippet or code block.",
144
+ origin: "native"
145
+ };
146
+ //#endregion
147
+ export { y as a, x as i, S as n, _ as o, b as r, C as t };
@@ -0,0 +1 @@
1
+ export declare function writeCodeHighlightTheme(): void;
@@ -1,4 +1,5 @@
1
- type InlineProps = Omit<React.HTMLAttributes<HTMLElement>, "children"> & {
1
+ import { useRender } from '@base-ui/react/use-render';
2
+ type InlineProps = Omit<useRender.ComponentProps<"code">, "children"> & {
2
3
  /** Code content shown in the chip. The copy button copies its rendered text. */
3
4
  children: React.ReactNode;
4
5
  /** Show a small copy button on the right, behind a hairline separator. @default false */
@@ -9,12 +10,12 @@ type InlineProps = Omit<React.HTMLAttributes<HTMLElement>, "children"> & {
9
10
  * text. `Typo.InlineCode` renders this under the hood so inline-code chrome is
10
11
  * defined in one place. The copy button copies the rendered text.
11
12
  */
12
- export declare function Inline({ className, copyable, children, ...props }: InlineProps): import("react/jsx-runtime").JSX.Element;
13
+ export declare function Inline({ className, copyable, children, render, ...props }: InlineProps): import('react').ReactElement<unknown, string | import('react').JSXElementConstructor<any>>;
13
14
  export declare namespace Inline {
14
15
  var displayName: string;
15
16
  }
16
17
  export type CodeInlineLinkKind = "external" | "internal";
17
- type InlineLinkProps = Omit<React.AnchorHTMLAttributes<HTMLAnchorElement>, "children"> & {
18
+ type InlineLinkProps = Omit<useRender.ComponentProps<"a">, "children"> & {
18
19
  /** The link text, as a raw string, rendered as a code fragment. */
19
20
  children: string;
20
21
  /** Link target scope. `"external"` (default) opens in a new tab with a diagonal `ArrowUpRight` icon; `"internal"` stays in the current tab with a horizontal `ArrowRight` icon. */
@@ -27,7 +28,7 @@ type InlineLinkProps = Omit<React.AnchorHTMLAttributes<HTMLAnchorElement>, "chil
27
28
  * copy button and a link on the same chip. Mirrors `ChipLink`'s shape (anchor
28
29
  * is the chip root, trailing icon nudges on hover, `data-kind` picks the icon).
29
30
  */
30
- export declare function InlineLink({ className, kind, children, ...props }: InlineLinkProps): import("react/jsx-runtime").JSX.Element;
31
+ export declare function InlineLink({ className, kind, children, render, ...props }: InlineLinkProps): import('react').ReactElement<unknown, string | import('react').JSXElementConstructor<any>>;
31
32
  export declare namespace InlineLink {
32
33
  var displayName: string;
33
34
  }
@@ -1,6 +1,6 @@
1
1
  import { VariantProps } from 'class-variance-authority';
2
2
  declare const stack: (props?: ({
3
- gap?: "1" | "2" | "3" | "4" | "5" | "6" | "7" | "8" | "9" | "10" | null | undefined;
3
+ gap?: "0" | "1" | "2" | "3" | "4" | "5" | "6" | "7" | "8" | "9" | "10" | null | undefined;
4
4
  align?: "center" | "end" | "start" | "stretch" | null | undefined;
5
5
  justify?: "center" | "end" | "start" | "between" | "around" | "evenly" | null | undefined;
6
6
  } & import('class-variance-authority/types').ClassProp) | undefined) => string;
@@ -0,0 +1,2 @@
1
+ export * as Toast from './toast';
2
+ export { toastMeta } from './toast.meta';