Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
81 changes: 81 additions & 0 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
@@ -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/<name>/). 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 == 'true' }}
- uses: pnpm/action-setup@v4
if: ${{ steps.release.outputs.releases_created == 'true' }}
with:
version: 11.1.1
- uses: actions/setup-node@v6
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 == 'true' }}
env:
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
run: |
set -eu
cd "packages/${{ matrix.package }}"
# 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
# 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
32 changes: 32 additions & 0 deletions docs/documentation-audiences.json
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand All @@ -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"
Expand Down Expand Up @@ -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"
Expand All @@ -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"
Expand All @@ -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"
Expand All @@ -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"
Expand Down Expand Up @@ -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"
Expand Down Expand Up @@ -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"
Expand Down
4 changes: 2 additions & 2 deletions packages/drill/.github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,8 @@ 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
- CHANGELOG.md
- packages/drill/.release-please-manifest.json
- packages/drill/CHANGELOG.md

jobs:
check:
Expand Down
4 changes: 2 additions & 2 deletions packages/drill/.github/workflows/drill-required.yml
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,8 @@ 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
- packages/drill/.release-please-manifest.json
- packages/drill/CHANGELOG.md

permissions:
contents: read
Expand Down
8 changes: 4 additions & 4 deletions packages/drill/.github/workflows/guard-generated-files.yml
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,8 @@ 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
- packages/drill/.release-please-manifest.json
- packages/drill/CHANGELOG.md

permissions:
contents: read
Expand Down Expand Up @@ -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 packages/drill/.release-please-manifest.json; do
if printf '%s\n' "$files" | grep -qxF -- "$path"; then
violated="${violated} ${path}"
fi
Expand All @@ -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 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"
Expand Down
2 changes: 1 addition & 1 deletion packages/drill/.release-please-manifest.json
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
{
".": "0.1.0"
"packages/drill": "0.1.0"
}
2 changes: 1 addition & 1 deletion packages/drill/AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -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**
Expand Down
15 changes: 15 additions & 0 deletions packages/drill/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -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))

4 changes: 3 additions & 1 deletion packages/drill/release-please-config.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
{
"bootstrap-sha": "71715714efeea44e804152126f25c199a8ffe7fa",
"packages": {
".": {
"packages/drill": {
"release-type": "go",
"package-name": "drill",
"bump-minor-pre-major": true,
"bump-patch-for-minor-pre-major": true,
"draft": true,
Expand Down
7 changes: 5 additions & 2 deletions packages/drill/workflow_release_pr_ci_exclusions_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -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/<name>/.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")
Expand Down
8 changes: 4 additions & 4 deletions packages/drill/workflow_release_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -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")
Expand All @@ -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")
Expand Down
6 changes: 3 additions & 3 deletions packages/fob/.github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,9 @@ on:
pull_request:
branches: [main]
paths-ignore:
- .release-please-manifest.json
- CHANGELOG.md
- flake.nix
- packages/fob/.release-please-manifest.json
- packages/fob/CHANGELOG.md
- packages/fob/flake.nix

jobs:
check:
Expand Down
2 changes: 1 addition & 1 deletion packages/fob/.release-please-manifest.json
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
{
".": "0.1.0"
"packages/fob": "0.1.0"
}
13 changes: 13 additions & 0 deletions packages/fob/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
# Changelog

## 0.1.0 (2026-08-14)

### Features

* **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

* **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))

4 changes: 3 additions & 1 deletion packages/fob/release-please-config.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
{
"bootstrap-sha": "71715714efeea44e804152126f25c199a8ffe7fa",
"packages": {
".": {
"packages/fob": {
"release-type": "go",
"package-name": "fob",
"bump-minor-pre-major": true,
"bump-patch-for-minor-pre-major": true,
"extra-files": [
Expand Down
19 changes: 14 additions & 5 deletions packages/fob/release_ci_exclusions_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -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 != "" {
Expand Down Expand Up @@ -84,6 +89,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{}{}
}
}
Expand Down Expand Up @@ -356,7 +365,7 @@ func TestExpectedReleaseOutputsIncludesConfiguredExtraFiles(t *testing.T) {
if err != nil {
t.Fatal(err)
}
want := []string{".release-please-manifest.json", "CHANGELOG.md", "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)
}
Expand Down
2 changes: 1 addition & 1 deletion packages/pr-review/.release-please-manifest.json
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
{
".": "0.1.0"
"packages/pr-review": "0.1.0"
}
Loading
Loading