Skip to content

feat(plan): date-ground the planner and critic prompts #80

feat(plan): date-ground the planner and critic prompts

feat(plan): date-ground the planner and critic prompts #80

Workflow file for this run

name: Auto release on version bump
# Fires on merge of ANY PR to master. Exits early unless package.json's
# `version` field differs from the parent commit's — so PRs that don't
# touch version are cheap no-ops (~10s). When the version did change,
# creates the matching `vX.Y.Z` tag + GitHub release AND publishes to
# npm inline — both steps in the same job.
#
# Why inline-publish rather than relying on publish.yml's `release:
# published` trigger: GitHub intentionally doesn't fire other workflows
# for events created by GITHUB_TOKEN (loop protection). So
# `gh release create` here would create the release but NOT kick
# publish.yml — which cost us a manual delete+recreate on v0.3.0 before
# this was fixed. Inlining means the chain is:
# PR merge → this workflow → tag+release+npm publish in one run.
#
# publish.yml stays in place for the *manual* release case (a maintainer
# running `gh release create` locally does trigger publish.yml, since
# that release event isn't from GITHUB_TOKEN).
on:
pull_request:
types: [closed]
branches: [master]
permissions:
contents: write
# id-token: write required for `npm publish --provenance` (SLSA
# attestation). Without this, npm publish would fail or skip provenance.
id-token: write
jobs:
release:
# Guards stacked so a closed-but-not-merged PR or a merge that didn't
# touch package.json never fires a release:
# 1. pull_request event type must be `closed` (implicit from `on:`)
# 2. `merged == true` rules out close-without-merge
# 3. version-changed check (first step) short-circuits the rest
if: github.event.pull_request.merged == true
runs-on: ubuntu-latest
steps:
- name: Checkout master (post-merge state)
uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
with:
ref: master
fetch-depth: 2 # need HEAD^1 for the version-diff check
- name: Check if version actually changed
id: ver
# Compares package.json's `version` field between HEAD and HEAD^1.
# Unchanged → skip. Malformed (non-X.Y.Z) → abort loudly. Bumped
# cleanly → proceed with `version` + `changed=true` as outputs.
run: |
set -eo pipefail
CURRENT=$(node -pe "require('./package.json').version")
PARENT=$(git show HEAD^1:package.json 2>/dev/null \
| node -pe "JSON.parse(require('fs').readFileSync(0,'utf-8')).version" \
|| echo "")
if [ "$CURRENT" = "$PARENT" ]; then
echo "Version unchanged at $CURRENT — not releasing."
echo "changed=false" >> "$GITHUB_OUTPUT"
exit 0
fi
if ! [[ "$CURRENT" =~ ^[0-9]+\.[0-9]+\.[0-9]+$ ]]; then
echo "Refusing to release — package.json version '$CURRENT' doesn't match X.Y.Z" >&2
exit 1
fi
echo "Version bumped: $PARENT → $CURRENT"
echo "changed=true" >> "$GITHUB_OUTPUT"
echo "version=$CURRENT" >> "$GITHUB_OUTPUT"
- name: Ensure tag doesn't already exist
if: steps.ver.outputs.changed == 'true'
run: |
TAG="v${{ steps.ver.outputs.version }}"
if git rev-parse "$TAG" >/dev/null 2>&1; then
echo "Tag $TAG already exists — likely a previous run already released this version. Aborting to avoid tag-overwrite."
exit 1
fi
# ─── Build + test pipeline (mirrors publish.yml) ──────────────
# We do this BEFORE cutting the GitHub release, so a failing
# build/test aborts everything — no release, no npm publish, no
# half-shipped state. Node 22 matches publish.yml's choice.
- name: Set up Node
if: steps.ver.outputs.changed == 'true'
uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0
with:
node-version: 22
registry-url: https://registry.npmjs.org
- name: npm ci
if: steps.ver.outputs.changed == 'true'
env:
PLAYWRIGHT_SKIP_BROWSER_DOWNLOAD: "1"
run: npm ci
- name: typecheck
if: steps.ver.outputs.changed == 'true'
run: npm run typecheck
- name: build
if: steps.ver.outputs.changed == 'true'
run: npm run build
- name: test
if: steps.ver.outputs.changed == 'true'
run: npm test
- name: --help smoke
if: steps.ver.outputs.changed == 'true'
run: node dist/cli.js --help
# ─── Release + publish ────────────────────────────────────────
- name: Extract release notes from CHANGELOG
if: steps.ver.outputs.changed == 'true'
# Pulls the section for this version from CHANGELOG.md so the
# GitHub release body shows what was in the bump, not a generic
# "see changelog" link. Tiny Node one-liner to avoid shell-
# escaping the markdown.
run: |
set -eo pipefail
VERSION="${{ steps.ver.outputs.version }}"
node -e "
const fs = require('fs');
const md = fs.readFileSync('CHANGELOG.md', 'utf-8');
const re = new RegExp('^## \\\\[' + '${VERSION}' + '\\\\][^\\\\n]*\\\\n([\\\\s\\\\S]*?)(?=\\\\n## \\\\[|$)', 'm');
const m = re.exec(md);
process.stdout.write(m ? m[1].trim() : '(no changelog section found for this version)');
" > release-notes.md
echo "--- release-notes.md ---"
cat release-notes.md
- name: Create GitHub release
if: steps.ver.outputs.changed == 'true'
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
TAG="v${{ steps.ver.outputs.version }}"
{
echo "Auto-released from merge of [PR #${{ github.event.pull_request.number }}](${{ github.event.pull_request.html_url }})."
echo ""
cat release-notes.md
echo ""
echo "---"
echo ""
echo "Built + tested + npm-published inline by \`auto-release.yml\` on this run. See the workflow log for the provenance-attested publish output."
} > body.md
gh release create "$TAG" --title "$TAG" --notes-file body.md
- name: npm publish
if: steps.ver.outputs.changed == 'true'
env:
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
run: npm publish --access public --provenance
- name: Post-release summary
if: steps.ver.outputs.changed == 'true'
run: |
echo "✓ Released v${{ steps.ver.outputs.version }}"
echo "✓ Triggered by PR #${{ github.event.pull_request.number }}"
echo "✓ Published to npm (with SLSA provenance)"