@adia-ai/a2ui-retrieval 0.7.27 → 0.7.28

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,22 @@
1
1
  # Changelog — @adia-ai/a2ui-retrieval
2
+ ## [0.7.28] — 2026-07-14
3
+
4
+ ### Fixed
5
+
6
+ - **`anti-patterns.js`'s `noInventedComponents` derives its allowlist
7
+ live, not from a hand-frozen list.** The ~140-tag `Set` was a manual
8
+ snapshot ("regenerated 2026-06-10") with a documented prior staleness
9
+ incident (missing `field-ui`, a core primitive) — independent of the
10
+ live `registry` Map `validator.js` already imports for the same class
11
+ of check. Now built once at module load from `registry`
12
+ (`@adia-ai/a2ui-runtime`) + `component-catalog.js`'s per-component
13
+ sidecars, plus one named exception (`router-ui`, core-defined, no yaml
14
+ sidecar). Diffing the old list against the live union incidentally
15
+ surfaced a second staleness bug (the registry was itself missing
16
+ several shell-family tags the old list never had either) and dropped
17
+ 6 confirmed-stale entries. New regression suite,
18
+ `anti-patterns.test.js` (6 cases).
19
+
2
20
  ## [0.7.27] — 2026-07-12
3
21
 
4
22
  ### Lockstep
package/anti-patterns.js CHANGED
@@ -8,6 +8,38 @@
8
8
  * - fix: guidance on how to correct it
9
9
  */
10
10
 
11
+ import { registry } from '../runtime/registry.js';
12
+ import { getAllComponentData } from './component-catalog.js';
13
+
14
+ // `noInventedComponents`'s allowlist, below, used to be a hand-frozen Set —
15
+ // it drifted stale at least once in production (missing field-ui, a core
16
+ // primitive) before being "regenerated" as a one-time manual snapshot on
17
+ // 2026-06-10, which is itself already stale again. Built live instead, from
18
+ // the two sources every registered tag actually comes from:
19
+ // - `registry` (@adia-ai/a2ui-runtime) — the A2UI-emittable compose types
20
+ // (validator.js's checkAllTypesRegistered already imports this same Map).
21
+ // - `component-catalog.js`'s per-component `.a2ui.json` sidecars (the
22
+ // dual-mode Node/browser/static loader AGENTS.md names as the canonical
23
+ // pattern for this directory) — covers every component with a yaml SoT,
24
+ // including ones like agent-artifact-ui/aside-ui/preview-ui that exist
25
+ // but were never wired into the compose-emission registry.
26
+ // `CORE_INFRA_TAGS` covers the residual few real elements neither source
27
+ // carries: `router-ui` is defined directly in core/provider.js with no
28
+ // yaml/generated sidecar and is never an A2UI-emittable type.
29
+ const CORE_INFRA_TAGS = ['router-ui'];
30
+
31
+ function buildKnownTags() {
32
+ const tags = new Set(registry.values());
33
+ for (const data of Object.values(getAllComponentData())) {
34
+ const tag = data?.['x-adiaui']?.tag;
35
+ if (tag) tags.add(tag);
36
+ }
37
+ for (const tag of CORE_INFRA_TAGS) tags.add(tag);
38
+ return tags;
39
+ }
40
+
41
+ const KNOWN_TAGS = buildKnownTags();
42
+
11
43
  const antiPatterns = [
12
44
  {
13
45
  name: 'noBareDivs',
@@ -66,41 +98,9 @@ const antiPatterns = [
66
98
  description: 'Only use components from the AdiaUI registry. Do not invent custom component tags.',
67
99
  check: (html) => {
68
100
  const tags = html.match(/<([a-z]+-(?:n|ui))\b/gi) || [];
69
- const known = new Set([
70
- // Regenerated 2026-06-10 from the per-component yaml `tag:` SoT
71
- // (node: scan packages/web-components/components/*/*.yaml) + the
72
- // runtime/infra extras below. The previous hand-rolled list was
73
- // stale — it was MISSING field-ui (a core primitive), so every
74
- // canonical labeled form flagged noInventedComponents.
75
- 'accordion-item-ui', 'accordion-ui', 'action-item-ui', 'action-list-ui', 'adia-root', 'agent-artifact-ui',
76
- 'agent-feedback-bar-ui', 'agent-questions-ui', 'agent-reasoning-ui', 'agent-suggestions-ui', 'agent-trace-ui', 'alert-ui',
77
- 'aside-ui', 'avatar-group-ui', 'avatar-ui', 'badge-ui', 'block-ui', 'blockquote-ui',
78
- 'breadcrumb-ui', 'button-ui', 'calendar-grid-ui', 'calendar-picker-ui', 'canvas-ui', 'card-ui',
79
- 'chart-legend-ui', 'chart-ui', 'chat-input-ui', 'chat-thread-ui', 'check-ui', 'code-ui',
80
- 'col-ui', 'color-input-ui', 'color-picker-ui', 'combobox-ui', 'command-ui', 'context-menu-ui',
81
- 'date-range-picker-ui', 'datetime-picker-ui', 'datetime-ui', 'demo-toggle-ui', 'description-list-ui', 'divider-ui',
82
- 'drawer-ui', 'embed-ui', 'empty-state-ui', 'feed-item-ui', 'feed-ui', 'field-ui',
83
- 'fields-ui', 'footer-ui', 'form-container-ui', 'frame-ui', 'grid-ui', 'header-ui',
84
- 'heatmap-ui', 'icon-provider', 'icon-ui', 'image-ui', 'inline-edit-ui', 'inline-message-ui',
85
- 'input-ui', 'inspector-ui', 'integration-card-ui', 'kbd-ui', 'link-ui', 'list-item-ui',
86
- 'list-ui', 'list-window-ui', 'listbox-ui', 'loading-overlay-ui', 'mark-ui', 'menu-divider-ui',
87
- 'menu-item-ui', 'menu-label-ui', 'menu-ui', 'modal-ui', 'nav-group-ui', 'nav-item-ui',
88
- 'nav-ui', 'noodles-ui', 'number-format-ui', 'option-card-ui', 'otp-input-ui', 'page-ui',
89
- 'pagination-ui', 'pane-ui', 'password-strength-ui', 'pipeline-status-ui', 'popover-ui', 'preview-ui',
90
- 'progress-row-ui', 'progress-ui', 'qr-code-ui', 'radio-ui', 'range-ui', 'rating-ui',
91
- 'relative-time-ui', 'richtext-ui', 'router-ui', 'row-ui', 'search-ui', 'section-ui',
92
- 'segment-ui', 'segmented-ui', 'select-ui', 'skeleton-ui', 'skip-nav-ui', 'slider-ui',
93
- 'spinner-ui', 'stack-ui', 'stat-ui', 'step-progress-ui', 'stepper-item-ui', 'stepper-ui',
94
- 'stream-ui', 'swatch-ui', 'swiper-ui', 'switch-ui', 'tab-ui', 'table-toolbar-ui',
95
- 'table-ui', 'tabs-ui', 'tag-ui', 'tags-input-ui', 'text-ui', 'textarea-ui',
96
- 'theme-provider', 'theme-ui', 'time-picker-ui', 'timeline-item-ui', 'timeline-ui', 'toast-ui',
97
- 'toc-ui', 'toggle-group-ui', 'toggle-option-ui', 'toggle-scheme-ui', 'toolbar-group-ui', 'toolbar-ui',
98
- 'tooltip-ui', 'tour-step-ui', 'tour-ui', 'tree-item-ui', 'tree-ui', 'upload-ui',
99
- 'visually-hidden-ui',
100
- ]);
101
101
  for (const match of tags) {
102
102
  const tag = match.slice(1).toLowerCase();
103
- if (!known.has(tag)) return true;
103
+ if (!KNOWN_TAGS.has(tag)) return true;
104
104
  }
105
105
  return false;
106
106
  },
@@ -0,0 +1,59 @@
1
+ /**
2
+ * anti-patterns.js — regression coverage for the noInventedComponents
3
+ * catalog-fragmentation fix.
4
+ *
5
+ * Prior bug: `known` was a hand-frozen Set (~140 tags, "regenerated"
6
+ * 2026-06-10) independent of the live `registry` Map validator.js already
7
+ * imports for the same purpose — it drifted stale at least once before
8
+ * (documented: missing field-ui, a core primitive). Fixed to build the
9
+ * allowlist live from `registry` + `component-catalog.js`'s per-component
10
+ * sidecars + a tiny, named core-infra exception list (`router-ui`).
11
+ */
12
+ import { describe, it, expect } from 'vitest';
13
+ import { checkAntiPattern } from './anti-patterns.js';
14
+ import { registry } from '../runtime/registry.js';
15
+
16
+ const check = (tag) => checkAntiPattern('noInventedComponents', `<${tag}></${tag}>`).violated;
17
+
18
+ describe('anti-patterns — noInventedComponents (live catalog derivation)', () => {
19
+ it('accepts every tag the live registry maps to (validator.js checkAllTypesRegistered\'s own source)', () => {
20
+ const flagged = [...new Set(registry.values())].filter((tag) => check(tag));
21
+ expect(flagged).toEqual([]);
22
+ });
23
+
24
+ it('accepts a component that exists but was previously missing from the compose-emission registry (agent-artifact-ui)', () => {
25
+ expect(check('agent-artifact-ui')).toBe(false);
26
+ });
27
+
28
+ it('accepts router-ui — core infra defined in provider.js, no yaml sidecar, no registry entry', () => {
29
+ expect(check('router-ui')).toBe(false);
30
+ });
31
+
32
+ it('accepts chat-thread-ui — a real sidecar-carried tag masked in the aggregated catalog by a ChatThread name collision with web-modules/chat/chat-thread (tag "chat-thread")', () => {
33
+ expect(check('chat-thread-ui')).toBe(false);
34
+ });
35
+
36
+ it('still flags a genuinely invented single-hyphen tag', () => {
37
+ expect(check('madeup-ui')).toBe(true);
38
+ });
39
+
40
+ it('drops confirmed-stale entries the old hand list carried for tags that no longer exist anywhere in the tree', () => {
41
+ // datetime-ui / listbox-ui / theme-ui: zero hits for a real component
42
+ // dir, yaml `tag:`, or customElements.define anywhere in the repo at
43
+ // the time of the fix — genuinely stale, now correctly flaggable.
44
+ //
45
+ // adia-root / icon-provider / form-container-ui were ALSO in the old
46
+ // hand list but are excluded from this assertion on purpose: the tag-
47
+ // extraction regex just above (`/<([a-z]+-(?:n|ui))\b/gi`) only
48
+ // captures single-hyphen tags ending in "-n" or "-ui" — it never
49
+ // extracted "adia-root"/"icon-provider" (wrong suffix) or
50
+ // "form-container-ui" (two hyphens) in the first place, under the old
51
+ // list OR this one. Their allowlist membership was always inert; a
52
+ // pre-existing, separate regex-coverage gap, not something this fix
53
+ // changes either way (see the "genuinely invented single-hyphen tag"
54
+ // case above for what the regex CAN catch).
55
+ for (const stale of ['datetime-ui', 'listbox-ui', 'theme-ui']) {
56
+ expect(check(stale)).toBe(true);
57
+ }
58
+ });
59
+ });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@adia-ai/a2ui-retrieval",
3
- "version": "0.7.27",
3
+ "version": "0.7.28",
4
4
  "description": "AdiaUI A2UI retrieval layer \u2014 catalog lookup, intent classification, domain routing, pattern + anti-pattern matching, clarity + context assembly. Consumed by the compose engine and any A2UI-protocol tooling that needs to reason about user intent against the catalog.",
5
5
  "type": "module",
6
6
  "main": "./index.js",