@adia-ai/adia-ui-forge 0.8.20 → 0.8.22
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 +20 -0
- package/package.json +1 -1
- package/skills/adia-deploy/SKILL.md +7 -1
- package/skills/adia-release/SKILL.md +1 -1
- package/skills/adia-release/references/cut-procedure.md +2 -1
- package/skills/adia-release/references/gates-catalog.md +1 -1
- package/skills/adia-release/scripts/gate-roster.mjs +6 -1
- package/skills/adia-release/scripts/release-pack.mjs +67 -1
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "adia-forge",
|
|
3
|
-
"version": "0.8.
|
|
3
|
+
"version": "0.8.22",
|
|
4
4
|
"description": "Maintain the adia-ui (@adia-ai) framework itself \u2014 author primitives and shells, run the A2UI generation pipeline and its corpus, review gen-UI quality, sweep QA, cut releases, deploy. The maintainer counterpart to adia-factory (the consumer/app-author plugin).",
|
|
5
5
|
"author": {
|
|
6
6
|
"name": "Kim",
|
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,25 @@
|
|
|
1
1
|
# Changelog — adia-forge
|
|
2
2
|
|
|
3
|
+
## [0.8.22] — 2026-07-29
|
|
4
|
+
|
|
5
|
+
### Fixed
|
|
6
|
+
- **`release-pack.mjs` Step 10 failures name their reason** — `shOk` discarded stderr, so a release-create that failed twice reported "could not be created" with an expired gh token, a network reset, and a bad notes file all indistinguishable. Create calls now pass `{ report: true }` (stderr surfaced, first 3 lines); existence probes stay silent since their failure is the answer.
|
|
7
|
+
- **`release-pack.mjs` Step 10 is idempotent and resumable** — the GH-release loop called `gh release create` unconditionally, so ONE network blip aborted the whole handoff. The v0.8.21 cut hit exactly that: `connection reset by peer` with 4 of 11 releases made, *after* tags were pushed and all 9 packages published — the irreversible half done, the bookkeeping half stranded, and a plain re-run then failing on "release already exists" for the first 4 (repaired by hand). Now: a non-throwing `shOk()` probe skips releases that already exist, one retry absorbs a transient reset, and a genuine failure reports created/skipped/failed counts plus the fact that tags and publishes are unaffected — re-running the same handoff command finishes the job. Verified against the live v0.8.21 releases: 11 detected as existing, 0 would be re-created, and the probe returns false for a bogus tag (no false-positive skips).
|
|
8
|
+
|
|
9
|
+
### Maintenance
|
|
10
|
+
- **`.claude-plugin/plugin.json` version bump** — moves in lockstep with package.json (the `/plugin update` cache key).
|
|
11
|
+
- **`skills/` touched in this release window** (1 file(s), e.g. `scripts/release-pack.mjs`) — carried by the entries above.
|
|
12
|
+
|
|
13
|
+
## [0.8.21] — 2026-07-28
|
|
14
|
+
|
|
15
|
+
### Fixed
|
|
16
|
+
- **Pre-cut gate roster 23 → 24** (`skills/adia-release/scripts/gate-roster.mjs`) — adds `check:brand-assets` (the Adia mark must be token-driven, never a baked `agent-ui-*.svg`; gh#473). `cut-procedure.md` §3.1's transcribed table and the SKILL/gates-catalog counts moved with it, and the cut-hygiene gate renumbered 23 → 24; doc-vs-module equality re-verified programmatically (24/24 in sync, contiguous numbering).
|
|
17
|
+
|
|
18
|
+
- **`release-pack.mjs` stages the root CHANGELOG it promotes** — the gh#453 machinery renamed root `[Unreleased]` → `[X.Y.Z]` at Step 4 but the Step 5 stage roster predated it, so the v0.8.20 cut promoted the heading and shipped without it (main kept `[Unreleased]`; the rename sat uncommitted in the cutter's working tree). `CHANGELOG.md` joins `releaseFiles`; the stranded v0.8.20 rename rides this same PR.
|
|
19
|
+
|
|
20
|
+
### Maintenance
|
|
21
|
+
- **`.claude-plugin/plugin.json` version bump** — moves in lockstep with package.json (the `/plugin update` cache key).
|
|
22
|
+
|
|
3
23
|
## [0.8.20] — 2026-07-28
|
|
4
24
|
|
|
5
25
|
### Maintenance
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@adia-ai/adia-ui-forge",
|
|
3
|
-
"version": "0.8.
|
|
3
|
+
"version": "0.8.22",
|
|
4
4
|
"description": "Maintain the adia-ui (@adia-ai) framework itself \u2014 author primitives and shells, run the A2UI generation pipeline and its corpus, review gen-UI quality, sweep QA, cut releases, deploy. The maintainer counterpart to adia-factory (the consumer/app-author plugin).",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"adia-ui",
|
|
@@ -95,7 +95,13 @@ delete-adjudication classes.
|
|
|
95
95
|
prod-only runtime-written files (feedback logs wiped 2026-06-10).
|
|
96
96
|
3. Snapshot prod: `cp -al /srv/<app>/dist /srv/<app>/dist.bak-<date>`
|
|
97
97
|
(hardlink farm — instant, and the only rollback).
|
|
98
|
-
4. Real rsync — the dry-run minus `-n`, SAME excludes
|
|
98
|
+
4. Real rsync — the dry-run minus `-n`, SAME excludes, and the SAME BYTES:
|
|
99
|
+
both jobs rsync the artifact-round-tripped tree, and the deploy job aborts
|
|
100
|
+
if its tree's sha256 fingerprint differs from the one whose delete summary
|
|
101
|
+
was approved (gh#425 — the dry-run used to read the build job's own
|
|
102
|
+
`dist/`, so the v0.8.14 summary listed 3,128 deletions the real send never
|
|
103
|
+
performed; an over-reporting summary trains reviewers to approve past scary
|
|
104
|
+
numbers, and the same gap can under-report).
|
|
99
105
|
5. Verify a fixture **file** that only exists in the new build, then
|
|
100
106
|
render-check a `/site/components/*` page headlessly (SPA returns 200 shell
|
|
101
107
|
for any route; file presence alone misses the llm-404 class).
|
|
@@ -93,7 +93,7 @@ assumed pass, or "published" without the actual `npm view` output.
|
|
|
93
93
|
|
|
94
94
|
## Mechanization (bundled `scripts/`, stdlib Node, all support `--dry`)
|
|
95
95
|
|
|
96
|
-
`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 of the 11 packages 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
|
|
96
|
+
`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 of the 11 packages 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 24-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.
|
|
97
97
|
|
|
98
98
|
The pieces are callable alone: `bump.mjs` (version fields + the factory `.mcp.json` a2ui-mcp pin, invariant 8), `promote-unreleased.mjs` / `insert-stub.mjs` (CHANGELOG blocks), `tag-lockstep.mjs` (12 tags, `--delete` to move), `dispatch-publish.mjs` (publish workflows; `--verify-triggered` re-dispatches only missing runs; `--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.
|
|
99
99
|
|
|
@@ -111,7 +111,8 @@ npm run verify:site-a2ui # 19 site-a2ui rows vs source fra
|
|
|
111
111
|
npm run verify:contrast # 20 WCAG AA — canvas-text AND text-on-fill
|
|
112
112
|
npm run check:token-semantics-sync # 21 adia-tokens generated refs vs token sources
|
|
113
113
|
npm run check:demo-routes # 22 demo surfaces routed + patterns indexed
|
|
114
|
-
|
|
114
|
+
npm run check:brand-assets # 23 brand mark token-driven, not baked raster
|
|
115
|
+
node scripts/release/check-cut-hygiene.mjs --version <mode-dependent> # 24 README CDN-pin + version currency — CUT modes pre-flight at the PREVIOUS version (the README claim is exact-match and only moves at the Step-4 bump; Step 4g re-proves at the cut version), HANDOFF pre-flights at the CUT version (post-merge, the claim already moved)
|
|
115
116
|
```
|
|
116
117
|
|
|
117
118
|
Any red → route via [`gates-catalog.md`](gates-catalog.md); fix at the source, re-run the narrowest gate, then re-run the full sequence. The canonical miss: a cut that ran 7 of the gates shipped a stale-embeddings defect that surfaced a day later and cost a tag-move recovery.
|
|
@@ -202,7 +202,7 @@ npm run check:demo-shells
|
|
|
202
202
|
|
|
203
203
|
Add `verify:corpus` + `check:embeddings-fresh` if chunks were touched; `check:lightningcss-build` if CSS was touched; F-N1 if unpushed release tags exist.
|
|
204
204
|
|
|
205
|
-
**Full pre-cut sweep** — the
|
|
205
|
+
**Full pre-cut sweep** — the 24-gate roster in [`cut-procedure.md`](cut-procedure.md) §Step 3, sourced from `` `${CLAUDE_PLUGIN_ROOT}/skills/adia-release/scripts/gate-roster.mjs` `` (the ONE list; `release-pack.mjs` imports and runs it in full — a subset run is impossible without editing that file). ~90s wall time.
|
|
206
206
|
|
|
207
207
|
**Omnibus** — `npm run check` invokes everything. Heavy; use when re-baselining a stale checkout.
|
|
208
208
|
|
|
@@ -54,11 +54,16 @@ export const GATE_ROSTER = [
|
|
|
54
54
|
// components/modules with .examples.html need a /site/components route,
|
|
55
55
|
// catalog patterns need their Pattern Library sitemap entry.
|
|
56
56
|
{ n: 22, cmd: 'npm run check:demo-routes', what: 'demo surfaces routed + patterns indexed' },
|
|
57
|
+
// gh#473: the brand mark must be token-driven (<adia-mark-ui>), never a
|
|
58
|
+
// baked agent-ui-*.svg — a light-only raster cannot invert for dark mode,
|
|
59
|
+
// and 54 authored files (mostly harvested *.contents.html) had been
|
|
60
|
+
// teaching the anti-pattern to the generative corpus.
|
|
61
|
+
{ n: 23, cmd: 'npm run check:brand-assets', what: 'brand mark token-driven, not baked raster' },
|
|
57
62
|
// versionArg: the runner appends ` --version X.Y.Z` (release-pack knows the
|
|
58
63
|
// cut version; the roster stays a static list). Objective half of the
|
|
59
64
|
// v0.7.13-retro hygiene checker — README CDN pins / "Current version"
|
|
60
65
|
// claims vs the cut version; branch/worktree limbo prints as warns (H2).
|
|
61
|
-
{ n:
|
|
66
|
+
{ n: 24, cmd: 'node scripts/release/check-cut-hygiene.mjs', what: 'README CDN-pin + version currency', versionArg: true },
|
|
62
67
|
];
|
|
63
68
|
|
|
64
69
|
// -- CLI ------------------------------------------------------------------
|
|
@@ -226,6 +226,28 @@ function shQuiet(cmd, args) {
|
|
|
226
226
|
return execSync(cmd, { cwd: REPO, encoding: 'utf8' });
|
|
227
227
|
}
|
|
228
228
|
|
|
229
|
+
/** Run a command for its EXIT STATUS only — true on 0, false on anything
|
|
230
|
+
* else, never throws and never streams. For probes and retryable steps
|
|
231
|
+
* where a non-zero exit is an expected answer, not a crash (Step 10's
|
|
232
|
+
* "does this release already exist?" and its one transient retry).
|
|
233
|
+
* Pass { report: true } for the CREATE calls: stderr is then captured and
|
|
234
|
+
* printed on failure, so "could not be created" names its reason — an
|
|
235
|
+
* expired gh token, a network reset, and a bad notes file were previously
|
|
236
|
+
* indistinguishable (reviewer note, 2026-07-29). Probes stay silent:
|
|
237
|
+
* their failure IS the answer. */
|
|
238
|
+
function shOk(cmd, { report = false } = {}) {
|
|
239
|
+
try {
|
|
240
|
+
execSync(cmd, { cwd: REPO, encoding: 'utf8', stdio: ['ignore', 'ignore', 'pipe'] });
|
|
241
|
+
return true;
|
|
242
|
+
} catch (e) {
|
|
243
|
+
if (report) {
|
|
244
|
+
const err = (e.stderr || e.message || '').toString().trim().split('\n').slice(0, 3).join('\n ');
|
|
245
|
+
if (err) console.error(` stderr: ${err}`);
|
|
246
|
+
}
|
|
247
|
+
return false;
|
|
248
|
+
}
|
|
249
|
+
}
|
|
250
|
+
|
|
229
251
|
// Runs a command and CAPTURES its combined output instead of streaming it —
|
|
230
252
|
// used where the output itself becomes evidence in a later checkpoint's
|
|
231
253
|
// evidence block (H5), rather than just scrolling past in the terminal.
|
|
@@ -453,6 +475,12 @@ function step5Commit(args) {
|
|
|
453
475
|
// (REPO_PINNED_REFS); gate 18 (check-cut-hygiene doc-currency) exact-matches
|
|
454
476
|
// it against the cut version, so it must ride the release commit.
|
|
455
477
|
'README.md',
|
|
478
|
+
// Root CHANGELOG — the gh#453 promotion machinery renames its
|
|
479
|
+
// [Unreleased] heading at Step 4, but this roster predated it, so the
|
|
480
|
+
// v0.8.20 cut promoted the heading and then shipped WITHOUT it (the
|
|
481
|
+
// rename sat uncommitted in the cutter's working tree while main kept
|
|
482
|
+
// [Unreleased]). Promotion and staging must travel together.
|
|
483
|
+
'CHANGELOG.md',
|
|
456
484
|
// gh#399: Step 4e generates this but never staged it before — it landed
|
|
457
485
|
// in a second PR after the release commit instead (v0.8.11 cut).
|
|
458
486
|
`docs/releases/v${args.version}.md`,
|
|
@@ -654,9 +682,47 @@ async function step10GhAndSite(args) {
|
|
|
654
682
|
console.error(`ERROR: GH notes file not found: ${args.ghNotesFile}`);
|
|
655
683
|
process.exit(2);
|
|
656
684
|
}
|
|
685
|
+
// Idempotent + resumable (v0.8.21 incident): this loop used to `gh release
|
|
686
|
+
// create` unconditionally, so ONE network blip aborted the whole handoff —
|
|
687
|
+
// that cut died on `connection reset by peer` with 4 of 11 releases made,
|
|
688
|
+
// after tags were pushed and all 9 packages were already published. The
|
|
689
|
+
// irreversible half of the release had happened; only the bookkeeping half
|
|
690
|
+
// was half-done, and a plain re-run then failed on "release already exists"
|
|
691
|
+
// for the first 4. So: skip what exists, create what doesn't, retry a
|
|
692
|
+
// transient failure, and report what remains instead of throwing away the
|
|
693
|
+
// work that succeeded. Re-running Step 10 after ANY partial failure is now
|
|
694
|
+
// safe and finishes the job.
|
|
695
|
+
const created = [];
|
|
696
|
+
const skipped = [];
|
|
697
|
+
const failed = [];
|
|
657
698
|
for (const pkg of PACKAGES) {
|
|
658
|
-
|
|
699
|
+
const tag = `${pkg}-v${args.version}`;
|
|
700
|
+
if (!args.dry && shOk(`gh release view "${tag}"`)) {
|
|
701
|
+
skipped.push(pkg);
|
|
702
|
+
console.log(` = ${tag} — already exists, skipping`);
|
|
703
|
+
continue;
|
|
704
|
+
}
|
|
705
|
+
const cmd = `gh release create "${tag}" --title "${args.scope}/${pkg} v${args.version}" --notes-file ${args.ghNotesFile}`;
|
|
706
|
+
// One retry: the observed failure mode is a transient TLS/connection
|
|
707
|
+
// reset against api.github.com, not a bad request.
|
|
708
|
+
let ok = args.dry ? (sh(cmd, args), true) : shOk(cmd, { report: true });
|
|
709
|
+
if (!ok && !args.dry) {
|
|
710
|
+
console.log(` … ${tag} failed once (transient?) — retrying in 3s`);
|
|
711
|
+
sh('sleep 3', args);
|
|
712
|
+
ok = shOk(cmd, { report: true });
|
|
713
|
+
}
|
|
714
|
+
(ok ? created : failed).push(pkg);
|
|
715
|
+
if (ok) console.log(` ✓ ${tag}`);
|
|
716
|
+
}
|
|
717
|
+
if (failed.length > 0) {
|
|
718
|
+
console.error(`\nERROR: ${failed.length}/${PACKAGES.length} GH release(s) could not be created: ${failed.join(', ')}`);
|
|
719
|
+
console.error(` ${created.length} created, ${skipped.length} already existed.`);
|
|
720
|
+
console.error(' Tags and npm publishes are DONE and unaffected — only the GH-release');
|
|
721
|
+
console.error(' bookkeeping is incomplete. Re-run this same handoff command: the loop');
|
|
722
|
+
console.error(' skips what exists and creates only the remainder.');
|
|
723
|
+
process.exit(1);
|
|
659
724
|
}
|
|
725
|
+
console.log(` ✓ GH releases: ${created.length} created, ${skipped.length} already present (${PACKAGES.length} total)`);
|
|
660
726
|
if (args.skipSite) {
|
|
661
727
|
console.log(' --skip-site set; skipping EXE deploy');
|
|
662
728
|
return;
|