@adia-ai/adia-ui-forge 0.8.4 → 0.8.6
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/.claude-plugin/plugin.json +1 -1
- package/CHANGELOG.md +27 -2
- package/README.md +13 -4
- package/agents/a2ui-builder.corpus.json +35 -0
- package/agents/a2ui-builder.md +37 -0
- package/agents/component-author.corpus.json +40 -0
- package/agents/component-author.md +10 -1
- package/agents/framework-reviewer.corpus.json +35 -0
- package/agents/framework-reviewer.md +42 -0
- package/agents/release-builder.corpus.json +39 -0
- package/agents/release-builder.md +39 -0
- package/agents/routing-corpus.json +38 -38
- package/bin/release-pretag-docs-gate +226 -0
- package/commands/release.md +5 -3
- package/hooks/hooks.json +10 -0
- package/package.json +1 -1
- package/skills/adia-a2ui/SKILL.md +37 -8
- package/skills/adia-a2ui/evals/routing-corpus.json +36 -29
- package/skills/adia-a2ui/references/pipeline-overview.md +1 -1
- package/skills/adia-a2ui/references/zettel-calibration.md +5 -5
- package/skills/adia-author/SKILL.md +16 -8
- package/skills/adia-author/evals/routing-corpus.json +39 -218
- package/skills/adia-author/references/anti-patterns.md +7 -7
- package/skills/adia-author/references/api-contract.md +9 -9
- package/skills/adia-author/references/authoring-cycle.md +25 -6
- package/skills/adia-author/references/code-style.md +4 -5
- package/skills/adia-author/references/lifecycle-patterns.md +8 -8
- package/skills/adia-author/references/llm-bridge.md +7 -0
- package/skills/adia-author/references/token-contract.md +5 -5
- package/skills/adia-author/references/worked-example.md +34 -18
- package/skills/adia-author/references/yaml-contract.md +1 -1
- package/skills/adia-deploy/SKILL.md +71 -12
- package/skills/adia-deploy/evals/routing-corpus.json +37 -0
- package/skills/adia-deploy/references/deploy-playbooks.md +1 -1
- package/skills/adia-dogfood/SKILL.md +71 -11
- package/skills/adia-dogfood/evals/routing-corpus.json +34 -0
- package/skills/adia-dogfood/references/admin-shell-anatomy.md +1 -1
- package/skills/adia-gen-review/SKILL.md +73 -7
- package/skills/adia-gen-review/evals/routing-corpus.json +34 -0
- package/skills/adia-gen-review/scripts/gen-review-decompose.mjs +5 -0
- package/skills/adia-llm-internals/SKILL.md +10 -6
- package/skills/adia-llm-internals/evals/routing-corpus.json +37 -0
- package/skills/adia-llm-internals/references/bridge-facade.md +2 -2
- package/skills/adia-llm-internals/references/streaming-sse.md +1 -1
- package/skills/adia-release/SKILL.md +43 -13
- package/skills/adia-release/evals/evals.json +24 -0
- package/skills/adia-release/evals/routing-corpus.json +35 -0
- package/skills/adia-release/references/changelog-discipline.md +15 -9
- package/skills/adia-release/references/cut-procedure.md +78 -24
- package/skills/adia-release/references/gates-catalog.md +3 -3
- package/skills/adia-release/references/independent-package-release.md +1 -1
- package/skills/adia-release/references/recovery-paths.md +4 -2
- package/skills/adia-release/scripts/bump.mjs +32 -1
- package/skills/adia-release/scripts/dispatch-publish.mjs +49 -11
- package/skills/adia-release/scripts/gate-roster.mjs +71 -0
- package/skills/adia-release/scripts/insert-stub.mjs +36 -2
- package/skills/adia-release/scripts/promote-unreleased.mjs +35 -1
- package/skills/adia-release/scripts/release-pack.mjs +315 -56
- package/skills/adia-release/scripts/tag-lockstep.mjs +29 -7
- package/skills/adia-site-docs/SKILL.md +6 -1
- package/skills/adia-site-docs/evals/routing-corpus.json +35 -173
- package/skills/adia-ssr/SKILL.md +128 -0
- package/skills/adia-ssr/evals/audit-report.md +63 -0
- package/skills/adia-ssr/evals/routing-corpus.json +34 -0
- package/skills/adia-ssr/references/consumer-workarounds.md +81 -0
- package/skills/adia-ssr/references/failure-shapes.md +164 -0
- package/skills/adia-ssr/references/guard-patterns.md +183 -0
- package/skills/adia-ssr/references/status-ledger.md +33 -0
- package/skills/adia-ssr/references/test-without-linkedom.md +129 -0
- package/agents/a2ui-engineer.md +0 -26
- package/agents/framework-verifier.md +0 -26
- package/agents/release-engineer.md +0 -26
|
@@ -1,222 +1,43 @@
|
|
|
1
1
|
{
|
|
2
|
-
"
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
"
|
|
12
|
-
"
|
|
13
|
-
"
|
|
14
|
-
"
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
"should_route_to_author": true,
|
|
22
|
-
"expected_shape": "new-primitive",
|
|
23
|
-
"rationale": "Canonical new-primitive task shape."
|
|
24
|
-
},
|
|
25
|
-
{
|
|
26
|
-
"id": "author-new-primitive-02",
|
|
27
|
-
"phrase": "build a new <toggle-ui> component from scratch",
|
|
28
|
-
"should_route_to_author": true,
|
|
29
|
-
"expected_shape": "new-primitive",
|
|
30
|
-
"rationale": "'build a <foo-ui>' phrasing."
|
|
31
|
-
},
|
|
32
|
-
{
|
|
33
|
-
"id": "author-new-primitive-03",
|
|
34
|
-
"phrase": "create a new primitive web component in packages/web-components",
|
|
35
|
-
"should_route_to_author": true,
|
|
36
|
-
"expected_shape": "new-primitive",
|
|
37
|
-
"rationale": "Explicit packages/web-components path mention."
|
|
38
|
-
},
|
|
39
|
-
|
|
40
|
-
{
|
|
41
|
-
"id": "author-modify-01",
|
|
42
|
-
"phrase": "add a new prop to table-ui",
|
|
43
|
-
"should_route_to_author": true,
|
|
44
|
-
"expected_shape": "modify-primitive",
|
|
45
|
-
"rationale": "Modify existing primitive — add a prop."
|
|
46
|
-
},
|
|
47
|
-
{
|
|
48
|
-
"id": "author-modify-02",
|
|
49
|
-
"phrase": "fix the CSS in card-ui to handle the new bleed variant",
|
|
50
|
-
"should_route_to_author": true,
|
|
51
|
-
"expected_shape": "modify-primitive",
|
|
52
|
-
"rationale": "Modify existing primitive CSS."
|
|
53
|
-
},
|
|
54
|
-
{
|
|
55
|
-
"id": "author-modify-03",
|
|
56
|
-
"phrase": "update the input-ui yaml to add a placeholder attribute",
|
|
57
|
-
"should_route_to_author": true,
|
|
58
|
-
"expected_shape": "modify-primitive",
|
|
59
|
-
"rationale": "Update the yaml SoT for an existing primitive."
|
|
60
|
-
},
|
|
61
|
-
|
|
62
|
-
{
|
|
63
|
-
"id": "author-shell-01",
|
|
64
|
-
"phrase": "build the chat-shell composition with the new sidebar slot",
|
|
65
|
-
"should_route_to_author": true,
|
|
66
|
-
"expected_shape": "shell",
|
|
67
|
-
"rationale": "Shell authoring."
|
|
68
|
-
},
|
|
69
|
-
{
|
|
70
|
-
"id": "author-shell-02",
|
|
71
|
-
"phrase": "author a new web-module shell at packages/web-modules/editor/editor-shell",
|
|
72
|
-
"should_route_to_author": true,
|
|
73
|
-
"expected_shape": "shell",
|
|
74
|
-
"rationale": "Explicit web-modules + shell."
|
|
75
|
-
},
|
|
76
|
-
{
|
|
77
|
-
"id": "author-shell-03",
|
|
78
|
-
"phrase": "add a pane behaviour to admin-shell per the bespoke shell-tier convention",
|
|
79
|
-
"should_route_to_author": true,
|
|
80
|
-
"expected_shape": "shell",
|
|
81
|
-
"rationale": "Bespoke shell-tier (ADR-0023 shape) work."
|
|
82
|
-
},
|
|
83
|
-
|
|
84
|
-
{
|
|
85
|
-
"id": "author-promote-01",
|
|
86
|
-
"phrase": "promote this inline content to a shared web-modules module",
|
|
87
|
-
"should_route_to_author": true,
|
|
88
|
-
"expected_shape": "module-promotion",
|
|
89
|
-
"rationale": "Promote inline → module."
|
|
90
|
-
},
|
|
91
|
-
{
|
|
92
|
-
"id": "author-promote-02",
|
|
93
|
-
"phrase": "this content keeps repeating across apps, extract to a shared module",
|
|
94
|
-
"should_route_to_author": true,
|
|
95
|
-
"expected_shape": "module-promotion",
|
|
96
|
-
"rationale": "Repetition trigger."
|
|
97
|
-
},
|
|
98
|
-
{
|
|
99
|
-
"id": "author-promote-03",
|
|
100
|
-
"phrase": "lift this billing-summary block from apps/saas to web-modules",
|
|
101
|
-
"should_route_to_author": true,
|
|
102
|
-
"expected_shape": "module-promotion",
|
|
103
|
-
"rationale": "Lift inline page content to a reusable module."
|
|
104
|
-
},
|
|
105
|
-
|
|
106
|
-
{
|
|
107
|
-
"id": "author-audit-01",
|
|
108
|
-
"phrase": "audit the four-axis contract for table-ui",
|
|
109
|
-
"should_route_to_author": true,
|
|
110
|
-
"expected_shape": "drift-audit",
|
|
111
|
-
"rationale": "Contract drift audit."
|
|
112
|
-
},
|
|
113
|
-
{
|
|
114
|
-
"id": "author-audit-02",
|
|
115
|
-
"phrase": "check the token usage in card-ui for drift",
|
|
116
|
-
"should_route_to_author": true,
|
|
117
|
-
"expected_shape": "drift-audit",
|
|
118
|
-
"rationale": "Token audit procedure."
|
|
119
|
-
},
|
|
120
|
-
{
|
|
121
|
-
"id": "author-audit-03",
|
|
122
|
-
"phrase": "lifecycle audit on dropdown-ui — symmetric connected/disconnected?",
|
|
123
|
-
"should_route_to_author": true,
|
|
124
|
-
"expected_shape": "drift-audit",
|
|
125
|
-
"rationale": "Lifecycle audit."
|
|
126
|
-
},
|
|
127
|
-
|
|
128
|
-
{
|
|
129
|
-
"id": "author-llm-01",
|
|
130
|
-
"phrase": "extend the LLM bridge to add a new provider",
|
|
131
|
-
"should_route_to_author": true,
|
|
132
|
-
"expected_shape": "llm-bridge",
|
|
133
|
-
"rationale": "Extend @adia-ai/llm."
|
|
134
|
-
},
|
|
135
|
-
{
|
|
136
|
-
"id": "author-llm-02",
|
|
137
|
-
"phrase": "modify createAdapter in @adia-ai/llm to add chunk-shape support",
|
|
138
|
-
"should_route_to_author": true,
|
|
139
|
-
"expected_shape": "llm-bridge",
|
|
140
|
-
"rationale": "Explicit createAdapter + @adia-ai/llm mention."
|
|
141
|
-
},
|
|
142
|
-
{
|
|
143
|
-
"id": "author-llm-03",
|
|
144
|
-
"phrase": "set up the LLM-bridge surface for a new tool-call provider",
|
|
145
|
-
"should_route_to_author": true,
|
|
146
|
-
"expected_shape": "llm-bridge",
|
|
147
|
-
"rationale": "LLM-bridge trigger phrase."
|
|
148
|
-
},
|
|
149
|
-
|
|
150
|
-
{
|
|
151
|
-
"id": "author-demo-01",
|
|
152
|
-
"phrase": "author a demo for the billing-overview composite",
|
|
153
|
-
"should_route_to_author": true,
|
|
154
|
-
"expected_shape": "composite-demo",
|
|
155
|
-
"rationale": "Composite-demo authoring."
|
|
156
|
-
},
|
|
157
|
-
{
|
|
158
|
-
"id": "author-demo-02",
|
|
159
|
-
"phrase": "compose the examples.html for dashboard-layout",
|
|
160
|
-
"should_route_to_author": true,
|
|
161
|
-
"expected_shape": "composite-demo",
|
|
162
|
-
"rationale": "'compose examples.html for Y' trigger."
|
|
163
|
-
},
|
|
164
|
-
{
|
|
165
|
-
"id": "author-demo-03",
|
|
166
|
-
"phrase": "write the demo for <integrations-page-ui> in packages/web-modules/settings",
|
|
167
|
-
"should_route_to_author": true,
|
|
168
|
-
"expected_shape": "composite-demo",
|
|
169
|
-
"rationale": "'write the demo for <module-ui>' + web-modules path."
|
|
170
|
-
},
|
|
171
|
-
|
|
172
|
-
{
|
|
173
|
-
"id": "author-adv-01",
|
|
174
|
-
"phrase": "compose this Figma mock into AdiaUI components for our consumer app",
|
|
175
|
-
"should_route_to_author": false,
|
|
176
|
-
"expected_alternative": "adia-compose (adia-factory plugin)",
|
|
177
|
-
"rationale": "Adversarial — consumer-side composition (screens FROM existing primitives). The description NEG-fences it."
|
|
178
|
-
},
|
|
179
|
-
{
|
|
180
|
-
"id": "author-adv-02",
|
|
181
|
-
"phrase": "cut a release of the next version and publish the npm packages",
|
|
182
|
-
"should_route_to_author": false,
|
|
183
|
-
"expected_alternative": "adia-release",
|
|
184
|
-
"rationale": "Adversarial — release territory."
|
|
185
|
-
},
|
|
186
|
-
{
|
|
187
|
-
"id": "author-adv-03",
|
|
188
|
-
"phrase": "tune the zettel composition coverage; eval is at 38%",
|
|
189
|
-
"should_route_to_author": false,
|
|
190
|
-
"expected_alternative": "adia-a2ui",
|
|
191
|
-
"rationale": "Adversarial — a2ui pipeline internals (compose strategies, eval coverage)."
|
|
192
|
-
},
|
|
193
|
-
{
|
|
194
|
-
"id": "author-adv-04",
|
|
195
|
-
"phrase": "build a user profile card with avatar and edit actions",
|
|
196
|
-
"should_route_to_author": false,
|
|
197
|
-
"expected_alternative": "adia-compose (adia-factory plugin)",
|
|
198
|
-
"rationale": "Adversarial — canonical consumer-composition task (build UI from intent)."
|
|
199
|
-
},
|
|
200
|
-
{
|
|
201
|
-
"id": "author-adv-05",
|
|
202
|
-
"phrase": "deploy the api service to the hosting platform",
|
|
203
|
-
"should_route_to_author": false,
|
|
204
|
-
"expected_alternative": "adia-deploy",
|
|
205
|
-
"rationale": "Adversarial — deployment/ops territory."
|
|
206
|
-
},
|
|
207
|
-
{
|
|
208
|
-
"id": "author-adv-06",
|
|
209
|
-
"phrase": "explain how React hooks work",
|
|
210
|
-
"should_route_to_author": false,
|
|
211
|
-
"expected_alternative": null,
|
|
212
|
-
"rationale": "Adversarial — generic framework knowledge; no AdiaUI skill should activate."
|
|
213
|
-
}
|
|
2
|
+
"positives": [
|
|
3
|
+
"add a new button-ui primitive component",
|
|
4
|
+
"build a new <toggle-ui> component from scratch",
|
|
5
|
+
"create a new primitive web component in packages/web-components",
|
|
6
|
+
"add a new prop to table-ui",
|
|
7
|
+
"fix the CSS in card-ui to handle the new bleed variant",
|
|
8
|
+
"update the input-ui yaml to add a placeholder attribute",
|
|
9
|
+
"build the chat-shell composition with the new sidebar slot",
|
|
10
|
+
"author a new web-module shell at packages/web-modules/editor/editor-shell",
|
|
11
|
+
"add a pane behaviour to admin-shell per the bespoke shell-tier convention",
|
|
12
|
+
"promote this inline content to a shared web-modules module",
|
|
13
|
+
"this content keeps repeating across apps, extract to a shared module",
|
|
14
|
+
"lift this billing-summary block from apps/saas to web-modules",
|
|
15
|
+
"audit the four-axis contract for table-ui",
|
|
16
|
+
"check the token usage in card-ui for drift",
|
|
17
|
+
"lifecycle audit on dropdown-ui \u2014 symmetric connected/disconnected?",
|
|
18
|
+
"author a demo for the billing-overview composite",
|
|
19
|
+
"compose the examples.html for dashboard-layout",
|
|
20
|
+
"write the demo for <integrations-page-ui> in packages/web-modules/settings"
|
|
214
21
|
],
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
"
|
|
218
|
-
"
|
|
219
|
-
"
|
|
220
|
-
"
|
|
22
|
+
"negatives": [
|
|
23
|
+
"compose this Figma mock into AdiaUI components for our consumer app",
|
|
24
|
+
"cut a release of the next version and publish the npm packages",
|
|
25
|
+
"tune the zettel composition coverage; eval is at 38%",
|
|
26
|
+
"build a user profile card with avatar and edit actions",
|
|
27
|
+
"deploy the api service to the hosting platform",
|
|
28
|
+
"explain how React hooks work",
|
|
29
|
+
"the gemini adapter is dropping usage tokens on streamed responses",
|
|
30
|
+
"fix the openai stopReason mapping in the llm client",
|
|
31
|
+
"extend the LLM bridge to add a new provider",
|
|
32
|
+
"modify createAdapter in @adia-ai/llm to add chunk-shape support",
|
|
33
|
+
"set up the LLM-bridge surface for a new tool-call provider"
|
|
34
|
+
],
|
|
35
|
+
"_measured": {
|
|
36
|
+
"as_of": "2026-07-18",
|
|
37
|
+
"scorer": "routing_eval.py (nonoun-plugins/forge)",
|
|
38
|
+
"f1": 0.971,
|
|
39
|
+
"precision": 1.0,
|
|
40
|
+
"recall": 0.944,
|
|
41
|
+
"exit_code": 0
|
|
221
42
|
}
|
|
222
43
|
}
|
|
@@ -376,7 +376,7 @@ disconnected() {
|
|
|
376
376
|
|
|
377
377
|
```javascript
|
|
378
378
|
// WRONG — chart.js (pre-fix)
|
|
379
|
-
class
|
|
379
|
+
class UIChart extends UIElement {
|
|
380
380
|
connected() { /* ... */ this.#ro = new ResizeObserver(...); }
|
|
381
381
|
|
|
382
382
|
disconnected() {
|
|
@@ -408,8 +408,8 @@ disconnected() {
|
|
|
408
408
|
### AP-L3 · Missing `super.connected()` / `super.disconnected()`
|
|
409
409
|
|
|
410
410
|
```javascript
|
|
411
|
-
// WRONG —
|
|
412
|
-
class
|
|
411
|
+
// WRONG — UIFormElement subclass missing super call
|
|
412
|
+
class UIInput extends UIFormElement {
|
|
413
413
|
connected() {
|
|
414
414
|
// super.connected() NOT called
|
|
415
415
|
this.#inputEl = this.querySelector('input');
|
|
@@ -479,7 +479,7 @@ updateConfig(opts) {
|
|
|
479
479
|
|
|
480
480
|
```javascript
|
|
481
481
|
// WRONG — drawer.js (pre-fix)
|
|
482
|
-
class
|
|
482
|
+
class UIDrawer extends UIElement {
|
|
483
483
|
static template = () => html``; // ← looks harmless. It isn't.
|
|
484
484
|
|
|
485
485
|
connected() {
|
|
@@ -489,7 +489,7 @@ class AdiaDrawer extends AdiaElement {
|
|
|
489
489
|
}
|
|
490
490
|
```
|
|
491
491
|
|
|
492
|
-
**What went wrong:** `
|
|
492
|
+
**What went wrong:** `UIElement`'s base `connectedCallback` runs an effect that calls `stamp(template(this), this)`. `stamp` calls `mount`, which calls `container.replaceChildren(fragment)`. Even an "empty" `html\`\``produces a non-null result, so`replaceChildren`runs and clears every authored child (header/section/footer) out of the host element. The component's own`render()` then tries to migrate children that no longer exist.
|
|
493
493
|
|
|
494
494
|
Symptom: drawers render with a close button in an empty panel; all authored content is gone. Hard to debug because the children WERE in the DOM at `connected()` time — they get wiped milliseconds later when the effect runs.
|
|
495
495
|
|
|
@@ -497,8 +497,8 @@ Symptom: drawers render with a close button in an empty panel; all authored cont
|
|
|
497
497
|
|
|
498
498
|
```javascript
|
|
499
499
|
// RIGHT — no template override
|
|
500
|
-
class
|
|
501
|
-
// base
|
|
500
|
+
class UIDrawer extends UIElement {
|
|
501
|
+
// base UIElement.template returns null → stamp() is skipped →
|
|
502
502
|
// authored light-DOM children survive through render().
|
|
503
503
|
|
|
504
504
|
connected() { /* ... */ }
|
|
@@ -4,7 +4,7 @@ Deep dive on declaring component APIs in AdiaUI. Read this when adding a new pro
|
|
|
4
4
|
|
|
5
5
|
## The `static properties` block
|
|
6
6
|
|
|
7
|
-
Every `
|
|
7
|
+
Every `UIElement` subclass declares its public API as a `static properties` object. Keys are camelCase JS names; values describe type, default, reflection, and attribute mapping.
|
|
8
8
|
|
|
9
9
|
```javascript
|
|
10
10
|
static properties = {
|
|
@@ -141,21 +141,21 @@ Reserve `error` for validation state (`[error]` on form inputs matches ARIA patt
|
|
|
141
141
|
The component has three names that must agree:
|
|
142
142
|
|
|
143
143
|
- **File path:** `packages/web-components/components/foo/foo.js`
|
|
144
|
-
- **Class name:** `class
|
|
145
|
-
- **Custom element tag:** `customElements.define('foo-ui',
|
|
144
|
+
- **Class name:** `class UIFoo extends UIElement`
|
|
145
|
+
- **Custom element tag:** `customElements.define('foo-ui', UIFoo)`
|
|
146
146
|
|
|
147
147
|
A fourth consistency requirement: the CSS file at `packages/web-components/components/foo/foo.css` uses `@scope (foo-ui)`.
|
|
148
148
|
|
|
149
|
-
## Extending `
|
|
149
|
+
## Extending `UIFormElement`
|
|
150
150
|
|
|
151
|
-
Form-participating components extend `
|
|
151
|
+
Form-participating components extend `UIFormElement` (which extends `UIElement`) and get `ElementInternals` wiring, form-reset handling, and `.form` / `.labels` / `.validity` accessors for free.
|
|
152
152
|
|
|
153
153
|
```javascript
|
|
154
|
-
import {
|
|
154
|
+
import { UIFormElement } from '../../core/form.js';
|
|
155
155
|
|
|
156
|
-
class
|
|
156
|
+
class UIInput extends UIFormElement {
|
|
157
157
|
static properties = {
|
|
158
|
-
...
|
|
158
|
+
...UIFormElement.properties, // inherit name, value, disabled, required, etc.
|
|
159
159
|
placeholder: { type: String, default: '', reflect: true },
|
|
160
160
|
};
|
|
161
161
|
|
|
@@ -180,7 +180,7 @@ Key details:
|
|
|
180
180
|
|
|
181
181
|
- **Always `super.connected()` and `super.disconnected()`** — without them, form-association doesn't register.
|
|
182
182
|
- **`this.syncValue(str)`** — call this whenever the value changes to update the form-submitted string. Accepts a string.
|
|
183
|
-
- **Inheriting properties** — spread `
|
|
183
|
+
- **Inheriting properties** — spread `UIFormElement.properties` into your own `static properties` so you don't re-declare `name`, `disabled`, `required`.
|
|
184
184
|
|
|
185
185
|
## Event conventions
|
|
186
186
|
|
|
@@ -9,8 +9,8 @@ The 5-step procedure run AFTER [primitive-audit.md](primitive-audit.md) clears (
|
|
|
9
9
|
Before writing or editing, load these four files. They are the ground truth:
|
|
10
10
|
|
|
11
11
|
- `.claude/docs/specs/component-token-contract.md` — the authoritative invariants. Skim the whole thing if you haven't read it this session; focus on "Variants vs Modes" and "Sanctioned Mode Attributes" if you're adding a new layout-affecting attribute.
|
|
12
|
-
- `packages/web-components/core/element.js` — `
|
|
13
|
-
- `packages/web-components/core/form.js` — `
|
|
12
|
+
- `packages/web-components/core/element.js` — `UIElement` base class. The `static properties` schema, `connected()`/`disconnected()`/`render()` lifecycle, and attribute-mapping conventions are all defined here.
|
|
13
|
+
- `packages/web-components/core/form.js` — `UIFormElement`. Only needed if the new component participates in forms (inputs, selects, checkboxes, etc.).
|
|
14
14
|
- At least one good-citizen reference that matches the shape of what you're building. Pick from: `button-ui`, `card-ui`, `input-ui`, `textarea-ui`, `check-ui`. Read both the `.js` and the `.css`.
|
|
15
15
|
|
|
16
16
|
## Step 2 — Classify the work before you write
|
|
@@ -41,7 +41,7 @@ These rules are the distilled lessons from a 5-iteration audit. Each one corresp
|
|
|
41
41
|
|
|
42
42
|
5. **Reserved-name anti-patterns.** Avoid: `title` (collides with HTML tooltip attribute), `active` on parent components (use `value` for a selection or `step` for an index — per-item `active` on children is fine), `error` in variant names (use `danger`; reserve `error` for validation state), `disabled` on non-form-participating components (use `readonly`), `multiple` with exclusion semantics (use a negated positive like `single`).
|
|
43
43
|
|
|
44
|
-
6. **Element tag ends in `-ui`; JS class is `
|
|
44
|
+
6. **Element tag ends in `-ui`; JS class is `UI<Component>`.** `<foo-ui>` ↔ `class UIFoo extends UIElement`. Three-way consistency: filename, class name, custom-element tag. The sanctioned `-n` carve-out is `cot-ui` (the chain-of-thought streaming component); `nav-ui` was deprecated in favor of the `-ui` replacements. New `-n` tags require a contract-doc update — see `.claude/docs/specs/component-token-contract.md`.
|
|
45
45
|
|
|
46
46
|
### CSS
|
|
47
47
|
|
|
@@ -86,7 +86,7 @@ These rules are the distilled lessons from a 5-iteration audit. Each one corresp
|
|
|
86
86
|
|
|
87
87
|
1. **Every `addEventListener` in `connected()` has a matching `removeEventListener` in `disconnected()`.** Handler must be a stable `#field` arrow (`#onClick = (e) => { ... }`), never an inline arrow passed to `addEventListener`. Inline arrows can't be removed — `removeEventListener` needs reference equality.
|
|
88
88
|
|
|
89
|
-
2. **`
|
|
89
|
+
2. **`UIFormElement` subclasses call `super.connected()` and `super.disconnected()`.** `ElementInternals` registration depends on it. Omitting `super` strands the form-association.
|
|
90
90
|
|
|
91
91
|
3. **Timers and observers are torn down.** `clearInterval`, `clearTimeout`, `ResizeObserver.disconnect()`, `MutationObserver.disconnect()`, `IntersectionObserver.disconnect()` all in `disconnected()`.
|
|
92
92
|
|
|
@@ -164,7 +164,7 @@ Before declaring the work done, run through this checklist. If anything fails, f
|
|
|
164
164
|
- [ ] Every `static properties` entry uses `attribute:` (not `attr:`).
|
|
165
165
|
- [ ] Every state-bearing Boolean has `reflect: true`.
|
|
166
166
|
- [ ] No reserved-name anti-patterns (`title`, parent-level `active`, `error` variant, `disabled` on non-form, exclusion-`multiple`).
|
|
167
|
-
- [ ] Element tag ends in `-ui`; class is `
|
|
167
|
+
- [ ] Element tag ends in `-ui`; class is `UI<Component>`.
|
|
168
168
|
|
|
169
169
|
### CSS
|
|
170
170
|
|
|
@@ -179,11 +179,29 @@ Before declaring the work done, run through this checklist. If anything fails, f
|
|
|
179
179
|
|
|
180
180
|
- [ ] Every `addEventListener` in `connected()` has a paired `removeEventListener` in `disconnected()`.
|
|
181
181
|
- [ ] All handlers passed to `addEventListener` are stable `#field` arrows (or bound method refs), not inline arrows.
|
|
182
|
-
- [ ] If the class extends `
|
|
182
|
+
- [ ] If the class extends `UIFormElement`, both `connected()` and `disconnected()` call `super`.
|
|
183
183
|
- [ ] Every timer/observer created in `connected()` is disposed in `disconnected()`.
|
|
184
184
|
- [ ] Cached DOM refs (`this.#fooEl`) are nulled in `disconnected()`.
|
|
185
185
|
- [ ] Class declares `disconnected()` exactly once.
|
|
186
186
|
|
|
187
|
+
## Step 4b — Author the yaml SoT (+ regenerate the sidecar)
|
|
188
|
+
|
|
189
|
+
A component isn't just its `.js`/`.css` — the `<name>.yaml` is the SOURCE OF
|
|
190
|
+
TRUTH the whole pipeline reads (docs site, A2UI registries, consumer
|
|
191
|
+
harnesses, `.d.ts` codegen). Every new primitive ships one; every prop/slot/
|
|
192
|
+
event change updates it. Field-by-field contract:
|
|
193
|
+
[yaml-contract.md](yaml-contract.md). Then regenerate — never hand-edit the
|
|
194
|
+
sidecar (`sidecar-prewrite-guard` blocks it anyway):
|
|
195
|
+
|
|
196
|
+
```bash
|
|
197
|
+
npm run build:components # yaml → <name>.a2ui.json + catalog + .d.ts
|
|
198
|
+
node scripts/build/components.mjs --verify # "clean — N files up-to-date"
|
|
199
|
+
```
|
|
200
|
+
|
|
201
|
+
A primitive also needs BOTH barrel registrations — the CSS `@import` in
|
|
202
|
+
`styles/components.css` AND the JS `export` in `components/index.js`
|
|
203
|
+
(`scripts/audit/check-components-js-barrel.mjs` gates the second).
|
|
204
|
+
|
|
187
205
|
## Step 5 — Run the project's verification gates
|
|
188
206
|
|
|
189
207
|
Before committing, run the project's verify scripts. These catch the drift-shaped bugs the checklist can miss:
|
|
@@ -206,4 +224,5 @@ If a gate fails, fix before declaring done.
|
|
|
206
224
|
- [lifecycle-patterns.md](lifecycle-patterns.md) — timers, observers, popovers, listener patterns
|
|
207
225
|
- [anti-patterns.md](anti-patterns.md) — full failure-mode catalogue, file:line refs
|
|
208
226
|
- [worked-example.md](worked-example.md) — badge-ui + counter-ui walkthroughs
|
|
227
|
+
- [yaml-contract.md](yaml-contract.md) — the `<name>.yaml` SoT schema (Step 4b)
|
|
209
228
|
- [token-contract.md](token-contract.md) — token audit (post-implementation check)
|
|
@@ -210,7 +210,7 @@ Native DOM accessors (`textContent`, `innerHTML`) get clobbered if declared in `
|
|
|
210
210
|
Every `addEventListener` in `connected()` must be paired with a `removeEventListener` in `disconnected()`. Every timer cleared, every observer disconnected, every popover removed. Handlers must be stable `#field` arrows so `removeEventListener` finds them via reference equality.
|
|
211
211
|
|
|
212
212
|
```js
|
|
213
|
-
class
|
|
213
|
+
class UIBadge extends UIElement {
|
|
214
214
|
#onRemove = (e) => { /* ... */ }; // stable handler
|
|
215
215
|
|
|
216
216
|
connected() {
|
|
@@ -226,7 +226,7 @@ class AdiaBadge extends AdiaElement {
|
|
|
226
226
|
|
|
227
227
|
Inline arrows passed to `addEventListener` look fine and leak quietly — `removeEventListener` no-ops because the new arrow has different identity. Three components in one audit cycle bit on this exact bug.
|
|
228
228
|
|
|
229
|
-
If the class extends `
|
|
229
|
+
If the class extends `UIFormElement`, `connected()` and `disconnected()` MUST call `super.*` — `ElementInternals` registration depends on it. And declare `disconnected()` exactly once per class; the second silently overrides the first.
|
|
230
230
|
|
|
231
231
|
Full lifecycle patterns in [lifecycle-patterns.md](lifecycle-patterns.md).
|
|
232
232
|
|
|
@@ -276,11 +276,11 @@ When transparency-mixing colors, use `oklab` not `oklch` for the interpolation s
|
|
|
276
276
|
|
|
277
277
|
## Legacy avoidance
|
|
278
278
|
|
|
279
|
-
The library was renamed from `@agent-ui-kit/*` to `@adia-ai/*`; tokens went from `--n-*` to `--a-*`; the base class went
|
|
279
|
+
The library was renamed from `@agent-ui-kit/*` to `@adia-ai/*`; tokens went from `--n-*` to `--a-*`; the base class went `NanoElement` → `AdiaElement` → `UIElement` (ADR-0016 class rename). Don't use the legacy forms in new code. Don't reference `nano-ui` in notes, commit messages, CHANGELOG entries, or any AdiaUI artifact.
|
|
280
280
|
|
|
281
281
|
```js
|
|
282
282
|
// right
|
|
283
|
-
import {
|
|
283
|
+
import { UIElement } from '@adia-ai/web-components/core';
|
|
284
284
|
:where(:scope) { --button-bg: var(--a-primary-bg); }
|
|
285
285
|
|
|
286
286
|
// wrong
|
|
@@ -319,7 +319,6 @@ For component source under `packages/web-components/components/**`, the gate is
|
|
|
319
319
|
- [css-patterns.md](css-patterns.md) — full @scope + variant/mode CSS architecture
|
|
320
320
|
- [lifecycle-patterns.md](lifecycle-patterns.md) — timers, observers, popovers, listeners
|
|
321
321
|
- [token-contract.md](token-contract.md) — token audit procedure
|
|
322
|
-
- [llm-bridge.md](llm-bridge.md) — extend @adia-ai/llm
|
|
323
322
|
- [module-promotion.md](module-promotion.md) — promote inline → module
|
|
324
323
|
- [anti-patterns.md](anti-patterns.md) — failure-mode catalogue with file:line refs
|
|
325
324
|
- **adia-a2ui** (sibling skill) — generator / corpus / MCP pipeline
|
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
# Lifecycle Patterns — Listeners, Timers, Observers, Popovers
|
|
2
2
|
|
|
3
|
-
Deep dive on symmetric `connected()` / `disconnected()` in AdiaUI components. Read when adding any side effect (listener, timer, observer, popover) to a component, or when inheriting from `
|
|
3
|
+
Deep dive on symmetric `connected()` / `disconnected()` in AdiaUI components. Read when adding any side effect (listener, timer, observer, popover) to a component, or when inheriting from `UIFormElement`.
|
|
4
4
|
|
|
5
5
|
## The symmetry rule
|
|
6
6
|
|
|
7
7
|
Every side effect set up in `connected()` has a matching teardown in `disconnected()`. The teardown is authored at the same time as the setup, not later — if you leave `disconnected()` for tomorrow, tomorrow won't happen.
|
|
8
8
|
|
|
9
9
|
```javascript
|
|
10
|
-
class
|
|
10
|
+
class UIWidget extends UIElement {
|
|
11
11
|
static properties = { /* ... */ };
|
|
12
12
|
static template = () => null;
|
|
13
13
|
|
|
@@ -150,16 +150,16 @@ disconnected() {
|
|
|
150
150
|
|
|
151
151
|
**Lesson:** a class must declare `disconnected()` exactly once. If you need to add teardown, edit the existing method. Duplicate method names silently shadow — no error, no warning.
|
|
152
152
|
|
|
153
|
-
## `
|
|
153
|
+
## `UIFormElement` — `super` discipline
|
|
154
154
|
|
|
155
|
-
Form-participating components inherit `ElementInternals` wiring from `
|
|
155
|
+
Form-participating components inherit `ElementInternals` wiring from `UIFormElement`. That wiring only works if `super.connected()` and `super.disconnected()` are called:
|
|
156
156
|
|
|
157
157
|
```javascript
|
|
158
|
-
import {
|
|
158
|
+
import { UIFormElement } from '../../core/form.js';
|
|
159
159
|
|
|
160
|
-
class
|
|
160
|
+
class UIInput extends UIFormElement {
|
|
161
161
|
static properties = {
|
|
162
|
-
...
|
|
162
|
+
...UIFormElement.properties,
|
|
163
163
|
placeholder: { type: String, default: '', reflect: true },
|
|
164
164
|
};
|
|
165
165
|
|
|
@@ -296,7 +296,7 @@ Especially important for components that are attached/detached frequently (modal
|
|
|
296
296
|
- **Inline arrow + `removeEventListener`** — the listener isn't really being removed. Silent leak.
|
|
297
297
|
- **Forgot to create `disconnected()`** — if `connected()` adds side effects, `disconnected()` must exist. No exceptions.
|
|
298
298
|
- **Two `disconnected()` methods in the same class** — the second silently wins; the first's cleanup is lost.
|
|
299
|
-
- **`super.connected()` missing in `
|
|
299
|
+
- **`super.connected()` missing in `UIFormElement` subclass** — form participation silently fails.
|
|
300
300
|
- **Popover / tooltip never cleaned up** — stays in `document.body` forever.
|
|
301
301
|
- **Observer recreated on every render** — re-observing without disconnecting first leaks observer refs.
|
|
302
302
|
- **Timer fired after component removed** — not cleared in `disconnected()`, fires on a dead component. Can cause null-deref crashes or phantom re-renders.
|
|
@@ -1,5 +1,12 @@
|
|
|
1
1
|
# LLM Bridge extension — @adia-ai/llm
|
|
2
2
|
|
|
3
|
+
**Superseded 2026-07-18 — `@adia-ai/llm` internals are `adia-llm-internals`'s charter, not
|
|
4
|
+
`adia-author`'s.** That skill's references (`adapter-contract.md`, `streaming-sse.md`,
|
|
5
|
+
`model-registry.md`, `bridge-facade.md`, `browser-proxy-boundary.md`, `add-a-provider.md`)
|
|
6
|
+
are the current, maintained source — this file is kept only as a historical pointer and is
|
|
7
|
+
no longer linked from `adia-author`'s task-shape table or `code-style.md`. Route provider/
|
|
8
|
+
streaming/bridge work to `adia-llm-internals`.
|
|
9
|
+
|
|
3
10
|
Use when adding a 4th provider, modifying `createAdapter()`, changing the streaming chunk shape, or extending `packages/llm/server.js`.
|
|
4
11
|
|
|
5
12
|
This reference is about **modifying** the package. For day-to-day consumption (import + call), the README at `packages/llm/README.md` is sufficient.
|
|
@@ -14,7 +14,7 @@ Every component's `.css` file must follow the **two-block @scope** pattern:
|
|
|
14
14
|
/* Block 1: token declarations on :where(:scope) — zero specificity */
|
|
15
15
|
@scope (my-component-ui) {
|
|
16
16
|
:where(:scope) {
|
|
17
|
-
--my-bg: var(--a-
|
|
17
|
+
--my-bg: var(--a-bg);
|
|
18
18
|
--my-text: var(--a-fg);
|
|
19
19
|
--my-radius: var(--a-radius-md);
|
|
20
20
|
}
|
|
@@ -30,8 +30,8 @@ Every component's `.css` file must follow the **two-block @scope** pattern:
|
|
|
30
30
|
|
|
31
31
|
/* Variants override TOKENS, not base styles */
|
|
32
32
|
:scope[variant="danger"] {
|
|
33
|
-
--my-bg: var(--a-danger-
|
|
34
|
-
--my-text: var(--a-danger-
|
|
33
|
+
--my-bg: var(--a-danger-bg);
|
|
34
|
+
--my-text: var(--a-danger-fg);
|
|
35
35
|
}
|
|
36
36
|
}
|
|
37
37
|
```
|
|
@@ -40,7 +40,7 @@ Every component's `.css` file must follow the **two-block @scope** pattern:
|
|
|
40
40
|
|
|
41
41
|
1. **Zero raw color values** anywhere in component CSS
|
|
42
42
|
- No `#fff`, `rgb(...)`, `oklch(...)` literals
|
|
43
|
-
- All colors must reference `--a-chrome-*`, `--a-data-0..9`, `--a-fg*`, `--a-
|
|
43
|
+
- All colors must reference `--a-chrome-*`, `--a-data-0..9`, `--a-fg*`, `--a-bg-*`, or family tokens (`--a-brand-*`, `--a-primary-*`, etc.)
|
|
44
44
|
2. **Two-block pattern** — token declarations separate from style rules
|
|
45
45
|
3. **Variants override tokens** — never rewrite base styles inside `[variant]` selectors. Change token values; the base styles absorb the change.
|
|
46
46
|
4. **`:where(:scope)`** for token defaults — zero specificity lets consumers override tokens from outside
|
|
@@ -75,7 +75,7 @@ Every component's `.css` file must follow the **two-block @scope** pattern:
|
|
|
75
75
|
4. **Check token usage in parent stylesheet**
|
|
76
76
|
|
|
77
77
|
```bash
|
|
78
|
-
grep -n "--a-chrome\|--a-data\|--a-fg\|--a-
|
|
78
|
+
grep -n -- "--a-chrome\|--a-data\|--a-fg\|--a-bg" \
|
|
79
79
|
packages/web-components/components/<name>/*.css
|
|
80
80
|
```
|
|
81
81
|
|