From 71715714efeea44e804152126f25c199a8ffe7fa Mon Sep 17 00:00:00 2001 From: Jonathan Rehem Date: Thu, 13 Aug 2026 23:52:52 -0300 Subject: [PATCH 01/11] feat(release): wire release-please per package with npm publish and initial changelogs --- .github/workflows/release.yml | 81 +++++++++++++++++++ packages/drill/.release-please-manifest.json | 2 +- packages/drill/CHANGELOG.md | 15 ++++ packages/drill/release-please-config.json | 3 +- packages/fob/.release-please-manifest.json | 2 +- packages/fob/CHANGELOG.md | 13 +++ packages/fob/release-please-config.json | 3 +- .../pr-review/.release-please-manifest.json | 2 +- packages/pr-review/CHANGELOG.md | 17 ++++ packages/pr-review/release-please-config.json | 2 +- .../sq-browser/.release-please-manifest.json | 2 +- packages/sq-browser/CHANGELOG.md | 10 +++ packages/sq-browser/package.json | 2 +- .../sq-browser/release-please-config.json | 2 +- packages/sq-gh/.release-please-manifest.json | 2 +- packages/sq-gh/CHANGELOG.md | 10 +++ packages/sq-gh/package.json | 2 +- packages/sq-gh/release-please-config.json | 2 +- .../sq-quota/.release-please-manifest.json | 2 +- packages/sq-quota/CHANGELOG.md | 10 +++ packages/sq-quota/package.json | 2 +- packages/sq-quota/release-please-config.json | 2 +- .../sq-report/.release-please-manifest.json | 2 +- packages/sq-report/CHANGELOG.md | 10 +++ packages/sq-report/release-please-config.json | 2 +- .../sq-tasks/.release-please-manifest.json | 2 +- packages/sq-tasks/CHANGELOG.md | 10 +++ packages/sq-tasks/release-please-config.json | 2 +- 28 files changed, 197 insertions(+), 19 deletions(-) create mode 100644 .github/workflows/release.yml create mode 100644 packages/drill/CHANGELOG.md create mode 100644 packages/fob/CHANGELOG.md create mode 100644 packages/pr-review/CHANGELOG.md create mode 100644 packages/sq-browser/CHANGELOG.md create mode 100644 packages/sq-gh/CHANGELOG.md create mode 100644 packages/sq-quota/CHANGELOG.md create mode 100644 packages/sq-report/CHANGELOG.md create mode 100644 packages/sq-tasks/CHANGELOG.md diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml new file mode 100644 index 00000000..409af851 --- /dev/null +++ b/.github/workflows/release.yml @@ -0,0 +1,81 @@ +name: Release + +# release-please drives one release stream per package (each package has its +# own release-please-config.json + .release-please-manifest.json under +# packages//). On push to main it opens or updates the package's release +# PR; once that PR is merged, the next run detects the merged PR, creates the +# GitHub release and tag (drill-v0.1.1, sq-tasks-v0.1.1, ...), and publishes +# the JS packages to npm. Go binaries (drill, fob) only get releases/tags; +# drill's release is created as a draft per its config so assets can be +# attached before publishing. +# +# npm publishing needs an NPM_TOKEN repository secret (npm auth token for the +# publishing account). Without it the publish step fails loudly on the first +# real release instead of silently skipping. +on: + push: + branches: [main] + workflow_dispatch: + +permissions: + contents: write + issues: write + pull-requests: write + # npm provenance (publishConfig.provenance in pr-review and sq-tasks) + # requires the OIDC id-token from this permission. + id-token: write + +# One stream per package is independent state; the job-level group prevents +# two overlapping runs of the same package on the same ref. + +jobs: + release-please: + name: Release ${{ matrix.package }} + runs-on: ubuntu-latest + concurrency: + group: release-${{ matrix.package }}-${{ github.ref }} + cancel-in-progress: true + strategy: + fail-fast: false + matrix: + package: [drill, fob, pr-review, sq-browser, sq-gh, sq-quota, sq-report, sq-tasks] + steps: + - uses: googleapis/release-please-action@v4 + id: release + with: + config-file: packages/${{ matrix.package }}/release-please-config.json + manifest-file: packages/${{ matrix.package }}/.release-please-manifest.json + - uses: actions/checkout@v6 + if: ${{ steps.release.outputs.releases_created }} + - uses: pnpm/action-setup@v4 + if: ${{ steps.release.outputs.releases_created }} + with: + version: 11.1.1 + - uses: actions/setup-node@v6 + if: ${{ steps.release.outputs.releases_created }} + with: + node-version: 22 + registry-url: https://registry.npmjs.org + - name: Publish to npm + if: ${{ steps.release.outputs.releases_created }} + env: + NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }} + run: | + set -eu + cd "packages/${{ matrix.package }}" + # Go binaries have no package.json; their release is a GitHub + # release/tag only. + if [ ! -f package.json ]; then + echo "No npm package for ${{ matrix.package }} (Go binary); nothing to publish." + exit 0 + fi + # pr-review is a plain source package with no lockfile and no build; + # everything else installs frozen deps and builds (prepack also + # rebuilds as a safety net). + if [ -f pnpm-lock.yaml ]; then + npx -y pnpm@11.1.1 install --frozen-lockfile + npx -y pnpm@11.1.1 run build + fi + # publishConfig in each package.json owns access/public and + # provenance; NODE_AUTH_TOKEN above authenticates the publish. + npm publish diff --git a/packages/drill/.release-please-manifest.json b/packages/drill/.release-please-manifest.json index 466df71c..37d74c12 100644 --- a/packages/drill/.release-please-manifest.json +++ b/packages/drill/.release-please-manifest.json @@ -1,3 +1,3 @@ { - ".": "0.1.0" + "packages/drill": "0.1.0" } diff --git a/packages/drill/CHANGELOG.md b/packages/drill/CHANGELOG.md new file mode 100644 index 00000000..7efa0166 --- /dev/null +++ b/packages/drill/CHANGELOG.md @@ -0,0 +1,15 @@ +# Changelog + +## 0.1.0 (2026-08-14) + +### Features + +* **drill:** rename no-mistakes validation pipeline to drill ([#8](https://github.com/runecraftai/squad/issues/8)) ([7a4b094](https://github.com/runecraftai/squad/commit/7a4b094415ae6b4030e38161d6d39f0a9bca306e)) +* **drill:** session reuse for opencode and pi fixer loops ([#34](https://github.com/runecraftai/squad/issues/34)) ([1eb6619](https://github.com/runecraftai/squad/commit/1eb6619ca9d579d5f133304b8a916561ba549a69)) + +### Bug Fixes + +* **drill:** correct buildinfo ldflags, drop legacy demo media, add flow diagram ([#15](https://github.com/runecraftai/squad/issues/15)) ([d23e1f4](https://github.com/runecraftai/squad/commit/d23e1f4d6df929b546268b911b8189ea93f5bf28)) +* **drill:** tolerate prose and unclosed fences in pi agent output parsing ([#9](https://github.com/runecraftai/squad/issues/9)) ([14f3a2b](https://github.com/runecraftai/squad/commit/14f3a2bb6400680e2b0af5124952c12781b46da9)) +* **drill:** treat prose-only fix rounds as summaries instead of losing fixes ([#35](https://github.com/runecraftai/squad/issues/35)) ([84182c4](https://github.com/runecraftai/squad/commit/84182c427e3d94e4c4028a225d8441d4eb2787e7)) + diff --git a/packages/drill/release-please-config.json b/packages/drill/release-please-config.json index f8a74d2b..718f2a0b 100644 --- a/packages/drill/release-please-config.json +++ b/packages/drill/release-please-config.json @@ -1,7 +1,8 @@ { "packages": { - ".": { + "packages/drill": { "release-type": "go", + "package-name": "drill", "bump-minor-pre-major": true, "bump-patch-for-minor-pre-major": true, "draft": true, diff --git a/packages/fob/.release-please-manifest.json b/packages/fob/.release-please-manifest.json index 466df71c..564ce485 100644 --- a/packages/fob/.release-please-manifest.json +++ b/packages/fob/.release-please-manifest.json @@ -1,3 +1,3 @@ { - ".": "0.1.0" + "packages/fob": "0.1.0" } diff --git a/packages/fob/CHANGELOG.md b/packages/fob/CHANGELOG.md new file mode 100644 index 00000000..79d5ccbf --- /dev/null +++ b/packages/fob/CHANGELOG.md @@ -0,0 +1,13 @@ +# Changelog + +## 0.1.0 (2026-08-14) + +### Features + +* **fob:** build vendored fob from source instead of downloading a pinned release ([#26](https://github.com/runecraftai/squad/issues/26)) ([371ae46](https://github.com/runecraftai/squad/commit/371ae46205224c7358edca73084053be99c7812a)) + +### Bug Fixes + +* **fob:** suppress built-in updater for non-semver builds ([#27](https://github.com/runecraftai/squad/issues/27)) ([aa87f23](https://github.com/runecraftai/squad/commit/aa87f23fe2be4cbb01e0c939932bc7d13b2df286)) +* root .gitignore anchored (/config/ etc.) — generic config/ rule swallowed packages/*/internal/config (16 files never committed); restored fob + no-mistakes internal/config ([507ef99](https://github.com/runecraftai/squad/commit/507ef9984f86b17f396c56ba28da81ebf565e00a)) + diff --git a/packages/fob/release-please-config.json b/packages/fob/release-please-config.json index 4f5b73d3..0423056d 100644 --- a/packages/fob/release-please-config.json +++ b/packages/fob/release-please-config.json @@ -1,7 +1,8 @@ { "packages": { - ".": { + "packages/fob": { "release-type": "go", + "package-name": "fob", "bump-minor-pre-major": true, "bump-patch-for-minor-pre-major": true, "extra-files": [ diff --git a/packages/pr-review/.release-please-manifest.json b/packages/pr-review/.release-please-manifest.json index 466df71c..d2c0aa52 100644 --- a/packages/pr-review/.release-please-manifest.json +++ b/packages/pr-review/.release-please-manifest.json @@ -1,3 +1,3 @@ { - ".": "0.1.0" + "packages/pr-review": "0.1.0" } diff --git a/packages/pr-review/CHANGELOG.md b/packages/pr-review/CHANGELOG.md new file mode 100644 index 00000000..b7c46276 --- /dev/null +++ b/packages/pr-review/CHANGELOG.md @@ -0,0 +1,17 @@ +# Changelog + +## 0.1.0 (2026-08-14) + +### Features + +* vendor M6 toolchain packages and rename tasks-axi to sq-tasks ([#2](https://github.com/runecraftai/squad/issues/2)) ([774b6bf](https://github.com/runecraftai/squad/commit/774b6bf9136d6248715356cefb66e81b1ed4d5d0)) + +### Documentation + +* beautify all 8 package READMEs with project-native designs ([#11](https://github.com/runecraftai/squad/issues/11)) ([81d9f47](https://github.com/runecraftai/squad/commit/81d9f47f8fb80ed50842e05f678436a180154950)) +* **README:** beautify-github-readme skill pass — project-native hero + workflow SVGs (assets/readme/, replace 3MB banner.png), README reordered (proof before claims, quick start up), alt text on all visuals; doc-audience inventory +67 package classifications; site-rooted link exception in doc-audience check; vendored README ROUTING links fixed ([ebb2a98](https://github.com/runecraftai/squad/commit/ebb2a98fa4e083d05e2bfbf3b8c2732795592244)) + +### Miscellaneous Chores + +* reset workspace packages to clean 0.1.0 baseline and unvendor pr-review ([#16](https://github.com/runecraftai/squad/issues/16)) ([fd4f9b9](https://github.com/runecraftai/squad/commit/fd4f9b90d2ded60ff0ee5897057336382c14dcb0)) + diff --git a/packages/pr-review/release-please-config.json b/packages/pr-review/release-please-config.json index 3acdef8e..65e20b5d 100644 --- a/packages/pr-review/release-please-config.json +++ b/packages/pr-review/release-please-config.json @@ -2,7 +2,7 @@ "$schema": "https://raw.githubusercontent.com/googleapis/release-please/main/schemas/config.json", "bootstrap-sha": "b9b62811aab72269b5f2bbb58d08d37b3c20ecff", "packages": { - ".": { + "packages/pr-review": { "release-type": "node", "package-name": "pi-pr-review", "changelog-path": "CHANGELOG.md", diff --git a/packages/sq-browser/.release-please-manifest.json b/packages/sq-browser/.release-please-manifest.json index 466df71c..901b03d7 100644 --- a/packages/sq-browser/.release-please-manifest.json +++ b/packages/sq-browser/.release-please-manifest.json @@ -1,3 +1,3 @@ { - ".": "0.1.0" + "packages/sq-browser": "0.1.0" } diff --git a/packages/sq-browser/CHANGELOG.md b/packages/sq-browser/CHANGELOG.md new file mode 100644 index 00000000..5d490d1b --- /dev/null +++ b/packages/sq-browser/CHANGELOG.md @@ -0,0 +1,10 @@ +# Changelog + +## 0.1.0 (2026-08-14) + +### Features + +* **drill:** rename no-mistakes validation pipeline to drill ([#8](https://github.com/runecraftai/squad/issues/8)) ([7a4b094](https://github.com/runecraftai/squad/commit/7a4b094415ae6b4030e38161d6d39f0a9bca306e)) +* rebrand vendored tool names to sq-* across packages ([#14](https://github.com/runecraftai/squad/issues/14)) ([39bb7bb](https://github.com/runecraftai/squad/commit/39bb7bb60a32f6e8ef8fe276e27a93fac4834cd3)) +* vendor M6 toolchain packages and rename tasks-axi to sq-tasks ([#2](https://github.com/runecraftai/squad/issues/2)) ([774b6bf](https://github.com/runecraftai/squad/commit/774b6bf9136d6248715356cefb66e81b1ed4d5d0)) + diff --git a/packages/sq-browser/package.json b/packages/sq-browser/package.json index ed2a5c59..f3cb7fd5 100644 --- a/packages/sq-browser/package.json +++ b/packages/sq-browser/package.json @@ -36,7 +36,7 @@ "dev": "tsx bin/sq-browser.ts", "test": "vitest run", "test:watch": "vitest", - "prepublishOnly": "npm run build" + "prepack": "npm run build" }, "license": "MIT", "engines": { diff --git a/packages/sq-browser/release-please-config.json b/packages/sq-browser/release-please-config.json index f0cd8453..9c6976d9 100644 --- a/packages/sq-browser/release-please-config.json +++ b/packages/sq-browser/release-please-config.json @@ -3,7 +3,7 @@ "bump-minor-pre-major": true, "bump-patch-for-minor-pre-major": true, "packages": { - ".": { + "packages/sq-browser": { "release-type": "node", "package-name": "sq-browser" } diff --git a/packages/sq-gh/.release-please-manifest.json b/packages/sq-gh/.release-please-manifest.json index 466df71c..f7c0f7ea 100644 --- a/packages/sq-gh/.release-please-manifest.json +++ b/packages/sq-gh/.release-please-manifest.json @@ -1,3 +1,3 @@ { - ".": "0.1.0" + "packages/sq-gh": "0.1.0" } diff --git a/packages/sq-gh/CHANGELOG.md b/packages/sq-gh/CHANGELOG.md new file mode 100644 index 00000000..5d490d1b --- /dev/null +++ b/packages/sq-gh/CHANGELOG.md @@ -0,0 +1,10 @@ +# Changelog + +## 0.1.0 (2026-08-14) + +### Features + +* **drill:** rename no-mistakes validation pipeline to drill ([#8](https://github.com/runecraftai/squad/issues/8)) ([7a4b094](https://github.com/runecraftai/squad/commit/7a4b094415ae6b4030e38161d6d39f0a9bca306e)) +* rebrand vendored tool names to sq-* across packages ([#14](https://github.com/runecraftai/squad/issues/14)) ([39bb7bb](https://github.com/runecraftai/squad/commit/39bb7bb60a32f6e8ef8fe276e27a93fac4834cd3)) +* vendor M6 toolchain packages and rename tasks-axi to sq-tasks ([#2](https://github.com/runecraftai/squad/issues/2)) ([774b6bf](https://github.com/runecraftai/squad/commit/774b6bf9136d6248715356cefb66e81b1ed4d5d0)) + diff --git a/packages/sq-gh/package.json b/packages/sq-gh/package.json index a346bed3..db5a4080 100644 --- a/packages/sq-gh/package.json +++ b/packages/sq-gh/package.json @@ -34,7 +34,7 @@ "test": "vitest run", "test:watch": "vitest", "dev": "tsx bin/sq-gh.ts", - "prepublishOnly": "npm run build" + "prepack": "npm run build" }, "license": "MIT", "engines": { diff --git a/packages/sq-gh/release-please-config.json b/packages/sq-gh/release-please-config.json index cd466e20..a119fbff 100644 --- a/packages/sq-gh/release-please-config.json +++ b/packages/sq-gh/release-please-config.json @@ -3,7 +3,7 @@ "bump-minor-pre-major": true, "bump-patch-for-minor-pre-major": true, "packages": { - ".": { + "packages/sq-gh": { "release-type": "node", "package-name": "sq-gh" } diff --git a/packages/sq-quota/.release-please-manifest.json b/packages/sq-quota/.release-please-manifest.json index 466df71c..8bb1fdd0 100644 --- a/packages/sq-quota/.release-please-manifest.json +++ b/packages/sq-quota/.release-please-manifest.json @@ -1,3 +1,3 @@ { - ".": "0.1.0" + "packages/sq-quota": "0.1.0" } diff --git a/packages/sq-quota/CHANGELOG.md b/packages/sq-quota/CHANGELOG.md new file mode 100644 index 00000000..5d490d1b --- /dev/null +++ b/packages/sq-quota/CHANGELOG.md @@ -0,0 +1,10 @@ +# Changelog + +## 0.1.0 (2026-08-14) + +### Features + +* **drill:** rename no-mistakes validation pipeline to drill ([#8](https://github.com/runecraftai/squad/issues/8)) ([7a4b094](https://github.com/runecraftai/squad/commit/7a4b094415ae6b4030e38161d6d39f0a9bca306e)) +* rebrand vendored tool names to sq-* across packages ([#14](https://github.com/runecraftai/squad/issues/14)) ([39bb7bb](https://github.com/runecraftai/squad/commit/39bb7bb60a32f6e8ef8fe276e27a93fac4834cd3)) +* vendor M6 toolchain packages and rename tasks-axi to sq-tasks ([#2](https://github.com/runecraftai/squad/issues/2)) ([774b6bf](https://github.com/runecraftai/squad/commit/774b6bf9136d6248715356cefb66e81b1ed4d5d0)) + diff --git a/packages/sq-quota/package.json b/packages/sq-quota/package.json index 4bebbf9a..5f83bf62 100644 --- a/packages/sq-quota/package.json +++ b/packages/sq-quota/package.json @@ -51,7 +51,7 @@ "lint": "eslint bin src test scripts", "format": "prettier --write .", "format:check": "prettier --check .", - "prepublishOnly": "npm run build" + "prepack": "npm run build" }, "license": "MIT", "engines": { diff --git a/packages/sq-quota/release-please-config.json b/packages/sq-quota/release-please-config.json index d8e63ca3..a9e612b7 100644 --- a/packages/sq-quota/release-please-config.json +++ b/packages/sq-quota/release-please-config.json @@ -4,7 +4,7 @@ "bump-minor-pre-major": true, "bump-patch-for-minor-pre-major": true, "packages": { - ".": { + "packages/sq-quota": { "release-type": "node", "package-name": "sq-quota" } diff --git a/packages/sq-report/.release-please-manifest.json b/packages/sq-report/.release-please-manifest.json index 466df71c..a4b06cc2 100644 --- a/packages/sq-report/.release-please-manifest.json +++ b/packages/sq-report/.release-please-manifest.json @@ -1,3 +1,3 @@ { - ".": "0.1.0" + "packages/sq-report": "0.1.0" } diff --git a/packages/sq-report/CHANGELOG.md b/packages/sq-report/CHANGELOG.md new file mode 100644 index 00000000..5d490d1b --- /dev/null +++ b/packages/sq-report/CHANGELOG.md @@ -0,0 +1,10 @@ +# Changelog + +## 0.1.0 (2026-08-14) + +### Features + +* **drill:** rename no-mistakes validation pipeline to drill ([#8](https://github.com/runecraftai/squad/issues/8)) ([7a4b094](https://github.com/runecraftai/squad/commit/7a4b094415ae6b4030e38161d6d39f0a9bca306e)) +* rebrand vendored tool names to sq-* across packages ([#14](https://github.com/runecraftai/squad/issues/14)) ([39bb7bb](https://github.com/runecraftai/squad/commit/39bb7bb60a32f6e8ef8fe276e27a93fac4834cd3)) +* vendor M6 toolchain packages and rename tasks-axi to sq-tasks ([#2](https://github.com/runecraftai/squad/issues/2)) ([774b6bf](https://github.com/runecraftai/squad/commit/774b6bf9136d6248715356cefb66e81b1ed4d5d0)) + diff --git a/packages/sq-report/release-please-config.json b/packages/sq-report/release-please-config.json index d72d6c93..6c06be97 100644 --- a/packages/sq-report/release-please-config.json +++ b/packages/sq-report/release-please-config.json @@ -3,7 +3,7 @@ "bump-minor-pre-major": true, "bump-patch-for-minor-pre-major": true, "packages": { - ".": { + "packages/sq-report": { "release-type": "node", "package-name": "sq-report", "extra-files": [ diff --git a/packages/sq-tasks/.release-please-manifest.json b/packages/sq-tasks/.release-please-manifest.json index 466df71c..1897e5ed 100644 --- a/packages/sq-tasks/.release-please-manifest.json +++ b/packages/sq-tasks/.release-please-manifest.json @@ -1,3 +1,3 @@ { - ".": "0.1.0" + "packages/sq-tasks": "0.1.0" } diff --git a/packages/sq-tasks/CHANGELOG.md b/packages/sq-tasks/CHANGELOG.md new file mode 100644 index 00000000..5d490d1b --- /dev/null +++ b/packages/sq-tasks/CHANGELOG.md @@ -0,0 +1,10 @@ +# Changelog + +## 0.1.0 (2026-08-14) + +### Features + +* **drill:** rename no-mistakes validation pipeline to drill ([#8](https://github.com/runecraftai/squad/issues/8)) ([7a4b094](https://github.com/runecraftai/squad/commit/7a4b094415ae6b4030e38161d6d39f0a9bca306e)) +* rebrand vendored tool names to sq-* across packages ([#14](https://github.com/runecraftai/squad/issues/14)) ([39bb7bb](https://github.com/runecraftai/squad/commit/39bb7bb60a32f6e8ef8fe276e27a93fac4834cd3)) +* vendor M6 toolchain packages and rename tasks-axi to sq-tasks ([#2](https://github.com/runecraftai/squad/issues/2)) ([774b6bf](https://github.com/runecraftai/squad/commit/774b6bf9136d6248715356cefb66e81b1ed4d5d0)) + diff --git a/packages/sq-tasks/release-please-config.json b/packages/sq-tasks/release-please-config.json index 7da37bc0..f4917fba 100644 --- a/packages/sq-tasks/release-please-config.json +++ b/packages/sq-tasks/release-please-config.json @@ -3,7 +3,7 @@ "bump-minor-pre-major": true, "bump-patch-for-minor-pre-major": true, "packages": { - ".": { + "packages/sq-tasks": { "release-type": "node", "package-name": "sq-tasks" } From ffce0838e9bf3b146bbb2714e6c9f40d5fe1d7d9 Mon Sep 17 00:00:00 2001 From: Jonathan Rehem Date: Fri, 14 Aug 2026 01:46:51 -0300 Subject: [PATCH 02/11] drill(review): Fix npm publish skip guard and pr-review manifest key --- .github/workflows/release.yml | 6 +++--- packages/pr-review/scripts/verify-release-version.mjs | 2 +- packages/pr-review/tests/release-version.test.ts | 4 ++-- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 409af851..56d3eae1 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -63,9 +63,9 @@ jobs: run: | set -eu cd "packages/${{ matrix.package }}" - # Go binaries have no package.json; their release is a GitHub - # release/tag only. - if [ ! -f package.json ]; then + # Go binaries and private workspace stubs have no npm distribution; + # their release is a GitHub release/tag only. + if [ ! -f package.json ] || node -e "process.exit(require('./package.json').private ? 0 : 1)"; then echo "No npm package for ${{ matrix.package }} (Go binary); nothing to publish." exit 0 fi diff --git a/packages/pr-review/scripts/verify-release-version.mjs b/packages/pr-review/scripts/verify-release-version.mjs index 3e117748..59b3d0b6 100644 --- a/packages/pr-review/scripts/verify-release-version.mjs +++ b/packages/pr-review/scripts/verify-release-version.mjs @@ -30,7 +30,7 @@ export function verifyRootReleaseVersion(rootDir = process.cwd(), expectedVersio const manifest = readJson(path.join(rootDir, ".release-please-manifest.json")); const packageJson = readJson(path.join(rootDir, "package.json")); const versions = { - '.release-please-manifest.json["."]': manifest["."], + '.release-please-manifest.json["packages/pr-review"]': manifest["packages/pr-review"], "package.json.version": packageJson.version, }; diff --git a/packages/pr-review/tests/release-version.test.ts b/packages/pr-review/tests/release-version.test.ts index 99fa7d61..9566b73d 100644 --- a/packages/pr-review/tests/release-version.test.ts +++ b/packages/pr-review/tests/release-version.test.ts @@ -14,7 +14,7 @@ const tempDirs: string[] = []; function writeVersionFiles(versions: VersionFiles = {}): string { const dir = fs.mkdtempSync(path.join(os.tmpdir(), "pi-pr-review-release-version-test-")); tempDirs.push(dir); - fs.writeFileSync(path.join(dir, ".release-please-manifest.json"), JSON.stringify({ ".": versions.manifest ?? "1.2.3" })); + fs.writeFileSync(path.join(dir, ".release-please-manifest.json"), JSON.stringify({ "packages/pr-review": versions.manifest ?? "1.2.3" })); fs.writeFileSync(path.join(dir, "package.json"), JSON.stringify({ version: versions.packageJson ?? "1.2.3" })); return dir; } @@ -41,7 +41,7 @@ describe("root release-version invariant", () => { test("rejects missing or malformed root versions", () => { const missing = fs.mkdtempSync(path.join(os.tmpdir(), "pi-pr-review-release-version-test-")); tempDirs.push(missing); - fs.writeFileSync(path.join(missing, ".release-please-manifest.json"), JSON.stringify({ ".": "1.2.3" })); + fs.writeFileSync(path.join(missing, ".release-please-manifest.json"), JSON.stringify({ "packages/pr-review": "1.2.3" })); fs.writeFileSync(path.join(missing, "package.json"), JSON.stringify({})); expect(() => verifyRootReleaseVersion(missing)).toThrow(/valid semantic version/); expect(() => verifyRootReleaseVersion(writeVersionFiles({ packageJson: "not-a-version" }))).toThrow(/valid semantic version/); From a72a4f86af55ff3409ba6df9b526fc51aceee4d2 Mon Sep 17 00:00:00 2001 From: Jonathan Rehem Date: Fri, 14 Aug 2026 01:56:05 -0300 Subject: [PATCH 03/11] drill(review): Update drill/fob tests to re-keyed packages/drill and packages/fob --- packages/drill/workflow_release_test.go | 8 ++++---- packages/fob/release_ci_exclusions_test.go | 6 +++++- 2 files changed, 9 insertions(+), 5 deletions(-) diff --git a/packages/drill/workflow_release_test.go b/packages/drill/workflow_release_test.go index 3cb2e96d..3b82c7c8 100644 --- a/packages/drill/workflow_release_test.go +++ b/packages/drill/workflow_release_test.go @@ -105,9 +105,9 @@ func TestReleasePleaseConfigCreatesDrafts(t *testing.T) { if err := json.Unmarshal(data, &cfg); err != nil { t.Fatalf("parse config: %v", err) } - pkg, ok := cfg.Packages["."] + pkg, ok := cfg.Packages["packages/drill"] if !ok { - t.Fatalf("release-please config missing '.' package") + t.Fatalf("release-please config missing 'packages/drill' package") } if !pkg.Draft { t.Fatalf("release-please must create releases as drafts; partial releases would otherwise be marked latest before binaries are uploaded") @@ -127,9 +127,9 @@ func TestReleasePleaseConfigForcesTagCreation(t *testing.T) { if err := json.Unmarshal(data, &cfg); err != nil { t.Fatalf("parse config: %v", err) } - pkg, ok := cfg.Packages["."] + pkg, ok := cfg.Packages["packages/drill"] if !ok { - t.Fatalf("release-please config missing '.' package") + t.Fatalf("release-please config missing 'packages/drill' package") } if !pkg.ForceTagCreation { t.Fatalf("release-please config must force tag creation so an existing GitHub release cannot silently prevent the tag from being recreated") diff --git a/packages/fob/release_ci_exclusions_test.go b/packages/fob/release_ci_exclusions_test.go index c3eee494..434fa16b 100644 --- a/packages/fob/release_ci_exclusions_test.go +++ b/packages/fob/release_ci_exclusions_test.go @@ -84,6 +84,10 @@ func expectedReleaseOutputs(cfg releasePleaseConfig) ([]string, error) { if extra == "" { continue } + if pkgPath != "." && pkgPath != "" && !strings.Contains(extra, "/") && !strings.HasPrefix(extra, "!") { + seen[filepath.ToSlash(filepath.Join(pkgPath, extra))] = struct{}{} + continue + } seen[filepath.ToSlash(extra)] = struct{}{} } } @@ -356,7 +360,7 @@ func TestExpectedReleaseOutputsIncludesConfiguredExtraFiles(t *testing.T) { if err != nil { t.Fatal(err) } - want := []string{".release-please-manifest.json", "CHANGELOG.md", "flake.nix"} + want := []string{".release-please-manifest.json", "packages/fob/CHANGELOG.md", "packages/fob/flake.nix"} if strings.Join(got, ",") != strings.Join(want, ",") { t.Fatalf("expected %v, got %v", want, got) } From 088ad35ca5475ddb4be71aeec71e2c60f7ab6b3a Mon Sep 17 00:00:00 2001 From: Jonathan Rehem Date: Fri, 14 Aug 2026 02:08:47 -0300 Subject: [PATCH 04/11] drill(review): Fix sq-report test key, drill/fob path filters, pr-review repository --- packages/drill/.github/workflows/ci.yml | 2 +- packages/drill/.github/workflows/drill-required.yml | 2 +- packages/drill/.github/workflows/guard-generated-files.yml | 6 +++--- packages/fob/.github/workflows/ci.yml | 4 ++-- packages/pr-review/package.json | 4 ++++ packages/sq-report/test/package-json.test.js | 2 +- 6 files changed, 12 insertions(+), 8 deletions(-) diff --git a/packages/drill/.github/workflows/ci.yml b/packages/drill/.github/workflows/ci.yml index 363079d7..f57559e1 100644 --- a/packages/drill/.github/workflows/ci.yml +++ b/packages/drill/.github/workflows/ci.yml @@ -9,7 +9,7 @@ on: # no run is created at all. push/tag/release triggers are unaffected. paths-ignore: - .release-please-manifest.json - - CHANGELOG.md + - packages/drill/CHANGELOG.md jobs: check: diff --git a/packages/drill/.github/workflows/drill-required.yml b/packages/drill/.github/workflows/drill-required.yml index 2d6d3469..3c73291b 100644 --- a/packages/drill/.github/workflows/drill-required.yml +++ b/packages/drill/.github/workflows/drill-required.yml @@ -11,7 +11,7 @@ on: # run is created in action_required and never starts. paths-ignore: - .release-please-manifest.json - - CHANGELOG.md + - packages/drill/CHANGELOG.md permissions: contents: read diff --git a/packages/drill/.github/workflows/guard-generated-files.yml b/packages/drill/.github/workflows/guard-generated-files.yml index d5201722..153605cd 100644 --- a/packages/drill/.github/workflows/guard-generated-files.yml +++ b/packages/drill/.github/workflows/guard-generated-files.yml @@ -10,7 +10,7 @@ on: # run is created in action_required and never starts. paths-ignore: - .release-please-manifest.json - - CHANGELOG.md + - packages/drill/CHANGELOG.md permissions: contents: read @@ -44,7 +44,7 @@ jobs: files=$(git diff --name-only "${BASE_SHA}...${HEAD_SHA}") violated="" - for path in CHANGELOG.md .release-please-manifest.json; do + for path in packages/drill/CHANGELOG.md .release-please-manifest.json; do if printf '%s\n' "$files" | grep -qxF -- "$path"; then violated="${violated} ${path}" fi @@ -54,7 +54,7 @@ jobs: { echo "::error::This PR modifies release-please-generated files:${violated}" echo - echo "CHANGELOG.md and .release-please-manifest.json are auto-generated by" + echo "packages/drill/CHANGELOG.md and .release-please-manifest.json are auto-generated by" echo "release-please from conventional commits on main. Do not hand-edit them." echo echo "If you want your change to appear in the next release notes, use a" diff --git a/packages/fob/.github/workflows/ci.yml b/packages/fob/.github/workflows/ci.yml index 52918291..56dacddd 100644 --- a/packages/fob/.github/workflows/ci.yml +++ b/packages/fob/.github/workflows/ci.yml @@ -10,8 +10,8 @@ on: branches: [main] paths-ignore: - .release-please-manifest.json - - CHANGELOG.md - - flake.nix + - packages/fob/CHANGELOG.md + - packages/fob/flake.nix jobs: check: diff --git a/packages/pr-review/package.json b/packages/pr-review/package.json index 6c8d9a5d..c77b3ea3 100644 --- a/packages/pr-review/package.json +++ b/packages/pr-review/package.json @@ -26,6 +26,10 @@ "developer-tools" ], "license": "MIT", + "repository": { + "type": "git", + "url": "git+https://github.com/runecraftai/squad.git" + }, "engines": { "node": ">=20" }, diff --git a/packages/sq-report/test/package-json.test.js b/packages/sq-report/test/package-json.test.js index 5f98b448..12e5d023 100644 --- a/packages/sq-report/test/package-json.test.js +++ b/packages/sq-report/test/package-json.test.js @@ -42,7 +42,7 @@ test("published package root is a complete Agent Plugin", async () => { test("release-please keeps the plugin manifest version in step with the package", async () => { const config = JSON.parse(await readFile(new URL("../release-please-config.json", import.meta.url), "utf8")); - assert.deepEqual(config.packages["."]["extra-files"], [{ type: "json", path: "plugin.json", jsonpath: "$.version" }]); + assert.deepEqual(config.packages["packages/sq-report"]["extra-files"], [{ type: "json", path: "plugin.json", jsonpath: "$.version" }]); }); test("lavish-design agent skill is marked internal for skills CLI discovery", async () => { From abaed4b7a61a12fe848998a7793c5e9e9a87a65a Mon Sep 17 00:00:00 2001 From: Jonathan Rehem Date: Fri, 14 Aug 2026 02:21:37 -0300 Subject: [PATCH 05/11] drill(review): Ignore package-relative release manifests in drill/fob workflows and tests --- packages/drill/.github/workflows/ci.yml | 2 +- .../drill/.github/workflows/drill-required.yml | 2 +- .../.github/workflows/guard-generated-files.yml | 6 +++--- .../workflow_release_pr_ci_exclusions_test.go | 7 +++++-- packages/fob/.github/workflows/ci.yml | 2 +- packages/fob/release_ci_exclusions_test.go | 15 ++++++++++----- 6 files changed, 21 insertions(+), 13 deletions(-) diff --git a/packages/drill/.github/workflows/ci.yml b/packages/drill/.github/workflows/ci.yml index f57559e1..aa906060 100644 --- a/packages/drill/.github/workflows/ci.yml +++ b/packages/drill/.github/workflows/ci.yml @@ -8,7 +8,7 @@ on: # action_required and never start; excluding the exact release-output set means # no run is created at all. push/tag/release triggers are unaffected. paths-ignore: - - .release-please-manifest.json + - packages/drill/.release-please-manifest.json - packages/drill/CHANGELOG.md jobs: diff --git a/packages/drill/.github/workflows/drill-required.yml b/packages/drill/.github/workflows/drill-required.yml index 3c73291b..4a0bce28 100644 --- a/packages/drill/.github/workflows/drill-required.yml +++ b/packages/drill/.github/workflows/drill-required.yml @@ -10,7 +10,7 @@ on: # below cannot do this: it is evaluated inside a run, and a GITHUB_TOKEN PR's # run is created in action_required and never starts. paths-ignore: - - .release-please-manifest.json + - packages/drill/.release-please-manifest.json - packages/drill/CHANGELOG.md permissions: diff --git a/packages/drill/.github/workflows/guard-generated-files.yml b/packages/drill/.github/workflows/guard-generated-files.yml index 153605cd..3f00b224 100644 --- a/packages/drill/.github/workflows/guard-generated-files.yml +++ b/packages/drill/.github/workflows/guard-generated-files.yml @@ -9,7 +9,7 @@ on: # below cannot do this: it is evaluated inside a run, and a GITHUB_TOKEN PR's # run is created in action_required and never starts. paths-ignore: - - .release-please-manifest.json + - packages/drill/.release-please-manifest.json - packages/drill/CHANGELOG.md permissions: @@ -44,7 +44,7 @@ jobs: files=$(git diff --name-only "${BASE_SHA}...${HEAD_SHA}") violated="" - for path in packages/drill/CHANGELOG.md .release-please-manifest.json; do + for path in packages/drill/CHANGELOG.md packages/drill/.release-please-manifest.json; do if printf '%s\n' "$files" | grep -qxF -- "$path"; then violated="${violated} ${path}" fi @@ -54,7 +54,7 @@ jobs: { echo "::error::This PR modifies release-please-generated files:${violated}" echo - echo "packages/drill/CHANGELOG.md and .release-please-manifest.json are auto-generated by" + echo "packages/drill/CHANGELOG.md and packages/drill/.release-please-manifest.json are auto-generated by" echo "release-please from conventional commits on main. Do not hand-edit them." echo echo "If you want your change to appear in the next release notes, use a" diff --git a/packages/drill/workflow_release_pr_ci_exclusions_test.go b/packages/drill/workflow_release_pr_ci_exclusions_test.go index 637259c8..269f9aa4 100644 --- a/packages/drill/workflow_release_pr_ci_exclusions_test.go +++ b/packages/drill/workflow_release_pr_ci_exclusions_test.go @@ -92,13 +92,16 @@ func expectedReleasePleaseOutputs(t *testing.T) []string { seen[path] = struct{}{} out = append(out, path) } - add(".release-please-manifest.json") - for pkgPath, pkg := range cfg.Packages { prefix := "" if pkgPath != "." { prefix = strings.TrimSuffix(pkgPath, "/") + "/" } + // The manifest for a package's release stream lives next to its + // config (packages//.release-please-manifest.json), where + // release.yml points manifest-file; root-keyed configs keep the + // root manifest path. + add(prefix + ".release-please-manifest.json") switch pkg.ReleaseType { case "go", "simple", "rust", "python", "elixir", "terraform-module": add(prefix + "CHANGELOG.md") diff --git a/packages/fob/.github/workflows/ci.yml b/packages/fob/.github/workflows/ci.yml index 56dacddd..ebf9f82a 100644 --- a/packages/fob/.github/workflows/ci.yml +++ b/packages/fob/.github/workflows/ci.yml @@ -9,7 +9,7 @@ on: pull_request: branches: [main] paths-ignore: - - .release-please-manifest.json + - packages/fob/.release-please-manifest.json - packages/fob/CHANGELOG.md - packages/fob/flake.nix diff --git a/packages/fob/release_ci_exclusions_test.go b/packages/fob/release_ci_exclusions_test.go index 434fa16b..a96b0a71 100644 --- a/packages/fob/release_ci_exclusions_test.go +++ b/packages/fob/release_ci_exclusions_test.go @@ -33,12 +33,17 @@ func expectedReleaseOutputs(cfg releasePleaseConfig) ([]string, error) { return nil, fmt.Errorf("release-please-config.json has no packages") } - seen := map[string]struct{}{ - // Manifest is always written for multi and single-package configs. - ".release-please-manifest.json": {}, - } + seen := map[string]struct{}{} for pkgPath, pkg := range cfg.Packages { + // Manifest is always written for multi and single-package configs; + // per-package streams keep it next to their config. + manifest := ".release-please-manifest.json" + if pkgPath != "." && pkgPath != "" { + manifest = filepath.ToSlash(filepath.Join(pkgPath, ".release-please-manifest.json")) + } + seen[manifest] = struct{}{} + // CHANGELOG.md lives at the package root (repo root for "."). changelog := "CHANGELOG.md" if pkgPath != "." && pkgPath != "" { @@ -360,7 +365,7 @@ func TestExpectedReleaseOutputsIncludesConfiguredExtraFiles(t *testing.T) { if err != nil { t.Fatal(err) } - want := []string{".release-please-manifest.json", "packages/fob/CHANGELOG.md", "packages/fob/flake.nix"} + want := []string{"packages/fob/.release-please-manifest.json", "packages/fob/CHANGELOG.md", "packages/fob/flake.nix"} if strings.Join(got, ",") != strings.Join(want, ",") { t.Fatalf("expected %v, got %v", want, got) } From b4f168a2b4b89964317c7edc0adb9e11830b27c1 Mon Sep 17 00:00:00 2001 From: Jonathan Rehem Date: Fri, 14 Aug 2026 02:27:06 -0300 Subject: [PATCH 06/11] drill(review): Update sq-report exclusion test to packages/sq-report config key --- packages/sq-report/test/release-ci-exclusions.test.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/sq-report/test/release-ci-exclusions.test.js b/packages/sq-report/test/release-ci-exclusions.test.js index 35bf3a63..1a3b37aa 100644 --- a/packages/sq-report/test/release-ci-exclusions.test.js +++ b/packages/sq-report/test/release-ci-exclusions.test.js @@ -15,7 +15,7 @@ const workflowsDir = join(root, ".github", "workflows"); */ function expectedReleaseOutputs() { const config = JSON.parse(readFileSync(join(root, "release-please-config.json"), "utf8")); - const pkg = config.packages?.["."] ?? {}; + const pkg = config.packages?.["packages/sq-report"] ?? {}; const releaseType = pkg["release-type"] ?? config["release-type"] ?? "node"; const changelog = pkg["changelog-path"] ?? config["changelog-path"] ?? "CHANGELOG.md"; From 613c5a43ec8b651eff0be19c934979db5c025408 Mon Sep 17 00:00:00 2001 From: Jonathan Rehem Date: Fri, 14 Aug 2026 02:56:37 -0300 Subject: [PATCH 07/11] drill(document): docs: sync release pipeline docs and audience inventory --- docs/documentation-audiences.json | 32 ++++++ packages/drill/AGENTS.md | 2 +- packages/pr-review/RELEASING.md | 178 ++---------------------------- packages/sq-gh/AGENTS.md | 3 +- packages/sq-quota/AGENTS.md | 8 +- packages/sq-quota/CONTRIBUTING.md | 2 +- packages/sq-tasks/AGENTS.md | 5 +- 7 files changed, 53 insertions(+), 177 deletions(-) diff --git a/docs/documentation-audiences.json b/docs/documentation-audiences.json index 97ec6c1a..302fb89e 100644 --- a/docs/documentation-audiences.json +++ b/docs/documentation-audiences.json @@ -496,6 +496,10 @@ "path": "packages/fob/AGENTS.md", "audience": "maintainer-architecture" }, + { + "path": "packages/fob/CHANGELOG.md", + "audience": "public-product" + }, { "path": "packages/fob/CLAUDE.md", "audience": "maintainer-architecture" @@ -516,6 +520,10 @@ "path": "packages/drill/AGENTS.md", "audience": "maintainer-architecture" }, + { + "path": "packages/drill/CHANGELOG.md", + "audience": "public-product" + }, { "path": "packages/drill/CLAUDE.md", "audience": "maintainer-architecture" @@ -632,6 +640,10 @@ "path": "packages/drill/skills/drill/SKILL.md", "audience": "agent-runtime" }, + { + "path": "packages/pr-review/CHANGELOG.md", + "audience": "public-product" + }, { "path": "packages/pr-review/README.md", "audience": "public-product" @@ -648,6 +660,10 @@ "path": "packages/sq-browser/AGENTS.md", "audience": "maintainer-architecture" }, + { + "path": "packages/sq-browser/CHANGELOG.md", + "audience": "public-product" + }, { "path": "packages/sq-browser/CLAUDE.md", "audience": "maintainer-architecture" @@ -672,6 +688,10 @@ "path": "packages/sq-gh/AGENTS.md", "audience": "maintainer-architecture" }, + { + "path": "packages/sq-gh/CHANGELOG.md", + "audience": "public-product" + }, { "path": "packages/sq-gh/CLAUDE.md", "audience": "maintainer-architecture" @@ -696,6 +716,10 @@ "path": "packages/sq-quota/AGENTS.md", "audience": "maintainer-architecture" }, + { + "path": "packages/sq-quota/CHANGELOG.md", + "audience": "public-product" + }, { "path": "packages/sq-quota/CLAUDE.md", "audience": "maintainer-architecture" @@ -728,6 +752,10 @@ "path": "packages/sq-report/AGENTS.md", "audience": "maintainer-architecture" }, + { + "path": "packages/sq-report/CHANGELOG.md", + "audience": "public-product" + }, { "path": "packages/sq-report/CLAUDE.md", "audience": "maintainer-architecture" @@ -760,6 +788,10 @@ "path": "packages/sq-tasks/AGENTS.md", "audience": "maintainer-architecture" }, + { + "path": "packages/sq-tasks/CHANGELOG.md", + "audience": "public-product" + }, { "path": "packages/sq-tasks/CLAUDE.md", "audience": "maintainer-architecture" diff --git a/packages/drill/AGENTS.md b/packages/drill/AGENTS.md index 76a6f6d1..35432ece 100644 --- a/packages/drill/AGENTS.md +++ b/packages/drill/AGENTS.md @@ -232,7 +232,7 @@ Safest local verification sequence after non-trivial changes: - The executable identifier `com.squad.drill` is the permanent Developer ID identity and MUST NEVER change: it is the invariant of the identity-based designated requirement that lets macOS permission grants survive `drill update`, so changing it resets every grant once. The Team ID `SQ00000000` is an explicit placeholder that MUST be replaced with the real Apple Developer Team ID before the first public signed release. - Signing runs only in the darwin build job gated behind the `release-signing` GitHub environment; the certificate is the base64 `CSC_LINK` secret unlocked with `CSC_KEY_PASSWORD`, imported into an ephemeral keychain with a runtime-generated password that is deleted on success and failure, and no other job may reference those secrets. - Signing happens before tarball creation and checksum generation, and the verify gate fails the release closed on any missing or ambiguous signature, wrong Team ID, non-permanent identifier, content-based (`cdhash`) requirement, missing hardened runtime or timestamp, or wrong architecture. -- Mechanics live in `.github/workflows/release.yml`; the contract is pinned by the root `TestReleaseWorkflow*` static tests in `workflow_release_signing_test.go`, and secret values are never recorded here or in any test fixture. +- Mechanics live in `packages/drill/.github/workflows/release.yml` (the repo-root `release.yml` is the monorepo release-please pipeline, a different workflow); the contract is pinned by the root `TestReleaseWorkflow*` static tests in `workflow_release_signing_test.go`, and secret values are never recorded here or in any test fixture. - Notarization, stapling, a PKG, Homebrew, and universal binaries are intentionally out of scope for this phase. **When Making Changes** diff --git a/packages/pr-review/RELEASING.md b/packages/pr-review/RELEASING.md index 6691fce8..1e7dd1ac 100644 --- a/packages/pr-review/RELEASING.md +++ b/packages/pr-review/RELEASING.md @@ -1,172 +1,10 @@ # Release operations -This runbook covers activation, normal operation, recovery, and emergency shutdown for the `pi-pr-review` npm release pipeline. GitHub tags, GitHub releases, workflow artifacts, and npm versions are immutable release records; never move, reuse, or replace them. - -## Security boundaries - -`.github/workflows/release-please.yml` denies permissions by default and uses four jobs: - -| Job | Environment | Permissions | Purpose | -| --- | --- | --- | --- | -| `release` | `release-automation` | `contents: read` for `github.token` | Reads the environment-scoped App key, creates a short-lived repository installation token, and runs Release Please. | -| `validate` | none | `contents: read` | Checks the exact tag and `main` ancestry before running source, sets up pinned Node and Bun releases without installing project dependencies, then runs all tests and package/workflow policy checks. | -| `package` | none | `contents: read` | Uses a fresh runner and exact tag checkout. It installs nothing and runs no repository script; it creates one `npm pack --ignore-scripts` tarball and uploads it by unique artifact ID. | -| `publish` | `npm-publish` | `actions: read`, `id-token: write` | Checks out no source, runs no repository code, verifies the exact current-run tarball, rechecks npm state, and publishes through OIDC. | - -The App private key and npm OIDC permission never coexist with project execution. The publish job accepts only the artifact ID and digests emitted by the fresh package job, and it independently checks the archive paths, package metadata, Pi entry points, lifecycle-script policy, package version, and SHA-256. - -All jobs require these repository variables to equal the exact lowercase value `true`: - -- `NPM_TRUSTED_PUBLISHING_READY` -- `RELEASE_AUTOMATION_ENABLED` - -An absent or different value closes the gate. Keep both variables absent throughout rollout. - -## One-time activation - -### 1. Protect GitHub environments - -Create both environments with selected deployment branches restricted to branch `main` only. Tags and unrestricted deployment policies are not allowed. - -For `release-automation`: - -- Store `NERV_OPS_PRIVATE_KEY` only as an environment secret. -- Store the App Client ID as the repository variable `NERV_OPS_CLIENT_ID`. The Client ID is an identifier, not a secret. -- Do not configure an approval gate that could block routine Release Please operation. - -For `npm-publish`: - -- Store no secrets. -- Use the environment name as part of the npm trusted-publisher identity. -- With the current single-operator model, do not enable prevent-self-review or required reviewers. Add an independent reviewer and backup only when those people actually exist. - -### 2. Scope the GitHub App - -The private `nerv-ops` App should be installed only on intended repositories and have only: - -- Contents: read and write -- Pull requests: read and write -- Metadata: read-only, required by GitHub - -Do not grant Actions, Administration, Environments, Secrets, or Workflows permissions. Do not allow the App to bypass `main` protection. The workflow omits `owner` and `repositories` when creating the token, so the resulting installation token is scoped to the current repository. - -Upload the existing active App private key without putting it in a shell argument or repository file: - -```bash -gh secret set NERV_OPS_PRIVATE_KEY \ - --repo 10ego/pi-pr-review \ - --env release-automation \ - < /secure/path/to/nerv-ops-private-key.pem -``` - -After the environment secret is confirmed and release authentication is validated, delete the repository-level secret with the same name. Do not rotate or revoke the still-active key solely for this migration. - -### 3. Bind npm trusted publishing - -In the npm settings for `pi-pr-review`, configure the GitHub Actions trusted publisher with exactly: - -```text -Owner: 10ego -Repository: pi-pr-review -Workflow: release-please.yml -Environment: npm-publish -``` - -Do not configure `NPM_TOKEN` or another token fallback. Keep npm account 2FA enabled and remove unused automation tokens. - -### 4. Protect release tags - -Protect tags matching `v*` against updates and deletion, and enable immutable GitHub releases when available. Release Please must be able to create a new tag, but neither operators nor the App should be able to move an existing release tag. - -### 5. Verify configuration before opening gates - -Use name-only checks; never print the private key: - -```bash -gh secret list --repo 10ego/pi-pr-review -gh secret list --repo 10ego/pi-pr-review --env release-automation -gh secret list --repo 10ego/pi-pr-review --env npm-publish -gh api repos/10ego/pi-pr-review/environments/release-automation -gh api repos/10ego/pi-pr-review/environments/npm-publish -npm view pi-pr-review version dist-tags --json -``` - -Confirm: - -- `main` still requires `Validate PR title` and `Test`, including for administrators. -- Both environments admit only `main`. -- The App key appears only in `release-automation`. -- `npm-publish` contains no secrets. -- npm names the exact workflow and `npm-publish` environment. -- Every workflow action is pinned to an approved full commit SHA. -- `bun test`, `npm run test:tooling`, `npm run verify:release-version`, `npm run verify:package`, `npm run verify:workflows`, and Actionlint pass on `main`. - -### 6. Open gates in order - -Set npm readiness first: - -```bash -gh variable set NPM_TRUSTED_PUBLISHING_READY \ - --repo 10ego/pi-pr-review \ - --body true -``` - -After one final configuration review, enable automation: - -```bash -gh variable set RELEASE_AUTOMATION_ENABLED \ - --repo 10ego/pi-pr-review \ - --body true -``` - -A variable change does not cancel a workflow already running. Cancel unsafe or stale runs separately. - -## Normal releases - -1. A conventional squash commit lands on `main`. -2. `release` enters `release-automation`, creates a one-hour repository-scoped App token, and creates or updates the Release Please PR. -3. Required checks hold the release PR until it is safe to auto-merge with squash. -4. The release PR merge synchronizes the root package version, changelog, and release manifest. -5. A subsequent Release Please run creates the exact `v` tag and non-draft GitHub release. -6. `validate` verifies the tag before running code, tests the release, and checks npm availability. -7. `package` creates and uploads one fresh lifecycle-script-disabled tarball. -8. `publish` verifies the current-run artifact, rechecks that the exact version is absent and the selected dist-tag advances, then publishes with npm provenance. - -Stable versions explicitly update `latest`; prereleases explicitly update `next`. A normal run fails if the exact npm version already exists. - -## Recovery publication - -Recovery is only for an existing non-draft GitHub release whose npm publication did not complete. Inspect the release and dispatch from `main`: - -```bash -gh release view v1.8.0 \ - --repo 10ego/pi-pr-review \ - --json tagName,isDraft,targetCommitish - -gh workflow run .github/workflows/release-please.yml \ - --repo 10ego/pi-pr-review \ - --ref main \ - -f tag=v1.8.0 -``` - -Recovery skips the App-key environment, verifies the release with read-only `github.token`, and performs all normal validation, packaging, and publication checks. If npm already contains the exact version, recovery succeeds as a no-op. - -Never recover by moving a tag, drafting a replacement release, rebuilding an existing npm version, or uploading a manually repacked artifact. - -## Emergency shutdown - -Close automation immediately by deleting or changing `RELEASE_AUTOMATION_ENABLED`: - -```bash -gh variable delete RELEASE_AUTOMATION_ENABLED --repo 10ego/pi-pr-review -``` - -Close `NPM_TRUSTED_PUBLISHING_READY` as well if npm OIDC or the trusted-publisher identity is suspect. Cancel active workflow runs and revoke the App key if GitHub credentials may be exposed. Restore npm readiness first and release automation last only after all prerequisites are revalidated. - -## Maintenance - -- Update pinned Actions through reviewed pull requests and update the workflow policy allowlist in the same change. -- Run package inspection only with `--ignore-scripts`. -- Add no package install, pack, prepare, or publish lifecycle scripts without a new security review. -- Update the package file policy when adding a new published component path. -- Treat a changed artifact digest, moved tag, npm integrity mismatch, or unexpected dist-tag as a security incident rather than a reason to bypass a check. +`@runecraft/pr-review` ships from the Squad monorepo (runecraftai/squad), not from a standalone `pi-pr-review` repository. +Releases are cut by the monorepo release-please pipeline, which is the single owner of release mechanics: the repo-root `.github/workflows/release.yml` runs one release stream per package, driven by `packages/pr-review/release-please-config.json` and `packages/pr-review/.release-please-manifest.json`, and writes `packages/pr-review/CHANGELOG.md`. +Merging the bot's release PR creates the GitHub release and tag (bare `v` because `include-component-in-tag` is `false`) and publishes the package to npm with the `NPM_TOKEN` repository secret. +The `NPM_TOKEN` secret was still missing from the repository as of 2026-08-14, so no publish has happened yet; the first release requires the commander's approval and the secret. +GitHub tags, GitHub releases, workflow artifacts, and npm versions are immutable release records; never move, reuse, or replace them. + +The runbook that previously lived in this file described the upstream `10ego/pi-pr-review` pipeline (nerv-ops App, npm OIDC trusted publisher, `NPM_TRUSTED_PUBLISHING_READY`/`RELEASE_AUTOMATION_ENABLED` variables, GitHub environments). +That pipeline belongs to the upstream repository and does not apply here; do not recreate it in this repository. diff --git a/packages/sq-gh/AGENTS.md b/packages/sq-gh/AGENTS.md index a745c740..8c6a7a1e 100644 --- a/packages/sq-gh/AGENTS.md +++ b/packages/sq-gh/AGENTS.md @@ -19,7 +19,8 @@ The SDK also appends a `"built-in":` section to the top-level `--help` output at ## Release process -Releases are cut by release-please from conventional commit messages on `main`; merging the bot's release PR triggers `npm publish` via `.github/workflows/release-please.yml`. +Releases are cut by release-please from conventional commit messages on `main`. +The monorepo `.github/workflows/release.yml` runs one release stream per package (`packages/sq-gh/release-please-config.json` + `.release-please-manifest.json`), and merging the bot's release PR triggers `npm publish` with the `NPM_TOKEN` secret. Do not hand-edit `CHANGELOG.md` or `.release-please-manifest.json` (a guard workflow blocks PRs that touch them), and regenerate `skills/sq-gh/SKILL.md` with `pnpm run build:skill` instead of editing it directly. Every `pull_request` workflow (`ci.yml`, `guard-generated-files.yml`, `drill-required.yml`) uses `paths-ignore` for the release-please output set (`.release-please-manifest.json`, `CHANGELOG.md`, `package.json`) so release PRs create zero runs. Job-level bot `if`s stay as defense in depth. `test/release-ci-exclusions.test.ts` derives that set from `release-please-config.json` and fails if a workflow drifts; update the ignore lists when adding `extra-files` or changing `release-type`. diff --git a/packages/sq-quota/AGENTS.md b/packages/sq-quota/AGENTS.md index dc601312..94d6cfcc 100644 --- a/packages/sq-quota/AGENTS.md +++ b/packages/sq-quota/AGENTS.md @@ -54,9 +54,11 @@ pnpm run build:skill -- --check ## Release process -Releases are cut by release-please from conventional commit messages on `main`; merging the bot's release PR triggers `npm publish` via `.github/workflows/release-please.yml`, using npm's OIDC trusted-publisher flow (`id-token: write` + `--provenance`), not an `NPM_TOKEN` secret. -`.release-please-manifest.json` is primed at `0.1.0`, the version already published to npm by hand before release-please was wired up; release-please owns every version after that. -`release-please-config.json` intentionally sets `bootstrap-sha` to `9f5dc949c50ab8ac0a441be777e1c3693ee0b612`, the commit that produced the already-published npm `0.1.0`; do not retarget it to later scaffolding commits unless the published baseline itself is being corrected. +Releases are cut by release-please from conventional commit messages on `main`. +The monorepo `.github/workflows/release.yml` runs one release stream per package (`packages/sq-quota/release-please-config.json` + `.release-please-manifest.json`), and merging the bot's release PR triggers `npm publish` with the `NPM_TOKEN` secret. +`.release-please-manifest.json` is primed at `0.1.0`, matching the package version. +Nothing has been published to npm yet (`sq-quota` is free on npm), so the first publish happens only after the commander approves and the `NPM_TOKEN` secret exists; release-please owns every version after that. +`release-please-config.json` keeps the `bootstrap-sha` inherited from the vendored upstream config (`9f5dc949c50ab8ac0a441be777e1c3693ee0b612`, a commit outside this repo's history); do not retarget it to later scaffolding commits unless the published baseline itself is being corrected. Do not hand-edit `CHANGELOG.md` or `.release-please-manifest.json` (a guard workflow blocks PRs that touch them), and regenerate `skills/sq-quota/SKILL.md` with `pnpm run build:skill` instead of editing it directly (`pnpm run build:skill -- --check` in CI fails if it drifts from `src/skill.ts`). Every `pull_request` workflow must `paths-ignore` the release-please output set (`.release-please-manifest.json`, `CHANGELOG.md`, `package.json`) so release PRs create zero runs; `test/release-ci-exclusions.test.ts` derives that set from `release-please-config.json` and fails if a workflow drifts. diff --git a/packages/sq-quota/CONTRIBUTING.md b/packages/sq-quota/CONTRIBUTING.md index 6a762ccd..d080f577 100644 --- a/packages/sq-quota/CONTRIBUTING.md +++ b/packages/sq-quota/CONTRIBUTING.md @@ -42,7 +42,7 @@ See the [drill quick start](https://github.com/runecraftai/squad) for the full f - Do not bump `package.json`'s `version` by hand for ordinary changes. release-please updates it in the release PR. - Do not change `release-please-config.json`'s `bootstrap-sha` for ordinary changes. - It points at commit `9f5dc949c50ab8ac0a441be777e1c3693ee0b612`, the published npm `0.1.0` baseline. + It is inherited from the vendored upstream config (commit `9f5dc949c50ab8ac0a441be777e1c3693ee0b612`, outside this repo's history). - Do not hand-edit `skills/sq-quota/SKILL.md`. It is generated from the shared skill source, including frontmatter metadata; run `pnpm run build:skill` and commit the result. - sq-quota is data only: it must never route, recommend, proxy, intercept, log in, import browser cookies, or mutate provider state. Keep changes within that boundary. diff --git a/packages/sq-tasks/AGENTS.md b/packages/sq-tasks/AGENTS.md index 8af1caab..c79f5f7a 100644 --- a/packages/sq-tasks/AGENTS.md +++ b/packages/sq-tasks/AGENTS.md @@ -82,7 +82,10 @@ Any argv shape other than exactly one version flag falls through to `runAxiCli`, ### Release & packaging (mirrors the `*-axi` siblings) -- **Published to npm as a public package** via `release-please` → `npm publish --access public --provenance` on a release commit (`.github/workflows/release-please.yml`); the commander can also `npm publish` manually. Conventional commits drive the version bump; `release-please-config.json` + `.release-please-manifest.json` own versioning and `CHANGELOG.md`. +- **Published to npm as a public package** on a release commit. + The monorepo `.github/workflows/release.yml` runs one release stream per package, and merging the bot's release PR triggers `npm publish` with the `NPM_TOKEN` secret (provenance stays enabled through `publishConfig`). + The commander can also `npm publish` manually. + Conventional commits drive the version bump; `release-please-config.json` + `.release-please-manifest.json` own versioning and `CHANGELOG.md`. - Every `pull_request` workflow (`ci.yml`, `guard-generated-files.yml`, `drill-required.yml`) uses `paths-ignore` for the release-please output set (`.release-please-manifest.json`, `CHANGELOG.md`, `package.json`) so release PRs create zero runs. Job-level bot `if`s stay as defense in depth. `test/release-ci-exclusions.test.ts` derives that set from `release-please-config.json` and fails if a workflow drifts; update the ignore lists when adding `extra-files` or changing `release-type`. - **The tarball ships runtime JS only.** `package.json` `files` is `dist/**/*.js` (+ `skills/sq-tasks`, `LICENSE`, `README.md`), so the `.d.ts`/`.js.map` that `tsc` emits for local debugging are kept out of the package. `prepack` runs `npm run build`, so `npm pack`/`npm publish` always rebuild `dist` first. From 0b6dea787d6d415c592eb23d2a28f55134aca902 Mon Sep 17 00:00:00 2001 From: Jonathan Rehem Date: Fri, 14 Aug 2026 07:07:52 -0300 Subject: [PATCH 08/11] docs: rewrite package changelog entries in product language and redesign sq-tasks hero Rewrite the initial 0.1.0 entries in 7 package changelogs so they read as product feature/fix history (install from source, tool suite additions, sq-* naming) instead of vendor transitions, keeping real dates and commit links. Redesign the sq-tasks hero: replace the unit-patch star and the order-of-battle/diamond marker with a completed-task product mark and a source-of-truth header. --- packages/fob/CHANGELOG.md | 2 +- packages/pr-review/CHANGELOG.md | 6 +++--- packages/sq-browser/CHANGELOG.md | 4 ++-- packages/sq-gh/CHANGELOG.md | 4 ++-- packages/sq-quota/CHANGELOG.md | 4 ++-- packages/sq-report/CHANGELOG.md | 4 ++-- packages/sq-tasks/CHANGELOG.md | 4 ++-- packages/sq-tasks/assets/readme/hero.svg | 17 +++++++---------- 8 files changed, 21 insertions(+), 24 deletions(-) diff --git a/packages/fob/CHANGELOG.md b/packages/fob/CHANGELOG.md index 79d5ccbf..46923b31 100644 --- a/packages/fob/CHANGELOG.md +++ b/packages/fob/CHANGELOG.md @@ -4,7 +4,7 @@ ### Features -* **fob:** build vendored fob from source instead of downloading a pinned release ([#26](https://github.com/runecraftai/squad/issues/26)) ([371ae46](https://github.com/runecraftai/squad/commit/371ae46205224c7358edca73084053be99c7812a)) +* **fob:** build fob from source at install time, reporting an accurate version from the source tree ([#26](https://github.com/runecraftai/squad/issues/26)) ([371ae46](https://github.com/runecraftai/squad/commit/371ae46205224c7358edca73084053be99c7812a)) ### Bug Fixes diff --git a/packages/pr-review/CHANGELOG.md b/packages/pr-review/CHANGELOG.md index b7c46276..850820b1 100644 --- a/packages/pr-review/CHANGELOG.md +++ b/packages/pr-review/CHANGELOG.md @@ -4,14 +4,14 @@ ### Features -* vendor M6 toolchain packages and rename tasks-axi to sq-tasks ([#2](https://github.com/runecraftai/squad/issues/2)) ([774b6bf](https://github.com/runecraftai/squad/commit/774b6bf9136d6248715356cefb66e81b1ed4d5d0)) +* add the sq-* companion tools: sq-browser, sq-gh, sq-quota, sq-report, and sq-tasks ([#2](https://github.com/runecraftai/squad/issues/2)) ([774b6bf](https://github.com/runecraftai/squad/commit/774b6bf9136d6248715356cefb66e81b1ed4d5d0)) ### Documentation * beautify all 8 package READMEs with project-native designs ([#11](https://github.com/runecraftai/squad/issues/11)) ([81d9f47](https://github.com/runecraftai/squad/commit/81d9f47f8fb80ed50842e05f678436a180154950)) -* **README:** beautify-github-readme skill pass — project-native hero + workflow SVGs (assets/readme/, replace 3MB banner.png), README reordered (proof before claims, quick start up), alt text on all visuals; doc-audience inventory +67 package classifications; site-rooted link exception in doc-audience check; vendored README ROUTING links fixed ([ebb2a98](https://github.com/runecraftai/squad/commit/ebb2a98fa4e083d05e2bfbf3b8c2732795592244)) +* **README:** beautify-github-readme skill pass - project-native hero + workflow SVGs (assets/readme/, replace 3MB banner.png), README reordered (proof before claims, quick start up), alt text on all visuals; doc-audience inventory +67 package classifications; site-rooted link exception in doc-audience check; README ROUTING links fixed ([ebb2a98](https://github.com/runecraftai/squad/commit/ebb2a98fa4e083d05e2bfbf3b8c2732795592244)) ### Miscellaneous Chores -* reset workspace packages to clean 0.1.0 baseline and unvendor pr-review ([#16](https://github.com/runecraftai/squad/issues/16)) ([fd4f9b9](https://github.com/runecraftai/squad/commit/fd4f9b90d2ded60ff0ee5897057336382c14dcb0)) +* reset workspace packages to a clean 0.1.0 baseline and ship pr-review as a standalone maintained package ([#16](https://github.com/runecraftai/squad/issues/16)) ([fd4f9b9](https://github.com/runecraftai/squad/commit/fd4f9b90d2ded60ff0ee5897057336382c14dcb0)) diff --git a/packages/sq-browser/CHANGELOG.md b/packages/sq-browser/CHANGELOG.md index 5d490d1b..4948f288 100644 --- a/packages/sq-browser/CHANGELOG.md +++ b/packages/sq-browser/CHANGELOG.md @@ -5,6 +5,6 @@ ### Features * **drill:** rename no-mistakes validation pipeline to drill ([#8](https://github.com/runecraftai/squad/issues/8)) ([7a4b094](https://github.com/runecraftai/squad/commit/7a4b094415ae6b4030e38161d6d39f0a9bca306e)) -* rebrand vendored tool names to sq-* across packages ([#14](https://github.com/runecraftai/squad/issues/14)) ([39bb7bb](https://github.com/runecraftai/squad/commit/39bb7bb60a32f6e8ef8fe276e27a93fac4834cd3)) -* vendor M6 toolchain packages and rename tasks-axi to sq-tasks ([#2](https://github.com/runecraftai/squad/issues/2)) ([774b6bf](https://github.com/runecraftai/squad/commit/774b6bf9136d6248715356cefb66e81b1ed4d5d0)) +* rename tool names to their sq-* names across packages ([#14](https://github.com/runecraftai/squad/issues/14)) ([39bb7bb](https://github.com/runecraftai/squad/commit/39bb7bb60a32f6e8ef8fe276e27a93fac4834cd3)) +* add sq-browser: a Chrome session your agent can drive from the terminal ([#2](https://github.com/runecraftai/squad/issues/2)) ([774b6bf](https://github.com/runecraftai/squad/commit/774b6bf9136d6248715356cefb66e81b1ed4d5d0)) diff --git a/packages/sq-gh/CHANGELOG.md b/packages/sq-gh/CHANGELOG.md index 5d490d1b..209fa502 100644 --- a/packages/sq-gh/CHANGELOG.md +++ b/packages/sq-gh/CHANGELOG.md @@ -5,6 +5,6 @@ ### Features * **drill:** rename no-mistakes validation pipeline to drill ([#8](https://github.com/runecraftai/squad/issues/8)) ([7a4b094](https://github.com/runecraftai/squad/commit/7a4b094415ae6b4030e38161d6d39f0a9bca306e)) -* rebrand vendored tool names to sq-* across packages ([#14](https://github.com/runecraftai/squad/issues/14)) ([39bb7bb](https://github.com/runecraftai/squad/commit/39bb7bb60a32f6e8ef8fe276e27a93fac4834cd3)) -* vendor M6 toolchain packages and rename tasks-axi to sq-tasks ([#2](https://github.com/runecraftai/squad/issues/2)) ([774b6bf](https://github.com/runecraftai/squad/commit/774b6bf9136d6248715356cefb66e81b1ed4d5d0)) +* rename tool names to their sq-* names across packages ([#14](https://github.com/runecraftai/squad/issues/14)) ([39bb7bb](https://github.com/runecraftai/squad/commit/39bb7bb60a32f6e8ef8fe276e27a93fac4834cd3)) +* add sq-gh: the GitHub CLI rebuilt for agents, with token-efficient output and next-step hints ([#2](https://github.com/runecraftai/squad/issues/2)) ([774b6bf](https://github.com/runecraftai/squad/commit/774b6bf9136d6248715356cefb66e81b1ed4d5d0)) diff --git a/packages/sq-quota/CHANGELOG.md b/packages/sq-quota/CHANGELOG.md index 5d490d1b..9750f613 100644 --- a/packages/sq-quota/CHANGELOG.md +++ b/packages/sq-quota/CHANGELOG.md @@ -5,6 +5,6 @@ ### Features * **drill:** rename no-mistakes validation pipeline to drill ([#8](https://github.com/runecraftai/squad/issues/8)) ([7a4b094](https://github.com/runecraftai/squad/commit/7a4b094415ae6b4030e38161d6d39f0a9bca306e)) -* rebrand vendored tool names to sq-* across packages ([#14](https://github.com/runecraftai/squad/issues/14)) ([39bb7bb](https://github.com/runecraftai/squad/commit/39bb7bb60a32f6e8ef8fe276e27a93fac4834cd3)) -* vendor M6 toolchain packages and rename tasks-axi to sq-tasks ([#2](https://github.com/runecraftai/squad/issues/2)) ([774b6bf](https://github.com/runecraftai/squad/commit/774b6bf9136d6248715356cefb66e81b1ed4d5d0)) +* rename tool names to their sq-* names across packages ([#14](https://github.com/runecraftai/squad/issues/14)) ([39bb7bb](https://github.com/runecraftai/squad/commit/39bb7bb60a32f6e8ef8fe276e27a93fac4834cd3)) +* add sq-quota: local agent-provider quota windows, reported in one call ([#2](https://github.com/runecraftai/squad/issues/2)) ([774b6bf](https://github.com/runecraftai/squad/commit/774b6bf9136d6248715356cefb66e81b1ed4d5d0)) diff --git a/packages/sq-report/CHANGELOG.md b/packages/sq-report/CHANGELOG.md index 5d490d1b..33e3a85c 100644 --- a/packages/sq-report/CHANGELOG.md +++ b/packages/sq-report/CHANGELOG.md @@ -5,6 +5,6 @@ ### Features * **drill:** rename no-mistakes validation pipeline to drill ([#8](https://github.com/runecraftai/squad/issues/8)) ([7a4b094](https://github.com/runecraftai/squad/commit/7a4b094415ae6b4030e38161d6d39f0a9bca306e)) -* rebrand vendored tool names to sq-* across packages ([#14](https://github.com/runecraftai/squad/issues/14)) ([39bb7bb](https://github.com/runecraftai/squad/commit/39bb7bb60a32f6e8ef8fe276e27a93fac4834cd3)) -* vendor M6 toolchain packages and rename tasks-axi to sq-tasks ([#2](https://github.com/runecraftai/squad/issues/2)) ([774b6bf](https://github.com/runecraftai/squad/commit/774b6bf9136d6248715356cefb66e81b1ed4d5d0)) +* rename tool names to their sq-* names across packages ([#14](https://github.com/runecraftai/squad/issues/14)) ([39bb7bb](https://github.com/runecraftai/squad/commit/39bb7bb60a32f6e8ef8fe276e27a93fac4834cd3)) +* add sq-report: a review surface for agent-generated HTML artifacts ([#2](https://github.com/runecraftai/squad/issues/2)) ([774b6bf](https://github.com/runecraftai/squad/commit/774b6bf9136d6248715356cefb66e81b1ed4d5d0)) diff --git a/packages/sq-tasks/CHANGELOG.md b/packages/sq-tasks/CHANGELOG.md index 5d490d1b..92cbef4d 100644 --- a/packages/sq-tasks/CHANGELOG.md +++ b/packages/sq-tasks/CHANGELOG.md @@ -5,6 +5,6 @@ ### Features * **drill:** rename no-mistakes validation pipeline to drill ([#8](https://github.com/runecraftai/squad/issues/8)) ([7a4b094](https://github.com/runecraftai/squad/commit/7a4b094415ae6b4030e38161d6d39f0a9bca306e)) -* rebrand vendored tool names to sq-* across packages ([#14](https://github.com/runecraftai/squad/issues/14)) ([39bb7bb](https://github.com/runecraftai/squad/commit/39bb7bb60a32f6e8ef8fe276e27a93fac4834cd3)) -* vendor M6 toolchain packages and rename tasks-axi to sq-tasks ([#2](https://github.com/runecraftai/squad/issues/2)) ([774b6bf](https://github.com/runecraftai/squad/commit/774b6bf9136d6248715356cefb66e81b1ed4d5d0)) +* rename tool names to their sq-* names across packages ([#14](https://github.com/runecraftai/squad/issues/14)) ([39bb7bb](https://github.com/runecraftai/squad/commit/39bb7bb60a32f6e8ef8fe276e27a93fac4834cd3)) +* add sq-tasks: a markdown backlog that stays human-editable while agents work it ([#2](https://github.com/runecraftai/squad/issues/2)) ([774b6bf](https://github.com/runecraftai/squad/commit/774b6bf9136d6248715356cefb66e81b1ed4d5d0)) diff --git a/packages/sq-tasks/assets/readme/hero.svg b/packages/sq-tasks/assets/readme/hero.svg index b224f56d..7561fa2a 100644 --- a/packages/sq-tasks/assets/readme/hero.svg +++ b/packages/sq-tasks/assets/readme/hero.svg @@ -1,8 +1,8 @@ - sq-tasks: an operations board task backlog that stays human-editable while agents work it - A backlog.md document shows queued and done tasks with checkboxes; a band below proves the byte-exact round-trip: render(parse(src)) equals src. + sq-tasks: an operations board that stays human-editable while agents work it + A backlog.md document shows queued and done tasks with checkboxes, headed source of truth; a band below proves the byte-exact round-trip: render(parse(src)) equals src. @@ -13,10 +13,10 @@ - - - - + + + + @@ -32,10 +32,7 @@ backlog.md - order of battle - - - + source of truth From 09059c3ef4996b2e82e7d0eb686d60170969751b Mon Sep 17 00:00:00 2001 From: Jonathan Rehem Date: Fri, 14 Aug 2026 07:46:06 -0300 Subject: [PATCH 09/11] drill(review): Fix bootstrap-sha and re-key sq-* release exclusion guards --- packages/drill/release-please-config.json | 1 + packages/fob/release-please-config.json | 1 + packages/pr-review/release-please-config.json | 2 +- packages/sq-browser/.github/workflows/ci.yml | 6 +-- .../.github/workflows/drill-required.yml | 6 +-- .../workflows/guard-generated-files.yml | 10 ++-- packages/sq-browser/AGENTS.md | 2 +- .../sq-browser/release-please-config.json | 1 + .../test/release-ci-exclusions.test.ts | 46 ++++++++++++------- packages/sq-gh/.github/workflows/ci.yml | 6 +-- .../.github/workflows/drill-required.yml | 6 +-- .../workflows/guard-generated-files.yml | 10 ++-- packages/sq-gh/AGENTS.md | 2 +- packages/sq-gh/release-please-config.json | 1 + .../sq-gh/test/release-ci-exclusions.test.ts | 40 ++++++++++------ packages/sq-quota/.github/workflows/ci.yml | 6 +-- .../.github/workflows/drill-required.yml | 6 +-- .../workflows/guard-generated-files.yml | 10 ++-- packages/sq-quota/AGENTS.md | 4 +- packages/sq-quota/CONTRIBUTING.md | 2 +- packages/sq-quota/release-please-config.json | 2 +- .../test/release-ci-exclusions.test.ts | 40 ++++++++++------ packages/sq-report/.github/workflows/ci.yml | 8 ++-- .../.github/workflows/drill-required.yml | 8 ++-- .../workflows/guard-generated-files.yml | 12 ++--- packages/sq-report/release-please-config.json | 1 + .../test/release-ci-exclusions.test.js | 39 ++++++++++------ packages/sq-tasks/.github/workflows/ci.yml | 6 +-- .../.github/workflows/drill-required.yml | 6 +-- .../workflows/guard-generated-files.yml | 6 +-- packages/sq-tasks/AGENTS.md | 2 +- packages/sq-tasks/release-please-config.json | 1 + .../sq-tasks/scripts/guard-generated-files.sh | 6 +-- .../test/release-ci-exclusions.test.ts | 40 ++++++++++------ .../workflows/guard-generated-files.test.ts | 25 ++++++---- 35 files changed, 221 insertions(+), 149 deletions(-) diff --git a/packages/drill/release-please-config.json b/packages/drill/release-please-config.json index 718f2a0b..4fb64c91 100644 --- a/packages/drill/release-please-config.json +++ b/packages/drill/release-please-config.json @@ -1,4 +1,5 @@ { + "bootstrap-sha": "71715714efeea44e804152126f25c199a8ffe7fa", "packages": { "packages/drill": { "release-type": "go", diff --git a/packages/fob/release-please-config.json b/packages/fob/release-please-config.json index 0423056d..4ab0e8b5 100644 --- a/packages/fob/release-please-config.json +++ b/packages/fob/release-please-config.json @@ -1,4 +1,5 @@ { + "bootstrap-sha": "71715714efeea44e804152126f25c199a8ffe7fa", "packages": { "packages/fob": { "release-type": "go", diff --git a/packages/pr-review/release-please-config.json b/packages/pr-review/release-please-config.json index 65e20b5d..3071a08a 100644 --- a/packages/pr-review/release-please-config.json +++ b/packages/pr-review/release-please-config.json @@ -1,6 +1,6 @@ { "$schema": "https://raw.githubusercontent.com/googleapis/release-please/main/schemas/config.json", - "bootstrap-sha": "b9b62811aab72269b5f2bbb58d08d37b3c20ecff", + "bootstrap-sha": "71715714efeea44e804152126f25c199a8ffe7fa", "packages": { "packages/pr-review": { "release-type": "node", diff --git a/packages/sq-browser/.github/workflows/ci.yml b/packages/sq-browser/.github/workflows/ci.yml index 70a35a47..78f9fe8b 100644 --- a/packages/sq-browser/.github/workflows/ci.yml +++ b/packages/sq-browser/.github/workflows/ci.yml @@ -9,9 +9,9 @@ on: # pull_request run that can only sit in action_required. Its output set is # exactly these files, so excluding them means no run is ever created. paths-ignore: - - .release-please-manifest.json - - CHANGELOG.md - - package.json + - packages/sq-browser/.release-please-manifest.json + - packages/sq-browser/CHANGELOG.md + - packages/sq-browser/package.json jobs: build-and-test: diff --git a/packages/sq-browser/.github/workflows/drill-required.yml b/packages/sq-browser/.github/workflows/drill-required.yml index cc7df178..b53e5644 100644 --- a/packages/sq-browser/.github/workflows/drill-required.yml +++ b/packages/sq-browser/.github/workflows/drill-required.yml @@ -10,9 +10,9 @@ on: # below cannot do this: it is evaluated inside a run, and a GITHUB_TOKEN PR's # run is created in action_required and never starts. paths-ignore: - - .release-please-manifest.json - - CHANGELOG.md - - package.json + - packages/sq-browser/.release-please-manifest.json + - packages/sq-browser/CHANGELOG.md + - packages/sq-browser/package.json permissions: contents: read diff --git a/packages/sq-browser/.github/workflows/guard-generated-files.yml b/packages/sq-browser/.github/workflows/guard-generated-files.yml index 313346b4..3448e12b 100644 --- a/packages/sq-browser/.github/workflows/guard-generated-files.yml +++ b/packages/sq-browser/.github/workflows/guard-generated-files.yml @@ -9,9 +9,9 @@ on: # below cannot do this: it is evaluated inside a run, and a GITHUB_TOKEN PR's # run is created in action_required and never starts. paths-ignore: - - .release-please-manifest.json - - CHANGELOG.md - - package.json + - packages/sq-browser/.release-please-manifest.json + - packages/sq-browser/CHANGELOG.md + - packages/sq-browser/package.json permissions: contents: read @@ -45,7 +45,7 @@ jobs: files=$(git diff --name-only "${BASE_SHA}...${HEAD_SHA}") violated="" - for path in CHANGELOG.md .release-please-manifest.json; do + for path in packages/sq-browser/CHANGELOG.md packages/sq-browser/.release-please-manifest.json; do if printf '%s\n' "$files" | grep -qxF -- "$path"; then violated="${violated} ${path}" fi @@ -55,7 +55,7 @@ jobs: { echo "::error::This PR modifies release-please-generated files:${violated}" echo - echo "CHANGELOG.md and .release-please-manifest.json are auto-generated by" + echo "packages/sq-browser/CHANGELOG.md and packages/sq-browser/.release-please-manifest.json are auto-generated by" echo "release-please from conventional commits on main. Do not hand-edit them." echo echo "If you want your change to appear in the next release notes, use a" diff --git a/packages/sq-browser/AGENTS.md b/packages/sq-browser/AGENTS.md index be39d107..508fbc77 100644 --- a/packages/sq-browser/AGENTS.md +++ b/packages/sq-browser/AGENTS.md @@ -25,7 +25,7 @@ Its frontmatter includes Hermes Agent metadata from `src/skill.ts`; update the g - Tests live in `test/*.test.ts` and run with Vitest. - Run `pnpm run build` and `pnpm test` before pushing. - Do not hand-edit generated files: `CHANGELOG.md` and `.release-please-manifest.json` (owned by release-please) or `skills/sq-browser/SKILL.md` (owned by `build:skill`). -- Every `pull_request` workflow (`ci.yml`, `guard-generated-files.yml`, `drill-required.yml`) uses `paths-ignore` for the release-please output set (`.release-please-manifest.json`, `CHANGELOG.md`, `package.json`) so release PRs create zero runs. Job-level bot `if`s stay as defense in depth. `test/release-ci-exclusions.test.ts` derives that set from `release-please-config.json` and fails if a workflow drifts; update the ignore lists when adding `extra-files` or changing `release-type`. +- Every `pull_request` workflow (`ci.yml`, `guard-generated-files.yml`, `drill-required.yml`) uses `paths-ignore` for the release-please output set (`packages/sq-browser/.release-please-manifest.json`, `packages/sq-browser/CHANGELOG.md`, `packages/sq-browser/package.json`) so release PRs create zero runs. Job-level bot `if`s stay as defense in depth. `test/release-ci-exclusions.test.ts` derives that set from `release-please-config.json` and fails if a workflow drifts; update the ignore lists when adding `extra-files` or changing `release-type`. - Generated files are listed in `.prettierignore`; validate them with their generator checks instead of formatting them directly. - Keep `skills/sq-browser/` in the npm `files` list when changing package contents; the skill-first install path depends on it shipping with the package. - `pnpm-workspace.yaml` enforces a minimum release age for dependency updates as a supply-chain guard; `axi-sdk-js` and `sq-browser` are exempt. diff --git a/packages/sq-browser/release-please-config.json b/packages/sq-browser/release-please-config.json index 9c6976d9..83921276 100644 --- a/packages/sq-browser/release-please-config.json +++ b/packages/sq-browser/release-please-config.json @@ -1,5 +1,6 @@ { "$schema": "https://raw.githubusercontent.com/googleapis/release-please/main/schemas/config.json", + "bootstrap-sha": "71715714efeea44e804152126f25c199a8ffe7fa", "bump-minor-pre-major": true, "bump-patch-for-minor-pre-major": true, "packages": { diff --git a/packages/sq-browser/test/release-ci-exclusions.test.ts b/packages/sq-browser/test/release-ci-exclusions.test.ts index 6f484b96..f6f0a495 100644 --- a/packages/sq-browser/test/release-ci-exclusions.test.ts +++ b/packages/sq-browser/test/release-ci-exclusions.test.ts @@ -31,22 +31,31 @@ function expectedReleaseOutputs(): string[] { } >; }; - const pkg = config.packages?.["."] ?? {}; + const pkgKey = "packages/sq-browser"; + const pkg = config.packages?.[pkgKey]; + if (!pkg) { + throw new Error( + `release-please-config.json has no "${pkgKey}" package entry`, + ); + } + const prefix = `${pkgKey}/`; const releaseType = pkg["release-type"] ?? config["release-type"] ?? "node"; const changelog = - pkg["changelog-path"] ?? config["changelog-path"] ?? "CHANGELOG.md"; + prefix + + (pkg["changelog-path"] ?? config["changelog-path"] ?? "CHANGELOG.md"); const expected: string[] = [changelog]; switch (releaseType) { case "simple": expected.push( - pkg["version-file"] ?? config["version-file"] ?? "version.txt", + prefix + + (pkg["version-file"] ?? config["version-file"] ?? "version.txt"), ); break; case "node": - expected.push("package.json"); + expected.push(prefix + "package.json"); if (existsSync(join(root, "package-lock.json"))) { - expected.push("package-lock.json"); + expected.push(prefix + "package-lock.json"); } break; case "go": @@ -60,16 +69,19 @@ function expectedReleaseOutputs(): string[] { const extra = pkg["extra-files"] ?? config["extra-files"] ?? []; for (const entry of extra) { const path = typeof entry === "string" ? entry : entry?.path; - if (path) expected.push(path); + if (path) expected.push(path.includes("/") ? path : prefix + path); } - let manifest = ".release-please-manifest.json"; + let manifest = prefix + ".release-please-manifest.json"; const releaseWorkflow = readFileSync( join(workflowsDir, "release-please.yml"), "utf8", ); const manifestMatch = releaseWorkflow.match(/manifest-file:\s*(\S+)/); - if (manifestMatch) manifest = manifestMatch[1]; + if (manifestMatch) { + const configured = manifestMatch[1]; + manifest = configured.includes("/") ? configured : prefix + configured; + } expected.push(manifest); return [...new Set(expected)]; @@ -169,16 +181,16 @@ function allPathsIgnored(ignorePatterns: string[], paths: string[]): boolean { describe("release-please CI exclusions", () => { const expected = expectedReleaseOutputs(); const ignoreSet = [ - ".release-please-manifest.json", - "CHANGELOG.md", - "package.json", + "packages/sq-browser/.release-please-manifest.json", + "packages/sq-browser/CHANGELOG.md", + "packages/sq-browser/package.json", ]; it("derives the node release-output set for this repository", () => { expect(expected).toEqual([ - "CHANGELOG.md", - "package.json", - ".release-please-manifest.json", + "packages/sq-browser/CHANGELOG.md", + "packages/sq-browser/package.json", + "packages/sq-browser/.release-please-manifest.json", ]); }); @@ -245,9 +257,9 @@ describe("release-please CI exclusions", () => { it("offline filter: latest release PR file set is fully ignored", () => { // sq-browser #90 (release 0.1.28) - exact observed release-output set. const releasePrFiles = [ - ".release-please-manifest.json", - "CHANGELOG.md", - "package.json", + "packages/sq-browser/.release-please-manifest.json", + "packages/sq-browser/CHANGELOG.md", + "packages/sq-browser/package.json", ]; expect(allPathsIgnored(ignoreSet, releasePrFiles)).toBe(true); }); diff --git a/packages/sq-gh/.github/workflows/ci.yml b/packages/sq-gh/.github/workflows/ci.yml index 70a35a47..79a83d7a 100644 --- a/packages/sq-gh/.github/workflows/ci.yml +++ b/packages/sq-gh/.github/workflows/ci.yml @@ -9,9 +9,9 @@ on: # pull_request run that can only sit in action_required. Its output set is # exactly these files, so excluding them means no run is ever created. paths-ignore: - - .release-please-manifest.json - - CHANGELOG.md - - package.json + - packages/sq-gh/.release-please-manifest.json + - packages/sq-gh/CHANGELOG.md + - packages/sq-gh/package.json jobs: build-and-test: diff --git a/packages/sq-gh/.github/workflows/drill-required.yml b/packages/sq-gh/.github/workflows/drill-required.yml index 0648d962..539b3f70 100644 --- a/packages/sq-gh/.github/workflows/drill-required.yml +++ b/packages/sq-gh/.github/workflows/drill-required.yml @@ -10,9 +10,9 @@ on: # below cannot do this: it is evaluated inside a run, and a GITHUB_TOKEN PR's # run is created in action_required and never starts. paths-ignore: - - .release-please-manifest.json - - CHANGELOG.md - - package.json + - packages/sq-gh/.release-please-manifest.json + - packages/sq-gh/CHANGELOG.md + - packages/sq-gh/package.json permissions: contents: read diff --git a/packages/sq-gh/.github/workflows/guard-generated-files.yml b/packages/sq-gh/.github/workflows/guard-generated-files.yml index 313346b4..cfec518a 100644 --- a/packages/sq-gh/.github/workflows/guard-generated-files.yml +++ b/packages/sq-gh/.github/workflows/guard-generated-files.yml @@ -9,9 +9,9 @@ on: # below cannot do this: it is evaluated inside a run, and a GITHUB_TOKEN PR's # run is created in action_required and never starts. paths-ignore: - - .release-please-manifest.json - - CHANGELOG.md - - package.json + - packages/sq-gh/.release-please-manifest.json + - packages/sq-gh/CHANGELOG.md + - packages/sq-gh/package.json permissions: contents: read @@ -45,7 +45,7 @@ jobs: files=$(git diff --name-only "${BASE_SHA}...${HEAD_SHA}") violated="" - for path in CHANGELOG.md .release-please-manifest.json; do + for path in packages/sq-gh/CHANGELOG.md packages/sq-gh/.release-please-manifest.json; do if printf '%s\n' "$files" | grep -qxF -- "$path"; then violated="${violated} ${path}" fi @@ -55,7 +55,7 @@ jobs: { echo "::error::This PR modifies release-please-generated files:${violated}" echo - echo "CHANGELOG.md and .release-please-manifest.json are auto-generated by" + echo "packages/sq-gh/CHANGELOG.md and packages/sq-gh/.release-please-manifest.json are auto-generated by" echo "release-please from conventional commits on main. Do not hand-edit them." echo echo "If you want your change to appear in the next release notes, use a" diff --git a/packages/sq-gh/AGENTS.md b/packages/sq-gh/AGENTS.md index 8c6a7a1e..c5c84384 100644 --- a/packages/sq-gh/AGENTS.md +++ b/packages/sq-gh/AGENTS.md @@ -23,7 +23,7 @@ Releases are cut by release-please from conventional commit messages on `main`. The monorepo `.github/workflows/release.yml` runs one release stream per package (`packages/sq-gh/release-please-config.json` + `.release-please-manifest.json`), and merging the bot's release PR triggers `npm publish` with the `NPM_TOKEN` secret. Do not hand-edit `CHANGELOG.md` or `.release-please-manifest.json` (a guard workflow blocks PRs that touch them), and regenerate `skills/sq-gh/SKILL.md` with `pnpm run build:skill` instead of editing it directly. -Every `pull_request` workflow (`ci.yml`, `guard-generated-files.yml`, `drill-required.yml`) uses `paths-ignore` for the release-please output set (`.release-please-manifest.json`, `CHANGELOG.md`, `package.json`) so release PRs create zero runs. Job-level bot `if`s stay as defense in depth. `test/release-ci-exclusions.test.ts` derives that set from `release-please-config.json` and fails if a workflow drifts; update the ignore lists when adding `extra-files` or changing `release-type`. +Every `pull_request` workflow (`ci.yml`, `guard-generated-files.yml`, `drill-required.yml`) uses `paths-ignore` for the release-please output set (`packages/sq-gh/.release-please-manifest.json`, `packages/sq-gh/CHANGELOG.md`, `packages/sq-gh/package.json`) so release PRs create zero runs. Job-level bot `if`s stay as defense in depth. `test/release-ci-exclusions.test.ts` derives that set from `release-please-config.json` and fails if a workflow drifts; update the ignore lists when adding `extra-files` or changing `release-type`. ## GitHub Enterprise host support (`src/host.ts`, `src/cli.ts`) diff --git a/packages/sq-gh/release-please-config.json b/packages/sq-gh/release-please-config.json index a119fbff..dbc5290b 100644 --- a/packages/sq-gh/release-please-config.json +++ b/packages/sq-gh/release-please-config.json @@ -1,5 +1,6 @@ { "$schema": "https://raw.githubusercontent.com/googleapis/release-please/main/schemas/config.json", + "bootstrap-sha": "71715714efeea44e804152126f25c199a8ffe7fa", "bump-minor-pre-major": true, "bump-patch-for-minor-pre-major": true, "packages": { diff --git a/packages/sq-gh/test/release-ci-exclusions.test.ts b/packages/sq-gh/test/release-ci-exclusions.test.ts index f697cd49..f7d29359 100644 --- a/packages/sq-gh/test/release-ci-exclusions.test.ts +++ b/packages/sq-gh/test/release-ci-exclusions.test.ts @@ -31,22 +31,31 @@ function expectedReleaseOutputs(): string[] { } >; }; - const pkg = config.packages?.["."] ?? {}; + const pkgKey = "packages/sq-gh"; + const pkg = config.packages?.[pkgKey]; + if (!pkg) { + throw new Error( + `release-please-config.json has no "${pkgKey}" package entry`, + ); + } + const prefix = `${pkgKey}/`; const releaseType = pkg["release-type"] ?? config["release-type"] ?? "node"; const changelog = - pkg["changelog-path"] ?? config["changelog-path"] ?? "CHANGELOG.md"; + prefix + + (pkg["changelog-path"] ?? config["changelog-path"] ?? "CHANGELOG.md"); const expected: string[] = [changelog]; switch (releaseType) { case "simple": expected.push( - pkg["version-file"] ?? config["version-file"] ?? "version.txt", + prefix + + (pkg["version-file"] ?? config["version-file"] ?? "version.txt"), ); break; case "node": - expected.push("package.json"); + expected.push(prefix + "package.json"); if (existsSync(join(root, "package-lock.json"))) { - expected.push("package-lock.json"); + expected.push(prefix + "package-lock.json"); } break; case "go": @@ -60,16 +69,19 @@ function expectedReleaseOutputs(): string[] { const extra = pkg["extra-files"] ?? config["extra-files"] ?? []; for (const entry of extra) { const path = typeof entry === "string" ? entry : entry?.path; - if (path) expected.push(path); + if (path) expected.push(path.includes("/") ? path : prefix + path); } - let manifest = ".release-please-manifest.json"; + let manifest = prefix + ".release-please-manifest.json"; const releaseWorkflow = readFileSync( join(workflowsDir, "release-please.yml"), "utf8", ); const manifestMatch = releaseWorkflow.match(/manifest-file:\s*(\S+)/); - if (manifestMatch) manifest = manifestMatch[1]; + if (manifestMatch) { + const configured = manifestMatch[1]; + manifest = configured.includes("/") ? configured : prefix + configured; + } expected.push(manifest); return [...new Set(expected)]; @@ -159,9 +171,9 @@ describe("release-please CI exclusions", () => { it("derives the node release-output set for this repository", () => { expect(expected).toEqual([ - "CHANGELOG.md", - "package.json", - ".release-please-manifest.json", + "packages/sq-gh/CHANGELOG.md", + "packages/sq-gh/package.json", + "packages/sq-gh/.release-please-manifest.json", ]); }); @@ -205,9 +217,9 @@ describe("release-please CI exclusions", () => { const pr = on!.pull_request as Record; expect(pr.branches).toEqual(["main"]); expect(pr["paths-ignore"]).toEqual([ - ".release-please-manifest.json", - "CHANGELOG.md", - "package.json", + "packages/sq-gh/.release-please-manifest.json", + "packages/sq-gh/CHANGELOG.md", + "packages/sq-gh/package.json", ]); expect(on!.release).toBeUndefined(); expect(on!.workflow_dispatch).toBeUndefined(); diff --git a/packages/sq-quota/.github/workflows/ci.yml b/packages/sq-quota/.github/workflows/ci.yml index e1711068..9fcb4278 100644 --- a/packages/sq-quota/.github/workflows/ci.yml +++ b/packages/sq-quota/.github/workflows/ci.yml @@ -9,9 +9,9 @@ on: # pull_request run that can only sit in action_required. Its output set is # exactly these files, so excluding them means no run is ever created. paths-ignore: - - .release-please-manifest.json - - CHANGELOG.md - - package.json + - packages/sq-quota/.release-please-manifest.json + - packages/sq-quota/CHANGELOG.md + - packages/sq-quota/package.json jobs: build-and-test: diff --git a/packages/sq-quota/.github/workflows/drill-required.yml b/packages/sq-quota/.github/workflows/drill-required.yml index 0648d962..51ed435d 100644 --- a/packages/sq-quota/.github/workflows/drill-required.yml +++ b/packages/sq-quota/.github/workflows/drill-required.yml @@ -10,9 +10,9 @@ on: # below cannot do this: it is evaluated inside a run, and a GITHUB_TOKEN PR's # run is created in action_required and never starts. paths-ignore: - - .release-please-manifest.json - - CHANGELOG.md - - package.json + - packages/sq-quota/.release-please-manifest.json + - packages/sq-quota/CHANGELOG.md + - packages/sq-quota/package.json permissions: contents: read diff --git a/packages/sq-quota/.github/workflows/guard-generated-files.yml b/packages/sq-quota/.github/workflows/guard-generated-files.yml index 42d5d9e1..247f7cbe 100644 --- a/packages/sq-quota/.github/workflows/guard-generated-files.yml +++ b/packages/sq-quota/.github/workflows/guard-generated-files.yml @@ -9,9 +9,9 @@ on: # below cannot do this: it is evaluated inside a run, and a GITHUB_TOKEN PR's # run is created in action_required and never starts. paths-ignore: - - .release-please-manifest.json - - CHANGELOG.md - - package.json + - packages/sq-quota/.release-please-manifest.json + - packages/sq-quota/CHANGELOG.md + - packages/sq-quota/package.json permissions: contents: read @@ -45,7 +45,7 @@ jobs: files=$(git diff --name-only "${BASE_SHA}...${HEAD_SHA}") violated="" - for path in CHANGELOG.md .release-please-manifest.json; do + for path in packages/sq-quota/CHANGELOG.md packages/sq-quota/.release-please-manifest.json; do if printf '%s\n' "$files" | grep -qxF -- "$path"; then # Only a violation if the file already existed on the base branch. # A PR that creates it for the first time (e.g. wiring up @@ -60,7 +60,7 @@ jobs: { echo "::error::This PR modifies release-please-generated files:${violated}" echo - echo "CHANGELOG.md and .release-please-manifest.json are auto-generated by" + echo "packages/sq-quota/CHANGELOG.md and packages/sq-quota/.release-please-manifest.json are auto-generated by" echo "release-please from conventional commits on main. Do not hand-edit them." echo echo "If you want your change to appear in the next release notes, use a" diff --git a/packages/sq-quota/AGENTS.md b/packages/sq-quota/AGENTS.md index 94d6cfcc..37662ace 100644 --- a/packages/sq-quota/AGENTS.md +++ b/packages/sq-quota/AGENTS.md @@ -58,9 +58,9 @@ Releases are cut by release-please from conventional commit messages on `main`. The monorepo `.github/workflows/release.yml` runs one release stream per package (`packages/sq-quota/release-please-config.json` + `.release-please-manifest.json`), and merging the bot's release PR triggers `npm publish` with the `NPM_TOKEN` secret. `.release-please-manifest.json` is primed at `0.1.0`, matching the package version. Nothing has been published to npm yet (`sq-quota` is free on npm), so the first publish happens only after the commander approves and the `NPM_TOKEN` secret exists; release-please owns every version after that. -`release-please-config.json` keeps the `bootstrap-sha` inherited from the vendored upstream config (`9f5dc949c50ab8ac0a441be777e1c3693ee0b612`, a commit outside this repo's history); do not retarget it to later scaffolding commits unless the published baseline itself is being corrected. +`release-please-config.json` pins `bootstrap-sha` to commit `71715714efeea44e804152126f25c199a8ffe7fa` (the per-package release wiring in this repo's history), so the first generated changelogs truncate before the pre-release scaffolding commits; do not retarget it unless the published baseline itself is being corrected. Do not hand-edit `CHANGELOG.md` or `.release-please-manifest.json` (a guard workflow blocks PRs that touch them), and regenerate `skills/sq-quota/SKILL.md` with `pnpm run build:skill` instead of editing it directly (`pnpm run build:skill -- --check` in CI fails if it drifts from `src/skill.ts`). -Every `pull_request` workflow must `paths-ignore` the release-please output set (`.release-please-manifest.json`, `CHANGELOG.md`, `package.json`) so release PRs create zero runs; `test/release-ci-exclusions.test.ts` derives that set from `release-please-config.json` and fails if a workflow drifts. +Every `pull_request` workflow must `paths-ignore` the release-please output set (`packages/sq-quota/.release-please-manifest.json`, `packages/sq-quota/CHANGELOG.md`, `packages/sq-quota/package.json`) so release PRs create zero runs; `test/release-ci-exclusions.test.ts` derives that set from `release-please-config.json` and fails if a workflow drifts. ## Lockfile formatting diff --git a/packages/sq-quota/CONTRIBUTING.md b/packages/sq-quota/CONTRIBUTING.md index d080f577..e72b69d4 100644 --- a/packages/sq-quota/CONTRIBUTING.md +++ b/packages/sq-quota/CONTRIBUTING.md @@ -42,7 +42,7 @@ See the [drill quick start](https://github.com/runecraftai/squad) for the full f - Do not bump `package.json`'s `version` by hand for ordinary changes. release-please updates it in the release PR. - Do not change `release-please-config.json`'s `bootstrap-sha` for ordinary changes. - It is inherited from the vendored upstream config (commit `9f5dc949c50ab8ac0a441be777e1c3693ee0b612`, outside this repo's history). + It pins release history to commit `71715714efeea44e804152126f25c199a8ffe7fa` (the per-package release wiring in this repo), so generated changelogs never include the pre-release scaffolding commits. - Do not hand-edit `skills/sq-quota/SKILL.md`. It is generated from the shared skill source, including frontmatter metadata; run `pnpm run build:skill` and commit the result. - sq-quota is data only: it must never route, recommend, proxy, intercept, log in, import browser cookies, or mutate provider state. Keep changes within that boundary. diff --git a/packages/sq-quota/release-please-config.json b/packages/sq-quota/release-please-config.json index a9e612b7..5412a791 100644 --- a/packages/sq-quota/release-please-config.json +++ b/packages/sq-quota/release-please-config.json @@ -1,6 +1,6 @@ { "$schema": "https://raw.githubusercontent.com/googleapis/release-please/main/schemas/config.json", - "bootstrap-sha": "9f5dc949c50ab8ac0a441be777e1c3693ee0b612", + "bootstrap-sha": "71715714efeea44e804152126f25c199a8ffe7fa", "bump-minor-pre-major": true, "bump-patch-for-minor-pre-major": true, "packages": { diff --git a/packages/sq-quota/test/release-ci-exclusions.test.ts b/packages/sq-quota/test/release-ci-exclusions.test.ts index 9c7cc4f2..43a9145a 100644 --- a/packages/sq-quota/test/release-ci-exclusions.test.ts +++ b/packages/sq-quota/test/release-ci-exclusions.test.ts @@ -31,22 +31,31 @@ function expectedReleaseOutputs(): string[] { >; }; - const pkg = config.packages?.["."] ?? {}; + const pkgKey = "packages/sq-quota"; + const pkg = config.packages?.[pkgKey]; + if (!pkg) { + throw new Error( + `release-please-config.json has no "${pkgKey}" package entry`, + ); + } + const prefix = `${pkgKey}/`; const releaseType = pkg["release-type"] ?? config["release-type"] ?? "node"; const changelog = - pkg["changelog-path"] ?? config["changelog-path"] ?? "CHANGELOG.md"; + prefix + + (pkg["changelog-path"] ?? config["changelog-path"] ?? "CHANGELOG.md"); const expected = [changelog]; switch (releaseType) { case "simple": expected.push( - pkg["version-file"] ?? config["version-file"] ?? "version.txt", + prefix + + (pkg["version-file"] ?? config["version-file"] ?? "version.txt"), ); break; case "node": - expected.push("package.json"); + expected.push(prefix + "package.json"); if (existsSync(join(root, "package-lock.json"))) { - expected.push("package-lock.json"); + expected.push(prefix + "package-lock.json"); } break; case "go": @@ -60,16 +69,19 @@ function expectedReleaseOutputs(): string[] { const extra = pkg["extra-files"] ?? config["extra-files"] ?? []; for (const entry of extra) { const path = typeof entry === "string" ? entry : entry?.path; - if (path) expected.push(path); + if (path) expected.push(path.includes("/") ? path : prefix + path); } - let manifest = ".release-please-manifest.json"; + let manifest = prefix + ".release-please-manifest.json"; const releaseWorkflow = readFileSync( join(workflowsDir, "release-please.yml"), "utf8", ); const manifestMatch = releaseWorkflow.match(/manifest-file:\s*(\S+)/); - if (manifestMatch) manifest = manifestMatch[1]; + if (manifestMatch) { + const configured = manifestMatch[1]; + manifest = configured.includes("/") ? configured : prefix + configured; + } expected.push(manifest); return [...new Set(expected)]; @@ -159,9 +171,9 @@ describe("release-please CI exclusions", () => { it("derives the node release-output set for this repository", () => { expect(expected).toEqual([ - "CHANGELOG.md", - "package.json", - ".release-please-manifest.json", + "packages/sq-quota/CHANGELOG.md", + "packages/sq-quota/package.json", + "packages/sq-quota/.release-please-manifest.json", ]); }); @@ -205,9 +217,9 @@ describe("release-please CI exclusions", () => { const pr = on!.pull_request as Record; expect(pr.branches).toEqual(["main"]); expect(pr["paths-ignore"]).toEqual([ - ".release-please-manifest.json", - "CHANGELOG.md", - "package.json", + "packages/sq-quota/.release-please-manifest.json", + "packages/sq-quota/CHANGELOG.md", + "packages/sq-quota/package.json", ]); expect(on!.release).toBeUndefined(); expect(on!.workflow_dispatch).toBeUndefined(); diff --git a/packages/sq-report/.github/workflows/ci.yml b/packages/sq-report/.github/workflows/ci.yml index 88a1acb3..ab6cdf48 100644 --- a/packages/sq-report/.github/workflows/ci.yml +++ b/packages/sq-report/.github/workflows/ci.yml @@ -9,10 +9,10 @@ on: # pull_request run that can only sit in action_required. Its output set is # exactly these files, so excluding them means no run is ever created. paths-ignore: - - .release-please-manifest.json - - CHANGELOG.md - - package.json - - plugin.json + - packages/sq-report/.release-please-manifest.json + - packages/sq-report/CHANGELOG.md + - packages/sq-report/package.json + - packages/sq-report/plugin.json jobs: build-and-test: diff --git a/packages/sq-report/.github/workflows/drill-required.yml b/packages/sq-report/.github/workflows/drill-required.yml index 92507f75..a4da6ba6 100644 --- a/packages/sq-report/.github/workflows/drill-required.yml +++ b/packages/sq-report/.github/workflows/drill-required.yml @@ -10,10 +10,10 @@ on: # below cannot do this: it is evaluated inside a run, and a GITHUB_TOKEN PR's # run is created in action_required and never starts. paths-ignore: - - .release-please-manifest.json - - CHANGELOG.md - - package.json - - plugin.json + - packages/sq-report/.release-please-manifest.json + - packages/sq-report/CHANGELOG.md + - packages/sq-report/package.json + - packages/sq-report/plugin.json permissions: contents: read diff --git a/packages/sq-report/.github/workflows/guard-generated-files.yml b/packages/sq-report/.github/workflows/guard-generated-files.yml index b02590d8..f1e2d52f 100644 --- a/packages/sq-report/.github/workflows/guard-generated-files.yml +++ b/packages/sq-report/.github/workflows/guard-generated-files.yml @@ -9,10 +9,10 @@ on: # below cannot do this: it is evaluated inside a run, and a GITHUB_TOKEN PR's # run is created in action_required and never starts. paths-ignore: - - .release-please-manifest.json - - CHANGELOG.md - - package.json - - plugin.json + - packages/sq-report/.release-please-manifest.json + - packages/sq-report/CHANGELOG.md + - packages/sq-report/package.json + - packages/sq-report/plugin.json permissions: contents: read @@ -42,7 +42,7 @@ jobs: files=$(git diff --name-only "${BASE_SHA}...${HEAD_SHA}") violated="" - for path in CHANGELOG.md .release-please-manifest.json; do + for path in packages/sq-report/CHANGELOG.md packages/sq-report/.release-please-manifest.json; do if printf '%s\n' "$files" | grep -qxF -- "$path"; then violated="${violated} ${path}" fi @@ -52,7 +52,7 @@ jobs: { echo "::error::This PR modifies release-please-generated files:${violated}" echo - echo "CHANGELOG.md and .release-please-manifest.json are auto-generated by" + echo "packages/sq-report/CHANGELOG.md and packages/sq-report/.release-please-manifest.json are auto-generated by" echo "release-please from conventional commits on main. Do not hand-edit them." echo echo "If you want your change to appear in the next release notes, use a" diff --git a/packages/sq-report/release-please-config.json b/packages/sq-report/release-please-config.json index 6c06be97..3df1cb0b 100644 --- a/packages/sq-report/release-please-config.json +++ b/packages/sq-report/release-please-config.json @@ -1,5 +1,6 @@ { "$schema": "https://raw.githubusercontent.com/googleapis/release-please/main/schemas/config.json", + "bootstrap-sha": "71715714efeea44e804152126f25c199a8ffe7fa", "bump-minor-pre-major": true, "bump-patch-for-minor-pre-major": true, "packages": { diff --git a/packages/sq-report/test/release-ci-exclusions.test.js b/packages/sq-report/test/release-ci-exclusions.test.js index 1a3b37aa..5e061462 100644 --- a/packages/sq-report/test/release-ci-exclusions.test.js +++ b/packages/sq-report/test/release-ci-exclusions.test.js @@ -15,19 +15,24 @@ const workflowsDir = join(root, ".github", "workflows"); */ function expectedReleaseOutputs() { const config = JSON.parse(readFileSync(join(root, "release-please-config.json"), "utf8")); - const pkg = config.packages?.["packages/sq-report"] ?? {}; + const pkgKey = "packages/sq-report"; + const pkg = config.packages?.[pkgKey]; + if (!pkg) { + throw new Error(`release-please-config.json has no "${pkgKey}" package entry`); + } + const prefix = `${pkgKey}/`; const releaseType = pkg["release-type"] ?? config["release-type"] ?? "node"; - const changelog = pkg["changelog-path"] ?? config["changelog-path"] ?? "CHANGELOG.md"; + const changelog = prefix + (pkg["changelog-path"] ?? config["changelog-path"] ?? "CHANGELOG.md"); const expected = [changelog]; switch (releaseType) { case "simple": - expected.push(pkg["version-file"] ?? config["version-file"] ?? "version.txt"); + expected.push(prefix + (pkg["version-file"] ?? config["version-file"] ?? "version.txt")); break; case "node": - expected.push("package.json"); + expected.push(prefix + "package.json"); if (existsSync(join(root, "package-lock.json"))) { - expected.push("package-lock.json"); + expected.push(prefix + "package-lock.json"); } break; case "go": @@ -39,13 +44,16 @@ function expectedReleaseOutputs() { const extra = pkg["extra-files"] ?? config["extra-files"] ?? []; for (const entry of extra) { const path = typeof entry === "string" ? entry : entry?.path; - if (path) expected.push(path); + if (path) expected.push(path.includes("/") ? path : prefix + path); } - let manifest = ".release-please-manifest.json"; + let manifest = prefix + ".release-please-manifest.json"; const releaseWorkflow = readFileSync(join(workflowsDir, "release-please.yml"), "utf8"); const manifestMatch = releaseWorkflow.match(/manifest-file:\s*(\S+)/); - if (manifestMatch) manifest = manifestMatch[1]; + if (manifestMatch) { + const configured = manifestMatch[1]; + manifest = configured.includes("/") ? configured : prefix + configured; + } expected.push(manifest); return [...new Set(expected)]; @@ -191,7 +199,12 @@ const expected = expectedReleaseOutputs(); test("derives the node release-output set for this repository", () => { // plugin.json is an extra-file: release-please bumps its version alongside package.json. - assert.deepEqual(expected, ["CHANGELOG.md", "package.json", "plugin.json", ".release-please-manifest.json"]); + assert.deepEqual(expected, [ + "packages/sq-report/CHANGELOG.md", + "packages/sq-report/package.json", + "packages/sq-report/plugin.json", + "packages/sq-report/.release-please-manifest.json", + ]); }); test("every pull_request workflow ignores the full release-output set", () => { @@ -228,10 +241,10 @@ test("does not attach path filters to non-pull_request triggers on ci.yml", () = assert.deepEqual(on.push, { branches: ["main"] }); assert.deepEqual(on.pull_request.branches, ["main"]); assert.deepEqual(on.pull_request["paths-ignore"], [ - ".release-please-manifest.json", - "CHANGELOG.md", - "package.json", - "plugin.json", + "packages/sq-report/.release-please-manifest.json", + "packages/sq-report/CHANGELOG.md", + "packages/sq-report/package.json", + "packages/sq-report/plugin.json", ]); assert.equal(on.release, undefined); assert.equal(on.workflow_dispatch, undefined); diff --git a/packages/sq-tasks/.github/workflows/ci.yml b/packages/sq-tasks/.github/workflows/ci.yml index 0378ff02..40ab6bfa 100644 --- a/packages/sq-tasks/.github/workflows/ci.yml +++ b/packages/sq-tasks/.github/workflows/ci.yml @@ -9,9 +9,9 @@ on: # pull_request run that can only sit in action_required. Its output set is # exactly these files, so excluding them means no run is ever created. paths-ignore: - - .release-please-manifest.json - - CHANGELOG.md - - package.json + - packages/sq-tasks/.release-please-manifest.json + - packages/sq-tasks/CHANGELOG.md + - packages/sq-tasks/package.json jobs: build-and-test: diff --git a/packages/sq-tasks/.github/workflows/drill-required.yml b/packages/sq-tasks/.github/workflows/drill-required.yml index 0e591e75..f4ec9266 100644 --- a/packages/sq-tasks/.github/workflows/drill-required.yml +++ b/packages/sq-tasks/.github/workflows/drill-required.yml @@ -10,9 +10,9 @@ on: # below cannot do this: it is evaluated inside a run, and a GITHUB_TOKEN PR's # run is created in action_required and never starts. paths-ignore: - - .release-please-manifest.json - - CHANGELOG.md - - package.json + - packages/sq-tasks/.release-please-manifest.json + - packages/sq-tasks/CHANGELOG.md + - packages/sq-tasks/package.json permissions: contents: read diff --git a/packages/sq-tasks/.github/workflows/guard-generated-files.yml b/packages/sq-tasks/.github/workflows/guard-generated-files.yml index 7e9cb996..3f44aa01 100644 --- a/packages/sq-tasks/.github/workflows/guard-generated-files.yml +++ b/packages/sq-tasks/.github/workflows/guard-generated-files.yml @@ -9,9 +9,9 @@ on: # below cannot do this: it is evaluated inside a run, and a GITHUB_TOKEN PR's # run is created in action_required and never starts. paths-ignore: - - .release-please-manifest.json - - CHANGELOG.md - - package.json + - packages/sq-tasks/.release-please-manifest.json + - packages/sq-tasks/CHANGELOG.md + - packages/sq-tasks/package.json permissions: contents: read diff --git a/packages/sq-tasks/AGENTS.md b/packages/sq-tasks/AGENTS.md index c79f5f7a..94a5feaf 100644 --- a/packages/sq-tasks/AGENTS.md +++ b/packages/sq-tasks/AGENTS.md @@ -86,7 +86,7 @@ Any argv shape other than exactly one version flag falls through to `runAxiCli`, The monorepo `.github/workflows/release.yml` runs one release stream per package, and merging the bot's release PR triggers `npm publish` with the `NPM_TOKEN` secret (provenance stays enabled through `publishConfig`). The commander can also `npm publish` manually. Conventional commits drive the version bump; `release-please-config.json` + `.release-please-manifest.json` own versioning and `CHANGELOG.md`. -- Every `pull_request` workflow (`ci.yml`, `guard-generated-files.yml`, `drill-required.yml`) uses `paths-ignore` for the release-please output set (`.release-please-manifest.json`, `CHANGELOG.md`, `package.json`) so release PRs create zero runs. Job-level bot `if`s stay as defense in depth. `test/release-ci-exclusions.test.ts` derives that set from `release-please-config.json` and fails if a workflow drifts; update the ignore lists when adding `extra-files` or changing `release-type`. +- Every `pull_request` workflow (`ci.yml`, `guard-generated-files.yml`, `drill-required.yml`) uses `paths-ignore` for the release-please output set (`packages/sq-tasks/.release-please-manifest.json`, `packages/sq-tasks/CHANGELOG.md`, `packages/sq-tasks/package.json`) so release PRs create zero runs. Job-level bot `if`s stay as defense in depth. `test/release-ci-exclusions.test.ts` derives that set from `release-please-config.json` and fails if a workflow drifts; update the ignore lists when adding `extra-files` or changing `release-type`. - **The tarball ships runtime JS only.** `package.json` `files` is `dist/**/*.js` (+ `skills/sq-tasks`, `LICENSE`, `README.md`), so the `.d.ts`/`.js.map` that `tsc` emits for local debugging are kept out of the package. `prepack` runs `npm run build`, so `npm pack`/`npm publish` always rebuild `dist` first. In a fresh clone, run `pnpm install --frozen-lockfile` before manual pack or publish. diff --git a/packages/sq-tasks/release-please-config.json b/packages/sq-tasks/release-please-config.json index f4917fba..74a98458 100644 --- a/packages/sq-tasks/release-please-config.json +++ b/packages/sq-tasks/release-please-config.json @@ -1,5 +1,6 @@ { "$schema": "https://raw.githubusercontent.com/googleapis/release-please/main/schemas/config.json", + "bootstrap-sha": "71715714efeea44e804152126f25c199a8ffe7fa", "bump-minor-pre-major": true, "bump-patch-for-minor-pre-major": true, "packages": { diff --git a/packages/sq-tasks/scripts/guard-generated-files.sh b/packages/sq-tasks/scripts/guard-generated-files.sh index 8b4e3782..6e999271 100644 --- a/packages/sq-tasks/scripts/guard-generated-files.sh +++ b/packages/sq-tasks/scripts/guard-generated-files.sh @@ -9,9 +9,9 @@ violated=$( git diff --name-status --find-renames --find-copies --find-copies-harder "${base_sha}...${head_sha}" | awk ' function generated(path) { - return path == "CHANGELOG.md" || path == ".release-please-manifest.json" + return path == "packages/sq-tasks/CHANGELOG.md" || path == "packages/sq-tasks/.release-please-manifest.json" } - $1 == "A" && $2 == ".release-please-manifest.json" { next } + $1 == "A" && $2 == "packages/sq-tasks/.release-please-manifest.json" { next } $1 == "A" && generated($2) { printf " %s", $2 } @@ -32,7 +32,7 @@ if [ -n "$violated" ]; then { echo "::error::This PR modifies release-please-generated files:${violated}" echo - echo "CHANGELOG.md and .release-please-manifest.json are auto-generated by" + echo "packages/sq-tasks/CHANGELOG.md and packages/sq-tasks/.release-please-manifest.json are auto-generated by" echo "release-please from conventional commits on main. Do not hand-edit them." echo echo "If you want your change to appear in the next release notes, use a" diff --git a/packages/sq-tasks/test/release-ci-exclusions.test.ts b/packages/sq-tasks/test/release-ci-exclusions.test.ts index 4e7ccbc5..8c2bf1ae 100644 --- a/packages/sq-tasks/test/release-ci-exclusions.test.ts +++ b/packages/sq-tasks/test/release-ci-exclusions.test.ts @@ -31,22 +31,31 @@ function expectedReleaseOutputs(): string[] { } >; }; - const pkg = config.packages?.["."] ?? {}; + const pkgKey = "packages/sq-tasks"; + const pkg = config.packages?.[pkgKey]; + if (!pkg) { + throw new Error( + `release-please-config.json has no "${pkgKey}" package entry`, + ); + } + const prefix = `${pkgKey}/`; const releaseType = pkg["release-type"] ?? config["release-type"] ?? "node"; const changelog = - pkg["changelog-path"] ?? config["changelog-path"] ?? "CHANGELOG.md"; + prefix + + (pkg["changelog-path"] ?? config["changelog-path"] ?? "CHANGELOG.md"); const expected: string[] = [changelog]; switch (releaseType) { case "simple": expected.push( - pkg["version-file"] ?? config["version-file"] ?? "version.txt", + prefix + + (pkg["version-file"] ?? config["version-file"] ?? "version.txt"), ); break; case "node": - expected.push("package.json"); + expected.push(prefix + "package.json"); if (existsSync(join(root, "package-lock.json"))) { - expected.push("package-lock.json"); + expected.push(prefix + "package-lock.json"); } break; case "go": @@ -60,16 +69,19 @@ function expectedReleaseOutputs(): string[] { const extra = pkg["extra-files"] ?? config["extra-files"] ?? []; for (const entry of extra) { const path = typeof entry === "string" ? entry : entry?.path; - if (path) expected.push(path); + if (path) expected.push(path.includes("/") ? path : prefix + path); } - let manifest = ".release-please-manifest.json"; + let manifest = prefix + ".release-please-manifest.json"; const releaseWorkflow = readFileSync( join(workflowsDir, "release-please.yml"), "utf8", ); const manifestMatch = releaseWorkflow.match(/manifest-file:\s*(\S+)/); - if (manifestMatch) manifest = manifestMatch[1]; + if (manifestMatch) { + const configured = manifestMatch[1]; + manifest = configured.includes("/") ? configured : prefix + configured; + } expected.push(manifest); return [...new Set(expected)]; @@ -159,9 +171,9 @@ describe("release-please CI exclusions", () => { it("derives the node release-output set for this repository", () => { expect(expected).toEqual([ - "CHANGELOG.md", - "package.json", - ".release-please-manifest.json", + "packages/sq-tasks/CHANGELOG.md", + "packages/sq-tasks/package.json", + "packages/sq-tasks/.release-please-manifest.json", ]); }); @@ -205,9 +217,9 @@ describe("release-please CI exclusions", () => { const pr = on!.pull_request as Record; expect(pr.branches).toEqual(["main"]); expect(pr["paths-ignore"]).toEqual([ - ".release-please-manifest.json", - "CHANGELOG.md", - "package.json", + "packages/sq-tasks/.release-please-manifest.json", + "packages/sq-tasks/CHANGELOG.md", + "packages/sq-tasks/package.json", ]); expect(on!.release).toBeUndefined(); expect(on!.workflow_dispatch).toBeUndefined(); diff --git a/packages/sq-tasks/test/workflows/guard-generated-files.test.ts b/packages/sq-tasks/test/workflows/guard-generated-files.test.ts index 6c33c205..3ad9ea2a 100644 --- a/packages/sq-tasks/test/workflows/guard-generated-files.test.ts +++ b/packages/sq-tasks/test/workflows/guard-generated-files.test.ts @@ -1,5 +1,5 @@ import { execFileSync } from "node:child_process"; -import { mkdtempSync, rmSync, writeFileSync } from "node:fs"; +import { mkdirSync, mkdtempSync, rmSync, writeFileSync } from "node:fs"; import { tmpdir } from "node:os"; import { join } from "node:path"; import { fileURLToPath } from "node:url"; @@ -79,7 +79,8 @@ describe("guard-generated-files workflow helper", () => { const repo = initRepo(); writeFileSync(join(repo, "README.md"), "seed\n"); const base = commit(repo, "seed"); - writeFileSync(join(repo, ".release-please-manifest.json"), "{}\n"); + mkdirSync(join(repo, "packages/sq-tasks"), { recursive: true }); + writeFileSync(join(repo, "packages/sq-tasks/.release-please-manifest.json"), "{}\n"); const head = commit(repo, "add manifest"); const result = runGuard(repo, base, head); @@ -92,7 +93,8 @@ describe("guard-generated-files workflow helper", () => { const repo = initRepo(); writeFileSync(join(repo, "README.md"), "seed\n"); const base = commit(repo, "seed"); - writeFileSync(join(repo, "CHANGELOG.md"), "# Changelog\n"); + mkdirSync(join(repo, "packages/sq-tasks"), { recursive: true }); + writeFileSync(join(repo, "packages/sq-tasks/CHANGELOG.md"), "# Changelog\n"); const head = commit(repo, "add changelog"); const result = runGuard(repo, base, head); @@ -104,9 +106,10 @@ describe("guard-generated-files workflow helper", () => { it("rejects deleting an existing generated file", () => { const repo = initRepo(); writeFileSync(join(repo, "README.md"), "seed\n"); - writeFileSync(join(repo, ".release-please-manifest.json"), "{}\n"); + mkdirSync(join(repo, "packages/sq-tasks"), { recursive: true }); + writeFileSync(join(repo, "packages/sq-tasks/.release-please-manifest.json"), "{}\n"); const base = commit(repo, "seed"); - rmSync(join(repo, ".release-please-manifest.json")); + rmSync(join(repo, "packages/sq-tasks/.release-please-manifest.json")); const head = commit(repo, "delete manifest"); const result = runGuard(repo, base, head); @@ -117,9 +120,10 @@ describe("guard-generated-files workflow helper", () => { it("rejects renaming an existing generated file", () => { const repo = initRepo(); - writeFileSync(join(repo, "CHANGELOG.md"), "# Changelog\n"); + mkdirSync(join(repo, "packages/sq-tasks"), { recursive: true }); + writeFileSync(join(repo, "packages/sq-tasks/CHANGELOG.md"), "# Changelog\n"); const base = commit(repo, "seed changelog"); - git(repo, ["mv", "CHANGELOG.md", "NOTES.md"]); + git(repo, ["mv", "packages/sq-tasks/CHANGELOG.md", "packages/sq-tasks/NOTES.md"]); const head = commit(repo, "rename changelog"); const result = runGuard(repo, base, head); @@ -130,11 +134,12 @@ describe("guard-generated-files workflow helper", () => { it("rejects copying an existing file into a generated path", () => { const repo = initRepo(); - writeFileSync(join(repo, "README.md"), '{"."":"0.1.0"}\n'); + writeFileSync(join(repo, "README.md"), '{".":"0.1.0"}\n'); const base = commit(repo, "seed"); + mkdirSync(join(repo, "packages/sq-tasks"), { recursive: true }); writeFileSync( - join(repo, ".release-please-manifest.json"), - '{"."":"0.1.0"}\n', + join(repo, "packages/sq-tasks/.release-please-manifest.json"), + '{".":"0.1.0"}\n', ); const head = commit(repo, "copy manifest"); From bf2d1e22d9378309505481ecaa070fb47cc1e342 Mon Sep 17 00:00:00 2001 From: Jonathan Rehem Date: Fri, 14 Aug 2026 07:56:16 -0300 Subject: [PATCH 10/11] drill(review): Gate release publish steps on releases_created == 'true --- .github/workflows/release.yml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 56d3eae1..eb67d015 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -46,18 +46,18 @@ jobs: config-file: packages/${{ matrix.package }}/release-please-config.json manifest-file: packages/${{ matrix.package }}/.release-please-manifest.json - uses: actions/checkout@v6 - if: ${{ steps.release.outputs.releases_created }} + if: ${{ steps.release.outputs.releases_created == 'true' }} - uses: pnpm/action-setup@v4 - if: ${{ steps.release.outputs.releases_created }} + if: ${{ steps.release.outputs.releases_created == 'true' }} with: version: 11.1.1 - uses: actions/setup-node@v6 - if: ${{ steps.release.outputs.releases_created }} + if: ${{ steps.release.outputs.releases_created == 'true' }} with: node-version: 22 registry-url: https://registry.npmjs.org - name: Publish to npm - if: ${{ steps.release.outputs.releases_created }} + if: ${{ steps.release.outputs.releases_created == 'true' }} env: NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }} run: | From 19e4ca5640ccf94fd040b109c7db09088671c588 Mon Sep 17 00:00:00 2001 From: Jonathan Rehem Date: Fri, 14 Aug 2026 08:12:17 -0300 Subject: [PATCH 11/11] drill(document): sync sq-tasks release docs with monorepo pipeline --- packages/sq-tasks/CLAUDE.md | 7 +++++-- packages/sq-tasks/CONTRIBUTING.md | 2 +- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/packages/sq-tasks/CLAUDE.md b/packages/sq-tasks/CLAUDE.md index 8af1caab..94a5feaf 100644 --- a/packages/sq-tasks/CLAUDE.md +++ b/packages/sq-tasks/CLAUDE.md @@ -82,8 +82,11 @@ Any argv shape other than exactly one version flag falls through to `runAxiCli`, ### Release & packaging (mirrors the `*-axi` siblings) -- **Published to npm as a public package** via `release-please` → `npm publish --access public --provenance` on a release commit (`.github/workflows/release-please.yml`); the commander can also `npm publish` manually. Conventional commits drive the version bump; `release-please-config.json` + `.release-please-manifest.json` own versioning and `CHANGELOG.md`. -- Every `pull_request` workflow (`ci.yml`, `guard-generated-files.yml`, `drill-required.yml`) uses `paths-ignore` for the release-please output set (`.release-please-manifest.json`, `CHANGELOG.md`, `package.json`) so release PRs create zero runs. Job-level bot `if`s stay as defense in depth. `test/release-ci-exclusions.test.ts` derives that set from `release-please-config.json` and fails if a workflow drifts; update the ignore lists when adding `extra-files` or changing `release-type`. +- **Published to npm as a public package** on a release commit. + The monorepo `.github/workflows/release.yml` runs one release stream per package, and merging the bot's release PR triggers `npm publish` with the `NPM_TOKEN` secret (provenance stays enabled through `publishConfig`). + The commander can also `npm publish` manually. + Conventional commits drive the version bump; `release-please-config.json` + `.release-please-manifest.json` own versioning and `CHANGELOG.md`. +- Every `pull_request` workflow (`ci.yml`, `guard-generated-files.yml`, `drill-required.yml`) uses `paths-ignore` for the release-please output set (`packages/sq-tasks/.release-please-manifest.json`, `packages/sq-tasks/CHANGELOG.md`, `packages/sq-tasks/package.json`) so release PRs create zero runs. Job-level bot `if`s stay as defense in depth. `test/release-ci-exclusions.test.ts` derives that set from `release-please-config.json` and fails if a workflow drifts; update the ignore lists when adding `extra-files` or changing `release-type`. - **The tarball ships runtime JS only.** `package.json` `files` is `dist/**/*.js` (+ `skills/sq-tasks`, `LICENSE`, `README.md`), so the `.d.ts`/`.js.map` that `tsc` emits for local debugging are kept out of the package. `prepack` runs `npm run build`, so `npm pack`/`npm publish` always rebuild `dist` first. In a fresh clone, run `pnpm install --frozen-lockfile` before manual pack or publish. diff --git a/packages/sq-tasks/CONTRIBUTING.md b/packages/sq-tasks/CONTRIBUTING.md index 91c7d778..322971fa 100644 --- a/packages/sq-tasks/CONTRIBUTING.md +++ b/packages/sq-tasks/CONTRIBUTING.md @@ -41,7 +41,7 @@ See the [drill quick start](https://github.com/runecraftai/squad/tree/main/packa ## Release and Packaging Releases are cut by release-please from Conventional Commits on `main`. -When a release is created, the release workflow installs dependencies, builds, lints, tests, checks generated skill drift, and publishes with `npm publish --access public --provenance`. +When a release is created, the monorepo release workflow (`.github/workflows/release.yml`) installs dependencies, builds, and publishes the package to npm with the `NPM_TOKEN` secret; public access and npm provenance stay enabled through `publishConfig`. The npm package intentionally ships runtime JavaScript only. Keep `package.json` `files` limited to `dist/**/*.js`, `skills/sq-tasks`, `LICENSE`, and `README.md`; TypeScript declarations and source maps stay local for development.