@adia-ai/a2ui-compose 0.7.26 → 0.7.27
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md
CHANGED
|
@@ -1,4 +1,13 @@
|
|
|
1
1
|
# Changelog — @adia-ai/a2ui-compose
|
|
2
|
+
## [0.7.27] — 2026-07-12
|
|
3
|
+
|
|
4
|
+
### Fixed
|
|
5
|
+
- **Transpiler — `[span]` is now universally preserved (TKT-0002).** `extractProps()` had a universal preserve for `[slot]` but not `[span]` — the same class of cross-cutting, layout-bearing attribute, consumed purely via `grid.css`'s `& > [span="N"]` child selectors and never declared in any component's own yaml `props:`. Every transpiled asymmetric grid collapsed to equal columns (the admin-dashboard's 3:2 Overview/Recent-Sales split was the operator-reported case). Regression tests cover `span="3"`, `span="full"`, and the absent case.
|
|
6
|
+
- **Transpiler — `Tag` is a leaf type; labels ride the `text` prop (TKT-0004 A).** `Tag` was missing from `LEAF_TYPES`, so `<tag-ui size="sm">label</tag-ui>` transpiled to `Tag > Text variant=body` — a full body-size paragraph inside the pill, inflating every converted chip (581 instances across 233 docs pages measured). Labels now ride tag.yaml's documented `attr(text)` contract, in both the pure-text and element-children extraction paths.
|
|
7
|
+
- **`strategies/zettel/issue-reporter.js` — issue storage repointed to `qa/findings/issues/`.** The previous path would have silently recreated the retired `.brain/` tree at runtime on the first `report_issue` call.
|
|
8
|
+
|
|
9
|
+
### Maintenance
|
|
10
|
+
- Transpiler test suite: `extract-props.test.js` 19 → 24 cases (span preservation ×3, Tag text contract ×2).
|
|
2
11
|
|
|
3
12
|
## [0.7.26] — 2026-07-04
|
|
4
13
|
|
|
@@ -916,7 +925,7 @@ See root [CHANGELOG.md `[Unreleased]`](../../../CHANGELOG.md) for the v0.4.5 ove
|
|
|
916
925
|
- **`compose/strategies/monolithic/generate-pro.js` + companion `_shared/fragment-expander.js` — fragment machinery removed (§37).** Fragments retired; 85 compositions inlined with previously-referenced fragment content. Expander deleted; its caller's try/catch in `generator-adapter.js` handles the absence gracefully.
|
|
917
926
|
- **MCP server `mcp/server.js` (§37).** Removed `get_fragment` tool, simplified `zettel_stats`, updated imports + boot logs + engine description to reflect the post-fragment world.
|
|
918
927
|
|
|
919
|
-
See root [CHANGELOG.md `[Unreleased]`](../../../CHANGELOG.md) for the cross-cutting arc narrative +
|
|
928
|
+
See root [CHANGELOG.md `[Unreleased]`](../../../CHANGELOG.md) for the cross-cutting arc narrative + `.claude/docs/journal/2026/05/2026-05-12.md` §§ 37 / 38 / 41 / 47 for per-§ details.
|
|
920
929
|
## [0.4.3] - 2026-05-11
|
|
921
930
|
|
|
922
931
|
### Fixed
|
|
@@ -1200,7 +1209,7 @@ packages now share one version, governed by
|
|
|
1200
1209
|
[`.claude/docs/specs/package-architecture.md` § 15 (Versioning Policy)](../../../.claude/docs/specs/package-architecture.md#15-versioning-policy).
|
|
1201
1210
|
This release also lands the `engine/` ↔ `engines/` collision fix from
|
|
1202
1211
|
T3 of the
|
|
1203
|
-
|
|
1212
|
+
`.claude/docs/plans/packages-architecture-fixes-2026-05-02.md`
|
|
1204
1213
|
plan.
|
|
1205
1214
|
|
|
1206
1215
|
### Changed
|
|
@@ -1255,8 +1264,8 @@ multi-turn surface, plus a first-class telemetry surface that auto-fires
|
|
|
1255
1264
|
issue tickets on engine failure paths.
|
|
1256
1265
|
|
|
1257
1266
|
Spec: [`.claude/docs/specs/genui-multiturn-architecture.md`](../../../.claude/docs/specs/genui-multiturn-architecture.md) (Active v0.1.0).
|
|
1258
|
-
Plan:
|
|
1259
|
-
ADR:
|
|
1267
|
+
Plan: `.claude/docs/plans/genui-multiturn-rollout-2026-04-28.md` (Phase A scoped).
|
|
1268
|
+
ADR: `0008-multiturn-genui-architecture.md`.
|
|
1260
1269
|
|
|
1261
1270
|
### Added (engine modules)
|
|
1262
1271
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@adia-ai/a2ui-compose",
|
|
3
|
-
"version": "0.7.
|
|
3
|
+
"version": "0.7.27",
|
|
4
4
|
"description": "AdiaUI A2UI compose engine \u2014 framework-agnostic. Takes natural-language intents + a catalog and produces A2UI protocol messages. Pairs with `@adia-ai/a2ui-retrieval` (intent classification, catalog lookup) and `@adia-ai/a2ui-validator` (schema + semantic checks).",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"exports": {
|
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
* 3. Engine auto-fire — internal failure paths trigger `autoReport(reason)`.
|
|
8
8
|
* ctx.reporter = 'auto'. Suppressed when ctx.evalMode is true.
|
|
9
9
|
*
|
|
10
|
-
* Every issue lands as immutable JSON under
|
|
10
|
+
* Every issue lands as immutable JSON under `qa/findings/issues/`.
|
|
11
11
|
* Traces > 200KB spill to a sidecar `.trace.json` next to the issue.
|
|
12
12
|
*
|
|
13
13
|
* Spec: .claude/docs/specs/genui-multiturn-architecture.md §3.5 + §4.6 + §11.
|
|
@@ -23,7 +23,7 @@ import { fileURLToPath } from 'node:url';
|
|
|
23
23
|
|
|
24
24
|
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
25
25
|
const REPO_ROOT = resolve(__dirname, '../../../../..');
|
|
26
|
-
const DEFAULT_STORAGE_ROOT = resolve(REPO_ROOT, '
|
|
26
|
+
const DEFAULT_STORAGE_ROOT = resolve(REPO_ROOT, 'qa/findings/issues');
|
|
27
27
|
const TRACE_INLINE_THRESHOLD_BYTES = 200 * 1024;
|
|
28
28
|
|
|
29
29
|
const VALID_TYPES = new Set(['bug', 'training-gap', 'protocol-gap', 'ux-feedback']);
|
|
@@ -225,4 +225,39 @@ describe('§163 extractProps — catalog-driven prop fidelity', () => {
|
|
|
225
225
|
expect(props.variant).toBe('outline');
|
|
226
226
|
});
|
|
227
227
|
});
|
|
228
|
+
|
|
229
|
+
describe('TKT-0004 — Tag label via text prop (attr(text) contract)', () => {
|
|
230
|
+
it('falls back to light-DOM textContent when no text= attribute', () => {
|
|
231
|
+
const el = elem({ size: 'sm', variant: 'success' }, { text: '~1 min · no tools' });
|
|
232
|
+
const props = extractProps(el, 'Tag');
|
|
233
|
+
expect(props.text).toBe('~1 min · no tools');
|
|
234
|
+
expect(props.size).toBe('sm');
|
|
235
|
+
});
|
|
236
|
+
|
|
237
|
+
it('an explicit text= attribute wins over textContent', () => {
|
|
238
|
+
const el = elem({ text: 'explicit' }, { text: 'ignored light-dom' });
|
|
239
|
+
const props = extractProps(el, 'Tag');
|
|
240
|
+
expect(props.text).toBe('explicit');
|
|
241
|
+
});
|
|
242
|
+
});
|
|
243
|
+
|
|
244
|
+
describe('TKT-0002 — [span] universal preservation', () => {
|
|
245
|
+
it('preserves span on a Card (grid-ui child), same as slot', () => {
|
|
246
|
+
const el = elem({ span: '3' });
|
|
247
|
+
const props = extractProps(el, 'Card');
|
|
248
|
+
expect(props.span).toBe('3');
|
|
249
|
+
});
|
|
250
|
+
|
|
251
|
+
it('preserves span="full" verbatim (not coerced to a number)', () => {
|
|
252
|
+
const el = elem({ span: 'full' });
|
|
253
|
+
const props = extractProps(el, 'Card');
|
|
254
|
+
expect(props.span).toBe('full');
|
|
255
|
+
});
|
|
256
|
+
|
|
257
|
+
it('omits span when absent — no stray empty prop', () => {
|
|
258
|
+
const el = elem({});
|
|
259
|
+
const props = extractProps(el, 'Card');
|
|
260
|
+
expect(props.span).toBeUndefined();
|
|
261
|
+
});
|
|
262
|
+
});
|
|
228
263
|
});
|
|
@@ -317,6 +317,17 @@ export function extractProps(el, a2uiType) {
|
|
|
317
317
|
const slotAttr = attr('slot');
|
|
318
318
|
if (slotAttr) props.slot = slotAttr;
|
|
319
319
|
|
|
320
|
+
// Universal: preserve [span] for every element. Span is a layout-bearing
|
|
321
|
+
// attribute grid-ui's child reads via a pure CSS attribute selector
|
|
322
|
+
// (grid.css: `& > [span="3"] { grid-column: span 3; }`) — it belongs to
|
|
323
|
+
// "whatever this grid child happens to be," never to a specific
|
|
324
|
+
// component's own prop schema, so no .yaml declares it and the
|
|
325
|
+
// catalog-driven pass below silently drops it (TKT-0002: collapsed the
|
|
326
|
+
// admin-dashboard Overview/Recent Sales 3:2 split to two equal, unspanned
|
|
327
|
+
// columns).
|
|
328
|
+
const spanAttr = attr('span');
|
|
329
|
+
if (spanAttr) props.span = spanAttr;
|
|
330
|
+
|
|
320
331
|
// §163 (v0.5.4) — Catalog-driven generic extraction FIRST. Fills in
|
|
321
332
|
// every prop the v0.9 catalog declares for this type (label, icon,
|
|
322
333
|
// variant=, etc.). Legacy per-type blocks below run AFTER and can
|
|
@@ -351,6 +362,15 @@ export function extractProps(el, a2uiType) {
|
|
|
351
362
|
}
|
|
352
363
|
}
|
|
353
364
|
|
|
365
|
+
// ── Tag ── (TKT-0004: tag-ui renders its label via CSS attr(text) —
|
|
366
|
+
// tag.yaml documents textContent as routing to the text attribute. The
|
|
367
|
+
// authored form is light-DOM content (<tag-ui size="sm">label</tag-ui>),
|
|
368
|
+
// so fall back to textContent when no text= attribute is set.)
|
|
369
|
+
if (a2uiType === 'Tag' && props.text === undefined) {
|
|
370
|
+
const text = (el.textContent || '').trim().replace(/\s+/g, ' ');
|
|
371
|
+
if (text) props.text = text;
|
|
372
|
+
}
|
|
373
|
+
|
|
354
374
|
// ── Link ── (§47 — <a> tags map to Link, not Button; carries href, target, rel)
|
|
355
375
|
if (a2uiType === 'Link') {
|
|
356
376
|
const text = (el.textContent || '').trim().replace(/\s+/g, ' ');
|
package/transpiler/transpiler.js
CHANGED
|
@@ -201,9 +201,13 @@ function walkNode(el, context) {
|
|
|
201
201
|
return id;
|
|
202
202
|
}
|
|
203
203
|
|
|
204
|
-
// Leaf types: these render their own text, don't recurse into children
|
|
204
|
+
// Leaf types: these render their own text, don't recurse into children.
|
|
205
|
+
// Tag joined 2026-07-12 (TKT-0004): tag-ui renders its label via CSS
|
|
206
|
+
// attr(text) — as a container, its light-DOM label became a child Text
|
|
207
|
+
// at body size, inflating every converted chip site-wide (581 instances
|
|
208
|
+
// across 233 pages measured).
|
|
205
209
|
const LEAF_TYPES = new Set([
|
|
206
|
-
'Text', 'Button', 'Kbd', 'Code', 'Badge', 'Image', 'Divider',
|
|
210
|
+
'Text', 'Button', 'Kbd', 'Code', 'Badge', 'Tag', 'Image', 'Divider',
|
|
207
211
|
'TextField', 'CheckBox', 'Toggle', 'Radio', 'Slider', 'Search',
|
|
208
212
|
'Upload', 'ColorPicker', 'DateTimeInput', 'TextArea', 'OtpInput',
|
|
209
213
|
]);
|
|
@@ -244,7 +248,7 @@ function walkNode(el, context) {
|
|
|
244
248
|
if (directText) {
|
|
245
249
|
// Preserve the direct text on whichever prop the type uses
|
|
246
250
|
if (a2uiType === 'Text' || a2uiType === 'Kbd' || a2uiType === 'Code') containerProps.textContent = directText;
|
|
247
|
-
else if (a2uiType === 'Button' || a2uiType === 'Badge') {
|
|
251
|
+
else if (a2uiType === 'Button' || a2uiType === 'Badge' || a2uiType === 'Tag') {
|
|
248
252
|
if (containerProps.text === undefined) containerProps.text = directText;
|
|
249
253
|
}
|
|
250
254
|
} else {
|