@adia-ai/adia-ui-forge 0.1.2 → 0.8.0
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 +3 -6
- package/CHANGELOG.md +27 -26
- package/README.md +35 -40
- package/agents/a2ui-engineer.md +26 -0
- package/agents/component-author.md +29 -0
- package/agents/framework-verifier.md +26 -0
- package/agents/release-engineer.md +25 -0
- package/agents/routing-corpus.json +318 -0
- package/bin/demo-postwrite-pattern-gate +94 -0
- package/bin/forge-lint +17 -2
- package/bin/sidecar-prewrite-guard +104 -0
- package/commands/deploy.md +9 -0
- package/commands/dogfood.md +10 -0
- package/commands/gen-review.md +9 -0
- package/commands/release.md +10 -0
- package/hooks/hooks.json +15 -0
- package/package.json +3 -5
- package/references/contracts/a2ui-mcp-surface.md +35 -0
- package/references/contracts/migration-guide-format.md +34 -0
- package/references/shared/content-trust.md +19 -74
- package/skills/adia-a2ui/SKILL.md +99 -0
- package/skills/{adia-ui-a2ui → adia-a2ui}/evals/routing-corpus.json +10 -10
- package/skills/adia-a2ui/references/anti-patterns.md +27 -0
- package/skills/adia-a2ui/references/chunk-authoring.md +71 -0
- package/skills/adia-a2ui/references/corpus-discipline.md +68 -0
- package/skills/adia-a2ui/references/eval-diagnostics.md +86 -0
- package/skills/adia-a2ui/references/format-extension-decisions.md +66 -0
- package/skills/adia-a2ui/references/leverage-rules.md +52 -0
- package/skills/adia-a2ui/references/mcp-pipeline-ops.md +83 -0
- package/skills/adia-a2ui/references/mcp-tool-reference.md +59 -0
- package/skills/adia-a2ui/references/pipeline-overview.md +115 -0
- package/skills/adia-a2ui/references/semantic-fail-lifting.md +74 -0
- package/skills/adia-a2ui/references/strategy-engines.md +109 -0
- package/skills/adia-a2ui/references/zettel-calibration.md +104 -0
- package/skills/adia-author/SKILL.md +112 -0
- package/skills/adia-author/evals/routing-corpus.json +222 -0
- package/skills/{adia-ui-authoring → adia-author}/references/anti-patterns.md +33 -4
- package/skills/{adia-ui-authoring → adia-author}/references/authoring-cycle.md +9 -11
- package/skills/adia-author/references/canonical-pattern-index.md +243 -0
- package/skills/{adia-ui-authoring → adia-author}/references/code-style.md +19 -21
- package/skills/adia-author/references/common-gotchas.md +129 -0
- package/skills/adia-author/references/composite-demo-protocol.md +271 -0
- package/skills/{adia-ui-authoring → adia-author}/references/css-patterns.md +19 -6
- package/skills/{adia-ui-authoring → adia-author}/references/lifecycle-patterns.md +1 -0
- package/skills/{adia-ui-authoring → adia-author}/references/llm-bridge.md +3 -5
- package/skills/{adia-ui-authoring → adia-author}/references/module-promotion.md +22 -40
- package/skills/{adia-ui-authoring → adia-author}/references/primitive-audit.md +2 -4
- package/skills/{adia-ui-authoring → adia-author}/references/shell-patterns.md +12 -18
- package/skills/{adia-ui-authoring → adia-author}/references/token-contract.md +5 -7
- package/skills/{adia-ui-authoring → adia-author}/references/worked-example.md +3 -3
- package/skills/{adia-ui-authoring → adia-author}/references/yaml-contract.md +3 -3
- package/skills/{adia-ui-authoring → adia-author}/scripts/build-canonical-pattern-index.mjs +3 -3
- package/skills/adia-deploy/SKILL.md +128 -0
- package/skills/adia-deploy/references/deploy-playbooks.md +276 -0
- package/skills/adia-dogfood/SKILL.md +124 -0
- package/skills/adia-dogfood/references/admin-shell-anatomy.md +77 -0
- package/skills/adia-dogfood/references/app-shell-pitfalls.md +66 -0
- package/skills/adia-dogfood/references/card-anatomy-sweep.md +66 -0
- package/skills/adia-dogfood/references/html-attr-sweep.md +63 -0
- package/skills/adia-dogfood/references/native-leak-annotations.md +73 -0
- package/skills/adia-dogfood/references/visual-probe-triage.md +80 -0
- package/skills/{adia-ui-dogfood → adia-dogfood}/scripts/analyze.mjs +30 -14
- package/skills/adia-gen-review/SKILL.md +127 -0
- package/skills/adia-gen-review/references/corpus-html-patterns.md +279 -0
- package/skills/adia-gen-review/references/loop-protocol.md +216 -0
- package/skills/adia-gen-review/references/rubric-cosmetic.md +100 -0
- package/skills/adia-gen-review/references/rubric-decompose.md +101 -0
- package/skills/adia-gen-review/references/rubric-score.md +214 -0
- package/skills/{adia-ui-gen-review → adia-gen-review}/references/scores.schema.json +2 -2
- package/skills/{adia-ui-gen-review → adia-gen-review}/scripts/gen-review-coverage-audit.mjs +4 -4
- package/skills/{adia-ui-gen-review → adia-gen-review}/scripts/gen-review-decompose.mjs +10 -6
- package/skills/{adia-ui-gen-review → adia-gen-review}/scripts/gen-review-status.mjs +5 -5
- package/skills/{adia-ui-gen-review → adia-gen-review}/scripts/validate-cycle-scores.mjs +5 -5
- package/skills/adia-llm-internals/SKILL.md +77 -0
- package/skills/{adia-ui-llm → adia-llm-internals}/references/adapter-contract.md +4 -2
- package/skills/{adia-ui-llm → adia-llm-internals}/references/add-a-provider.md +4 -5
- package/skills/{adia-ui-llm → adia-llm-internals}/references/bridge-facade.md +10 -3
- package/skills/{adia-ui-llm → adia-llm-internals}/references/browser-proxy-boundary.md +1 -1
- package/skills/{adia-ui-llm → adia-llm-internals}/references/model-registry.md +5 -3
- package/skills/{adia-ui-llm → adia-llm-internals}/references/streaming-sse.md +2 -2
- package/skills/adia-release/SKILL.md +72 -0
- package/skills/adia-release/references/changelog-discipline.md +119 -0
- package/skills/adia-release/references/cut-procedure.md +247 -0
- package/skills/adia-release/references/gates-catalog.md +222 -0
- package/skills/adia-release/references/independent-package-release.md +52 -0
- package/skills/adia-release/references/migration-guide-authoring.md +86 -0
- package/skills/adia-release/references/notes-authoring.md +90 -0
- package/skills/adia-release/references/recovery-paths.md +106 -0
- package/skills/{adia-ui-release → adia-release}/scripts/bump.mjs +27 -2
- package/skills/{adia-ui-release → adia-release}/scripts/dispatch-publish.mjs +72 -6
- package/skills/{adia-ui-release → adia-release}/scripts/insert-stub.mjs +6 -4
- package/skills/adia-release/scripts/package-paths.mjs +50 -0
- package/skills/{adia-ui-release → adia-release}/scripts/promote-unreleased.mjs +4 -3
- package/skills/{adia-ui-release → adia-release}/scripts/release-pack.mjs +48 -27
- package/skills/{adia-ui-release → adia-release}/scripts/tag-lockstep.mjs +15 -3
- package/skills/adia-site-docs/SKILL.md +68 -0
- package/skills/adia-site-docs/evals/audit-report.md +30 -0
- package/skills/adia-site-docs/evals/routing-corpus.json +176 -0
- package/skills/adia-site-docs/intent.md +72 -0
- package/bin/lib/audit-axes.mjs +0 -555
- package/bin/lib/dry-run-irreversible.mjs +0 -236
- package/bin/lib/run-skill-evals.mjs +0 -487
- package/bin/lib/teach-router.mjs +0 -250
- package/commands/adia-forge-a2ui.md +0 -10
- package/commands/adia-forge-author.md +0 -10
- package/commands/adia-forge-dogfood.md +0 -8
- package/commands/adia-forge-llm.md +0 -8
- package/commands/adia-forge-orient.md +0 -10
- package/commands/adia-forge-release.md +0 -8
- package/commands/adia-forge-review.md +0 -10
- package/references/shared/pev-rationale.md +0 -64
- package/references/shared/skill-conventions.md +0 -133
- package/skills/adia-ui-a2ui/CHANGELOG.md +0 -32
- package/skills/adia-ui-a2ui/SKILL.md +0 -243
- package/skills/adia-ui-a2ui/evals/adversarial-corpus.json +0 -75
- package/skills/adia-ui-a2ui/evals/teach-routing-cases.json +0 -100
- package/skills/adia-ui-a2ui/references/anti-patterns.md +0 -24
- package/skills/adia-ui-a2ui/references/chunk-authoring.md +0 -88
- package/skills/adia-ui-a2ui/references/corpus-discipline.md +0 -56
- package/skills/adia-ui-a2ui/references/eval-diagnostics.md +0 -127
- package/skills/adia-ui-a2ui/references/fragment-graph.md +0 -91
- package/skills/adia-ui-a2ui/references/mcp-pipeline-ops.md +0 -106
- package/skills/adia-ui-a2ui/references/mcp-tool-reference.md +0 -398
- package/skills/adia-ui-a2ui/references/pipeline-overview.md +0 -175
- package/skills/adia-ui-a2ui/references/semantic-fail-lifting.md +0 -120
- package/skills/adia-ui-a2ui/references/strategy-engines.md +0 -111
- package/skills/adia-ui-a2ui/references/teach-protocol.md +0 -220
- package/skills/adia-ui-a2ui/references/zettel-calibration.md +0 -93
- package/skills/adia-ui-a2ui/scripts/audit-a2ui-roster.mjs +0 -96
- package/skills/adia-ui-a2ui/scripts/teach-route.mjs +0 -157
- package/skills/adia-ui-a2ui/skill.json +0 -38
- package/skills/adia-ui-authoring/CHANGELOG.md +0 -32
- package/skills/adia-ui-authoring/SKILL.md +0 -256
- package/skills/adia-ui-authoring/assets/case-studies/admin-shell-decomposition.md +0 -101
- package/skills/adia-ui-authoring/assets/case-studies/maxtokens-32768-discovery.md +0 -109
- package/skills/adia-ui-authoring/assets/case-studies/theme-panel-promotion.md +0 -113
- package/skills/adia-ui-authoring/evals/adversarial-design-plan-gates.json +0 -138
- package/skills/adia-ui-authoring/evals/routing-corpus.json +0 -245
- package/skills/adia-ui-authoring/references/canonical-pattern-index.md +0 -179
- package/skills/adia-ui-authoring/references/common-gotchas.md +0 -93
- package/skills/adia-ui-authoring/references/composite-demo-protocol.md +0 -1084
- package/skills/adia-ui-authoring/references/teach-protocol.md +0 -428
- package/skills/adia-ui-authoring/scripts/audit-authoring-roster.mjs +0 -148
- package/skills/adia-ui-authoring/skill.json +0 -45
- package/skills/adia-ui-dogfood/CHANGELOG.md +0 -17
- package/skills/adia-ui-dogfood/README.md +0 -62
- package/skills/adia-ui-dogfood/SKILL.md +0 -866
- package/skills/adia-ui-dogfood/skill.json +0 -40
- package/skills/adia-ui-forge/SKILL.md +0 -88
- package/skills/adia-ui-forge/evals/routing-corpus.json +0 -30
- package/skills/adia-ui-gen-review/CHANGELOG.md +0 -108
- package/skills/adia-ui-gen-review/SKILL.md +0 -266
- package/skills/adia-ui-gen-review/references/loop-protocol.md +0 -712
- package/skills/adia-ui-gen-review/references/rubric-cosmetic.md +0 -144
- package/skills/adia-ui-gen-review/references/rubric-decompose.md +0 -117
- package/skills/adia-ui-gen-review/references/rubric-score.md +0 -249
- package/skills/adia-ui-gen-review/references/teach-protocol.md +0 -214
- package/skills/adia-ui-gen-review/skill.json +0 -22
- package/skills/adia-ui-llm/CHANGELOG.md +0 -25
- package/skills/adia-ui-llm/SKILL.md +0 -165
- package/skills/adia-ui-llm/evals/adversarial-corpus.json +0 -75
- package/skills/adia-ui-llm/evals/routing-corpus.json +0 -30
- package/skills/adia-ui-llm/evals/teach-routing-cases.json +0 -73
- package/skills/adia-ui-llm/references/teach-protocol.md +0 -78
- package/skills/adia-ui-llm/scripts/audit-llm-roster.mjs +0 -93
- package/skills/adia-ui-llm/scripts/teach-route.mjs +0 -119
- package/skills/adia-ui-llm/skill.json +0 -33
- package/skills/adia-ui-release/CHANGELOG.md +0 -23
- package/skills/adia-ui-release/SKILL.md +0 -295
- package/skills/adia-ui-release/assets/case-studies/2026-05-20-batch-push-v0.6.14-v0.6.15.md +0 -144
- package/skills/adia-ui-release/assets/case-studies/2026-05-20-corpus-drift-remediation-v0.6.15.md +0 -155
- package/skills/adia-ui-release/assets/case-studies/2026-05-20-version-skip-correction-v0.6.12.md +0 -114
- package/skills/adia-ui-release/assets/case-studies/2026-05-21-author-from-scratch-v0.6.18.md +0 -139
- package/skills/adia-ui-release/assets/case-studies/2026-05-21-feedback37-retraction-v0.6.21.md +0 -124
- package/skills/adia-ui-release/assets/case-studies/2026-05-21-fn1-enrichment-pass-v0.6.19.md +0 -125
- package/skills/adia-ui-release/assets/case-studies/2026-05-21-stale-test-detection-v0.6.20.md +0 -142
- package/skills/adia-ui-release/assets/case-studies/2026-05-23-freshness-gate-recovery-v0.6.32.md +0 -97
- package/skills/adia-ui-release/assets/case-studies/2026-05-26-catalog-drift-recurring-v0.6.40.md +0 -147
- package/skills/adia-ui-release/assets/templates/stub-changelog.template.md +0 -22
- package/skills/adia-ui-release/evals/evals.json +0 -164
- package/skills/adia-ui-release/references/changelog-discipline.md +0 -250
- package/skills/adia-ui-release/references/cycle-happy-path.md +0 -520
- package/skills/adia-ui-release/references/exe-deploy.md +0 -149
- package/skills/adia-ui-release/references/gates-catalog.md +0 -778
- package/skills/adia-ui-release/references/ledger-discipline.md +0 -232
- package/skills/adia-ui-release/references/migration-guide-authoring.md +0 -174
- package/skills/adia-ui-release/references/multi-agent-baseline.md +0 -207
- package/skills/adia-ui-release/references/notes-authoring.md +0 -212
- package/skills/adia-ui-release/references/recovery-paths.md +0 -215
- package/skills/adia-ui-release/references/rollup-notes.md +0 -208
- package/skills/adia-ui-release/references/teach-protocol.md +0 -468
- package/skills/adia-ui-release/scripts/audit-gate-roster.mjs +0 -196
- package/skills/adia-ui-release/scripts/make-ledger.mjs +0 -179
- package/skills/adia-ui-release/skill.json +0 -75
- /package/skills/{adia-ui-authoring → adia-author}/references/api-contract.md +0 -0
- /package/skills/{adia-ui-release → adia-release}/scripts/assert-monorepo-root.mjs +0 -0
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
# `notes-authoring.md` — release notes: GH body · Slack post · multi-version rollup
|
|
2
|
+
|
|
3
|
+
> Load for the end-of-cycle notes step or a notes-only request. The GH release
|
|
4
|
+
> body attached to each per-package tag is the **durable record**; drafts live in
|
|
5
|
+
> the session scratch dir and the operator copy-pastes — the skill never posts to
|
|
6
|
+
> Slack directly.
|
|
7
|
+
|
|
8
|
+
## §Author from the diff, not the intent
|
|
9
|
+
|
|
10
|
+
Draft every note from `git diff <prev-tag>..HEAD` — what actually shipped — never from an ADR's intent or a PR's plan. The first two commands of any draft:
|
|
11
|
+
|
|
12
|
+
```bash
|
|
13
|
+
git log --oneline <prev-tag>..HEAD
|
|
14
|
+
git diff --stat <prev-tag>..HEAD
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
If the diff contradicts the plan (a feature deferred, a refactor split across cuts), the notes follow the diff. This is a discipline because the inverse shipped a real defect: notes copied from an ADR once claimed features that were never staged into the cut. F-N1 catches *undocumented diff*, not *over-claimed notes* — that guard is the author's.
|
|
18
|
+
|
|
19
|
+
## §The GH release body (single version, ~80–200 lines)
|
|
20
|
+
|
|
21
|
+
All 9 packages get the same body (`gh release create <pkg>-vX.Y.Z --notes-file …`).
|
|
22
|
+
|
|
23
|
+
```markdown
|
|
24
|
+
## vX.Y.Z — <one-line tagline>
|
|
25
|
+
|
|
26
|
+
9-package lockstep **PATCH** cut. <One sentence on scope.>
|
|
27
|
+
|
|
28
|
+
### `@adia-ai/<substantive-pkg>`
|
|
29
|
+
- **<Bold-prefix headline>.** <Why → what → inline file paths.> Closes <FEEDBACK-NN>.
|
|
30
|
+
|
|
31
|
+
### Ride-along stubs
|
|
32
|
+
`@adia-ai/<pkg1>`, `@adia-ai/<pkg2>`, … — version bump only.
|
|
33
|
+
|
|
34
|
+
### Verification
|
|
35
|
+
- `check:lockstep` OK at `X.Y.Z / ^X.Y.0`
|
|
36
|
+
- **N/N vitest** · typecheck clean · `components --verify` clean · `verify:traits` 100%
|
|
37
|
+
- `check:demo-shells` · `check:lightningcss-build` · `verify:corpus` 0/0 · `check:embeddings-fresh` OK
|
|
38
|
+
- `smoke:engines` · `smoke:register-engine` 11/11 · `eval:diff zettel` cov=N% avg=N · `check:links` clean
|
|
39
|
+
|
|
40
|
+
### Install
|
|
41
|
+
npm i @adia-ai/web-components@X.Y.Z @adia-ai/web-modules@X.Y.Z
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
Shape rules: open with the tagline, no preamble; group by `### @adia-ai/<pkg>`; bold-prefix every bullet then why → what → files; cite tickets by ID; before/after fenced blocks for consumer-facing markup changes; paste the verification block from the actual pre-flight output (the cycle-to-cycle repetition is a feature); a breaking cut adds a `⚠️` paragraph linking its MIGRATION GUIDE section. Anti-patterns: marketing language, vague verbs, missing file paths.
|
|
45
|
+
|
|
46
|
+
## §The Slack post (~40–80 lines)
|
|
47
|
+
|
|
48
|
+
```markdown
|
|
49
|
+
🚀 **AdiaUI vX.Y.Z** is out — <tagline>
|
|
50
|
+
|
|
51
|
+
npm i @adia-ai/web-components@X.Y.Z @adia-ai/web-modules@X.Y.Z
|
|
52
|
+
|
|
53
|
+
9-package lockstep PATCH cut. <One sentence.>
|
|
54
|
+
|
|
55
|
+
## 🔷 `@adia-ai/<pkg>` — <headline>
|
|
56
|
+
<2–4 sentences.> Closes <FEEDBACK-NN>.
|
|
57
|
+
|
|
58
|
+
## ✅ Verification
|
|
59
|
+
<one line>
|
|
60
|
+
|
|
61
|
+
## 📚 Links
|
|
62
|
+
- GH Releases: https://github.com/adiahealth/gen-ui-kit/releases (filter `vX.Y.Z`)
|
|
63
|
+
- Live demos: https://ui-kit.exe.xyz/site/playground/gen-ui
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
- **Install matrix is mandatory, npm + CDN, both packages**: npm always names `web-components` AND `web-modules`; the CDN block pins the `@0.X` minor range — `web-components@0.X/dist/web-components.min.{css,js}` plus `web-modules@0.X/dist/everything.min.js` as the all-in-one `<script>`.
|
|
67
|
+
- Section emojis: 🔷 feature · 🛠️ DX fix · 🎨 visual · 🧹 cleanup · ⚠️ breaking/behavior · ✅ verification · 📚 links.
|
|
68
|
+
- Slack renders standard markdown (fenced blocks, `-` bullets, `[text](URL)`); no legacy mrkdwn needed.
|
|
69
|
+
- **Every `https://ui-kit.exe.xyz/site/<route>` URL must be verified against `site/sitemap.json` first** — the docs site is an SPA; an unmatched route returns 200 and renders blank, so curl proves nothing. The Gen UI Canvas is `/site/playground/gen-ui`; there is no `/site/gen-ui/`.
|
|
70
|
+
|
|
71
|
+
Save drafts to the session scratch dir (e.g. `<scratch>/release-vX.Y.Z/notes.md`); strip nothing for Slack, and the GH body is the same content without the rocket header.
|
|
72
|
+
|
|
73
|
+
## §Rollup — multi-version retrospective (≥2 versions since the last broadcast)
|
|
74
|
+
|
|
75
|
+
Audience: consumers or teammates catching up on a window (vA.B.C → vX.Y.Z). Five-section skeleton:
|
|
76
|
+
|
|
77
|
+
1. **Header** — `🚀 AdiaUI vA.B.C → vX.Y.Z — <tagline>` + install snippet + 2–4 sentences on the window (releases count, what held across all of them, e.g. "internal deps held at ^0.X.0 throughout").
|
|
78
|
+
2. **🧵 Framing section — pick ONE:**
|
|
79
|
+
- **A. The arcs** — 2–4 thematic strands, each naming its contributing versions. Best mid-cycle with no dominant theme.
|
|
80
|
+
- **B. The headline event** — one milestone (graduation, ADR ratification) with the package cuts as substrate. Best for milestone windows.
|
|
81
|
+
- **C. Net deltas** — what consumers see differently end-to-end: new primitives / new APIs / breaking-ish / retired, as a bullet list. Best when the window includes a MINOR or a consumer is jumping a big gap.
|
|
82
|
+
3. **📦 Per-version breakdown** — one block per version: `### vN.M.X — <tagline>` + 3–5 bold-prefix bullets if substantive, 1–2 if small, a single sentence for stub-only versions. **Skip ride-along stubs entirely** — naming 6 no-change packages per version is noise.
|
|
83
|
+
4. **⚠️ Behavior-changes table** (only if the window has ≥2): `| Version | Change | Opt-out / migration |`.
|
|
84
|
+
5. **✅ Verification baseline** — one paragraph, not the full table: test-count growth across the window, gate roster held, eval floors held, F-N1 clean at every cut. Show the *growth* — it's the window's velocity signal. Close with one paragraph naming what the window accomplished, echoing the framing.
|
|
85
|
+
|
|
86
|
+
Save to `<scratch>/release-vA.B.C-vX.Y.Z/rollup.md`; announcement-grade rollups (milestone, MINOR) can also land as a GH "milestone" release body — operator's call.
|
|
87
|
+
|
|
88
|
+
## §What NOT to put in notes
|
|
89
|
+
|
|
90
|
+
Internal ticket fields; implementation details with no consumer effect; "coming soon" futures; jokes — notes are a permanent artifact attached to a tag.
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
# `recovery-paths.md` — the 8 recovery scenarios
|
|
2
|
+
|
|
3
|
+
> Load on any F-N1 / pre-flight failure, for a batch push, or for post-release
|
|
4
|
+
> recovery. Each scenario: the **shape** (what the repo state looks like), the
|
|
5
|
+
> **resolution** (commands + judgment calls), and what to record. Every scenario
|
|
6
|
+
> is grounded in a real past incident; the durable record of a recovery is the
|
|
7
|
+
> fix commit's message + the PR description — write the "what happened / root
|
|
8
|
+
> cause / fix" there.
|
|
9
|
+
|
|
10
|
+
---
|
|
11
|
+
|
|
12
|
+
## §Scenario 1 — Version-skip correction
|
|
13
|
+
|
|
14
|
+
**Shape:** a peer's release commit mislabels the version — package.json bumped 0.6.X → 0.6.X+2, skipping X+1; the CHANGELOG body may narrate the work as two releases. No tags yet, npm latest still 0.6.X, commit unpushed. (Real case: a "v0.6.13" cut that was actually v0.6.12's work.)
|
|
15
|
+
|
|
16
|
+
**Resolution:**
|
|
17
|
+
|
|
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
|
+
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: 9 × package.json, 9 × CHANGELOG (headers + body refs), any doc/CSS-comment refs, then regenerate the lockfile. Preserve filename references that intentionally encode the original label.
|
|
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
|
+
|
|
23
|
+
## §Scenario 2 — Batch push
|
|
24
|
+
|
|
25
|
+
**Shape:** multiple unpushed `release(*): vX.Y.Z` commits since the last published tag; operator asks to "publish what's accumulated."
|
|
26
|
+
|
|
27
|
+
**Resolution:**
|
|
28
|
+
|
|
29
|
+
1. Order the release commits oldest → newest.
|
|
30
|
+
2. Per version: **tag at that version's release-commit SHA** (the batch-push exception to tag-at-HEAD), run F-N1 against each tag candidate.
|
|
31
|
+
3. Push `main` once; push tags one-at-a-time (Scenario 7 prevention).
|
|
32
|
+
4. **Publish in version order, oldest first, waiting for each version's workflows to settle** before dispatching the next — `npm dist-tag latest` is set by publish order. `dispatch-publish.mjs --after <prev-version>` gates on `dist-tag latest` to enforce it. If mis-ordered: `npm dist-tag add @adia-ai/<pkg>@<newest> latest` per package.
|
|
33
|
+
5. One GH release note per version; site deploy once at the END (reflects HEAD).
|
|
34
|
+
|
|
35
|
+
## §Scenario 3 — Author from scratch (`[Unreleased]` promotion)
|
|
36
|
+
|
|
37
|
+
**Shape:** source + CHANGELOG entries landed under `## [Unreleased]`, no bump, no release commit.
|
|
38
|
+
|
|
39
|
+
**Resolution:** [`cut-procedure.md`](cut-procedure.md) Variant B; `scripts/promote-unreleased.mjs` mechanizes the heading swap; fresh blocks per [`changelog-discipline.md`](changelog-discipline.md) §Authoring.
|
|
40
|
+
|
|
41
|
+
## §Scenario 4 — `[Unreleased]` extension (early cut + entangled fix)
|
|
42
|
+
|
|
43
|
+
**Shape:** a peer pre-cut the release commit early, then landed more commits including a fix that **completes the early cut's own scope** (e.g. the demo-shell import its feature broke) entangled with unrelated `[Unreleased]` work. The early commit fails a release-blocking gate (`check:demo-shells`).
|
|
44
|
+
|
|
45
|
+
**Resolution — two options:**
|
|
46
|
+
|
|
47
|
+
1. Cherry-pick the fix onto the release commit (off-mainline tag; messy archaeology). Only when the operator explicitly wants minimal scope.
|
|
48
|
+
2. **Extend the release to HEAD** ← default. Verify HEAD passes all gates; promote the `[Unreleased]` content into `[vX.Y.Z]`; author fresh blocks for changed-but-unlogged packages; commit the CHANGELOG merge with a message documenting the boundary decision; tag at the new HEAD.
|
|
49
|
+
|
|
50
|
+
## §Scenario 5 — Stale test detection
|
|
51
|
+
|
|
52
|
+
**Shape:** a pre-flight test fails, but it asserts a behavior a peer *deliberately* changed (the change is CHANGELOG-documented); the test was never updated.
|
|
53
|
+
|
|
54
|
+
**Resolution:** read three things — the assertion, the CHANGELOG entry, the production source. Code matches the CHANGELOG's described behavior → the test is stale: update the assertion, add an inline comment naming the vX.Y.Z change, optionally pin the new contract with an extra assertion, include the test update in the release allowlist. Code matches the test → real regression (or the CHANGELOG is wrong) — fix that instead.
|
|
55
|
+
|
|
56
|
+
## §Scenario 6 — Concurrent peer mid-cycle
|
|
57
|
+
|
|
58
|
+
**Shape:** the working tree shifts between commands; `git stash pop` reports a conflict or "kept the stash."
|
|
59
|
+
|
|
60
|
+
**Resolution:** don't fight the peer. First confirm the release itself is fully shipped (tags pushed + npm + GH releases + site). Then for a kept stash: `git stash show -p stash@{0}` vs the file's recent `git log -p` — if the peer committed the same content, the stash is redundant → `git stash drop`; if not, leave the stash for the peer/operator to decide. Never blind-drop.
|
|
61
|
+
|
|
62
|
+
## §Scenario 7 — Tags pushed, ZERO publish workflows fired
|
|
63
|
+
|
|
64
|
+
**Shape:** all 10 tags exist on origin, but no `publish-<pkg>.yml` run exists for them; npm latest unchanged; nothing errored.
|
|
65
|
+
|
|
66
|
+
**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).
|
|
67
|
+
|
|
68
|
+
**Resolution:**
|
|
69
|
+
|
|
70
|
+
```bash
|
|
71
|
+
node "${CLAUDE_PLUGIN_ROOT}/skills/adia-release/scripts/dispatch-publish.mjs" \
|
|
72
|
+
--version X.Y.Z --verify-triggered # re-dispatches ONLY packages with no run; idempotent
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
For a batch, preserve npm-latest ordering (`--after <prev>`). Verify against the registry, not the workflows. **Prevention:** push tags one-at-a-time ([`cut-procedure.md`](cut-procedure.md) §Step 8); `release-pack.mjs` does this automatically and follows with `--verify-triggered`.
|
|
76
|
+
|
|
77
|
+
## §Scenario 8 — Cut on the wrong branch
|
|
78
|
+
|
|
79
|
+
**Shape:** the cut landed on a peer's local feature branch instead of `main`; caught at push (origin/main at a mid-window commit, tags pointing at the feature tip). (Real case: v0.7.4.)
|
|
80
|
+
|
|
81
|
+
**Resolution:** recovery is clean **while nothing has published** — publish is `workflow_dispatch`-driven, so npm stays put through the tangle. If the feature tip fast-forwards from main: `git branch -f main <release-sha>` → `git checkout main` → `git push origin main`. Verify `origin/main == vX.Y.Z tag == HEAD` **before** dispatching any publish. Moving tags while local is free (`tag-lockstep.mjs --delete` + re-tag); moving them after a publish is not. **Prevention:** the Step-1 `branch --show-current` check.
|
|
82
|
+
|
|
83
|
+
---
|
|
84
|
+
|
|
85
|
+
## §Decision flowchart
|
|
86
|
+
|
|
87
|
+
```text
|
|
88
|
+
Pre-flight or F-N1 gate failed?
|
|
89
|
+
├── check:demo-shells fails at the release-commit candidate?
|
|
90
|
+
│ └── a later fix exists but is entangled with [Unreleased] work → Scenario 4
|
|
91
|
+
│ otherwise → author the fix in this cycle (Variant B)
|
|
92
|
+
├── check:lockstep fails → peer edited an internal range mid-PATCH → fix in place
|
|
93
|
+
├── verify:corpus fails → corpus drift → route to the A2UI-pipeline skill
|
|
94
|
+
├── check:embeddings-fresh fails → npm run build:embeddings:chunks; stage; note in
|
|
95
|
+
│ the a2ui-corpus CHANGELOG
|
|
96
|
+
├── test:unit fails → Scenario 5 (stale test) OR real regression
|
|
97
|
+
│ (assertion vs CHANGELOG vs source tells them apart)
|
|
98
|
+
└── F-N1 cosmetic warns → enrichment pass (changelog-discipline.md)
|
|
99
|
+
|
|
100
|
+
Multiple unpushed release commits → Scenario 2 (batch push)
|
|
101
|
+
Commit's CHANGELOG version ≠ its bump → Scenario 1 (version skip)
|
|
102
|
+
Tags on origin, no publish runs, npm stale → Scenario 7 (batched tag push)
|
|
103
|
+
branch --show-current ≠ main → Scenario 8 (wrong branch)
|
|
104
|
+
Working tree dirty at cycle start → classify + stash per
|
|
105
|
+
cut-procedure.md §Step 2
|
|
106
|
+
```
|
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
// node bump.mjs --from 0.6.20 --to 0.6.21
|
|
9
9
|
// node bump.mjs --from 0.6.20 --to 0.6.21 --dry
|
|
10
10
|
//
|
|
11
|
-
//
|
|
11
|
+
// Part of the adia-release skill. Replaces the /tmp/vXXX-prep.mjs
|
|
12
12
|
// improvisation pattern from the v0.6.13 → v0.6.21 cycles.
|
|
13
13
|
//
|
|
14
14
|
// Exits:
|
|
@@ -31,8 +31,21 @@ const PACKAGES = [
|
|
|
31
31
|
'packages/a2ui/retrieval',
|
|
32
32
|
'packages/a2ui/runtime',
|
|
33
33
|
'packages/a2ui/validator',
|
|
34
|
+
// Plugins joined the lockstep 2026-07-15 (see check-lockstep.mjs's POLICY
|
|
35
|
+
// note). Each also carries a .claude-plugin/plugin.json whose version MUST
|
|
36
|
+
// move with package.json — plugin.json is the /plugin-update cache key
|
|
37
|
+
// (verify:plugins gates the sync).
|
|
38
|
+
'packages/plugins/adia-ui-factory',
|
|
39
|
+
'packages/plugins/adia-ui-forge',
|
|
34
40
|
];
|
|
35
41
|
|
|
42
|
+
// Sibling manifests bumped in the same pass as package.json (path relative to
|
|
43
|
+
// the package dir). Today: the Claude Code plugin manifests.
|
|
44
|
+
const SIBLING_MANIFESTS = {
|
|
45
|
+
'packages/plugins/adia-ui-factory': '.claude-plugin/plugin.json',
|
|
46
|
+
'packages/plugins/adia-ui-forge': '.claude-plugin/plugin.json',
|
|
47
|
+
};
|
|
48
|
+
|
|
36
49
|
function parseArgs(argv) {
|
|
37
50
|
const args = { from: null, to: null, dry: false, repo: process.cwd() };
|
|
38
51
|
for (let i = 0; i < argv.length; i++) {
|
|
@@ -96,6 +109,18 @@ function bumpAll(packages, from, to, dry) {
|
|
|
96
109
|
if (!dry) fs.writeFileSync(p.path, out);
|
|
97
110
|
bumped++;
|
|
98
111
|
console.log(` ${dry ? '[dry] ' : ''}bumped ${p.pkg}: ${from} → ${to}`);
|
|
112
|
+
const sibling = SIBLING_MANIFESTS[p.pkg];
|
|
113
|
+
if (sibling) {
|
|
114
|
+
const sibPath = path.join(path.dirname(p.path), sibling);
|
|
115
|
+
const sibTxt = fs.readFileSync(sibPath, 'utf8');
|
|
116
|
+
const sibOut = sibTxt.replace(FROM_PATTERN, TO_LITERAL);
|
|
117
|
+
if (sibOut === sibTxt) {
|
|
118
|
+
console.error(`error: ${p.pkg}/${sibling} — regex did not match (plugin.json out of sync?)`);
|
|
119
|
+
return -1;
|
|
120
|
+
}
|
|
121
|
+
if (!dry) fs.writeFileSync(sibPath, sibOut);
|
|
122
|
+
console.log(` ${dry ? '[dry] ' : ''}bumped ${p.pkg}/${sibling}: ${from} → ${to}`);
|
|
123
|
+
}
|
|
99
124
|
}
|
|
100
125
|
return bumped;
|
|
101
126
|
}
|
|
@@ -106,7 +131,7 @@ function main() {
|
|
|
106
131
|
if (!validateAllAtFrom(packages, args.from)) process.exit(1);
|
|
107
132
|
const bumped = bumpAll(packages, args.from, args.to, args.dry);
|
|
108
133
|
if (bumped < 0) process.exit(3);
|
|
109
|
-
console.log(`\n[bump] ${bumped}
|
|
134
|
+
console.log(`\n[bump] ${bumped}/${PACKAGES.length} ${args.dry ? '(dry — no files written)' : 'bumped'}`);
|
|
110
135
|
if (!args.dry) {
|
|
111
136
|
console.log(`\n[next] regenerate the lockfile:`);
|
|
112
137
|
console.log(` npm install --package-lock-only --no-audit --no-fund`);
|
|
@@ -14,7 +14,7 @@
|
|
|
14
14
|
// # Dry mode:
|
|
15
15
|
// node dispatch-publish.mjs --version 0.6.22 --dry
|
|
16
16
|
//
|
|
17
|
-
//
|
|
17
|
+
// Part of the adia-release skill. Mechanizes the dispatch loop
|
|
18
18
|
// + handles the npm-latest ordering rule for batch pushes.
|
|
19
19
|
|
|
20
20
|
import { execSync } from 'node:child_process';
|
|
@@ -35,12 +35,16 @@ const PACKAGES = [
|
|
|
35
35
|
'a2ui-mcp',
|
|
36
36
|
'a2ui-retrieval',
|
|
37
37
|
'a2ui-validator',
|
|
38
|
+
// Plugins joined the lockstep 2026-07-15 (check-lockstep.mjs POLICY note).
|
|
39
|
+
'adia-ui-factory',
|
|
40
|
+
'adia-ui-forge',
|
|
38
41
|
];
|
|
39
42
|
|
|
40
43
|
function parseArgs(argv) {
|
|
41
44
|
const args = {
|
|
42
45
|
version: null, after: null, dry: false, sleepBefore: 4,
|
|
43
46
|
scope: process.env.ADIA_NPM_SCOPE || DEFAULT_SCOPE,
|
|
47
|
+
verifyTriggered: false,
|
|
44
48
|
};
|
|
45
49
|
for (let i = 0; i < argv.length; i++) {
|
|
46
50
|
const k = argv[i];
|
|
@@ -49,13 +53,19 @@ function parseArgs(argv) {
|
|
|
49
53
|
else if (k === '--dry') args.dry = true;
|
|
50
54
|
else if (k === '--sleep-before') args.sleepBefore = parseInt(argv[++i], 10);
|
|
51
55
|
else if (k === '--scope') args.scope = argv[++i];
|
|
56
|
+
else if (k === '--verify-triggered') args.verifyTriggered = true;
|
|
52
57
|
else if (k === '-h' || k === '--help') {
|
|
53
|
-
console.log('Usage: node dispatch-publish.mjs --version X.Y.Z [--after X.Y.Z-1] [--dry] [--sleep-before <seconds>] [--scope @org]');
|
|
58
|
+
console.log('Usage: node dispatch-publish.mjs --version X.Y.Z [--after X.Y.Z-1] [--verify-triggered] [--dry] [--sleep-before <seconds>] [--scope @org]');
|
|
54
59
|
console.log('');
|
|
55
|
-
console.log('--after
|
|
56
|
-
console.log('
|
|
57
|
-
console.log(
|
|
58
|
-
console.log('
|
|
60
|
+
console.log('--after Verify npm latest is at the given version before dispatching this one.');
|
|
61
|
+
console.log(' Used in batch push to ensure publish ordering.');
|
|
62
|
+
console.log('--verify-triggered Instead of dispatching, check whether each per-package publish-<pkg>.yml');
|
|
63
|
+
console.log(' ALREADY has a run for the <pkg>-vX.Y.Z tag (i.e. push-on-tag fired), and');
|
|
64
|
+
console.log(' re-dispatch ONLY the misses. This is the recovery for the batch-tag-push');
|
|
65
|
+
console.log(' skip (recovery-paths.md §Scenario 7) — a single `git push <10 tags>` can');
|
|
66
|
+
console.log(' trigger ZERO publish workflows. Idempotent: re-dispatches nothing if all 9 fired.');
|
|
67
|
+
console.log(`--scope npm scope the packages publish under (default: ${DEFAULT_SCOPE};`);
|
|
68
|
+
console.log(' or set $ADIA_NPM_SCOPE). The --after npm-latest check uses this scope.');
|
|
59
69
|
process.exit(0);
|
|
60
70
|
}
|
|
61
71
|
}
|
|
@@ -115,12 +125,68 @@ async function sleep(ms) {
|
|
|
115
125
|
return new Promise((res) => setTimeout(res, ms));
|
|
116
126
|
}
|
|
117
127
|
|
|
128
|
+
// Has publish-<pkg>.yml already run for the <pkg>-vX.Y.Z tag? Tag-triggered runs
|
|
129
|
+
// report the tag in the `headBranch` field, so we filter the run list by it.
|
|
130
|
+
// Returns true if at least one run exists for that tag, false otherwise.
|
|
131
|
+
function triggeredForTag(pkg, version, dry) {
|
|
132
|
+
const tag = `${pkg}-v${version}`;
|
|
133
|
+
const cmd = `gh run list --workflow="publish-${pkg}.yml" --branch "${tag}" --limit 1 --json databaseId -q '.[0].databaseId // empty'`;
|
|
134
|
+
if (dry) {
|
|
135
|
+
console.log(` [dry] ${cmd}`);
|
|
136
|
+
return false; // dry preview assumes not-triggered so the re-dispatch path is shown
|
|
137
|
+
}
|
|
138
|
+
try {
|
|
139
|
+
const out = execSync(cmd, { encoding: 'utf8' }).trim();
|
|
140
|
+
return out.length > 0;
|
|
141
|
+
} catch {
|
|
142
|
+
// gh error (auth / rate limit / missing workflow) — treat as "unknown".
|
|
143
|
+
// Conservative: report not-triggered so the miss is re-dispatched rather than
|
|
144
|
+
// silently skipped. A redundant re-dispatch is harmless (publish is idempotent
|
|
145
|
+
// per the workflow's own guard); a skipped publish is the failure we're fixing.
|
|
146
|
+
return false;
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
// The batch-tag-push-skip recovery: verify each per-package publish workflow
|
|
151
|
+
// actually triggered off its pushed tag, and re-dispatch ONLY the misses.
|
|
152
|
+
// Idempotent — re-dispatches nothing if all 9 fired.
|
|
153
|
+
function verifyTriggeredAndRedispatch(version, dry) {
|
|
154
|
+
console.log(`\nVerifying publish-on-tag triggered for all ${PACKAGES.length} packages (v${version}):`);
|
|
155
|
+
const misses = [];
|
|
156
|
+
for (const pkg of PACKAGES) {
|
|
157
|
+
if (triggeredForTag(pkg, version, dry)) {
|
|
158
|
+
console.log(` ✓ ${pkg} — publish run found for ${pkg}-v${version}`);
|
|
159
|
+
} else {
|
|
160
|
+
console.log(` ✗ ${pkg} — NO publish run for ${pkg}-v${version} (batch-push skip) → will re-dispatch`);
|
|
161
|
+
misses.push(pkg);
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
if (misses.length === 0) {
|
|
165
|
+
console.log(`\n[verify-triggered] all ${PACKAGES.length} publish workflows triggered — nothing to re-dispatch.`);
|
|
166
|
+
return 0;
|
|
167
|
+
}
|
|
168
|
+
console.log(`\n[verify-triggered] ${misses.length} miss(es) — re-dispatching via workflow_dispatch:`);
|
|
169
|
+
let redispatched = 0;
|
|
170
|
+
for (const pkg of misses) {
|
|
171
|
+
if (dispatch(pkg, version, dry)) redispatched++;
|
|
172
|
+
}
|
|
173
|
+
console.log(`\n[verify-triggered] re-dispatched ${redispatched}/${misses.length} ${dry ? '(dry)' : ''}`);
|
|
174
|
+
return redispatched === misses.length ? 0 : 1;
|
|
175
|
+
}
|
|
176
|
+
|
|
118
177
|
async function main() {
|
|
119
178
|
const args = parseArgs(process.argv.slice(2));
|
|
120
179
|
// Fail-fast guard: refuse to run npm/gh against a non-monorepo directory.
|
|
121
180
|
assertMonorepoRoot(process.cwd());
|
|
122
181
|
if (args.after) checkAfter(args.after, args.scope);
|
|
123
182
|
|
|
183
|
+
// Recovery mode — verify each publish workflow triggered off its pushed tag,
|
|
184
|
+
// re-dispatch only the misses (the batch-tag-push skip). Skips the blind dispatch.
|
|
185
|
+
if (args.verifyTriggered) {
|
|
186
|
+
const rc = verifyTriggeredAndRedispatch(args.version, args.dry);
|
|
187
|
+
process.exit(rc);
|
|
188
|
+
}
|
|
189
|
+
|
|
124
190
|
if (args.sleepBefore > 0 && !args.dry) {
|
|
125
191
|
console.log(`Sleeping ${args.sleepBefore}s to let GH index the new tags...`);
|
|
126
192
|
await sleep(args.sleepBefore * 1000);
|
|
@@ -11,13 +11,13 @@
|
|
|
11
11
|
// --previous-version 0.6.21 \
|
|
12
12
|
// --packages llm,a2ui/compose,a2ui/mcp,a2ui/retrieval,a2ui/runtime,a2ui/validator
|
|
13
13
|
//
|
|
14
|
-
//
|
|
14
|
+
// Part of the adia-release skill. Replaces the inline stub-
|
|
15
15
|
// insertion pattern used across v0.6.18 / v0.6.19 / v0.6.20 / v0.6.21
|
|
16
16
|
// cycles.
|
|
17
17
|
|
|
18
18
|
import fs from 'node:fs';
|
|
19
|
-
import path from 'node:path';
|
|
20
19
|
import process from 'node:process';
|
|
20
|
+
import { resolvePackageChangelog } from './package-paths.mjs';
|
|
21
21
|
|
|
22
22
|
function parseArgs(argv) {
|
|
23
23
|
const args = {
|
|
@@ -72,7 +72,8 @@ function buildStub(version, date, substantive, xref) {
|
|
|
72
72
|
}
|
|
73
73
|
|
|
74
74
|
function insertStub(repo, pkg, anchor, stubBlock, version, dry) {
|
|
75
|
-
|
|
75
|
+
// Accept both name-form (a2ui-corpus) and path-form (a2ui/corpus). See package-paths.mjs.
|
|
76
|
+
const p = resolvePackageChangelog(repo, pkg);
|
|
76
77
|
if (!fs.existsSync(p)) {
|
|
77
78
|
console.error(` ERROR ${pkg} — CHANGELOG.md not found at ${p}`);
|
|
78
79
|
return 'missing';
|
|
@@ -101,7 +102,8 @@ function main() {
|
|
|
101
102
|
const PREV_HEADING_RE = new RegExp(`^## \\[${args.previous.replace(/\./g, '\\.')}\\] — \\d{4}-\\d{2}-\\d{2}$`, 'm');
|
|
102
103
|
const stubBlock = buildStub(args.version, args.date, args.substantive, args.xref);
|
|
103
104
|
const results = args.packages.map((pkg) => {
|
|
104
|
-
|
|
105
|
+
// Accept both name-form (a2ui-corpus) and path-form (a2ui/corpus). See package-paths.mjs.
|
|
106
|
+
const p = resolvePackageChangelog(args.repo, pkg);
|
|
105
107
|
if (!fs.existsSync(p)) {
|
|
106
108
|
console.error(` ERROR ${pkg} — not found`);
|
|
107
109
|
return 'missing';
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
// package-paths.mjs — package name-vs-path-form normalization for the
|
|
2
|
+
// standalone CHANGELOG helpers.
|
|
3
|
+
//
|
|
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
|
|
6
|
+
// flat npm-name `a2ui-<x>` everywhere else in the tooling (release-pack.mjs,
|
|
7
|
+
// dispatch-publish.mjs, tag-lockstep.mjs all use the NAME form). The two
|
|
8
|
+
// standalone helpers (promote-unreleased.mjs, insert-stub.mjs) joined
|
|
9
|
+
// `packages/<arg>/CHANGELOG.md` with the raw arg, so calling them with the
|
|
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`),
|
|
12
|
+
// so the two forms diverged: name-form failed standalone, path-form failed
|
|
13
|
+
// when handed to the orchestrator-style callers.
|
|
14
|
+
//
|
|
15
|
+
// THE FIX:
|
|
16
|
+
// Accept BOTH forms. Try `packages/<arg>` first (path form, backward-compat).
|
|
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/`.
|
|
20
|
+
//
|
|
21
|
+
// Pure Node, stdlib only — keeps the scripts free of runtime deps.
|
|
22
|
+
|
|
23
|
+
import fs from 'node:fs';
|
|
24
|
+
import path from 'node:path';
|
|
25
|
+
|
|
26
|
+
// Resolve a package arg to its on-disk directory under packages/, accepting
|
|
27
|
+
// BOTH the name form (`a2ui-corpus`) and the path form (`a2ui/corpus`).
|
|
28
|
+
// Returns the resolved relative directory (e.g. `a2ui/corpus`); does not
|
|
29
|
+
// require the directory to exist (so callers can render a legible not-found
|
|
30
|
+
// error against the resolved path).
|
|
31
|
+
export function resolvePackageDir(repo, pkg) {
|
|
32
|
+
if (fs.existsSync(path.join(repo, 'packages', pkg))) return pkg;
|
|
33
|
+
const m = /^a2ui-(.+)$/.exec(pkg);
|
|
34
|
+
if (m) {
|
|
35
|
+
const nested = path.join('a2ui', m[1]);
|
|
36
|
+
if (fs.existsSync(path.join(repo, 'packages', nested))) return nested;
|
|
37
|
+
}
|
|
38
|
+
// Plugins live under packages/plugins/<name> but carry the flat name form
|
|
39
|
+
// (adia-ui-forge) in the release tooling — same name-vs-path split as a2ui.
|
|
40
|
+
if (/^adia-ui-/.test(pkg)) {
|
|
41
|
+
const nested = path.join('plugins', pkg);
|
|
42
|
+
if (fs.existsSync(path.join(repo, 'packages', nested))) return nested;
|
|
43
|
+
}
|
|
44
|
+
return pkg; // fall through with the original arg so the not-found error names what was asked for
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
// Resolve a package arg to its CHANGELOG.md path, accepting both forms.
|
|
48
|
+
export function resolvePackageChangelog(repo, pkg) {
|
|
49
|
+
return path.join(repo, 'packages', resolvePackageDir(repo, pkg), 'CHANGELOG.md');
|
|
50
|
+
}
|
|
@@ -11,7 +11,7 @@
|
|
|
11
11
|
// node promote-unreleased.mjs --version 0.6.22 --date 2026-05-22 \
|
|
12
12
|
// --packages web-components,web-modules --dry
|
|
13
13
|
//
|
|
14
|
-
//
|
|
14
|
+
// Part of the adia-release skill. Replaces the inline heading-swap
|
|
15
15
|
// pattern used across v0.6.18 / v0.6.19 / v0.6.20 / v0.6.21 cycles.
|
|
16
16
|
//
|
|
17
17
|
// Exits:
|
|
@@ -20,8 +20,8 @@
|
|
|
20
20
|
// 2 — bad args / file I/O error
|
|
21
21
|
|
|
22
22
|
import fs from 'node:fs';
|
|
23
|
-
import path from 'node:path';
|
|
24
23
|
import process from 'node:process';
|
|
24
|
+
import { resolvePackageChangelog } from './package-paths.mjs';
|
|
25
25
|
|
|
26
26
|
function parseArgs(argv) {
|
|
27
27
|
const args = { version: null, date: null, packages: null, dry: false, repo: process.cwd() };
|
|
@@ -52,7 +52,8 @@ function parseArgs(argv) {
|
|
|
52
52
|
}
|
|
53
53
|
|
|
54
54
|
function promote(repo, pkg, version, date, dry) {
|
|
55
|
-
|
|
55
|
+
// Accept both name-form (a2ui-corpus) and path-form (a2ui/corpus). See package-paths.mjs.
|
|
56
|
+
const p = resolvePackageChangelog(repo, pkg);
|
|
56
57
|
if (!fs.existsSync(p)) {
|
|
57
58
|
console.error(` ERROR ${pkg} — CHANGELOG.md not found at ${p}`);
|
|
58
59
|
return 'missing';
|
|
@@ -1,12 +1,11 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
// release-pack.mjs — full-cycle orchestrator for an AdiaUI lockstep release.
|
|
3
3
|
//
|
|
4
|
-
// Chains the
|
|
5
|
-
//
|
|
6
|
-
//
|
|
7
|
-
//
|
|
8
|
-
//
|
|
9
|
-
// SKILL.md §Posture.
|
|
4
|
+
// Chains the 5 CLI helpers (bump · promote-unreleased · insert-stub ·
|
|
5
|
+
// tag-lockstep · dispatch-publish) plus the non-helper steps (lockfile ·
|
|
6
|
+
// pre-flight gates · git commit · F-N1 · push · GH releases · site
|
|
7
|
+
// deploy) into one walked sequence with 3 operator checkpoints (before
|
|
8
|
+
// tag, before push, before publish) per SKILL.md operator checkpoints.
|
|
10
9
|
//
|
|
11
10
|
// MODES:
|
|
12
11
|
// --mode cut (Mode 1 — peer pre-staged [Unreleased] or pure stub)
|
|
@@ -33,8 +32,8 @@
|
|
|
33
32
|
// --skip-gates : (DEBUG ONLY) skip pre-flight (don't ship anything!)
|
|
34
33
|
// --skip-site : skip the EXE deploy step (rare; for offline cycles)
|
|
35
34
|
//
|
|
36
|
-
//
|
|
37
|
-
// references/
|
|
35
|
+
// Part of the adia-release skill. Mechanizes the cut procedure from
|
|
36
|
+
// references/cut-procedure.md while preserving operator judgment at
|
|
38
37
|
// the 3 mutating-checkpoint boundaries.
|
|
39
38
|
|
|
40
39
|
import { execSync } from 'node:child_process';
|
|
@@ -269,21 +268,50 @@ function step7Fn1(args) {
|
|
|
269
268
|
}
|
|
270
269
|
|
|
271
270
|
// ── Step 8 — Push ────────────────────────────────────────────────
|
|
271
|
+
// Pushes per-package tags ONE-AT-A-TIME, not as a single batch.
|
|
272
|
+
//
|
|
273
|
+
// THE BATCH-PUSH SKIP (bit the v0.7.14 cut): `git push origin <10 tags>` in one
|
|
274
|
+
// invocation fires the push-on-tag `create` event ONCE for the whole ref-set,
|
|
275
|
+
// and GitHub Actions routinely drops it — ZERO publish-on-tag workflows trigger.
|
|
276
|
+
// (recovery-paths.md §Scenario 7 — the batch-tag-push publish-skip.)
|
|
277
|
+
// Pushing each per-package tag separately gives the per-package publish-<pkg>.yml
|
|
278
|
+
// `on: push: tags:` trigger its own create event. The umbrella tag is pushed
|
|
279
|
+
// last (it triggers nothing — convention only).
|
|
280
|
+
//
|
|
281
|
+
// Step 9 dispatches all 9 publishes via workflow_dispatch regardless, so the
|
|
282
|
+
// orchestrated cut does NOT rely on push-on-tag firing. The one-at-a-time push
|
|
283
|
+
// is defensive (a cut aborted after Step 8 still has its publishes triggered)
|
|
284
|
+
// AND keeps the standalone tag-lockstep.mjs hint honest.
|
|
272
285
|
async function step8Push(args) {
|
|
273
|
-
console.log('\n=== Step 8 — Push main + tags ===');
|
|
286
|
+
console.log('\n=== Step 8 — Push main + tags (per-tag, NOT batched) ===');
|
|
274
287
|
const count = shQuiet('git rev-list --count origin/main..HEAD', args).trim();
|
|
275
288
|
console.log(` commits to push: ${count}`);
|
|
276
|
-
await checkpoint(`Ready to push ${count} commit(s) + 10 tags`, args);
|
|
289
|
+
await checkpoint(`Ready to push ${count} commit(s) + 10 tags (one-at-a-time)`, args);
|
|
277
290
|
sh('git push origin main', args);
|
|
278
|
-
const
|
|
279
|
-
|
|
291
|
+
const perPkgTags = PACKAGES.map((p) => `${p}-v${args.version}`);
|
|
292
|
+
for (const t of perPkgTags) {
|
|
293
|
+
sh(`git push origin ${t}`, args);
|
|
294
|
+
}
|
|
295
|
+
// Umbrella tag last — triggers no workflow (convention only).
|
|
296
|
+
sh(`git push origin v${args.version}`, args);
|
|
297
|
+
console.log(`\n ${perPkgTags.length} per-package tags + 1 umbrella pushed individually.`);
|
|
298
|
+
console.log(' NOTE: a single `git push origin <all tags>` can skip ALL publish-on-tag');
|
|
299
|
+
console.log(' triggers (the GitHub batch-push skip). Step 9 dispatches via');
|
|
300
|
+
console.log(' workflow_dispatch + verifies each triggered — see recovery-paths.md §Scenario 7.');
|
|
280
301
|
}
|
|
281
302
|
|
|
282
303
|
// ── Step 9 — Publish ─────────────────────────────────────────────
|
|
304
|
+
// Step 8 pushed per-package tags one-at-a-time, so push-on-tag may have fired
|
|
305
|
+
// for some/all packages. --verify-triggered checks which publish-<pkg>.yml runs
|
|
306
|
+
// exist for the <pkg>-vX.Y.Z tags and re-dispatches ONLY the misses — closing the
|
|
307
|
+
// batch-tag-push skip without double-publishing the ones that already fired.
|
|
308
|
+
// Idempotent: if all 9 triggered (or none did), it does the right thing.
|
|
283
309
|
async function step9Publish(args) {
|
|
284
|
-
console.log('\n=== Step 9 —
|
|
285
|
-
await checkpoint('Ready to
|
|
286
|
-
|
|
310
|
+
console.log('\n=== Step 9 — Verify-triggered + re-dispatch misses ===');
|
|
311
|
+
await checkpoint('Ready to verify the 9 publish triggers + re-dispatch any misses', args);
|
|
312
|
+
// Give GH a moment to index the runs created by the per-tag push in Step 8.
|
|
313
|
+
if (!args.dry) sh('sleep 6', args);
|
|
314
|
+
sh(`node ${SCRIPT_DIR}/dispatch-publish.mjs --version ${args.version} --scope ${args.scope} --verify-triggered`, args);
|
|
287
315
|
console.log('\n Waiting for publishes to settle...');
|
|
288
316
|
sh(`until [ "$(gh run list --workflow=publish-a2ui-validator.yml --limit 1 --json status -q '.[0].status')" = "completed" ]; do sleep 5; done`, args);
|
|
289
317
|
console.log(' ✓ publishes settled');
|
|
@@ -312,15 +340,9 @@ async function step10GhAndSite(args) {
|
|
|
312
340
|
}
|
|
313
341
|
sh('npm run build:site', args);
|
|
314
342
|
sh(`rsync -az --delete dist/ ${args.host}:/srv/adia-ui/dist/`, args);
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
// ── Step 11 — Ledger ─────────────────────────────────────────────
|
|
319
|
-
function step11Ledger(args) {
|
|
320
|
-
console.log('\n=== Step 11 — Audit-history ledger ===');
|
|
321
|
-
const cmd = `node ${SCRIPT_DIR}/make-ledger.mjs --version ${args.version} --date ${args.date} --summary "<TODO: paste from commit message>" --note "Shipped via release-pack.mjs mode=${args.mode}"`;
|
|
322
|
-
sh(cmd, args);
|
|
323
|
-
console.log('\n Edit the generated ledger to fill in scope/verification details, then commit + push.');
|
|
343
|
+
// Verify a deployed CONTENT FILE, never an SPA route — the docs site
|
|
344
|
+
// returns HTTP 200 + a blank shell for ANY unmatched route (v0.7.4 trap).
|
|
345
|
+
sh(`curl -s -o /dev/null -w "EXE host.css: HTTP %{http_code}\\n" https://${args.host}/packages/web-components/styles/host.css`, args);
|
|
324
346
|
}
|
|
325
347
|
|
|
326
348
|
// ── Main ─────────────────────────────────────────────────────────
|
|
@@ -328,7 +350,7 @@ async function main() {
|
|
|
328
350
|
const args = parseArgs(process.argv.slice(2));
|
|
329
351
|
// Fail-fast guard: refuse to git/npm/gh/curl against a non-monorepo directory.
|
|
330
352
|
assertMonorepoRoot(REPO);
|
|
331
|
-
console.log(`adia-
|
|
353
|
+
console.log(`adia-release release-pack — v${args.version} (${args.mode})${args.dry ? ' [DRY]' : ''}`);
|
|
332
354
|
step1ReBaseline(args);
|
|
333
355
|
step3PreFlight(args);
|
|
334
356
|
step4PromoteAndBump(args);
|
|
@@ -338,9 +360,8 @@ async function main() {
|
|
|
338
360
|
await step8Push(args);
|
|
339
361
|
await step9Publish(args);
|
|
340
362
|
await step10GhAndSite(args);
|
|
341
|
-
step11Ledger(args);
|
|
342
363
|
rl.close();
|
|
343
|
-
console.log('\n✓ release-pack complete.
|
|
364
|
+
console.log('\n✓ release-pack complete. Verify against the npm registry + GH releases, then author the release notes.');
|
|
344
365
|
}
|
|
345
366
|
|
|
346
367
|
main().catch((e) => {
|