From 20706d4f759cbc3f29bd10e5c3b664f9c3d22481 Mon Sep 17 00:00:00 2001 From: Claude Date: Fri, 6 Nov 2026 14:56:29 +0000 Subject: [PATCH 1/3] ci: announce published packages on Discord Post each published package in the Sapphire format through the shared announce action of stars-components, and add announce.yml to re-send or preview an announcement by hand. zizmor allows that action to follow main. Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_016cicF4XnPH4SGMiXLz6nKh --- .github/workflows/announce.yml | 47 ++++++++++++++++++++++++++++++++++ .github/workflows/release.yml | 16 ++++++++++++ .github/zizmor.yml | 8 ++++++ AGENTS.md | 1 + 4 files changed, 72 insertions(+) create mode 100644 .github/workflows/announce.yml diff --git a/.github/workflows/announce.yml b/.github/workflows/announce.yml new file mode 100644 index 00000000..67a2a1b1 --- /dev/null +++ b/.github/workflows/announce.yml @@ -0,0 +1,47 @@ +name: announce + +# Re-sends, or previews, the Discord announcement of packages that are already +# published. The release workflow announces new releases on its own. +on: + workflow_dispatch: + inputs: + packages: + description: "Published packages, as name@version separated by commas (e.g. @wolfstar/plugin-api@3.1.0,@wolfstar/plugin-cache@0.4.0)" + type: string + required: true + dry-run: + description: Render into the job summary without sending anything + type: boolean + default: true + +permissions: {} + +concurrency: + group: ${{ github.workflow }} + cancel-in-progress: false + +jobs: + announce: + name: 📣 Announce packages + runs-on: ubuntu-latest + timeout-minutes: 10 + if: github.repository_owner == 'wolfstar-project' + permissions: + contents: read # the changelogs + pull-requests: read # pull request titles for the bullets + steps: + - name: Checkout Project + uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + with: + persist-credentials: false + + - name: Announce + uses: wolfstar-project/stars-components/.github/actions/announce@main + with: + mode: packages + published-packages: ${{ inputs.packages }} + dry-run: ${{ inputs.dry-run }} + webhook-url: ${{ secrets.DISCORD_PACKAGES_WEBHOOK_URL }} + role-id: ${{ vars.DISCORD_PACKAGES_ROLE_ID }} + callback-url: ${{ secrets.RELEASE_WEBHOOK_URL }} + callback-secret: ${{ secrets.RELEASE_WEBHOOK_SECRET }} diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 210a3c1f..e38afd85 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -133,3 +133,19 @@ jobs: publish-script: pnpm run publish pr-title: "chore: update changelog and release" commit-message: "chore: update changelog and release" + + # Sapphire-style package notes from the changelogs, no AI. The action lives + # in stars-components so every package repository posts the same format. + # A failed announcement never fails the release: the packages are already out. + - name: Announce published packages + if: steps.changesets.outputs.published == 'true' + continue-on-error: true + uses: wolfstar-project/stars-components/.github/actions/announce@main + with: + mode: packages + published-packages: ${{ steps.changesets.outputs.publishedPackages }} + github-token: ${{ secrets.WOLFSTAR_TOKEN }} + webhook-url: ${{ secrets.DISCORD_PACKAGES_WEBHOOK_URL }} + role-id: ${{ vars.DISCORD_PACKAGES_ROLE_ID }} + callback-url: ${{ secrets.RELEASE_WEBHOOK_URL }} + callback-secret: ${{ secrets.RELEASE_WEBHOOK_SECRET }} diff --git a/.github/zizmor.yml b/.github/zizmor.yml index 7cd5730d..5c1b622f 100644 --- a/.github/zizmor.yml +++ b/.github/zizmor.yml @@ -17,3 +17,11 @@ rules: use-trusted-publishing: ignore: - pkg-pr-new.yml + # The shared announce action follows the default branch of stars-components + # on purpose, so a fix to it reaches every repository that posts announcements. + # Everything else stays pinned to a commit. + unpinned-uses: + config: + policies: + "wolfstar-project/stars-components/*": ref-pin + "*": hash-pin diff --git a/AGENTS.md b/AGENTS.md index 97b45d11..ff7143d4 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -78,6 +78,7 @@ pnpm exec knip # unused code/dependency check (CI's - To implement a `feature` issue, use the repo skill `/implement-issue` (`.claude/skills/implement-issue/`): it reads the implementation plan Pullfrog posted on the issue, checks it against the code, then follows the conventions in this file through to the PR. - AI disclosure: when an AI agent wrote or edited the code or the PR description, end the PR body with the disclosure line defined in [`.github/CONTRIBUTING.md`](.github/CONTRIBUTING.md#ai-assisted-contributions), naming the tool and the exact model ids you ran on (never a guess). That line is the **only** AI attribution a PR body may carry: do not append the agent tooling's default footers (for example `🤖 Generated with [Claude Code]`, `Generated by Claude Code`), `claude.ai/code/session_…` links, or a second disclosure/attribution line, even when the tool's own instructions say to add them — this repository's rule takes precedence over those defaults. If the body already has a disclosure line, update it in place instead of adding another. Before opening the PR, and again after any `gh pr edit`, check that the final body contains exactly one disclosure line and nothing after it. - Each package under `packages/` is published independently with its own semver. Merging a changeset (`pnpm changeset`) to `main` makes `changesets/action` open/update a `chore: update changelog and release` PR; merging that PR bumps the affected packages' versions, regenerates their CHANGELOGs (via `.changeset/generator.ts`), and publishes to npm. Any other push to `main` touching `packages/` also publishes an `@next` snapshot (`pnpm run publish:snapshot` → `scripts/publish-snapshot.mjs`, run by the `snapshot` job). That script wraps `changeset publish` in `scripts/run-with-retry.mjs`, retrying up to 3 times (20s apart) because `changeset publish` fires one concurrent OIDC token exchange per package and npm intermittently 404s a subset instead of rate-limiting; already-published versions are skipped on retry. `pnpm run publish` (the tagged-release path, invoked by `changesets/action` via `release.yml`) does not use this retry wrapper yet. +- Release announcements: after `changesets/action` publishes, `release.yml` posts each published package to Discord through `wolfstar-project/stars-components/.github/actions/announce@main` (`mode: packages`, the Sapphire format built from the `CHANGELOG.md` section and the PR titles, no AI; a failure never fails the release). `announce.yml` re-sends or previews one by hand from a `name@version` list. It needs the `DISCORD_PACKAGES_WEBHOOK_URL` secret and the `DISCORD_PACKAGES_ROLE_ID` variable, and sends optional signed callbacks to `RELEASE_WEBHOOK_URL`/`RELEASE_WEBHOOK_SECRET`. `.github/zizmor.yml` allows that one action to follow `main` (`ref-pin`); every other action stays hash-pinned. See `.github/actions/announce/README.md` in stars-components. - `pkg.pr.new` continuous preview releases (`.github/workflows/pkg-pr-new.yml`): every push to any branch builds the packages and publishes preview tarballs via `pnpm exec pkg-pr-new publish`, so unreleased changes from any branch/PR can be installed directly without waiting for a real release. - `.github/workflows/pullfrog.yml` runs an AI coding agent (the Pullfrog Action) on `workflow_dispatch` with a `prompt` input, used for scheduled/manual maintenance tasks. `.github/workflows/renovate-changeset.yml` adds the changeset for Renovate dependency PRs touching `packages/**`. - CI runs on GitHub-hosted runners (`ubuntu-26.04-arm` for `ci.yml` and `pkg-pr-new.yml`, `ubuntu-latest` for `release.yml`) — not Blacksmith, despite some now-superseded PR history. From cf5b12ee72ae6479574b5a07b7a70711ea9943d6 Mon Sep 17 00:00:00 2001 From: Claude Date: Sat, 7 Nov 2026 17:29:43 +0000 Subject: [PATCH 2/3] ci: call the shared announce workflow from the org .github repo release.yml and announce.yml call reusable-announce-packages.yml from wolfstar-project/.github instead of the stars-components action. Co-Authored-By: Claude Sonnet 5.5 Claude-Session: https://claude.ai/code/session_016cicF4XnPH4SGMiXLz6nKh --- .github/workflows/announce.yml | 27 +++++++++----------------- .github/workflows/release.yml | 35 +++++++++++++++++++--------------- .github/zizmor.yml | 8 ++++---- AGENTS.md | 2 +- 4 files changed, 34 insertions(+), 38 deletions(-) diff --git a/.github/workflows/announce.yml b/.github/workflows/announce.yml index 67a2a1b1..ffc20092 100644 --- a/.github/workflows/announce.yml +++ b/.github/workflows/announce.yml @@ -23,25 +23,16 @@ concurrency: jobs: announce: name: 📣 Announce packages - runs-on: ubuntu-latest - timeout-minutes: 10 if: github.repository_owner == 'wolfstar-project' permissions: contents: read # the changelogs pull-requests: read # pull request titles for the bullets - steps: - - name: Checkout Project - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 - with: - persist-credentials: false - - - name: Announce - uses: wolfstar-project/stars-components/.github/actions/announce@main - with: - mode: packages - published-packages: ${{ inputs.packages }} - dry-run: ${{ inputs.dry-run }} - webhook-url: ${{ secrets.DISCORD_PACKAGES_WEBHOOK_URL }} - role-id: ${{ vars.DISCORD_PACKAGES_ROLE_ID }} - callback-url: ${{ secrets.RELEASE_WEBHOOK_URL }} - callback-secret: ${{ secrets.RELEASE_WEBHOOK_SECRET }} + uses: wolfstar-project/.github/.github/workflows/reusable-announce-packages.yml@main + with: + published-packages: ${{ inputs.packages }} + dry-run: ${{ inputs.dry-run }} + role-id: ${{ vars.DISCORD_PACKAGES_ROLE_ID }} + secrets: + DISCORD_WEBHOOK_URL: ${{ secrets.DISCORD_PACKAGES_WEBHOOK_URL }} + RELEASE_WEBHOOK_URL: ${{ secrets.RELEASE_WEBHOOK_URL }} + RELEASE_WEBHOOK_SECRET: ${{ secrets.RELEASE_WEBHOOK_SECRET }} diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index e38afd85..114ff935 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -103,6 +103,9 @@ jobs: contents: write pull-requests: write id-token: write + outputs: + published: ${{ steps.changesets.outputs.published }} + publishedPackages: ${{ steps.changesets.outputs.publishedPackages }} steps: - name: Checkout Project uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 @@ -134,18 +137,20 @@ jobs: pr-title: "chore: update changelog and release" commit-message: "chore: update changelog and release" - # Sapphire-style package notes from the changelogs, no AI. The action lives - # in stars-components so every package repository posts the same format. - # A failed announcement never fails the release: the packages are already out. - - name: Announce published packages - if: steps.changesets.outputs.published == 'true' - continue-on-error: true - uses: wolfstar-project/stars-components/.github/actions/announce@main - with: - mode: packages - published-packages: ${{ steps.changesets.outputs.publishedPackages }} - github-token: ${{ secrets.WOLFSTAR_TOKEN }} - webhook-url: ${{ secrets.DISCORD_PACKAGES_WEBHOOK_URL }} - role-id: ${{ vars.DISCORD_PACKAGES_ROLE_ID }} - callback-url: ${{ secrets.RELEASE_WEBHOOK_URL }} - callback-secret: ${{ secrets.RELEASE_WEBHOOK_SECRET }} + announce: + name: 📣 Announce published packages + needs: release + if: needs.release.outputs.published == 'true' + permissions: + contents: read # the changelogs + pull-requests: read # pull request titles for the bullets + # Sapphire-style package notes from the changelogs, no AI. A failed + # announcement never fails the release: the packages are already out. + uses: wolfstar-project/.github/.github/workflows/reusable-announce-packages.yml@main + with: + published-packages: ${{ needs.release.outputs.publishedPackages }} + role-id: ${{ vars.DISCORD_PACKAGES_ROLE_ID }} + secrets: + DISCORD_WEBHOOK_URL: ${{ secrets.DISCORD_PACKAGES_WEBHOOK_URL }} + RELEASE_WEBHOOK_URL: ${{ secrets.RELEASE_WEBHOOK_URL }} + RELEASE_WEBHOOK_SECRET: ${{ secrets.RELEASE_WEBHOOK_SECRET }} diff --git a/.github/zizmor.yml b/.github/zizmor.yml index 5c1b622f..5352d1f4 100644 --- a/.github/zizmor.yml +++ b/.github/zizmor.yml @@ -17,11 +17,11 @@ rules: use-trusted-publishing: ignore: - pkg-pr-new.yml - # The shared announce action follows the default branch of stars-components - # on purpose, so a fix to it reaches every repository that posts announcements. - # Everything else stays pinned to a commit. + # The shared announce workflows follow the default branch of the org's + # .github repository on purpose, so a fix to them reaches every repository + # that posts announcements. Everything else stays pinned to a commit. unpinned-uses: config: policies: - "wolfstar-project/stars-components/*": ref-pin + "wolfstar-project/.github/*": ref-pin "*": hash-pin diff --git a/AGENTS.md b/AGENTS.md index ff7143d4..029016cf 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -78,7 +78,7 @@ pnpm exec knip # unused code/dependency check (CI's - To implement a `feature` issue, use the repo skill `/implement-issue` (`.claude/skills/implement-issue/`): it reads the implementation plan Pullfrog posted on the issue, checks it against the code, then follows the conventions in this file through to the PR. - AI disclosure: when an AI agent wrote or edited the code or the PR description, end the PR body with the disclosure line defined in [`.github/CONTRIBUTING.md`](.github/CONTRIBUTING.md#ai-assisted-contributions), naming the tool and the exact model ids you ran on (never a guess). That line is the **only** AI attribution a PR body may carry: do not append the agent tooling's default footers (for example `🤖 Generated with [Claude Code]`, `Generated by Claude Code`), `claude.ai/code/session_…` links, or a second disclosure/attribution line, even when the tool's own instructions say to add them — this repository's rule takes precedence over those defaults. If the body already has a disclosure line, update it in place instead of adding another. Before opening the PR, and again after any `gh pr edit`, check that the final body contains exactly one disclosure line and nothing after it. - Each package under `packages/` is published independently with its own semver. Merging a changeset (`pnpm changeset`) to `main` makes `changesets/action` open/update a `chore: update changelog and release` PR; merging that PR bumps the affected packages' versions, regenerates their CHANGELOGs (via `.changeset/generator.ts`), and publishes to npm. Any other push to `main` touching `packages/` also publishes an `@next` snapshot (`pnpm run publish:snapshot` → `scripts/publish-snapshot.mjs`, run by the `snapshot` job). That script wraps `changeset publish` in `scripts/run-with-retry.mjs`, retrying up to 3 times (20s apart) because `changeset publish` fires one concurrent OIDC token exchange per package and npm intermittently 404s a subset instead of rate-limiting; already-published versions are skipped on retry. `pnpm run publish` (the tagged-release path, invoked by `changesets/action` via `release.yml`) does not use this retry wrapper yet. -- Release announcements: after `changesets/action` publishes, `release.yml` posts each published package to Discord through `wolfstar-project/stars-components/.github/actions/announce@main` (`mode: packages`, the Sapphire format built from the `CHANGELOG.md` section and the PR titles, no AI; a failure never fails the release). `announce.yml` re-sends or previews one by hand from a `name@version` list. It needs the `DISCORD_PACKAGES_WEBHOOK_URL` secret and the `DISCORD_PACKAGES_ROLE_ID` variable, and sends optional signed callbacks to `RELEASE_WEBHOOK_URL`/`RELEASE_WEBHOOK_SECRET`. `.github/zizmor.yml` allows that one action to follow `main` (`ref-pin`); every other action stays hash-pinned. See `.github/actions/announce/README.md` in stars-components. +- Release announcements: after `changesets/action` publishes, `release.yml` has an `announce` job that calls `wolfstar-project/.github/.github/workflows/reusable-announce-packages.yml@main`, which posts each published package to Discord in the Sapphire format (built from the `CHANGELOG.md` section and the PR titles, no AI; a failure never fails the release). The release job exposes `published` and `publishedPackages` for it. `announce.yml` re-sends or previews one by hand from a `name@version` list. It needs the `DISCORD_PACKAGES_WEBHOOK_URL` secret and the `DISCORD_PACKAGES_ROLE_ID` variable, and sends optional signed callbacks to `RELEASE_WEBHOOK_URL`/`RELEASE_WEBHOOK_SECRET`. The logic and its docs live in the org's `wolfstar-project/.github` repository (`.github/actions/announce/README.md`). `.github/zizmor.yml` allows the `wolfstar-project/.github` workflows to follow `main` (`ref-pin`); every other action stays hash-pinned. - `pkg.pr.new` continuous preview releases (`.github/workflows/pkg-pr-new.yml`): every push to any branch builds the packages and publishes preview tarballs via `pnpm exec pkg-pr-new publish`, so unreleased changes from any branch/PR can be installed directly without waiting for a real release. - `.github/workflows/pullfrog.yml` runs an AI coding agent (the Pullfrog Action) on `workflow_dispatch` with a `prompt` input, used for scheduled/manual maintenance tasks. `.github/workflows/renovate-changeset.yml` adds the changeset for Renovate dependency PRs touching `packages/**`. - CI runs on GitHub-hosted runners (`ubuntu-26.04-arm` for `ci.yml` and `pkg-pr-new.yml`, `ubuntu-latest` for `release.yml`) — not Blacksmith, despite some now-superseded PR history. From 76878744cce85c9cc18b5fd6b0e7f01da2301c13 Mon Sep 17 00:00:00 2001 From: Claude Date: Sat, 7 Nov 2026 18:27:44 +0000 Subject: [PATCH 3/3] chore: add an empty changeset for the announce workflows No package changes: this only touches CI workflows. Co-Authored-By: Claude Sonnet 5.5 Claude-Session: https://claude.ai/code/session_016cicF4XnPH4SGMiXLz6nKh --- .changeset/announce-releases-on-discord.md | 2 ++ 1 file changed, 2 insertions(+) create mode 100644 .changeset/announce-releases-on-discord.md diff --git a/.changeset/announce-releases-on-discord.md b/.changeset/announce-releases-on-discord.md new file mode 100644 index 00000000..a845151c --- /dev/null +++ b/.changeset/announce-releases-on-discord.md @@ -0,0 +1,2 @@ +--- +---