@softspark/ai-toolkit 4.30.2 → 4.31.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.
Files changed (40) hide show
  1. package/CHANGELOG.md +57 -0
  2. package/README.md +27 -28
  3. package/app/.claude-plugin/plugin.json +1 -1
  4. package/app/agents/code-reviewer.md +14 -0
  5. package/app/agents/frontend-specialist.md +27 -24
  6. package/app/agents/infrastructure-validator.md +2 -2
  7. package/app/claude-app/skills/ai-toolkit-rules/SKILL.md +44 -1
  8. package/app/personas/frontend-lead.md +20 -12
  9. package/app/rules/claude-toolkit-rules.md +4 -1
  10. package/app/rules/edit-discipline.md +37 -0
  11. package/app/skills/app-builder/SKILL.md +37 -6
  12. package/app/skills/claude-toolkit-rules/SKILL.md +37 -0
  13. package/app/skills/design-engineering/SKILL.md +87 -102
  14. package/app/skills/design-engineering/reference/animation-recipes.md +67 -0
  15. package/app/skills/design-engineering/reference/component-craft.md +28 -0
  16. package/app/skills/documentation-standards/SKILL.md +1 -1
  17. package/app/skills/edit-discipline/SKILL.md +50 -0
  18. package/app/skills/git-conventions/SKILL.md +18 -0
  19. package/app/skills/output-mode/SKILL.md +41 -0
  20. package/app/skills/quality-gates/SKILL.md +23 -0
  21. package/app/skills/review/SKILL.md +10 -0
  22. package/kb/procedures/{ecosystem-sync-sop.md → sop-ecosystem-sync.md} +2 -2
  23. package/kb/procedures/{post-release-testing-sop.md → sop-post-release-testing.md} +3 -3
  24. package/kb/procedures/sop-pre-commit.md +96 -0
  25. package/kb/procedures/{release-preparation-sop.md → sop-release.md} +87 -26
  26. package/kb/reference/architecture-overview.md +1 -1
  27. package/kb/reference/copilot-compatibility.md +1 -1
  28. package/kb/reference/licensing.md +2 -2
  29. package/kb/reference/quick-wins-implementation-summary.md +1 -1
  30. package/kb/reference/supported-tools-registry.md +2 -2
  31. package/kb/troubleshooting/plugin-double-load.md +1 -1
  32. package/llms-full.txt +974 -806
  33. package/llms.txt +6 -5
  34. package/manifest.json +1 -1
  35. package/package.json +2 -1
  36. package/scripts/doctor.py +1 -1
  37. package/scripts/generate_toolkit_rules_skills.py +189 -0
  38. package/scripts/validate.py +1 -1
  39. /package/kb/procedures/{maintenance-sop.md → sop-maintenance.md} +0 -0
  40. /package/kb/procedures/{release-verification-sop.md → sop-release-verification.md} +0 -0
@@ -3,17 +3,17 @@ title: "SOP: Release Preparation"
3
3
  category: procedures
4
4
  service: ai-toolkit
5
5
  tags: [sop, release, version, publish, changelog, semver, provenance, sarif, ecosystem, shellcheck]
6
- version: "1.14.0"
6
+ version: "1.15.0"
7
7
  created: "2026-04-10"
8
- last_updated: "2026-08-06"
9
- description: "Step-by-step checklist for preparing a new ai-toolkit release — ecosystem-sync drift check, version sync, changelog, artifact regeneration, validation, and tagging. Run BEFORE every git tag. Includes mandatory Provenance, SARIF, and checksum-pin checks added in v2.8.0, the single-run npm test discipline added in v1.8.0, the ecosystem-sync gate added in v1.9.0, the registry-vs-generators drift gate added in v1.10.0, the mandatory pre-tag ShellCheck gate added in v1.11.0 (publish.yml does not run ShellCheck, so a hook lint failure can publish while reddening main CI see the v4.5.1 postmortem in Phase 5), the pre-push tag assertions added in v1.12.0 after v4.19.0 was tagged on the wrong commit (Phase 7), and the licensing gate added in v1.13.0 with the move to Apache-2.0 (Phase 5c)."
8
+ last_updated: "2026-09-02"
9
+ description: "Step-by-step checklist for preparing a new ai-toolkit release — ecosystem-sync drift check, version sync, changelog, artifact regeneration, validation, branch CI, and tagging. Run BEFORE every git tag. Includes mandatory Provenance, SARIF, checksum-pin, ShellCheck, licensing, exact-tag assertions, and a green Ubuntu/macOS branch-CI gate before any release tag is created."
10
10
  ---
11
11
 
12
12
  # SOP: Release Preparation
13
13
 
14
14
  Complete checklist for preparing a new `@softspark/ai-toolkit` release.
15
15
  Run this **before** tagging. After tagging and publishing, run the
16
- [Release Verification SOP](release-verification-sop.md) to smoke-test.
16
+ [Release Verification SOP](sop-release-verification.md) to smoke-test.
17
17
 
18
18
  **Pipeline:**
19
19
  ```
@@ -32,10 +32,10 @@ git tag → CI publish → Release Verification SOP
32
32
 
33
33
  ```bash
34
34
  # 0. Ecosystem sync (mandatory for minor/major releases; optional for patch)
35
- # Full procedure: kb/procedures/ecosystem-sync-sop.md
35
+ # Full procedure: kb/procedures/sop-ecosystem-sync.md
36
36
  python3 scripts/ecosystem_doctor.py --format text > /tmp/eco-report.txt
37
37
  cat /tmp/eco-report.txt
38
- # If drift detected: stop here, follow ecosystem-sync-sop.md Phase 2-4 to
38
+ # If drift detected: stop here, follow sop-ecosystem-sync.md Phase 2-4 to
39
39
  # classify each drift (A-F), update generators as needed, refresh snapshot,
40
40
  # THEN resume this SOP.
41
41
  python3 scripts/ecosystem_doctor.py --update # after all drift resolved
@@ -68,16 +68,38 @@ python3 scripts/ecosystem_doctor.py --offline --check || { echo "STALE ecosystem
68
68
  # 5c. Licensing gate — SPDX headers, LICENSE, NOTICE, manifest consistency
69
69
  npx bats tests/test_licensing.bats || { echo "LICENSING GATE FAILED"; exit 1; }
70
70
 
71
- # 6. Commit + tag + push
71
+ # 6. Commit, push branch, and wait for the exact commit's full CI
72
72
  git add -A && git commit -m "chore: release vX.Y.Z"
73
- git tag vX.Y.Z
74
-
75
- # 6a. Assert the tag before pushing it (v4.19.0 postmortem, Phase 7)
76
- test "$(git rev-parse vX.Y.Z)" = "$(git rev-parse HEAD)" || { echo "FAIL: tag not on HEAD"; exit 1; }
73
+ RELEASE_SHA=$(git rev-parse HEAD)
74
+ git push origin main || { echo "FAIL: release commit push failed"; exit 1; }
75
+ RUN_ID=""
76
+ for ATTEMPT in 1 2 3 4 5; do
77
+ RUN_ID=$(gh run list --workflow ci.yml --event push --commit "$RELEASE_SHA" \
78
+ --limit 1 --json databaseId --jq '.[0].databaseId')
79
+ [ -n "$RUN_ID" ] && break
80
+ echo "Waiting for CI run registration ($ATTEMPT/5)" >&2
81
+ [ "$ATTEMPT" -eq 5 ] || sleep 60
82
+ done
83
+ test -n "$RUN_ID" || { echo "FAIL: CI run not found for release commit"; exit 1; }
84
+ gh run watch "$RUN_ID" --exit-status \
85
+ || { echo "FAIL: release commit CI failed"; exit 1; }
86
+ for OS in ubuntu-latest macos-latest; do
87
+ gh run view "$RUN_ID" --json jobs \
88
+ --jq ".jobs[] | select(.name == \"Bats test suite ($OS)\") | .conclusion" \
89
+ | grep -qx success || { echo "FAIL: $OS test job not green"; exit 1; }
90
+ done
91
+ test "$(git rev-parse HEAD)" = "$RELEASE_SHA" || { echo "FAIL: local HEAD changed during CI"; exit 1; }
92
+ git fetch origin main || { echo "FAIL: origin/main refresh failed"; exit 1; }
93
+ test "$(git rev-parse origin/main)" = "$RELEASE_SHA" || { echo "FAIL: origin/main changed during CI"; exit 1; }
94
+
95
+ # 6a. Only green branch CI authorizes tag creation
96
+ git tag vX.Y.Z "$RELEASE_SHA"
97
+
98
+ # 6b. Assert the tag before pushing it (v4.19.0 postmortem, Phase 7)
99
+ test "$(git rev-parse vX.Y.Z)" = "$RELEASE_SHA" || { echo "FAIL: tag not on tested release commit"; exit 1; }
77
100
  git show --no-patch --format=%s vX.Y.Z | grep -qx "chore: release vX.Y.Z" || { echo "FAIL: tag not on release commit"; exit 1; }
78
101
 
79
- # 6b. Branch first, then the single tag by full ref. Never --tags.
80
- git push origin main
102
+ # 6c. Push the single tag by full ref. Never --tags.
81
103
  git push origin refs/tags/vX.Y.Z
82
104
  ```
83
105
 
@@ -104,7 +126,7 @@ Output classifies every registered tool as **Clean**, **Drift**, or **Errored**.
104
126
 
105
127
  ### 0.2 Act on drift
106
128
 
107
- For each drifting tool, follow [ecosystem-sync-sop.md](ecosystem-sync-sop.md) Phase 2-4:
129
+ For each drifting tool, follow [sop-ecosystem-sync.md](sop-ecosystem-sync.md) Phase 2-4:
108
130
 
109
131
  | Drift class | Release impact |
110
132
  |-------------|----------------|
@@ -173,7 +195,7 @@ The canonical version lives in `package.json`. These files **must** match:
173
195
 
174
196
  | File | Field | When to update |
175
197
  |------|-------|---------------|
176
- | `kb/procedures/maintenance-sop.md` | frontmatter `version:` | If SOP content changed |
198
+ | `kb/procedures/sop-maintenance.md` | frontmatter `version:` | If SOP content changed |
177
199
  | `kb/reference/skills-catalog.md` | frontmatter `version:` | If skills added/removed |
178
200
  | `kb/reference/agents-catalog.md` | frontmatter `version:` | If agents added/removed |
179
201
  | `kb/reference/hooks-catalog.md` | frontmatter `version:` | If hooks changed |
@@ -493,23 +515,60 @@ git commit -m "chore: release vX.Y.Z"
493
515
 
494
516
  ---
495
517
 
496
- ## Phase 7: Tag and Push
518
+ ## Phase 7: Push Branch, Verify CI, Tag, and Push Tag
497
519
 
498
520
  ```bash
499
- git tag vX.Y.Z
521
+ RELEASE_SHA=$(git rev-parse HEAD)
522
+ git push origin main || { echo "FAIL: release commit push failed"; exit 1; }
523
+
524
+ # Bind the gate to the exact release commit. GitHub run registration is
525
+ # asynchronous, so retry at most five times and log every attempt.
526
+ RUN_ID=""
527
+ for ATTEMPT in 1 2 3 4 5; do
528
+ RUN_ID=$(gh run list --workflow ci.yml --event push --commit "$RELEASE_SHA" \
529
+ --limit 1 --json databaseId --jq '.[0].databaseId')
530
+ [ -n "$RUN_ID" ] && break
531
+ echo "Waiting for CI run registration ($ATTEMPT/5)" >&2
532
+ [ "$ATTEMPT" -eq 5 ] || sleep 60
533
+ done
534
+ test -n "$RUN_ID" || { echo "FAIL: CI run not found for release commit"; exit 1; }
535
+ gh run watch "$RUN_ID" --exit-status \
536
+ || { echo "FAIL: release commit CI failed"; exit 1; }
537
+
538
+ # publish.yml is Ubuntu-only. Require both full CI matrix jobs before creating
539
+ # the tag so a green publish job cannot bypass a red macOS test.
540
+ for OS in ubuntu-latest macos-latest; do
541
+ gh run view "$RUN_ID" --json jobs \
542
+ --jq ".jobs[] | select(.name == \"Bats test suite ($OS)\") | .conclusion" \
543
+ | grep -qx success || { echo "FAIL: $OS test job not green"; exit 1; }
544
+ done
545
+
546
+ # Refuse to tag if either local or remote main moved while CI was running.
547
+ test "$(git rev-parse HEAD)" = "$RELEASE_SHA" \
548
+ || { echo "FAIL: local HEAD changed during CI"; exit 1; }
549
+ git fetch origin main || { echo "FAIL: origin/main refresh failed"; exit 1; }
550
+ test "$(git rev-parse origin/main)" = "$RELEASE_SHA" \
551
+ || { echo "FAIL: origin/main changed during CI"; exit 1; }
552
+
553
+ git tag vX.Y.Z "$RELEASE_SHA"
500
554
 
501
555
  # Assert the tag before pushing it. Both checks are one line each and both
502
556
  # have caught a real broken release.
503
- test "$(git rev-parse vX.Y.Z)" = "$(git rev-parse HEAD)" \
504
- || { echo "FAIL: tag is not on HEAD"; exit 1; }
557
+ test "$(git rev-parse vX.Y.Z)" = "$RELEASE_SHA" \
558
+ || { echo "FAIL: tag is not on the tested release commit"; exit 1; }
505
559
  git show --no-patch --format=%s vX.Y.Z | grep -qx "chore: release vX.Y.Z" \
506
560
  || { echo "FAIL: tag is not on the chore: release commit"; exit 1; }
507
561
 
508
- # Push the branch, then the single release tag by its full ref.
509
- git push origin main
562
+ # Push the single release tag by its full ref.
510
563
  git push origin refs/tags/vX.Y.Z
511
564
  ```
512
565
 
566
+ **Why branch CI comes before the tag (v4.30.2 postmortem).** The publish
567
+ workflow runs only on Ubuntu and can publish while the separate macOS matrix job
568
+ is red. `v4.30.2` exposed this with a macOS-only DSH timing failure. A release
569
+ commit must therefore pass the complete Ubuntu/macOS branch workflow before its
570
+ tag exists; a successful publish workflow is not a substitute for green CI.
571
+
513
572
  **Why the assertions (v4.19.0 postmortem).** v4.19.0 was tagged on a commit
514
573
  that contained only a KB document and still carried `package.json` version
515
574
  `4.18.0`; the actual release sat in the commit above it under a recycled
@@ -532,7 +591,7 @@ This triggers `.github/workflows/publish.yml` which:
532
591
 
533
592
  **Provenance is non-negotiable.** If `id-token: write` permission or the `--provenance` flag is missing from `publish.yml`, fix it BEFORE tagging — an unsigned release is a regression against the v2.8.0 standard.
534
593
 
535
- **After CI completes:** Run the [Release Verification SOP](release-verification-sop.md)
594
+ **After CI completes:** Run the [Release Verification SOP](sop-release-verification.md)
536
595
  to smoke-test the published package AND verify the provenance attestation landed on npm.
537
596
 
538
597
  ---
@@ -580,7 +639,9 @@ git push origin --delete vX.Y.Z
580
639
  | 15a | Licensing gate | `npx bats tests/test_licensing.bats` | 7/7 — SPDX headers, LICENSE, NOTICE, npm `files`, manifest consistency |
581
640
  | 16 | Tests | `git add -A kb/` if the KB changed, then `npm test` | All pass |
582
641
  | 17 | Commit | `git commit` | Clean working tree |
583
- | 18 | Tag | `git tag vX.Y.Z` | Tag exists |
584
- | 18a | Tag is on HEAD | `test "$(git rev-parse vX.Y.Z)" = "$(git rev-parse HEAD)"` | Exit 0 |
585
- | 18b | Tag is on the release commit | `git show --no-patch --format=%s vX.Y.Z` | Reads `chore: release vX.Y.Z` |
586
- | 19 | Push branch, then the single tag | `git push origin main && git push origin refs/tags/vX.Y.Z` | CI triggered with `id-token: write`. Never `--tags`. |
642
+ | 18 | Push branch | `git push origin main` | Exact release commit is on `origin/main` |
643
+ | 18a | Full branch CI | `gh run watch "$RUN_ID" --exit-status` plus matrix job assertions | Ubuntu and macOS Bats jobs both conclude `success` |
644
+ | 19 | Tag | `git tag vX.Y.Z` | Tag exists only after green branch CI |
645
+ | 19a | Tag is on tested SHA | `test "$(git rev-parse vX.Y.Z)" = "$RELEASE_SHA"` | Exit 0 |
646
+ | 19b | Tag is on the release commit | `git show --no-patch --format=%s vX.Y.Z` | Reads `chore: release vX.Y.Z` |
647
+ | 20 | Push the single tag | `git push origin refs/tags/vX.Y.Z` | Publish CI triggered with `id-token: write`. Never `--tags`. |
@@ -228,7 +228,7 @@ Three tiers determine how to approach a task:
228
228
  |------|-------|-----------|-------|
229
229
  | Task | `disable-model-invocation: true` | User via `/skill` only | 32 |
230
230
  | Hybrid | (neither) | User via `/skill` + agent knowledge | 31 |
231
- | Knowledge | `user-invocable: false` | Claude auto-loads | 46 |
231
+ | Knowledge | `user-invocable: false` | Claude auto-loads | 51 |
232
232
 
233
233
  ## Multi-Agent Execution
234
234
 
@@ -159,7 +159,7 @@ running the generators directly:
159
159
 
160
160
  - `scripts/generate_copilot.py` / `generate_copilot_hooks.py` contract tests
161
161
  (`tests/test_copilot.bats`, `tests/test_copilot_hooks.bats`).
162
- - Release layout check in `kb/procedures/release-verification-sop.md` asserts the
162
+ - Release layout check in `kb/procedures/sop-release-verification.md` asserts the
163
163
  `.github/{agents,skills,instructions,prompts,hooks}` surfaces.
164
164
  - `validate.py --strict` + `audit_skills.py --ci` in CI.
165
165
 
@@ -131,7 +131,7 @@ MIT remnant would need each contributor's agreement.
131
131
 
132
132
  It is a test rather than a checklist line on purpose. This project has two
133
133
  same-day postmortems about SOPs that existed and were skipped; CI does not skip.
134
- [Release Preparation](../procedures/release-preparation-sop.md) Phase 5c runs the
134
+ [Release Preparation](../procedures/sop-release.md) Phase 5c runs the
135
135
  same gate before tagging so a failure surfaces before the tag, not after.
136
136
 
137
137
  ## If the licence ever changes again
@@ -144,5 +144,5 @@ source, cross-verify against a second independent copy, and only then write
144
144
  ## Related
145
145
 
146
146
  - [`LICENSE`](../../LICENSE), [`NOTICE`](../../NOTICE)
147
- - [Release Preparation SOP](../procedures/release-preparation-sop.md) — Phase 5c
147
+ - [Release Preparation SOP](../procedures/sop-release.md) — Phase 5c
148
148
  - [Distribution Model](distribution-model.md) — what ships and where
@@ -53,7 +53,7 @@ Updated baseline docs:
53
53
  - `kb/reference/skills-catalog.md`
54
54
  - `kb/reference/plugin-pack-conventions.md`
55
55
  - `kb/reference/claude-ecosystem-benchmark-snapshot.md`
56
- - `kb/procedures/maintenance-sop.md`
56
+ - `kb/procedures/sop-maintenance.md`
57
57
 
58
58
  ## Validation Evidence
59
59
 
@@ -285,13 +285,13 @@ See [DSH Compatibility](./dsh-compatibility.md) for commands, topology, subscrip
285
285
  2. Delete its section from this document.
286
286
  3. Delete its snapshot entry from `benchmarks/ecosystem-doctor-snapshot.json` (or let the next `--update` prune it — currently not pruned automatically).
287
287
  4. Decide whether to keep the generator (`scripts/generate_<tool>_*.py`) for backwards compatibility or delete it.
288
- 5. Remove references from `README.md`, `manifest.json` `description` field, and `kb/procedures/maintenance-sop.md` `Supported editors` line.
288
+ 5. Remove references from `README.md`, `manifest.json` `description` field, and `kb/procedures/sop-maintenance.md` `Supported editors` line.
289
289
 
290
290
  ---
291
291
 
292
292
  ## Related
293
293
 
294
- - [Ecosystem Sync SOP](../procedures/ecosystem-sync-sop.md) — how to use the doctor
294
+ - [Ecosystem Sync SOP](../procedures/sop-ecosystem-sync.md) — how to use the doctor
295
295
  - [MCP Editor Compatibility](./mcp-editor-compatibility.md) — MCP-specific subset
296
296
  - `scripts/ecosystem_tools.json` — source of truth
297
297
  - `scripts/ecosystem_doctor.py` — drift detector
@@ -94,4 +94,4 @@ Expect `Total plugin skills loaded: 0`, `Total plugin agents loaded: 0`, and the
94
94
  ## Related
95
95
 
96
96
  - `kb/reference/global-install-model.md`
97
- - `kb/procedures/maintenance-sop.md`
97
+ - `kb/procedures/sop-maintenance.md`