@imfusion/web-ui 0.6.4-dev.7.g1840f300 → 0.6.4-dev.84.gbfc0d437

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 (139) hide show
  1. package/README.md +19 -55
  2. package/dist/assets/vendors/base-ui.d.ts +2 -3
  3. package/dist/breakpoints/min-width.d.ts +3 -7
  4. package/dist/breakpoints/registry.d.ts +3 -9
  5. package/dist/{code-Ce8uiPsv.js → code-D2lwxHgd.js} +15 -15
  6. package/dist/codegen/gen-breakpoints-css.d.ts +0 -4
  7. package/dist/codegen/gen-token-css.d.ts +0 -2
  8. package/dist/components/app-shell/app-shell.d.ts +7 -11
  9. package/dist/components/button/button.d.ts +7 -12
  10. package/dist/components/callout/callout.d.ts +11 -18
  11. package/dist/components/card/card.d.ts +11 -10
  12. package/dist/components/checkbox/checkbox.d.ts +2 -38
  13. package/dist/components/chip/chip.cva.d.ts +2 -4
  14. package/dist/components/chip/chip.d.ts +1 -1
  15. package/dist/components/code/code.d.ts +2 -2
  16. package/dist/components/collapsible/collapsible.d.ts +4 -35
  17. package/dist/components/copy-button/copy-button.d.ts +1 -1
  18. package/dist/components/drawer/drawer.d.ts +17 -100
  19. package/dist/components/field/field.d.ts +7 -67
  20. package/dist/components/fieldset/fieldset.d.ts +2 -15
  21. package/dist/components/icon/icon.d.ts +2 -2
  22. package/dist/components/input/input.d.ts +2 -8
  23. package/dist/components/logo/imfusion/imfusion.d.ts +2 -5
  24. package/dist/components/logo/imfusion/marks.d.ts +10 -0
  25. package/dist/components/logo/logo.d.ts +3 -3
  26. package/dist/components/navigation-menu/subs/flyout-link.d.ts +5 -19
  27. package/dist/components/navigation-menu/subs/inline-submenu.d.ts +2 -4
  28. package/dist/components/navigation-menu/subs/link.d.ts +6 -23
  29. package/dist/components/navigation-menu/subs/overlay.d.ts +6 -51
  30. package/dist/components/navigation-menu/subs/shared.d.ts +4 -14
  31. package/dist/components/navigation-menu/subs/structure.d.ts +7 -29
  32. package/dist/components/navigation-menu/subs/trigger.d.ts +11 -20
  33. package/dist/components/number-field/index.d.ts +2 -0
  34. package/dist/components/number-field/number-field.d.ts +72 -0
  35. package/dist/components/number-field/number-field.meta.d.ts +2 -0
  36. package/dist/components/popover/popover.d.ts +23 -98
  37. package/dist/components/row/row.d.ts +1 -1
  38. package/dist/components/select/select.d.ts +26 -189
  39. package/dist/components/separator/separator.d.ts +5 -4
  40. package/dist/components/slider/slider.d.ts +7 -77
  41. package/dist/components/spinner/spinner.d.ts +13 -8
  42. package/dist/components/stack/stack.d.ts +3 -4
  43. package/dist/components/switch/switch.d.ts +2 -31
  44. package/dist/components/table/table.d.ts +10 -18
  45. package/dist/components/tabs/tabs.d.ts +18 -52
  46. package/dist/components/toast/toast.d.ts +16 -103
  47. package/dist/components/toggle/toggle.d.ts +3 -21
  48. package/dist/components/toggle-group/toggle-group.d.ts +3 -20
  49. package/dist/components/tooltip/tooltip.d.ts +26 -85
  50. package/dist/components/typo/typo.d.ts +25 -25
  51. package/dist/docgen/gen-docgen.utils.d.ts +3 -4
  52. package/dist/hooks/use-color-scheme.d.ts +5 -11
  53. package/dist/hooks/use-media-query.d.ts +2 -7
  54. package/dist/{icons-Cy1HAosO.js → icons-CaGCCwG-.js} +7 -7
  55. package/dist/icons.js +1 -1
  56. package/dist/index.d.ts +1 -0
  57. package/dist/index.js +1486 -1368
  58. package/dist/integrations/code-highlight/highlighter.d.ts +1 -56
  59. package/dist/integrations/code-highlight.js +41 -189
  60. package/dist/integrations/image-display-options/image-display-options-view.utils.d.ts +0 -1
  61. package/dist/integrations/image-display-options.js +54 -54
  62. package/dist/llms/evals/runner/affected.d.ts +2 -0
  63. package/dist/llms/evals/runner/benchmark.d.ts +12 -0
  64. package/dist/llms/evals/runner/compare.d.ts +2 -0
  65. package/dist/llms/evals/runner/config.d.ts +29 -0
  66. package/dist/llms/evals/runner/evidence.d.ts +7 -0
  67. package/dist/llms/evals/runner/execute.d.ts +32 -0
  68. package/dist/llms/evals/runner/grade.d.ts +10 -0
  69. package/dist/llms/evals/runner/report-md.d.ts +2 -0
  70. package/dist/llms/evals/runner/report.d.ts +4 -0
  71. package/dist/llms/evals/runner/run.d.ts +2 -0
  72. package/dist/llms/evals/runner/scenario.d.ts +3 -0
  73. package/dist/llms/evals/runner/types.d.ts +140 -0
  74. package/dist/llms/evals/runner/workspace.d.ts +2 -0
  75. package/dist/llms/evals/runner/write-generated.d.ts +1 -0
  76. package/dist/provider/web-ui-provider.d.ts +4 -1
  77. package/dist/style.css +1 -1
  78. package/dist/{tabs-DIe1Utiy.js → tabs-By5ir2pt.js} +162 -159
  79. package/dist/tokens/apply.d.ts +4 -9
  80. package/dist/tokens/control-registry.d.ts +3 -6
  81. package/dist/tokens/types.d.ts +7 -24
  82. package/dist/tokens/use-token-controls.d.ts +3 -12
  83. package/dist/types/meta.d.ts +15 -32
  84. package/dist/utils/index.d.ts +1 -0
  85. package/dist/utils/resolve-state-props.d.ts +4 -0
  86. package/dist/vite/brand-assets.d.ts +3 -0
  87. package/dist/vite/index.d.ts +2 -0
  88. package/dist/vite/readable-css-module-names.d.ts +11 -0
  89. package/dist/vite.js +55 -0
  90. package/dist/web-ui-cli.js +322 -0
  91. package/docs/user-guide/AgentTooling.mdx +127 -0
  92. package/docs/user-guide/BrandAssets.mdx +102 -0
  93. package/docs/user-guide/Changelog.mdx +23 -0
  94. package/docs/user-guide/GettingStarted.mdx +70 -0
  95. package/docs/user-guide/HowItsBuilt.mdx +113 -0
  96. package/docs/user-guide/Tokens.mdx +87 -0
  97. package/docs/user-guide/UsagePatterns.mdx +122 -0
  98. package/package.json +27 -22
  99. package/src/assets/public/favicon/apple-touch-icon.png +0 -0
  100. package/src/assets/public/favicon/favicon-16.png +0 -0
  101. package/src/assets/public/favicon/favicon-32.png +0 -0
  102. package/src/assets/public/favicon/favicon.ico +0 -0
  103. package/src/assets/public/favicon/favicon.svg +7 -0
  104. package/src/assets/public/favicon/icon-192.png +0 -0
  105. package/src/assets/public/favicon/icon-512.png +0 -0
  106. package/src/assets/public/favicon/og-image.png +0 -0
  107. package/src/assets/public/spinner/imfusion-spinner-black.webp +0 -0
  108. package/src/assets/public/spinner/imfusion-spinner-blue.webp +0 -0
  109. package/src/assets/public/spinner/imfusion-spinner-white.webp +0 -0
  110. package/src/docgen/doc.gen.json +3255 -603
  111. package/src/llms/install-templates/AGENTS.md +4 -4
  112. package/src/llms/install-templates/hooks/baseline-staleness.sh +9 -2
  113. package/src/llms/llms.gen.txt +7 -1
  114. package/src/llms/skills/imf-web-ui/SKILL.md +44 -21
  115. package/src/llms/skills/imf-web-ui-audit/SKILL.md +25 -11
  116. package/src/llms/skills/imf-web-ui-components/SKILL.md +4 -1
  117. package/src/llms/skills/imf-web-ui-conventions/SKILL.md +2 -2
  118. package/src/llms/skills/imf-web-ui-conventions/templates/AUDIT_CHECKLIST.md +0 -1
  119. package/src/llms/skills/imf-web-ui-conventions/templates/REPORT.md +21 -2
  120. package/src/llms/skills/imf-web-ui-conventions/topics/agent-tooling.md +15 -10
  121. package/src/llms/skills/imf-web-ui-conventions/topics/assets.md +7 -4
  122. package/src/llms/skills/imf-web-ui-conventions/topics/data.md +3 -1
  123. package/src/llms/skills/imf-web-ui-conventions/topics/docs-structure.md +2 -2
  124. package/src/llms/skills/imf-web-ui-conventions/topics/git.md +4 -2
  125. package/src/llms/skills/imf-web-ui-conventions/topics/library-setup.md +10 -1
  126. package/src/llms/skills/imf-web-ui-conventions/topics/styling.md +2 -2
  127. package/src/llms/skills/imf-web-ui-conventions/topics/tokens.md +4 -2
  128. package/src/llms/skills/imf-web-ui-conventions/topics/tooling.md +13 -11
  129. package/src/llms/skills/imf-web-ui-setup/SKILL.md +17 -9
  130. package/src/llms/skills/imf-web-ui-update/SKILL.md +36 -14
  131. package/src/llms/skills/imf-web-ui-ux/SKILL.md +5 -3
  132. package/src/llms/tokens.gen.json +71 -7
  133. package/bin/install.js +0 -446
  134. package/dist/build/vite-css-module-names/index.d.ts +0 -20
  135. package/dist/build/vite-css-module-names.js +0 -17
  136. package/dist/components/spinner/spinner.geometry.d.ts +0 -37
  137. package/dist/integrations/code-highlight/languages/cmake.d.ts +0 -1
  138. package/dist/integrations/code-highlight/languages/cpp.d.ts +0 -1
  139. /package/dist/{meta-CySnRuVp.js → meta-j-7HGrWv.js} +0 -0
@@ -1,12 +1,9 @@
1
1
  export type ComponentCategoryId = "buttons" | "inputs" | "layout" | "display";
2
2
  export type ComponentStatus = "stable" | "experimental" | "deprecated";
3
3
  /**
4
- * Provenance of a component. `"adapted"` wraps an upstream behavioral package —
5
- * Base UI by default, or another best-in-class library (e.g. TanStack Table);
6
- * `"native"` is built by us with no upstream runtime dependency, regardless of
7
- * whether the design took inspiration from elsewhere. Surfaces as the origin
8
- * badge in the docs UI and on consumer-side surfaces that disambiguate the
9
- * implementation source.
4
+ * Provenance of a component. `"adapted"` wraps an upstream behavioral package
5
+ * (Base UI by default, or another library); `"native"` has no upstream runtime
6
+ * dependency, regardless of whether the design took inspiration elsewhere.
10
7
  */
11
8
  export type ComponentOrigin = "adapted" | "native";
12
9
  /**
@@ -24,23 +21,16 @@ export interface ComponentUpstream {
24
21
  /** LLM-friendly documentation URL — typically the `.md` companion of `docLink`. */
25
22
  llmDocLink?: string;
26
23
  /**
27
- * Package specifiers a consumer must install to use this primitive, when
28
- * adapting from an upstream OTHER than the house dependency (Base UI) — e.g.
29
- * `["@tanstack/react-table"]` for Table. Omitted for Base-UI-adapted
30
- * primitives, which are already present transitively; an absent field and an
31
- * empty array both mean "no extra install". An array (not a single string)
32
- * because one adapt may require several independently-installable peers (a
33
- * lib plus a required companion package). Docs read this to render an install
34
- * hint; `name` remains the human-readable display name.
24
+ * Install-time package specifiers, e.g. `["@tanstack/react-table"]`. Omitted
25
+ * for Base-UI-adapted primitives (already present transitively); an absent
26
+ * field and an empty array both mean "no extra install".
35
27
  */
36
28
  runtimeDependencies?: string[];
37
29
  }
38
30
  /**
39
- * A taxonomic category as it appears on a component's meta. Carries both the
40
- * stable `id` (slug used for grouping/sorting) and a human-readable `label`.
41
- * Default labels are English; i18n is out of scope for v0 — a later evolution
42
- * can swap `ComponentCategories` for locale-aware sources without changing the
43
- * `ComponentCategory` shape consumers read.
31
+ * A taxonomic category as it appears on a component's meta: a stable `id`
32
+ * (slug used for grouping/sorting) and a human-readable `label`. Labels are English only;
33
+ * locale-aware sources can replace `ComponentCategories` without changing this shape.
44
34
  */
45
35
  export interface ComponentCategory {
46
36
  id: ComponentCategoryId;
@@ -48,8 +38,7 @@ export interface ComponentCategory {
48
38
  }
49
39
  /**
50
40
  * Canonical category objects. Every `*.meta.ts` should reference one of these
51
- * (e.g. `category: ComponentCategories.inputs`) rather than inlining a literal
52
- * — a literal allows ID/label drift and duplicates the label string per meta.
41
+ * rather than inlining a literal, which would allow ID/label drift.
53
42
  */
54
43
  export declare const ComponentCategories: {
55
44
  readonly buttons: {
@@ -70,13 +59,9 @@ export declare const ComponentCategories: {
70
59
  };
71
60
  };
72
61
  /**
73
- * Self-descriptive metadata for an exported component. Describes *what the
74
- * component is* — name, taxonomy, lifecycle, a one-sentence identity line, and
75
- * provenance (adapted from an upstream vs. native). NOT documentation prose,
76
- * usage examples, props, or part enumerations. Props are derived from the
77
- * component's TypeScript Props interface at build time; longer-form
78
- * documentation lives in MDX; named sub-exports are the source of truth for
79
- * compound-component parts.
62
+ * Self-descriptive metadata for an exported component: name, taxonomy,
63
+ * lifecycle, identity line, provenance. NOT documentation prose, usage
64
+ * examples, props, or part enumerations — those live in MDX and the Props interface.
80
65
  */
81
66
  export interface ComponentMeta {
82
67
  /** PascalCase component name as exported from `@imfusion/web-ui`. Matches the `data-imf-ui-component` attribute. */
@@ -99,10 +84,8 @@ export interface ComponentMeta {
99
84
  upstream?: ComponentUpstream;
100
85
  /**
101
86
  * PascalCase names of other `@imfusion/web-ui` components this component
102
- * composes internally (e.g. CopyButton renders through Button).
103
- * The in-library counterpart to `upstream.runtimeDependencies`: no install
104
- * implication — purely discovery/documentation, surfaced by doc tooling
105
- * (DocHeader "Uses" row). Omit when the component composes nothing.
87
+ * composes internally (e.g. CopyButton renders through Button). No install
88
+ * implication — surfaced by doc tooling (DocHeader "Uses" row).
106
89
  */
107
90
  internalDependencies?: string[];
108
91
  }
@@ -0,0 +1 @@
1
+ export { resolveClassName, resolveStyle } from './resolve-state-props';
@@ -0,0 +1,4 @@
1
+ /** Resolves a Base UI `className` against the part's state. */
2
+ export declare function resolveClassName<State>(className: string | ((state: State) => string | undefined) | undefined, state: State): string | undefined;
3
+ /** Resolves a Base UI `style` against the part's state. */
4
+ export declare function resolveStyle<State>(style: React.CSSProperties | ((state: State) => React.CSSProperties | undefined) | undefined, state: State): React.CSSProperties | undefined;
@@ -0,0 +1,3 @@
1
+ import { Plugin } from 'vite';
2
+ /** Serves and emits the complete ImFusion favicon set at stable root URLs. */
3
+ export declare function imfusionBrandAssets(): Plugin;
@@ -0,0 +1,2 @@
1
+ export { imfusionBrandAssets } from './brand-assets.ts';
2
+ export { readableCssModuleNames, type ReadableCssModuleNamesOptions } from './readable-css-module-names.ts';
@@ -0,0 +1,11 @@
1
+ import { Plugin } from 'vite';
2
+ export interface ReadableCssModuleNamesOptions {
3
+ /** Namespace for every generated class name. Short, stable, app-scoped (`imf-ui`, `acme`). */
4
+ prefix: string;
5
+ }
6
+ /**
7
+ * `button.module.css` yields `{prefix}-button-module-root`. Register in every CSS-compiling
8
+ * tool (app build AND Storybook) or class names diverge and styles silently break. Defaults to
9
+ * Lightning CSS, which drops `css.modules` options like `localsConvention`.
10
+ */
11
+ export declare function readableCssModuleNames({ prefix }: ReadableCssModuleNamesOptions): Plugin;
package/dist/vite.js ADDED
@@ -0,0 +1,55 @@
1
+ import { readFileSync as e, readdirSync as t } from "node:fs";
2
+ import { dirname as n, join as r } from "node:path";
3
+ import { fileURLToPath as i } from "node:url";
4
+ //#region src/vite/brand-assets.ts
5
+ var a = n(i(import.meta.resolve("@imfusion/web-ui/assets/favicon/favicon.svg"))), o = t(a).map((t) => ({
6
+ name: t,
7
+ source: e(r(a, t))
8
+ })), s = {
9
+ ".ico": "image/x-icon",
10
+ ".png": "image/png",
11
+ ".svg": "image/svg+xml"
12
+ };
13
+ function c(e) {
14
+ return s[e.slice(e.lastIndexOf("."))] ?? "application/octet-stream";
15
+ }
16
+ function l() {
17
+ return {
18
+ name: "imf-ui:brand-assets",
19
+ configureServer(e) {
20
+ e.middlewares.use((e, t, n) => {
21
+ let r = o.find(({ name: t }) => e.url?.split("?")[0] === `/${t}`);
22
+ if (!r) {
23
+ n();
24
+ return;
25
+ }
26
+ t.setHeader("Content-Type", c(r.name)), t.end(r.source);
27
+ });
28
+ },
29
+ generateBundle() {
30
+ for (let e of o) this.emitFile({
31
+ fileName: e.name,
32
+ source: e.source,
33
+ type: "asset"
34
+ });
35
+ }
36
+ };
37
+ }
38
+ //#endregion
39
+ //#region src/vite/readable-css-module-names.ts
40
+ function u(e, t) {
41
+ let { lightningcss: n, modules: r, transformer: i } = e.css ?? {}, a = n?.cssModules;
42
+ if (!(typeof a == "boolean" || r === !1) && !a?.pattern && !(typeof r == "object" && r.generateScopedName)) return i === "postcss" ? { css: { modules: { generateScopedName: t } } } : { css: {
43
+ transformer: "lightningcss",
44
+ lightningcss: { cssModules: { pattern: t } }
45
+ } };
46
+ }
47
+ function d({ prefix: e }) {
48
+ let t = `${e}-[name]-[local]`;
49
+ return {
50
+ name: "imf-ui:readable-css-module-names",
51
+ config: (e) => u(e, t)
52
+ };
53
+ }
54
+ //#endregion
55
+ export { l as imfusionBrandAssets, d as readableCssModuleNames };
@@ -0,0 +1,322 @@
1
+ #!/usr/bin/env node
2
+ import { chmodSync as e, cpSync as t, existsSync as n, lstatSync as r, mkdirSync as i, readFileSync as a, readdirSync as o, readlinkSync as s, realpathSync as c, rmSync as l, symlinkSync as u, writeFileSync as d } from "node:fs";
3
+ import { dirname as f, relative as p, resolve as m } from "node:path";
4
+ import { fileURLToPath as ee } from "node:url";
5
+ import { Command as te, Option as ne } from "commander";
6
+ import * as h from "@clack/prompts";
7
+ import { spawnSync as g } from "node:child_process";
8
+ var _ = {
9
+ harnesses: {
10
+ claude: {
11
+ label: "Claude Code",
12
+ hookSettings: ".claude/settings.json",
13
+ hookTemplate: "settings.json"
14
+ },
15
+ codex: {
16
+ label: "Codex",
17
+ hookSettings: ".codex/hooks.json",
18
+ hookTemplate: "codex-hooks.json"
19
+ }
20
+ },
21
+ namespace: "imf-web-ui",
22
+ hooksDir: ".agents/hooks/imf-web-ui",
23
+ templatesDir: "src/llms/install-templates",
24
+ skillsSource: "src/llms/skills",
25
+ skillsDir: ".agents/skills",
26
+ linkDir: ".claude/skills",
27
+ versionMarker: ".imf-web-ui-skill-version.json"
28
+ };
29
+ //#endregion
30
+ //#region src/cli/paths.ts
31
+ function re(e) {
32
+ let t = e;
33
+ for (; !n(m(t, "package.json"));) {
34
+ let n = f(t);
35
+ if (n === t) throw Error(`Could not find package.json above ${e}`);
36
+ t = n;
37
+ }
38
+ return t;
39
+ }
40
+ var v = re(f(ee(import.meta.url))), y = process.cwd(), ie = `<!-- ${_.namespace}:begin`, b = `<!-- ${_.namespace}:end -->`, ae = m(v, _.templatesDir, "AGENTS.md"), x = m(y, "AGENTS.md");
41
+ function S(e) {
42
+ let t = e.indexOf(ie), n = e.indexOf(b);
43
+ return t === -1 || n === -1 ? null : e.slice(t, n + b.length);
44
+ }
45
+ function oe() {
46
+ if (!n(x)) return "absent";
47
+ let e = S(a(ae, "utf-8"));
48
+ if (!e) return "absent";
49
+ let t = a(x, "utf-8"), r = S(t), i = r ? t.replace(r, e) : `${t.trimEnd()}\n\n${e}\n`;
50
+ return i === t ? "unchanged" : (d(x, i), r ? "updated" : "added");
51
+ }
52
+ //#endregion
53
+ //#region src/cli/skills.ts
54
+ var C = Object.keys(_.harnesses).filter((e) => e in _.harnesses), se = [...C, "all"];
55
+ function w(e) {
56
+ return e === "all" ? C : [e];
57
+ }
58
+ function T(e) {
59
+ return `./${p(y, e)}`;
60
+ }
61
+ var E = _.namespace, D = _.versionMarker, O = m(v, _.skillsSource), k = m(y, _.skillsDir), A = m(y, _.linkDir), j = class extends Error {}, M = JSON.parse(a(m(v, "package.json"), "utf-8"));
62
+ if (typeof M != "object" || !M || !("version" in M) || typeof M.version != "string") throw Error(`${m(v, "package.json")} has no string "version" field`);
63
+ var N = M.version;
64
+ function P(e) {
65
+ return e === E || e.startsWith(`${E}-`);
66
+ }
67
+ function F() {
68
+ return n(O) ? o(O, { withFileTypes: !0 }).filter((e) => e.isDirectory() && P(e.name)).map((e) => e.name).sort() : [];
69
+ }
70
+ function I(e) {
71
+ let t = m(k, e, D);
72
+ if (!n(t)) return null;
73
+ try {
74
+ let e = JSON.parse(a(t, "utf-8"));
75
+ if (typeof e != "object" || !e) return null;
76
+ let n = "harnesses" in e && Array.isArray(e.harnesses) ? e.harnesses : null;
77
+ return n ? C.filter((e) => n.includes(e)) : null;
78
+ } catch {
79
+ return null;
80
+ }
81
+ }
82
+ function L(e) {
83
+ for (let t of e) {
84
+ let e = I(t);
85
+ if (e && e.length > 0) return e;
86
+ }
87
+ return null;
88
+ }
89
+ function R(e, t, r) {
90
+ if (n(e)) for (let n of o(e).filter(P)) t.has(n) || (l(m(e, n), {
91
+ recursive: !0,
92
+ force: !0
93
+ }), h.log.info(`Removed skill: ${n} (${r})`));
94
+ }
95
+ function ce() {
96
+ return n(A) && n(k) && c(A) === c(k);
97
+ }
98
+ function le(e) {
99
+ let t = m(A, e), n = p(A, m(k, e)), a = r(t, { throwIfNoEntry: !1 });
100
+ a?.isSymbolicLink() && s(t) === n || (a && l(t, {
101
+ recursive: !0,
102
+ force: !0
103
+ }), i(A, { recursive: !0 }), u(n, t));
104
+ }
105
+ function z(e, n) {
106
+ try {
107
+ i(k, { recursive: !0 });
108
+ for (let r of e) {
109
+ let e = m(k, r);
110
+ l(e, {
111
+ recursive: !0,
112
+ force: !0
113
+ }), t(m(O, r), e, { recursive: !0 }), d(m(e, D), JSON.stringify({
114
+ version: N,
115
+ harnesses: n
116
+ }, null, 2) + "\n");
117
+ }
118
+ if (R(k, new Set(e), "no longer in this bundle"), h.log.success(`Skills -> ${T(k)}/${E}*`), ce()) return;
119
+ if (n.includes("claude")) {
120
+ for (let t of e) le(t);
121
+ R(A, new Set(e), "no longer in this bundle"), h.log.success(`Claude Code -> ${T(A)}/${E}* (symlinks -> ${T(k)})`);
122
+ } else R(A, /* @__PURE__ */ new Set(), "claude not selected");
123
+ } catch (e) {
124
+ throw e instanceof Error ? new j(e.message) : e;
125
+ }
126
+ }
127
+ //#endregion
128
+ //#region src/cli/hooks.ts
129
+ var B = m(v, _.templatesDir), V = m(B, "hooks"), H = m(y, _.hooksDir), U = class extends Error {};
130
+ function ue(e, t) {
131
+ if (typeof e != "object" || !e || Array.isArray(e)) throw new U(`${t} is not a JSON object.`);
132
+ let n = { ...e };
133
+ if ("hooks" in n) {
134
+ if (typeof n.hooks != "object" || n.hooks === null || Array.isArray(n.hooks)) throw new U(`${t}: "hooks" is not a JSON object.`);
135
+ for (let [e, r] of Object.entries(n.hooks)) if (!Array.isArray(r)) throw new U(`${t}: "hooks.${e}" is not a JSON array.`);
136
+ }
137
+ return n;
138
+ }
139
+ function W(e) {
140
+ let t;
141
+ try {
142
+ t = JSON.parse(a(e, "utf-8"));
143
+ } catch {
144
+ throw new U(`${e} is not valid JSON.`);
145
+ }
146
+ return ue(t, e);
147
+ }
148
+ function de(e) {
149
+ let t = y;
150
+ for (; t !== f(t) && !n(m(t, "node_modules", ".bin"));) t = f(t);
151
+ let r = m(t, "node_modules", ".bin", "prettier");
152
+ n(r) && g(r, ["--write", e], {
153
+ cwd: y,
154
+ stdio: "ignore"
155
+ });
156
+ }
157
+ function fe() {
158
+ let n = o(V).filter((e) => e.endsWith(".sh"));
159
+ i(H, { recursive: !0 });
160
+ for (let r of n) {
161
+ let n = m(H, r);
162
+ t(m(V, r), n, { force: !0 }), e(n, 493);
163
+ }
164
+ let r = o(H).filter((e) => e.endsWith(".sh") && !n.includes(e));
165
+ for (let e of r) l(m(H, e), { force: !0 });
166
+ return {
167
+ installed: n,
168
+ removed: r
169
+ };
170
+ }
171
+ var G = `${_.hooksDir}/`;
172
+ function K(e) {
173
+ if (typeof e != "string") return null;
174
+ let t = e.lastIndexOf(G);
175
+ if (t === -1) return null;
176
+ let n = /^([\w.-]+)["']?$/.exec(e.slice(t + G.length));
177
+ return n ? n[1] : null;
178
+ }
179
+ function q(e) {
180
+ return typeof e == "object" && !!e && "hooks" in e && Array.isArray(e.hooks);
181
+ }
182
+ function J(e) {
183
+ return q(e) ? e.hooks : null;
184
+ }
185
+ function Y(e) {
186
+ return typeof e == "object" && e && "command" in e ? e.command : void 0;
187
+ }
188
+ function X(e) {
189
+ let t = J(e);
190
+ return t ? t.map((e) => K(Y(e))).filter((e) => e !== null) : [];
191
+ }
192
+ function pe(e, t, n) {
193
+ e.hooks ??= {};
194
+ let r = 0, i = 0, a = [];
195
+ for (let [r, o] of Object.entries(e.hooks)) {
196
+ let s = 0, c = o.map((e) => {
197
+ if (!q(e)) return e;
198
+ let t = e.hooks, r = t.filter((e) => {
199
+ let t = K(Y(e));
200
+ return t === null || n.includes(t);
201
+ });
202
+ return s += t.length - r.length, r.length === t.length ? e : {
203
+ ...e,
204
+ hooks: r
205
+ };
206
+ }).filter((e) => {
207
+ let t = J(e);
208
+ return t === null || t.length > 0;
209
+ });
210
+ s !== 0 && (i += s, c.length === 0 && !(r in t) ? a.push(r) : e.hooks[r] = c);
211
+ }
212
+ a.length > 0 && (e.hooks = Object.fromEntries(Object.entries(e.hooks).filter(([e]) => !a.includes(e))));
213
+ for (let [n, i] of Object.entries(t)) {
214
+ e.hooks[n] ??= [];
215
+ for (let t of i) {
216
+ let i = X(t);
217
+ e.hooks[n].some((e) => X(e).some((e) => i.includes(e))) || (e.hooks[n].push(t), r++);
218
+ }
219
+ }
220
+ return {
221
+ added: r,
222
+ removed: i
223
+ };
224
+ }
225
+ function me(e) {
226
+ let t = /* @__PURE__ */ new Map(), r = /* @__PURE__ */ new Map();
227
+ for (let i of C) {
228
+ let a = m(y, _.harnesses[i].hookSettings);
229
+ if (n(a) && t.set(i, W(a)), e.includes(i)) {
230
+ let e = m(B, _.harnesses[i].hookTemplate);
231
+ r.set(i, W(e).hooks ?? {});
232
+ }
233
+ }
234
+ let { installed: a, removed: o } = fe();
235
+ h.log.success(`Agent hooks -> ${T(H)} (${String(a.length)} scripts)`), o.length > 0 && h.log.info(`Removed stale hook script(s): ${o.join(", ")} (no longer shipped)`);
236
+ for (let n of C) {
237
+ let o = e.includes(n);
238
+ if (!o && !t.has(n)) continue;
239
+ let s = m(y, _.harnesses[n].hookSettings), c = r.get(n) ?? {}, l = t.get(n) ?? {}, u = pe(l, c, o ? a : []);
240
+ if (u.added === 0 && u.removed === 0) {
241
+ o && h.log.info(`Hook registrations already present in ${T(s)}`);
242
+ continue;
243
+ }
244
+ i(f(s), { recursive: !0 }), d(s, JSON.stringify(l, null, 2) + "\n"), de(s);
245
+ let p = [u.added > 0 && `registered ${String(u.added)}`, u.removed > 0 && `removed ${String(u.removed)} stale`].filter(Boolean);
246
+ h.log.success(`${p.join(", ")} hook registration(s) in ${T(s)}`);
247
+ }
248
+ }
249
+ //#endregion
250
+ //#region src/cli/index.ts
251
+ function Z() {
252
+ return new ne("--harness <harness>", "claude, codex, or all").choices(se);
253
+ }
254
+ async function he(e, t, n) {
255
+ if (t) return h.log.info(`Harness from --harness flag: ${t.join(", ")}`), t;
256
+ let r = L(e);
257
+ if (r && !n) return h.log.info(`Refreshing the existing install: ${r.join(", ")} — pass --reconfigure to choose differently.`), r;
258
+ if (!process.stdin.isTTY) return console.error("Pass --harness=claude|codex|all — no terminal to prompt in."), process.exitCode = 1, null;
259
+ let i = await h.multiselect({
260
+ message: "Install into which harness (or harnesses)?",
261
+ options: C.map((e) => ({
262
+ value: e,
263
+ label: _.harnesses[e].label
264
+ })),
265
+ required: !0
266
+ });
267
+ return h.isCancel(i) ? (h.cancel("Cancelled — nothing installed."), null) : i;
268
+ }
269
+ async function ge(e) {
270
+ let t = e.harness ? w(e.harness) : null, n = F();
271
+ if (h.intro(`@imfusion/web-ui install skills — ${String(n.length)} skills`), n.length === 0) {
272
+ h.log.error("No skills found. Reinstall @imfusion/web-ui and try again."), h.outro("Nothing installed."), process.exitCode = 1;
273
+ return;
274
+ }
275
+ let r = await he(n, t, e.reconfigure === !0);
276
+ if (!r) return;
277
+ h.log.message(`Skills in this bundle:\n${n.map((e) => ` - ${e}`).join("\n")}`);
278
+ try {
279
+ z(n, r);
280
+ } catch (e) {
281
+ if (e instanceof j) {
282
+ h.log.error(e.message), h.outro("Install failed."), process.exitCode = 1;
283
+ return;
284
+ }
285
+ throw e;
286
+ }
287
+ let i = oe();
288
+ (i === "updated" || i === "added") && h.log.success(`Refreshed the ${_.namespace} block in ./AGENTS.md`), h.outro(`Done — ${String(n.length)} skills installed.`);
289
+ }
290
+ function _e(e) {
291
+ let t = e.harness ? w(e.harness) : null, n = L(F());
292
+ if (!t && !n) {
293
+ console.error("No harness recorded. Pass --harness=claude|codex|all."), process.exitCode = 1;
294
+ return;
295
+ }
296
+ let r = t ?? n ?? [], i = r.filter((e) => !(n ?? []).includes(e));
297
+ if (i.length > 0) {
298
+ for (let e of i) console.error(`No skills installed for ${e}. Run \`npx web-ui install skills --harness=${e}\` first.`);
299
+ process.exitCode = 1;
300
+ return;
301
+ }
302
+ h.intro("@imfusion/web-ui install hooks");
303
+ try {
304
+ me(r);
305
+ } catch (e) {
306
+ if (e instanceof U) {
307
+ console.error(e.message), process.exitCode = 1;
308
+ return;
309
+ }
310
+ throw e;
311
+ }
312
+ h.outro("Done — agent hooks installed.");
313
+ }
314
+ var Q = new te();
315
+ Q.name("web-ui").description("Command-line tools for @imfusion/web-ui").version(N);
316
+ var $ = Q.command("install").description("Install @imfusion/web-ui agent skills or hooks into a project");
317
+ $.command("skills").description("Install skills for the chosen harness").addOption(Z()).option("--reconfigure", "Re-open the harness selection prompt on an existing install").action(ge), $.command("hooks").description("Install agent lifecycle hooks (requires skills already installed for the harness)").addOption(Z()).action(_e), $.action(() => {
318
+ $.help();
319
+ }), Q.action(() => {
320
+ Q.help();
321
+ }), await Q.parseAsync();
322
+ //#endregion
@@ -0,0 +1,127 @@
1
+ import { Meta } from "@storybook/addon-docs/blocks";
2
+
3
+ <Meta title="User Guide/Agent Tooling" />
4
+
5
+ # Agent tooling
6
+
7
+ The package ships skills and lifecycle hooks for coding agents working in a project that uses `@imfusion/web-ui`. Both are
8
+ optional, but highly recommended: the library is built to be set up and used through an agent.
9
+
10
+ ## Supported agents
11
+
12
+ The skills follow the [Agent Skills](https://agentskills.io/) standard and install into `.agents/skills/`. Project
13
+ instructions go into [`AGENTS.md`](https://agents.md/): when the project has one, the installer keeps a fenced Web UI block
14
+ in it up to date.
15
+
16
+ | Agent | Skills | `AGENTS.md` | Hooks |
17
+ | --- | --- | --- | --- |
18
+ | [Codex](https://developers.openai.com/codex/skills) | Reads `.agents/skills/` | [Reads it](https://developers.openai.com/codex/guides/agents-md) | [Supported](https://developers.openai.com/codex/hooks) |
19
+ | [Claude Code](https://code.claude.com/docs/en/skills) | Reads only `.claude/skills/`, so the installer links each skill there | [Reads it](https://code.claude.com/docs/en/changelog#2-1-277) when the project has no `CLAUDE.md`; otherwise add `@AGENTS.md` to `CLAUDE.md` | [Supported](https://code.claude.com/docs/en/hooks) |
20
+ | Other Agent Skills clients | Check the agent's docs for `.agents/skills/` | Check the agent's docs | Not installed |
21
+
22
+ The installer targets Codex and Claude Code. Other agents that implement the standard are listed on
23
+ [agentskills.io](https://agentskills.io/); one that reads `.agents/skills/` picks up the same skills, without the hooks.
24
+
25
+ ## Install
26
+
27
+ Install the package first, then run this in the project root:
28
+
29
+ ```sh
30
+ npx web-ui install skills --harness=all
31
+ npx web-ui install hooks --harness=all
32
+ ```
33
+
34
+ `--harness` picks the agent the tooling is installed for:
35
+
36
+ | Value | Installs for |
37
+ | --- | --- |
38
+ | `claude` | Claude Code |
39
+ | `codex` | Codex, and any agent that reads `.agents/skills/` |
40
+ | `all` | Both |
41
+
42
+ Without `--harness`, `install skills` prompts once and records the choice, and later runs reuse it. `install hooks` needs the
43
+ skills installed for the same harness first. Leave out the second command to install only the skills.
44
+
45
+ `npx web-ui --help` lists the commands, and `--help` on any subcommand lists its options.
46
+
47
+ ## Skills
48
+
49
+ `/imf-web-ui` is the router: the entry point for UI work and library questions. It routes usage questions to the packaged user
50
+ guides and development tasks to the matching companion skill, and it keeps small tasks small instead of loading every
51
+ reference just because the package is installed.
52
+
53
+ With the hooks installed, the agent is pointed at the router at the start of every session. Without them, the agent usually
54
+ picks it up from the skill's description; invoke it by name when it does not.
55
+
56
+ | Skill | Use it for |
57
+ | --- | --- |
58
+ | `/imf-web-ui` | The router: any UI task or library question. |
59
+ | `/imf-web-ui-components` | Component props, parts, defaults, and icons. |
60
+ | `/imf-web-ui-ux` | Choosing components and shaping screens or flows. |
61
+ | `/imf-web-ui-conventions` | Code, styling, data, validation, and project conventions. |
62
+ | `/imf-web-ui-setup` | First-time wiring and approved project setup. |
63
+ | `/imf-web-ui-audit` | A read-only check of an existing project. |
64
+ | `/imf-web-ui-update` | Updating the package and its installed tooling. |
65
+
66
+ ## Hooks
67
+
68
+ The hooks put the agent on the right skill at the right moment and ask it to verify the project after it edits source files:
69
+
70
+ | Event | What the hook does |
71
+ | --- | --- |
72
+ | `SessionStart` | Points the agent at the router once per session. |
73
+ | `SubagentStart` | Gives the same pointer to spawned agents. |
74
+ | `UserPromptSubmit` | Names the companion skills relevant to the prompt. |
75
+ | `Stop` | Asks for project verification after a turn edits source files. |
76
+
77
+ ## Keeping it current
78
+
79
+ Ask the agent to update the library, for example "Update @imfusion/web-ui". That runs `/imf-web-ui-update`, which installs
80
+ the newer package and refreshes the skills, hook scripts, and registrations to match it.
81
+
82
+ To do the same by hand, update the package, then run:
83
+
84
+ ```sh
85
+ npx web-ui install skills
86
+ npx web-ui install hooks
87
+ ```
88
+
89
+ Both reuse the recorded harness. Leave out the second command if the project skips hooks. Together they bring the installed
90
+ tooling in line with the package version and remove anything the package no longer ships.
91
+
92
+ ## Reference
93
+
94
+ ### Where the files go
95
+
96
+ - Skills: `.agents/skills/` for every harness. `claude` also links each skill from `.claude/skills/`.
97
+ - Hook scripts: `.agents/hooks/imf-web-ui/`.
98
+ - Hook registrations: `.claude/settings.json` for Claude Code, `.codex/hooks.json` for Codex.
99
+
100
+ ### Changing the harness
101
+
102
+ Pass a different `--harness`, or `--reconfigure` to get the prompt again. Dropping `claude` removes its `.claude/skills`
103
+ links. The next `install hooks` run removes the registrations from a harness that is no longer selected and adds them for the
104
+ newly selected one.
105
+
106
+ ### What the installer owns
107
+
108
+ The installer owns every skill directory named `imf-web-ui` or `imf-web-ui-*`. It overwrites and prunes those directories and
109
+ leaves every other skill alone, so a project must not put its own skills under that prefix.
110
+
111
+ Hook registrations merge into the chosen harness's file without touching unrelated entries. For each event, the installer
112
+ adds a shipped hook unless that same script is already registered there; other hooks on that event stay alongside it.
113
+
114
+ An agent reads the `agent-tooling` topic in the installed `imf-web-ui-conventions` skill before adapting a hook registration.
115
+
116
+ ### Codex trust
117
+
118
+ Codex only runs project hooks after the project is trusted and each script is approved through `/hooks`. Revisit that review
119
+ after a hook script changes. Claude Code has no equivalent trust gate.
120
+
121
+ ### Where the files come from
122
+
123
+ The skills ship inside the package under `src/llms/skills/`, and `web-ui install` copies them into the project. The package
124
+ also exposes generated component, token, and icon indexes for the lookup skill. User guides ship as readable MDX under
125
+ `docs/user-guide/`; agents read them from the installed package without a running Storybook.
126
+
127
+ <PageNav>Importing and composing components, then changing their look with tokens, CSS, and state attributes.</PageNav>