diff --git a/.changeset/exact-gh-aw-enlistment-version.md b/.changeset/exact-gh-aw-enlistment-version.md new file mode 100644 index 000000000..a2450cd22 --- /dev/null +++ b/.changeset/exact-gh-aw-enlistment-version.md @@ -0,0 +1,8 @@ +--- +"@bradygaster/squad-cli": patch +"@bradygaster/squad-sdk": patch +--- + +Make public Squad gh-aw enlistment prove exact compiler version `v0.89.22`, +cleanly reinstall the pinned extension on mismatch, and stop before generating +repository artifacts when the supported version cannot be verified. diff --git a/.squad-templates/skills/gh-aw-enlistment/SKILL.md b/.squad-templates/skills/gh-aw-enlistment/SKILL.md index f6ac0e9fe..fd87d223c 100644 --- a/.squad-templates/skills/gh-aw-enlistment/SKILL.md +++ b/.squad-templates/skills/gh-aw-enlistment/SKILL.md @@ -54,27 +54,50 @@ condition and wait for a human decision — do not work around it. # gh is authenticated gh auth status +# Prove the exact package-capable compiler version before creating artifacts +# gh-aw-exact-version-start +required_gh_aw_version="v0.89.22" +gh_aw_version_output="$(gh aw --version 2>&1)" || gh_aw_version_output="" +gh_aw_version="$(printf '%s\n' "${gh_aw_version_output}" | awk 'END {print $NF}')" + +if [ "${gh_aw_version}" != "${required_gh_aw_version}" ]; then + echo "Installing exact supported gh-aw ${required_gh_aw_version}." + gh extension remove gh-aw >/dev/null 2>&1 || true + gh extension install --pin "${required_gh_aw_version}" github/gh-aw + gh_aw_version_output="$(gh aw --version 2>&1)" || { + echo "STOP: gh-aw version could not be verified after clean installation." >&2 + exit 1 + } + gh_aw_version="$(printf '%s\n' "${gh_aw_version_output}" | awk 'END {print $NF}')" +fi + +test "${gh_aw_version}" = "${required_gh_aw_version}" || { + echo "STOP: required gh-aw v0.89.22, but found ${gh_aw_version:-unavailable} after clean installation." >&2 + exit 1 +} +# gh-aw-exact-version-end + # Capture repository identity and default branch AT RUNTIME owner_repo="$(gh repo view --json nameWithOwner --jq '.nameWithOwner')" default_branch="$(gh repo view --json defaultBranchRef --jq '.defaultBranchRef.name')" echo "Repo: ${owner_repo} Default branch: ${default_branch}" -# Install the package-capable compiler version used by the distribution contract -gh extension install --force --pin v0.89.22 github/gh-aw -test "$(gh aw --version | awk '{print $NF}')" = "v0.89.22" - # Git state must be understood and clean enough to isolate the install git status --short ``` > **Portability — compiler check:** use the equivalent PowerShell commands to -> force-install `github/gh-aw` at `v0.89.22`, then confirm `gh aw --version` -> reports that exact version before installation. +> capture both output streams from `gh aw --version`. On any mismatch, remove +> `github/gh-aw`, cleanly install the exact `v0.89.22` pin, and verify both +> streams again. Stop before branch creation or file generation unless that +> second check proves exactly `v0.89.22`; never select a newer release. - **STOP** if `gh auth status` is not logged in, or is logged in as the wrong identity for this repo (see the `gh-auth-isolation` skill to operate as a specific account without switching the global default). - **STOP** if `owner_repo` or `default_branch` cannot be resolved. +- **STOP** if exact gh-aw `v0.89.22` cannot be proven after the clean pinned + reinstall. Do not create a branch or generate repository files. - **STOP** if the working tree has unrelated uncommitted changes you cannot account for — the bootstrap must land as an isolated, reviewable change. - Confirm Copilot is enabled for the repository where checkable; the activation @@ -166,7 +189,7 @@ full stack consistent and avoids a second bootstrap pass later. Report/proposal-only is the default. Ordinary fixes require the explicit `"squadRetroAutoImplement": "allow"` setting in `.squad/config.json`; -five action issues and three dispatches per wakeup remain separate caps. +five action issues and three dispatches per wake-up remain separate caps. An improvement requires `/squad approve-improvement`, `Approved-Revision:` and exact `Approved-Path:` lines from a human with write/maintain/admin access. The dispatcher sends nested issue and approval-comment IDs to the worker; diff --git a/docs/src/content/docs/guide/gh-aw.md b/docs/src/content/docs/guide/gh-aw.md index a478eff7b..ce60a0056 100644 --- a/docs/src/content/docs/guide/gh-aw.md +++ b/docs/src/content/docs/guide/gh-aw.md @@ -27,12 +27,33 @@ Seven steps from zero to a validated, reviewable Squad bootstrap: ```bash set -euo pipefail -# 1. Verify GitHub access, resolve this repo, and install gh-aw if needed +# 1. Verify GitHub access and prove the exact supported gh-aw version gh auth status + +# gh-aw-exact-version-start +required_gh_aw_version="v0.89.22" +gh_aw_version_output="$(gh aw --version 2>&1)" || gh_aw_version_output="" +gh_aw_version="$(printf '%s\n' "${gh_aw_version_output}" | awk 'END {print $NF}')" + +if [ "${gh_aw_version}" != "${required_gh_aw_version}" ]; then + echo "Installing exact supported gh-aw ${required_gh_aw_version}." + gh extension remove gh-aw >/dev/null 2>&1 || true + gh extension install --pin "${required_gh_aw_version}" github/gh-aw + gh_aw_version_output="$(gh aw --version 2>&1)" || { + echo "STOP: gh-aw version could not be verified after clean installation." >&2 + exit 1 + } + gh_aw_version="$(printf '%s\n' "${gh_aw_version_output}" | awk 'END {print $NF}')" +fi + +test "${gh_aw_version}" = "${required_gh_aw_version}" || { + echo "STOP: required gh-aw v0.89.22, but found ${gh_aw_version:-unavailable} after clean installation." >&2 + exit 1 +} +# gh-aw-exact-version-end + owner_repo="$(gh repo view --json nameWithOwner --jq '.nameWithOwner')" default_branch="$(gh repo view --json defaultBranchRef --jq '.defaultBranchRef.name')" -gh extension install --force --pin v0.89.22 github/gh-aw -test "$(gh aw --version | awk '{print $NF}')" = "v0.89.22" # 2. Require GitHub Issues, then allow GitHub Actions to create pull requests issues_enabled="$(gh api "repos/${owner_repo}" --jq '.has_issues')" diff --git a/packages/squad-cli/templates/skills/gh-aw-enlistment/SKILL.md b/packages/squad-cli/templates/skills/gh-aw-enlistment/SKILL.md index f6ac0e9fe..fd87d223c 100644 --- a/packages/squad-cli/templates/skills/gh-aw-enlistment/SKILL.md +++ b/packages/squad-cli/templates/skills/gh-aw-enlistment/SKILL.md @@ -54,27 +54,50 @@ condition and wait for a human decision — do not work around it. # gh is authenticated gh auth status +# Prove the exact package-capable compiler version before creating artifacts +# gh-aw-exact-version-start +required_gh_aw_version="v0.89.22" +gh_aw_version_output="$(gh aw --version 2>&1)" || gh_aw_version_output="" +gh_aw_version="$(printf '%s\n' "${gh_aw_version_output}" | awk 'END {print $NF}')" + +if [ "${gh_aw_version}" != "${required_gh_aw_version}" ]; then + echo "Installing exact supported gh-aw ${required_gh_aw_version}." + gh extension remove gh-aw >/dev/null 2>&1 || true + gh extension install --pin "${required_gh_aw_version}" github/gh-aw + gh_aw_version_output="$(gh aw --version 2>&1)" || { + echo "STOP: gh-aw version could not be verified after clean installation." >&2 + exit 1 + } + gh_aw_version="$(printf '%s\n' "${gh_aw_version_output}" | awk 'END {print $NF}')" +fi + +test "${gh_aw_version}" = "${required_gh_aw_version}" || { + echo "STOP: required gh-aw v0.89.22, but found ${gh_aw_version:-unavailable} after clean installation." >&2 + exit 1 +} +# gh-aw-exact-version-end + # Capture repository identity and default branch AT RUNTIME owner_repo="$(gh repo view --json nameWithOwner --jq '.nameWithOwner')" default_branch="$(gh repo view --json defaultBranchRef --jq '.defaultBranchRef.name')" echo "Repo: ${owner_repo} Default branch: ${default_branch}" -# Install the package-capable compiler version used by the distribution contract -gh extension install --force --pin v0.89.22 github/gh-aw -test "$(gh aw --version | awk '{print $NF}')" = "v0.89.22" - # Git state must be understood and clean enough to isolate the install git status --short ``` > **Portability — compiler check:** use the equivalent PowerShell commands to -> force-install `github/gh-aw` at `v0.89.22`, then confirm `gh aw --version` -> reports that exact version before installation. +> capture both output streams from `gh aw --version`. On any mismatch, remove +> `github/gh-aw`, cleanly install the exact `v0.89.22` pin, and verify both +> streams again. Stop before branch creation or file generation unless that +> second check proves exactly `v0.89.22`; never select a newer release. - **STOP** if `gh auth status` is not logged in, or is logged in as the wrong identity for this repo (see the `gh-auth-isolation` skill to operate as a specific account without switching the global default). - **STOP** if `owner_repo` or `default_branch` cannot be resolved. +- **STOP** if exact gh-aw `v0.89.22` cannot be proven after the clean pinned + reinstall. Do not create a branch or generate repository files. - **STOP** if the working tree has unrelated uncommitted changes you cannot account for — the bootstrap must land as an isolated, reviewable change. - Confirm Copilot is enabled for the repository where checkable; the activation @@ -166,7 +189,7 @@ full stack consistent and avoids a second bootstrap pass later. Report/proposal-only is the default. Ordinary fixes require the explicit `"squadRetroAutoImplement": "allow"` setting in `.squad/config.json`; -five action issues and three dispatches per wakeup remain separate caps. +five action issues and three dispatches per wake-up remain separate caps. An improvement requires `/squad approve-improvement`, `Approved-Revision:` and exact `Approved-Path:` lines from a human with write/maintain/admin access. The dispatcher sends nested issue and approval-comment IDs to the worker; diff --git a/packages/squad-sdk/templates/skills/gh-aw-enlistment/SKILL.md b/packages/squad-sdk/templates/skills/gh-aw-enlistment/SKILL.md index f6ac0e9fe..fd87d223c 100644 --- a/packages/squad-sdk/templates/skills/gh-aw-enlistment/SKILL.md +++ b/packages/squad-sdk/templates/skills/gh-aw-enlistment/SKILL.md @@ -54,27 +54,50 @@ condition and wait for a human decision — do not work around it. # gh is authenticated gh auth status +# Prove the exact package-capable compiler version before creating artifacts +# gh-aw-exact-version-start +required_gh_aw_version="v0.89.22" +gh_aw_version_output="$(gh aw --version 2>&1)" || gh_aw_version_output="" +gh_aw_version="$(printf '%s\n' "${gh_aw_version_output}" | awk 'END {print $NF}')" + +if [ "${gh_aw_version}" != "${required_gh_aw_version}" ]; then + echo "Installing exact supported gh-aw ${required_gh_aw_version}." + gh extension remove gh-aw >/dev/null 2>&1 || true + gh extension install --pin "${required_gh_aw_version}" github/gh-aw + gh_aw_version_output="$(gh aw --version 2>&1)" || { + echo "STOP: gh-aw version could not be verified after clean installation." >&2 + exit 1 + } + gh_aw_version="$(printf '%s\n' "${gh_aw_version_output}" | awk 'END {print $NF}')" +fi + +test "${gh_aw_version}" = "${required_gh_aw_version}" || { + echo "STOP: required gh-aw v0.89.22, but found ${gh_aw_version:-unavailable} after clean installation." >&2 + exit 1 +} +# gh-aw-exact-version-end + # Capture repository identity and default branch AT RUNTIME owner_repo="$(gh repo view --json nameWithOwner --jq '.nameWithOwner')" default_branch="$(gh repo view --json defaultBranchRef --jq '.defaultBranchRef.name')" echo "Repo: ${owner_repo} Default branch: ${default_branch}" -# Install the package-capable compiler version used by the distribution contract -gh extension install --force --pin v0.89.22 github/gh-aw -test "$(gh aw --version | awk '{print $NF}')" = "v0.89.22" - # Git state must be understood and clean enough to isolate the install git status --short ``` > **Portability — compiler check:** use the equivalent PowerShell commands to -> force-install `github/gh-aw` at `v0.89.22`, then confirm `gh aw --version` -> reports that exact version before installation. +> capture both output streams from `gh aw --version`. On any mismatch, remove +> `github/gh-aw`, cleanly install the exact `v0.89.22` pin, and verify both +> streams again. Stop before branch creation or file generation unless that +> second check proves exactly `v0.89.22`; never select a newer release. - **STOP** if `gh auth status` is not logged in, or is logged in as the wrong identity for this repo (see the `gh-auth-isolation` skill to operate as a specific account without switching the global default). - **STOP** if `owner_repo` or `default_branch` cannot be resolved. +- **STOP** if exact gh-aw `v0.89.22` cannot be proven after the clean pinned + reinstall. Do not create a branch or generate repository files. - **STOP** if the working tree has unrelated uncommitted changes you cannot account for — the bootstrap must land as an isolated, reviewable change. - Confirm Copilot is enabled for the repository where checkable; the activation @@ -166,7 +189,7 @@ full stack consistent and avoids a second bootstrap pass later. Report/proposal-only is the default. Ordinary fixes require the explicit `"squadRetroAutoImplement": "allow"` setting in `.squad/config.json`; -five action issues and three dispatches per wakeup remain separate caps. +five action issues and three dispatches per wake-up remain separate caps. An improvement requires `/squad approve-improvement`, `Approved-Revision:` and exact `Approved-Path:` lines from a human with write/maintain/admin access. The dispatcher sends nested issue and approval-comment IDs to the worker; diff --git a/templates/skills/gh-aw-enlistment/SKILL.md b/templates/skills/gh-aw-enlistment/SKILL.md index f6ac0e9fe..fd87d223c 100644 --- a/templates/skills/gh-aw-enlistment/SKILL.md +++ b/templates/skills/gh-aw-enlistment/SKILL.md @@ -54,27 +54,50 @@ condition and wait for a human decision — do not work around it. # gh is authenticated gh auth status +# Prove the exact package-capable compiler version before creating artifacts +# gh-aw-exact-version-start +required_gh_aw_version="v0.89.22" +gh_aw_version_output="$(gh aw --version 2>&1)" || gh_aw_version_output="" +gh_aw_version="$(printf '%s\n' "${gh_aw_version_output}" | awk 'END {print $NF}')" + +if [ "${gh_aw_version}" != "${required_gh_aw_version}" ]; then + echo "Installing exact supported gh-aw ${required_gh_aw_version}." + gh extension remove gh-aw >/dev/null 2>&1 || true + gh extension install --pin "${required_gh_aw_version}" github/gh-aw + gh_aw_version_output="$(gh aw --version 2>&1)" || { + echo "STOP: gh-aw version could not be verified after clean installation." >&2 + exit 1 + } + gh_aw_version="$(printf '%s\n' "${gh_aw_version_output}" | awk 'END {print $NF}')" +fi + +test "${gh_aw_version}" = "${required_gh_aw_version}" || { + echo "STOP: required gh-aw v0.89.22, but found ${gh_aw_version:-unavailable} after clean installation." >&2 + exit 1 +} +# gh-aw-exact-version-end + # Capture repository identity and default branch AT RUNTIME owner_repo="$(gh repo view --json nameWithOwner --jq '.nameWithOwner')" default_branch="$(gh repo view --json defaultBranchRef --jq '.defaultBranchRef.name')" echo "Repo: ${owner_repo} Default branch: ${default_branch}" -# Install the package-capable compiler version used by the distribution contract -gh extension install --force --pin v0.89.22 github/gh-aw -test "$(gh aw --version | awk '{print $NF}')" = "v0.89.22" - # Git state must be understood and clean enough to isolate the install git status --short ``` > **Portability — compiler check:** use the equivalent PowerShell commands to -> force-install `github/gh-aw` at `v0.89.22`, then confirm `gh aw --version` -> reports that exact version before installation. +> capture both output streams from `gh aw --version`. On any mismatch, remove +> `github/gh-aw`, cleanly install the exact `v0.89.22` pin, and verify both +> streams again. Stop before branch creation or file generation unless that +> second check proves exactly `v0.89.22`; never select a newer release. - **STOP** if `gh auth status` is not logged in, or is logged in as the wrong identity for this repo (see the `gh-auth-isolation` skill to operate as a specific account without switching the global default). - **STOP** if `owner_repo` or `default_branch` cannot be resolved. +- **STOP** if exact gh-aw `v0.89.22` cannot be proven after the clean pinned + reinstall. Do not create a branch or generate repository files. - **STOP** if the working tree has unrelated uncommitted changes you cannot account for — the bootstrap must land as an isolated, reviewable change. - Confirm Copilot is enabled for the repository where checkable; the activation @@ -166,7 +189,7 @@ full stack consistent and avoids a second bootstrap pass later. Report/proposal-only is the default. Ordinary fixes require the explicit `"squadRetroAutoImplement": "allow"` setting in `.squad/config.json`; -five action issues and three dispatches per wakeup remain separate caps. +five action issues and three dispatches per wake-up remain separate caps. An improvement requires `/squad approve-improvement`, `Approved-Revision:` and exact `Approved-Path:` lines from a human with write/maintain/admin access. The dispatcher sends nested issue and approval-comment IDs to the worker; diff --git a/test/gh-aw-enlistment-skill.test.ts b/test/gh-aw-enlistment-skill.test.ts index d824ce114..527037fc6 100644 --- a/test/gh-aw-enlistment-skill.test.ts +++ b/test/gh-aw-enlistment-skill.test.ts @@ -15,6 +15,7 @@ import { describe, it, expect } from 'vitest'; import { readFileSync, existsSync } from 'node:fs'; +import { spawnSync } from 'node:child_process'; import { resolve, dirname } from 'node:path'; import { fileURLToPath } from 'node:url'; import { parseSkillFile } from '@bradygaster/squad-sdk/skills'; @@ -42,6 +43,63 @@ function readLF(rel: string): string { return readRaw(rel).replace(/\r\n/g, '\n'); } +const VERSION_GATE_START = '# gh-aw-exact-version-start'; +const VERSION_GATE_END = '# gh-aw-exact-version-end'; + +function extractVersionGate(content: string): string { + const start = content.indexOf(VERSION_GATE_START); + const end = content.indexOf(VERSION_GATE_END); + expect(start, `${VERSION_GATE_START} must exist`).toBeGreaterThan(-1); + expect(end, `${VERSION_GATE_END} must follow its start marker`).toBeGreaterThan(start); + return content.slice(start + VERSION_GATE_START.length, end); +} + +function runVersionGate( + gate: string, + initialVersion: string, + installedVersion: string, + versionStream: 'stdout' | 'stderr' = 'stdout', +) { + const script = ` +set -euo pipefail +installed=0 +exec 3>&2 +gh() { + if [ "$1" = "aw" ] && [ "$2" = "--version" ]; then + printf 'CALL version\\n' >&3 + version="$INITIAL_VERSION" + if [ "$installed" -eq 1 ]; then version="$INSTALLED_VERSION"; fi + if [ "$VERSION_STREAM" = "stderr" ]; then + printf 'gh-aw %s\\n' "$version" >&2 + else + printf 'gh-aw %s\\n' "$version" + fi + return 0 + fi + if [ "$1" = "extension" ] && [ "$2" = "remove" ] && [ "$3" = "gh-aw" ]; then + printf 'CALL remove\\n' >&3 + return 0 + fi + if [ "$1" = "extension" ] && [ "$2" = "install" ]; then + printf 'CALL install %s %s\\n' "$3" "$4" >&3 + installed=1 + return 0 + fi + return 64 +} +${gate} +`; + return spawnSync('bash', ['-c', script], { + encoding: 'utf8', + env: { + ...process.env, + INITIAL_VERSION: initialVersion, + INSTALLED_VERSION: installedVersion, + VERSION_STREAM: versionStream, + }, + }); +} + const COMPILE_WARNINGS = [ '.github/workflows/squad-review.md: warning: pull_request_target is a very dangerous trigger.', ".github/workflows/squad.md: warning: Both slash_command and bots triggers are configured. If a bot listed in bots: posts a comment that starts with the slash command text (e.g., /command-name), it will trigger the workflow and occupy the concurrency slot, potentially blocking simultaneous manual invocations. To ensure the workflow only runs on explicit user commands, remove the 'bots:' field.", @@ -277,8 +335,11 @@ describe('gh-aw-enlistment skill', () => { }); it('pins and verifies the package-capable gh-aw compiler', () => { - expect(content).toContain('gh extension install --force --pin v0.89.22 github/gh-aw'); - expect(content).toContain('gh aw --version'); + expect(content).toContain('gh_aw_version_output="$(gh aw --version 2>&1)"'); + expect(content).toContain('gh extension remove gh-aw'); + expect(content).toContain('required_gh_aw_version="v0.89.22"'); + expect(content).toContain('gh extension install --pin "${required_gh_aw_version}" github/gh-aw'); + expect(content).toContain('never select a newer release'); expect(content).toContain('PowerShell'); }); @@ -291,6 +352,50 @@ describe('gh-aw-enlistment skill', () => { describe('gh-aw bootstrap documentation', () => { const guide = readLF(GUIDE); const agentGuide = readLF(AGENT_GUIDE); + const versionGate = extractVersionGate(guide); + + it('accepts an existing exact v0.89.22 installation without reinstalling', () => { + const result = runVersionGate(versionGate, 'v0.89.22', 'v0.89.22'); + expect(result.status).toBe(0); + expect(result.stderr.match(/^CALL version$/gm)).toHaveLength(1); + expect(result.stderr).not.toContain('CALL remove'); + expect(result.stderr).not.toContain('CALL install'); + }); + + it('captures exact v0.89.22 version output emitted on stderr', () => { + const result = runVersionGate(versionGate, 'v0.89.22', 'v0.89.22', 'stderr'); + expect(result.status).toBe(0); + expect(result.stderr.match(/^CALL version$/gm)).toHaveLength(1); + expect(result.stderr).not.toContain('CALL remove'); + expect(result.stderr).not.toContain('CALL install'); + }); + + it('removes pre-existing v0.89.21 and verifies a clean v0.89.22 install', () => { + const result = runVersionGate(versionGate, 'v0.89.21', 'v0.89.22'); + expect(result.status).toBe(0); + expect(result.stderr.match(/^CALL version$/gm)).toHaveLength(2); + expect(result.stderr.match(/^CALL remove$/gm)).toHaveLength(1); + expect(result.stderr.match(/^CALL install --pin v0\.89\.22$/gm)).toHaveLength(1); + }); + + it('fails closed when a clean reinstall persistently reports v0.89.21', () => { + const result = runVersionGate(versionGate, 'v0.89.21', 'v0.89.21'); + expect(result.status).toBe(1); + expect(result.stderr).toContain('required gh-aw v0.89.22, but found v0.89.21'); + expect(result.stderr.match(/^CALL version$/gm)).toHaveLength(2); + expect(result.stderr.match(/^CALL remove$/gm)).toHaveLength(1); + expect(result.stderr.match(/^CALL install --pin v0\.89\.22$/gm)).toHaveLength(1); + expect(guide.indexOf(VERSION_GATE_END)).toBeLessThan( + guide.indexOf('git switch -c chore/squad-gh-aw-bootstrap'), + ); + expect(guide.indexOf(VERSION_GATE_END)).toBeLessThan( + guide.indexOf('gh aw add "bradygaster/squad/workflows@${SQUAD_SHA}"'), + ); + }); + + it('keeps the canonical skill version gate synchronized with the guide', () => { + expect(extractVersionGate(readLF(CANONICAL))).toBe(versionGate); + }); it('checks the staged installation before every bootstrap commit', () => { expect(guide.match(/--verify-staged-install --stage-ownership --source-revision "\$\{SQUAD_SHA\}" \|\| exit 1/g)) diff --git a/workflows/skills/gh-aw-enlistment/SKILL.md b/workflows/skills/gh-aw-enlistment/SKILL.md index f6ac0e9fe..fd87d223c 100644 --- a/workflows/skills/gh-aw-enlistment/SKILL.md +++ b/workflows/skills/gh-aw-enlistment/SKILL.md @@ -54,27 +54,50 @@ condition and wait for a human decision — do not work around it. # gh is authenticated gh auth status +# Prove the exact package-capable compiler version before creating artifacts +# gh-aw-exact-version-start +required_gh_aw_version="v0.89.22" +gh_aw_version_output="$(gh aw --version 2>&1)" || gh_aw_version_output="" +gh_aw_version="$(printf '%s\n' "${gh_aw_version_output}" | awk 'END {print $NF}')" + +if [ "${gh_aw_version}" != "${required_gh_aw_version}" ]; then + echo "Installing exact supported gh-aw ${required_gh_aw_version}." + gh extension remove gh-aw >/dev/null 2>&1 || true + gh extension install --pin "${required_gh_aw_version}" github/gh-aw + gh_aw_version_output="$(gh aw --version 2>&1)" || { + echo "STOP: gh-aw version could not be verified after clean installation." >&2 + exit 1 + } + gh_aw_version="$(printf '%s\n' "${gh_aw_version_output}" | awk 'END {print $NF}')" +fi + +test "${gh_aw_version}" = "${required_gh_aw_version}" || { + echo "STOP: required gh-aw v0.89.22, but found ${gh_aw_version:-unavailable} after clean installation." >&2 + exit 1 +} +# gh-aw-exact-version-end + # Capture repository identity and default branch AT RUNTIME owner_repo="$(gh repo view --json nameWithOwner --jq '.nameWithOwner')" default_branch="$(gh repo view --json defaultBranchRef --jq '.defaultBranchRef.name')" echo "Repo: ${owner_repo} Default branch: ${default_branch}" -# Install the package-capable compiler version used by the distribution contract -gh extension install --force --pin v0.89.22 github/gh-aw -test "$(gh aw --version | awk '{print $NF}')" = "v0.89.22" - # Git state must be understood and clean enough to isolate the install git status --short ``` > **Portability — compiler check:** use the equivalent PowerShell commands to -> force-install `github/gh-aw` at `v0.89.22`, then confirm `gh aw --version` -> reports that exact version before installation. +> capture both output streams from `gh aw --version`. On any mismatch, remove +> `github/gh-aw`, cleanly install the exact `v0.89.22` pin, and verify both +> streams again. Stop before branch creation or file generation unless that +> second check proves exactly `v0.89.22`; never select a newer release. - **STOP** if `gh auth status` is not logged in, or is logged in as the wrong identity for this repo (see the `gh-auth-isolation` skill to operate as a specific account without switching the global default). - **STOP** if `owner_repo` or `default_branch` cannot be resolved. +- **STOP** if exact gh-aw `v0.89.22` cannot be proven after the clean pinned + reinstall. Do not create a branch or generate repository files. - **STOP** if the working tree has unrelated uncommitted changes you cannot account for — the bootstrap must land as an isolated, reviewable change. - Confirm Copilot is enabled for the repository where checkable; the activation @@ -166,7 +189,7 @@ full stack consistent and avoids a second bootstrap pass later. Report/proposal-only is the default. Ordinary fixes require the explicit `"squadRetroAutoImplement": "allow"` setting in `.squad/config.json`; -five action issues and three dispatches per wakeup remain separate caps. +five action issues and three dispatches per wake-up remain separate caps. An improvement requires `/squad approve-improvement`, `Approved-Revision:` and exact `Approved-Path:` lines from a human with write/maintain/admin access. The dispatcher sends nested issue and approval-comment IDs to the worker; diff --git a/workflows/squad-workflows.manifest.json b/workflows/squad-workflows.manifest.json index a29fdcf8d..e8dacf717 100644 --- a/workflows/squad-workflows.manifest.json +++ b/workflows/squad-workflows.manifest.json @@ -225,7 +225,7 @@ "name": "gh-aw-enlistment", "source": "workflows/skills/gh-aw-enlistment/SKILL.md", "destination": ".github/skills/gh-aw-enlistment/SKILL.md", - "sha256": "40bb309ee82f5eccda89b5a264d8c55db010fb97df0f23fa9f738341def0d414" + "sha256": "ba9b51e335404b00a157fc78d301a349abb6e68fbf0c834a063febcd4be15396" } ], "bootstrap": {