@adia-ai/web-components 0.8.36 → 0.8.38

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 (52) hide show
  1. package/CHANGELOG.md +29 -0
  2. package/MIGRATION.md +248 -45
  3. package/README.md +3 -3
  4. package/bin/doc.mjs +27 -5
  5. package/components/card/card.css +1 -1
  6. package/components/drilldown/drilldown.a2ui.json +242 -0
  7. package/components/drilldown/drilldown.class.js +542 -0
  8. package/components/drilldown/drilldown.css +305 -0
  9. package/components/drilldown/drilldown.d.ts +68 -0
  10. package/components/drilldown/drilldown.examples.md +20 -0
  11. package/components/drilldown/drilldown.js +17 -0
  12. package/components/drilldown/drilldown.yaml +271 -0
  13. package/components/index.js +1 -0
  14. package/components/inspector/inspector.class.js +1 -1
  15. package/components/nav/nav.class.js +11 -8
  16. package/components/nav-item/nav-item.class.js +9 -6
  17. package/components/page/page.a2ui.json +13 -1
  18. package/components/page/page.css +113 -0
  19. package/components/page/page.yaml +30 -3
  20. package/components/table-toolbar/table-toolbar.examples.md +3 -3
  21. package/core/streams-bridge.d.ts +2 -2
  22. package/core/streams-bridge.js +1 -1
  23. package/custom-elements.json +183 -26
  24. package/dist/theme-provider.min.js +1 -1
  25. package/dist/web-components.min.css +1 -1
  26. package/dist/web-components.min.js +103 -84
  27. package/dist/web-components.sheet.js +1 -1
  28. package/package.json +3 -3
  29. package/patterns/admin-keys-and-export/admin-keys-and-export.examples.html +8 -8
  30. package/patterns/agent-cost/agent-cost.examples.html +3 -3
  31. package/patterns/agent-memory/agent-memory.examples.html +4 -4
  32. package/patterns/agent-prompt-library/agent-prompt-library.examples.html +8 -8
  33. package/patterns/approvals/approvals.examples.html +2 -2
  34. package/patterns/bulk-action-toolbar/bulk-action-toolbar.examples.html +1 -1
  35. package/patterns/changelog-feed/changelog-feed.examples.html +1 -1
  36. package/patterns/comments-and-collaboration/comments-and-collaboration.examples.html +7 -7
  37. package/patterns/data-tables-inline-edit-and-tree/data-tables-inline-edit-and-tree.examples.html +4 -4
  38. package/patterns/diff-review/diff-review.examples.html +6 -6
  39. package/patterns/filter-bar/filter-bar.examples.html +5 -5
  40. package/patterns/inline-dialog/inline-dialog.examples.html +1 -1
  41. package/patterns/kanban-board/kanban-board.examples.html +12 -12
  42. package/patterns/layout/layout.examples.html +3 -3
  43. package/patterns/marketing-engagement/marketing-engagement.examples.html +13 -13
  44. package/patterns/notifications-bell-and-digest/notifications-bell-and-digest.examples.html +1 -1
  45. package/patterns/permissions-matrix/permissions-matrix.examples.html +1 -1
  46. package/patterns/permissions-role-picker/permissions-role-picker.examples.html +1 -1
  47. package/patterns/permissions-sharing/permissions-sharing.examples.html +3 -3
  48. package/patterns/profile-public-and-verification/profile-public-and-verification.examples.html +2 -2
  49. package/patterns/search-discovery/search-discovery.examples.html +15 -15
  50. package/styles/components.css +1 -0
  51. package/styles/type/scale.css +2 -1
  52. package/traits/view-transition/view-transition.js +7 -0
package/CHANGELOG.md CHANGED
@@ -1,5 +1,34 @@
1
1
  # Changelog — @adia-ai/web-components
2
2
 
3
+ ## [0.8.38] — 2026-08-15
4
+
5
+ ### Added
6
+ - **`drilldown-ui` — a new single-panel, multi-level drill-in menu primitive (gh#1285).** Replaces the hand-rolled miller-columns shape (two stacked list columns) that adiav2's Schema Manager had to build because the kit had no drill-down primitive — cleared the pre-build audit against `tree-ui` (inline expand/collapse, wrong for wide/deep >2-level data), `segmented-ui` (no overflow behavior for 18 namespaces), `tag-ui`-as-menu (no keyboard path), `list-ui`/`nav-ui`/`menu-ui`/`context-menu`/`breadcrumb-ui` (flat, not hierarchical drill-in) — none provide single-panel level-swap navigation with back/focus-restoration. Data-driven (`.items` tree of `{value, label, meta?, dot?, counts?, children?}` nodes; `children` may be sync or an async `(item) => array | Promise<array>` lazy loader, rendering a `<skeleton-ui>` loading level while pending). Full keyboard path (roving-tabindex listbox per level; ArrowRight/Enter drills in, ArrowLeft/Backspace goes back with focus restored to the item drilled from), `select` + `navigate` events, a `path` property that reflects to a JSON-encoded attribute both ways (hand-managed, not the generic `reflect:` mechanism — array values don't round-trip through `String(v)`) for deep-link/URL restore, `[filterable]` filter input, `[select-on-drill]` mode flag, a `breadcrumb` slot, row-native trailing count chips (not full `<badge-ui>`, which reads oversized at row density), and a horizontal slide transition that honors `prefers-reduced-motion: reduce` automatically (also suppressible via `[static]`).
7
+
8
+ ### Fixed
9
+ - **`page-ui` header now ships the slot-gated grid its docs promised (gh#1253).** ADR-0009 recorded the named-slot vocabulary (`slot="icon"` / `slot="heading"` / `slot="action"`) as wired into four containers — Card, Drawer, Modal, and Page — but `page.css` never shipped its half; the slot attributes on a page header's children were dead metadata, so a block-level action child (e.g. `<toggle-scheme-ui>`) dropped to its own row instead of clustering. `page.css` gains the same `:has(> [slot])`-gated header grid as `card.css` (icon/heading/action columns, direct-child guard against nested false-positives), plus the `--page-header-gap` / `--page-heading-*` tokens `card-ui`'s pair already had. `page.yaml`'s `slots.default` and `page.examples.html` (new "Header slot-gated grid" demo) now describe the contract that's actually implemented.
10
+ - **`nav-ui` / `nav-item-ui` — `nav-select` now fires exactly once per click, and zero times re-clicking the already-selected item (gh#1254).** Root cause: two layered click handlers both drove selection for the same physical click — `nav-item-ui`'s own click handler called `nav.select(this)` *and* dispatched its own `nav-select`, while `nav-ui`'s click-delegation listener matched the same item on bubble and called `select()` again — three dispatches per click. `nav.select()` is now the single source of the event (idempotent: a no-op, including no hover-flush, when the item is already selected); `nav-item-ui` no longer dispatches its own copy, and `nav-ui`'s click listener no longer delegates item selection (it now only handles group expand/popover).
11
+ - **`view-transition` trait — no longer leaks unhandled `AbortError` rejections when a transition is superseded (gh#1255).** Only `transition.finished` had a `.catch()`; `ready` and `updateCallbackDone` are distinct promises that also reject (with `AbortError`) when a newer transition supersedes this one, and were previously uncaught. All three are now swallowed on abort — expected behavior for rapid navigation, not an error — with `fireEnd()` still driven solely by `finished`.
12
+
13
+ ### Maintenance
14
+ - **`bin/` touched in this release window** (1 file(s), e.g. `bin/doc.mjs`) — carried by the entries above.
15
+ - **`components/` touched in this release window** (18 file(s), e.g. `card/card.css`) — carried by the entries above.
16
+ - **`dist/` bundles rebuilt** in this cut's window (4 file(s)) — regenerated from the source changes described above, not independent edits.
17
+ - **`patterns/` touched in this release window** (1 file(s), e.g. `bulk-action-toolbar/bulk-action-toolbar.examples.html`) — carried by the entries above.
18
+ - **`styles/` touched in this release window** (1 file(s), e.g. `styles/components.css`) — carried by the entries above.
19
+ - **`traits/` touched in this release window** (2 file(s), e.g. `view-transition/view-transition.js`) — carried by the entries above.
20
+
21
+ ## [0.8.37] — 2026-08-14
22
+
23
+ ### Maintenance
24
+ - **Lockstep version bump only.** No source changes in this package; bumped to maintain the lockstep version coherence enforced by `scripts/release/check-lockstep.mjs`. Substantive v0.8.37 work shipped in ADR-0048 estate split: @adia-ai/{a2ui,gen-ui,mcp} first publish; six a2ui-* names ship as shims and retire. See `packages/mcp/CHANGELOG.md#0837--2026-08-14` for details.
25
+ - **`components/` touched in this release window** (123 file(s), e.g. `accordion/accordion.examples.html`) — carried by the entries above.
26
+ - **`core/` touched in this release window** (3 file(s), e.g. `core/element.test.js`) — carried by the entries above.
27
+ - **`dist/` bundles rebuilt** in this cut's window (1 file(s)) — regenerated from the source changes described above, not independent edits.
28
+ - **`patterns/` touched in this release window** (20 file(s), e.g. `admin-keys-and-export/admin-keys-and-export.examples.html`) — carried by the entries above.
29
+ - **`styles/` touched in this release window** (1 file(s), e.g. `type/scale.css`) — carried by the entries above.
30
+ - **`traits/` touched in this release window** (57 file(s), e.g. `active-state/active-state.examples.html`) — carried by the entries above.
31
+
3
32
  ## [0.8.36] — 2026-08-13
4
33
 
5
34
  ### Maintenance
package/MIGRATION.md CHANGED
@@ -52,10 +52,195 @@ Version cuts and migration scope:
52
52
 
53
53
  - **`0.8.11`** — PATCH lockstep cut (2026-07-23). Internal ranges stay at `^0.8.0`. **BREAKING: the size model.** Every component `size` enum is now exactly `sm | md | lg`; the removed tiers (`xs`, `xl`, icon's `2xl/3xl/4xl/fill`) are served by the new ancestor **`[scale]`** context — six hand-tabled tiers (`ui-sm · ui-md · ui-lg · content-sm · content-md · content-lg`): scale picks the table, `size` picks the row. `[verse]`/`[prose]` are deprecated aliases of `ui-sm`/`content-md` (removed at v1.0). Also new: `<adia-wordmark-ui>`. See [§ v0.8.11 section below](#migrating-to-adia-aiv0811-2026-07-23).
54
54
 
55
+ - **`0.8.37`** — PATCH lockstep cut. **BREAKING: the a2ui / gen-ui estate split (ADR-0048).** Six published package names (`a2ui-runtime`, `a2ui-compose`, `a2ui-corpus`, `a2ui-retrieval`, `a2ui-validator`, `a2ui-mcp`) are replaced by four (`a2ui`, `gen-ui`, `gen-ui-mcp`, `a2ui-protocol-mcp`). **A patch-shaped version number does not make this non-breaking** — every old name is renamed. One-cycle re-export shims bridge the gap; the cut AFTER `0.8.37` retires them. See [§ 0.8.37 — the a2ui / gen-ui estate split](#0837--the-a2ui--gen-ui-estate-split-adr-0048).
56
+
55
57
  Live demos and per-component docs at [ui-kit.exe.xyz/site/](https://ui-kit.exe.xyz/site/). The `adia-ui-migration` skill (in `.agents/skills/`) automates most of the mechanical sweeps in this guide.
56
58
 
57
59
  ---
58
60
 
61
+ ## `0.8.37` — the a2ui / gen-ui estate split (ADR-0048)
62
+
63
+ **Read this even though the version number is a patch.** The `0.8.37` lockstep
64
+ cut renames six published packages. Nothing about the rename is patch-shaped
65
+ except the number, which is an operator ruling (gh#1192, 2026-08-13) about
66
+ release cadence, not a claim that your imports keep working forever.
67
+
68
+ The split is by concept, ruled in `docs/adr/adr-0048-a2ui-gen-ui-estate-split.md`:
69
+
70
+ - **`@adia-ai/a2ui` — the protocol.** How one system renders gen-UI canvases
71
+ in another system, safely: renderer, registry, streams, surface, wiring,
72
+ dockables, prop-apply, schema, plus protocol-side validation. **Zero
73
+ dependencies** — no LLM stack, no corpus. This is what an embedding host
74
+ installs.
75
+ - **`@adia-ai/gen-ui` — the generation system.** compose + retrieval + corpus
76
+ + catalog-aware and LLM-judge validation, as one package.
77
+ - **Two MCP servers, one npm package.** `@adia-ai/mcp` (gh#1240 — folds what
78
+ were originally two planned packages, `@adia-ai/gen-ui-mcp` and
79
+ `@adia-ai/a2ui-protocol-mcp`, before either ever published) ships one bin,
80
+ `adia-mcp`, dispatching two subcommands as separate processes:
81
+ `adia-mcp gen-ui` (30 tools — the generation surface, direct successor of
82
+ `@adia-ai/a2ui-mcp`) and `adia-mcp protocol` (4 tools — `validate_document`,
83
+ `get_registry_map`, `get_wiring_registry`, `protocol_status`; renamed off
84
+ their original same-named-as-`gen-ui`-surface forms by gh#1248 before this
85
+ server ever published). The name `@adia-ai/a2ui-mcp` is **burned, never
86
+ reused**: it means "the generation MCP" to every consumer that has it
87
+ pinned, so it is deprecated with a pointer rather than repurposed.
88
+
89
+ ### The one-cycle bridge — what happens if you do nothing
90
+
91
+ At `0.8.37` every old name gets a final **shim publish**: a thin package whose
92
+ exports re-export the new package's matching subpaths. Because npm's caret is
93
+ minor-locked below 1.0, `0.8.37` satisfies the `^0.8.x` range you already
94
+ carry — so **an existing consumer floats onto the shim on its next
95
+ `npm install`, with no action and no broken import.** The `npm deprecate`
96
+ pointer on each old name tells you where to move.
97
+
98
+ That window is exactly one cycle. The follow-up PR deletes the shims from the
99
+ repo and the release roster, so **the cut after `0.8.37` is the one that breaks
100
+ an un-migrated consumer.** Migrate during the `0.8.37` line.
101
+
102
+ Two things the shim structurally cannot bridge, so migrate these first:
103
+
104
+ - **JSON-data subpaths of `@adia-ai/a2ui-corpus`** — the catalog,
105
+ `./manifest`, `./chunks`, `./chunks/*`, `./chunk-embeddings`. A JavaScript
106
+ forwarder cannot re-export a JSON module (`export *` drops `default`, and
107
+ Node requires `with { type: 'json' }`, which throws against a `.js` target).
108
+ These get pointer text only. The corpus package's one JS export,
109
+ `./chunk-library`, IS forwarded.
110
+ - **TypeScript types**, except the two subpaths the old package itself
111
+ published as `.d.ts` (`a2ui-runtime`'s `./schema` and `./types`). A one-cycle
112
+ bridge ships JS.
113
+
114
+ Also not minted, because they never worked on the published packages:
115
+ extension-suffixed alias forms (`@adia-ai/a2ui-runtime/registry.js`,
116
+ `@adia-ai/a2ui-compose/core/artifacts.js`). The published wildcard targets
117
+ already end in `.js`, so those specifiers resolved to `…/artifacts.js.js` and
118
+ failed at load. If you were writing them, they were already broken.
119
+
120
+ ### Subpath-export map (old → new)
121
+
122
+ | Old import | New import |
123
+ |---|---|
124
+ | `@adia-ai/a2ui-runtime` | `@adia-ai/a2ui` |
125
+ | `@adia-ai/a2ui-runtime/<sub>` (`registry`, `renderer`, `prop-apply`, `streams`, `surface`, `wiring`, `dockables`, `schema`, `types`) | `@adia-ai/a2ui/<sub>` (unchanged sub) |
126
+ | `@adia-ai/a2ui-validator` / `./validator` | `@adia-ai/a2ui/validate` |
127
+ | `@adia-ai/a2ui-validator/catalog` | `@adia-ai/gen-ui/validate/catalog` |
128
+ | `@adia-ai/a2ui-validator/semantic` (+`/*`) | `@adia-ai/gen-ui/validate/semantic` (+`/*`) |
129
+ | `@adia-ai/a2ui-compose` | `@adia-ai/gen-ui` (compose is the package's primary surface; root re-exports `generateUI`) |
130
+ | `@adia-ai/a2ui-compose/<sub>` (`core`, `strategies/*`, `transpiler`, `evals`, `shared/*`; incl. deprecated `engine`/`engines/*` aliases) | `@adia-ai/gen-ui/compose/<sub>` (aliases NOT carried over — they were already deprecated one cycle) |
131
+ | `@adia-ai/a2ui-retrieval` | `@adia-ai/gen-ui/retrieval` |
132
+ | `@adia-ai/a2ui-retrieval/<sub>` (e.g. `domain-router`, `intent/*`, `embedding/*`, `feedback/*`, `authoring/*`) | `@adia-ai/gen-ui/retrieval/<sub>` (e.g. `@adia-ai/gen-ui/retrieval/domain-router`) |
133
+ | `@adia-ai/a2ui-corpus` | **`@adia-ai/a2ui/catalog`** — this export WAS the catalog document, and the catalog moved protocol-side at ADR-0050 (gh#1243). `@adia-ai/gen-ui/corpus` no longer resolves as a root export |
134
+ | `@adia-ai/a2ui-corpus/<sub>` (`chunks/*`, `chunk-library`, `chunk-embeddings`, `manifest`) | `@adia-ai/gen-ui/corpus/<sub>` (unchanged — corpus fuel stays in gen-ui) |
135
+ | `@adia-ai/a2ui-mcp` (bin `adiaui-mcp`) | `@adia-ai/mcp` (bin `adia-mcp`, subcommand `gen-ui`) — retargeted gh#1240; the `@adia-ai/gen-ui-mcp` name this row originally named never published |
136
+ | — (new) | `@adia-ai/mcp` (bin `adia-mcp`, subcommand `protocol`) — folded into the same package as the row above by gh#1240; the `@adia-ai/a2ui-protocol-mcp` name this row originally named never published |
137
+
138
+ ### Mechanical sweeps
139
+
140
+ **First, hand-migrate the two deprecated compose aliases — the sweep below
141
+ cannot do it and will silently break them.** `@adia-ai/a2ui-compose` published
142
+ `./engine` and `./engines/*`, deprecated one cycle ago; they are **not** carried
143
+ over to `@adia-ai/gen-ui`. A blind prefix rewrite would turn them into
144
+ `@adia-ai/gen-ui/compose/engine{,s/…}`, which do not exist — and the post-sweep
145
+ grep would not catch it, because by then they carry the new package name.
146
+
147
+ ```bash
148
+ git grep -n '@adia-ai/a2ui-compose/engine' # must be empty before you sweep
149
+ ```
150
+
151
+ Any hit maps like this (the old alias and its successor resolve to the same
152
+ file, so this is a rename, not a behaviour change):
153
+
154
+ | Deprecated alias | Migrate to |
155
+ |---|---|
156
+ | `@adia-ai/a2ui-compose/engine` | `@adia-ai/gen-ui/compose/core` |
157
+ | `@adia-ai/a2ui-compose/engines/zettel` | `@adia-ai/gen-ui/compose/strategies/zettel` |
158
+ | `@adia-ai/a2ui-compose/engines/registry` | `@adia-ai/gen-ui/compose/strategies/registry` |
159
+ | `@adia-ai/a2ui-compose/engines/cascade` | `@adia-ai/gen-ui/compose/strategies/cascade` |
160
+ | `@adia-ai/a2ui-compose/engines/escalation` | `@adia-ai/gen-ui/compose/strategies/escalation` |
161
+
162
+ Then run the sweeps in this order — the longest specifier first, so a shorter
163
+ prefix doesn't eat a longer one:
164
+
165
+ ```bash
166
+ # One helper, three deliberate choices:
167
+ #
168
+ # 1. A `while` loop, not `| xargs perl -i -pe …`: with no matches, GNU xargs
169
+ # runs perl with NO file arguments and it hangs reading stdin. The loop
170
+ # body simply never executes.
171
+ # 2. The old/new strings go through the ENVIRONMENT, not the perl source —
172
+ # inlining them would let perl read `@adia-ai` on the replacement side as
173
+ # an array interpolation and silently substitute an empty string.
174
+ # 3. NUL-delimited (`-lz` + `read -d ''`), so a path containing a space
175
+ # survives — this repo's own "MIGRATION GUIDE.md" is one, and
176
+ # `for f in $(git grep -l …)` word-splits it into two nonexistent paths.
177
+ sweep() {
178
+ git grep -lz "$1" | while IFS= read -r -d '' f; do
179
+ OLD="$1" NEW="$2" perl -i -pe 'BEGIN{$o=$ENV{OLD};$n=$ENV{NEW}} s/\Q$o\E/$n/g' "$f"
180
+ done
181
+ }
182
+
183
+ # validator — longest specifier FIRST, so a shorter prefix doesn't eat it.
184
+ # `./validator` was a real published subpath and maps to the SAME target as the
185
+ # bare name; without its own line the generic rule below would produce
186
+ # `@adia-ai/a2ui/validate/validator`, which a2ui does not export (no `./validate/*`
187
+ # wildcard) → ERR_PACKAGE_PATH_NOT_EXPORTED.
188
+ sweep '@adia-ai/a2ui-validator/validator' '@adia-ai/a2ui/validate'
189
+ sweep '@adia-ai/a2ui-validator/catalog' '@adia-ai/gen-ui/validate/catalog'
190
+ sweep '@adia-ai/a2ui-validator/semantic' '@adia-ai/gen-ui/validate/semantic'
191
+ sweep '@adia-ai/a2ui-validator' '@adia-ai/a2ui/validate'
192
+
193
+ # generation system
194
+ sweep '@adia-ai/a2ui-compose/' '@adia-ai/gen-ui/compose/'
195
+ sweep '@adia-ai/a2ui-compose' '@adia-ai/gen-ui'
196
+ sweep '@adia-ai/a2ui-retrieval' '@adia-ai/gen-ui/retrieval'
197
+ sweep '@adia-ai/a2ui-corpus/' '@adia-ai/gen-ui/corpus/'
198
+ sweep '@adia-ai/a2ui-corpus' '@adia-ai/a2ui/catalog' # bare corpus import WAS the catalog (ADR-0050)
199
+
200
+ # protocol
201
+ sweep '@adia-ai/a2ui-runtime' '@adia-ai/a2ui'
202
+ ```
203
+
204
+ The helper takes paths from `git grep`, so it only ever touches tracked files —
205
+ `node_modules/` and build output are never rewritten.
206
+
207
+ Then fix your manifest by hand — a find-replace does not know the difference
208
+ between a dependency and a peer:
209
+
210
+ - **`dependencies` / `devDependencies`** on any renamed package → the new name
211
+ at the caret range for the cut (`^0.8.0`).
212
+ - **`peerDependencies`** stay **exact-pinned** to the lockstep version. If you
213
+ peer-pinned `@adia-ai/a2ui-runtime`, the pin moves to `@adia-ai/a2ui` —
214
+ moving the import without the peer pin leaves you resolving two runtimes.
215
+ - **MCP client config** (`.mcp.json`, Claude Desktop, Cursor): the generation
216
+ server's package and bin both change —
217
+ `npx -y @adia-ai/a2ui-mcp` → `npx -y @adia-ai/mcp gen-ui` (gh#1240 folded
218
+ the originally-planned `@adia-ai/gen-ui-mcp` name, and the separate protocol
219
+ MCP, into one package, `@adia-ai/mcp`, before either ever published — the
220
+ bin gained a subcommand accordingly). Tool names and their input/output
221
+ shapes are **unchanged**; only the package that serves them is renamed. The
222
+ 30-tool surface is documented at `packages/gen-ui/mcp/TOOLS.md` (the `gen-ui`
223
+ section).
224
+
225
+ ### After the sweep, check
226
+
227
+ - No `@adia-ai/a2ui-` specifier survives:
228
+ `git grep -nE '@adia-ai/a2ui-(runtime|compose|corpus|retrieval|validator|mcp)'`
229
+ should return nothing. (There is no exception to read past here —
230
+ `@adia-ai/a2ui-protocol-mcp` was the originally-planned protocol-server
231
+ name, but gh#1240 folded it into `@adia-ai/mcp`'s `protocol` subcommand
232
+ before it ever published, so it never became a real name to match.)
233
+ - **The grep above cannot see a mis-rewritten subpath**, because those carry
234
+ the new package name. Check the two classes it misses directly:
235
+ `git grep -nE '@adia-ai/gen-ui/compose/engines?(/|$)'` and
236
+ `git grep -n '@adia-ai/a2ui/validate/'` — both should return nothing.
237
+ Any hit is a specifier that does not exist and will fail at import.
238
+ - Your lockfile actually resolved the new names — a stale lockfile keeps
239
+ installing shims and hides the work until they retire.
240
+ - `npm ls @adia-ai/a2ui` shows one copy, not two.
241
+
242
+ ---
243
+
59
244
  ## Upcoming — variant/color/tone convention cut
60
245
 
61
246
  **One theme: every color-ish attribute owns exactly one axis.** `variant`/`tone` on badge & tag
@@ -77,7 +262,9 @@ have exactly one fill style each.
77
262
 
78
263
  ```bash
79
264
  git grep -nE '<badge-ui[^>]*variant="accent"'
80
- git grep -lE '<badge-ui[^>]*variant="accent"' | xargs perl -i -pe 's/(<badge-ui[^>]*variant=")accent(")/${1}primary${2}/g'
265
+ git grep -lz '<badge-ui[^>]*variant="accent"' | while IFS= read -r -d '' f; do
266
+ perl -i -pe 's/(<badge-ui[^>]*variant=")accent(")/${1}primary${2}/g' "$f"
267
+ done
81
268
  ```
82
269
 
83
270
  - **`<tag-ui variant="accent">` → `<tag-ui variant="primary">`** — identical rendering
@@ -85,7 +272,9 @@ have exactly one fill style each.
85
272
 
86
273
  ```bash
87
274
  git grep -nE '<tag-ui[^>]*variant="accent"'
88
- git grep -lE '<tag-ui[^>]*variant="accent"' | xargs perl -i -pe 's/(<tag-ui[^>]*variant=")accent(")/${1}primary${2}/g'
275
+ git grep -lz '<tag-ui[^>]*variant="accent"' | while IFS= read -r -d '' f; do
276
+ perl -i -pe 's/(<tag-ui[^>]*variant=")accent(")/${1}primary${2}/g' "$f"
277
+ done
89
278
  ```
90
279
 
91
280
  - **`<badge-ui variant="muted">` / `<badge-ui variant="neutral">` → `<badge-ui tone="muted">`**
@@ -97,7 +286,9 @@ have exactly one fill style each.
97
286
 
98
287
  ```bash
99
288
  git grep -nE '<badge-ui[^>]*variant="(muted|neutral)"'
100
- git grep -lE '<badge-ui[^>]*variant="(muted|neutral)"' | xargs perl -i -pe 's/(<badge-ui[^>]*)variant="(?:muted|neutral)"/${1}tone="muted"/g'
289
+ git grep -lz '<badge-ui[^>]*variant="(muted|neutral)"' | while IFS= read -r -d '' f; do
290
+ perl -i -pe 's/(<badge-ui[^>]*)variant="(?:muted|neutral)"/${1}tone="muted"/g' "$f"
291
+ done
101
292
  ```
102
293
 
103
294
  - **`<alert-ui variant="muted">` / `<alert-ui variant="neutral">` → drop the attribute** — both
@@ -113,8 +304,10 @@ have exactly one fill style each.
113
304
  ```bash
114
305
  EX=(-g '!*MIGRATION*' -g '!*CHANGELOG.md' -g '!**/dist/**' -g '!*.a2ui.json' -g '!*.examples.md')
115
306
  rg -nU '<alert-ui(\s[^>]*)?\svariant="(muted|neutral)"' "${EX[@]}"
116
- rg -lU '<alert-ui(\s[^>]*)?\svariant="(muted|neutral)"' "${EX[@]}" \
117
- | xargs perl -0777 -i -pe 's/(<alert-ui(?:\s[^>]*)?)\s+variant="(?:muted|neutral)"/${1}/gs'
307
+ rg -0 -lU '<alert-ui(\s[^>]*)?\svariant="(muted|neutral)"' "${EX[@]}" \
308
+ | while IFS= read -r -d '' f; do
309
+ perl -0777 -i -pe 's/(<alert-ui(?:\s[^>]*)?)\s+variant="(?:muted|neutral)"/${1}/gs' "$f"
310
+ done
118
311
  ```
119
312
 
120
313
  - **Programmatic setters (JS render paths — the sweep HTML greps miss):**
@@ -230,7 +423,9 @@ git grep -nE '"size": *"(xs|xl|2xl|3xl|4xl|fill)"' # A2UI/JSON form
230
423
 
231
424
  **Sweep (mechanical, non-icon tags):**
232
425
  ```bash
233
- git grep -lE 'size="(xs|xl)"' | xargs perl -i -pe 's/size="xs"/size="sm"/g; s/size="xl"/size="lg"/g'
426
+ git grep -lz 'size="(xs|xl)"' | while IFS= read -r -d '' f; do
427
+ perl -i -pe 's/size="xs"/size="sm"/g; s/size="xl"/size="lg"/g' "$f"
428
+ done
234
429
  ```
235
430
  Icon named tiers are a table-driven remap (`xs→"12"`, `xl→"32"`, `2xl→"48"`, `3xl→"64"`, `4xl→"96"`, `fill→"100%"`) — sweep them BEFORE the generic pass, and never touch already-free-form values (`size="48"`).
236
431
 
@@ -268,7 +463,9 @@ git grep -nE -- '--a-accent'
268
463
 
269
464
  **Sweep (mechanical):**
270
465
  ```bash
271
- git grep -lE -- '--a-accent' | xargs perl -i -pe 's/--a-accent(?![a-z0-9])/--a-primary/g'
466
+ git grep -lz -- '--a-accent' | while IFS= read -r -d '' f; do
467
+ perl -i -pe 's/--a-accent(?![a-z0-9])/--a-primary/g' "$f"
468
+ done
272
469
  ```
273
470
 
274
471
  (The `(?![a-z0-9])` guard keeps suffixed forms like `--a-accent-strong` → `--a-primary-strong` correct while never touching unrelated names. Prefer consuming `--md-sys-color-primary*` directly in new code.)
@@ -295,7 +492,9 @@ git grep -n 'primitives-accent'
295
492
 
296
493
  **Sweep (mechanical):**
297
494
  ```bash
298
- git grep -l 'primitives-accent' | xargs perl -i -pe 's/primitives-accent/primitives-primary/g'
495
+ git grep -lz 'primitives-accent' | while IFS= read -r -d '' f; do
496
+ perl -i -pe 's/primitives-accent/primitives-primary/g' "$f"
497
+ done
299
498
  ```
300
499
 
301
500
  ### Behavioral: named `[theme]` presets no longer re-color (manual review)
@@ -315,7 +514,7 @@ git grep -c 'primitives-accent' || echo clean # expect clean (item
315
514
  git grep -cE -- '--a-[a-z]+-[0-9]-(tint-|shade-)?scrim\b' || echo clean # expect clean (item 2)
316
515
  ```
317
516
 
318
- Then the browser gate on the migrated screens (`adia-verify`): zero console errors,
517
+ Then the browser gate on the migrated screens (`surface-qa`): zero console errors,
319
518
  non-zero bounding boxes, and read the screenshot — the scrim remap (item 2) and the
320
519
  `[theme]` behavioral change are visual; only the pixels prove overlay weights and
321
520
  brand color survived. Compare a before/after screenshot of one themed page if the
@@ -965,7 +1164,7 @@ Non-zero exit on regression. Used internally for the 6 in-repo consumers — pas
965
1164
  If you maintain your own shell-style components in your fork or extension:
966
1165
  - `<admin-shell>` host: 305 → **87 LOC** (-71%) at v0.4.0
967
1166
  - The bespoke pattern moves resize / collapse / persistence / dialog behavior INTO each child. The host coordinates only.
968
- - See [`bespoke-shell-children` skill](../../.agents/skills/adia-author/SKILL.md) for the canonical decomposition recipe.
1167
+ - See [`bespoke-shell-children` skill](../../.agents/skills/primitive-authoring/SKILL.md) for the canonical decomposition recipe.
969
1168
 
970
1169
  ### Don't roll back
971
1170
 
@@ -978,11 +1177,13 @@ Once on `0.4.0`, the legacy paths cannot be reactivated by config — they're ph
978
1177
  `grid-ui` has only ever accepted `columns="N"` (see [`packages/web-components/components/grid/grid.js:12`](../../packages/web-components/components/grid/grid.js#L12)). Pages authored with `cols=` were silently rendering as the default 3-column grid — the attribute was ignored. Sweep:
979
1178
 
980
1179
  ```bash
981
- git grep -nlE '<grid-ui[^>]*\bcols=' \
982
- | xargs perl -i -pe 's/(<grid-ui[^>]*?)\bcols=/$1columns=/g'
1180
+ git grep -nlz '<grid-ui[^>]*\bcols=' \
1181
+ | while IFS= read -r -d '' f; do
1182
+ perl -i -pe 's/(<grid-ui[^>]*?)\bcols=/$1columns=/g' "$f"
1183
+ done
983
1184
  ```
984
1185
 
985
- Then re-run `npm run harvest:chunks` if any of the touched pages live under `site/pages/` and are tagged with `data-chunk` (extracts to `packages/a2ui/corpus/chunks/`).
1186
+ Then re-run `npm run harvest:chunks` if any of the touched pages live under `site/pages/` and are tagged with `data-chunk` (extracts to `packages/gen-ui/a2ui/corpus/chunks/`).
986
1187
 
987
1188
  ---
988
1189
 
@@ -1355,46 +1556,48 @@ Not a break, but pairs with §1. `<button-ui>` now accepts `[color="default | ac
1355
1556
 
1356
1557
  ```bash
1357
1558
  # 1. button variant=danger → color=danger (sweep HTML)
1358
- git grep -nlE 'button-ui[^>]*variant="danger"' \
1359
- | xargs perl -i -pe 's/(<button-ui[^>]*?)variant="danger"/$1color="danger"/g'
1559
+ git grep -nlz 'button-ui[^>]*variant="danger"' \
1560
+ | while IFS= read -r -d '' f; do perl -i -pe 's/(<button-ui[^>]*?)variant="danger"/$1color="danger"/g' "$f"; done
1360
1561
 
1361
1562
  # 2. timeline-item-ui Booleans → status enum
1362
- git grep -nlE '<timeline-item-ui[^>]*\bcompleted\b' \
1363
- | xargs perl -i -pe 's/(<timeline-item-ui[^>]*?)\bcompleted\b/$1status="completed"/g'
1364
- git grep -nlE '<timeline-item-ui[^>]*\bactive\b' \
1365
- | xargs perl -i -pe 's/(<timeline-item-ui[^>]*?)\bactive\b/$1status="active"/g'
1366
- git grep -nlE '<timeline-item-ui[^>]*\berror\b' \
1367
- | xargs perl -i -pe 's/(<timeline-item-ui[^>]*?)\berror\b/$1status="error"/g'
1563
+ git grep -nlz '<timeline-item-ui[^>]*\bcompleted\b' \
1564
+ | while IFS= read -r -d '' f; do perl -i -pe 's/(<timeline-item-ui[^>]*?)\bcompleted\b/$1status="completed"/g' "$f"; done
1565
+ git grep -nlz '<timeline-item-ui[^>]*\bactive\b' \
1566
+ | while IFS= read -r -d '' f; do perl -i -pe 's/(<timeline-item-ui[^>]*?)\bactive\b/$1status="active"/g' "$f"; done
1567
+ git grep -nlz '<timeline-item-ui[^>]*\berror\b' \
1568
+ | while IFS= read -r -d '' f; do perl -i -pe 's/(<timeline-item-ui[^>]*?)\berror\b/$1status="error"/g' "$f"; done
1368
1569
 
1369
1570
  # 3. stepper-item-ui similarly
1370
- git grep -nlE '<stepper-item-ui[^>]*\bcompleted\b' \
1371
- | xargs perl -i -pe 's/(<stepper-item-ui[^>]*?)\bcompleted\b/$1status="completed"/g'
1571
+ git grep -nlz '<stepper-item-ui[^>]*\bcompleted\b' \
1572
+ | while IFS= read -r -d '' f; do perl -i -pe 's/(<stepper-item-ui[^>]*?)\bcompleted\b/$1status="completed"/g' "$f"; done
1372
1573
 
1373
1574
  # 4. pipeline-status-ui complete → status=completed (note spelling)
1374
- git grep -nlE '<pipeline-status-ui[^>]*\bcomplete\b' \
1375
- | xargs perl -i -pe 's/(<pipeline-status-ui[^>]*?)\bcomplete\b/$1status="completed"/g'
1376
-
1377
- # 5. event listeners
1378
- git grep -nE "addEventListener.*'chat-submit'" \
1379
- | xargs perl -i -pe "s/'chat-submit'/'submit'/g"
1380
- git grep -nE "addEventListener.*'legend-toggle'" \
1381
- | xargs perl -i -pe "s/'legend-toggle'/'toggle'/g"
1382
- git grep -nE "addEventListener.*'slide-change'" \
1383
- | xargs perl -i -pe "s/'slide-change'/'change'/g"
1575
+ git grep -nlz '<pipeline-status-ui[^>]*\bcomplete\b' \
1576
+ | while IFS= read -r -d '' f; do perl -i -pe 's/(<pipeline-status-ui[^>]*?)\bcomplete\b/$1status="completed"/g' "$f"; done
1577
+
1578
+ # 5. event listeners — note -l (files-with-matches), not -n: the old form piped
1579
+ # `grep -n` (file:line:text) straight into `perl -i`, handing perl a bogus
1580
+ # "filename" that never exists.
1581
+ git grep -lz "addEventListener.*'chat-submit'" \
1582
+ | while IFS= read -r -d '' f; do perl -i -pe "s/'chat-submit'/'submit'/g" "$f"; done
1583
+ git grep -lz "addEventListener.*'legend-toggle'" \
1584
+ | while IFS= read -r -d '' f; do perl -i -pe "s/'legend-toggle'/'toggle'/g" "$f"; done
1585
+ git grep -lz "addEventListener.*'slide-change'" \
1586
+ | while IFS= read -r -d '' f; do perl -i -pe "s/'slide-change'/'change'/g" "$f"; done
1384
1587
 
1385
1588
  # 6. error → danger on toast/alert/tag (one component at a time so other variant=error don't collide)
1386
- git grep -nlE '<toast-ui[^>]*variant="error"' \
1387
- | xargs perl -i -pe 's/(<toast-ui[^>]*?)variant="error"/$1variant="danger"/g'
1388
- git grep -nlE '<alert-ui[^>]*variant="error"' \
1389
- | xargs perl -i -pe 's/(<alert-ui[^>]*?)variant="error"/$1variant="danger"/g'
1390
- git grep -nlE '<tag-ui[^>]*variant="error"' \
1391
- | xargs perl -i -pe 's/(<tag-ui[^>]*?)variant="error"/$1variant="danger"/g'
1589
+ git grep -nlz '<toast-ui[^>]*variant="error"' \
1590
+ | while IFS= read -r -d '' f; do perl -i -pe 's/(<toast-ui[^>]*?)variant="error"/$1variant="danger"/g' "$f"; done
1591
+ git grep -nlz '<alert-ui[^>]*variant="error"' \
1592
+ | while IFS= read -r -d '' f; do perl -i -pe 's/(<alert-ui[^>]*?)variant="error"/$1variant="danger"/g' "$f"; done
1593
+ git grep -nlz '<tag-ui[^>]*variant="error"' \
1594
+ | while IFS= read -r -d '' f; do perl -i -pe 's/(<tag-ui[^>]*?)variant="error"/$1variant="danger"/g' "$f"; done
1392
1595
 
1393
1596
  # 7. chat-input busy → loading
1394
- git grep -nlE '<chat-input-ui[^>]*\bbusy\b' \
1395
- | xargs perl -i -pe 's/(<chat-input-ui[^>]*?)\bbusy\b/$1loading/g'
1396
- git grep -nlE 'chatInput\.busy' \
1397
- | xargs perl -i -pe 's/chatInput\.busy/chatInput.loading/g'
1597
+ git grep -nlz '<chat-input-ui[^>]*\bbusy\b' \
1598
+ | while IFS= read -r -d '' f; do perl -i -pe 's/(<chat-input-ui[^>]*?)\bbusy\b/$1loading/g' "$f"; done
1599
+ git grep -nlz 'chatInput\.busy' \
1600
+ | while IFS= read -r -d '' f; do perl -i -pe 's/chatInput\.busy/chatInput.loading/g' "$f"; done
1398
1601
 
1399
1602
  # 8. agent-trace open → no attr (default visible) OR collapsed
1400
1603
  # Manual review: default-visible is the new default; consumers that wrote
@@ -1405,8 +1608,8 @@ git grep -nE '<agent-trace-ui'
1405
1608
  # 9. avatar-ui name= → text= (deprecated alias, scheduled for removal)
1406
1609
  # `name=` still works in 0.0.20+ but fires a one-shot console warning
1407
1610
  # per page. Sweep before the next major to avoid the upcoming break.
1408
- git grep -nlE '<avatar-ui[^>]*\bname=' \
1409
- | xargs perl -i -pe 's/(<avatar-ui[^>]*?\s)name=/\1text=/g'
1611
+ git grep -nlz '<avatar-ui[^>]*\bname=' \
1612
+ | while IFS= read -r -d '' f; do perl -i -pe 's/(<avatar-ui[^>]*?\s)name=/\1text=/g' "$f"; done
1410
1613
  ```
1411
1614
 
1412
1615
  The `adia-ui-migration` skill in `.claude/skills/adia-ui-migration/` automates these sweeps and runs the verification gate after.
package/README.md CHANGED
@@ -3,7 +3,7 @@
3
3
  Vanilla web components + A2UI runtime for AdiaUI. **95 light-DOM custom
4
4
  elements** + **56 composable traits**, a reactive core (signals + tagged-template renderer), form-associated form controls, and integration into the A2UI generation pipeline.
5
5
 
6
- > This package ships UI atoms only. Composite shells (admin / chat / editor / simple / theme) live in [`@adia-ai/web-modules`](../web-modules). The generation pipeline lives in [`@adia-ai/a2ui-compose`](../a2ui/compose); the pattern corpus in [`@adia-ai/a2ui-corpus`](../a2ui/corpus); the MCP server in [`@adia-ai/a2ui-mcp`](../a2ui/mcp).
6
+ > This package ships UI atoms only. Composite shells (admin / chat / editor / simple / theme) live in [`@adia-ai/web-modules`](../web-modules). The generation pipeline lives in [`@adia-ai/a2ui-compose`](../gen-ui/engine/compose); the pattern corpus in [`@adia-ai/a2ui-corpus`](../gen-ui/engine/corpus); the MCP server in [`@adia-ai/mcp`](../gen-ui/mcp) (its `gen-ui` surface).
7
7
  >
8
8
  > **Consumer guide:** [`USAGE.md`](./USAGE.md) — property reactivity, event contract, form participation, lifecycle, registration, TypeScript. Start here if you're integrating AdiaUI into an app.
9
9
  >
@@ -125,7 +125,7 @@ web-components/
125
125
  │ All actual A2UI runtime code (renderer,
126
126
  │ registry, streams, surface manifest,
127
127
  │ wiring, dockables, controllers) lives in
128
- │ `@adia-ai/a2ui-runtime` at packages/a2ui/runtime/.
128
+ │ `@adia-ai/a2ui` at packages/gen-ui/a2ui/.
129
129
 
130
130
  └── styles/ — Global tokens and CSS layering
131
131
  ├── tokens.css all --a-* design tokens
@@ -329,7 +329,7 @@ attribute table + live demos:
329
329
  npm run build:components # regenerate all .a2ui.json from YAML
330
330
  ```
331
331
 
332
- The build also writes `packages/a2ui/corpus/catalog-a2ui_0_9.json` and
332
+ The build also writes `packages/gen-ui/engine/corpus/catalog-a2ui_0_9.json` and
333
333
  `catalog-a2ui_0_9_rules.txt` — the flat-file catalog the MCP server and
334
334
  generation engine consume.
335
335
 
package/bin/doc.mjs CHANGED
@@ -45,6 +45,32 @@ const DEMO_BASE = 'https://ui-kit.exe.xyz/site/components';
45
45
  * Defensive: any parse error returns a partial object plus an `_errors`
46
46
  * array — the caller decides how to surface failures.
47
47
  */
48
+ /**
49
+ * Strips a trailing YAML comment from a single raw line. A `#` only
50
+ * starts a comment when it's at column 0 or preceded by whitespace (the
51
+ * YAML plain-scalar rule) — a bare mid-word `#` (e.g. `gh#1253` inside a
52
+ * folded description block) is content, not a comment marker. Quote
53
+ * state is tracked (paired ' / ") so a `#` inside an actual quoted
54
+ * string is never treated as a comment start either.
55
+ *
56
+ * Fixes a truncation bug (CodeRabbit, PR #1284): the previous regex
57
+ * (`/^([^#"']*)(#.*)?$/`) cut ANY line at its first bare `#` regardless
58
+ * of context, silently truncating descriptions containing `gh#NNNN`.
59
+ */
60
+ function stripYamlComment(line) {
61
+ let inSingle = false;
62
+ let inDouble = false;
63
+ for (let i = 0; i < line.length; i++) {
64
+ const ch = line[i];
65
+ if (ch === "'" && !inDouble) inSingle = !inSingle;
66
+ else if (ch === '"' && !inSingle) inDouble = !inDouble;
67
+ else if (ch === '#' && !inSingle && !inDouble && (i === 0 || /\s/.test(line[i - 1]))) {
68
+ return line.slice(0, i).replace(/\s+$/, '');
69
+ }
70
+ }
71
+ return line.replace(/\s+$/, '');
72
+ }
73
+
48
74
  function parseYaml(source) {
49
75
  const out = {
50
76
  name: '',
@@ -59,11 +85,7 @@ function parseYaml(source) {
59
85
 
60
86
  // Strip comments + trailing whitespace, keep blank lines for block detection
61
87
  const rawLines = source.split(/\r?\n/);
62
- const lines = rawLines.map((l) => {
63
- // strip line comments unless inside a quoted string (rough heuristic)
64
- const m = l.match(/^([^#"']*)(#.*)?$/);
65
- return m ? m[1].replace(/\s+$/, '') : l;
66
- });
88
+ const lines = rawLines.map(stripYamlComment);
67
89
 
68
90
  /** Find the line range of a top-level key block (indent === 0). */
69
91
  function blockRange(key) {
@@ -264,7 +264,7 @@
264
264
  /* Heading — row 1.
265
265
  Matches native h1-h6 AND the text-ui variants the A2UI transpiler emits
266
266
  for them (display|title|heading|subsection — see HTML_TAG_MAP in
267
- packages/a2ui/compose/transpiler/transpiler-maps.js).
267
+ packages/gen-ui/a2ui/compose/transpiler/transpiler-maps.js).
268
268
  The text-ui variants are matched only when UNSLOTTED so an explicit
269
269
  `slot="heading"` / `slot="description"` / `slot="action"` always wins. */
270
270
  & > header > :is([slot="heading"], h1, h2, h3, h4, h5, h6),