@adia-ai/adia-ui-forge 0.8.37 → 0.8.39
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 +23 -0
- package/README.md +6 -2
- package/agents/a2ui-planner-agent.md +52 -0
- package/agents/framework-alignment-agent.md +60 -0
- package/agents/framework-planner-agent.md +49 -0
- package/package.json +1 -1
- package/references/contracts/a2ui-mcp-surface.md +7 -7
- package/skills/a2ui-maintenance/SKILL.md +5 -5
- package/skills/a2ui-maintenance/references/anti-patterns.md +2 -2
- package/skills/a2ui-maintenance/references/chunk-authoring.md +2 -2
- package/skills/a2ui-maintenance/references/eval-diagnostics.md +3 -3
- package/skills/a2ui-maintenance/references/format-extension-decisions.md +1 -1
- package/skills/a2ui-maintenance/references/mcp-pipeline-ops.md +5 -5
- package/skills/a2ui-maintenance/references/mcp-tool-reference.md +4 -4
- package/skills/a2ui-maintenance/references/pipeline-overview.md +18 -18
- package/skills/a2ui-maintenance/references/semantic-fail-lifting.md +2 -2
- package/skills/a2ui-maintenance/references/strategy-engines.md +2 -2
- package/skills/a2ui-maintenance/references/zettel-calibration.md +2 -2
- package/skills/gen-ui-review/references/corpus-html-patterns.md +1 -1
- package/skills/gen-ui-review/references/loop-protocol.md +1 -1
- package/skills/llm-client-maintenance/SKILL.md +4 -4
- package/skills/llm-client-maintenance/references/adapter-contract.md +3 -3
- package/skills/llm-client-maintenance/references/add-a-provider.md +5 -5
- package/skills/llm-client-maintenance/references/bridge-facade.md +2 -2
- package/skills/llm-client-maintenance/references/browser-proxy-boundary.md +2 -2
- package/skills/llm-client-maintenance/references/model-registry.md +2 -2
- package/skills/llm-client-maintenance/references/streaming-sse.md +2 -2
- package/skills/package-release/SKILL.md +8 -8
- package/skills/package-release/references/cut-procedure.md +6 -91
- package/skills/package-release/references/gates-catalog.md +4 -4
- package/skills/package-release/references/independent-package-release.md +2 -2
- package/skills/package-release/references/recovery-paths.md +2 -2
- package/skills/package-release/scripts/bump.mjs +31 -28
- package/skills/package-release/scripts/insert-stub.mjs +1 -1
- package/skills/package-release/scripts/package-paths.mjs +34 -50
- package/skills/package-release/scripts/release-pack.mjs +12 -5
- package/skills/package-release/scripts/tag-lockstep.mjs +1 -1
- package/skills/primitive-authoring/references/common-gotchas.md +1 -1
- package/skills/primitive-authoring/references/css-patterns.md +1 -1
- package/skills/primitive-authoring/references/llm-bridge.md +12 -12
- package/skills/primitive-authoring/references/module-promotion.md +2 -2
- package/skills/primitive-authoring/references/token-contract.md +20 -1
- package/skills/site-deployment/SKILL.md +2 -2
- package/skills/site-deployment/references/deploy-playbooks.md +8 -8
- package/skills/site-docs-authoring/intent.md +1 -1
|
@@ -2,21 +2,21 @@
|
|
|
2
2
|
// standalone CHANGELOG helpers.
|
|
3
3
|
//
|
|
4
4
|
// THE PROBLEM (bit all 6 a2ui packages at the v0.7.14 cut):
|
|
5
|
-
// The 6 a2ui packages live on disk under `packages/a2ui/<x>/` but carry the
|
|
5
|
+
// The 6 a2ui packages live on disk under `packages/gen-ui/a2ui/<x>/` but carry the
|
|
6
6
|
// flat npm-name `a2ui-<x>` everywhere else in the tooling (release-pack.mjs,
|
|
7
7
|
// dispatch-publish.mjs, tag-lockstep.mjs all use the NAME form). The two
|
|
8
8
|
// standalone helpers (promote-unreleased.mjs, insert-stub.mjs) joined
|
|
9
9
|
// `packages/<arg>/CHANGELOG.md` with the raw arg, so calling them with the
|
|
10
10
|
// name form silently 404'd: `CHANGELOG.md not found at packages/a2ui-corpus/`.
|
|
11
|
-
// release-pack.mjs maps internally (`a2ui-corpus` → `packages/a2ui/corpus`),
|
|
11
|
+
// release-pack.mjs maps internally (`a2ui-corpus` → `packages/gen-ui/a2ui/corpus`),
|
|
12
12
|
// so the two forms diverged: name-form failed standalone, path-form failed
|
|
13
13
|
// when handed to the orchestrator-style callers.
|
|
14
14
|
//
|
|
15
15
|
// THE FIX:
|
|
16
16
|
// Accept BOTH forms. Try `packages/<arg>` first (path form, backward-compat).
|
|
17
17
|
// If that directory is absent AND the arg matches `a2ui-<x>`, fall back to
|
|
18
|
-
// `packages/a2ui/<x>`. So `a2ui-corpus` (name) and `a2ui/corpus` (path) both
|
|
19
|
-
// resolve to `packages/a2ui/corpus/`.
|
|
18
|
+
// `packages/gen-ui/a2ui/<x>`. So `a2ui-corpus` (name) and `a2ui/corpus` (path) both
|
|
19
|
+
// resolve to `packages/gen-ui/a2ui/corpus/`.
|
|
20
20
|
//
|
|
21
21
|
// Pure Node, stdlib only — keeps the scripts free of runtime deps.
|
|
22
22
|
|
|
@@ -55,12 +55,11 @@ import path from 'node:path';
|
|
|
55
55
|
// trip-wire (check-release.mjs's per-tag `checkTag` lookup) reads the FULL
|
|
56
56
|
// roster unfiltered — every pushed tag, lockstep or not, still needs its
|
|
57
57
|
// package.json/CHANGELOG validated, so it must recognize a class-B tag too.
|
|
58
|
-
//
|
|
59
|
-
//
|
|
60
|
-
//
|
|
61
|
-
//
|
|
62
|
-
//
|
|
63
|
-
// re-derive from a doc. Absent = a permanent package.
|
|
58
|
+
//
|
|
59
|
+
// `shim: true` (ADR-0048 P5) marked the six retired a2ui-* names for their
|
|
60
|
+
// single 0.8.37 bridge cut; the P7 follow-up PR deleted those rows together
|
|
61
|
+
// with packages/shims/. No row carries the flag anymore, and none may — a
|
|
62
|
+
// future one-cut bridge re-introduces the marker with its own retirement PR.
|
|
64
63
|
//
|
|
65
64
|
// Every lockstep-scoped consumer must filter `p.lockstep !== false` itself
|
|
66
65
|
// (this module intentionally does NOT pre-filter PACKAGE_NAMES/PACKAGE_DIRS —
|
|
@@ -69,9 +68,9 @@ import path from 'node:path';
|
|
|
69
68
|
export const PACKAGE_ROSTER = [
|
|
70
69
|
{ name: 'web-components', dir: 'packages/web-components', lockstep: true },
|
|
71
70
|
{ name: 'web-modules', dir: 'packages/web-modules', lockstep: true },
|
|
72
|
-
{ name: 'llm', dir: 'packages/llm', lockstep: true },
|
|
73
|
-
{ name: 'agent', dir: 'packages/agent', lockstep: true },
|
|
74
|
-
{ name: 'persona', dir: 'packages/persona', lockstep: true },
|
|
71
|
+
{ name: 'llm', dir: 'packages/llm/core', lockstep: true },
|
|
72
|
+
{ name: 'agent', dir: 'packages/llm/agent', lockstep: true },
|
|
73
|
+
{ name: 'persona', dir: 'packages/llm/persona', lockstep: true },
|
|
75
74
|
// ── ADR-0048 P5 — the estate split's published names ────────────────────
|
|
76
75
|
//
|
|
77
76
|
// The successors of the six old a2ui-* names. `a2ui`/`gen-ui` join here,
|
|
@@ -83,32 +82,19 @@ export const PACKAGE_ROSTER = [
|
|
|
83
82
|
// `mcp` (gh#1240, operator ruling 2026-08-14, roster 17 → 16): folds what
|
|
84
83
|
// were TWO planned rows — `gen-ui-mcp` (P2 rename target) and
|
|
85
84
|
// `a2ui-protocol-mcp` (minted fresh at P4) — into ONE published name,
|
|
86
|
-
// `@adia-ai/mcp`, at `packages/mcp/`. Neither predecessor name ever
|
|
85
|
+
// `@adia-ai/mcp`, at `packages/gen-ui/mcp/`. Neither predecessor name ever
|
|
87
86
|
// published a 0.8.x, so this fold has no npm deprecation cycle to run —
|
|
88
|
-
// unlike the SIX old a2ui-*
|
|
89
|
-
//
|
|
90
|
-
// npm-distribution row count dropped by one.
|
|
91
|
-
{ name: 'a2ui', dir: 'packages/a2ui', lockstep: true },
|
|
92
|
-
{ name: 'gen-ui', dir: 'packages/gen-ui', lockstep: true },
|
|
93
|
-
{ name: 'mcp', dir: 'packages/mcp', lockstep: true },
|
|
94
|
-
//
|
|
95
|
-
//
|
|
96
|
-
//
|
|
97
|
-
//
|
|
98
|
-
//
|
|
99
|
-
// post-publish. They are on the roster only so that cut versions, tags,
|
|
100
|
-
// CHANGELOGs and publish workflows treat them like any other package.
|
|
101
|
-
//
|
|
102
|
-
// `shim: true` is the retirement marker, not decoration: P7's follow-up PR
|
|
103
|
-
// deletes exactly the entries carrying it, together with packages/shims/,
|
|
104
|
-
// their publish workflows, and resolvePackageDir's `shims/` fallback below.
|
|
105
|
-
// Nothing else in the roster is allowed to carry it.
|
|
106
|
-
{ name: 'a2ui-runtime', dir: 'packages/shims/a2ui-runtime', lockstep: true, shim: true },
|
|
107
|
-
{ name: 'a2ui-compose', dir: 'packages/shims/a2ui-compose', lockstep: true, shim: true },
|
|
108
|
-
{ name: 'a2ui-corpus', dir: 'packages/shims/a2ui-corpus', lockstep: true, shim: true },
|
|
109
|
-
{ name: 'a2ui-mcp', dir: 'packages/shims/a2ui-mcp', lockstep: true, shim: true },
|
|
110
|
-
{ name: 'a2ui-retrieval', dir: 'packages/shims/a2ui-retrieval', lockstep: true, shim: true },
|
|
111
|
-
{ name: 'a2ui-validator', dir: 'packages/shims/a2ui-validator', lockstep: true, shim: true },
|
|
87
|
+
// unlike the SIX old a2ui-* names, which really did publish and got one
|
|
88
|
+
// (shim rows retired below). The two-SERVER decision (ADR-0048 §3) is
|
|
89
|
+
// unchanged; only the npm-distribution row count dropped by one.
|
|
90
|
+
{ name: 'a2ui', dir: 'packages/gen-ui/a2ui', lockstep: true },
|
|
91
|
+
{ name: 'gen-ui', dir: 'packages/gen-ui/engine', lockstep: true },
|
|
92
|
+
{ name: 'mcp', dir: 'packages/gen-ui/mcp', lockstep: true },
|
|
93
|
+
// The six retired a2ui-* names (a2ui-runtime/-compose/-corpus/-mcp/
|
|
94
|
+
// -retrieval/-validator) rode EXACTLY the 0.8.37 cut here as `shim: true`
|
|
95
|
+
// rows under packages/shims/, then the P7 follow-up PR deleted them
|
|
96
|
+
// (cut-procedure.md §0.8.38 precondition 1). Their npm names are
|
|
97
|
+
// deprecated pointers; nothing may re-add them.
|
|
112
98
|
// Plugins joined the lockstep 2026-07-15 (check-lockstep.mjs POLICY note);
|
|
113
99
|
// each carries a .claude-plugin/plugin.json that bumps with package.json.
|
|
114
100
|
{ name: 'adia-ui-factory', dir: 'packages/plugins/adia-ui-factory', lockstep: true, plugin: true },
|
|
@@ -135,19 +121,17 @@ export const PACKAGE_DIRS = PACKAGE_ROSTER.map((p) => p.dir);
|
|
|
135
121
|
// require the directory to exist (so callers can render a legible not-found
|
|
136
122
|
// error against the resolved path).
|
|
137
123
|
export function resolvePackageDir(repo, pkg) {
|
|
124
|
+
// Roster name-form first (ADR-0049): `llm` must resolve to the roster's
|
|
125
|
+
// `packages/llm/core`, never to the bare `packages/llm/` FAMILY GROUPING
|
|
126
|
+
// dir that now exists on disk (no package.json, no CHANGELOG) — an
|
|
127
|
+
// existsSync-first probe would hit the grouping dir and silently target
|
|
128
|
+
// a non-package. Same for `gen-ui` → `packages/gen-ui/engine`.
|
|
129
|
+
const row = PACKAGE_ROSTER.find((p) => p.name === pkg);
|
|
130
|
+
if (row) return path.relative('packages', row.dir);
|
|
138
131
|
if (fs.existsSync(path.join(repo, 'packages', pkg))) return pkg;
|
|
139
|
-
//
|
|
140
|
-
//
|
|
141
|
-
//
|
|
142
|
-
if (/^a2ui-/.test(pkg)) {
|
|
143
|
-
const shim = path.join('shims', pkg);
|
|
144
|
-
if (fs.existsSync(path.join(repo, 'packages', shim))) return shim;
|
|
145
|
-
}
|
|
146
|
-
const m = /^a2ui-(.+)$/.exec(pkg);
|
|
147
|
-
if (m) {
|
|
148
|
-
const nested = path.join('a2ui', m[1]);
|
|
149
|
-
if (fs.existsSync(path.join(repo, 'packages', nested))) return nested;
|
|
150
|
-
}
|
|
132
|
+
// (The historical a2ui-* fallbacks — packages/shims/<old-name> and the
|
|
133
|
+
// pre-split packages/gen-ui/a2ui/<x> nesting — died with the shim-deletion
|
|
134
|
+
// follow-up PR after the 0.8.37 cut; a2ui-gen-ui-split.md ruled both dead.)
|
|
151
135
|
// Plugins live under packages/plugins/<name> but carry the flat name form
|
|
152
136
|
// (adia-ui-forge) in the release tooling — same name-vs-path split as a2ui.
|
|
153
137
|
if (/^adia-ui-/.test(pkg)) {
|
|
@@ -222,8 +222,8 @@ function help() {
|
|
|
222
222
|
--gh-notes-file /tmp/release-v$X.Y.Z.md \\
|
|
223
223
|
--substantive "<one-line>" \\
|
|
224
224
|
--xref "packages/web-modules/CHANGELOG.md#0$X$Y$Z--YYYY-MM-DD" \\
|
|
225
|
-
--substantive-packages web-components,web-modules,
|
|
226
|
-
--stub-packages llm,a2ui
|
|
225
|
+
--substantive-packages web-components,web-modules,gen-ui \\
|
|
226
|
+
--stub-packages llm,agent,persona,a2ui,mcp,adia-ui-factory,adia-ui-forge
|
|
227
227
|
|
|
228
228
|
Flags: --go (single-authorization: the operator's cut-start go covers the
|
|
229
229
|
whole cycle — auto-confirms ALL checkpoints; stops only on
|
|
@@ -704,8 +704,9 @@ function step5Commit(args) {
|
|
|
704
704
|
...LOCKSTEP_ROSTER.flatMap(({ name, dir, plugin }) => {
|
|
705
705
|
// Roster-driven (H3): each package stages its manifest + CHANGELOG;
|
|
706
706
|
// plugins also stage .claude-plugin/plugin.json (the /plugin-update
|
|
707
|
-
// cache key, moved by bump.mjs); factory additionally pins
|
|
708
|
-
// .mcp.json (SKILL invariant 8 —
|
|
707
|
+
// cache key, moved by bump.mjs); factory additionally pins the
|
|
708
|
+
// generation MCP (@adia-ai/mcp) in .mcp.json (SKILL invariant 8 —
|
|
709
|
+
// bump.mjs moves the pin too).
|
|
709
710
|
const files = [`${dir}/package.json`, `${dir}/CHANGELOG.md`];
|
|
710
711
|
if (plugin) files.push(`${dir}/.claude-plugin/plugin.json`);
|
|
711
712
|
if (name === 'adia-ui-factory') files.push(`${dir}/.mcp.json`);
|
|
@@ -1167,7 +1168,13 @@ function selftest() {
|
|
|
1167
1168
|
guardFailed = true;
|
|
1168
1169
|
guardOut = (e.stdout || '') + (e.stderr || '');
|
|
1169
1170
|
}
|
|
1170
|
-
|
|
1171
|
+
// The expected ride-alongs are DERIVED from the roster (everything but
|
|
1172
|
+
// the one --substantive-packages entry above), never transcribed — a
|
|
1173
|
+
// hard-coded name here went stale when the shim-deletion follow-up PR
|
|
1174
|
+
// shrank the roster 16 → 10 (the same never-transcribe rule the cut
|
|
1175
|
+
// docs enforce on every other roster projection).
|
|
1176
|
+
const expectedRideAlongs = PACKAGES.filter((p) => p !== 'web-components');
|
|
1177
|
+
if (!guardFailed || !guardOut.includes('ride-along') || !expectedRideAlongs.every((p) => guardOut.includes(p))) {
|
|
1171
1178
|
console.error('selftest FAIL: from-scratch without --stub-packages must hard-reject at parse time, naming the ride-alongs');
|
|
1172
1179
|
process.exit(1);
|
|
1173
1180
|
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
// tag-lockstep.mjs — create the lockstep tag set (umbrella vX.Y.Z + one
|
|
3
3
|
// per-package <pkg>-vX.Y.Z per roster entry — package-paths.mjs is the
|
|
4
|
-
// live census;
|
|
4
|
+
// live census; 11 tags as of gh#1282) at HEAD or at a specified SHA.
|
|
5
5
|
//
|
|
6
6
|
// Usage:
|
|
7
7
|
// node tag-lockstep.mjs --version 0.6.22
|
|
@@ -125,7 +125,7 @@ async #loadContent(route) {
|
|
|
125
125
|
|
|
126
126
|
## 7. Minting a wrapper-shaped component before its registry.js entry lands — site-a2ui silently deletes the node, not just mis-types it
|
|
127
127
|
|
|
128
|
-
**Pattern**: a tag is gated first and only, for `*-ui` tags, by `packages/a2ui/registry.js`'s hand-maintained `registry` map — inverted into `reverseRegistry` at `transpiler-maps.js`'s module init, consulted first thing in `compose/transpiler/transpiler.js:149-150`. `registry.js` is hand-edited, not generated by `node scripts/build/components.mjs` (that script writes sidecars/prop-catalog data, consumed only for prop-extraction fidelity on tags the transpiler ALREADY resolved — `transpiler-maps.js:22-26`); a runtime `registerType()` call doesn't rescue a stale row either — `reverseRegistry` is a one-time init snapshot, not live. Regenerate a site-a2ui row for a demo using a component minted in the SAME change, before its `registry.js` line lands, and the tag falls through to `transpiler.js`'s "Unknown → Column" branch (line 180-183) — same mechanism as gh#535's toolbar-group breakage, which at least rendered visibly-wrong. A NEW component is usually wrapper-shaped (one child, author-defined attributes like `anchor="bottom"` the transpiler doesn't map to any real A2UI prop). That shape trips a SECOND, separate rule right after — "single-child container chains flatten" (`transpiler.js:282-285`): a retyped Column with exactly one child and zero recognized props is discarded outright, and its child is spliced directly into the PARENT's children in its place. The wrapper's own id and node are never pushed to the tree at all — not visible-but-wrong, just gone. The row is then internally self-consistent (content hash matches source) so `check:chunks-fresh`/`verify:site-a2ui` both report clean.
|
|
128
|
+
**Pattern**: a tag is gated first and only, for `*-ui` tags, by `packages/gen-ui/a2ui/registry.js`'s hand-maintained `registry` map — inverted into `reverseRegistry` at `transpiler-maps.js`'s module init, consulted first thing in `compose/transpiler/transpiler.js:149-150`. `registry.js` is hand-edited, not generated by `node scripts/build/components.mjs` (that script writes sidecars/prop-catalog data, consumed only for prop-extraction fidelity on tags the transpiler ALREADY resolved — `transpiler-maps.js:22-26`); a runtime `registerType()` call doesn't rescue a stale row either — `reverseRegistry` is a one-time init snapshot, not live. Regenerate a site-a2ui row for a demo using a component minted in the SAME change, before its `registry.js` line lands, and the tag falls through to `transpiler.js`'s "Unknown → Column" branch (line 180-183) — same mechanism as gh#535's toolbar-group breakage, which at least rendered visibly-wrong. A NEW component is usually wrapper-shaped (one child, author-defined attributes like `anchor="bottom"` the transpiler doesn't map to any real A2UI prop). That shape trips a SECOND, separate rule right after — "single-child container chains flatten" (`transpiler.js:282-285`): a retyped Column with exactly one child and zero recognized props is discarded outright, and its child is spliced directly into the PARENT's children in its place. The wrapper's own id and node are never pushed to the tree at all — not visible-but-wrong, just gone. The row is then internally self-consistent (content hash matches source) so `check:chunks-fresh`/`verify:site-a2ui` both report clean.
|
|
129
129
|
|
|
130
130
|
**Example**: minting `anchor-bar-ui` (gh#495, PR #569) and regenerating the `bulk-action-toolbar` pattern's site-a2ui row before the worktree's `registry.js` entry for it existed. Git-verified on the pre-fix commit (`ebf71832d`): `site-a2ui/pages/site__patterns__bulk-action-toolbar.a2ui.json` contains zero occurrences of `pat-bulk-float-bar` (the anchor-bar-ui's own authored id) anywhere — not retyped-and-visible, genuinely absent — while its single child (the toolbar content) survived, reparented one level up. `verify:site-a2ui` reported 321/321 clean.
|
|
131
131
|
|
|
@@ -223,7 +223,7 @@ AdiaUI is light-DOM. Slotted children are just children. Style them with attribu
|
|
|
223
223
|
}
|
|
224
224
|
|
|
225
225
|
:scope > header > [slot="heading"] {
|
|
226
|
-
font-weight: var(--a-
|
|
226
|
+
font-weight: var(--a-weight-semibold);
|
|
227
227
|
}
|
|
228
228
|
|
|
229
229
|
/* WRONG — ::slotted() is for shadow DOM */
|
|
@@ -7,9 +7,9 @@ are the current, maintained source — this file is kept only as a historical po
|
|
|
7
7
|
no longer linked from `primitive-authoring`'s task-shape table or `code-style.md`. Route provider/
|
|
8
8
|
streaming/bridge work to `llm-client-maintenance`.
|
|
9
9
|
|
|
10
|
-
Use when adding a 4th provider, modifying `createAdapter()`, changing the streaming chunk shape, or extending `packages/llm/server.js`.
|
|
10
|
+
Use when adding a 4th provider, modifying `createAdapter()`, changing the streaming chunk shape, or extending `packages/llm/core/server.js`.
|
|
11
11
|
|
|
12
|
-
This reference is about **modifying** the package. For day-to-day consumption (import + call), the README at `packages/llm/README.md` is sufficient.
|
|
12
|
+
This reference is about **modifying** the package. For day-to-day consumption (import + call), the README at `packages/llm/core/README.md` is sufficient.
|
|
13
13
|
|
|
14
14
|
---
|
|
15
15
|
|
|
@@ -18,7 +18,7 @@ This reference is about **modifying** the package. For day-to-day consumption (i
|
|
|
18
18
|
- Adding a new provider adapter (e.g., DeepSeek, Cohere, Mistral)
|
|
19
19
|
- Changing `maxTokens`, `temperature`, or another bridge default
|
|
20
20
|
- Extending the streaming chunk type set (currently: `text` / `thinking` / `done` / `error`)
|
|
21
|
-
- Adding a new endpoint to `packages/llm/server.js`
|
|
21
|
+
- Adding a new endpoint to `packages/llm/core/server.js`
|
|
22
22
|
- Modifying the bridge's `complete()` / `stream()` shape
|
|
23
23
|
- Debugging "why does my LLM call return truncated JSON?"
|
|
24
24
|
|
|
@@ -112,7 +112,7 @@ If you add a new endpoint, document it in the npm README under "Browser proxy mo
|
|
|
112
112
|
|
|
113
113
|
### Step 1: Create the adapter
|
|
114
114
|
|
|
115
|
-
`packages/llm/adapters/<name>.js` exports a single object matching the shape used by anthropic / openai / gemini:
|
|
115
|
+
`packages/llm/core/adapters/<name>.js` exports a single object matching the shape used by anthropic / openai / gemini:
|
|
116
116
|
|
|
117
117
|
```js
|
|
118
118
|
import { readSSE } from './sse.js';
|
|
@@ -139,7 +139,7 @@ export const myProvider = {
|
|
|
139
139
|
|
|
140
140
|
### Step 2: Register in the facade
|
|
141
141
|
|
|
142
|
-
Edit `packages/llm/adapters/index.js`:
|
|
142
|
+
Edit `packages/llm/core/adapters/index.js`:
|
|
143
143
|
|
|
144
144
|
```js
|
|
145
145
|
import { myProvider } from './myprovider.js';
|
|
@@ -154,7 +154,7 @@ function detectProvider(model) {
|
|
|
154
154
|
|
|
155
155
|
### Step 3: Subpath export
|
|
156
156
|
|
|
157
|
-
Edit `packages/llm/package.json`:
|
|
157
|
+
Edit `packages/llm/core/package.json`:
|
|
158
158
|
|
|
159
159
|
```json
|
|
160
160
|
"exports": {
|
|
@@ -216,19 +216,19 @@ const DEFAULT_MODELS = {
|
|
|
216
216
|
Run the smoke tests against the new provider:
|
|
217
217
|
|
|
218
218
|
```bash
|
|
219
|
-
MYPROVIDER_API_KEY=*** node packages/mcp/gen-ui/scripts/smoke-engine-registry.mjs
|
|
219
|
+
MYPROVIDER_API_KEY=*** node packages/gen-ui/mcp/gen-ui/scripts/smoke-engine-registry.mjs
|
|
220
220
|
```
|
|
221
221
|
|
|
222
222
|
Then run real-LLM eval at low intent count:
|
|
223
223
|
|
|
224
224
|
```bash
|
|
225
|
-
LLM_PROVIDER=myprovider node packages/mcp/gen-ui/scripts/eval-diff.mjs --semantic
|
|
225
|
+
LLM_PROVIDER=myprovider node packages/gen-ui/mcp/gen-ui/scripts/eval-diff.mjs --semantic
|
|
226
226
|
```
|
|
227
227
|
|
|
228
228
|
## Pitfalls
|
|
229
229
|
|
|
230
|
-
- **Two proxy shapes — `proxyUrl` is overloaded.** The bridge supports two architecturally different proxies and the dispatcher in `packages/llm/adapters/index.js` chooses between them by URL shape. Get this wrong and you get silent 401s in the browser even though `node packages/llm/server.js` works fine.
|
|
231
|
-
- **Smart proxy** (`packages/llm/server.js`, route `POST /api/chat`): accepts a **provider-neutral body** `{ provider, model, messages, ... }`, holds the API key server-side, and dispatches internally to the right adapter. Headers are just `content-type: application/json`.
|
|
230
|
+
- **Two proxy shapes — `proxyUrl` is overloaded.** The bridge supports two architecturally different proxies and the dispatcher in `packages/llm/core/adapters/index.js` chooses between them by URL shape. Get this wrong and you get silent 401s in the browser even though `node packages/llm/core/server.js` works fine.
|
|
231
|
+
- **Smart proxy** (`packages/llm/core/server.js`, route `POST /api/chat`): accepts a **provider-neutral body** `{ provider, model, messages, ... }`, holds the API key server-side, and dispatches internally to the right adapter. Headers are just `content-type: application/json`.
|
|
232
232
|
- **Passthrough proxy** (Vite dev `/api/llm/<provider>/<rest>` → real upstream URL `https://api.<provider>.com/<rest>`): expects the **real upstream body shape** (Anthropic-shaped for `/anthropic/`, OpenAI-shaped for `/openai/`, etc.) plus the **adapter's own auth headers** (`x-api-key` + `anthropic-version`, or `Authorization: Bearer …`). The proxy is dumb — it just rewrites the URL and forwards bytes.
|
|
233
233
|
- Dispatcher: `chat()` and `streamChat()` in `adapters/index.js` call `isPassthroughProxy(proxyUrl)` (regex `/\/api\/llm\/[a-z]+(\/|$)/`). If true, they call `passthroughRequest()` which builds the real upstream body via `adapter.buildRequest()` then swaps in `proxyUrl`. If false, they call `proxyRequest()` with the provider-neutral body.
|
|
234
234
|
- **When adding a new provider**, make sure: (1) `buildRequest()` omits the API key header when `proxyUrl` is the smart proxy (already handled), (2) `buildRequest()` _includes_ the API key header when called from `passthroughRequest()` (also already handled — passthroughRequest forwards adapter headers). The adapter's `buildRequest()` is the single source of truth for upstream-shape body + headers. Don't fork it for proxy mode.
|
|
@@ -246,7 +246,7 @@ After any extension:
|
|
|
246
246
|
npm run check:lockstep # @adia-ai/llm version must match the others
|
|
247
247
|
npm run smoke:engines # engines still register; pick still works
|
|
248
248
|
npm run test:a2ui # 22 pass / 0 fail / 1 skipped
|
|
249
|
-
node packages/llm/server.js # boots cleanly; .env auto-loads
|
|
249
|
+
node packages/llm/core/server.js # boots cleanly; .env auto-loads
|
|
250
250
|
```
|
|
251
251
|
|
|
252
252
|
If you added a new SSE chunk type to the streaming protocol, verify all 7 consumers (chat-shell, generator.js, synthesis.js, eval-chunk-synthesis, eval-refine-synthesis, playgrounds/chat, apps/genui) still handle it correctly or fall through gracefully.
|
|
@@ -256,4 +256,4 @@ If you added a new SSE chunk type to the streaming protocol, verify all 7 consum
|
|
|
256
256
|
- [code-style.md](code-style.md) — general AdiaUI conventions (this is a specialty path; start there if you need broader context)
|
|
257
257
|
- **a2ui-maintenance** (sibling skill) — generator / MCP / zettel synthesis (consumes the bridge)
|
|
258
258
|
- Spec: `.claude/docs/specs/package-architecture.md` § 11 (Phase 5 — engine registry)
|
|
259
|
-
- README: `packages/llm/README.md` — consumer-facing docs
|
|
259
|
+
- README: `packages/llm/core/README.md` — consumer-facing docs
|
|
@@ -119,7 +119,7 @@ The "stripped" consumer. Same structural change minus persistence.
|
|
|
119
119
|
|
|
120
120
|
### Phase 4 — Migrate the chunk corpus
|
|
121
121
|
|
|
122
|
-
The harvested training-corpus chunk (`packages/a2ui/corpus/chunks/<name>.json`) embeds the consumer's HTML as an escaped string. Update it so the LLM sees the new authoring shape.
|
|
122
|
+
The harvested training-corpus chunk (`packages/gen-ui/a2ui/corpus/chunks/<name>.json`) embeds the consumer's HTML as an escaped string. Update it so the LLM sees the new authoring shape.
|
|
123
123
|
|
|
124
124
|
1. **Preferred** — re-run the harvester:
|
|
125
125
|
|
|
@@ -144,7 +144,7 @@ The harvested training-corpus chunk (`packages/a2ui/corpus/chunks/<name>.json`)
|
|
|
144
144
|
3. **Defensive grep across all chunks** for the legacy markers:
|
|
145
145
|
|
|
146
146
|
```bash
|
|
147
|
-
grep -l 'id="<old-id>"' packages/a2ui/corpus/chunks/*.json
|
|
147
|
+
grep -l 'id="<old-id>"' packages/gen-ui/a2ui/corpus/chunks/*.json
|
|
148
148
|
```
|
|
149
149
|
|
|
150
150
|
4. **Gotcha — hand-edit + later re-harvest** — if you used the fallback (step 2) AND a peer later adds your consumer's directory to harvester SOURCES, the next `harvest:chunks` run will overwrite your hand-edit with the live consumer HTML. Usually that's _good_ (the re-harvest captures the live state, including any post-edit consumer updates), but diff before assuming. Concrete example: theme-panel's `playground-app-shell.json` was hand-edited, then re-harvested after `playgrounds/` was added to SOURCES — the re-harvest captured the `<aside-ui>` → `<admin-sidebar>` bespoke conversion that the hand-edit missed.
|
|
@@ -114,13 +114,32 @@ Every file under `packages/web-components/styles/` answers two questions — whi
|
|
|
114
114
|
- Spatial / size / radius / motion / elevation primitives → `styles/foundation/` (one file per dimension)
|
|
115
115
|
- Type scale (L1/L2), roles (L3), native-element defaults → `styles/type/`
|
|
116
116
|
- Color layers → `styles/colors/` (parameters · primitives-* · surfaces · scrims · semantics/*)
|
|
117
|
-
- The global attribute API (`[size]` `[density]` `[gap]` `[padding]` `[margin]` …) → `styles/api/{sizing,text,layout}.css` — the ONLY home for global `[attr]` selectors
|
|
117
|
+
- The global attribute API (`[size]` `[density]` `[gap]` `[padding]` `[margin]` …) → `styles/api/{sizing,text,layout}.css` — the ONLY home for global `[attr]` selectors (governed by the grammar spec below)
|
|
118
118
|
- `tokens.css`, `typography.css`, `colors/semantics.css`, etc. remain **compat barrels** at their public paths — they only `@import`; never add declarations to them
|
|
119
119
|
|
|
120
120
|
Enforced by `scripts/release/check-foundation-layer-placement.mjs` (wired into `npm run check`): header tags present, primitive files free of attribute selectors, the attribute API confined to `api/`, no orphan files. Import order inside `colors/semantics/` is load-bearing (`aliases.css` last) and asserted in file headers.
|
|
121
121
|
|
|
122
122
|
Source: ADR-0035.
|
|
123
123
|
|
|
124
|
+
## The global attribute grammar — read the spec before naming an attribute
|
|
125
|
+
|
|
126
|
+
The global attribute API is a *designed system* with its own spec:
|
|
127
|
+
`.claude/docs/specs/attribute-api-system.md` (companion audit:
|
|
128
|
+
`.claude/docs/specs/attribute-api-audit.md`). That spec — not this checklist —
|
|
129
|
+
owns the grammar. Two rules an author must know exist (read the spec for the
|
|
130
|
+
mechanics; never work from this summary alone):
|
|
131
|
+
|
|
132
|
+
- **Explicit vs ambient** (spec §5.2): `[gap]`/`[padding]`/`[margin]` are
|
|
133
|
+
*explicit* per-element overrides (non-inheriting), while `[size]`/`[density]`
|
|
134
|
+
are *ambient* context-setters (inheriting by design). Which axis an attribute
|
|
135
|
+
sits on decides its `@property` registration and how components read it.
|
|
136
|
+
- **No shadowing** (`docs/adr/adr-0053-no-shadowing-global-attributes.md`): a
|
|
137
|
+
component-local attribute may not share a name with any global attribute —
|
|
138
|
+
the global name always means the global thing. Before minting any attribute
|
|
139
|
+
in a component yaml, check it against the spec's attribute inventory; the
|
|
140
|
+
only sanctioned collisions live in the spec's §11 Global-Attribute Exemption
|
|
141
|
+
List (first entries: `swatch-ui[color]` / `noodles-ui[color]`, ADR-0054).
|
|
142
|
+
|
|
124
143
|
## When to update this reference
|
|
125
144
|
|
|
126
145
|
If you add a new token category (like `--a-chrome-*` was added), update both this file and `.claude/docs/specs/component-token-contract.md`. The spec doc is the live source of truth; this file is the practitioner's checklist.
|
|
@@ -88,9 +88,9 @@ delete-adjudication classes.
|
|
|
88
88
|
1. Build from clean, fully-merged `main`. In a fresh worktree,
|
|
89
89
|
`npm run build -w @adia-ai/llm` runs **before** `build:site` — llm compiles
|
|
90
90
|
at publish time and its outputs are gitignored, so without it
|
|
91
|
-
`/packages/llm/index.js` 404s and component registration breaks site-wide
|
|
91
|
+
`/packages/llm/core/index.js` 404s and component registration breaks site-wide
|
|
92
92
|
(found live 2026-06-09).
|
|
93
|
-
2. Dry-run `rsync -azni --delete --exclude='packages/a2ui/corpus/feedback/'`
|
|
93
|
+
2. Dry-run `rsync -azni --delete --exclude='packages/gen-ui/a2ui/corpus/feedback/'`
|
|
94
94
|
and bucket **every** `*deleting` line into a known-safe class; any
|
|
95
95
|
unexplained served-content delete aborts the deploy. The exclude protects
|
|
96
96
|
prod-only runtime-written files (feedback logs wiped 2026-06-10).
|
|
@@ -129,8 +129,8 @@ itself is unavailable.
|
|
|
129
129
|
```
|
|
130
130
|
The `llm` package **compiles its JS at publish time** and its outputs are
|
|
131
131
|
**gitignored** — so a fresh worktree (or any tree that hasn't published llm
|
|
132
|
-
locally) has no `packages/llm/index.js`, `build:site` copies nothing, and
|
|
133
|
-
**`/packages/llm/index.js` 404s on the deployed site → component registration
|
|
132
|
+
locally) has no `packages/llm/core/index.js`, `build:site` copies nothing, and
|
|
133
|
+
**`/packages/llm/core/index.js` 404s on the deployed site → component registration
|
|
134
134
|
breaks on every `/site/components/*` page** (the docs components reference it). Found
|
|
135
135
|
**live 2026-06-09**; the **0-delete dry-run proved it had never been deployed** (the
|
|
136
136
|
file was absent on the server, so there was nothing to delete — not a regression, a
|
|
@@ -145,22 +145,22 @@ itself is unavailable.
|
|
|
145
145
|
deploy gaps). After any package add/rename, check `site.mjs` before deploying.
|
|
146
146
|
2. **Dry-run first, and adjudicate every delete — BEFORE the real rsync, never after:**
|
|
147
147
|
```sh
|
|
148
|
-
rsync -azni --delete --exclude='packages/a2ui/corpus/feedback/' \
|
|
148
|
+
rsync -azni --delete --exclude='packages/gen-ui/a2ui/corpus/feedback/' \
|
|
149
149
|
dist/ <host>.exe.xyz:/srv/<app>/dist/ # -n simulates · -i itemizes
|
|
150
150
|
```
|
|
151
151
|
- **Exclude server-side runtime-written paths.** Some files exist ONLY on prod —
|
|
152
152
|
written by the running service at runtime, never present in a local build — so
|
|
153
153
|
`--delete` wipes them on every deploy. Known class on ui-kit:
|
|
154
|
-
`packages/a2ui/corpus/feedback/*.jsonl` (the gen-UI canvas training-feedback log).
|
|
154
|
+
`packages/gen-ui/a2ui/corpus/feedback/*.jsonl` (the gen-UI canvas training-feedback log).
|
|
155
155
|
Found **live 2026-06-10** (the deploy deleted the day's feedback log; restored from
|
|
156
156
|
the pre-deploy snapshot). Carry the same `--exclude` list on BOTH the dry-run and
|
|
157
157
|
the real rsync; when a new runtime-written path appears, add it here.
|
|
158
158
|
- `*deleting` lines = files removed from prod. Bucket **every one** into a known-safe
|
|
159
159
|
class; **abort if any served-content delete is unexplained.** Safe classes seen on
|
|
160
160
|
ui-kit: gallery review artifacts (`apps/genui/.../review/cycle-*/`), stale
|
|
161
|
-
`packages/a2ui/retrieval/` + eval reports, **content-hash-rotated** CodeMirror
|
|
161
|
+
`packages/gen-ui/a2ui/retrieval/` + eval reports, **content-hash-rotated** CodeMirror
|
|
162
162
|
chunks (`code/{chunk,dist}-<hash>.js` — old hash deleted, new hash sent = rotation,
|
|
163
|
-
not loss), restructured `packages/llm/*.js` dist copies, `node_modules/`
|
|
163
|
+
not loss), restructured `packages/llm/core/*.js` dist copies, `node_modules/`
|
|
164
164
|
symlink-farm dirs, and refactor-orphaned app files. None are served HTML.
|
|
165
165
|
- **Don't panic at the send count.** A fresh local build never mtime-aligns with the
|
|
166
166
|
remote, so `rsync -a` flags ~every file as a send (`<f..t` = mtime-only touch). Only
|
|
@@ -176,7 +176,7 @@ itself is unavailable.
|
|
|
176
176
|
mutating in place. Restore with `rm -rf dist && mv dist.bak-<date> dist`.
|
|
177
177
|
4. **Deploy** (the dry-run, minus `-n` — SAME excludes):
|
|
178
178
|
```sh
|
|
179
|
-
rsync -az --delete --exclude='packages/a2ui/corpus/feedback/' \
|
|
179
|
+
rsync -az --delete --exclude='packages/gen-ui/a2ui/corpus/feedback/' \
|
|
180
180
|
dist/ <host>.exe.xyz:/srv/<app>/dist/
|
|
181
181
|
```
|
|
182
182
|
5. **Verify the FILE, not the route.** A SPA returns `200` + the app shell for *any*
|
|
@@ -205,7 +205,7 @@ itself is unavailable.
|
|
|
205
205
|
>
|
|
206
206
|
> **The one exception — `@adia-ai/llm` (2026-06-09):** llm is NOT a source-tree
|
|
207
207
|
> component; it **builds its JS at publish** (gitignored outputs), so `build:site` copies
|
|
208
|
-
> nothing for it in a fresh worktree and `/packages/llm/index.js` 404s → component
|
|
208
|
+
> nothing for it in a fresh worktree and `/packages/llm/core/index.js` 404s → component
|
|
209
209
|
> registration breaks site-wide. Run `npm run build -w @adia-ai/llm` **before** `build:site`
|
|
210
210
|
> (step 1 above). This is exactly why step 5 render-checks a **`/site/components/*`** page,
|
|
211
211
|
> not just a fixture file — the 404 is invisible to file-presence and to the SPA shell.
|
|
@@ -49,7 +49,7 @@ before they start typing.
|
|
|
49
49
|
|
|
50
50
|
## fences
|
|
51
51
|
- NOT for `packages/web-components/components/*/*.examples.html` component demo pages (primitive-authoring)
|
|
52
|
-
- NOT for `site/pages/examples/**`, `site/pages/gen-ui/**`, `packages/a2ui/corpus/exemplars/**` — pure primitive-composition training-harvest surfaces with their own no-style-block rule (`composition-and-examples.md`, a2ui-maintenance)
|
|
52
|
+
- NOT for `site/pages/examples/**`, `site/pages/gen-ui/**`, `packages/gen-ui/a2ui/corpus/exemplars/**` — pure primitive-composition training-harvest surfaces with their own no-style-block rule (`composition-and-examples.md`, a2ui-maintenance)
|
|
53
53
|
- NOT for the A2UI generation pipeline itself, chunk corpus, or MCP tools (a2ui-maintenance)
|
|
54
54
|
|
|
55
55
|
## assertions
|