@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
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
# Adapter contract
|
|
2
2
|
|
|
3
|
-
The single shape every provider adapter implements. Source: `packages/llm/src/adapters/anthropic.ts` (the canonical adapter — `openai.ts` and `gemini.ts` import their shared types from it), the facade `packages/llm/src/adapters/index.ts`, and the shared parser `packages/llm/src/adapters/sse.ts`.
|
|
3
|
+
The single shape every provider adapter implements. Source: `packages/llm/core/src/adapters/anthropic.ts` (the canonical adapter — `openai.ts` and `gemini.ts` import their shared types from it), the facade `packages/llm/core/src/adapters/index.ts`, and the shared parser `packages/llm/core/src/adapters/sse.ts`.
|
|
4
4
|
|
|
5
5
|
This reference is about the adapter object — its three methods, the request it builds, and the response/usage/`stopReason` it parses. The SSE-byte mechanics live in `streaming-sse.md`; the facade that dispatches to an adapter lives in `bridge-facade.md`.
|
|
6
6
|
|
|
7
|
-
Field tables below are a snapshot verified against `packages/llm/src/` on 2026-07-10 — on any conflict, the source wins; re-grep before relying on an exact field name.
|
|
7
|
+
Field tables below are a snapshot verified against `packages/llm/core/src/` on 2026-07-10 — on any conflict, the source wins; re-grep before relying on an exact field name.
|
|
8
8
|
|
|
9
9
|
---
|
|
10
10
|
|
|
@@ -98,4 +98,4 @@ Symptom: cache hit-rate telemetry reads `0` for Anthropic even though the API re
|
|
|
98
98
|
- [bridge-facade.md](bridge-facade.md) — how `chat()` / `streamChat()` resolve and call an adapter; the `ChatResult` wrapper
|
|
99
99
|
- [browser-proxy-boundary.md](browser-proxy-boundary.md) — why `buildRequest()` must stay proxy-agnostic
|
|
100
100
|
- [add-a-provider.md](add-a-provider.md) — the end-to-end recipe that uses this contract
|
|
101
|
-
- Source: `packages/llm/src/adapters/anthropic.ts` (canonical types + adapter), `openai.ts`, `gemini.ts`
|
|
101
|
+
- Source: `packages/llm/core/src/adapters/anthropic.ts` (canonical types + adapter), `openai.ts`, `gemini.ts`
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# Add a provider
|
|
2
2
|
|
|
3
|
-
The end-to-end recipe for a 4th provider adapter (DeepSeek, Mistral, Cohere, an OpenAI-compatible gateway, …). Grounded in the existing three adapters under `packages/llm/src/adapters/` and the facade `packages/llm/src/adapters/index.ts`. Read `adapter-contract.md` first — this recipe wires the contract it defines.
|
|
3
|
+
The end-to-end recipe for a 4th provider adapter (DeepSeek, Mistral, Cohere, an OpenAI-compatible gateway, …). Grounded in the existing three adapters under `packages/llm/core/src/adapters/` and the facade `packages/llm/core/src/adapters/index.ts`. Read `adapter-contract.md` first — this recipe wires the contract it defines.
|
|
4
4
|
|
|
5
5
|
Adding a provider is **additive** to the public surface (a new adapter, a new `MODELS` group, a new `detectProvider` branch). It does not break existing consumers if you follow the contract.
|
|
6
6
|
|
|
@@ -12,7 +12,7 @@ Many providers (Groq, Together, Mistral, any OpenAI-compatible gateway) speak th
|
|
|
12
12
|
|
|
13
13
|
## Step 1 — write the adapter
|
|
14
14
|
|
|
15
|
-
Create `packages/llm/src/adapters/<name>.ts` exporting one `const` matching the contract (model on `anthropic.ts`):
|
|
15
|
+
Create `packages/llm/core/src/adapters/<name>.ts` exporting one `const` matching the contract (model on `anthropic.ts`):
|
|
16
16
|
|
|
17
17
|
- `name: '<name>' as const`.
|
|
18
18
|
- `buildRequest(opts: BuildRequestOpts): AdapterRequest` — return `{ url, headers, body }`. Set the auth header the provider expects. Map `opts.system`, `opts.messages`, `opts.maxTokens` (default to the package's `32768` unless the provider's ceiling is lower), `opts.temperature`, and the `stream` flag into the provider's body shape.
|
|
@@ -23,7 +23,7 @@ Create `packages/llm/src/adapters/<name>.ts` exporting one `const` matching the
|
|
|
23
23
|
|
|
24
24
|
## Step 2 — register in the facade
|
|
25
25
|
|
|
26
|
-
Edit `packages/llm/src/adapters/index.ts`:
|
|
26
|
+
Edit `packages/llm/core/src/adapters/index.ts`:
|
|
27
27
|
|
|
28
28
|
```text
|
|
29
29
|
import { myprovider } from './myprovider.js';
|
|
@@ -44,7 +44,7 @@ Support both conventions — a substring (`m.includes(...)`) and a `provider/mod
|
|
|
44
44
|
|
|
45
45
|
## Step 4 — add to the model registry
|
|
46
46
|
|
|
47
|
-
Edit `packages/llm/src/models.ts` — add a `ModelGroup`:
|
|
47
|
+
Edit `packages/llm/core/src/models.ts` — add a `ModelGroup`:
|
|
48
48
|
|
|
49
49
|
```text
|
|
50
50
|
{ label: 'MyProvider', options: [ { value: '<model-id>', label: '<display name>' } ] }
|
|
@@ -54,7 +54,7 @@ Keep the `[{ label, options: [{ value, label }] }]` shape exactly (the `<chat-in
|
|
|
54
54
|
|
|
55
55
|
## Step 5 — wire the bridge default + browser route (if browser-routable)
|
|
56
56
|
|
|
57
|
-
Edit `packages/llm/src/llm-bridge.ts`:
|
|
57
|
+
Edit `packages/llm/core/src/llm-bridge.ts`:
|
|
58
58
|
|
|
59
59
|
- Add `myprovider: '<default-model-id>'` to `DEFAULT_MODELS` (the per-provider fallback `createAdapter()` uses when no model is supplied — distinct from `models.ts`'s `DEFAULT_MODEL`; see `model-registry.md`).
|
|
60
60
|
- **INVARIANT: every keyed map in the bridge (`DEFAULT_MODELS`, `resolveBaseUrl`'s proxyMap, `detectProvider`'s return) uses the SAME key as the adapters registry** (`providers` in `adapters/index.ts`). A mismatched key compiles fine and throws at runtime (`Unknown provider`) — the gh#268 L-1 bug class. If a marketing name differs from the registry key (Google/Gemini), normalize the alias at the top of `createAdapter()` and use the registry key everywhere below.
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# Bridge + facade + stub
|
|
2
2
|
|
|
3
|
-
The three public entry layers above the adapters. Source: the facade `packages/llm/src/adapters/index.ts` (`chat` / `streamChat` / `createClient` + types), the bridge `packages/llm/src/llm-bridge.ts` (`createAdapter` → `AdiaUILLMBridge`), the stub `packages/llm/src/llm-stub.ts` (`StubLLMAdapter`), and the barrel `packages/llm/src/index.ts`.
|
|
3
|
+
The three public entry layers above the adapters. Source: the facade `packages/llm/core/src/adapters/index.ts` (`chat` / `streamChat` / `createClient` + types), the bridge `packages/llm/core/src/llm-bridge.ts` (`createAdapter` → `AdiaUILLMBridge`), the stub `packages/llm/core/src/llm-stub.ts` (`StubLLMAdapter`), and the barrel `packages/llm/core/src/index.ts`.
|
|
4
4
|
|
|
5
5
|
This reference covers the facade/bridge contract and the stub. The proxy-flavor mechanics are in `browser-proxy-boundary.md`.
|
|
6
6
|
|
|
@@ -98,4 +98,4 @@ The stub's `complete()` result shape (`{ content, usage: { inputTokens, outputTo
|
|
|
98
98
|
- [browser-proxy-boundary.md](browser-proxy-boundary.md) — the `proxyUrl` dispatch and the production-host stub path
|
|
99
99
|
- [model-registry.md](model-registry.md) — `DEFAULT_MODEL` vs the bridge's `DEFAULT_MODELS`
|
|
100
100
|
- [streaming-sse.md](streaming-sse.md) — the `StreamChunk` union the bridge re-shapes
|
|
101
|
-
- Source: `packages/llm/src/adapters/index.ts`, `packages/llm/src/llm-bridge.ts`, `packages/llm/src/llm-stub.ts`, `packages/llm/src/index.ts`
|
|
101
|
+
- Source: `packages/llm/core/src/adapters/index.ts`, `packages/llm/core/src/llm-bridge.ts`, `packages/llm/core/src/llm-stub.ts`, `packages/llm/core/src/index.ts`
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# Browser / proxy boundary
|
|
2
2
|
|
|
3
|
-
The browser+Node duality and the two proxy flavors. Source: the dispatch in `packages/llm/src/adapters/index.ts` (`isPassthroughProxy`, `proxyRequest`, `passthroughRequest`) and the browser logic in `packages/llm/src/llm-bridge.ts` (`resolveBaseUrl`, `isProductionHost`, `createBrowserProxyBridge`, the key-in-browser warning).
|
|
3
|
+
The browser+Node duality and the two proxy flavors. Source: the dispatch in `packages/llm/core/src/adapters/index.ts` (`isPassthroughProxy`, `proxyRequest`, `passthroughRequest`) and the browser logic in `packages/llm/core/src/llm-bridge.ts` (`resolveBaseUrl`, `isProductionHost`, `createBrowserProxyBridge`, the key-in-browser warning).
|
|
4
4
|
|
|
5
5
|
This is the single most error-prone area of the package: `proxyUrl` is overloaded, and getting it wrong produces silent 401s in the browser even when the local server works fine.
|
|
6
6
|
|
|
@@ -88,4 +88,4 @@ Keep the warning and the dedup flag when touching `createAdapter()`.
|
|
|
88
88
|
- [adapter-contract.md](adapter-contract.md) — `buildRequest()` as the single upstream-shape source
|
|
89
89
|
- [bridge-facade.md](bridge-facade.md) — `createAdapter()` and the stub fallback
|
|
90
90
|
- [streaming-sse.md](streaming-sse.md) — SSE-through-a-proxy buffering symptoms
|
|
91
|
-
- Source: `isPassthroughProxy` / `proxyRequest` / `passthroughRequest` in `packages/llm/src/adapters/index.ts`; `resolveBaseUrl` / `isProductionHost` / `createBrowserProxyBridge` in `packages/llm/src/llm-bridge.ts`
|
|
91
|
+
- Source: `isPassthroughProxy` / `proxyRequest` / `passthroughRequest` in `packages/llm/core/src/adapters/index.ts`; `resolveBaseUrl` / `isProductionHost` / `createBrowserProxyBridge` in `packages/llm/core/src/llm-bridge.ts`
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# Model registry
|
|
2
2
|
|
|
3
|
-
The shared model catalog and provider detection. Source: `packages/llm/src/models.ts` (the `MODELS` catalog + `DEFAULT_MODEL`) and the `detectProvider()` function in `packages/llm/src/adapters/index.ts`.
|
|
3
|
+
The shared model catalog and provider detection. Source: `packages/llm/core/src/models.ts` (the `MODELS` catalog + `DEFAULT_MODEL`) and the `detectProvider()` function in `packages/llm/core/src/adapters/index.ts`.
|
|
4
4
|
|
|
5
5
|
Concrete ids/groups below are a snapshot verified against the source on 2026-07-10 — on any conflict, the source wins.
|
|
6
6
|
|
|
@@ -74,4 +74,4 @@ Add a new Anthropic model to the chat-input dropdown.
|
|
|
74
74
|
|
|
75
75
|
- [bridge-facade.md](bridge-facade.md) — `createAdapter()` and its per-provider `DEFAULT_MODELS`
|
|
76
76
|
- [add-a-provider.md](add-a-provider.md) — the recipe that adds a `MODELS` group + a `detectProvider` branch together
|
|
77
|
-
- Source: `packages/llm/src/models.ts`, `detectProvider()` in `packages/llm/src/adapters/index.ts`, `DEFAULT_MODELS` in `packages/llm/src/llm-bridge.ts`
|
|
77
|
+
- Source: `packages/llm/core/src/models.ts`, `detectProvider()` in `packages/llm/core/src/adapters/index.ts`, `DEFAULT_MODELS` in `packages/llm/core/src/llm-bridge.ts`
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# Streaming + SSE
|
|
2
2
|
|
|
3
|
-
The streaming protocol and the shared SSE parser. Source: `packages/llm/src/adapters/sse.ts` (the parser) and the `parseStream` method of each adapter in `packages/llm/src/adapters/anthropic.ts` / `openai.ts` / `gemini.ts`. The `StreamChunk` union is declared in `anthropic.ts`.
|
|
3
|
+
The streaming protocol and the shared SSE parser. Source: `packages/llm/core/src/adapters/sse.ts` (the parser) and the `parseStream` method of each adapter in `packages/llm/core/src/adapters/anthropic.ts` / `openai.ts` / `gemini.ts`. The `StreamChunk` union is declared in `anthropic.ts`.
|
|
4
4
|
|
|
5
5
|
---
|
|
6
6
|
|
|
@@ -92,4 +92,4 @@ A new `StreamChunk` variant (e.g. `{ type: 'tool_call'; ... }`):
|
|
|
92
92
|
- [adapter-contract.md](adapter-contract.md) — the adapter object, `parseResponse`, and the `usage` / `stopReason` mapping
|
|
93
93
|
- [bridge-facade.md](bridge-facade.md) — how the bridge re-shapes `StreamChunk` for the adia-ui pipeline
|
|
94
94
|
- [browser-proxy-boundary.md](browser-proxy-boundary.md) — SSE through a proxy (buffering pitfalls)
|
|
95
|
-
- Source: `packages/llm/src/adapters/sse.ts`, and the `parseStream` of `anthropic.ts` / `openai.ts` / `gemini.ts`
|
|
95
|
+
- Source: `packages/llm/core/src/adapters/sse.ts`, and the `parseStream` of `anthropic.ts` / `openai.ts` / `gemini.ts`
|
|
@@ -3,8 +3,8 @@ name: package-release
|
|
|
3
3
|
description: >-
|
|
4
4
|
Release engineering for the @adia-ai lockstep monorepo. Use when asked to
|
|
5
5
|
cut and ship a release, promote [Unreleased] CHANGELOG entries, tag and push the
|
|
6
|
-
lockstep packages to origin, publish a
|
|
7
|
-
npm libraries + 2 Claude Code plugins, as of gh#
|
|
6
|
+
lockstep packages to origin, publish a 10-package release (8
|
|
7
|
+
npm libraries + 2 Claude Code plugins, as of gh#1282's shim retirement — see
|
|
8
8
|
scripts/package-paths.mjs), batch-push piled-up release commits,
|
|
9
9
|
recover a cut that landed wrong or whose publish workflows didn't fire,
|
|
10
10
|
fix a check:lockstep bump failure or an F-N1 CHANGELOG-coverage warning,
|
|
@@ -18,7 +18,7 @@ user-invocable: true
|
|
|
18
18
|
|
|
19
19
|
# package-release
|
|
20
20
|
|
|
21
|
-
Release engineering for an @adia-ai-style lockstep monorepo: the `@adia-ai/*` packages on the roster (`scripts/package-paths.mjs`, the single source —
|
|
21
|
+
Release engineering for an @adia-ai-style lockstep monorepo: the `@adia-ai/*` packages on the roster (`scripts/package-paths.mjs`, the single source — 10 lockstep as of gh#1282's shim retirement (ADR-0048 P7 follow-up: the six `shim: true` old-name rows rode the 0.8.37 cut once and are deleted): 8 npm libraries plus the 2 Claude Code plugins under `packages/plugins/*`) version and publish together (class A; the plugins joined the lockstep 2026-07-15 after class-B independence let npm drift a full harness-reset behind the repo). Class B (independent versioning) has one member — `@adia-ai/adia-plugins` (gh#1133/gh#1160, ADR-0045), the npm-sourced marketplace manifest package, marked `lockstep: false` on the roster; it cuts on its own version line and its own tag, never the umbrella ([`references/independent-package-release.md`](references/independent-package-release.md)). The substrate — `scripts/release/*`, the `check:*` gates, the tag-triggered publish workflows — encodes the invariants; this skill routes, sequences, and stops at the judgment calls.
|
|
22
22
|
|
|
23
23
|
## Authorization — one go, gates do the rest (operator ruling 2026-07-17)
|
|
24
24
|
|
|
@@ -35,11 +35,11 @@ Mechanics: `release-pack.mjs --go` auto-confirms all checkpoints (it equals `--y
|
|
|
35
35
|
1. **Lockstep coherence** — every roster package bumps together (`check:lockstep`). **The roster is `scripts/package-paths.mjs`'s `PACKAGE_ROSTER` — read it, never a copy.** This line used to enumerate the names inline and went stale the first time the roster moved (ADR-0048 P4 added a package while the list still read the pre-split six); a name list here has no gate behind it, so it can only decay. Each plugin's `.claude-plugin/plugin.json` version moves with its package.json — `bump.mjs` handles both; `verify:plugins` gates the sync.
|
|
36
36
|
2. **PATCH-cut asymmetry** — internal `@adia-ai/*` ranges hold at `^X.Y.0` during PATCH cuts; only MINOR bumps the floor. `^0.0.x` is forbidden (pre-1.0 caret locks exact — shipped a real stale-sibling bug).
|
|
37
37
|
3. **Release commits land via PR, never a direct push to `main`** (repo policy, operator ruling 2026-07-12): commit on `release/vX.Y.Z` → PR → CI → merge — THEN tag at `main`'s post-merge HEAD, not at the bump commit; post-bump fixes merge before tagging and belong in the tarball. Exception: batch push tags each version at its own release-merge SHA.
|
|
38
|
-
4. **One umbrella + one per-package tag per cut** (`vX.Y.Z` +
|
|
38
|
+
4. **One umbrella + one per-package tag per cut** (`vX.Y.Z` + 10 × `<pkg>-vX.Y.Z`, one per lockstep-roster package — `scripts/package-paths.mjs`); publish workflows key off the per-package tags. Push tags **one per `git push`** — a batched multi-tag push drops the trigger event.
|
|
39
39
|
5. **F-N1 (`check:release --all-pending`) per-package clean** — the umbrella-tag mismatch error is expected noise. Coverage is mechanized at cut time: Step 4f (`check-release.mjs --pending-version X.Y.Z --fix`) runs the SAME matcher pre-PR and auto-appends verified Maintenance bullets, so a post-tag warn means something novel — stop and investigate, don't loop enrichment PRs.
|
|
40
40
|
6. **`npm dist-tag latest` is set by publish order** — batch pushes publish oldest first and WAIT for settle.
|
|
41
41
|
7. **A breaking (MINOR) cut MUST ship its MIGRATION GUIDE section in the same cycle** — MINOR is reserved for removed/renamed API symbols; everything else, including visible behavior changes, stays PATCH.
|
|
42
|
-
8. **The adia-factory plugin's `.mcp.json` pins the generation MCP exactly** — bump the pin in `packages/plugins/adia-ui-factory/.mcp.json` in the same cut (the consumer never floats; with the plugins in-lockstep this lands in the release commit itself, not a follow-up). The pinned NAME is
|
|
42
|
+
8. **The adia-factory plugin's `.mcp.json` pins the generation MCP exactly** — bump the pin in `packages/plugins/adia-ui-factory/.mcp.json` in the same cut (the consumer never floats; with the plugins in-lockstep this lands in the release commit itself, not a follow-up). The pinned NAME is `@adia-ai/mcp` with the `gen-ui` subcommand (`npx -y @adia-ai/mcp@<exact> gen-ui`) — the single live name since the ADR-0048 P7 cut (v0.8.37) per the gh#1240 one-package amendment; `@adia-ai/a2ui-mcp` is retired and the P2-planned `@adia-ai/gen-ui-mcp` never published. `check:lockstep`'s mcp-pin guard and `bump.mjs` both enforce this pin.
|
|
43
43
|
|
|
44
44
|
The release is done only when reality confirms it: **the npm registry, the GH release page, and the deployed endpoint — a workflow's green check or any self-report is never the verify target.**
|
|
45
45
|
|
|
@@ -59,7 +59,7 @@ The release is done only when reality confirms it: **the npm registry, the GH re
|
|
|
59
59
|
|
|
60
60
|
| Task shape | Done when |
|
|
61
61
|
| --- | --- |
|
|
62
|
-
| Lockstep cut / handoff | `npm view @adia-ai/<pkg> version` = X.Y.Z for all
|
|
62
|
+
| Lockstep cut / handoff | `npm view @adia-ai/<pkg> version` = X.Y.Z for all 10 lockstep packages AND `dist-tags.latest` = X.Y.Z AND a deployed content file (not an SPA route) serves real bytes |
|
|
63
63
|
| Batch push | every batched tag on `git ls-remote --tags origin` + every version on the registry, `latest` on the newest |
|
|
64
64
|
| Verify-only | the failing gate re-runs green |
|
|
65
65
|
| Recovery | the trip-wire that surfaced the issue passes |
|
|
@@ -75,7 +75,7 @@ Every cut reports, whether it ran inline or via `package-release-agent`:
|
|
|
75
75
|
| --- | --- |
|
|
76
76
|
| Version | X.Y.Z — all roster packages at this version (`check:lockstep`) |
|
|
77
77
|
| Commit / PR | release commit SHA, PR # (merged) |
|
|
78
|
-
| Tags | umbrella `vX.Y.Z` +
|
|
78
|
+
| Tags | umbrella `vX.Y.Z` + 10 per-package tags pushed (or: which are still pending, and why) |
|
|
79
79
|
| Registry | `npm view @adia-ai/<pkg> version` per package, cited (not "publish workflow green") |
|
|
80
80
|
| `dist-tags.latest` | confirmed = X.Y.Z |
|
|
81
81
|
| Deploy | dispatched (`deploy-site.yml` run URL) / N/A this cut |
|
|
@@ -96,7 +96,7 @@ assumed pass, or "published" without the actual `npm view` output.
|
|
|
96
96
|
|
|
97
97
|
`release-pack.mjs` walks the cycle in two phases per invariant 3 — `--mode cut` / `--mode from-scratch` promote `[Unreleased]` (BOTH modes now — a peer's hand-authored section must be promoted whichever mode cut it, and a loud guard blocks the bump if any roster package still carries non-empty `[Unreleased]` content after promotion), run Step 4f (pre-tag coverage `--fix` with the authoritative F-N1 matcher), and stop at the release commit (PR → merge); `--mode handoff` tags/publishes/deploys from post-merge main. **`--go` is the standard invocation for an operator-initiated release** — the single authorization covers the cycle; evidence blocks print as a log; granular `--yes`/`--push`/`--publish` remain for cautious manual runs (`--push` still refuses to auto-fire past any F-N1 finding). `--mode batch` is not implemented — it hard-rejects with a pointer to [`recovery-paths.md`](references/recovery-paths.md) §Scenario 2 rather than silently misbehaving; a real batch tags each version at its own release-merge SHA, which this single-version orchestrator has no model for. Pre-flight (Step 3) runs the full 29-gate roster from the single shared list in `scripts/gate-roster.mjs` — the same list [`cut-procedure.md`](references/cut-procedure.md) §3.1 transcribes, so a subset run requires editing that one file, not two.
|
|
98
98
|
|
|
99
|
-
The pieces are callable alone: `bump.mjs` (version fields + the factory `.mcp.json`
|
|
99
|
+
The pieces are callable alone: `bump.mjs` (version fields + the factory `.mcp.json` `@adia-ai/mcp` pin, invariant 8), `promote-unreleased.mjs` / `insert-stub.mjs` (CHANGELOG blocks), `tag-lockstep.mjs` (umbrella + one tag per lockstep roster package — the set is derived from `PACKAGE_ROSTER`, never a number written here: it went stale at 14 while the roster said 17, 17 went stale in turn when gh#1240 folded two planned MCP rows into one (now 16), and 16 goes stale again the day the ADR-0048 shims retire; run `--dry` to see the live list, `--delete` to move), `dispatch-publish.mjs` (publish workflows; `--verify-triggered` re-dispatches missing AND dead — cancelled/failed/timed-out — runs, each gated behind an npm-registry check so an already-published version is never re-dispatched (gh#763); `--after` enforces batch ordering — dispatch output states what WAS done, never a to-do phrased as if it hadn't fired), and `pr-bridge.mjs` (the two-phase bridge: pushes the release branch, opens the PR, waits out CI, and merges ONLY on all-non-fail-soft-checks-green + zero unresolved threads + no changes-requested; any other state stops with evidence — §5.7 mechanized, `--dry` to preview the decision). All fail fast outside a monorepo root (`assert-monorepo-root.mjs`); fork-configurable via `--host` / `--scope`. All 6 CLI scripts (plus `scripts/release/check-release.mjs`) have a `selftest` mode wired into CI's Plugin bin selftests step; the 3 helper modules (`assert-monorepo-root`, `gate-roster`, `package-paths`) are exercised through the CLIs' selftests, not their own.
|
|
100
100
|
|
|
101
101
|
Site deploy (Step 10 of the handoff) dispatches `deploy-site.yml` (its own pre-flight verify → snapshot → hardened rsync → post-deploy verify → auto-rollback), never a raw local `rsync` — H1 (forge-campaign gh#268 audit): the script had drifted into bypassing that pipeline even though this doc already taught the workflow-dispatch path. The dispatch rides the cycle's single authorization (`--go`, or `--publish` on a manual run); the workflow's own GitHub environment gate is the human stop for the deploy itself.
|
|
102
102
|
|
|
@@ -92,7 +92,7 @@ When only source *hashes* move and chunk content does not, `check:embeddings-fre
|
|
|
92
92
|
```bash
|
|
93
93
|
node scripts/build/components.mjs --verify # 1 yaml ↔ sidecar ↔ .d.ts
|
|
94
94
|
npm run verify:traits # 2 trait coverage
|
|
95
|
-
npm run check:lockstep # 3 version coherence (+ factory .mcp.json
|
|
95
|
+
npm run check:lockstep # 3 version coherence (+ factory .mcp.json @adia-ai/mcp pin, invariant 8)
|
|
96
96
|
npm run test:unit:serial # 4 vitest, serial — the source of truth (§Cat 8; parallel flakes under load)
|
|
97
97
|
npm run typecheck # 5 tsc --noEmit
|
|
98
98
|
npm run check:demo-shells # 6 demo imports cover composes:
|
|
@@ -223,7 +223,7 @@ allowlist (never `git add -A`; if peers may have pre-staged files,
|
|
|
223
223
|
git -C "$REPO" checkout -b "release/vX.Y.Z"
|
|
224
224
|
git -C "$REPO" reset HEAD >/dev/null 2>&1
|
|
225
225
|
git -C "$REPO" add package-lock.json packages/*/package.json packages/*/CHANGELOG.md \
|
|
226
|
-
packages/a2ui/*/package.json packages/a2ui/*/CHANGELOG.md \
|
|
226
|
+
packages/gen-ui/a2ui/*/package.json packages/gen-ui/a2ui/*/CHANGELOG.md \
|
|
227
227
|
packages/genui/adia-catalog/base.json packages/genui/adia-catalog/adia-pack.json \
|
|
228
228
|
docs/releases/vX.Y.Z.md # + in-scope source + Step-3.0 regen outputs
|
|
229
229
|
git -C "$REPO" diff --cached --stat | tail -3 # count must match the allowlist
|
|
@@ -276,7 +276,7 @@ The operator's initiating instruction covers the whole cycle — no per-step re-
|
|
|
276
276
|
|
|
277
277
|
| Evidence logged before | Content | Why it's still printed |
|
|
278
278
|
| --- | --- | --- |
|
|
279
|
-
| Tagging (Step 6) | The planned tag list (umbrella +
|
|
279
|
+
| Tagging (Step 6) | The planned tag list (umbrella + 10 per-package) | The log line a recovery diagnoses from |
|
|
280
280
|
| Pushing (Step 8) | The Step 7 F-N1 output + tag list + `origin/main..HEAD` count | F-N1's first real evidence — and its ERROR path still hard-stops unconditionally |
|
|
281
281
|
| Publishing (Step 9) | The current registry snapshot (versions + `dist-tags.latest`) | Ordering is verified against what's LIVE, mechanically |
|
|
282
282
|
| Deploying (Step 10) | The `deploy-site.yml` dispatch (never a raw rsync) | The workflow carries its own GitHub-environment human gate |
|
|
@@ -299,7 +299,7 @@ Log the planned tag list (evidence table above), then tag **at `main`'s post-mer
|
|
|
299
299
|
|
|
300
300
|
```bash
|
|
301
301
|
node "${CLAUDE_PLUGIN_ROOT}/skills/package-release/scripts/tag-lockstep.mjs" \
|
|
302
|
-
--version X.Y.Z # umbrella vX.Y.Z +
|
|
302
|
+
--version X.Y.Z # umbrella vX.Y.Z + 10 <pkg>-vX.Y.Z (8 npm + 2 plugins)
|
|
303
303
|
```
|
|
304
304
|
|
|
305
305
|
## §Step 7 — F-N1 release trip-wire
|
|
@@ -395,98 +395,13 @@ Any Step-2 stashes: `git stash pop`; flag conflicts to the operator.
|
|
|
395
395
|
|
|
396
396
|
Always author notes at end-of-cycle without being asked — context is freshest now. Single version → [`notes-authoring.md`](notes-authoring.md); ≥2 versions since the last broadcast → its §Rollup section. Surface the draft inline for copy-paste; the operator owns posting. Skip only on an explicit "no notes".
|
|
397
397
|
|
|
398
|
-
## §The 0.8.37 estate-split cut (ADR-0048 P7 — ONE cut, then delete this section)
|
|
399
|
-
|
|
400
|
-
Extra steps for the single cut that ships the a2ui/gen-ui split. They ride the
|
|
401
|
-
normal procedure above; nothing here replaces a step.
|
|
402
|
-
|
|
403
|
-
**It is a PATCH cut, by operator ruling (2026-08-13, gh#1192)** — `0.8.37`, not
|
|
404
|
-
the `0.9.0` MINOR the ADR originally proposed. Two consequences to hold in mind
|
|
405
|
-
before Step 4:
|
|
406
|
-
|
|
407
|
-
- **Invariant 2 (PATCH asymmetry) applies UNCHANGED — no exception.** Internal
|
|
408
|
-
`@adia-ai/*` dep ranges stay `^0.8.0` on a patch cut, and that is exactly
|
|
409
|
-
right here: `targetCaret("0.8.37")` is `^0.8.0`, the three new names
|
|
410
|
-
(`a2ui`, `gen-ui`, `mcp` — retargeted gh#1240, 2026-08-14: this row named
|
|
411
|
-
`gen-ui-mcp` before the MCP-distribution fold; that name never published,
|
|
412
|
-
`mcp` is its real successor) publish `0.8.37` as their FIRST version, and
|
|
413
|
-
`^0.8.0` resolves to it. The shims' deps on their successors are already
|
|
414
|
-
`^0.8.0` and need no edit; web-modules' EXACT peer pin moves to `0.8.37` by
|
|
415
|
-
the normal peer rule (gh#489), which `bump.mjs` does. So nothing in the split
|
|
416
|
-
needs a hand-written range — if `check:lockstep` asks for one, something else
|
|
417
|
-
is wrong; do not hand-pin.
|
|
418
|
-
- **A patch-shaped number does NOT relax the MIGRATION GUIDE obligation**
|
|
419
|
-
(invariant 7). Six published names are being replaced; the guide is owed
|
|
420
|
-
regardless of what the version looks like. This is the one failure mode the
|
|
421
|
-
small number invites.
|
|
422
|
-
|
|
423
|
-
**In the release commit (Step 4/5), not before and not after:**
|
|
424
|
-
|
|
425
|
-
1. **Flip the factory `.mcp.json` pin NAME** — `@adia-ai/a2ui-mcp` →
|
|
426
|
-
`@adia-ai/mcp` (retargeted gh#1240, 2026-08-14: this step named
|
|
427
|
-
`@adia-ai/gen-ui-mcp` before the MCP-distribution fold folded that planned
|
|
428
|
-
name — and `@adia-ai/a2ui-protocol-mcp` — into `@adia-ai/mcp` before either
|
|
429
|
-
ever published; the flip target moved, the flip's own timing did not), in
|
|
430
|
-
`packages/plugins/adia-ui-factory/.mcp.json` AND its README prose echo
|
|
431
|
-
(invariant 8 covers both files; `bump.mjs` moves the VERSION on either
|
|
432
|
-
name, so only the name is hand-edited). The pinned args also grow a
|
|
433
|
-
subcommand: `["-y", "@adia-ai/mcp@0.8.37", "gen-ui"]` — the fold's bin
|
|
434
|
-
dispatches `adia-mcp gen-ui`/`adia-mcp protocol`, not a bare invocation.
|
|
435
|
-
**Why here and not at P5:** invariant 8 forces the pin to the CURRENT
|
|
436
|
-
lockstep version. Before this cut that is `0.8.36`, and `@adia-ai/mcp`
|
|
437
|
-
has no `0.8.36` on npm — flipping early pins every local-marketplace install
|
|
438
|
-
to `npx -y @adia-ai/mcp@0.8.36`, i.e. a registry 404. In this commit
|
|
439
|
-
the version becomes `0.8.37`, which this cut publishes. (The reasoning is
|
|
440
|
-
unchanged by the 0.9.0 → 0.8.37 ruling, and unchanged again by the
|
|
441
|
-
gen-ui-mcp → mcp retarget; only the numbers and the name moved.)
|
|
442
|
-
`check:lockstep` accepts any name this pin has carried (`MCP_PIN_RE`), so
|
|
443
|
-
the flip is gate-clean regardless of which name is live when this runs.
|
|
444
|
-
|
|
445
|
-
**Config-KEY standardization rides the same flip (operator ruling
|
|
446
|
-
2026-08-14):** the `mcpServers` key names move with the pin so a tool
|
|
447
|
-
call's prefix always names which server answered. Factory `.mcp.json`:
|
|
448
|
-
key `a2ui` → `adia-gen-ui`. Repo root `.mcp.json`: key `adia-ui` →
|
|
449
|
-
`adia-gen-ui`. New entries added later use `adia-protocol` /
|
|
450
|
-
`adia-factory` for the other subcommands. Key renames change consumers'
|
|
451
|
-
tool prefixes (`mcp__a2ui__*` → `mcp__adia-gen-ui__*`) — that is the
|
|
452
|
-
point, and it ships in the same breaking-named cut as everything else.
|
|
453
|
-
|
|
454
|
-
**After Step 9 (publish), once `npm view <old-name> version` shows the shim on
|
|
455
|
-
the registry — never before:**
|
|
456
|
-
|
|
457
|
-
2. **Deprecate the six retired names.** The list is projected from the shim
|
|
458
|
-
generator's SPEC, so it cannot drift from what actually shipped:
|
|
459
|
-
|
|
460
|
-
```bash
|
|
461
|
-
node scripts/build/generate-shims.mjs --deprecate-commands
|
|
462
|
-
```
|
|
463
|
-
|
|
464
|
-
It prints the `npm deprecate` lines plus an `npm info <pkg> deprecated`
|
|
465
|
-
verify line per package. Print-only by design — read them, then run them.
|
|
466
|
-
**Verify by reading the field back**; a zero exit code is not proof.
|
|
467
|
-
Deprecating before the shim publishes leaves consumers at a dead end (the
|
|
468
|
-
pointer text names a package version that isn't there yet).
|
|
469
|
-
|
|
470
|
-
3. **Verify a shim tarball's CONTENTS, not just the publish exit code** — e.g.
|
|
471
|
-
`npm pack @adia-ai/a2ui-runtime@0.8.37 && tar -tzf *.tgz`, then import one
|
|
472
|
-
subpath from a scratch dir and confirm it resolves through to
|
|
473
|
-
`@adia-ai/a2ui`.
|
|
474
|
-
|
|
475
|
-
**Follow-up PR (not this cut):** delete `packages/shims/`, the roster rows
|
|
476
|
-
marked `shim: true`, their six `publish-a2ui-*.yml` workflows,
|
|
477
|
-
`resolvePackageDir`'s `shims/` fallback, `scripts/build/generate-shims.mjs`,
|
|
478
|
-
`scripts/verify/check-shim-bridges.mjs`, the `check:shims` gate, and this
|
|
479
|
-
section. Then narrow `MCP_PIN_RE` + `bump.mjs`'s pin pattern back to the single
|
|
480
|
-
new name.
|
|
481
|
-
|
|
482
|
-
---
|
|
483
|
-
|
|
484
398
|
## §The 0.8.38 cut (the clean-world cut — delete this section after it lands)
|
|
485
399
|
|
|
486
400
|
The first cut AFTER the estate-split bridge. Pre-conditions, all verifiable
|
|
487
401
|
before Step 1:
|
|
488
402
|
|
|
489
|
-
1. **The shim-deletion follow-up PR has MERGED** (the §0.8.37 follow-up
|
|
403
|
+
1. **The shim-deletion follow-up PR has MERGED** (the §0.8.37 follow-up — that
|
|
404
|
+
section deleted itself with the same PR, as designed:
|
|
490
405
|
`packages/shims/` gone, roster shim rows gone, the six `publish-a2ui-*.yml`
|
|
491
406
|
workflows gone, `check:shims`/`check-shim-bridges` retired). The roster file
|
|
492
407
|
is the member count — never transcribe it.
|
|
@@ -14,7 +14,7 @@ Row layout per gate: **What** · **Typical failure** · **Recovery**.
|
|
|
14
14
|
|
|
15
15
|
### `npm run check:lockstep`
|
|
16
16
|
|
|
17
|
-
- **What:** all
|
|
17
|
+
- **What:** all 10 lockstep `@adia-ai/*` packages declare the same `version` (the class-B `adia-plugins` package is excluded — `lockstep: false`, `scripts/package-paths.mjs`); internal `@adia-ai/*` dep ranges match policy (`^X.Y.0` during PATCH cycles, bumped at MINOR).
|
|
18
18
|
- **Typical failure:** one package forgot to bump; a peer edited an internal range mid-PATCH; a `^0.0.x` range slipped in.
|
|
19
19
|
- **Recovery:** version drift → `` `${CLAUDE_PLUGIN_ROOT}/skills/package-release/scripts/bump.mjs` ``; range drift → `npm run check:lockstep:fix` auto-aligns, then re-run.
|
|
20
20
|
- **Why `^0.0.x` is forbidden:** npm pre-1.0 semver only widens the caret when major+minor aren't both zero — `^0.0.6` resolves to `>=0.0.6 <0.0.7`, locked to exactly 0.0.6. An internal dep pinned that way silently installs a *stale* sibling on every fresh `npm i` (this shipped a real ~4-day-latent bug before the lockstep policy). The `^X.Y.0` floor (Y≥1) widens correctly across patches; trust the gate, don't reason about caret semantics by hand. Moot at 1.0.0.
|
|
@@ -96,8 +96,8 @@ Also: `check:no-self-import-css` (no transitively self-importing barrel) · `che
|
|
|
96
96
|
|
|
97
97
|
### `npm run check:browser-safe`
|
|
98
98
|
|
|
99
|
-
- **What:** no top-level `import 'node:*'` in browser-reachable modules (`packages/a2ui/{compose,retrieval,validator}`, `web-components/`, `web-modules/`, `apps/*/app/*.contents.js`).
|
|
100
|
-
- **Recovery:** dual-mode pattern (`IS_NODE` + dynamic `await import(/* @vite-ignore */ 'node:*')` + `import.meta.glob` browser branch); canonical impl: `packages/a2ui/retrieval/component-catalog.js`.
|
|
99
|
+
- **What:** no top-level `import 'node:*'` in browser-reachable modules (`packages/gen-ui/a2ui/{compose,retrieval,validator}`, `web-components/`, `web-modules/`, `apps/*/app/*.contents.js`).
|
|
100
|
+
- **Recovery:** dual-mode pattern (`IS_NODE` + dynamic `await import(/* @vite-ignore */ 'node:*')` + `import.meta.glob` browser branch); canonical impl: `packages/gen-ui/a2ui/retrieval/component-catalog.js`.
|
|
101
101
|
|
|
102
102
|
Siblings: `check:absolute-imports` (no leading-`/` imports — rewrite relative) · `check:template-interp` (template `${expr}` contract) · `check:yaml-events` (yaml `events:` match runtime `dispatchEvent` calls) · `check:yaml-impl-coverage` (every yaml prop implemented in the JS class).
|
|
103
103
|
|
|
@@ -121,7 +121,7 @@ The two `audit:*` probes are soft-fail pre-cut (exit-1 only on criticals); findi
|
|
|
121
121
|
|
|
122
122
|
### `npm run verify:corpus`
|
|
123
123
|
|
|
124
|
-
- **What:** every chunk in `packages/a2ui/corpus/chunks/*.json` is reachable and well-formed.
|
|
124
|
+
- **What:** every chunk in `packages/gen-ui/a2ui/corpus/chunks/*.json` is reachable and well-formed.
|
|
125
125
|
- **Recovery:** corpus remediation routes to the A2UI-pipeline skill, not this one.
|
|
126
126
|
|
|
127
127
|
### `npm run check:chunks-fresh`
|
|
@@ -19,7 +19,7 @@
|
|
|
19
19
|
| | Class A — lockstep cut | Class B — independent package |
|
|
20
20
|
| --- | --- | --- |
|
|
21
21
|
| Versioning | whole set bumps together | own version line per package |
|
|
22
|
-
| Lockstep gate | enforced (`check:lockstep`
|
|
22
|
+
| Lockstep gate | enforced (`check:lockstep` 10/10) | **excluded** — a class-B package is not listed in `check-lockstep.mjs`'s `PACKAGES` (`adia-plugins`, the current member, is filtered out via `lockstep: false` — `scripts/package-paths.mjs`) |
|
|
23
23
|
| Umbrella tag | `vX.Y.Z` + per-package | **none** — per-package tags only (versions differ) |
|
|
24
24
|
| `dist-tag` ordering | cross-package publish order matters | N/A |
|
|
25
25
|
| Demo-site deploy | yes | **none** |
|
|
@@ -47,7 +47,7 @@ Substrate fixes (release scripts / lockfile / CHANGELOG), landed once as a norma
|
|
|
47
47
|
|
|
48
48
|
## §Verify target
|
|
49
49
|
|
|
50
|
-
The published package(s) on the **npm registry** at their independent versions, plus the npm-published `@adia-ai/adia-plugins` manifest referencing the new versions (ADR-0045). NOT "all
|
|
50
|
+
The published package(s) on the **npm registry** at their independent versions, plus the npm-published `@adia-ai/adia-plugins` manifest referencing the new versions (ADR-0045). NOT "all 10 lockstep packages + the demo site" — that's class A.
|
|
51
51
|
|
|
52
52
|
## §Gotchas (from the first independent cut, factory v0.2.2 + forge v0.1.2)
|
|
53
53
|
|
|
@@ -17,7 +17,7 @@
|
|
|
17
17
|
|
|
18
18
|
1. Verify the skip: `npm view <pkg> versions --json | tail` (no X+1 on npm) + `git tag --list 'vX.Y.*'` (no tags). Run pre-flight at the peer's commit to confirm it's shippable.
|
|
19
19
|
2. Correct the version via a **new commit on top** (not amend — the peer's commit stays for history).
|
|
20
|
-
3. Sweep every occurrence of the wrong version:
|
|
20
|
+
3. Sweep every occurrence of the wrong version: 10 × package.json, 10 × CHANGELOG (headers + body refs — the lockstep roster, `scripts/package-paths.mjs`), any doc/CSS-comment refs, then regenerate the lockfile. Preserve filename references that intentionally encode the original label.
|
|
21
21
|
4. Commit as `fix(release): correct vX.Y.Z+1 version-skip → vX.Y.Z` documenting the discovery, then resume [`cut-procedure.md`](cut-procedure.md) at Step 5.
|
|
22
22
|
|
|
23
23
|
## §Scenario 2 — Batch push
|
|
@@ -63,7 +63,7 @@
|
|
|
63
63
|
|
|
64
64
|
## §Scenario 7 — Tags pushed, ZERO publish workflows fired
|
|
65
65
|
|
|
66
|
-
**Shape:** all
|
|
66
|
+
**Shape:** all 11 tags exist on origin (umbrella + one per lockstep-roster package — `scripts/package-paths.mjs`), but no `publish-<pkg>.yml` run exists for them; npm latest unchanged; nothing errored.
|
|
67
67
|
|
|
68
68
|
**Root cause:** pushing many tags in **one** `git push` fires a single batched create event that GitHub Actions routinely drops. Re-pushing is a no-op (the tags already exist remotely).
|
|
69
69
|
|
|
@@ -41,36 +41,34 @@ const SIBLING_MANIFESTS = Object.fromEntries(
|
|
|
41
41
|
|
|
42
42
|
// Cross-package EXACT pins bumped in the same pass — a different shape from a
|
|
43
43
|
// package.json "version" field, so SIBLING_MANIFESTS' regex can't reach them.
|
|
44
|
-
// The factory plugin's .mcp.json pins @adia-ai/
|
|
44
|
+
// The factory plugin's .mcp.json pins @adia-ai/mcp to the exact lockstep
|
|
45
45
|
// version (SKILL invariant 8 — the consumer never floats). bump.mjs left this
|
|
46
46
|
// untouched through the 0.8.6 + 0.8.7 cuts, forcing a manual edit + amend each
|
|
47
47
|
// time; check-lockstep's mcp-pin guard now catches a drift, this moves it.
|
|
48
48
|
//
|
|
49
49
|
// Each package maps to an ARRAY of pin configs — the factory README's own
|
|
50
|
-
// prose echo of the same pin (`server pinned: @adia-ai/
|
|
50
|
+
// prose echo of the same pin (`server pinned: @adia-ai/mcp@X`) is a
|
|
51
51
|
// SECOND file invariant 8 covers, and check:plugin-count-claims' "factory
|
|
52
|
-
// README
|
|
53
|
-
// this array through the 0.8.35 + 0.8.36 cuts, it needed the same manual
|
|
52
|
+
// README generation-MCP pin" EQUALITY check enforces the two agree. Left out
|
|
53
|
+
// of this array through the 0.8.35 + 0.8.36 cuts, it needed the same manual
|
|
54
54
|
// hand-commit .mcp.json used to (gh#1198) — same file set, invariant 8's own
|
|
55
55
|
// scope, so it moves alongside .mcp.json rather than getting its own key.
|
|
56
56
|
//
|
|
57
|
-
//
|
|
58
|
-
// the
|
|
59
|
-
//
|
|
60
|
-
//
|
|
61
|
-
//
|
|
62
|
-
//
|
|
63
|
-
// the version bump works before AND after either flip, with no cut-day edit
|
|
64
|
-
// to this file.
|
|
57
|
+
// `@adia-ai/mcp` is the single live name since the 0.8.37 estate-split cut
|
|
58
|
+
// flipped the pin in its release commit (ADR-0048 P7). The bridge-window
|
|
59
|
+
// alternation over the retired names (`a2ui-mcp`, the never-published
|
|
60
|
+
// `gen-ui-mcp`) was narrowed back by the shim-deletion follow-up PR, matching
|
|
61
|
+
// lockstep-checks.mjs's MCP_PIN_RE — a retired name in the pin must now fail
|
|
62
|
+
// loudly instead of being bumped along.
|
|
65
63
|
const A2UI_MCP_PIN = {
|
|
66
|
-
label: 'generation-MCP pin (@adia-ai/
|
|
67
|
-
// `@adia-ai/
|
|
64
|
+
label: 'generation-MCP pin (@adia-ai/mcp)',
|
|
65
|
+
// `@adia-ai/mcp@<from>` (not a prefix of a longer version) → `@<to>`
|
|
68
66
|
// Escape EVERY regex metacharacter in `from`, not just dots: a prerelease or
|
|
69
67
|
// build-metadata version (`0.9.0-rc+1`) would otherwise inject `+` as a
|
|
70
68
|
// quantifier and silently match the wrong text. Same class as the truncating
|
|
71
69
|
// MCP_PIN_RE suffix CodeRabbit found on PR #1229.
|
|
72
70
|
pattern: (from) =>
|
|
73
|
-
new RegExp(`(@adia-ai/
|
|
71
|
+
new RegExp(`(@adia-ai/mcp@)${from.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')}(?![\\d.])`),
|
|
74
72
|
replace: (to) => `$1${to}`,
|
|
75
73
|
};
|
|
76
74
|
const PINNED_REFS = {
|
|
@@ -298,38 +296,43 @@ function selftest() {
|
|
|
298
296
|
console.error('selftest FAIL: corrupted package.json (no version match) not caught'); process.exit(1);
|
|
299
297
|
}
|
|
300
298
|
|
|
301
|
-
// PINNED_REFS — the .mcp.json
|
|
299
|
+
// PINNED_REFS — the .mcp.json @adia-ai/mcp pin (invariant 8) moves in lockstep.
|
|
302
300
|
const [pinCfg, readmePinCfg] = PINNED_REFS['packages/plugins/adia-ui-factory'];
|
|
303
|
-
const pinBefore = '{"args":["-y","@adia-ai/
|
|
301
|
+
const pinBefore = '{"args":["-y","@adia-ai/mcp@0.8.6","gen-ui"]}';
|
|
304
302
|
const pinAfter = bumpPinnedRef(pinBefore, pinCfg, '0.8.6', '0.8.7');
|
|
305
|
-
if (!pinAfter.includes('@adia-ai/
|
|
306
|
-
console.error('selftest FAIL: PINNED_REFS did not bump the .mcp.json
|
|
303
|
+
if (!pinAfter.includes('@adia-ai/mcp@0.8.7') || pinAfter.includes('@0.8.6')) {
|
|
304
|
+
console.error('selftest FAIL: PINNED_REFS did not bump the .mcp.json generation-MCP pin'); process.exit(1);
|
|
307
305
|
}
|
|
308
306
|
// Must NOT prefix-match a longer version (0.8.6 inside 0.8.60).
|
|
309
|
-
if (bumpPinnedRef('@adia-ai/
|
|
307
|
+
if (bumpPinnedRef('@adia-ai/mcp@0.8.60', pinCfg, '0.8.6', '0.8.7') !== '@adia-ai/mcp@0.8.60') {
|
|
310
308
|
console.error('selftest FAIL: PINNED_REFS pattern prefix-matched a longer version'); process.exit(1);
|
|
311
309
|
}
|
|
310
|
+
// A retired bridge name must NOT be bumped along — it should fail the later
|
|
311
|
+
// check-lockstep gate loudly, not be silently kept alive by this pass.
|
|
312
|
+
if (bumpPinnedRef('@adia-ai/a2ui-mcp@0.8.6', pinCfg, '0.8.6', '0.8.7') !== '@adia-ai/a2ui-mcp@0.8.6') {
|
|
313
|
+
console.error('selftest FAIL: pin pattern matched a retired generation-MCP name'); process.exit(1);
|
|
314
|
+
}
|
|
312
315
|
|
|
313
316
|
// gh#1198 — the factory README's OWN prose echo of the same pin
|
|
314
|
-
// (`server pinned: @adia-ai/
|
|
315
|
-
// check:plugin-count-claims' "factory README
|
|
316
|
-
// is what caught this drift on the v0.8.35 + v0.8.36 cuts.
|
|
317
|
+
// (`server pinned: @adia-ai/mcp@X`) must move alongside .mcp.json;
|
|
318
|
+
// check:plugin-count-claims' "factory README generation-MCP pin" EQUALITY
|
|
319
|
+
// check is what caught this drift on the v0.8.35 + v0.8.36 cuts.
|
|
317
320
|
if (readmePinCfg.file !== 'README.md') {
|
|
318
321
|
console.error('selftest FAIL: expected the second factory pin config to target README.md'); process.exit(1);
|
|
319
322
|
}
|
|
320
|
-
const readmeBefore = '`
|
|
323
|
+
const readmeBefore = '`adia-gen-ui` server pinned: `@adia-ai/mcp@0.8.6` (tool SoT: `packages/gen-ui/mcp/TOOLS.md`)';
|
|
321
324
|
const readmeAfter = bumpPinnedRef(readmeBefore, readmePinCfg, '0.8.6', '0.8.7');
|
|
322
|
-
if (!readmeAfter.includes('@adia-ai/
|
|
323
|
-
console.error('selftest FAIL: PINNED_REFS did not bump the README
|
|
325
|
+
if (!readmeAfter.includes('@adia-ai/mcp@0.8.7') || readmeAfter.includes('@0.8.6')) {
|
|
326
|
+
console.error('selftest FAIL: PINNED_REFS did not bump the README generation-MCP prose pin'); process.exit(1);
|
|
324
327
|
}
|
|
325
|
-
if (bumpPinnedRef('@adia-ai/
|
|
328
|
+
if (bumpPinnedRef('@adia-ai/mcp@0.8.60', readmePinCfg, '0.8.6', '0.8.7') !== '@adia-ai/mcp@0.8.60') {
|
|
326
329
|
console.error('selftest FAIL: README pin pattern prefix-matched a longer version'); process.exit(1);
|
|
327
330
|
}
|
|
328
331
|
|
|
329
332
|
// web-modules exact peer pins (gh#489) — all three move in one pass; a
|
|
330
333
|
// longer version must not prefix-match.
|
|
331
334
|
const [peerCfg] = PINNED_REFS['packages/web-modules'];
|
|
332
|
-
const peersBefore = '{"peerDependencies":{"@adia-ai/web-components": "0.8.22","@adia-ai/a2ui
|
|
335
|
+
const peersBefore = '{"peerDependencies":{"@adia-ai/web-components": "0.8.22","@adia-ai/a2ui": "0.8.22","@adia-ai/llm": "0.8.22"}}';
|
|
333
336
|
const peersAfter = bumpPinnedRef(peersBefore, peerCfg, '0.8.22', '0.8.23');
|
|
334
337
|
if ((peersAfter.match(/0\.8\.23/g) || []).length !== 3 || peersAfter.includes('0.8.22')) {
|
|
335
338
|
console.error('selftest FAIL: web-modules peer pins did not all move'); process.exit(1);
|
|
@@ -144,7 +144,7 @@ function main() {
|
|
|
144
144
|
function selftest() {
|
|
145
145
|
const tmp = fs.mkdtempSync(path.join(os.tmpdir(), 'insert-stub-selftest-'));
|
|
146
146
|
try {
|
|
147
|
-
const dir = path.join(tmp, 'packages', 'llm');
|
|
147
|
+
const dir = path.join(tmp, 'packages', 'llm', 'core');
|
|
148
148
|
fs.mkdirSync(dir, { recursive: true });
|
|
149
149
|
const clPath = path.join(dir, 'CHANGELOG.md');
|
|
150
150
|
const anchor = '## [0.1.0] — 2026-01-01';
|