diff --git a/.changeset/init-next-steps.md b/.changeset/init-next-steps.md
new file mode 100644
index 000000000..c736fe74f
--- /dev/null
+++ b/.changeset/init-next-steps.md
@@ -0,0 +1,5 @@
+---
+"@bradygaster/squad-cli": patch
+---
+
+`squad init` now tells you to run the host you chose (#2453). `squad init --client claude` ends with `claude --agent squad --mcp-config .mcp.json` and a matching `claude -p` tip, instead of telling Claude Code users to run Copilot. With several hosts, it gives one line per host.
diff --git a/.changeset/portable-launch.md b/.changeset/portable-launch.md
new file mode 100644
index 000000000..0e5d6fe83
--- /dev/null
+++ b/.changeset/portable-launch.md
@@ -0,0 +1,6 @@
+---
+"@bradygaster/squad-sdk": patch
+"@bradygaster/squad-cli": patch
+---
+
+Committed files no longer contain paths from your machine (#2462). When the Squad CLI is installed, `squad init` and `squad upgrade` used to write `node /your/path/cli-entry.js state-mcp` into `.mcp.json`, the other hosts' MCP configs and every Claude Code hook in `.claude/settings.json`, so they failed on any other clone. They now write `node .squad/squad.mjs state-mcp`, a launcher Squad commits that finds a Squad CLI on each machine (`SQUAD_CLI`, the project's `node_modules`, then `squad` on PATH; `npx` only with `SQUAD_ALLOW_NPX=1`). Claude hooks reach it through `$CLAUDE_PROJECT_DIR`, and standalone bundle installs write `squad state-mcp`. Run `squad upgrade` once to fix an existing repository. `squad doctor` has a new check that flags machine-specific launch commands and a missing launcher.
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 80e402e4b..c335fc66c 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -64,7 +64,15 @@ Claude Code is the first host after GitHub Copilot where Squad uses the host's o
- The Claude coordinator names Claude Code's `Agent` subagent tool (formerly `Task`). The Claude Code spec, docs and host feature matrix now match the code, and host-projection regression guards keep them that way (#2440, #2445).
- Every generated Claude Markdown file states its projection version. Files from earlier projections are still recognised as Squad's and upgraded in place, and rolling back the `CLAUDE.md`, `AGENTS.md` and `GEMINI.md` blocks restores the original bytes exactly (#2450).
-- Copilot output, `.github/agents/squad.agent.md` and the projections for other hosts are unchanged.
+- Copilot output, `.github/agents/squad.agent.md` and the projections for other hosts are unchanged, apart from the portable `squad_state` launch command below, which every host gets.
+
+#### Fixed
+
+- **Committed files no longer contain paths from your machine** (#2462). With the Squad CLI installed, `squad init` and `squad upgrade` used to write `node /your/path/cli-entry.js state-mcp` into `.mcp.json`, the other hosts' MCP configs and every Claude Code hook, so a clone on any other machine failed. They now write `node .squad/squad.mjs state-mcp`.
+ - `.squad/squad.mjs` is a launcher Squad commits. It finds a Squad CLI on each machine: `SQUAD_CLI`, the project's `node_modules`, then `squad` on PATH. It skips a CLI older than the one that wrote it, and uses `npx` only with `SQUAD_ALLOW_NPX=1`. It shares its code with the plugin's launcher.
+ - Claude hooks reach the launcher through `$CLAUDE_PROJECT_DIR`. Standalone bundle installs write `squad state-mcp`. A CLI run through `npx` keeps the exact-version `npx` command.
+ - `squad doctor` flags machine-specific launch commands and a missing launcher. Run `squad upgrade` once to fix an existing repository.
+- `squad init --client claude` tells you to run `claude --agent squad --mcp-config .mcp.json`, not Copilot. With several hosts it gives one line per host (#2453).
## [2.0.0-preview.4] - 2026-11-09
diff --git a/docs/src/content/docs/features/mcp.md b/docs/src/content/docs/features/mcp.md
index 624850367..aaa3cd2b1 100644
--- a/docs/src/content/docs/features/mcp.md
+++ b/docs/src/content/docs/features/mcp.md
@@ -31,6 +31,8 @@ Where you add a server depends on your host:
Copilot CLI doesn't read a `.copilot/mcp-config.json` inside the project (`squad init` writes a sample one there), so a server added to it never loads. Hosts added with `squad init --client` have their own MCP config (Claude Code shares `.mcp.json`), and Squad adds `squad_state` to it for you.
+The `squad_state` entry Squad writes works on every clone of the repository. If you installed the Squad CLI (globally, in the project, or from a source build), the entry runs `node .squad/squad.mjs state-mcp`. That small launcher, which Squad writes and you commit, finds a Squad CLI on whichever machine runs it: `SQUAD_CLI` if set, then the project's `node_modules`, then `squad` on PATH. It skips a CLI older than the one that wrote it. If none is found, it prints how to install one; set `SQUAD_ALLOW_NPX=1` to let it run the exact version with `npx` instead. Claude Code hooks use the same launcher. A standalone bundle install writes `squad state-mcp`, and a CLI run through `npx` writes the exact-version `npx` command. `squad doctor` warns when a committed entry points at a path on one machine.
+
This guide covers Copilot CLI and VS Code. Pick the one that matches your workflow.
---
diff --git a/docs/src/content/docs/scenarios/troubleshooting.md b/docs/src/content/docs/scenarios/troubleshooting.md
index e98d521eb..6b625c227 100644
--- a/docs/src/content/docs/scenarios/troubleshooting.md
+++ b/docs/src/content/docs/scenarios/troubleshooting.md
@@ -154,6 +154,16 @@ declarations, which multiplied the process count.
---
+## `squad_state` or Claude hooks fail after cloning
+
+**Problem:** On a fresh clone or another machine, the `squad_state` MCP server doesn't start, or every Claude Code hook reports an error. `squad doctor` shows **portable squad_state launch** failing.
+
+**Cause:** The repository was set up with a Squad version that wrote absolute paths from one machine into `.mcp.json` and `.claude/settings.json`.
+
+**Fix:** run `squad upgrade` once and commit the result. It replaces those paths with `node .squad/squad.mjs`, a launcher that finds the Squad CLI on each machine. If the launcher says no Squad CLI was found, install one (`npm install -g @bradygaster/squad-cli`) or set `SQUAD_ALLOW_NPX=1`.
+
+---
+
## Upgrade doesn't change anything
**Problem:** Running `squad upgrade` completes but nothing changes.
diff --git a/docs/src/content/docs/scenarios/upgrading.md b/docs/src/content/docs/scenarios/upgrading.md
index 6f44c22db..697fe54f0 100644
--- a/docs/src/content/docs/scenarios/upgrading.md
+++ b/docs/src/content/docs/scenarios/upgrading.md
@@ -183,12 +183,12 @@ Every row below is a pinned, published artifact of an older Squad release driven
### Runs
-All recorded runs executed against **one tree**, commit `9da01a2e41ba15794d31b0b8251ddaa3abd34ba8`, with harness hash `bca27c39dc2dcbff…` (sha256 over the suite, renderer, workflow, fs hook and this fixture minus `runs`; the integrity test refuses a recorded run whose harness differs from the committed one, so folding results may change nothing but the runs data).
+All recorded runs executed against **one tree**, commit `9b254ba858abc19ef62e513993d9802312bfe34c`, with harness hash `a9713d320fdb479c…` (sha256 over the suite, renderer, workflow, fs hook and this fixture minus `runs`; the integrity test refuses a recorded run whose harness differs from the committed one, so folding results may change nothing but the runs data).
| Platform | Arch | Node | Target | Tree (targetSha) | Trigger | Recorded | Outcome |
|----------|------|------|--------|------------------|---------|----------|---------|
-| Linux (`linux`) | x64 | v22.23.3 | v1.2.0-preview.1 | `9da01a2e41ba` | [workflow_dispatch](https://github.com/bradygaster/squad/actions/runs/39903943542) | 2026-10-23 | 35 rows passed all non-xfail assertions; 4 of them carry a known expected failure (F3: Squad 0.9.1 squad upgrade --dry-run is not dry); 0 rows failed; 7 rows are structurally inapplicable (listed below). |
-| Windows (`win32`) | x64 | v22.23.4 | v1.2.0-preview.1 | `9da01a2e41ba` | [workflow_dispatch](https://github.com/bradygaster/squad/actions/runs/39903943542) | 2026-10-23 | 35 rows passed all non-xfail assertions; 4 of them carry a known expected failure (F3: Squad 0.9.1 squad upgrade --dry-run is not dry); 0 rows failed; 7 rows are structurally inapplicable (listed below). |
+| Linux (`linux`) | x64 | v22.23.4 | v2.0.0-preview.4 | `9b254ba858ab` | [pull_request](https://github.com/github/squad/actions/runs/43147851248) | 2026-11-12 | 35 rows passed all non-xfail assertions; 4 of them carry a known expected failure (F3: Squad 0.9.1 squad upgrade --dry-run is not dry); 0 rows failed; 7 rows are structurally inapplicable (listed below). |
+| Windows (`win32`) | x64 | v22.23.4 | v2.0.0-preview.4 | `9b254ba858ab` | [pull_request](https://github.com/github/squad/actions/runs/43147851248) | 2026-11-12 | 35 rows passed all non-xfail assertions; 4 of them carry a known expected failure (F3: Squad 0.9.1 squad upgrade --dry-run is not dry); 0 rows failed; 7 rows are structurally inapplicable (listed below). |
### Producers (pinned, immutable provenance)
@@ -197,8 +197,8 @@ All recorded runs executed against **one tree**, commit `9da01a2e41ba15794d31b0b
| **0.9.1** | npm | `@bradygaster/squad-cli@0.9.1`
sha1 `a5ee3dbfc44b7457eba56476f708ad6fdc2e09ca`
`sha512-TcZqRbJk3XBg4N8Y5/5OWJeA52ARAMuzk4MGtB0bfdr87e7iJRV6lJEw8+OIYz9IQ+1JxN/Q30dZDALMOcdi2w==`
`@bradygaster/squad-sdk@0.9.1`
sha1 `4735aba9f125de415160cd979ea3f1467903f16e`
`sha512-1KqZ2N6Lt/B4uYlU/Su9JjA1s/7ng0OAEb9CZrkRk19YSPi6tg7K5QWdTKl5gY/gp8zPAJqfjVffOwrZwGlzmw==` | Oldest 0.x line that still installs on Node 22 (engines >=22.5); pinned with its own @bradygaster/squad-sdk@0.9.1 (its `>=0.9.0` range would otherwise float to 1.0.1). Scaffolds `.squad/` with an EMPTY `casting/` directory and skills under `.copilot/skills/`; predates --state-backend. | no |
| **0.13.1** | npm | `@bradygaster/squad-cli@0.13.1`
sha1 `c8f6427bab4cae989934574315eabda98495fb37`
`sha512-ogfx2nhyx6fqMyqlaI5tDnOzUbRdh+a6Uh/rMQ0aNJwAXnvQp4N37Xp/eOTyB5CxcB7E34NBtAfCxyXbWSiS8w==`
`@bradygaster/squad-sdk@0.13.1`
sha1 `90e98450971e921ca2072673b325fcc8126a2fb6`
`sha512-1Jt6c9kahJq1JCcE77j/50D79YcXVG6Rt1genuLJ3O9J2SKTZKemlbvHgftkc5LgGH22DkWqHh5zLNEQ/p+ukA==` | Last 0.x stable; first line with --state-backend (local\|orphan\|two-layer) and user-profile squads (writes teamRoot when a profile squad exists). | yes |
| **1.0.0** | npm | `@bradygaster/squad-cli@1.0.0`
sha1 `e4e776ef938cbe8c65d8d2c729f2249a48bca638`
`sha512-mnZXnA+GAtp4KSLf7a4Zw0BpeOaHFAxYV5oxAy58ancZ9C2LguUGbcTxWIG0djM96XWET8K9fcncif3Vm6Z9RQ==`
`@bradygaster/squad-sdk@1.0.0`
sha1 `4abb8e450e79827b865a7846af6589789d079cab`
`sha512-9f4NthJaQDq6ifXU3f6VfsZz2bbWs2u57fHhXKtDgDMSvZ3Xq8FPjMvddxhRvseWqaSlkYcWsag3M/lzTtKaJA==` | First 1.x stable; last version published to npm (dist-tag latest). | yes |
-| **1.0.1** | GitHub Release | [bradygaster/squad v1.0.1](https://github.com/bradygaster/squad/releases/tag/v1.0.1) — assets by immutable id:
`squad-darwin-arm64.tar.gz` id `610330560` sha256 `47a8d44d0a9a338ae2c2b6192cb761187ebd71edbd1171a4800cee11cb001b43`
`squad-darwin-x64.tar.gz` id `610330564` sha256 `b88db7e8949878ba2cdf756758651cd50a0e9b5fc83f4c759bd7438d596b4951`
`squad-linux-arm64.tar.gz` id `610330558` sha256 `9d8105c903eeac4d1762e43432f54827a6c4676f4aa42cfdf34bf645e497e756`
`squad-linux-x64.tar.gz` id `610330551` sha256 `283a1893be9ddad11056dcc8bd0673eff6b48a789bbf523b3f7ec31994d27ac7`
`squad-win32-arm64.zip` id `610330674` sha256 `586c4e2d3d708f4d3f08b2c8ffb965d9312d6586d0830a1b8a817b27c3c14bd0`
`squad-win32-x64.zip` id `610330559` sha256 `f38a8f85e60982dba340187b761488f01de1aec68ea50c1b85725783d32df2fe` | Patch release whose CLI never reached npm (release run 37222633918: SDK publish failed, CLI publish skipped); only the standalone bundles exist. | yes |
-| **1.1.0** | GitHub Release | [bradygaster/squad v1.1.0](https://github.com/bradygaster/squad/releases/tag/v1.1.0) — assets by immutable id:
`squad-darwin-arm64.tar.gz` id `659607638` sha256 `057c8d2296e1c95cd77933bae55475409a2dce88aa5b3443cc6ca6cfcd545631`
`squad-darwin-x64.tar.gz` id `659607644` sha256 `4e4e8574f6a339f5537c82eb586d66ecf2ee3005e86b058b834b965be33a43cd`
`squad-linux-arm64.tar.gz` id `659607639` sha256 `992e9dbfe677e3c772446960051329aaed1578d5e4dbcb3350827dbb755e8b00`
`squad-linux-x64.tar.gz` id `659607641` sha256 `2de647a3feaef334051eb1b3084acba37a511818aad029a16abfe32fadb41aff`
`squad-win32-arm64.zip` id `659607808` sha256 `3c922c37863b255546403cffb2aa1c7dff2a347be87ca582759c149aec7bb1da`
`squad-win32-x64.zip` id `659607643` sha256 `571d734f7ae718fefefdfa9864f9f82a3d1fb1546f01ec8bf8866fa7e1829c57` | Latest 1.x release; npm CLI publish failed in release run 39442663504 ("Could not verify @bradygaster/squad-cli@1.1.0 on npm dist-tag 'latest' after 20 attempts"), so the standalone bundle is the only published artifact. | yes |
+| **1.0.1** | GitHub Release | [github/squad v1.0.1](https://github.com/github/squad/releases/tag/v1.0.1) — assets by immutable id:
`squad-darwin-arm64.tar.gz` id `610330560` sha256 `47a8d44d0a9a338ae2c2b6192cb761187ebd71edbd1171a4800cee11cb001b43`
`squad-darwin-x64.tar.gz` id `610330564` sha256 `b88db7e8949878ba2cdf756758651cd50a0e9b5fc83f4c759bd7438d596b4951`
`squad-linux-arm64.tar.gz` id `610330558` sha256 `9d8105c903eeac4d1762e43432f54827a6c4676f4aa42cfdf34bf645e497e756`
`squad-linux-x64.tar.gz` id `610330551` sha256 `283a1893be9ddad11056dcc8bd0673eff6b48a789bbf523b3f7ec31994d27ac7`
`squad-win32-arm64.zip` id `610330674` sha256 `586c4e2d3d708f4d3f08b2c8ffb965d9312d6586d0830a1b8a817b27c3c14bd0`
`squad-win32-x64.zip` id `610330559` sha256 `f38a8f85e60982dba340187b761488f01de1aec68ea50c1b85725783d32df2fe` | Patch release whose CLI never reached npm (release run 37222633918: SDK publish failed, CLI publish skipped); only the standalone bundles exist. | yes |
+| **1.1.0** | GitHub Release | [github/squad v1.1.0](https://github.com/github/squad/releases/tag/v1.1.0) — assets by immutable id:
`squad-darwin-arm64.tar.gz` id `659607638` sha256 `057c8d2296e1c95cd77933bae55475409a2dce88aa5b3443cc6ca6cfcd545631`
`squad-darwin-x64.tar.gz` id `659607644` sha256 `4e4e8574f6a339f5537c82eb586d66ecf2ee3005e86b058b834b965be33a43cd`
`squad-linux-arm64.tar.gz` id `659607639` sha256 `992e9dbfe677e3c772446960051329aaed1578d5e4dbcb3350827dbb755e8b00`
`squad-linux-x64.tar.gz` id `659607641` sha256 `2de647a3feaef334051eb1b3084acba37a511818aad029a16abfe32fadb41aff`
`squad-win32-arm64.zip` id `659607808` sha256 `3c922c37863b255546403cffb2aa1c7dff2a347be87ca582759c149aec7bb1da`
`squad-win32-x64.zip` id `659607643` sha256 `571d734f7ae718fefefdfa9864f9f82a3d1fb1546f01ec8bf8866fa7e1829c57` | Latest 1.x release; npm CLI publish failed in release run 39442663504 ("Could not verify @bradygaster/squad-cli@1.1.0 on npm dist-tag 'latest' after 20 attempts"), so the standalone bundle is the only published artifact. | yes |
| **HEAD** | local HEAD (pack) | npm pack of packages/squad-sdk and packages/squad-cli from the tree under test (targetSha) | Same-version idempotency: the CLI packed from this tree scaffolds and then upgrades itself. | yes |
npm tarballs are fetched by exact version through the registry npm is configured for and verified against the recorded sha1 + sha512 before use; GitHub Release bundles are downloaded by immutable asset id and verified against the recorded sha256. A verification mismatch **fails** the producer's rows (it is never a skip); only an unreachable registry/release yields a skip, and that skip carries the reason.
@@ -314,6 +314,7 @@ Paths a plain `squad upgrade` may create or rewrite (the only changes `user-stat
- `^\.copilot/skills/`
- `^\.github/workflows/(squad-[\w-]+|sync-squad-labels)\.yml(\.local-backup)?$`
- `^\.squad/\.first-run$`
+- `^\.squad/squad\.mjs$`
- `^\.squad/config\.json$`
- `^\.squad/casting/`
- `^\.squad/templates/`
@@ -394,12 +395,12 @@ Recorded by the `downgrade-probe` check (dry-run on a copy; the only assertion i
| Platform | Producer | Shapes | Observed |
|----------|----------|--------|----------|
-| `linux` | 0.9.1 | all 4 shapes | exit 0, last lines "[32m✓[0m refreshed .squad/templates/ \| Upgrade complete: v1.2.0-preview.1 → v0.9.1 \| [2mPreserves user state: team.md, decisions/, agents/*/history.md[0m"; MODIFIED 45 files (20 coordinator/templates/workflows, e.g. .copilot/skills/agent-collaboration/SKILL.md, .copilot/skills/cross-squad/SKILL.md, .copilot/skills/git-workflow/SKILL.md …) |
+| `linux` | 0.9.1 | all 4 shapes | exit 0, last lines "[32m✓[0m refreshed .squad/templates/ \| Upgrade complete: v2.0.0-preview.4 → v0.9.1 \| [2mPreserves user state: team.md, decisions/, agents/*/history.md[0m"; MODIFIED 68 files (20 coordinator/templates/workflows, e.g. .copilot/skills/agent-collaboration/SKILL.md, .copilot/skills/agent-conduct/SKILL.md, .copilot/skills/architectural-proposals/SKILL.md …) |
| `linux` | 0.13.1 | all 6 shapes | exit 0, last lines "overwrite ../.github/workflows/squad-triage.yml \| overwrite ../.github/workflows/sync-squad-labels.yml \| Run without --dry-run to apply."; modified nothing |
| `linux` | 1.0.0 | all 6 shapes | exit 0, last lines "overwrite ../.github/workflows/squad-triage.yml \| overwrite ../.github/workflows/sync-squad-labels.yml \| Run without --dry-run to apply."; modified nothing |
| `linux` | 1.0.1 | all 6 shapes | exit 0, last lines "overwrite ../.github/workflows/squad-triage.yml \| overwrite ../.github/workflows/sync-squad-labels.yml \| Run without --dry-run to apply."; modified nothing |
| `linux` | 1.1.0 | all 6 shapes | exit 0, last lines "overwrite ../.github/workflows/squad-triage.yml \| overwrite ../.github/workflows/sync-squad-labels.yml \| Run without --dry-run to apply."; modified nothing |
-| `win32` | 0.9.1 | all 4 shapes | exit 0, last lines "[32m✓[0m refreshed .squad/templates/ \| Upgrade complete: v1.2.0-preview.1 → v0.9.1 \| [2mPreserves user state: team.md, decisions/, agents/*/history.md[0m"; MODIFIED 44 files (20 coordinator/templates/workflows, e.g. .copilot/skills/agent-collaboration/SKILL.md, .copilot/skills/cross-squad/SKILL.md, .copilot/skills/git-workflow/SKILL.md …) |
+| `win32` | 0.9.1 | all 4 shapes | exit 0, last lines "[32m✓[0m refreshed .squad/templates/ \| Upgrade complete: v2.0.0-preview.4 → v0.9.1 \| [2mPreserves user state: team.md, decisions/, agents/*/history.md[0m"; MODIFIED 67 files (20 coordinator/templates/workflows, e.g. .copilot/skills/agent-collaboration/SKILL.md, .copilot/skills/agent-conduct/SKILL.md, .copilot/skills/architectural-proposals/SKILL.md …) |
| `win32` | 0.13.1 | all 6 shapes | exit 0, last lines "overwrite ../.github/workflows/squad-triage.yml \| overwrite ../.github/workflows/sync-squad-labels.yml \| Run without --dry-run to apply."; modified nothing |
| `win32` | 1.0.0 | all 6 shapes | exit 0, last lines "overwrite ../.github/workflows/squad-triage.yml \| overwrite ../.github/workflows/sync-squad-labels.yml \| Run without --dry-run to apply."; modified nothing |
| `win32` | 1.0.1 | all 6 shapes | exit 0, last lines "overwrite ../.github/workflows/squad-triage.yml \| overwrite ../.github/workflows/sync-squad-labels.yml \| Run without --dry-run to apply."; modified nothing |
diff --git a/packages/squad-cli/src/cli/commands/client.ts b/packages/squad-cli/src/cli/commands/client.ts
index 0a4ec240e..d90a9cc3a 100644
--- a/packages/squad-cli/src/cli/commands/client.ts
+++ b/packages/squad-cli/src/cli/commands/client.ts
@@ -21,7 +21,7 @@ import {
} from '@bradygaster/squad-sdk/client';
import { readClientFlag, readConfiguredClients, readUnknownConfiguredClients, syncClients, reportClientResults, parseClients } from '../core/clients.js';
import { detectSquadDir } from '../core/detect-squad-dir.js';
-import { projectSquadStateMcpSpec, resolveSquadStateMcpSpec } from '../core/mcp-spec.js';
+import { projectSquadStateMcpSpec, resolveCommittedSquadStateMcpSpec } from '../core/mcp-spec.js';
import { getPackageVersion } from '../core/version.js';
import { BOLD, DIM, GREEN, RESET, YELLOW } from '../core/output.js';
@@ -55,7 +55,9 @@ export async function listClients(dest: string): Promise {
const unknown = readUnknownConfiguredClients(squadDir);
const effective: ClientId[] = configured.length > 0 ? configured : ['copilot'];
- const spec = projectSquadStateMcpSpec(await resolveSquadStateMcpSpec(getPackageVersion()));
+ const spec = projectSquadStateMcpSpec(
+ await resolveCommittedSquadStateMcpSpec(getPackageVersion(), dest, squadDir, { write: false }),
+ );
const ctx = {
root: dest,
mcp: { command: spec.command, args: spec.args },
diff --git a/packages/squad-cli/src/cli/commands/doctor.ts b/packages/squad-cli/src/cli/commands/doctor.ts
index 6891ad06a..ba05db2de 100644
--- a/packages/squad-cli/src/cli/commands/doctor.ts
+++ b/packages/squad-cli/src/cli/commands/doctor.ts
@@ -716,6 +716,82 @@ export async function checkSquadStateBridge(cwd: string): Promise {
}
}
+// ── portable launch commands (#2462) ─────────────────────────────────
+
+/** Squad's launch commands in files the repository commits: `.mcp.json` and Claude hooks. */
+function committedSquadLaunches(cwd: string): { file: string; command: string; args: string[] }[] {
+ const found: { file: string; command: string; args: string[] }[] = [];
+ const read = (rel: string): unknown => {
+ try {
+ return JSON.parse(readFileSync(path.join(cwd, rel), 'utf8'));
+ } catch {
+ return undefined;
+ }
+ };
+ const mcp = read('.mcp.json') as { mcpServers?: Record } | undefined;
+ const entry = mcp?.mcpServers?.['squad_state'];
+ if (entry && typeof entry.command === 'string') {
+ found.push({ file: '.mcp.json', command: entry.command, args: Array.isArray(entry.args) ? entry.args.map(String) : [] });
+ }
+ const settings = read('.claude/settings.json') as { hooks?: Record } | undefined;
+ for (const groups of Object.values(settings?.hooks ?? {})) {
+ if (!Array.isArray(groups)) continue;
+ for (const group of groups as { hooks?: unknown }[]) {
+ for (const h of Array.isArray(group?.hooks) ? (group.hooks as Record[]) : []) {
+ const args = Array.isArray(h?.['args']) ? (h['args'] as unknown[]).map(String) : [];
+ if (typeof h?.['command'] !== 'string') continue;
+ const squadHook = args.slice(-3, -1).join(' ') === 'hook claude' || / hook claude [A-Za-z]+$/.test(h['command'] as string);
+ if (squadHook) found.push({ file: '.claude/settings.json', command: h['command'] as string, args });
+ }
+ }
+ }
+ return found;
+}
+
+/**
+ * Committed launch commands must work on every clone: no absolute paths into one machine's
+ * install, and the repository launcher they name must exist. Returns undefined when the
+ * repository commits no Squad launch command.
+ */
+export function checkPortableSquadLaunch(cwd: string): DoctorCheck | undefined {
+ const name = 'portable squad_state launch';
+ const launches = committedSquadLaunches(cwd);
+ if (launches.length === 0) return undefined;
+ const fix = "Run 'squad upgrade' to switch to the repository launcher (.squad/squad.mjs), then commit the result.";
+ // A committed file may come from any OS: recognise Windows and POSIX absolute paths everywhere.
+ const isAbs = (p: string) => path.posix.isAbsolute(p) || path.win32.isAbsolute(p);
+ const absolute = launches.filter(l => isAbs(l.command) || l.args.some(a => /cli-entry\.js$/.test(a) && isAbs(a)));
+ if (absolute.length > 0) {
+ const files = [...new Set(absolute.map(l => l.file))].join(', ');
+ // Only an absolute command is a file to check; a bare `node` is found on PATH.
+ const missing = absolute.some(l => (isAbs(l.command) && !lstatExists(l.command)) ||
+ l.args.some(a => isAbs(a) && !lstatExists(a)));
+ return {
+ name,
+ status: missing ? 'fail' : 'warn',
+ message: missing
+ ? `${files} start Squad from a path that does not exist on this machine (written on another machine?), so squad_state and the Claude hooks fail. ${fix}`
+ : `${files} start Squad from an absolute path on this machine, which fails on every other clone. ${fix}`,
+ };
+ }
+ for (const l of launches) {
+ const script = l.command === 'node' ? l.args[0] : /^node "\$CLAUDE_PROJECT_DIR\/([^"]+)"/.exec(l.command)?.[1];
+ if (script && /(?:^|\/)squad\.mjs$/.test(script) && !isAbs(script) && !lstatExists(path.join(cwd, script))) {
+ return { name, status: 'fail', message: `${l.file} runs ${script}, which is missing. ${fix}` };
+ }
+ }
+ return { name, status: 'pass', message: `${launches.length} committed launch command(s) are portable` };
+}
+
+function lstatExists(file: string): boolean {
+ try {
+ lstatSync(file);
+ return true;
+ } catch {
+ return false;
+ }
+}
+
// ── git sync hooks check ─────────────────────────────────────────────
const SQUAD_SYNC_HOOK_MARKER = '# --- squad-sync-hook ---';
@@ -1159,6 +1235,8 @@ export async function runDoctor(cwd?: string): Promise {
if (upstreamCheck) checks.push(upstreamCheck);
checks.push(await checkSquadStateBridge(resolvedCwd));
+ const portableLaunch = checkPortableSquadLaunch(resolvedCwd);
+ if (portableLaunch) checks.push(portableLaunch);
// Hook presence check (only for two-layer / orphan backends)
const hookCheck = checkGitSyncHooks(resolvedCwd, squadDir);
diff --git a/packages/squad-cli/src/cli/core/clients.ts b/packages/squad-cli/src/cli/core/clients.ts
index daeba0e3a..6c49c4b06 100644
--- a/packages/squad-cli/src/cli/core/clients.ts
+++ b/packages/squad-cli/src/cli/core/clients.ts
@@ -27,7 +27,7 @@ import {
type ApplyResult,
type ClientId,
} from '@bradygaster/squad-sdk/client';
-import { projectSquadStateMcpSpec, resolveSquadStateMcpSpec } from './mcp-spec.js';
+import { projectSquadStateMcpSpec, resolveCommittedSquadStateMcpSpec } from './mcp-spec.js';
import { getPackageVersion } from './version.js';
export { CLIENT_IDS, parseClients, type ClientId };
@@ -184,7 +184,7 @@ export async function syncClients(
if (options.claudePlugin !== undefined) persistClaudePlugin(squadDir, options.claudePlugin);
const version = options.version ?? getPackageVersion();
- const spec = projectSquadStateMcpSpec(await resolveSquadStateMcpSpec(version));
+ const spec = projectSquadStateMcpSpec(await resolveCommittedSquadStateMcpSpec(version, dest, squadDir));
const ctx = {
root: dest,
mcp: { command: spec.command, args: spec.args },
diff --git a/packages/squad-cli/src/cli/core/init.ts b/packages/squad-cli/src/cli/core/init.ts
index 209f4e044..282ad8425 100644
--- a/packages/squad-cli/src/cli/core/init.ts
+++ b/packages/squad-cli/src/cli/core/init.ts
@@ -14,7 +14,7 @@ import { getPackageVersion, stampVersion } from './version.js';
import { initSquad as sdkInitSquad, cleanupOrphanInitPrompt, clearResolveSquadCache, type InitOptions } from '@bradygaster/squad-sdk';
import { installGitHooks } from '../commands/install-hooks.js';
import { liftInitMutableStateOntoOrphan } from '../commands/migrate-backend.js';
-import { projectSquadStateMcpSpec, resolveSquadStateMcpSpec } from './mcp-spec.js';
+import { projectSquadStateMcpSpec, resolveCommittedSquadStateMcpSpec } from './mcp-spec.js';
import { describeMcpSpec, ensureUserOwnedTemplates, recordShippedFilesAfterInit } from './upgrade.js';
import { syncCopilotInstructionsFile } from './managed-file.js';
import { getTemplatesDir } from './templates.js';
@@ -23,7 +23,8 @@ import {
reconcileSquadStateUserConfig,
tombstoneStaleSquadStateInProjectMcp,
} from './mcp-root.js';
-import { applyClientProjectionsForInit, reportClientResults, type ClientId } from './clients.js';
+import { applyClientProjectionsForInit, readConfiguredClients, reportClientResults, type ClientId } from './clients.js';
+import { getHostProjection, readClaudePluginMode } from '@bradygaster/squad-sdk/client';
import {
readTeamMd,
writeTeamMd,
@@ -189,6 +190,41 @@ export interface RunInitOptions {
includeVscodeDefault?: boolean;
}
+/** A next-step line; `on`/`off` wrap the command (colour codes in the terminal, empty in tests). */
+type Styled = (on: string, off: string) => string;
+
+/**
+ * What `squad init` tells the user to run next, for the hosts they chose (#2453).
+ * No `--client` means Copilot, the default host. With one host the line is
+ * bare; with several, each line is prefixed with the host's name.
+ */
+export function initNextSteps(
+ clients: readonly ClientId[] | undefined,
+ claudePlugin?: boolean,
+): { lines: Styled[]; tips: string[] } {
+ const chosen: ClientId[] = clients && clients.length > 0 ? [...new Set(clients)] : ['copilot'];
+ if (claudePlugin && !chosen.includes('claude')) chosen.push('claude');
+ const steps: { host: string; text: Styled }[] = [];
+ const tips: string[] = [];
+ for (const id of chosen) {
+ const host = getHostProjection(id).label;
+ if (id === 'copilot') {
+ steps.push({ host, text: (on, off) => `Run ${on}copilot --agent squad${off} and tell it what you're building.` });
+ tips.push('"squad:copilot": "copilot --agent squad --additional-mcp-config @.mcp.json"');
+ } else if (id === 'claude' && claudePlugin) {
+ steps.push({ host, text: (on, off) => `Run ${on}claude${off}; the Squad plugin's coordinator starts by default in this repository.` });
+ tips.push('"squad:claude": "claude -p --agent squad:squad"');
+ } else if (id === 'claude') {
+ steps.push({ host, text: (on, off) => `Run ${on}claude --agent squad --mcp-config .mcp.json${off} and tell it what you're building.` });
+ tips.push('"squad:claude": "claude -p --agent squad --mcp-config .mcp.json"');
+ } else {
+ steps.push({ host, text: () => `Open ${host} in this repository and ask for the squad agent.` });
+ }
+ }
+ if (steps.length === 1) return { lines: [steps[0]!.text], tips };
+ return { lines: steps.map(s => (on: string, off: string) => `${s.host}: ${s.text(on, off)}`), tips };
+}
+
/**
* Main init command handler
*/
@@ -452,7 +488,7 @@ export async function runInit(dest: string, options: RunInitOptions = {}): Promi
// stale project-level entry left by the SDK init writer in
// `.copilot/mcp-config.json`. No HOME modifications.
try {
- const mcpSpec = projectSquadStateMcpSpec(await resolveSquadStateMcpSpec(getPackageVersion()));
+ const mcpSpec = projectSquadStateMcpSpec(await resolveCommittedSquadStateMcpSpec(getPackageVersion(), dest, squadDir));
const rootResult = ensureSquadStateMcpInRoot(dest, getPackageVersion(), mcpSpec);
if (rootResult.written) {
success(`installed squad_state MCP server to .mcp.json (${describeMcpSpec(mcpSpec)}) — Copilot CLI will auto-load on next invocation`);
@@ -480,7 +516,7 @@ export async function runInit(dest: string, options: RunInitOptions = {}): Promi
// for vanilla `squad init` (no --state-backend flag) so the squad_state
// MCP entry is reachable regardless of init path. No HOME modifications.
try {
- const mcpSpec = projectSquadStateMcpSpec(await resolveSquadStateMcpSpec(version));
+ const mcpSpec = projectSquadStateMcpSpec(await resolveCommittedSquadStateMcpSpec(version, dest, squadDir));
const rootResult = ensureSquadStateMcpInRoot(dest, version, mcpSpec);
if (rootResult.written) {
success(`installed squad_state MCP server to .mcp.json (${describeMcpSpec(mcpSpec)}) — Copilot CLI will auto-load on next invocation`);
@@ -599,14 +635,23 @@ export async function runInit(dest: string, options: RunInitOptions = {}): Promi
if (!isInitNoColor()) await sleep(80);
console.log();
- console.log(`${GREEN}${BOLD}Squad initialized.${RESET} Run ${CYAN}${BOLD}copilot --agent squad${RESET} and tell it what you're building.`);
- if (options.claudePlugin) {
- console.log(`Claude Code: run ${CYAN}${BOLD}claude${RESET}; the Squad plugin's coordinator starts by default in this repository.`);
+ // What this repository is now set up for: the flags, else what .squad/config.json already records
+ // (re-running `squad init` keeps an earlier --client and plugin mode).
+ const effectiveClients = options.clients && options.clients.length > 0 ? options.clients : readConfiguredClients(squadDir);
+ const next = initNextSteps(effectiveClients, options.claudePlugin ?? readClaudePluginMode(squadDir));
+ const steps = next.lines.map(line => line(CYAN + BOLD, RESET));
+ if (steps.length === 1) {
+ console.log(`${GREEN}${BOLD}Squad initialized.${RESET} ${steps[0]}`);
+ } else {
+ console.log(`${GREEN}${BOLD}Squad initialized.${RESET} Next, in the host you want to use:`);
+ for (const step of steps) console.log(` ${step}`);
}
console.log();
- console.log(`${DIM}Tip: for non-interactive scripts that need squad_state tools, add to package.json:${RESET}`);
- console.log(`${DIM} "squad:copilot": "copilot --agent squad --additional-mcp-config @.mcp.json"${RESET}`);
- console.log();
+ if (next.tips.length > 0) {
+ console.log(`${DIM}Tip: for non-interactive scripts that need squad_state tools, add to package.json:${RESET}`);
+ for (const tip of next.tips) console.log(`${DIM} ${tip}${RESET}`);
+ console.log();
+ }
if (squadInfo.isLegacy) {
showDeprecationWarning();
diff --git a/packages/squad-cli/src/cli/core/mcp-root.ts b/packages/squad-cli/src/cli/core/mcp-root.ts
index 666e7ac86..652e5fd74 100644
--- a/packages/squad-cli/src/cli/core/mcp-root.ts
+++ b/packages/squad-cli/src/cli/core/mcp-root.ts
@@ -33,7 +33,7 @@ import path from 'node:path';
import { realpathSync } from 'node:fs';
import { createHash } from 'node:crypto';
import { FSStorageProvider } from '@bradygaster/squad-sdk';
-import { projectSquadStateMcpSpec, type SquadStateMcpSpec } from './mcp-spec.js';
+import { isMachineSpecificMcpSpec, projectSquadStateMcpSpec, type SquadStateMcpSpec } from './mcp-spec.js';
import { writeManagedText, writeManagedTextAtomic } from './managed-file.js';
const storage = new FSStorageProvider();
@@ -121,7 +121,7 @@ export function ensureSquadStateMcpInRoot(
'x-squad': {
managed: true,
version: _cliVersion,
- machineSpecific: projectSpec.source !== 'pinned',
+ machineSpecific: isMachineSpecificMcpSpec(projectSpec),
source: projectSpec.source,
...(projectSpec.fallback ? { fallback: projectSpec.fallback } : {}),
},
diff --git a/packages/squad-cli/src/cli/core/mcp-spec.ts b/packages/squad-cli/src/cli/core/mcp-spec.ts
index 865b2c5a7..25aa6ca0b 100644
--- a/packages/squad-cli/src/cli/core/mcp-spec.ts
+++ b/packages/squad-cli/src/cli/core/mcp-spec.ts
@@ -11,16 +11,33 @@
* Dist-tags are intentionally never written. Registry mirrors frequently omit
* `insider` and `preview`, while an installed entry point or exact version is
* deterministic.
+ *
+ * 1 and 2 are paths on this machine. Files a repository commits (`.mcp.json`,
+ * host MCP configs, `.claude/settings.json` hooks) use
+ * {@link resolveCommittedSquadStateMcpSpec} instead, which swaps them for a
+ * portable form (#2462).
*/
-import { existsSync } from 'node:fs';
+import { existsSync, mkdirSync, readFileSync, writeFileSync } from 'node:fs';
+import os from 'node:os';
import path from 'node:path';
import { fileURLToPath } from 'node:url';
+import {
+ resolveInsideRoot,
+ SQUAD_REPO_LAUNCHER_MARKER,
+ SQUAD_REPO_LAUNCHER_PATH,
+ squadRepoLauncher,
+} from '@bradygaster/squad-sdk/client';
export interface SquadStateMcpSpec {
command: string;
args: string[];
- source: 'standalone' | 'local-entry' | 'pinned';
+ /**
+ * `standalone`, `local-entry`: paths on this machine. `pinned`: exact-version npx.
+ * `repo-launcher`: `node /squad.mjs`, committed with the repository.
+ * `path`: a bare `squad` from PATH (standalone bundle installs, which may have no Node).
+ */
+ source: 'standalone' | 'local-entry' | 'pinned' | 'repo-launcher' | 'path';
/** Portable exact-version fallback recorded beside machine-local specs. */
fallback?: {
command: 'npx';
@@ -133,3 +150,126 @@ function exactVersionFallback(version: string): { command: 'npx'; args: string[]
args: ['-y', `${PACKAGE_NAME}@${version}`, 'state-mcp'],
};
}
+
+/** True for a spec that names a path on this machine, which must not be committed. */
+export function isMachineSpecificMcpSpec(spec: SquadStateMcpSpec): boolean {
+ return spec.source === 'standalone' || spec.source === 'local-entry';
+}
+
+/**
+ * The portable form of `direct` for files a repository commits (#2462).
+ *
+ * - `local-entry` becomes `node /squad.mjs state-mcp`, the repository launcher
+ * ({@link writeSquadRepoLauncher}), which finds a Squad CLI on whatever machine runs it. A CLI
+ * running from a package runner's temporary cache (`npx`, `pnpm dlx`, `yarn dlx`) is gone once
+ * that command exits, so it keeps the exact-version `npx` form instead.
+ * - `standalone` becomes a bare `squad state-mcp`: standalone installs put `squad` on PATH and may
+ * have no Node to run the launcher.
+ * - `pinned` (exact-version npx) is already portable and is kept.
+ *
+ * `squadDir` is the squad directory relative to the repository root, POSIX separators. A squad
+ * directory outside the repository has no portable form; `direct` is returned.
+ */
+export function committedSquadStateMcpSpec(direct: SquadStateMcpSpec, squadDir: string | null): SquadStateMcpSpec {
+ if (direct.source === 'local-entry' && direct.fallback && isTransientCliEntry(direct.args[0] ?? '')) {
+ return { command: direct.fallback.command, args: [...direct.fallback.args], source: 'pinned' };
+ }
+ if (direct.source === 'local-entry' && squadDir) {
+ return {
+ command: 'node',
+ args: [`${squadDir}/${SQUAD_REPO_LAUNCHER_PATH}`, 'state-mcp'],
+ source: 'repo-launcher',
+ ...(direct.fallback ? { fallback: direct.fallback } : {}),
+ };
+ }
+ if (direct.source === 'standalone') {
+ return { command: 'squad', args: ['state-mcp'], source: 'path', ...(direct.fallback ? { fallback: direct.fallback } : {}) };
+ }
+ return direct;
+}
+
+/**
+ * True for an entry inside a package runner's temporary install: npm's `_npx` cache, pnpm's
+ * `dlx` cache, or yarn's `dlx-` / `xfs-` temporary directories.
+ */
+export function isTransientCliEntry(entry: string): boolean {
+ const parts = entry.split(/[\\/]+/);
+ return parts.includes('_npx') || parts.includes('dlx') || parts.some(p => /^(?:dlx|xfs)-[\w-]+$/.test(p));
+}
+
+/** The squad directory relative to `root` (POSIX), or null when it is outside `root`. */
+export function squadDirInRoot(root: string, squadDirAbs: string): string | null {
+ const rel = path.relative(path.resolve(root), path.resolve(squadDirAbs));
+ if (!rel || rel.startsWith('..') || path.isAbsolute(rel)) return null;
+ return rel.split(path.sep).join('/');
+}
+
+/**
+ * Write (or refresh) `/squad.mjs`. A file there without Squad's marker is the user's
+ * and is left alone. The path must stay inside `root` once symlinks are followed (a linked squad
+ * directory or a dangling link at the launcher path is refused), so this never writes outside the
+ * workspace.
+ */
+export function writeSquadRepoLauncher(
+ root: string,
+ squadDir: string,
+ version: string,
+): 'created' | 'updated' | 'unchanged' | 'skipped' {
+ let file: string;
+ try {
+ file = resolveInsideRoot(root, `${squadDir}/${SQUAD_REPO_LAUNCHER_PATH}`);
+ } catch {
+ return 'skipped';
+ }
+ const content = squadRepoLauncher(version, squadDir);
+ if (existsSync(file)) {
+ const existing = readFileSync(file, 'utf8');
+ if (existing === content) return 'unchanged';
+ if (!existing.includes(SQUAD_REPO_LAUNCHER_MARKER)) return 'skipped';
+ writeFileSync(file, content, { mode: 0o755 });
+ return 'updated';
+ }
+ mkdirSync(path.dirname(file), { recursive: true });
+ writeFileSync(file, content, { mode: 0o755 });
+ return 'created';
+}
+
+/**
+ * Resolve the spec for committed files under `root`, writing the repository launcher when the
+ * spec uses it (unless `write` is false, for read-only callers such as `squad client list`).
+ * A launcher Squad may not overwrite (user-authored) keeps the machine-specific spec.
+ */
+export async function resolveCommittedSquadStateMcpSpec(
+ cliVersion: string,
+ root: string,
+ squadDirAbs: string,
+ options: ResolveSquadStateMcpSpecOptions & { write?: boolean } = {},
+): Promise {
+ const direct = await resolveSquadStateMcpSpec(cliVersion, options);
+ const squadDir = squadDirInRoot(root, squadDirAbs);
+ const spec = committedSquadStateMcpSpec(direct, squadDir);
+ if (spec.source === 'repo-launcher' && squadDir && options.write !== false) {
+ if (writeSquadRepoLauncher(root, squadDir, cliVersion) === 'skipped') return direct;
+ const entry = direct.args[0];
+ if (entry && !isTransientCliEntry(entry)) recordSquadCli(entry, cliVersion);
+ }
+ return spec;
+}
+
+/**
+ * Record this CLI's entry in `/cli.json`, outside the repository, so the repository
+ * launcher also works on this machine when the CLI is neither on PATH nor in the project (a
+ * source build run by path, for example). Best effort: a failure only skips the record.
+ */
+export function recordSquadCli(entry: string, version: string, env: NodeJS.ProcessEnv = process.env): void {
+ try {
+ const home = env['SQUAD_HOME'] ? path.resolve(env['SQUAD_HOME']) : path.join(os.homedir(), '.squad');
+ const file = path.join(home, 'cli.json');
+ const content = `${JSON.stringify({ entry, version }, null, 2)}\n`;
+ if (existsSync(file) && readFileSync(file, 'utf8') === content) return;
+ mkdirSync(home, { recursive: true });
+ writeFileSync(file, content);
+ } catch {
+ // best effort
+ }
+}
diff --git a/packages/squad-cli/src/cli/core/upgrade.ts b/packages/squad-cli/src/cli/core/upgrade.ts
index 577f31fd5..f5216c1b0 100644
--- a/packages/squad-cli/src/cli/core/upgrade.ts
+++ b/packages/squad-cli/src/cli/core/upgrade.ts
@@ -25,7 +25,7 @@ import { TEMPLATE_MANIFEST, getTemplatesDir } from './templates.js';
import { runMigrations } from './migrations.js';
import { scrubEmails } from './email-scrub.js';
import { getPackageVersion, stampVersion, readInstalledVersion } from './version.js';
-import { projectSquadStateMcpSpec, resolveSquadStateMcpSpec, type SquadStateMcpSpec } from './mcp-spec.js';
+import { projectSquadStateMcpSpec, resolveCommittedSquadStateMcpSpec, type SquadStateMcpSpec } from './mcp-spec.js';
import { copyManagedFile, syncCopilotInstructionsFile, writeManagedText } from './managed-file.js';
export { resolveSquadStateMcpSpec } from './mcp-spec.js';
import {
@@ -1231,7 +1231,9 @@ async function runEnsureChecks(
// git root looking for .mcp.json) and tombstone any stale project-level
// entry left by older Squad versions in `.copilot/mcp-config.json`.
// No HOME modifications.
- const pinnedSpec = projectSquadStateMcpSpec(await resolveSquadStateMcpSpec(getPackageVersion()));
+ const pinnedSpec = projectSquadStateMcpSpec(
+ await resolveCommittedSquadStateMcpSpec(getPackageVersion(), dest, detectSquadDir(dest).path),
+ );
try {
const rootResult = ensureSquadStateMcpInRoot(dest, getPackageVersion(), pinnedSpec);
if (rootResult.written) {
@@ -1273,6 +1275,12 @@ export function describeMcpSpec(spec: SquadStateMcpSpec): string {
if (spec.source === 'local-entry') {
return `${spec.command} ${spec.args[0]} (machine-specific installed CLI; exact-version fallback recorded)`;
}
+ if (spec.source === 'repo-launcher') {
+ return `node ${spec.args[0]} (repository launcher: finds the Squad CLI on each machine)`;
+ }
+ if (spec.source === 'path') {
+ return 'squad from PATH';
+ }
const pkg = spec.args[1] ?? '';
return pkg;
}
diff --git a/packages/squad-sdk/src/client/adapters/claude-hooks.ts b/packages/squad-sdk/src/client/adapters/claude-hooks.ts
index 586b3de73..f04b9a915 100644
--- a/packages/squad-sdk/src/client/adapters/claude-hooks.ts
+++ b/packages/squad-sdk/src/client/adapters/claude-hooks.ts
@@ -94,19 +94,42 @@ export function readClaudeHooksMode(squadAbs: string): ClaudeHooksMode {
/**
* The hook launch command: the MCP launcher with its trailing `state-mcp` replaced.
*
- * No command allowlist on purpose. `mcp` is resolved by the running CLI from its own install
- * (standalone launcher, `node /cli-entry.js`, or `npx` with the exact package version), never
- * from repository content, and the same command is already projected into `.mcp.json` as the
- * `squad_state` server. Hooks therefore add no new executable.
+ * No command allowlist on purpose. `mcp` is resolved by the running CLI (a bare `squad`, `npx` with
+ * the exact package version, or the repository launcher `node /squad.mjs` that Squad
+ * writes), and the same command is already projected into `.mcp.json` as the `squad_state` server.
+ * Hooks therefore add no new executable.
+ *
+ * The repository launcher becomes a shell command through `$CLAUDE_PROJECT_DIR`, as Claude Code
+ * documents for project hooks, so it works whatever the session's working directory is (#2462).
+ * Its `args` is empty and the handler is written without one.
*/
export function claudeHookLaunch(mcp: McpLaunchSpec, event: ClaudeHookEvent): McpLaunchSpec | null {
if (mcp.args[mcp.args.length - 1] !== 'state-mcp') return null;
+ const launcher = repoLauncherPath(mcp);
+ if (launcher) return { command: `node "$CLAUDE_PROJECT_DIR/${launcher}" hook claude ${event}`, args: [] };
return { command: mcp.command, args: [...mcp.args.slice(0, -1), 'hook', 'claude', event] };
}
-/** A handler Squad wrote: a command hook whose arguments end in `hook claude `. */
+/** `/squad.mjs` when `mcp` is the repository launcher, else null. */
+function repoLauncherPath(mcp: McpLaunchSpec): string | null {
+ const [script, sub] = mcp.args;
+ if (mcp.command !== 'node' || mcp.args.length !== 2 || sub !== 'state-mcp' || !script) return null;
+ return /^(?:[\w.-]+\/)+squad\.mjs$/.test(script) && !script.split('/').includes('..') ? script : null;
+}
+
+const REPO_LAUNCHER_HOOK = /^node "\$CLAUDE_PROJECT_DIR\/(?:[\w.-]+\/)+squad\.mjs" hook claude ([A-Za-z]+)$/;
+
+/**
+ * A handler Squad wrote: a command hook whose arguments end in `hook claude `, or the
+ * repository-launcher shell command `node "$CLAUDE_PROJECT_DIR//squad.mjs" hook claude `.
+ */
export function isSquadHookHandler(h: unknown): boolean {
- if (!isObject(h) || h['type'] !== 'command' || !Array.isArray(h['args'])) return false;
+ if (!isObject(h) || h['type'] !== 'command') return false;
+ if (!('args' in h) && typeof h['command'] === 'string') {
+ const m = REPO_LAUNCHER_HOOK.exec(h['command']);
+ return !!m && (CLAUDE_HOOK_EVENTS as readonly unknown[]).includes(m[1]);
+ }
+ if (!Array.isArray(h['args'])) return false;
const a = h['args'] as unknown[];
return (
a.length >= 3 &&
@@ -164,7 +187,9 @@ export function mergeClaudeHooks(settings: Json, mcp: McpLaunchSpec | null): Jso
if (!launch) return stripped;
const groups = hooks[event] ?? [];
if (!Array.isArray(groups)) throw new Error(`Refusing to overwrite "hooks.${event}" in .claude/settings.json: expected an array`);
- const handler = { type: 'command', command: launch.command, args: launch.args, timeout: HOOK_TIMEOUT_SECONDS };
+ const handler = launch.args.length === 0
+ ? { type: 'command', command: launch.command, timeout: HOOK_TIMEOUT_SECONDS }
+ : { type: 'command', command: launch.command, args: launch.args, timeout: HOOK_TIMEOUT_SECONDS };
const matcher = MATCHERS[event];
hooks[event] = [...groups, matcher ? { matcher, hooks: [handler] } : { hooks: [handler] }];
}
diff --git a/packages/squad-sdk/src/client/adapters/claude-plugin.ts b/packages/squad-sdk/src/client/adapters/claude-plugin.ts
index f38141b46..ecd4a8f47 100644
--- a/packages/squad-sdk/src/client/adapters/claude-plugin.ts
+++ b/packages/squad-sdk/src/client/adapters/claude-plugin.ts
@@ -102,27 +102,37 @@ function walk(dir: string, rel = ''): string[] {
const NAME_RE = /^[a-z0-9]+(?:-[a-z0-9]+)*$/;
-/** The launcher every plugin entry point goes through: resolves a Squad CLI and passes argv on. */
-export const CLAUDE_PLUGIN_LAUNCHER = `#!/usr/bin/env node
-// ${NOTE_TEXT}
-//
-// Squad plugin launcher. Runs the Squad CLI with this process's arguments, resolved in this order:
-// 1. SQUAD_CLI (a command, or a .js entry run with this Node)
-// 2. the project's own install: node_modules/${CLI_PACKAGE}
-// 3. a \`squad\` on PATH (never this plugin's own bin/)
-// 4. npx -y ${CLI_PACKAGE}@, only when SQUAD_ALLOW_NPX=1: it downloads and runs
-// code, so it is opt-in. Without it, the launcher fails with install instructions.
-// 2 and 3 are skipped when their version is older than this plugin's: an older CLI lacks commands the
-// plugin calls (\`dashboard\`, \`hook --plugin\`). The version is read from package.json, BUNDLE-INFO.json
-// (standalone bundles), or an embedded node_modules. A CLI whose version cannot be read is used as found.
-import { spawn } from 'node:child_process';
+/**
+ * Where {@link squadRepoLauncher} lives, relative to the squad directory (#2462). Not under a
+ * `bin/` directory: many repositories ignore `bin/`, which would leave the launcher uncommitted.
+ */
+export const SQUAD_REPO_LAUNCHER_PATH = 'squad.mjs';
+/** First line after the shebang of a repository launcher Squad wrote: marks the file as Squad's. */
+export const SQUAD_REPO_LAUNCHER_MARKER = '// Generated by Squad. Managed file: rewritten by `squad init` and `squad upgrade`.';
+
+interface LauncherVariant {
+ /** Header comment lines after the shebang. */
+ header: string;
+ /** Statements defining `root` (for `ownBin`) and `projectStart` (where the project is). */
+ roots: string;
+ /** Body of `pluginVersion()`: the minimum CLI version. */
+ version: string;
+ /** Who the messages come from. */
+ who: string;
+ /** Who downloads with npx, in the install message. */
+ npxActor: string;
+}
+
+function squadLauncher(v: LauncherVariant): string {
+ return `#!/usr/bin/env node
+${v.header}import { spawn } from 'node:child_process';
import fs from 'node:fs';
+import os from 'node:os';
import path from 'node:path';
import { fileURLToPath } from 'node:url';
const PKG = '${CLI_PACKAGE}';
-const root = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '..');
-const ownBin = path.join(root, 'bin');
+${v.roots}const ownBin = path.join(root, 'bin');
const win = process.platform === 'win32';
function canonical(file) {
@@ -132,7 +142,7 @@ function canonical(file) {
// Hooks must be cheap no-ops outside an opted-in team, before CLI or npx resolution.
function hooksEnabled() {
- let project = path.resolve(process.env.CLAUDE_PROJECT_DIR || process.cwd());
+ let project = path.resolve(projectStart());
for (;;) {
for (const name of ['.squad', '.ai-team']) {
const local = path.join(project, name);
@@ -160,12 +170,7 @@ function hooksEnabled() {
if (process.argv[2] === 'hook' && process.argv[3] === 'claude' && !hooksEnabled()) process.exit(0);
function pluginVersion() {
- try {
- return JSON.parse(fs.readFileSync(path.join(root, '.claude-plugin', 'plugin.json'), 'utf8')).version;
- } catch {
- return undefined;
- }
-}
+${v.version}}
/** The version of the Squad CLI behind \`entry\` (a script, symlink or npm shim), if it can be found. */
function cliVersion(entry) {
@@ -250,20 +255,34 @@ function onPath(name) {
return undefined;
}
+/** The CLI entry \`squad init\` / \`squad upgrade\` last recorded on this machine (\`/cli.json\`). */
+function recordedCli() {
+ try {
+ const home = process.env.SQUAD_HOME ? path.resolve(process.env.SQUAD_HOME) : path.join(os.homedir(), '.squad');
+ const entry = JSON.parse(fs.readFileSync(path.join(home, 'cli.json'), 'utf8')).entry;
+ if (typeof entry === 'string' && path.isAbsolute(entry) && /\.[cm]?js$/.test(entry) && fs.existsSync(entry)) return entry;
+ } catch {
+ // no record
+ }
+ return undefined;
+}
+
function resolveCli() {
const override = process.env.SQUAD_CLI;
if (override) return /\\.[cm]?js$/.test(override) ? [process.execPath, [override]] : [override, []];
const version = pluginVersion();
- const project = process.env.CLAUDE_PROJECT_DIR || process.cwd();
+ const project = projectStart();
const local = path.join(project, 'node_modules', ...PKG.split('/'), 'dist', 'cli-entry.js');
if (fs.existsSync(local) && recentEnough(local, version)) return [process.execPath, [local]];
const global = onPath('squad');
if (global && recentEnough(global, version)) return [global, []];
+ const recorded = recordedCli();
+ if (recorded && recentEnough(recorded, version)) return [process.execPath, [recorded]];
const want = version ? \`\${PKG}@\${version}\` : PKG;
if (/^(1|true|yes)$/i.test(process.env.SQUAD_ALLOW_NPX || '')) return [win ? 'npx.cmd' : 'npx', ['-y', want]];
throw new Error(
- \`no Squad CLI\${version ? \` \${version} or newer\` : ''} found (looked at SQUAD_CLI, this project's node_modules and PATH). \` +
- \`Install it with: npm install -g \${want}. Or set SQUAD_ALLOW_NPX=1 to let the plugin download and run it with npx.\`,
+ \`no Squad CLI\${version ? \` \${version} or newer\` : ''} found (looked at SQUAD_CLI, this project's node_modules, PATH and the CLI recorded in ~/.squad/cli.json). \` +
+ \`Install it with: npm install -g \${want}. Or set SQUAD_ALLOW_NPX=1 to let ${v.npxActor} download and run it with npx.\`,
);
}
@@ -284,7 +303,7 @@ let command, prefix;
try {
[command, prefix] = withoutShell(...resolveCli());
} catch (err) {
- process.stderr.write(\`squad plugin: \${err.message}\\n\`);
+ process.stderr.write(\`${v.who}: \${err.message}\\n\`);
process.exit(1);
}
const child = spawn(command, [...prefix, ...process.argv.slice(2)], {
@@ -293,11 +312,73 @@ const child = spawn(command, [...prefix, ...process.argv.slice(2)], {
});
for (const signal of ['SIGINT', 'SIGTERM', 'SIGHUP']) process.on(signal, () => child.kill(signal));
child.on('error', (err) => {
- process.stderr.write(\`squad plugin: cannot start the Squad CLI (\${err.message}). Install it with: npm install -g \${PKG}\\n\`);
+ process.stderr.write(\`${v.who}: cannot start the Squad CLI (\${err.message}). Install it with: npm install -g \${PKG}\\n\`);
process.exit(1);
});
child.on('exit', (code, signal) => process.exit(code ?? (signal ? 1 : 0)));
`;
+}
+
+/** The launcher every plugin entry point goes through: resolves a Squad CLI and passes argv on. */
+export const CLAUDE_PLUGIN_LAUNCHER = squadLauncher({
+ header: `// ${NOTE_TEXT}
+//
+// Squad plugin launcher. Runs the Squad CLI with this process's arguments, resolved in this order:
+// 1. SQUAD_CLI (a command, or a .js entry run with this Node)
+// 2. the project's own install: node_modules/${CLI_PACKAGE}
+// 3. a \`squad\` on PATH (never this plugin's own bin/)
+// 4. the CLI that last ran \`squad init\` or \`squad upgrade\` on this machine (~/.squad/cli.json)
+// 5. npx -y ${CLI_PACKAGE}@, only when SQUAD_ALLOW_NPX=1: it downloads and runs
+// code, so it is opt-in. Without it, the launcher fails with install instructions.
+// 2, 3 and 4 are skipped when their version is older than this plugin's: an older CLI lacks commands the
+// plugin calls (\`dashboard\`, \`hook --plugin\`). The version is read from package.json, BUNDLE-INFO.json
+// (standalone bundles), or an embedded node_modules. A CLI whose version cannot be read is used as found.
+`,
+ roots: `const root = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '..');
+const projectStart = () => process.env.CLAUDE_PROJECT_DIR || process.cwd();
+`,
+ version: ` try {
+ return JSON.parse(fs.readFileSync(path.join(root, '.claude-plugin', 'plugin.json'), 'utf8')).version;
+ } catch {
+ return undefined;
+ }
+`,
+ who: 'squad plugin',
+ npxActor: 'the plugin',
+});
+
+/**
+ * The launcher a repository commits at `/squad.mjs` (#2462). Committed MCP configs and
+ * Claude hooks run it instead of a machine-specific \`node /cli-entry.js\`, so they work on every
+ * clone. Same resolution as the plugin launcher, from the repository root this file sits in.
+ *
+ * @param version - the CLI version that wrote it: older CLIs are skipped (they lack its commands).
+ * @param squadDir - the squad directory relative to the repository root, e.g. \`.squad\`.
+ */
+export function squadRepoLauncher(version: string, squadDir: string): string {
+ const up = squadDir.split('/').filter(Boolean).map(() => '..').join('/');
+ return squadLauncher({
+ header: `${SQUAD_REPO_LAUNCHER_MARKER}
+//
+// Starts the Squad CLI for this repository's MCP configs and Claude Code hooks, so they work on every
+// machine that clones it. Resolved in this order:
+// 1. SQUAD_CLI (a command, or a .js entry run with this Node)
+// 2. this repository's own install: node_modules/${CLI_PACKAGE}
+// 3. a \`squad\` on PATH
+// 4. the CLI that last ran \`squad init\` or \`squad upgrade\` on this machine (~/.squad/cli.json)
+// 5. npx -y ${CLI_PACKAGE}@${version}, only when SQUAD_ALLOW_NPX=1: it downloads and runs code, so it is
+// opt-in. Without it, the launcher fails with install instructions.
+// 2, 3 and 4 are skipped when their version is older than ${version}, the version that wrote this file.
+`,
+ roots: `const root = path.dirname(fileURLToPath(import.meta.url));
+const projectStart = () => path.resolve(path.dirname(fileURLToPath(import.meta.url)), ${JSON.stringify(up)});
+`,
+ version: ` return ${JSON.stringify(version)};
+`,
+ who: 'squad',
+ npxActor: 'Squad',
+ });
+}
function hooksJson(): string {
const hooks: Record = {};
diff --git a/plugins/squad/scripts/squad.mjs b/plugins/squad/scripts/squad.mjs
index a2123586d..2a005b99b 100755
--- a/plugins/squad/scripts/squad.mjs
+++ b/plugins/squad/scripts/squad.mjs
@@ -5,18 +5,21 @@
// 1. SQUAD_CLI (a command, or a .js entry run with this Node)
// 2. the project's own install: node_modules/@bradygaster/squad-cli
// 3. a `squad` on PATH (never this plugin's own bin/)
-// 4. npx -y @bradygaster/squad-cli@, only when SQUAD_ALLOW_NPX=1: it downloads and runs
+// 4. the CLI that last ran `squad init` or `squad upgrade` on this machine (~/.squad/cli.json)
+// 5. npx -y @bradygaster/squad-cli@, only when SQUAD_ALLOW_NPX=1: it downloads and runs
// code, so it is opt-in. Without it, the launcher fails with install instructions.
-// 2 and 3 are skipped when their version is older than this plugin's: an older CLI lacks commands the
+// 2, 3 and 4 are skipped when their version is older than this plugin's: an older CLI lacks commands the
// plugin calls (`dashboard`, `hook --plugin`). The version is read from package.json, BUNDLE-INFO.json
// (standalone bundles), or an embedded node_modules. A CLI whose version cannot be read is used as found.
import { spawn } from 'node:child_process';
import fs from 'node:fs';
+import os from 'node:os';
import path from 'node:path';
import { fileURLToPath } from 'node:url';
const PKG = '@bradygaster/squad-cli';
const root = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '..');
+const projectStart = () => process.env.CLAUDE_PROJECT_DIR || process.cwd();
const ownBin = path.join(root, 'bin');
const win = process.platform === 'win32';
@@ -27,7 +30,7 @@ function canonical(file) {
// Hooks must be cheap no-ops outside an opted-in team, before CLI or npx resolution.
function hooksEnabled() {
- let project = path.resolve(process.env.CLAUDE_PROJECT_DIR || process.cwd());
+ let project = path.resolve(projectStart());
for (;;) {
for (const name of ['.squad', '.ai-team']) {
const local = path.join(project, name);
@@ -145,19 +148,33 @@ function onPath(name) {
return undefined;
}
+/** The CLI entry `squad init` / `squad upgrade` last recorded on this machine (`/cli.json`). */
+function recordedCli() {
+ try {
+ const home = process.env.SQUAD_HOME ? path.resolve(process.env.SQUAD_HOME) : path.join(os.homedir(), '.squad');
+ const entry = JSON.parse(fs.readFileSync(path.join(home, 'cli.json'), 'utf8')).entry;
+ if (typeof entry === 'string' && path.isAbsolute(entry) && /.[cm]?js$/.test(entry) && fs.existsSync(entry)) return entry;
+ } catch {
+ // no record
+ }
+ return undefined;
+}
+
function resolveCli() {
const override = process.env.SQUAD_CLI;
if (override) return /\.[cm]?js$/.test(override) ? [process.execPath, [override]] : [override, []];
const version = pluginVersion();
- const project = process.env.CLAUDE_PROJECT_DIR || process.cwd();
+ const project = projectStart();
const local = path.join(project, 'node_modules', ...PKG.split('/'), 'dist', 'cli-entry.js');
if (fs.existsSync(local) && recentEnough(local, version)) return [process.execPath, [local]];
const global = onPath('squad');
if (global && recentEnough(global, version)) return [global, []];
+ const recorded = recordedCli();
+ if (recorded && recentEnough(recorded, version)) return [process.execPath, [recorded]];
const want = version ? `${PKG}@${version}` : PKG;
if (/^(1|true|yes)$/i.test(process.env.SQUAD_ALLOW_NPX || '')) return [win ? 'npx.cmd' : 'npx', ['-y', want]];
throw new Error(
- `no Squad CLI${version ? ` ${version} or newer` : ''} found (looked at SQUAD_CLI, this project's node_modules and PATH). ` +
+ `no Squad CLI${version ? ` ${version} or newer` : ''} found (looked at SQUAD_CLI, this project's node_modules, PATH and the CLI recorded in ~/.squad/cli.json). ` +
`Install it with: npm install -g ${want}. Or set SQUAD_ALLOW_NPX=1 to let the plugin download and run it with npx.`,
);
}
diff --git a/scripts/docs-site-location.mjs b/scripts/docs-site-location.mjs
index 3da52fdf5..083a288d6 100644
--- a/scripts/docs-site-location.mjs
+++ b/scripts/docs-site-location.mjs
@@ -127,11 +127,6 @@ export const HISTORICAL_REPO_LINKS = [
reason: 'Working-draft provenance cites the pull requests, issue and commit each draft came from; the Charter text is pinned by SHA-256.',
links: PERMALINK,
},
- {
- path: 'docs/src/content/docs/scenarios/upgrading.md',
- reason: 'The generated upgrade matrix records the CI runs and GitHub Releases behind its results (rendered from test-fixtures/spec/suite-v0.2/upgrade-matrix.json).',
- section: { from: /^/, to: /^/ },
- },
{
path: 'docs/_internal/launch/migration-announcement.md',
reason: 'Launch announcement from when Squad first went public.',
diff --git a/test-fixtures/spec/suite-v0.2/upgrade-matrix.json b/test-fixtures/spec/suite-v0.2/upgrade-matrix.json
index 21fe25b72..b4730598e 100644
--- a/test-fixtures/spec/suite-v0.2/upgrade-matrix.json
+++ b/test-fixtures/spec/suite-v0.2/upgrade-matrix.json
@@ -86,7 +86,7 @@
},
"artifacts": {
"release": {
- "repository": "bradygaster/squad",
+ "repository": "github/squad",
"tag": "v1.0.1",
"assets": {
"squad-darwin-arm64.tar.gz": {
@@ -127,7 +127,7 @@
},
"artifacts": {
"release": {
- "repository": "bradygaster/squad",
+ "repository": "github/squad",
"tag": "v1.1.0",
"assets": {
"squad-darwin-arm64.tar.gz": {
@@ -206,6 +206,7 @@
"^\\.copilot/skills/",
"^\\.github/workflows/(squad-[\\w-]+|sync-squad-labels)\\.yml(\\.local-backup)?$",
"^\\.squad/\\.first-run$",
+ "^\\.squad/squad\\.mjs$",
"^\\.squad/config\\.json$",
"^\\.squad/casting/",
"^\\.squad/templates/",
@@ -325,13 +326,13 @@
{
"platform": "linux",
"arch": "x64",
- "node": "v22.23.3",
- "target": "1.2.0-preview.1",
- "targetSha": "9da01a2e41ba15794d31b0b8251ddaa3abd34ba8",
- "harnessHash": "bca27c39dc2dcbffc3bf652bf1f45b471c09911a4bb9ba7e5b7247d25705a66e",
- "event": "workflow_dispatch",
- "runUrl": "https://github.com/bradygaster/squad/actions/runs/39903943542",
- "recordedAt": "2026-10-23T05:08:38.415Z",
+ "node": "v22.23.4",
+ "target": "2.0.0-preview.4",
+ "targetSha": "9b254ba858abc19ef62e513993d9802312bfe34c",
+ "harnessHash": "a9713d320fdb479ced9cd311f36cf33bbd70d5733afb1617cd740831ce6767f8",
+ "event": "pull_request",
+ "runUrl": "https://github.com/github/squad/actions/runs/43147851248",
+ "recordedAt": "2026-11-12T03:25:33.018Z",
"results": [
{
"producer": "0.9.1",
@@ -414,7 +415,7 @@
{
"id": "downgrade-probe",
"status": "xfail",
- "detail": "dry-run MODIFIED 45 files (20 coordinator/templates/workflows, e.g. .copilot/skills/agent-collaboration/SKILL.md, .copilot/skills/cross-squad/SKILL.md, .copilot/skills/git-workflow/SKILL.md …)"
+ "detail": "dry-run MODIFIED 68 files (20 coordinator/templates/workflows, e.g. .copilot/skills/agent-collaboration/SKILL.md, .copilot/skills/agent-conduct/SKILL.md, .copilot/skills/architectural-proposals/SKILL.md …)"
},
{
"id": "clients-projected",
@@ -439,15 +440,15 @@
}
],
"notes": [
- "plain upgrade changed 100 working-tree path(s), all Squad-owned: .copilot/skills/agent-collaboration/SKILL.md, .copilot/skills/cross-squad/SKILL.md, .copilot/skills/git-workflow/SKILL.md, .copilot/skills/reviewer-protocol/SKILL.md … (+96)",
- "old 0.9.1 upgrade --dry-run on upgraded project: exit 0, last lines \"\u001b[32m✓\u001b[0m refreshed .squad/templates/ | Upgrade complete: v1.2.0-preview.1 → v0.9.1 | \u001b[2mPreserves user state: team.md, decisions/, agents/*/history.md\u001b[0m\"; MODIFIED 45 files (20 coordinator/templates/workflows, e.g. .copilot/skills/agent-collaboration/SKILL.md, .copilot/skills/cross-squad/SKILL.md, .copilot/skills/git-workflow/SKILL.md …)",
+ "plain upgrade changed 229 working-tree path(s), all Squad-owned: .copilot/skills/agent-collaboration/SKILL.md, .copilot/skills/agent-conduct/SKILL.md, .copilot/skills/architectural-proposals/SKILL.md, .copilot/skills/ci-validation-gates/SKILL.md … (+225)",
+ "old 0.9.1 upgrade --dry-run on upgraded project: exit 0, last lines \"\u001b[32m✓\u001b[0m refreshed .squad/templates/ | Upgrade complete: v2.0.0-preview.4 → v0.9.1 | \u001b[2mPreserves user state: team.md, decisions/, agents/*/history.md\u001b[0m\"; MODIFIED 68 files (20 coordinator/templates/workflows, e.g. .copilot/skills/agent-collaboration/SKILL.md, .copilot/skills/agent-conduct/SKILL.md, .copilot/skills/architectural-proposals/SKILL.md …)",
"downgrade-probe: F3"
]
},
{
"producer": "0.9.1",
"source": "npm",
- "shape": "profile",
+ "shape": "legacy-casting",
"status": "pass",
"provenance": "npm: @bradygaster/squad-cli@0.9.1 sha512-TcZqRbJk3XBg4N8Y5/5OWJeA52ARAMuzk4MGtB0bfdr87e7iJRV6lJEw8+OIYz9IQ+1JxN/Q30dZDALMOcdi2w==; @bradygaster/squad-sdk@0.9.1 sha512-1KqZ2N6Lt/B4uYlU/Su9JjA1s/7ng0OAEb9CZrkRk19YSPi6tg7K5QWdTKl5gY/gp8zPAJqfjVffOwrZwGlzmw==",
"checks": [
@@ -495,7 +496,7 @@
{
"id": "downgrade-probe",
"status": "xfail",
- "detail": "dry-run MODIFIED 45 files (20 coordinator/templates/workflows, e.g. .copilot/skills/agent-collaboration/SKILL.md, .copilot/skills/cross-squad/SKILL.md, .copilot/skills/git-workflow/SKILL.md …)"
+ "detail": "dry-run MODIFIED 68 files (20 coordinator/templates/workflows, e.g. .copilot/skills/agent-collaboration/SKILL.md, .copilot/skills/agent-conduct/SKILL.md, .copilot/skills/architectural-proposals/SKILL.md …)"
},
{
"id": "clients-projected",
@@ -515,21 +516,22 @@
},
{
"id": "profile-untouched",
- "status": "pass"
+ "status": "skipped",
+ "detail": "no profile squad seeded in this shape"
}
],
"notes": [
- "plain upgrade changed 100 working-tree path(s), all Squad-owned: .copilot/skills/agent-collaboration/SKILL.md, .copilot/skills/cross-squad/SKILL.md, .copilot/skills/git-workflow/SKILL.md, .copilot/skills/reviewer-protocol/SKILL.md … (+96)",
- "old 0.9.1 upgrade --dry-run on upgraded project: exit 0, last lines \"\u001b[32m✓\u001b[0m refreshed .squad/templates/ | Upgrade complete: v1.2.0-preview.1 → v0.9.1 | \u001b[2mPreserves user state: team.md, decisions/, agents/*/history.md\u001b[0m\"; MODIFIED 45 files (20 coordinator/templates/workflows, e.g. .copilot/skills/agent-collaboration/SKILL.md, .copilot/skills/cross-squad/SKILL.md, .copilot/skills/git-workflow/SKILL.md …)",
+ "plain upgrade changed 230 working-tree path(s), all Squad-owned: .copilot/skills/agent-collaboration/SKILL.md, .copilot/skills/agent-conduct/SKILL.md, .copilot/skills/architectural-proposals/SKILL.md, .copilot/skills/ci-validation-gates/SKILL.md … (+226)",
+ "old 0.9.1 upgrade --dry-run on upgraded project: exit 0, last lines \"\u001b[32m✓\u001b[0m refreshed .squad/templates/ | Upgrade complete: v2.0.0-preview.4 → v0.9.1 | \u001b[2mPreserves user state: team.md, decisions/, agents/*/history.md\u001b[0m\"; MODIFIED 68 files (20 coordinator/templates/workflows, e.g. .copilot/skills/agent-collaboration/SKILL.md, .copilot/skills/agent-conduct/SKILL.md, .copilot/skills/architectural-proposals/SKILL.md …)",
"downgrade-probe: F3"
]
},
{
- "producer": "0.13.1",
+ "producer": "0.9.1",
"source": "npm",
- "shape": "default",
+ "shape": "profile",
"status": "pass",
- "provenance": "npm: @bradygaster/squad-cli@0.13.1 sha512-ogfx2nhyx6fqMyqlaI5tDnOzUbRdh+a6Uh/rMQ0aNJwAXnvQp4N37Xp/eOTyB5CxcB7E34NBtAfCxyXbWSiS8w==; @bradygaster/squad-sdk@0.13.1 sha512-1Jt6c9kahJq1JCcE77j/50D79YcXVG6Rt1genuLJ3O9J2SKTZKemlbvHgftkc5LgGH22DkWqHh5zLNEQ/p+ukA==",
+ "provenance": "npm: @bradygaster/squad-cli@0.9.1 sha512-TcZqRbJk3XBg4N8Y5/5OWJeA52ARAMuzk4MGtB0bfdr87e7iJRV6lJEw8+OIYz9IQ+1JxN/Q30dZDALMOcdi2w==; @bradygaster/squad-sdk@0.9.1 sha512-1KqZ2N6Lt/B4uYlU/Su9JjA1s/7ng0OAEb9CZrkRk19YSPi6tg7K5QWdTKl5gY/gp8zPAJqfjVffOwrZwGlzmw==",
"checks": [
{
"id": "producer-artifact-verified",
@@ -574,7 +576,8 @@
},
{
"id": "downgrade-probe",
- "status": "pass"
+ "status": "xfail",
+ "detail": "dry-run MODIFIED 68 files (20 coordinator/templates/workflows, e.g. .copilot/skills/agent-collaboration/SKILL.md, .copilot/skills/agent-conduct/SKILL.md, .copilot/skills/architectural-proposals/SKILL.md …)"
},
{
"id": "clients-projected",
@@ -594,19 +597,19 @@
},
{
"id": "profile-untouched",
- "status": "skipped",
- "detail": "no profile squad seeded in this shape"
+ "status": "pass"
}
],
"notes": [
- "plain upgrade changed 58 working-tree path(s), all Squad-owned: .github/agents/squad.agent.md, .github/agents/squad.agent.md.local-backup, .github/skills/coordinator-response-mode/SKILL.md, .github/skills/coordinator-source-of-truth/SKILL.md … (+54)",
- "old 0.13.1 upgrade --dry-run on upgraded project: exit 0, last lines \"overwrite ../.github/workflows/squad-triage.yml | overwrite ../.github/workflows/sync-squad-labels.yml | Run without --dry-run to apply.\"; modified nothing"
+ "plain upgrade changed 229 working-tree path(s), all Squad-owned: .copilot/skills/agent-collaboration/SKILL.md, .copilot/skills/agent-conduct/SKILL.md, .copilot/skills/architectural-proposals/SKILL.md, .copilot/skills/ci-validation-gates/SKILL.md … (+225)",
+ "old 0.9.1 upgrade --dry-run on upgraded project: exit 0, last lines \"\u001b[32m✓\u001b[0m refreshed .squad/templates/ | Upgrade complete: v2.0.0-preview.4 → v0.9.1 | \u001b[2mPreserves user state: team.md, decisions/, agents/*/history.md\u001b[0m\"; MODIFIED 68 files (20 coordinator/templates/workflows, e.g. .copilot/skills/agent-collaboration/SKILL.md, .copilot/skills/agent-conduct/SKILL.md, .copilot/skills/architectural-proposals/SKILL.md …)",
+ "downgrade-probe: F3"
]
},
{
"producer": "0.9.1",
"source": "npm",
- "shape": "legacy-casting",
+ "shape": "ai-team",
"status": "pass",
"provenance": "npm: @bradygaster/squad-cli@0.9.1 sha512-TcZqRbJk3XBg4N8Y5/5OWJeA52ARAMuzk4MGtB0bfdr87e7iJRV6lJEw8+OIYz9IQ+1JxN/Q30dZDALMOcdi2w==; @bradygaster/squad-sdk@0.9.1 sha512-1KqZ2N6Lt/B4uYlU/Su9JjA1s/7ng0OAEb9CZrkRk19YSPi6tg7K5QWdTKl5gY/gp8zPAJqfjVffOwrZwGlzmw==",
"checks": [
@@ -640,8 +643,7 @@
},
{
"id": "ai-team-migrated",
- "status": "skipped",
- "detail": "not an .ai-team shape"
+ "status": "pass"
},
{
"id": "team-root-absent",
@@ -654,7 +656,7 @@
{
"id": "downgrade-probe",
"status": "xfail",
- "detail": "dry-run MODIFIED 45 files (20 coordinator/templates/workflows, e.g. .copilot/skills/agent-collaboration/SKILL.md, .copilot/skills/cross-squad/SKILL.md, .copilot/skills/git-workflow/SKILL.md …)"
+ "detail": "dry-run MODIFIED 68 files (20 coordinator/templates/workflows, e.g. .copilot/skills/agent-collaboration/SKILL.md, .copilot/skills/agent-conduct/SKILL.md, .copilot/skills/architectural-proposals/SKILL.md …)"
},
{
"id": "clients-projected",
@@ -679,17 +681,17 @@
}
],
"notes": [
- "plain upgrade changed 101 working-tree path(s), all Squad-owned: .copilot/skills/agent-collaboration/SKILL.md, .copilot/skills/cross-squad/SKILL.md, .copilot/skills/git-workflow/SKILL.md, .copilot/skills/reviewer-protocol/SKILL.md … (+97)",
- "old 0.9.1 upgrade --dry-run on upgraded project: exit 0, last lines \"\u001b[32m✓\u001b[0m refreshed .squad/templates/ | Upgrade complete: v1.2.0-preview.1 → v0.9.1 | \u001b[2mPreserves user state: team.md, decisions/, agents/*/history.md\u001b[0m\"; MODIFIED 45 files (20 coordinator/templates/workflows, e.g. .copilot/skills/agent-collaboration/SKILL.md, .copilot/skills/cross-squad/SKILL.md, .copilot/skills/git-workflow/SKILL.md …)",
+ "plain upgrade changed 229 working-tree path(s), all Squad-owned: .copilot/skills/agent-collaboration/SKILL.md, .copilot/skills/agent-conduct/SKILL.md, .copilot/skills/architectural-proposals/SKILL.md, .copilot/skills/ci-validation-gates/SKILL.md … (+225)",
+ "old 0.9.1 upgrade --dry-run on upgraded project: exit 0, last lines \"\u001b[32m✓\u001b[0m refreshed .squad/templates/ | Upgrade complete: v2.0.0-preview.4 → v0.9.1 | \u001b[2mPreserves user state: team.md, decisions/, agents/*/history.md\u001b[0m\"; MODIFIED 68 files (20 coordinator/templates/workflows, e.g. .copilot/skills/agent-collaboration/SKILL.md, .copilot/skills/agent-conduct/SKILL.md, .copilot/skills/architectural-proposals/SKILL.md …)",
"downgrade-probe: F3"
]
},
{
- "producer": "0.9.1",
+ "producer": "0.13.1",
"source": "npm",
- "shape": "ai-team",
+ "shape": "default",
"status": "pass",
- "provenance": "npm: @bradygaster/squad-cli@0.9.1 sha512-TcZqRbJk3XBg4N8Y5/5OWJeA52ARAMuzk4MGtB0bfdr87e7iJRV6lJEw8+OIYz9IQ+1JxN/Q30dZDALMOcdi2w==; @bradygaster/squad-sdk@0.9.1 sha512-1KqZ2N6Lt/B4uYlU/Su9JjA1s/7ng0OAEb9CZrkRk19YSPi6tg7K5QWdTKl5gY/gp8zPAJqfjVffOwrZwGlzmw==",
+ "provenance": "npm: @bradygaster/squad-cli@0.13.1 sha512-ogfx2nhyx6fqMyqlaI5tDnOzUbRdh+a6Uh/rMQ0aNJwAXnvQp4N37Xp/eOTyB5CxcB7E34NBtAfCxyXbWSiS8w==; @bradygaster/squad-sdk@0.13.1 sha512-1Jt6c9kahJq1JCcE77j/50D79YcXVG6Rt1genuLJ3O9J2SKTZKemlbvHgftkc5LgGH22DkWqHh5zLNEQ/p+ukA==",
"checks": [
{
"id": "producer-artifact-verified",
@@ -721,7 +723,8 @@
},
{
"id": "ai-team-migrated",
- "status": "pass"
+ "status": "skipped",
+ "detail": "not an .ai-team shape"
},
{
"id": "team-root-absent",
@@ -733,8 +736,7 @@
},
{
"id": "downgrade-probe",
- "status": "xfail",
- "detail": "dry-run MODIFIED 45 files (20 coordinator/templates/workflows, e.g. .copilot/skills/agent-collaboration/SKILL.md, .copilot/skills/cross-squad/SKILL.md, .copilot/skills/git-workflow/SKILL.md …)"
+ "status": "pass"
},
{
"id": "clients-projected",
@@ -759,9 +761,8 @@
}
],
"notes": [
- "plain upgrade changed 100 working-tree path(s), all Squad-owned: .copilot/skills/agent-collaboration/SKILL.md, .copilot/skills/cross-squad/SKILL.md, .copilot/skills/git-workflow/SKILL.md, .copilot/skills/reviewer-protocol/SKILL.md … (+96)",
- "old 0.9.1 upgrade --dry-run on upgraded project: exit 0, last lines \"\u001b[32m✓\u001b[0m refreshed .squad/templates/ | Upgrade complete: v1.2.0-preview.1 → v0.9.1 | \u001b[2mPreserves user state: team.md, decisions/, agents/*/history.md\u001b[0m\"; MODIFIED 45 files (20 coordinator/templates/workflows, e.g. .copilot/skills/agent-collaboration/SKILL.md, .copilot/skills/cross-squad/SKILL.md, .copilot/skills/git-workflow/SKILL.md …)",
- "downgrade-probe: F3"
+ "plain upgrade changed 150 working-tree path(s), all Squad-owned: .gitattributes, .github/agents/squad.agent.md, .github/agents/squad.agent.md.local-backup, .github/skills/coordinator-response-mode/SKILL.md … (+146)",
+ "old 0.13.1 upgrade --dry-run on upgraded project: exit 0, last lines \"overwrite ../.github/workflows/squad-triage.yml | overwrite ../.github/workflows/sync-squad-labels.yml | Run without --dry-run to apply.\"; modified nothing"
]
},
{
@@ -839,7 +840,7 @@
],
"notes": [
"producer wrote teamRoot=/squad at init",
- "plain upgrade changed 59 working-tree path(s), all Squad-owned: .github/agents/squad.agent.md, .github/agents/squad.agent.md.local-backup, .github/skills/coordinator-response-mode/SKILL.md, .github/skills/coordinator-source-of-truth/SKILL.md … (+55)",
+ "plain upgrade changed 151 working-tree path(s), all Squad-owned: .gitattributes, .github/agents/squad.agent.md, .github/agents/squad.agent.md.local-backup, .github/skills/coordinator-response-mode/SKILL.md … (+147)",
"old 0.13.1 upgrade --dry-run on upgraded project: exit 0, last lines \"overwrite ../.github/workflows/squad-triage.yml | overwrite ../.github/workflows/sync-squad-labels.yml | Run without --dry-run to apply.\"; modified nothing"
]
},
@@ -928,7 +929,7 @@
}
],
"notes": [
- "plain upgrade changed 58 working-tree path(s), all Squad-owned: .github/agents/squad.agent.md, .github/agents/squad.agent.md.local-backup, .github/skills/coordinator-response-mode/SKILL.md, .github/skills/coordinator-source-of-truth/SKILL.md … (+54)",
+ "plain upgrade changed 150 working-tree path(s), all Squad-owned: .gitattributes, .github/agents/squad.agent.md, .github/agents/squad.agent.md.local-backup, .github/skills/coordinator-response-mode/SKILL.md … (+146)",
"old 0.13.1 upgrade --dry-run on upgraded project: exit 0, last lines \"overwrite ../.github/workflows/squad-triage.yml | overwrite ../.github/workflows/sync-squad-labels.yml | Run without --dry-run to apply.\"; modified nothing"
]
},
@@ -1006,14 +1007,14 @@
}
],
"notes": [
- "plain upgrade changed 58 working-tree path(s), all Squad-owned: .github/agents/squad.agent.md, .github/agents/squad.agent.md.local-backup, .github/skills/coordinator-response-mode/SKILL.md, .github/skills/coordinator-source-of-truth/SKILL.md … (+54)",
+ "plain upgrade changed 150 working-tree path(s), all Squad-owned: .gitattributes, .github/agents/squad.agent.md, .github/agents/squad.agent.md.local-backup, .github/skills/coordinator-response-mode/SKILL.md … (+146)",
"old 0.13.1 upgrade --dry-run on upgraded project: exit 0, last lines \"overwrite ../.github/workflows/squad-triage.yml | overwrite ../.github/workflows/sync-squad-labels.yml | Run without --dry-run to apply.\"; modified nothing"
]
},
{
"producer": "0.13.1",
"source": "npm",
- "shape": "orphan",
+ "shape": "two-layer",
"status": "pass",
"provenance": "npm: @bradygaster/squad-cli@0.13.1 sha512-ogfx2nhyx6fqMyqlaI5tDnOzUbRdh+a6Uh/rMQ0aNJwAXnvQp4N37Xp/eOTyB5CxcB7E34NBtAfCxyXbWSiS8w==; @bradygaster/squad-sdk@0.13.1 sha512-1Jt6c9kahJq1JCcE77j/50D79YcXVG6Rt1genuLJ3O9J2SKTZKemlbvHgftkc5LgGH22DkWqHh5zLNEQ/p+ukA==",
"checks": [
@@ -1085,14 +1086,14 @@
}
],
"notes": [
- "plain upgrade changed 56 working-tree path(s), all Squad-owned: .github/agents/squad.agent.md, .github/agents/squad.agent.md.local-backup, .github/skills/coordinator-response-mode/SKILL.md, .github/skills/coordinator-source-of-truth/SKILL.md … (+52); squad-state blobs for 3 seeded path(s) identical",
+ "plain upgrade changed 148 working-tree path(s), all Squad-owned: .gitattributes, .github/agents/squad.agent.md, .github/agents/squad.agent.md.local-backup, .github/skills/coordinator-response-mode/SKILL.md … (+144); squad-state blobs for 3 seeded path(s) identical",
"old 0.13.1 upgrade --dry-run on upgraded project: exit 0, last lines \"overwrite ../.github/workflows/squad-triage.yml | overwrite ../.github/workflows/sync-squad-labels.yml | Run without --dry-run to apply.\"; modified nothing"
]
},
{
"producer": "0.13.1",
"source": "npm",
- "shape": "two-layer",
+ "shape": "orphan",
"status": "pass",
"provenance": "npm: @bradygaster/squad-cli@0.13.1 sha512-ogfx2nhyx6fqMyqlaI5tDnOzUbRdh+a6Uh/rMQ0aNJwAXnvQp4N37Xp/eOTyB5CxcB7E34NBtAfCxyXbWSiS8w==; @bradygaster/squad-sdk@0.13.1 sha512-1Jt6c9kahJq1JCcE77j/50D79YcXVG6Rt1genuLJ3O9J2SKTZKemlbvHgftkc5LgGH22DkWqHh5zLNEQ/p+ukA==",
"checks": [
@@ -1164,7 +1165,7 @@
}
],
"notes": [
- "plain upgrade changed 56 working-tree path(s), all Squad-owned: .github/agents/squad.agent.md, .github/agents/squad.agent.md.local-backup, .github/skills/coordinator-response-mode/SKILL.md, .github/skills/coordinator-source-of-truth/SKILL.md … (+52); squad-state blobs for 3 seeded path(s) identical",
+ "plain upgrade changed 148 working-tree path(s), all Squad-owned: .gitattributes, .github/agents/squad.agent.md, .github/agents/squad.agent.md.local-backup, .github/skills/coordinator-response-mode/SKILL.md … (+144); squad-state blobs for 3 seeded path(s) identical",
"old 0.13.1 upgrade --dry-run on upgraded project: exit 0, last lines \"overwrite ../.github/workflows/squad-triage.yml | overwrite ../.github/workflows/sync-squad-labels.yml | Run without --dry-run to apply.\"; modified nothing"
]
},
@@ -1243,7 +1244,7 @@
}
],
"notes": [
- "plain upgrade changed 37 working-tree path(s), all Squad-owned: .github/agents/squad.agent.md, .github/agents/squad.agent.md.local-backup, .github/skills/coordinator-source-of-truth/SKILL.md, .github/workflows/squad-ci.yml … (+33)",
+ "plain upgrade changed 84 working-tree path(s), all Squad-owned: .gitattributes, .github/agents/squad.agent.md, .github/agents/squad.agent.md.local-backup, .github/skills/coordinator-response-mode/SKILL.md … (+80)",
"old 1.0.0 upgrade --dry-run on upgraded project: exit 0, last lines \"overwrite ../.github/workflows/squad-triage.yml | overwrite ../.github/workflows/sync-squad-labels.yml | Run without --dry-run to apply.\"; modified nothing"
]
},
@@ -1322,7 +1323,7 @@
],
"notes": [
"producer wrote teamRoot=/squad at init",
- "plain upgrade changed 38 working-tree path(s), all Squad-owned: .github/agents/squad.agent.md, .github/agents/squad.agent.md.local-backup, .github/skills/coordinator-source-of-truth/SKILL.md, .github/workflows/squad-ci.yml … (+34)",
+ "plain upgrade changed 85 working-tree path(s), all Squad-owned: .gitattributes, .github/agents/squad.agent.md, .github/agents/squad.agent.md.local-backup, .github/skills/coordinator-response-mode/SKILL.md … (+81)",
"old 1.0.0 upgrade --dry-run on upgraded project: exit 0, last lines \"overwrite ../.github/workflows/squad-triage.yml | overwrite ../.github/workflows/sync-squad-labels.yml | Run without --dry-run to apply.\"; modified nothing"
]
},
@@ -1411,7 +1412,7 @@
}
],
"notes": [
- "plain upgrade changed 42 working-tree path(s), all Squad-owned: .github/agents/squad.agent.md, .github/agents/squad.agent.md.local-backup, .github/skills/coordinator-source-of-truth/SKILL.md, .github/workflows/squad-ci.yml … (+38)",
+ "plain upgrade changed 89 working-tree path(s), all Squad-owned: .gitattributes, .github/agents/squad.agent.md, .github/agents/squad.agent.md.local-backup, .github/skills/coordinator-response-mode/SKILL.md … (+85)",
"old 1.0.0 upgrade --dry-run on upgraded project: exit 0, last lines \"overwrite ../.github/workflows/squad-triage.yml | overwrite ../.github/workflows/sync-squad-labels.yml | Run without --dry-run to apply.\"; modified nothing"
]
},
@@ -1490,7 +1491,7 @@
}
],
"notes": [
- "plain upgrade changed 35 working-tree path(s), all Squad-owned: .github/agents/squad.agent.md, .github/agents/squad.agent.md.local-backup, .github/skills/coordinator-source-of-truth/SKILL.md, .github/workflows/squad-ci.yml … (+31); squad-state blobs for 3 seeded path(s) identical",
+ "plain upgrade changed 82 working-tree path(s), all Squad-owned: .gitattributes, .github/agents/squad.agent.md, .github/agents/squad.agent.md.local-backup, .github/skills/coordinator-response-mode/SKILL.md … (+78); squad-state blobs for 3 seeded path(s) identical",
"old 1.0.0 upgrade --dry-run on upgraded project: exit 0, last lines \"overwrite ../.github/workflows/squad-triage.yml | overwrite ../.github/workflows/sync-squad-labels.yml | Run without --dry-run to apply.\"; modified nothing"
]
},
@@ -1569,16 +1570,16 @@
}
],
"notes": [
- "plain upgrade changed 35 working-tree path(s), all Squad-owned: .github/agents/squad.agent.md, .github/agents/squad.agent.md.local-backup, .github/skills/coordinator-source-of-truth/SKILL.md, .github/workflows/squad-ci.yml … (+31); squad-state blobs for 3 seeded path(s) identical",
+ "plain upgrade changed 82 working-tree path(s), all Squad-owned: .gitattributes, .github/agents/squad.agent.md, .github/agents/squad.agent.md.local-backup, .github/skills/coordinator-response-mode/SKILL.md … (+78); squad-state blobs for 3 seeded path(s) identical",
"old 1.0.0 upgrade --dry-run on upgraded project: exit 0, last lines \"overwrite ../.github/workflows/squad-triage.yml | overwrite ../.github/workflows/sync-squad-labels.yml | Run without --dry-run to apply.\"; modified nothing"
]
},
{
- "producer": "1.0.1",
- "source": "github-release",
- "shape": "default",
+ "producer": "1.0.0",
+ "source": "npm",
+ "shape": "ai-team",
"status": "pass",
- "provenance": "github-release: bradygaster/squad@v1.0.1 asset squad-linux-x64.tar.gz id 610330551 sha256 283a1893be9ddad11056dcc8bd0673eff6b48a789bbf523b3f7ec31994d27ac7 (bundled node 22.20.0)",
+ "provenance": "npm: @bradygaster/squad-cli@1.0.0 sha512-mnZXnA+GAtp4KSLf7a4Zw0BpeOaHFAxYV5oxAy58ancZ9C2LguUGbcTxWIG0djM96XWET8K9fcncif3Vm6Z9RQ==; @bradygaster/squad-sdk@1.0.0 sha512-9f4NthJaQDq6ifXU3f6VfsZz2bbWs2u57fHhXKtDgDMSvZ3Xq8FPjMvddxhRvseWqaSlkYcWsag3M/lzTtKaJA==",
"checks": [
{
"id": "producer-artifact-verified",
@@ -1610,8 +1611,7 @@
},
{
"id": "ai-team-migrated",
- "status": "skipped",
- "detail": "not an .ai-team shape"
+ "status": "pass"
},
{
"id": "team-root-absent",
@@ -1648,16 +1648,16 @@
}
],
"notes": [
- "plain upgrade changed 37 working-tree path(s), all Squad-owned: .github/agents/squad.agent.md, .github/agents/squad.agent.md.local-backup, .github/skills/coordinator-source-of-truth/SKILL.md, .github/workflows/squad-ci.yml … (+33)",
- "old 1.0.1 upgrade --dry-run on upgraded project: exit 0, last lines \"overwrite ../.github/workflows/squad-triage.yml | overwrite ../.github/workflows/sync-squad-labels.yml | Run without --dry-run to apply.\"; modified nothing"
+ "plain upgrade changed 84 working-tree path(s), all Squad-owned: .gitattributes, .github/agents/squad.agent.md, .github/agents/squad.agent.md.local-backup, .github/skills/coordinator-response-mode/SKILL.md … (+80)",
+ "old 1.0.0 upgrade --dry-run on upgraded project: exit 0, last lines \"overwrite ../.github/workflows/squad-triage.yml | overwrite ../.github/workflows/sync-squad-labels.yml | Run without --dry-run to apply.\"; modified nothing"
]
},
{
- "producer": "1.0.0",
- "source": "npm",
- "shape": "ai-team",
+ "producer": "1.0.1",
+ "source": "github-release",
+ "shape": "default",
"status": "pass",
- "provenance": "npm: @bradygaster/squad-cli@1.0.0 sha512-mnZXnA+GAtp4KSLf7a4Zw0BpeOaHFAxYV5oxAy58ancZ9C2LguUGbcTxWIG0djM96XWET8K9fcncif3Vm6Z9RQ==; @bradygaster/squad-sdk@1.0.0 sha512-9f4NthJaQDq6ifXU3f6VfsZz2bbWs2u57fHhXKtDgDMSvZ3Xq8FPjMvddxhRvseWqaSlkYcWsag3M/lzTtKaJA==",
+ "provenance": "github-release: github/squad@v1.0.1 asset squad-linux-x64.tar.gz id 610330551 sha256 283a1893be9ddad11056dcc8bd0673eff6b48a789bbf523b3f7ec31994d27ac7 (bundled node 22.20.0)",
"checks": [
{
"id": "producer-artifact-verified",
@@ -1689,7 +1689,8 @@
},
{
"id": "ai-team-migrated",
- "status": "pass"
+ "status": "skipped",
+ "detail": "not an .ai-team shape"
},
{
"id": "team-root-absent",
@@ -1726,8 +1727,8 @@
}
],
"notes": [
- "plain upgrade changed 37 working-tree path(s), all Squad-owned: .github/agents/squad.agent.md, .github/agents/squad.agent.md.local-backup, .github/skills/coordinator-source-of-truth/SKILL.md, .github/workflows/squad-ci.yml … (+33)",
- "old 1.0.0 upgrade --dry-run on upgraded project: exit 0, last lines \"overwrite ../.github/workflows/squad-triage.yml | overwrite ../.github/workflows/sync-squad-labels.yml | Run without --dry-run to apply.\"; modified nothing"
+ "plain upgrade changed 84 working-tree path(s), all Squad-owned: .gitattributes, .github/agents/squad.agent.md, .github/agents/squad.agent.md.local-backup, .github/skills/coordinator-response-mode/SKILL.md … (+80)",
+ "old 1.0.1 upgrade --dry-run on upgraded project: exit 0, last lines \"overwrite ../.github/workflows/squad-triage.yml | overwrite ../.github/workflows/sync-squad-labels.yml | Run without --dry-run to apply.\"; modified nothing"
]
},
{
@@ -1735,7 +1736,7 @@
"source": "github-release",
"shape": "profile",
"status": "pass",
- "provenance": "github-release: bradygaster/squad@v1.0.1 asset squad-linux-x64.tar.gz id 610330551 sha256 283a1893be9ddad11056dcc8bd0673eff6b48a789bbf523b3f7ec31994d27ac7 (bundled node 22.20.0)",
+ "provenance": "github-release: github/squad@v1.0.1 asset squad-linux-x64.tar.gz id 610330551 sha256 283a1893be9ddad11056dcc8bd0673eff6b48a789bbf523b3f7ec31994d27ac7 (bundled node 22.20.0)",
"checks": [
{
"id": "producer-artifact-verified",
@@ -1805,7 +1806,7 @@
],
"notes": [
"producer wrote teamRoot=/squad at init",
- "plain upgrade changed 38 working-tree path(s), all Squad-owned: .github/agents/squad.agent.md, .github/agents/squad.agent.md.local-backup, .github/skills/coordinator-source-of-truth/SKILL.md, .github/workflows/squad-ci.yml … (+34)",
+ "plain upgrade changed 85 working-tree path(s), all Squad-owned: .gitattributes, .github/agents/squad.agent.md, .github/agents/squad.agent.md.local-backup, .github/skills/coordinator-response-mode/SKILL.md … (+81)",
"old 1.0.1 upgrade --dry-run on upgraded project: exit 0, last lines \"overwrite ../.github/workflows/squad-triage.yml | overwrite ../.github/workflows/sync-squad-labels.yml | Run without --dry-run to apply.\"; modified nothing"
]
},
@@ -1815,7 +1816,7 @@
"shape": "upstream",
"status": "skipped",
"reason": "Upstream inheritance (`.squad/upstream.json`, `squad upstream add`) is a Squad 2.0 feature; 1.0.1 cannot declare an upstream, so there is nothing for the upgrade to preserve.",
- "provenance": "github-release: bradygaster/squad@v1.0.1 asset squad-linux-x64.tar.gz id 610330551 sha256 283a1893be9ddad11056dcc8bd0673eff6b48a789bbf523b3f7ec31994d27ac7 (bundled node 22.20.0)",
+ "provenance": "github-release: github/squad@v1.0.1 asset squad-linux-x64.tar.gz id 610330551 sha256 283a1893be9ddad11056dcc8bd0673eff6b48a789bbf523b3f7ec31994d27ac7 (bundled node 22.20.0)",
"checks": [],
"notes": []
},
@@ -1824,7 +1825,7 @@
"source": "github-release",
"shape": "legacy-casting",
"status": "pass",
- "provenance": "github-release: bradygaster/squad@v1.0.1 asset squad-linux-x64.tar.gz id 610330551 sha256 283a1893be9ddad11056dcc8bd0673eff6b48a789bbf523b3f7ec31994d27ac7 (bundled node 22.20.0)",
+ "provenance": "github-release: github/squad@v1.0.1 asset squad-linux-x64.tar.gz id 610330551 sha256 283a1893be9ddad11056dcc8bd0673eff6b48a789bbf523b3f7ec31994d27ac7 (bundled node 22.20.0)",
"checks": [
{
"id": "producer-artifact-verified",
@@ -1894,7 +1895,7 @@
}
],
"notes": [
- "plain upgrade changed 42 working-tree path(s), all Squad-owned: .github/agents/squad.agent.md, .github/agents/squad.agent.md.local-backup, .github/skills/coordinator-source-of-truth/SKILL.md, .github/workflows/squad-ci.yml … (+38)",
+ "plain upgrade changed 89 working-tree path(s), all Squad-owned: .gitattributes, .github/agents/squad.agent.md, .github/agents/squad.agent.md.local-backup, .github/skills/coordinator-response-mode/SKILL.md … (+85)",
"old 1.0.1 upgrade --dry-run on upgraded project: exit 0, last lines \"overwrite ../.github/workflows/squad-triage.yml | overwrite ../.github/workflows/sync-squad-labels.yml | Run without --dry-run to apply.\"; modified nothing"
]
},
@@ -1903,7 +1904,7 @@
"source": "github-release",
"shape": "orphan",
"status": "pass",
- "provenance": "github-release: bradygaster/squad@v1.0.1 asset squad-linux-x64.tar.gz id 610330551 sha256 283a1893be9ddad11056dcc8bd0673eff6b48a789bbf523b3f7ec31994d27ac7 (bundled node 22.20.0)",
+ "provenance": "github-release: github/squad@v1.0.1 asset squad-linux-x64.tar.gz id 610330551 sha256 283a1893be9ddad11056dcc8bd0673eff6b48a789bbf523b3f7ec31994d27ac7 (bundled node 22.20.0)",
"checks": [
{
"id": "producer-artifact-verified",
@@ -1973,16 +1974,16 @@
}
],
"notes": [
- "plain upgrade changed 35 working-tree path(s), all Squad-owned: .github/agents/squad.agent.md, .github/agents/squad.agent.md.local-backup, .github/skills/coordinator-source-of-truth/SKILL.md, .github/workflows/squad-ci.yml … (+31); squad-state blobs for 3 seeded path(s) identical",
+ "plain upgrade changed 82 working-tree path(s), all Squad-owned: .gitattributes, .github/agents/squad.agent.md, .github/agents/squad.agent.md.local-backup, .github/skills/coordinator-response-mode/SKILL.md … (+78); squad-state blobs for 3 seeded path(s) identical",
"old 1.0.1 upgrade --dry-run on upgraded project: exit 0, last lines \"overwrite ../.github/workflows/squad-triage.yml | overwrite ../.github/workflows/sync-squad-labels.yml | Run without --dry-run to apply.\"; modified nothing"
]
},
{
"producer": "1.0.1",
"source": "github-release",
- "shape": "two-layer",
+ "shape": "ai-team",
"status": "pass",
- "provenance": "github-release: bradygaster/squad@v1.0.1 asset squad-linux-x64.tar.gz id 610330551 sha256 283a1893be9ddad11056dcc8bd0673eff6b48a789bbf523b3f7ec31994d27ac7 (bundled node 22.20.0)",
+ "provenance": "github-release: github/squad@v1.0.1 asset squad-linux-x64.tar.gz id 610330551 sha256 283a1893be9ddad11056dcc8bd0673eff6b48a789bbf523b3f7ec31994d27ac7 (bundled node 22.20.0)",
"checks": [
{
"id": "producer-artifact-verified",
@@ -2014,8 +2015,7 @@
},
{
"id": "ai-team-migrated",
- "status": "skipped",
- "detail": "not an .ai-team shape"
+ "status": "pass"
},
{
"id": "team-root-absent",
@@ -2052,16 +2052,16 @@
}
],
"notes": [
- "plain upgrade changed 35 working-tree path(s), all Squad-owned: .github/agents/squad.agent.md, .github/agents/squad.agent.md.local-backup, .github/skills/coordinator-source-of-truth/SKILL.md, .github/workflows/squad-ci.yml … (+31); squad-state blobs for 3 seeded path(s) identical",
+ "plain upgrade changed 84 working-tree path(s), all Squad-owned: .gitattributes, .github/agents/squad.agent.md, .github/agents/squad.agent.md.local-backup, .github/skills/coordinator-response-mode/SKILL.md … (+80)",
"old 1.0.1 upgrade --dry-run on upgraded project: exit 0, last lines \"overwrite ../.github/workflows/squad-triage.yml | overwrite ../.github/workflows/sync-squad-labels.yml | Run without --dry-run to apply.\"; modified nothing"
]
},
{
- "producer": "1.1.0",
+ "producer": "1.0.1",
"source": "github-release",
- "shape": "default",
+ "shape": "two-layer",
"status": "pass",
- "provenance": "github-release: bradygaster/squad@v1.1.0 asset squad-linux-x64.tar.gz id 659607641 sha256 2de647a3feaef334051eb1b3084acba37a511818aad029a16abfe32fadb41aff (bundled node 22.20.0)",
+ "provenance": "github-release: github/squad@v1.0.1 asset squad-linux-x64.tar.gz id 610330551 sha256 283a1893be9ddad11056dcc8bd0673eff6b48a789bbf523b3f7ec31994d27ac7 (bundled node 22.20.0)",
"checks": [
{
"id": "producer-artifact-verified",
@@ -2131,16 +2131,16 @@
}
],
"notes": [
- "plain upgrade changed 27 working-tree path(s), all Squad-owned: .github/agents/squad.agent.md, .github/agents/squad.agent.md.local-backup, .github/workflows/squad-ci.yml, .github/workflows/squad-ci.yml.local-backup … (+23)",
- "old 1.1.0 upgrade --dry-run on upgraded project: exit 0, last lines \"overwrite ../.github/workflows/squad-triage.yml | overwrite ../.github/workflows/sync-squad-labels.yml | Run without --dry-run to apply.\"; modified nothing"
+ "plain upgrade changed 82 working-tree path(s), all Squad-owned: .gitattributes, .github/agents/squad.agent.md, .github/agents/squad.agent.md.local-backup, .github/skills/coordinator-response-mode/SKILL.md … (+78); squad-state blobs for 3 seeded path(s) identical",
+ "old 1.0.1 upgrade --dry-run on upgraded project: exit 0, last lines \"overwrite ../.github/workflows/squad-triage.yml | overwrite ../.github/workflows/sync-squad-labels.yml | Run without --dry-run to apply.\"; modified nothing"
]
},
{
- "producer": "1.0.1",
+ "producer": "1.1.0",
"source": "github-release",
- "shape": "ai-team",
+ "shape": "default",
"status": "pass",
- "provenance": "github-release: bradygaster/squad@v1.0.1 asset squad-linux-x64.tar.gz id 610330551 sha256 283a1893be9ddad11056dcc8bd0673eff6b48a789bbf523b3f7ec31994d27ac7 (bundled node 22.20.0)",
+ "provenance": "github-release: github/squad@v1.1.0 asset squad-linux-x64.tar.gz id 659607641 sha256 2de647a3feaef334051eb1b3084acba37a511818aad029a16abfe32fadb41aff (bundled node 22.20.0)",
"checks": [
{
"id": "producer-artifact-verified",
@@ -2172,7 +2172,8 @@
},
{
"id": "ai-team-migrated",
- "status": "pass"
+ "status": "skipped",
+ "detail": "not an .ai-team shape"
},
{
"id": "team-root-absent",
@@ -2209,16 +2210,16 @@
}
],
"notes": [
- "plain upgrade changed 37 working-tree path(s), all Squad-owned: .github/agents/squad.agent.md, .github/agents/squad.agent.md.local-backup, .github/skills/coordinator-source-of-truth/SKILL.md, .github/workflows/squad-ci.yml … (+33)",
- "old 1.0.1 upgrade --dry-run on upgraded project: exit 0, last lines \"overwrite ../.github/workflows/squad-triage.yml | overwrite ../.github/workflows/sync-squad-labels.yml | Run without --dry-run to apply.\"; modified nothing"
+ "plain upgrade changed 54 working-tree path(s), all Squad-owned: .gitattributes, .github/agents/squad.agent.md, .github/agents/squad.agent.md.local-backup, .github/skills/coordinator-response-mode/SKILL.md … (+50)",
+ "old 1.1.0 upgrade --dry-run on upgraded project: exit 0, last lines \"overwrite ../.github/workflows/squad-triage.yml | overwrite ../.github/workflows/sync-squad-labels.yml | Run without --dry-run to apply.\"; modified nothing"
]
},
{
"producer": "1.1.0",
"source": "github-release",
- "shape": "profile",
+ "shape": "legacy-casting",
"status": "pass",
- "provenance": "github-release: bradygaster/squad@v1.1.0 asset squad-linux-x64.tar.gz id 659607641 sha256 2de647a3feaef334051eb1b3084acba37a511818aad029a16abfe32fadb41aff (bundled node 22.20.0)",
+ "provenance": "github-release: github/squad@v1.1.0 asset squad-linux-x64.tar.gz id 659607641 sha256 2de647a3feaef334051eb1b3084acba37a511818aad029a16abfe32fadb41aff (bundled node 22.20.0)",
"checks": [
{
"id": "producer-artifact-verified",
@@ -2283,12 +2284,12 @@
},
{
"id": "profile-untouched",
- "status": "pass"
+ "status": "skipped",
+ "detail": "no profile squad seeded in this shape"
}
],
"notes": [
- "producer wrote teamRoot=/squad at init",
- "plain upgrade changed 28 working-tree path(s), all Squad-owned: .github/agents/squad.agent.md, .github/agents/squad.agent.md.local-backup, .github/workflows/squad-ci.yml, .github/workflows/squad-ci.yml.local-backup … (+24)",
+ "plain upgrade changed 59 working-tree path(s), all Squad-owned: .gitattributes, .github/agents/squad.agent.md, .github/agents/squad.agent.md.local-backup, .github/skills/coordinator-response-mode/SKILL.md … (+55)",
"old 1.1.0 upgrade --dry-run on upgraded project: exit 0, last lines \"overwrite ../.github/workflows/squad-triage.yml | overwrite ../.github/workflows/sync-squad-labels.yml | Run without --dry-run to apply.\"; modified nothing"
]
},
@@ -2298,16 +2299,16 @@
"shape": "upstream",
"status": "skipped",
"reason": "Upstream inheritance (`.squad/upstream.json`, `squad upstream add`) is a Squad 2.0 feature; 1.1.0 cannot declare an upstream, so there is nothing for the upgrade to preserve.",
- "provenance": "github-release: bradygaster/squad@v1.1.0 asset squad-linux-x64.tar.gz id 659607641 sha256 2de647a3feaef334051eb1b3084acba37a511818aad029a16abfe32fadb41aff (bundled node 22.20.0)",
+ "provenance": "github-release: github/squad@v1.1.0 asset squad-linux-x64.tar.gz id 659607641 sha256 2de647a3feaef334051eb1b3084acba37a511818aad029a16abfe32fadb41aff (bundled node 22.20.0)",
"checks": [],
"notes": []
},
{
"producer": "1.1.0",
"source": "github-release",
- "shape": "legacy-casting",
+ "shape": "profile",
"status": "pass",
- "provenance": "github-release: bradygaster/squad@v1.1.0 asset squad-linux-x64.tar.gz id 659607641 sha256 2de647a3feaef334051eb1b3084acba37a511818aad029a16abfe32fadb41aff (bundled node 22.20.0)",
+ "provenance": "github-release: github/squad@v1.1.0 asset squad-linux-x64.tar.gz id 659607641 sha256 2de647a3feaef334051eb1b3084acba37a511818aad029a16abfe32fadb41aff (bundled node 22.20.0)",
"checks": [
{
"id": "producer-artifact-verified",
@@ -2372,21 +2373,21 @@
},
{
"id": "profile-untouched",
- "status": "skipped",
- "detail": "no profile squad seeded in this shape"
+ "status": "pass"
}
],
"notes": [
- "plain upgrade changed 32 working-tree path(s), all Squad-owned: .github/agents/squad.agent.md, .github/agents/squad.agent.md.local-backup, .github/workflows/squad-ci.yml, .github/workflows/squad-ci.yml.local-backup … (+28)",
+ "producer wrote teamRoot=/squad at init",
+ "plain upgrade changed 55 working-tree path(s), all Squad-owned: .gitattributes, .github/agents/squad.agent.md, .github/agents/squad.agent.md.local-backup, .github/skills/coordinator-response-mode/SKILL.md … (+51)",
"old 1.1.0 upgrade --dry-run on upgraded project: exit 0, last lines \"overwrite ../.github/workflows/squad-triage.yml | overwrite ../.github/workflows/sync-squad-labels.yml | Run without --dry-run to apply.\"; modified nothing"
]
},
{
- "producer": "HEAD",
- "source": "pack",
- "shape": "default",
+ "producer": "1.1.0",
+ "source": "github-release",
+ "shape": "ai-team",
"status": "pass",
- "provenance": "pack: npm pack of packages/squad-sdk + packages/squad-cli at 9da01a2e41ba15794d31b0b8251ddaa3abd34ba8 (v1.2.0-preview.1)",
+ "provenance": "github-release: github/squad@v1.1.0 asset squad-linux-x64.tar.gz id 659607641 sha256 2de647a3feaef334051eb1b3084acba37a511818aad029a16abfe32fadb41aff (bundled node 22.20.0)",
"checks": [
{
"id": "producer-artifact-verified",
@@ -2418,8 +2419,7 @@
},
{
"id": "ai-team-migrated",
- "status": "skipped",
- "detail": "not an .ai-team shape"
+ "status": "pass"
},
{
"id": "team-root-absent",
@@ -2431,8 +2431,7 @@
},
{
"id": "downgrade-probe",
- "status": "skipped",
- "detail": "producer is the target version"
+ "status": "pass"
},
{
"id": "clients-projected",
@@ -2457,15 +2456,16 @@
}
],
"notes": [
- "plain upgrade changed 13 working-tree path(s), all Squad-owned: .github/workflows/squad-ci.yml, .github/workflows/squad-docs.yml, .github/workflows/squad-insider-release.yml, .github/workflows/squad-label-enforce.yml … (+9)"
+ "plain upgrade changed 54 working-tree path(s), all Squad-owned: .gitattributes, .github/agents/squad.agent.md, .github/agents/squad.agent.md.local-backup, .github/skills/coordinator-response-mode/SKILL.md … (+50)",
+ "old 1.1.0 upgrade --dry-run on upgraded project: exit 0, last lines \"overwrite ../.github/workflows/squad-triage.yml | overwrite ../.github/workflows/sync-squad-labels.yml | Run without --dry-run to apply.\"; modified nothing"
]
},
{
"producer": "1.1.0",
"source": "github-release",
- "shape": "ai-team",
+ "shape": "two-layer",
"status": "pass",
- "provenance": "github-release: bradygaster/squad@v1.1.0 asset squad-linux-x64.tar.gz id 659607641 sha256 2de647a3feaef334051eb1b3084acba37a511818aad029a16abfe32fadb41aff (bundled node 22.20.0)",
+ "provenance": "github-release: github/squad@v1.1.0 asset squad-linux-x64.tar.gz id 659607641 sha256 2de647a3feaef334051eb1b3084acba37a511818aad029a16abfe32fadb41aff (bundled node 22.20.0)",
"checks": [
{
"id": "producer-artifact-verified",
@@ -2497,7 +2497,8 @@
},
{
"id": "ai-team-migrated",
- "status": "pass"
+ "status": "skipped",
+ "detail": "not an .ai-team shape"
},
{
"id": "team-root-absent",
@@ -2534,16 +2535,16 @@
}
],
"notes": [
- "plain upgrade changed 27 working-tree path(s), all Squad-owned: .github/agents/squad.agent.md, .github/agents/squad.agent.md.local-backup, .github/workflows/squad-ci.yml, .github/workflows/squad-ci.yml.local-backup … (+23)",
+ "plain upgrade changed 52 working-tree path(s), all Squad-owned: .gitattributes, .github/agents/squad.agent.md, .github/agents/squad.agent.md.local-backup, .github/skills/coordinator-response-mode/SKILL.md … (+48); squad-state blobs for 3 seeded path(s) identical",
"old 1.1.0 upgrade --dry-run on upgraded project: exit 0, last lines \"overwrite ../.github/workflows/squad-triage.yml | overwrite ../.github/workflows/sync-squad-labels.yml | Run without --dry-run to apply.\"; modified nothing"
]
},
{
"producer": "1.1.0",
"source": "github-release",
- "shape": "two-layer",
+ "shape": "orphan",
"status": "pass",
- "provenance": "github-release: bradygaster/squad@v1.1.0 asset squad-linux-x64.tar.gz id 659607641 sha256 2de647a3feaef334051eb1b3084acba37a511818aad029a16abfe32fadb41aff (bundled node 22.20.0)",
+ "provenance": "github-release: github/squad@v1.1.0 asset squad-linux-x64.tar.gz id 659607641 sha256 2de647a3feaef334051eb1b3084acba37a511818aad029a16abfe32fadb41aff (bundled node 22.20.0)",
"checks": [
{
"id": "producer-artifact-verified",
@@ -2613,16 +2614,16 @@
}
],
"notes": [
- "plain upgrade changed 25 working-tree path(s), all Squad-owned: .github/agents/squad.agent.md, .github/agents/squad.agent.md.local-backup, .github/workflows/squad-ci.yml, .github/workflows/squad-ci.yml.local-backup … (+21); squad-state blobs for 3 seeded path(s) identical",
+ "plain upgrade changed 52 working-tree path(s), all Squad-owned: .gitattributes, .github/agents/squad.agent.md, .github/agents/squad.agent.md.local-backup, .github/skills/coordinator-response-mode/SKILL.md … (+48); squad-state blobs for 3 seeded path(s) identical",
"old 1.1.0 upgrade --dry-run on upgraded project: exit 0, last lines \"overwrite ../.github/workflows/squad-triage.yml | overwrite ../.github/workflows/sync-squad-labels.yml | Run without --dry-run to apply.\"; modified nothing"
]
},
{
- "producer": "1.1.0",
- "source": "github-release",
- "shape": "orphan",
+ "producer": "HEAD",
+ "source": "pack",
+ "shape": "profile",
"status": "pass",
- "provenance": "github-release: bradygaster/squad@v1.1.0 asset squad-linux-x64.tar.gz id 659607641 sha256 2de647a3feaef334051eb1b3084acba37a511818aad029a16abfe32fadb41aff (bundled node 22.20.0)",
+ "provenance": "pack: npm pack of packages/squad-sdk + packages/squad-cli at 9b254ba858abc19ef62e513993d9802312bfe34c (v2.0.0-preview.4)",
"checks": [
{
"id": "producer-artifact-verified",
@@ -2667,7 +2668,8 @@
},
{
"id": "downgrade-probe",
- "status": "pass"
+ "status": "skipped",
+ "detail": "producer is the target version"
},
{
"id": "clients-projected",
@@ -2687,21 +2689,19 @@
},
{
"id": "profile-untouched",
- "status": "skipped",
- "detail": "no profile squad seeded in this shape"
+ "status": "pass"
}
],
"notes": [
- "plain upgrade changed 25 working-tree path(s), all Squad-owned: .github/agents/squad.agent.md, .github/agents/squad.agent.md.local-backup, .github/workflows/squad-ci.yml, .github/workflows/squad-ci.yml.local-backup … (+21); squad-state blobs for 3 seeded path(s) identical",
- "old 1.1.0 upgrade --dry-run on upgraded project: exit 0, last lines \"overwrite ../.github/workflows/squad-triage.yml | overwrite ../.github/workflows/sync-squad-labels.yml | Run without --dry-run to apply.\"; modified nothing"
+ "plain upgrade changed 12 working-tree path(s), all Squad-owned: .github/workflows/squad-ci.yml, .github/workflows/squad-docs.yml, .github/workflows/squad-insider-release.yml, .github/workflows/squad-label-enforce.yml … (+8)"
]
},
{
"producer": "HEAD",
"source": "pack",
- "shape": "profile",
+ "shape": "default",
"status": "pass",
- "provenance": "pack: npm pack of packages/squad-sdk + packages/squad-cli at 9da01a2e41ba15794d31b0b8251ddaa3abd34ba8 (v1.2.0-preview.1)",
+ "provenance": "pack: npm pack of packages/squad-sdk + packages/squad-cli at 9b254ba858abc19ef62e513993d9802312bfe34c (v2.0.0-preview.4)",
"checks": [
{
"id": "producer-artifact-verified",
@@ -2767,11 +2767,12 @@
},
{
"id": "profile-untouched",
- "status": "pass"
+ "status": "skipped",
+ "detail": "no profile squad seeded in this shape"
}
],
"notes": [
- "plain upgrade changed 13 working-tree path(s), all Squad-owned: .github/workflows/squad-ci.yml, .github/workflows/squad-docs.yml, .github/workflows/squad-insider-release.yml, .github/workflows/squad-label-enforce.yml … (+9)"
+ "plain upgrade changed 12 working-tree path(s), all Squad-owned: .github/workflows/squad-ci.yml, .github/workflows/squad-docs.yml, .github/workflows/squad-insider-release.yml, .github/workflows/squad-label-enforce.yml … (+8)"
]
},
{
@@ -2779,7 +2780,7 @@
"source": "pack",
"shape": "legacy-casting",
"status": "pass",
- "provenance": "pack: npm pack of packages/squad-sdk + packages/squad-cli at 9da01a2e41ba15794d31b0b8251ddaa3abd34ba8 (v1.2.0-preview.1)",
+ "provenance": "pack: npm pack of packages/squad-sdk + packages/squad-cli at 9b254ba858abc19ef62e513993d9802312bfe34c (v2.0.0-preview.4)",
"checks": [
{
"id": "producer-artifact-verified",
@@ -2850,7 +2851,7 @@
}
],
"notes": [
- "plain upgrade changed 18 working-tree path(s), all Squad-owned: .github/workflows/squad-ci.yml, .github/workflows/squad-docs.yml, .github/workflows/squad-insider-release.yml, .github/workflows/squad-label-enforce.yml … (+14)"
+ "plain upgrade changed 17 working-tree path(s), all Squad-owned: .github/workflows/squad-ci.yml, .github/workflows/squad-docs.yml, .github/workflows/squad-insider-release.yml, .github/workflows/squad-label-enforce.yml … (+13)"
]
},
{
@@ -2858,7 +2859,7 @@
"source": "pack",
"shape": "ai-team",
"status": "pass",
- "provenance": "pack: npm pack of packages/squad-sdk + packages/squad-cli at 9da01a2e41ba15794d31b0b8251ddaa3abd34ba8 (v1.2.0-preview.1)",
+ "provenance": "pack: npm pack of packages/squad-sdk + packages/squad-cli at 9b254ba858abc19ef62e513993d9802312bfe34c (v2.0.0-preview.4)",
"checks": [
{
"id": "producer-artifact-verified",
@@ -2928,7 +2929,7 @@
}
],
"notes": [
- "plain upgrade changed 13 working-tree path(s), all Squad-owned: .github/workflows/squad-ci.yml, .github/workflows/squad-docs.yml, .github/workflows/squad-insider-release.yml, .github/workflows/squad-label-enforce.yml … (+9)"
+ "plain upgrade changed 12 working-tree path(s), all Squad-owned: .github/workflows/squad-ci.yml, .github/workflows/squad-docs.yml, .github/workflows/squad-insider-release.yml, .github/workflows/squad-label-enforce.yml … (+8)"
]
},
{
@@ -2936,7 +2937,7 @@
"source": "pack",
"shape": "orphan",
"status": "pass",
- "provenance": "pack: npm pack of packages/squad-sdk + packages/squad-cli at 9da01a2e41ba15794d31b0b8251ddaa3abd34ba8 (v1.2.0-preview.1)",
+ "provenance": "pack: npm pack of packages/squad-sdk + packages/squad-cli at 9b254ba858abc19ef62e513993d9802312bfe34c (v2.0.0-preview.4)",
"checks": [
{
"id": "producer-artifact-verified",
@@ -3007,7 +3008,7 @@
}
],
"notes": [
- "plain upgrade changed 11 working-tree path(s), all Squad-owned: .github/workflows/squad-ci.yml, .github/workflows/squad-docs.yml, .github/workflows/squad-insider-release.yml, .github/workflows/squad-label-enforce.yml … (+7); squad-state blobs for 3 seeded path(s) identical"
+ "plain upgrade changed 15 working-tree path(s), all Squad-owned: .github/workflows/squad-ci.yml, .github/workflows/squad-docs.yml, .github/workflows/squad-insider-release.yml, .github/workflows/squad-label-enforce.yml … (+11); squad-state blobs for 3 seeded path(s) identical"
]
},
{
@@ -3015,7 +3016,7 @@
"source": "pack",
"shape": "two-layer",
"status": "pass",
- "provenance": "pack: npm pack of packages/squad-sdk + packages/squad-cli at 9da01a2e41ba15794d31b0b8251ddaa3abd34ba8 (v1.2.0-preview.1)",
+ "provenance": "pack: npm pack of packages/squad-sdk + packages/squad-cli at 9b254ba858abc19ef62e513993d9802312bfe34c (v2.0.0-preview.4)",
"checks": [
{
"id": "producer-artifact-verified",
@@ -3086,7 +3087,7 @@
}
],
"notes": [
- "plain upgrade changed 11 working-tree path(s), all Squad-owned: .github/workflows/squad-ci.yml, .github/workflows/squad-docs.yml, .github/workflows/squad-insider-release.yml, .github/workflows/squad-label-enforce.yml … (+7); squad-state blobs for 3 seeded path(s) identical"
+ "plain upgrade changed 15 working-tree path(s), all Squad-owned: .github/workflows/squad-ci.yml, .github/workflows/squad-docs.yml, .github/workflows/squad-insider-release.yml, .github/workflows/squad-label-enforce.yml … (+11); squad-state blobs for 3 seeded path(s) identical"
]
},
{
@@ -3094,7 +3095,7 @@
"source": "pack",
"shape": "upstream",
"status": "pass",
- "provenance": "pack: npm pack of packages/squad-sdk + packages/squad-cli at 9da01a2e41ba15794d31b0b8251ddaa3abd34ba8 (v1.2.0-preview.1)",
+ "provenance": "pack: npm pack of packages/squad-sdk + packages/squad-cli at 9b254ba858abc19ef62e513993d9802312bfe34c (v2.0.0-preview.4)",
"checks": [
{
"id": "producer-artifact-verified",
@@ -3165,7 +3166,7 @@
}
],
"notes": [
- "plain upgrade changed 13 working-tree path(s), all Squad-owned: .github/workflows/squad-ci.yml, .github/workflows/squad-docs.yml, .github/workflows/squad-insider-release.yml, .github/workflows/squad-label-enforce.yml … (+9)"
+ "plain upgrade changed 12 working-tree path(s), all Squad-owned: .github/workflows/squad-ci.yml, .github/workflows/squad-docs.yml, .github/workflows/squad-insider-release.yml, .github/workflows/squad-label-enforce.yml … (+8)"
]
}
]
@@ -3174,12 +3175,12 @@
"platform": "win32",
"arch": "x64",
"node": "v22.23.4",
- "target": "1.2.0-preview.1",
- "targetSha": "9da01a2e41ba15794d31b0b8251ddaa3abd34ba8",
- "harnessHash": "bca27c39dc2dcbffc3bf652bf1f45b471c09911a4bb9ba7e5b7247d25705a66e",
- "event": "workflow_dispatch",
- "runUrl": "https://github.com/bradygaster/squad/actions/runs/39903943542",
- "recordedAt": "2026-10-23T05:10:56.011Z",
+ "target": "2.0.0-preview.4",
+ "targetSha": "9b254ba858abc19ef62e513993d9802312bfe34c",
+ "harnessHash": "a9713d320fdb479ced9cd311f36cf33bbd70d5733afb1617cd740831ce6767f8",
+ "event": "pull_request",
+ "runUrl": "https://github.com/github/squad/actions/runs/43147851248",
+ "recordedAt": "2026-11-12T03:28:29.483Z",
"results": [
{
"producer": "0.9.1",
@@ -3214,7 +3215,7 @@
{
"producer": "0.9.1",
"source": "npm",
- "shape": "profile",
+ "shape": "legacy-casting",
"status": "pass",
"provenance": "npm: @bradygaster/squad-cli@0.9.1 sha512-TcZqRbJk3XBg4N8Y5/5OWJeA52ARAMuzk4MGtB0bfdr87e7iJRV6lJEw8+OIYz9IQ+1JxN/Q30dZDALMOcdi2w==; @bradygaster/squad-sdk@0.9.1 sha512-1KqZ2N6Lt/B4uYlU/Su9JjA1s/7ng0OAEb9CZrkRk19YSPi6tg7K5QWdTKl5gY/gp8zPAJqfjVffOwrZwGlzmw==",
"checks": [
@@ -3262,7 +3263,7 @@
{
"id": "downgrade-probe",
"status": "xfail",
- "detail": "dry-run MODIFIED 44 files (20 coordinator/templates/workflows, e.g. .copilot/skills/agent-collaboration/SKILL.md, .copilot/skills/cross-squad/SKILL.md, .copilot/skills/git-workflow/SKILL.md …)"
+ "detail": "dry-run MODIFIED 67 files (20 coordinator/templates/workflows, e.g. .copilot/skills/agent-collaboration/SKILL.md, .copilot/skills/agent-conduct/SKILL.md, .copilot/skills/architectural-proposals/SKILL.md …)"
},
{
"id": "clients-projected",
@@ -3282,21 +3283,22 @@
},
{
"id": "profile-untouched",
- "status": "pass"
+ "status": "skipped",
+ "detail": "no profile squad seeded in this shape"
}
],
"notes": [
- "plain upgrade changed 100 working-tree path(s), all Squad-owned: .copilot/skills/agent-collaboration/SKILL.md, .copilot/skills/cross-squad/SKILL.md, .copilot/skills/git-workflow/SKILL.md, .copilot/skills/reviewer-protocol/SKILL.md … (+96)",
- "old 0.9.1 upgrade --dry-run on upgraded project: exit 0, last lines \"\u001b[32m✓\u001b[0m refreshed .squad/templates/ | Upgrade complete: v1.2.0-preview.1 → v0.9.1 | \u001b[2mPreserves user state: team.md, decisions/, agents/*/history.md\u001b[0m\"; MODIFIED 44 files (20 coordinator/templates/workflows, e.g. .copilot/skills/agent-collaboration/SKILL.md, .copilot/skills/cross-squad/SKILL.md, .copilot/skills/git-workflow/SKILL.md …)",
+ "plain upgrade changed 230 working-tree path(s), all Squad-owned: .copilot/skills/agent-collaboration/SKILL.md, .copilot/skills/agent-conduct/SKILL.md, .copilot/skills/architectural-proposals/SKILL.md, .copilot/skills/ci-validation-gates/SKILL.md … (+226)",
+ "old 0.9.1 upgrade --dry-run on upgraded project: exit 0, last lines \"\u001b[32m✓\u001b[0m refreshed .squad/templates/ | Upgrade complete: v2.0.0-preview.4 → v0.9.1 | \u001b[2mPreserves user state: team.md, decisions/, agents/*/history.md\u001b[0m\"; MODIFIED 67 files (20 coordinator/templates/workflows, e.g. .copilot/skills/agent-collaboration/SKILL.md, .copilot/skills/agent-conduct/SKILL.md, .copilot/skills/architectural-proposals/SKILL.md …)",
"downgrade-probe: F3"
]
},
{
- "producer": "0.9.1",
+ "producer": "0.13.1",
"source": "npm",
"shape": "default",
"status": "pass",
- "provenance": "npm: @bradygaster/squad-cli@0.9.1 sha512-TcZqRbJk3XBg4N8Y5/5OWJeA52ARAMuzk4MGtB0bfdr87e7iJRV6lJEw8+OIYz9IQ+1JxN/Q30dZDALMOcdi2w==; @bradygaster/squad-sdk@0.9.1 sha512-1KqZ2N6Lt/B4uYlU/Su9JjA1s/7ng0OAEb9CZrkRk19YSPi6tg7K5QWdTKl5gY/gp8zPAJqfjVffOwrZwGlzmw==",
+ "provenance": "npm: @bradygaster/squad-cli@0.13.1 sha512-ogfx2nhyx6fqMyqlaI5tDnOzUbRdh+a6Uh/rMQ0aNJwAXnvQp4N37Xp/eOTyB5CxcB7E34NBtAfCxyXbWSiS8w==; @bradygaster/squad-sdk@0.13.1 sha512-1Jt6c9kahJq1JCcE77j/50D79YcXVG6Rt1genuLJ3O9J2SKTZKemlbvHgftkc5LgGH22DkWqHh5zLNEQ/p+ukA==",
"checks": [
{
"id": "producer-artifact-verified",
@@ -3341,8 +3343,7 @@
},
{
"id": "downgrade-probe",
- "status": "xfail",
- "detail": "dry-run MODIFIED 44 files (20 coordinator/templates/workflows, e.g. .copilot/skills/agent-collaboration/SKILL.md, .copilot/skills/cross-squad/SKILL.md, .copilot/skills/git-workflow/SKILL.md …)"
+ "status": "pass"
},
{
"id": "clients-projected",
@@ -3367,17 +3368,16 @@
}
],
"notes": [
- "plain upgrade changed 100 working-tree path(s), all Squad-owned: .copilot/skills/agent-collaboration/SKILL.md, .copilot/skills/cross-squad/SKILL.md, .copilot/skills/git-workflow/SKILL.md, .copilot/skills/reviewer-protocol/SKILL.md … (+96)",
- "old 0.9.1 upgrade --dry-run on upgraded project: exit 0, last lines \"\u001b[32m✓\u001b[0m refreshed .squad/templates/ | Upgrade complete: v1.2.0-preview.1 → v0.9.1 | \u001b[2mPreserves user state: team.md, decisions/, agents/*/history.md\u001b[0m\"; MODIFIED 44 files (20 coordinator/templates/workflows, e.g. .copilot/skills/agent-collaboration/SKILL.md, .copilot/skills/cross-squad/SKILL.md, .copilot/skills/git-workflow/SKILL.md …)",
- "downgrade-probe: F3"
+ "plain upgrade changed 150 working-tree path(s), all Squad-owned: .gitattributes, .github/agents/squad.agent.md, .github/agents/squad.agent.md.local-backup, .github/skills/coordinator-response-mode/SKILL.md … (+146)",
+ "old 0.13.1 upgrade --dry-run on upgraded project: exit 0, last lines \"overwrite ../.github/workflows/squad-triage.yml | overwrite ../.github/workflows/sync-squad-labels.yml | Run without --dry-run to apply.\"; modified nothing"
]
},
{
- "producer": "0.13.1",
+ "producer": "0.9.1",
"source": "npm",
"shape": "default",
"status": "pass",
- "provenance": "npm: @bradygaster/squad-cli@0.13.1 sha512-ogfx2nhyx6fqMyqlaI5tDnOzUbRdh+a6Uh/rMQ0aNJwAXnvQp4N37Xp/eOTyB5CxcB7E34NBtAfCxyXbWSiS8w==; @bradygaster/squad-sdk@0.13.1 sha512-1Jt6c9kahJq1JCcE77j/50D79YcXVG6Rt1genuLJ3O9J2SKTZKemlbvHgftkc5LgGH22DkWqHh5zLNEQ/p+ukA==",
+ "provenance": "npm: @bradygaster/squad-cli@0.9.1 sha512-TcZqRbJk3XBg4N8Y5/5OWJeA52ARAMuzk4MGtB0bfdr87e7iJRV6lJEw8+OIYz9IQ+1JxN/Q30dZDALMOcdi2w==; @bradygaster/squad-sdk@0.9.1 sha512-1KqZ2N6Lt/B4uYlU/Su9JjA1s/7ng0OAEb9CZrkRk19YSPi6tg7K5QWdTKl5gY/gp8zPAJqfjVffOwrZwGlzmw==",
"checks": [
{
"id": "producer-artifact-verified",
@@ -3422,7 +3422,8 @@
},
{
"id": "downgrade-probe",
- "status": "pass"
+ "status": "xfail",
+ "detail": "dry-run MODIFIED 67 files (20 coordinator/templates/workflows, e.g. .copilot/skills/agent-collaboration/SKILL.md, .copilot/skills/agent-conduct/SKILL.md, .copilot/skills/architectural-proposals/SKILL.md …)"
},
{
"id": "clients-projected",
@@ -3447,14 +3448,15 @@
}
],
"notes": [
- "plain upgrade changed 58 working-tree path(s), all Squad-owned: .github/agents/squad.agent.md, .github/agents/squad.agent.md.local-backup, .github/skills/coordinator-response-mode/SKILL.md, .github/skills/coordinator-source-of-truth/SKILL.md … (+54)",
- "old 0.13.1 upgrade --dry-run on upgraded project: exit 0, last lines \"overwrite ../.github/workflows/squad-triage.yml | overwrite ../.github/workflows/sync-squad-labels.yml | Run without --dry-run to apply.\"; modified nothing"
+ "plain upgrade changed 229 working-tree path(s), all Squad-owned: .copilot/skills/agent-collaboration/SKILL.md, .copilot/skills/agent-conduct/SKILL.md, .copilot/skills/architectural-proposals/SKILL.md, .copilot/skills/ci-validation-gates/SKILL.md … (+225)",
+ "old 0.9.1 upgrade --dry-run on upgraded project: exit 0, last lines \"\u001b[32m✓\u001b[0m refreshed .squad/templates/ | Upgrade complete: v2.0.0-preview.4 → v0.9.1 | \u001b[2mPreserves user state: team.md, decisions/, agents/*/history.md\u001b[0m\"; MODIFIED 67 files (20 coordinator/templates/workflows, e.g. .copilot/skills/agent-collaboration/SKILL.md, .copilot/skills/agent-conduct/SKILL.md, .copilot/skills/architectural-proposals/SKILL.md …)",
+ "downgrade-probe: F3"
]
},
{
"producer": "0.9.1",
"source": "npm",
- "shape": "ai-team",
+ "shape": "profile",
"status": "pass",
"provenance": "npm: @bradygaster/squad-cli@0.9.1 sha512-TcZqRbJk3XBg4N8Y5/5OWJeA52ARAMuzk4MGtB0bfdr87e7iJRV6lJEw8+OIYz9IQ+1JxN/Q30dZDALMOcdi2w==; @bradygaster/squad-sdk@0.9.1 sha512-1KqZ2N6Lt/B4uYlU/Su9JjA1s/7ng0OAEb9CZrkRk19YSPi6tg7K5QWdTKl5gY/gp8zPAJqfjVffOwrZwGlzmw==",
"checks": [
@@ -3488,7 +3490,8 @@
},
{
"id": "ai-team-migrated",
- "status": "pass"
+ "status": "skipped",
+ "detail": "not an .ai-team shape"
},
{
"id": "team-root-absent",
@@ -3501,7 +3504,7 @@
{
"id": "downgrade-probe",
"status": "xfail",
- "detail": "dry-run MODIFIED 44 files (20 coordinator/templates/workflows, e.g. .copilot/skills/agent-collaboration/SKILL.md, .copilot/skills/cross-squad/SKILL.md, .copilot/skills/git-workflow/SKILL.md …)"
+ "detail": "dry-run MODIFIED 67 files (20 coordinator/templates/workflows, e.g. .copilot/skills/agent-collaboration/SKILL.md, .copilot/skills/agent-conduct/SKILL.md, .copilot/skills/architectural-proposals/SKILL.md …)"
},
{
"id": "clients-projected",
@@ -3521,20 +3524,19 @@
},
{
"id": "profile-untouched",
- "status": "skipped",
- "detail": "no profile squad seeded in this shape"
+ "status": "pass"
}
],
"notes": [
- "plain upgrade changed 100 working-tree path(s), all Squad-owned: .copilot/skills/agent-collaboration/SKILL.md, .copilot/skills/cross-squad/SKILL.md, .copilot/skills/git-workflow/SKILL.md, .copilot/skills/reviewer-protocol/SKILL.md … (+96)",
- "old 0.9.1 upgrade --dry-run on upgraded project: exit 0, last lines \"\u001b[32m✓\u001b[0m refreshed .squad/templates/ | Upgrade complete: v1.2.0-preview.1 → v0.9.1 | \u001b[2mPreserves user state: team.md, decisions/, agents/*/history.md\u001b[0m\"; MODIFIED 44 files (20 coordinator/templates/workflows, e.g. .copilot/skills/agent-collaboration/SKILL.md, .copilot/skills/cross-squad/SKILL.md, .copilot/skills/git-workflow/SKILL.md …)",
+ "plain upgrade changed 229 working-tree path(s), all Squad-owned: .copilot/skills/agent-collaboration/SKILL.md, .copilot/skills/agent-conduct/SKILL.md, .copilot/skills/architectural-proposals/SKILL.md, .copilot/skills/ci-validation-gates/SKILL.md … (+225)",
+ "old 0.9.1 upgrade --dry-run on upgraded project: exit 0, last lines \"\u001b[32m✓\u001b[0m refreshed .squad/templates/ | Upgrade complete: v2.0.0-preview.4 → v0.9.1 | \u001b[2mPreserves user state: team.md, decisions/, agents/*/history.md\u001b[0m\"; MODIFIED 67 files (20 coordinator/templates/workflows, e.g. .copilot/skills/agent-collaboration/SKILL.md, .copilot/skills/agent-conduct/SKILL.md, .copilot/skills/architectural-proposals/SKILL.md …)",
"downgrade-probe: F3"
]
},
{
"producer": "0.9.1",
"source": "npm",
- "shape": "legacy-casting",
+ "shape": "ai-team",
"status": "pass",
"provenance": "npm: @bradygaster/squad-cli@0.9.1 sha512-TcZqRbJk3XBg4N8Y5/5OWJeA52ARAMuzk4MGtB0bfdr87e7iJRV6lJEw8+OIYz9IQ+1JxN/Q30dZDALMOcdi2w==; @bradygaster/squad-sdk@0.9.1 sha512-1KqZ2N6Lt/B4uYlU/Su9JjA1s/7ng0OAEb9CZrkRk19YSPi6tg7K5QWdTKl5gY/gp8zPAJqfjVffOwrZwGlzmw==",
"checks": [
@@ -3568,8 +3570,7 @@
},
{
"id": "ai-team-migrated",
- "status": "skipped",
- "detail": "not an .ai-team shape"
+ "status": "pass"
},
{
"id": "team-root-absent",
@@ -3582,7 +3583,7 @@
{
"id": "downgrade-probe",
"status": "xfail",
- "detail": "dry-run MODIFIED 44 files (20 coordinator/templates/workflows, e.g. .copilot/skills/agent-collaboration/SKILL.md, .copilot/skills/cross-squad/SKILL.md, .copilot/skills/git-workflow/SKILL.md …)"
+ "detail": "dry-run MODIFIED 67 files (20 coordinator/templates/workflows, e.g. .copilot/skills/agent-collaboration/SKILL.md, .copilot/skills/agent-conduct/SKILL.md, .copilot/skills/architectural-proposals/SKILL.md …)"
},
{
"id": "clients-projected",
@@ -3607,8 +3608,8 @@
}
],
"notes": [
- "plain upgrade changed 101 working-tree path(s), all Squad-owned: .copilot/skills/agent-collaboration/SKILL.md, .copilot/skills/cross-squad/SKILL.md, .copilot/skills/git-workflow/SKILL.md, .copilot/skills/reviewer-protocol/SKILL.md … (+97)",
- "old 0.9.1 upgrade --dry-run on upgraded project: exit 0, last lines \"\u001b[32m✓\u001b[0m refreshed .squad/templates/ | Upgrade complete: v1.2.0-preview.1 → v0.9.1 | \u001b[2mPreserves user state: team.md, decisions/, agents/*/history.md\u001b[0m\"; MODIFIED 44 files (20 coordinator/templates/workflows, e.g. .copilot/skills/agent-collaboration/SKILL.md, .copilot/skills/cross-squad/SKILL.md, .copilot/skills/git-workflow/SKILL.md …)",
+ "plain upgrade changed 229 working-tree path(s), all Squad-owned: .copilot/skills/agent-collaboration/SKILL.md, .copilot/skills/agent-conduct/SKILL.md, .copilot/skills/architectural-proposals/SKILL.md, .copilot/skills/ci-validation-gates/SKILL.md … (+225)",
+ "old 0.9.1 upgrade --dry-run on upgraded project: exit 0, last lines \"\u001b[32m✓\u001b[0m refreshed .squad/templates/ | Upgrade complete: v2.0.0-preview.4 → v0.9.1 | \u001b[2mPreserves user state: team.md, decisions/, agents/*/history.md\u001b[0m\"; MODIFIED 67 files (20 coordinator/templates/workflows, e.g. .copilot/skills/agent-collaboration/SKILL.md, .copilot/skills/agent-conduct/SKILL.md, .copilot/skills/architectural-proposals/SKILL.md …)",
"downgrade-probe: F3"
]
},
@@ -3687,7 +3688,7 @@
],
"notes": [
"producer wrote teamRoot=\\squad at init",
- "plain upgrade changed 59 working-tree path(s), all Squad-owned: .github/agents/squad.agent.md, .github/agents/squad.agent.md.local-backup, .github/skills/coordinator-response-mode/SKILL.md, .github/skills/coordinator-source-of-truth/SKILL.md … (+55)",
+ "plain upgrade changed 151 working-tree path(s), all Squad-owned: .gitattributes, .github/agents/squad.agent.md, .github/agents/squad.agent.md.local-backup, .github/skills/coordinator-response-mode/SKILL.md … (+147)",
"old 0.13.1 upgrade --dry-run on upgraded project: exit 0, last lines \"overwrite ../.github/workflows/squad-triage.yml | overwrite ../.github/workflows/sync-squad-labels.yml | Run without --dry-run to apply.\"; modified nothing"
]
},
@@ -3776,7 +3777,7 @@
}
],
"notes": [
- "plain upgrade changed 58 working-tree path(s), all Squad-owned: .github/agents/squad.agent.md, .github/agents/squad.agent.md.local-backup, .github/skills/coordinator-response-mode/SKILL.md, .github/skills/coordinator-source-of-truth/SKILL.md … (+54)",
+ "plain upgrade changed 150 working-tree path(s), all Squad-owned: .gitattributes, .github/agents/squad.agent.md, .github/agents/squad.agent.md.local-backup, .github/skills/coordinator-response-mode/SKILL.md … (+146)",
"old 0.13.1 upgrade --dry-run on upgraded project: exit 0, last lines \"overwrite ../.github/workflows/squad-triage.yml | overwrite ../.github/workflows/sync-squad-labels.yml | Run without --dry-run to apply.\"; modified nothing"
]
},
@@ -3854,7 +3855,7 @@
}
],
"notes": [
- "plain upgrade changed 58 working-tree path(s), all Squad-owned: .github/agents/squad.agent.md, .github/agents/squad.agent.md.local-backup, .github/skills/coordinator-response-mode/SKILL.md, .github/skills/coordinator-source-of-truth/SKILL.md … (+54)",
+ "plain upgrade changed 150 working-tree path(s), all Squad-owned: .gitattributes, .github/agents/squad.agent.md, .github/agents/squad.agent.md.local-backup, .github/skills/coordinator-response-mode/SKILL.md … (+146)",
"old 0.13.1 upgrade --dry-run on upgraded project: exit 0, last lines \"overwrite ../.github/workflows/squad-triage.yml | overwrite ../.github/workflows/sync-squad-labels.yml | Run without --dry-run to apply.\"; modified nothing"
]
},
@@ -3933,7 +3934,7 @@
}
],
"notes": [
- "plain upgrade changed 56 working-tree path(s), all Squad-owned: .github/agents/squad.agent.md, .github/agents/squad.agent.md.local-backup, .github/skills/coordinator-response-mode/SKILL.md, .github/skills/coordinator-source-of-truth/SKILL.md … (+52); squad-state blobs for 3 seeded path(s) identical",
+ "plain upgrade changed 148 working-tree path(s), all Squad-owned: .gitattributes, .github/agents/squad.agent.md, .github/agents/squad.agent.md.local-backup, .github/skills/coordinator-response-mode/SKILL.md … (+144); squad-state blobs for 3 seeded path(s) identical",
"old 0.13.1 upgrade --dry-run on upgraded project: exit 0, last lines \"overwrite ../.github/workflows/squad-triage.yml | overwrite ../.github/workflows/sync-squad-labels.yml | Run without --dry-run to apply.\"; modified nothing"
]
},
@@ -4012,7 +4013,7 @@
}
],
"notes": [
- "plain upgrade changed 56 working-tree path(s), all Squad-owned: .github/agents/squad.agent.md, .github/agents/squad.agent.md.local-backup, .github/skills/coordinator-response-mode/SKILL.md, .github/skills/coordinator-source-of-truth/SKILL.md … (+52); squad-state blobs for 3 seeded path(s) identical",
+ "plain upgrade changed 148 working-tree path(s), all Squad-owned: .gitattributes, .github/agents/squad.agent.md, .github/agents/squad.agent.md.local-backup, .github/skills/coordinator-response-mode/SKILL.md … (+144); squad-state blobs for 3 seeded path(s) identical",
"old 0.13.1 upgrade --dry-run on upgraded project: exit 0, last lines \"overwrite ../.github/workflows/squad-triage.yml | overwrite ../.github/workflows/sync-squad-labels.yml | Run without --dry-run to apply.\"; modified nothing"
]
},
@@ -4091,7 +4092,7 @@
}
],
"notes": [
- "plain upgrade changed 38 working-tree path(s), all Squad-owned: .github/agents/squad.agent.md, .github/agents/squad.agent.md.local-backup, .github/skills/coordinator-source-of-truth/SKILL.md, .github/workflows/squad-ci.yml … (+34)",
+ "plain upgrade changed 85 working-tree path(s), all Squad-owned: .gitattributes, .github/agents/squad.agent.md, .github/agents/squad.agent.md.local-backup, .github/skills/coordinator-response-mode/SKILL.md … (+81)",
"old 1.0.0 upgrade --dry-run on upgraded project: exit 0, last lines \"overwrite ../.github/workflows/squad-triage.yml | overwrite ../.github/workflows/sync-squad-labels.yml | Run without --dry-run to apply.\"; modified nothing"
]
},
@@ -4170,7 +4171,7 @@
],
"notes": [
"producer wrote teamRoot=\\squad at init",
- "plain upgrade changed 39 working-tree path(s), all Squad-owned: .github/agents/squad.agent.md, .github/agents/squad.agent.md.local-backup, .github/skills/coordinator-source-of-truth/SKILL.md, .github/workflows/squad-ci.yml … (+35)",
+ "plain upgrade changed 86 working-tree path(s), all Squad-owned: .gitattributes, .github/agents/squad.agent.md, .github/agents/squad.agent.md.local-backup, .github/skills/coordinator-response-mode/SKILL.md … (+82)",
"old 1.0.0 upgrade --dry-run on upgraded project: exit 0, last lines \"overwrite ../.github/workflows/squad-triage.yml | overwrite ../.github/workflows/sync-squad-labels.yml | Run without --dry-run to apply.\"; modified nothing"
]
},
@@ -4259,14 +4260,14 @@
}
],
"notes": [
- "plain upgrade changed 43 working-tree path(s), all Squad-owned: .github/agents/squad.agent.md, .github/agents/squad.agent.md.local-backup, .github/skills/coordinator-source-of-truth/SKILL.md, .github/workflows/squad-ci.yml … (+39)",
+ "plain upgrade changed 90 working-tree path(s), all Squad-owned: .gitattributes, .github/agents/squad.agent.md, .github/agents/squad.agent.md.local-backup, .github/skills/coordinator-response-mode/SKILL.md … (+86)",
"old 1.0.0 upgrade --dry-run on upgraded project: exit 0, last lines \"overwrite ../.github/workflows/squad-triage.yml | overwrite ../.github/workflows/sync-squad-labels.yml | Run without --dry-run to apply.\"; modified nothing"
]
},
{
"producer": "1.0.0",
"source": "npm",
- "shape": "ai-team",
+ "shape": "orphan",
"status": "pass",
"provenance": "npm: @bradygaster/squad-cli@1.0.0 sha512-mnZXnA+GAtp4KSLf7a4Zw0BpeOaHFAxYV5oxAy58ancZ9C2LguUGbcTxWIG0djM96XWET8K9fcncif3Vm6Z9RQ==; @bradygaster/squad-sdk@1.0.0 sha512-9f4NthJaQDq6ifXU3f6VfsZz2bbWs2u57fHhXKtDgDMSvZ3Xq8FPjMvddxhRvseWqaSlkYcWsag3M/lzTtKaJA==",
"checks": [
@@ -4300,7 +4301,8 @@
},
{
"id": "ai-team-migrated",
- "status": "pass"
+ "status": "skipped",
+ "detail": "not an .ai-team shape"
},
{
"id": "team-root-absent",
@@ -4337,16 +4339,16 @@
}
],
"notes": [
- "plain upgrade changed 38 working-tree path(s), all Squad-owned: .github/agents/squad.agent.md, .github/agents/squad.agent.md.local-backup, .github/skills/coordinator-source-of-truth/SKILL.md, .github/workflows/squad-ci.yml … (+34)",
+ "plain upgrade changed 83 working-tree path(s), all Squad-owned: .gitattributes, .github/agents/squad.agent.md, .github/agents/squad.agent.md.local-backup, .github/skills/coordinator-response-mode/SKILL.md … (+79); squad-state blobs for 3 seeded path(s) identical",
"old 1.0.0 upgrade --dry-run on upgraded project: exit 0, last lines \"overwrite ../.github/workflows/squad-triage.yml | overwrite ../.github/workflows/sync-squad-labels.yml | Run without --dry-run to apply.\"; modified nothing"
]
},
{
- "producer": "1.0.1",
- "source": "github-release",
- "shape": "default",
+ "producer": "1.0.0",
+ "source": "npm",
+ "shape": "ai-team",
"status": "pass",
- "provenance": "github-release: bradygaster/squad@v1.0.1 asset squad-win32-x64.zip id 610330559 sha256 f38a8f85e60982dba340187b761488f01de1aec68ea50c1b85725783d32df2fe (bundled node 22.20.0)",
+ "provenance": "npm: @bradygaster/squad-cli@1.0.0 sha512-mnZXnA+GAtp4KSLf7a4Zw0BpeOaHFAxYV5oxAy58ancZ9C2LguUGbcTxWIG0djM96XWET8K9fcncif3Vm6Z9RQ==; @bradygaster/squad-sdk@1.0.0 sha512-9f4NthJaQDq6ifXU3f6VfsZz2bbWs2u57fHhXKtDgDMSvZ3Xq8FPjMvddxhRvseWqaSlkYcWsag3M/lzTtKaJA==",
"checks": [
{
"id": "producer-artifact-verified",
@@ -4378,8 +4380,7 @@
},
{
"id": "ai-team-migrated",
- "status": "skipped",
- "detail": "not an .ai-team shape"
+ "status": "pass"
},
{
"id": "team-root-absent",
@@ -4416,16 +4417,16 @@
}
],
"notes": [
- "plain upgrade changed 38 working-tree path(s), all Squad-owned: .github/agents/squad.agent.md, .github/agents/squad.agent.md.local-backup, .github/skills/coordinator-source-of-truth/SKILL.md, .github/workflows/squad-ci.yml … (+34)",
- "old 1.0.1 upgrade --dry-run on upgraded project: exit 0, last lines \"overwrite ../.github/workflows/squad-triage.yml | overwrite ../.github/workflows/sync-squad-labels.yml | Run without --dry-run to apply.\"; modified nothing"
+ "plain upgrade changed 85 working-tree path(s), all Squad-owned: .gitattributes, .github/agents/squad.agent.md, .github/agents/squad.agent.md.local-backup, .github/skills/coordinator-response-mode/SKILL.md … (+81)",
+ "old 1.0.0 upgrade --dry-run on upgraded project: exit 0, last lines \"overwrite ../.github/workflows/squad-triage.yml | overwrite ../.github/workflows/sync-squad-labels.yml | Run without --dry-run to apply.\"; modified nothing"
]
},
{
- "producer": "1.0.0",
- "source": "npm",
- "shape": "orphan",
+ "producer": "1.0.1",
+ "source": "github-release",
+ "shape": "default",
"status": "pass",
- "provenance": "npm: @bradygaster/squad-cli@1.0.0 sha512-mnZXnA+GAtp4KSLf7a4Zw0BpeOaHFAxYV5oxAy58ancZ9C2LguUGbcTxWIG0djM96XWET8K9fcncif3Vm6Z9RQ==; @bradygaster/squad-sdk@1.0.0 sha512-9f4NthJaQDq6ifXU3f6VfsZz2bbWs2u57fHhXKtDgDMSvZ3Xq8FPjMvddxhRvseWqaSlkYcWsag3M/lzTtKaJA==",
+ "provenance": "github-release: github/squad@v1.0.1 asset squad-win32-x64.zip id 610330559 sha256 f38a8f85e60982dba340187b761488f01de1aec68ea50c1b85725783d32df2fe (bundled node 22.20.0)",
"checks": [
{
"id": "producer-artifact-verified",
@@ -4495,8 +4496,8 @@
}
],
"notes": [
- "plain upgrade changed 36 working-tree path(s), all Squad-owned: .github/agents/squad.agent.md, .github/agents/squad.agent.md.local-backup, .github/skills/coordinator-source-of-truth/SKILL.md, .github/workflows/squad-ci.yml … (+32); squad-state blobs for 3 seeded path(s) identical",
- "old 1.0.0 upgrade --dry-run on upgraded project: exit 0, last lines \"overwrite ../.github/workflows/squad-triage.yml | overwrite ../.github/workflows/sync-squad-labels.yml | Run without --dry-run to apply.\"; modified nothing"
+ "plain upgrade changed 85 working-tree path(s), all Squad-owned: .gitattributes, .github/agents/squad.agent.md, .github/agents/squad.agent.md.local-backup, .github/skills/coordinator-response-mode/SKILL.md … (+81)",
+ "old 1.0.1 upgrade --dry-run on upgraded project: exit 0, last lines \"overwrite ../.github/workflows/squad-triage.yml | overwrite ../.github/workflows/sync-squad-labels.yml | Run without --dry-run to apply.\"; modified nothing"
]
},
{
@@ -4574,7 +4575,7 @@
}
],
"notes": [
- "plain upgrade changed 36 working-tree path(s), all Squad-owned: .github/agents/squad.agent.md, .github/agents/squad.agent.md.local-backup, .github/skills/coordinator-source-of-truth/SKILL.md, .github/workflows/squad-ci.yml … (+32); squad-state blobs for 3 seeded path(s) identical",
+ "plain upgrade changed 83 working-tree path(s), all Squad-owned: .gitattributes, .github/agents/squad.agent.md, .github/agents/squad.agent.md.local-backup, .github/skills/coordinator-response-mode/SKILL.md … (+79); squad-state blobs for 3 seeded path(s) identical",
"old 1.0.0 upgrade --dry-run on upgraded project: exit 0, last lines \"overwrite ../.github/workflows/squad-triage.yml | overwrite ../.github/workflows/sync-squad-labels.yml | Run without --dry-run to apply.\"; modified nothing"
]
},
@@ -4583,7 +4584,7 @@
"source": "github-release",
"shape": "profile",
"status": "pass",
- "provenance": "github-release: bradygaster/squad@v1.0.1 asset squad-win32-x64.zip id 610330559 sha256 f38a8f85e60982dba340187b761488f01de1aec68ea50c1b85725783d32df2fe (bundled node 22.20.0)",
+ "provenance": "github-release: github/squad@v1.0.1 asset squad-win32-x64.zip id 610330559 sha256 f38a8f85e60982dba340187b761488f01de1aec68ea50c1b85725783d32df2fe (bundled node 22.20.0)",
"checks": [
{
"id": "producer-artifact-verified",
@@ -4653,7 +4654,7 @@
],
"notes": [
"producer wrote teamRoot=\\squad at init",
- "plain upgrade changed 39 working-tree path(s), all Squad-owned: .github/agents/squad.agent.md, .github/agents/squad.agent.md.local-backup, .github/skills/coordinator-source-of-truth/SKILL.md, .github/workflows/squad-ci.yml … (+35)",
+ "plain upgrade changed 86 working-tree path(s), all Squad-owned: .gitattributes, .github/agents/squad.agent.md, .github/agents/squad.agent.md.local-backup, .github/skills/coordinator-response-mode/SKILL.md … (+82)",
"old 1.0.1 upgrade --dry-run on upgraded project: exit 0, last lines \"overwrite ../.github/workflows/squad-triage.yml | overwrite ../.github/workflows/sync-squad-labels.yml | Run without --dry-run to apply.\"; modified nothing"
]
},
@@ -4663,7 +4664,7 @@
"shape": "upstream",
"status": "skipped",
"reason": "Upstream inheritance (`.squad/upstream.json`, `squad upstream add`) is a Squad 2.0 feature; 1.0.1 cannot declare an upstream, so there is nothing for the upgrade to preserve.",
- "provenance": "github-release: bradygaster/squad@v1.0.1 asset squad-win32-x64.zip id 610330559 sha256 f38a8f85e60982dba340187b761488f01de1aec68ea50c1b85725783d32df2fe (bundled node 22.20.0)",
+ "provenance": "github-release: github/squad@v1.0.1 asset squad-win32-x64.zip id 610330559 sha256 f38a8f85e60982dba340187b761488f01de1aec68ea50c1b85725783d32df2fe (bundled node 22.20.0)",
"checks": [],
"notes": []
},
@@ -4672,7 +4673,7 @@
"source": "github-release",
"shape": "legacy-casting",
"status": "pass",
- "provenance": "github-release: bradygaster/squad@v1.0.1 asset squad-win32-x64.zip id 610330559 sha256 f38a8f85e60982dba340187b761488f01de1aec68ea50c1b85725783d32df2fe (bundled node 22.20.0)",
+ "provenance": "github-release: github/squad@v1.0.1 asset squad-win32-x64.zip id 610330559 sha256 f38a8f85e60982dba340187b761488f01de1aec68ea50c1b85725783d32df2fe (bundled node 22.20.0)",
"checks": [
{
"id": "producer-artifact-verified",
@@ -4742,7 +4743,7 @@
}
],
"notes": [
- "plain upgrade changed 43 working-tree path(s), all Squad-owned: .github/agents/squad.agent.md, .github/agents/squad.agent.md.local-backup, .github/skills/coordinator-source-of-truth/SKILL.md, .github/workflows/squad-ci.yml … (+39)",
+ "plain upgrade changed 90 working-tree path(s), all Squad-owned: .gitattributes, .github/agents/squad.agent.md, .github/agents/squad.agent.md.local-backup, .github/skills/coordinator-response-mode/SKILL.md … (+86)",
"old 1.0.1 upgrade --dry-run on upgraded project: exit 0, last lines \"overwrite ../.github/workflows/squad-triage.yml | overwrite ../.github/workflows/sync-squad-labels.yml | Run without --dry-run to apply.\"; modified nothing"
]
},
@@ -4751,7 +4752,7 @@
"source": "github-release",
"shape": "ai-team",
"status": "pass",
- "provenance": "github-release: bradygaster/squad@v1.0.1 asset squad-win32-x64.zip id 610330559 sha256 f38a8f85e60982dba340187b761488f01de1aec68ea50c1b85725783d32df2fe (bundled node 22.20.0)",
+ "provenance": "github-release: github/squad@v1.0.1 asset squad-win32-x64.zip id 610330559 sha256 f38a8f85e60982dba340187b761488f01de1aec68ea50c1b85725783d32df2fe (bundled node 22.20.0)",
"checks": [
{
"id": "producer-artifact-verified",
@@ -4820,7 +4821,7 @@
}
],
"notes": [
- "plain upgrade changed 38 working-tree path(s), all Squad-owned: .github/agents/squad.agent.md, .github/agents/squad.agent.md.local-backup, .github/skills/coordinator-source-of-truth/SKILL.md, .github/workflows/squad-ci.yml … (+34)",
+ "plain upgrade changed 85 working-tree path(s), all Squad-owned: .gitattributes, .github/agents/squad.agent.md, .github/agents/squad.agent.md.local-backup, .github/skills/coordinator-response-mode/SKILL.md … (+81)",
"old 1.0.1 upgrade --dry-run on upgraded project: exit 0, last lines \"overwrite ../.github/workflows/squad-triage.yml | overwrite ../.github/workflows/sync-squad-labels.yml | Run without --dry-run to apply.\"; modified nothing"
]
},
@@ -4829,7 +4830,7 @@
"source": "github-release",
"shape": "default",
"status": "pass",
- "provenance": "github-release: bradygaster/squad@v1.1.0 asset squad-win32-x64.zip id 659607643 sha256 571d734f7ae718fefefdfa9864f9f82a3d1fb1546f01ec8bf8866fa7e1829c57 (bundled node 22.20.0)",
+ "provenance": "github-release: github/squad@v1.1.0 asset squad-win32-x64.zip id 659607643 sha256 571d734f7ae718fefefdfa9864f9f82a3d1fb1546f01ec8bf8866fa7e1829c57 (bundled node 22.20.0)",
"checks": [
{
"id": "producer-artifact-verified",
@@ -4899,7 +4900,7 @@
}
],
"notes": [
- "plain upgrade changed 31 working-tree path(s), all Squad-owned: .github/agents/squad.agent.md, .github/agents/squad.agent.md.local-backup, .github/workflows/squad-ci.yml, .github/workflows/squad-ci.yml.local-backup … (+27)",
+ "plain upgrade changed 58 working-tree path(s), all Squad-owned: .gitattributes, .github/agents/squad.agent.md, .github/agents/squad.agent.md.local-backup, .github/skills/coordinator-response-mode/SKILL.md … (+54)",
"old 1.1.0 upgrade --dry-run on upgraded project: exit 0, last lines \"overwrite ../.github/workflows/squad-triage.yml | overwrite ../.github/workflows/sync-squad-labels.yml | Run without --dry-run to apply.\"; modified nothing"
]
},
@@ -4908,7 +4909,7 @@
"source": "github-release",
"shape": "orphan",
"status": "pass",
- "provenance": "github-release: bradygaster/squad@v1.0.1 asset squad-win32-x64.zip id 610330559 sha256 f38a8f85e60982dba340187b761488f01de1aec68ea50c1b85725783d32df2fe (bundled node 22.20.0)",
+ "provenance": "github-release: github/squad@v1.0.1 asset squad-win32-x64.zip id 610330559 sha256 f38a8f85e60982dba340187b761488f01de1aec68ea50c1b85725783d32df2fe (bundled node 22.20.0)",
"checks": [
{
"id": "producer-artifact-verified",
@@ -4978,7 +4979,7 @@
}
],
"notes": [
- "plain upgrade changed 36 working-tree path(s), all Squad-owned: .github/agents/squad.agent.md, .github/agents/squad.agent.md.local-backup, .github/skills/coordinator-source-of-truth/SKILL.md, .github/workflows/squad-ci.yml … (+32); squad-state blobs for 3 seeded path(s) identical",
+ "plain upgrade changed 83 working-tree path(s), all Squad-owned: .gitattributes, .github/agents/squad.agent.md, .github/agents/squad.agent.md.local-backup, .github/skills/coordinator-response-mode/SKILL.md … (+79); squad-state blobs for 3 seeded path(s) identical",
"old 1.0.1 upgrade --dry-run on upgraded project: exit 0, last lines \"overwrite ../.github/workflows/squad-triage.yml | overwrite ../.github/workflows/sync-squad-labels.yml | Run without --dry-run to apply.\"; modified nothing"
]
},
@@ -4987,7 +4988,7 @@
"source": "github-release",
"shape": "two-layer",
"status": "pass",
- "provenance": "github-release: bradygaster/squad@v1.0.1 asset squad-win32-x64.zip id 610330559 sha256 f38a8f85e60982dba340187b761488f01de1aec68ea50c1b85725783d32df2fe (bundled node 22.20.0)",
+ "provenance": "github-release: github/squad@v1.0.1 asset squad-win32-x64.zip id 610330559 sha256 f38a8f85e60982dba340187b761488f01de1aec68ea50c1b85725783d32df2fe (bundled node 22.20.0)",
"checks": [
{
"id": "producer-artifact-verified",
@@ -5057,7 +5058,7 @@
}
],
"notes": [
- "plain upgrade changed 36 working-tree path(s), all Squad-owned: .github/agents/squad.agent.md, .github/agents/squad.agent.md.local-backup, .github/skills/coordinator-source-of-truth/SKILL.md, .github/workflows/squad-ci.yml … (+32); squad-state blobs for 3 seeded path(s) identical",
+ "plain upgrade changed 83 working-tree path(s), all Squad-owned: .gitattributes, .github/agents/squad.agent.md, .github/agents/squad.agent.md.local-backup, .github/skills/coordinator-response-mode/SKILL.md … (+79); squad-state blobs for 3 seeded path(s) identical",
"old 1.0.1 upgrade --dry-run on upgraded project: exit 0, last lines \"overwrite ../.github/workflows/squad-triage.yml | overwrite ../.github/workflows/sync-squad-labels.yml | Run without --dry-run to apply.\"; modified nothing"
]
},
@@ -5066,7 +5067,7 @@
"source": "github-release",
"shape": "profile",
"status": "pass",
- "provenance": "github-release: bradygaster/squad@v1.1.0 asset squad-win32-x64.zip id 659607643 sha256 571d734f7ae718fefefdfa9864f9f82a3d1fb1546f01ec8bf8866fa7e1829c57 (bundled node 22.20.0)",
+ "provenance": "github-release: github/squad@v1.1.0 asset squad-win32-x64.zip id 659607643 sha256 571d734f7ae718fefefdfa9864f9f82a3d1fb1546f01ec8bf8866fa7e1829c57 (bundled node 22.20.0)",
"checks": [
{
"id": "producer-artifact-verified",
@@ -5136,7 +5137,7 @@
],
"notes": [
"producer wrote teamRoot=\\squad at init",
- "plain upgrade changed 32 working-tree path(s), all Squad-owned: .github/agents/squad.agent.md, .github/agents/squad.agent.md.local-backup, .github/workflows/squad-ci.yml, .github/workflows/squad-ci.yml.local-backup … (+28)",
+ "plain upgrade changed 59 working-tree path(s), all Squad-owned: .gitattributes, .github/agents/squad.agent.md, .github/agents/squad.agent.md.local-backup, .github/skills/coordinator-response-mode/SKILL.md … (+55)",
"old 1.1.0 upgrade --dry-run on upgraded project: exit 0, last lines \"overwrite ../.github/workflows/squad-triage.yml | overwrite ../.github/workflows/sync-squad-labels.yml | Run without --dry-run to apply.\"; modified nothing"
]
},
@@ -5146,7 +5147,7 @@
"shape": "upstream",
"status": "skipped",
"reason": "Upstream inheritance (`.squad/upstream.json`, `squad upstream add`) is a Squad 2.0 feature; 1.1.0 cannot declare an upstream, so there is nothing for the upgrade to preserve.",
- "provenance": "github-release: bradygaster/squad@v1.1.0 asset squad-win32-x64.zip id 659607643 sha256 571d734f7ae718fefefdfa9864f9f82a3d1fb1546f01ec8bf8866fa7e1829c57 (bundled node 22.20.0)",
+ "provenance": "github-release: github/squad@v1.1.0 asset squad-win32-x64.zip id 659607643 sha256 571d734f7ae718fefefdfa9864f9f82a3d1fb1546f01ec8bf8866fa7e1829c57 (bundled node 22.20.0)",
"checks": [],
"notes": []
},
@@ -5155,7 +5156,7 @@
"source": "github-release",
"shape": "legacy-casting",
"status": "pass",
- "provenance": "github-release: bradygaster/squad@v1.1.0 asset squad-win32-x64.zip id 659607643 sha256 571d734f7ae718fefefdfa9864f9f82a3d1fb1546f01ec8bf8866fa7e1829c57 (bundled node 22.20.0)",
+ "provenance": "github-release: github/squad@v1.1.0 asset squad-win32-x64.zip id 659607643 sha256 571d734f7ae718fefefdfa9864f9f82a3d1fb1546f01ec8bf8866fa7e1829c57 (bundled node 22.20.0)",
"checks": [
{
"id": "producer-artifact-verified",
@@ -5225,7 +5226,7 @@
}
],
"notes": [
- "plain upgrade changed 36 working-tree path(s), all Squad-owned: .github/agents/squad.agent.md, .github/agents/squad.agent.md.local-backup, .github/workflows/squad-ci.yml, .github/workflows/squad-ci.yml.local-backup … (+32)",
+ "plain upgrade changed 63 working-tree path(s), all Squad-owned: .gitattributes, .github/agents/squad.agent.md, .github/agents/squad.agent.md.local-backup, .github/skills/coordinator-response-mode/SKILL.md … (+59)",
"old 1.1.0 upgrade --dry-run on upgraded project: exit 0, last lines \"overwrite ../.github/workflows/squad-triage.yml | overwrite ../.github/workflows/sync-squad-labels.yml | Run without --dry-run to apply.\"; modified nothing"
]
},
@@ -5234,7 +5235,7 @@
"source": "github-release",
"shape": "ai-team",
"status": "pass",
- "provenance": "github-release: bradygaster/squad@v1.1.0 asset squad-win32-x64.zip id 659607643 sha256 571d734f7ae718fefefdfa9864f9f82a3d1fb1546f01ec8bf8866fa7e1829c57 (bundled node 22.20.0)",
+ "provenance": "github-release: github/squad@v1.1.0 asset squad-win32-x64.zip id 659607643 sha256 571d734f7ae718fefefdfa9864f9f82a3d1fb1546f01ec8bf8866fa7e1829c57 (bundled node 22.20.0)",
"checks": [
{
"id": "producer-artifact-verified",
@@ -5303,7 +5304,7 @@
}
],
"notes": [
- "plain upgrade changed 31 working-tree path(s), all Squad-owned: .github/agents/squad.agent.md, .github/agents/squad.agent.md.local-backup, .github/workflows/squad-ci.yml, .github/workflows/squad-ci.yml.local-backup … (+27)",
+ "plain upgrade changed 58 working-tree path(s), all Squad-owned: .gitattributes, .github/agents/squad.agent.md, .github/agents/squad.agent.md.local-backup, .github/skills/coordinator-response-mode/SKILL.md … (+54)",
"old 1.1.0 upgrade --dry-run on upgraded project: exit 0, last lines \"overwrite ../.github/workflows/squad-triage.yml | overwrite ../.github/workflows/sync-squad-labels.yml | Run without --dry-run to apply.\"; modified nothing"
]
},
@@ -5312,7 +5313,7 @@
"source": "github-release",
"shape": "orphan",
"status": "pass",
- "provenance": "github-release: bradygaster/squad@v1.1.0 asset squad-win32-x64.zip id 659607643 sha256 571d734f7ae718fefefdfa9864f9f82a3d1fb1546f01ec8bf8866fa7e1829c57 (bundled node 22.20.0)",
+ "provenance": "github-release: github/squad@v1.1.0 asset squad-win32-x64.zip id 659607643 sha256 571d734f7ae718fefefdfa9864f9f82a3d1fb1546f01ec8bf8866fa7e1829c57 (bundled node 22.20.0)",
"checks": [
{
"id": "producer-artifact-verified",
@@ -5382,16 +5383,16 @@
}
],
"notes": [
- "plain upgrade changed 29 working-tree path(s), all Squad-owned: .github/agents/squad.agent.md, .github/agents/squad.agent.md.local-backup, .github/workflows/squad-ci.yml, .github/workflows/squad-ci.yml.local-backup … (+25); squad-state blobs for 3 seeded path(s) identical",
+ "plain upgrade changed 56 working-tree path(s), all Squad-owned: .gitattributes, .github/agents/squad.agent.md, .github/agents/squad.agent.md.local-backup, .github/skills/coordinator-response-mode/SKILL.md … (+52); squad-state blobs for 3 seeded path(s) identical",
"old 1.1.0 upgrade --dry-run on upgraded project: exit 0, last lines \"overwrite ../.github/workflows/squad-triage.yml | overwrite ../.github/workflows/sync-squad-labels.yml | Run without --dry-run to apply.\"; modified nothing"
]
},
{
- "producer": "HEAD",
- "source": "pack",
- "shape": "default",
+ "producer": "1.1.0",
+ "source": "github-release",
+ "shape": "two-layer",
"status": "pass",
- "provenance": "pack: npm pack of packages/squad-sdk + packages/squad-cli at 9da01a2e41ba15794d31b0b8251ddaa3abd34ba8 (v1.2.0-preview.1)",
+ "provenance": "github-release: github/squad@v1.1.0 asset squad-win32-x64.zip id 659607643 sha256 571d734f7ae718fefefdfa9864f9f82a3d1fb1546f01ec8bf8866fa7e1829c57 (bundled node 22.20.0)",
"checks": [
{
"id": "producer-artifact-verified",
@@ -5436,8 +5437,7 @@
},
{
"id": "downgrade-probe",
- "status": "skipped",
- "detail": "producer is the target version"
+ "status": "pass"
},
{
"id": "clients-projected",
@@ -5462,15 +5462,16 @@
}
],
"notes": [
- "plain upgrade changed 17 working-tree path(s), all Squad-owned: .github/workflows/squad-ci.yml, .github/workflows/squad-docs.yml, .github/workflows/squad-heartbeat.yml, .github/workflows/squad-insider-release.yml … (+13)"
+ "plain upgrade changed 56 working-tree path(s), all Squad-owned: .gitattributes, .github/agents/squad.agent.md, .github/agents/squad.agent.md.local-backup, .github/skills/coordinator-response-mode/SKILL.md … (+52); squad-state blobs for 3 seeded path(s) identical",
+ "old 1.1.0 upgrade --dry-run on upgraded project: exit 0, last lines \"overwrite ../.github/workflows/squad-triage.yml | overwrite ../.github/workflows/sync-squad-labels.yml | Run without --dry-run to apply.\"; modified nothing"
]
},
{
- "producer": "1.1.0",
- "source": "github-release",
- "shape": "two-layer",
+ "producer": "HEAD",
+ "source": "pack",
+ "shape": "default",
"status": "pass",
- "provenance": "github-release: bradygaster/squad@v1.1.0 asset squad-win32-x64.zip id 659607643 sha256 571d734f7ae718fefefdfa9864f9f82a3d1fb1546f01ec8bf8866fa7e1829c57 (bundled node 22.20.0)",
+ "provenance": "pack: npm pack of packages/squad-sdk + packages/squad-cli at 9b254ba858abc19ef62e513993d9802312bfe34c (v2.0.0-preview.4)",
"checks": [
{
"id": "producer-artifact-verified",
@@ -5515,7 +5516,8 @@
},
{
"id": "downgrade-probe",
- "status": "pass"
+ "status": "skipped",
+ "detail": "producer is the target version"
},
{
"id": "clients-projected",
@@ -5540,8 +5542,7 @@
}
],
"notes": [
- "plain upgrade changed 29 working-tree path(s), all Squad-owned: .github/agents/squad.agent.md, .github/agents/squad.agent.md.local-backup, .github/workflows/squad-ci.yml, .github/workflows/squad-ci.yml.local-backup … (+25); squad-state blobs for 3 seeded path(s) identical",
- "old 1.1.0 upgrade --dry-run on upgraded project: exit 0, last lines \"overwrite ../.github/workflows/squad-triage.yml | overwrite ../.github/workflows/sync-squad-labels.yml | Run without --dry-run to apply.\"; modified nothing"
+ "plain upgrade changed 17 working-tree path(s), all Squad-owned: .github/workflows/squad-ci.yml, .github/workflows/squad-docs.yml, .github/workflows/squad-heartbeat.yml, .github/workflows/squad-insider-release.yml … (+13)"
]
},
{
@@ -5549,7 +5550,7 @@
"source": "pack",
"shape": "profile",
"status": "pass",
- "provenance": "pack: npm pack of packages/squad-sdk + packages/squad-cli at 9da01a2e41ba15794d31b0b8251ddaa3abd34ba8 (v1.2.0-preview.1)",
+ "provenance": "pack: npm pack of packages/squad-sdk + packages/squad-cli at 9b254ba858abc19ef62e513993d9802312bfe34c (v2.0.0-preview.4)",
"checks": [
{
"id": "producer-artifact-verified",
@@ -5627,7 +5628,7 @@
"source": "pack",
"shape": "legacy-casting",
"status": "pass",
- "provenance": "pack: npm pack of packages/squad-sdk + packages/squad-cli at 9da01a2e41ba15794d31b0b8251ddaa3abd34ba8 (v1.2.0-preview.1)",
+ "provenance": "pack: npm pack of packages/squad-sdk + packages/squad-cli at 9b254ba858abc19ef62e513993d9802312bfe34c (v2.0.0-preview.4)",
"checks": [
{
"id": "producer-artifact-verified",
@@ -5698,7 +5699,7 @@
}
],
"notes": [
- "plain upgrade changed 22 working-tree path(s), all Squad-owned: .github/workflows/squad-ci.yml, .github/workflows/squad-docs.yml, .github/workflows/squad-heartbeat.yml, .github/workflows/squad-insider-release.yml … (+18)"
+ "plain upgrade changed 21 working-tree path(s), all Squad-owned: .github/workflows/squad-ci.yml, .github/workflows/squad-docs.yml, .github/workflows/squad-heartbeat.yml, .github/workflows/squad-insider-release.yml … (+17)"
]
},
{
@@ -5706,7 +5707,7 @@
"source": "pack",
"shape": "ai-team",
"status": "pass",
- "provenance": "pack: npm pack of packages/squad-sdk + packages/squad-cli at 9da01a2e41ba15794d31b0b8251ddaa3abd34ba8 (v1.2.0-preview.1)",
+ "provenance": "pack: npm pack of packages/squad-sdk + packages/squad-cli at 9b254ba858abc19ef62e513993d9802312bfe34c (v2.0.0-preview.4)",
"checks": [
{
"id": "producer-artifact-verified",
@@ -5784,7 +5785,7 @@
"source": "pack",
"shape": "orphan",
"status": "pass",
- "provenance": "pack: npm pack of packages/squad-sdk + packages/squad-cli at 9da01a2e41ba15794d31b0b8251ddaa3abd34ba8 (v1.2.0-preview.1)",
+ "provenance": "pack: npm pack of packages/squad-sdk + packages/squad-cli at 9b254ba858abc19ef62e513993d9802312bfe34c (v2.0.0-preview.4)",
"checks": [
{
"id": "producer-artifact-verified",
@@ -5855,7 +5856,7 @@
}
],
"notes": [
- "plain upgrade changed 15 working-tree path(s), all Squad-owned: .github/workflows/squad-ci.yml, .github/workflows/squad-docs.yml, .github/workflows/squad-heartbeat.yml, .github/workflows/squad-insider-release.yml … (+11); squad-state blobs for 3 seeded path(s) identical"
+ "plain upgrade changed 20 working-tree path(s), all Squad-owned: .github/workflows/squad-ci.yml, .github/workflows/squad-docs.yml, .github/workflows/squad-heartbeat.yml, .github/workflows/squad-insider-release.yml … (+16); squad-state blobs for 3 seeded path(s) identical"
]
},
{
@@ -5863,7 +5864,7 @@
"source": "pack",
"shape": "two-layer",
"status": "pass",
- "provenance": "pack: npm pack of packages/squad-sdk + packages/squad-cli at 9da01a2e41ba15794d31b0b8251ddaa3abd34ba8 (v1.2.0-preview.1)",
+ "provenance": "pack: npm pack of packages/squad-sdk + packages/squad-cli at 9b254ba858abc19ef62e513993d9802312bfe34c (v2.0.0-preview.4)",
"checks": [
{
"id": "producer-artifact-verified",
@@ -5934,7 +5935,7 @@
}
],
"notes": [
- "plain upgrade changed 15 working-tree path(s), all Squad-owned: .github/workflows/squad-ci.yml, .github/workflows/squad-docs.yml, .github/workflows/squad-heartbeat.yml, .github/workflows/squad-insider-release.yml … (+11); squad-state blobs for 3 seeded path(s) identical"
+ "plain upgrade changed 20 working-tree path(s), all Squad-owned: .github/workflows/squad-ci.yml, .github/workflows/squad-docs.yml, .github/workflows/squad-heartbeat.yml, .github/workflows/squad-insider-release.yml … (+16); squad-state blobs for 3 seeded path(s) identical"
]
},
{
@@ -5942,7 +5943,7 @@
"source": "pack",
"shape": "upstream",
"status": "pass",
- "provenance": "pack: npm pack of packages/squad-sdk + packages/squad-cli at 9da01a2e41ba15794d31b0b8251ddaa3abd34ba8 (v1.2.0-preview.1)",
+ "provenance": "pack: npm pack of packages/squad-sdk + packages/squad-cli at 9b254ba858abc19ef62e513993d9802312bfe34c (v2.0.0-preview.4)",
"checks": [
{
"id": "producer-artifact-verified",
diff --git a/test/__snapshots__/host-projection-regression-guards.test.ts.snap b/test/__snapshots__/host-projection-regression-guards.test.ts.snap
index 61bab6d33..596988f71 100644
--- a/test/__snapshots__/host-projection-regression-guards.test.ts.snap
+++ b/test/__snapshots__/host-projection-regression-guards.test.ts.snap
@@ -36,6 +36,6 @@ exports[`host projection regression guards (#2438) > guard 1: the Copilot projec
".github/workflows/squad-triage.yml": "54f8a35713f9cd88bef9ee54b03da8f7d9cbd0bbdcbb03c73cb0dd37fd9bd1f2",
".github/workflows/sync-squad-labels.yml": "105f9f0b1e004833154c6511c84b7f70c465e69e1e8f3da8676ec1255396c34d",
".gitignore": "37aa6c4e49c873d2603b79e173ba46e216b18c596057964aac1cd6e62ff4e89f",
- ".mcp.json": "bfdf4acbf0b686e8cf8450c5416b3983ceda7016718e6b1e5a551d2576d1eb80",
+ ".mcp.json": "fc7033ca67bd82d6c4aab068c6afd7b2cad9533517417dea213dbd5641b986a7",
}
`;
diff --git a/test/cli/upgrade-portability.test.ts b/test/cli/upgrade-portability.test.ts
index 6c5a008b6..d7c561524 100644
--- a/test/cli/upgrade-portability.test.ts
+++ b/test/cli/upgrade-portability.test.ts
@@ -61,17 +61,21 @@ describe('upgrade portability and destination newlines', () => {
};
expect(config.mcpServers.custom).toEqual(custom);
expect(config.mcpServers.squad_state.env).toEqual({ EXTRA: 'keep' });
- expect(config.mcpServers.squad_state.command).toBe(mode === 'packaged'
- ? path.join(root, 'example-bundle', portableCommand) : process.execPath);
+ // Committed files carry no path into this machine's install (#2462): a standalone bundle
+ // becomes `squad` from PATH, an installed CLI becomes the repository launcher.
+ expect(config.mcpServers.squad_state.command).toBe(mode === 'packaged' ? 'squad' : 'node');
expect(config.mcpServers.squad_state.args).toEqual(mode === 'packaged'
- ? ['state-mcp'] : [path.resolve('packages/squad-cli/dist/cli-entry.js'), 'state-mcp']);
+ ? ['state-mcp'] : ['.squad/squad.mjs', 'state-mcp']);
expect(config.mcpServers.squad_state['x-squad']).toEqual({
managed: true,
version,
- machineSpecific: true,
- source: mode === 'packaged' ? 'standalone' : 'local-entry',
+ machineSpecific: false,
+ source: mode === 'packaged' ? 'path' : 'repo-launcher',
fallback,
});
+ expect(raw).not.toContain(root);
+ expect(raw).not.toContain(process.execPath);
+ expect(existsSync(path.join(root, '.squad', 'squad.mjs'))).toBe(mode === 'npm');
expect(raw).not.toMatch(/(? {
{ path: 'docs/src/content/docs/guide/contributors.md', text: `- [#298](${old}/pull/298)\nSee ${old}/blob/main/CONTRIBUTING.md` },
{ path: 'docs/specification/core-v0.1.md', text: `Provenance: [PR #2074](${old}/pull/2074)\nReference implementation: ${old}` },
{ path: 'docs/src/content/docs/whatsnew.md', text: `## v2.0.0\nFixed (${old}/pull/2279)\n## v1.1.0 — Stable Release\nPorted ([PR #131](${old}/pull/131))` },
- {
- path: 'docs/src/content/docs/scenarios/upgrading.md',
- text: `Report at ${old}/issues\n\n| [run](${old}/actions/runs/1) |\n\nAfter: ${old}/releases`,
- },
];
const { offenders, kept } = scanOldRepoLinks(files);
@@ -240,8 +236,6 @@ describe('old-repository pattern', () => {
'docs/src/content/docs/guide/contributors.md:2: github.com/bradygaster/squad/blob/main/CONTRIBUTING.md',
'docs/specification/core-v0.1.md:2: github.com/bradygaster/squad',
'docs/src/content/docs/whatsnew.md:2: github.com/bradygaster/squad/pull/2279',
- 'docs/src/content/docs/scenarios/upgrading.md:1: github.com/bradygaster/squad/issues',
- 'docs/src/content/docs/scenarios/upgrading.md:5: github.com/bradygaster/squad/releases',
]);
const keptByEntry = Object.fromEntries([...kept].filter(([, links]) => links.length > 0).map(([entry, links]) => [entry.path, links]));
expect(keptByEntry, `kept:\n${JSON.stringify(keptByEntry, null, 2)}`).toEqual({
@@ -249,7 +243,6 @@ describe('old-repository pattern', () => {
'docs/specification/': ['docs/specification/core-v0.1.md:1: github.com/bradygaster/squad/pull/2074'],
'docs/src/content/docs/guide/contributors.md': ['docs/src/content/docs/guide/contributors.md:1: github.com/bradygaster/squad/pull/298'],
'docs/src/content/docs/whatsnew.md': ['docs/src/content/docs/whatsnew.md:4: github.com/bradygaster/squad/pull/131'],
- 'docs/src/content/docs/scenarios/upgrading.md': ['docs/src/content/docs/scenarios/upgrading.md:3: github.com/bradygaster/squad/actions/runs/1'],
});
});
@@ -257,12 +250,10 @@ describe('old-repository pattern', () => {
const old = 'https://github.com/bradygaster/squad';
const files = [
{ path: 'docs/src/content/docs/whatsnew.md', text: `## v2.0.0\nPorted ([PR #131](${old}/pull/131))` },
- { path: 'docs/src/content/docs/scenarios/upgrading.md', text: `\n| [run](${old}/actions/runs/1) |` },
];
expectLines(scanOldRepoLinks(files).offenders, [
'docs/src/content/docs/whatsnew.md:2: github.com/bradygaster/squad/pull/131',
- 'docs/src/content/docs/scenarios/upgrading.md:2: github.com/bradygaster/squad/actions/runs/1',
]);
});
});
diff --git a/test/init-next-steps.test.ts b/test/init-next-steps.test.ts
new file mode 100644
index 000000000..79ddac398
--- /dev/null
+++ b/test/init-next-steps.test.ts
@@ -0,0 +1,80 @@
+/**
+ * `squad init` tells the user to run the host they chose, not always Copilot (#2453).
+ */
+import { describe, it, expect, vi } from 'vitest';
+import fs from 'node:fs';
+import os from 'node:os';
+import path from 'node:path';
+import { initNextSteps, runInit } from '../packages/squad-cli/src/cli/core/init.js';
+
+const plain = (clients: Parameters[0], plugin?: boolean) => {
+ const next = initNextSteps(clients, plugin);
+ return { lines: next.lines.map(line => line('', '')), tips: next.tips };
+};
+
+describe('initNextSteps (#2453)', () => {
+ it('defaults to Copilot when no client is chosen', () => {
+ for (const clients of [undefined, []]) {
+ const { lines, tips } = plain(clients);
+ expect(lines).toEqual(["Run copilot --agent squad and tell it what you're building."]);
+ expect(tips).toEqual(['"squad:copilot": "copilot --agent squad --additional-mcp-config @.mcp.json"']);
+ }
+ });
+
+ it('tells a Claude-only user to run Claude Code, never Copilot', () => {
+ const { lines, tips } = plain(['claude']);
+ expect(lines).toEqual(["Run claude --agent squad --mcp-config .mcp.json and tell it what you're building."]);
+ expect(tips).toEqual(['"squad:claude": "claude -p --agent squad --mcp-config .mcp.json"']);
+ expect([...lines, ...tips].join('\n')).not.toMatch(/copilot/i);
+ });
+
+ it('uses the plugin coordinator in plugin mode', () => {
+ const { lines, tips } = plain(['claude'], true);
+ expect(lines).toEqual(["Run claude; the Squad plugin's coordinator starts by default in this repository."]);
+ expect(tips).toEqual(['"squad:claude": "claude -p --agent squad:squad"']);
+ // --claude-plugin without --client keeps Copilot, the default host, beside Claude Code.
+ expect(plain(undefined, true).lines).toEqual([
+ "GitHub Copilot: Run copilot --agent squad and tell it what you're building.",
+ "Claude Code: Run claude; the Squad plugin's coordinator starts by default in this repository.",
+ ]);
+ });
+
+ it('lists every chosen host, each with its name', () => {
+ const { lines, tips } = plain(['copilot', 'claude', 'kiro', 'claude']);
+ expect(lines).toEqual([
+ "GitHub Copilot: Run copilot --agent squad and tell it what you're building.",
+ "Claude Code: Run claude --agent squad --mcp-config .mcp.json and tell it what you're building.",
+ 'Kiro: Open Kiro in this repository and ask for the squad agent.',
+ ]);
+ expect(tips).toHaveLength(2);
+ });
+
+ it('wraps the command, and only the command, in the styling', () => {
+ expect(initNextSteps(['claude']).lines[0]!('<', '>')).toBe(
+ "Run and tell it what you're building.",
+ );
+ });
+
+ it('re-running init without flags follows what .squad/config.json records (Copilot review)', async () => {
+ const root = fs.mkdtempSync(path.join(os.tmpdir(), 'squad-init-next-'));
+ const prev = { ni: process.env['SQUAD_NONINTERACTIVE'], nc: process.env['NO_COLOR'] };
+ process.env['SQUAD_NONINTERACTIVE'] = '1';
+ process.env['NO_COLOR'] = '1';
+ const log = vi.spyOn(console, 'log').mockImplementation(() => undefined);
+ const warn = vi.spyOn(console, 'warn').mockImplementation(() => undefined);
+ try {
+ await runInit(root, { clients: ['claude'], claudePlugin: true, includeWorkflows: false, includeVscodeDefault: false });
+ log.mockClear();
+ await runInit(root, { includeWorkflows: false, includeVscodeDefault: false });
+ const out = log.mock.calls.map(c => String(c[0])).join('\n');
+ expect(out).toContain("the Squad plugin's coordinator starts by default");
+ expect(out).not.toContain('--mcp-config .mcp.json and tell it');
+ } finally {
+ log.mockRestore();
+ warn.mockRestore();
+ if (prev.ni === undefined) delete process.env['SQUAD_NONINTERACTIVE']; else process.env['SQUAD_NONINTERACTIVE'] = prev.ni;
+ if (prev.nc === undefined) delete process.env['NO_COLOR']; else process.env['NO_COLOR'] = prev.nc;
+ fs.rmSync(root, { recursive: true, force: true });
+ }
+ }, 60_000);
+});
diff --git a/test/mcp-spec-init.test.ts b/test/mcp-spec-init.test.ts
index 7ba52d4cd..252195506 100644
--- a/test/mcp-spec-init.test.ts
+++ b/test/mcp-spec-init.test.ts
@@ -233,7 +233,8 @@ describe('init.ts uses resolveSquadStateMcpSpec (asymmetry fix)', () => {
'init.ts',
);
const src = readFileSync(initPath, 'utf-8');
- expect(src).toMatch(/resolveSquadStateMcpSpec/);
+ // The committed-file resolver wraps resolveSquadStateMcpSpec (#2462).
+ expect(src).toMatch(/resolve(Committed)?SquadStateMcpSpec/);
expect(src).toMatch(/from ['"]\.\/mcp-spec\.js['"]/);
});
diff --git a/test/portable-launch.test.ts b/test/portable-launch.test.ts
new file mode 100644
index 000000000..311107d34
--- /dev/null
+++ b/test/portable-launch.test.ts
@@ -0,0 +1,277 @@
+/**
+ * Committed launch commands work on every clone (#2462): `squad init` and `squad upgrade` write
+ * a repository launcher instead of `node /cli-entry.js`, Claude hooks reach it through
+ * `$CLAUDE_PROJECT_DIR`, and `squad doctor` flags machine-specific commands.
+ */
+import { afterEach, beforeEach, describe, expect, it } from 'vitest';
+import fs from 'node:fs';
+import os from 'node:os';
+import path from 'node:path';
+import { spawnSync } from 'node:child_process';
+import {
+ claudeHookLaunch,
+ isSquadHookHandler,
+ mergeClaudeHooks,
+ stripClaudeHooks,
+ squadRepoLauncher,
+ SQUAD_REPO_LAUNCHER_MARKER,
+} from '@bradygaster/squad-sdk/client';
+import {
+ committedSquadStateMcpSpec,
+ isTransientCliEntry,
+ resolveCommittedSquadStateMcpSpec,
+ squadDirInRoot,
+ writeSquadRepoLauncher,
+ type SquadStateMcpSpec,
+} from '../packages/squad-cli/src/cli/core/mcp-spec.js';
+import { checkPortableSquadLaunch } from '../packages/squad-cli/src/cli/commands/doctor.js';
+
+const fallback = { command: 'npx' as const, args: ['-y', '@bradygaster/squad-cli@9.9.9', 'state-mcp'] };
+const localEntry: SquadStateMcpSpec = {
+ command: '/opt/node/bin/node',
+ args: ['/home/someone/squad/dist/cli-entry.js', 'state-mcp'],
+ source: 'local-entry',
+ fallback,
+};
+const repoLauncher = { command: 'node', args: ['.squad/squad.mjs', 'state-mcp'] };
+
+let root: string;
+beforeEach(() => {
+ root = fs.mkdtempSync(path.join(os.tmpdir(), 'squad-portable-launch-'));
+});
+afterEach(() => {
+ fs.rmSync(root, { recursive: true, force: true });
+});
+
+function write(rel: string, body: string): string {
+ const file = path.join(root, rel);
+ fs.mkdirSync(path.dirname(file), { recursive: true });
+ fs.writeFileSync(file, body);
+ return file;
+}
+
+describe('committed spec (#2462)', () => {
+ it('turns an installed CLI into the repository launcher and a bundle into squad from PATH', () => {
+ expect(committedSquadStateMcpSpec(localEntry, '.squad')).toEqual({ ...repoLauncher, source: 'repo-launcher', fallback });
+ expect(committedSquadStateMcpSpec({ ...localEntry, command: '/b/squad', args: ['state-mcp'], source: 'standalone' }, '.squad'))
+ .toEqual({ command: 'squad', args: ['state-mcp'], source: 'path', fallback });
+ const pinned: SquadStateMcpSpec = { ...fallback, args: [...fallback.args], source: 'pinned' };
+ expect(committedSquadStateMcpSpec(pinned, '.squad')).toBe(pinned);
+ // No squad directory inside the repository: no portable form.
+ expect(committedSquadStateMcpSpec(localEntry, null)).toBe(localEntry);
+ });
+
+ it('finds the squad directory only inside the repository', () => {
+ expect(squadDirInRoot(root, path.join(root, '.squad'))).toBe('.squad');
+ expect(squadDirInRoot(root, path.join(root, 'team', '.squad'))).toBe('team/.squad');
+ expect(squadDirInRoot(root, path.dirname(root))).toBeNull();
+ expect(squadDirInRoot(root, root)).toBeNull();
+ });
+
+ it('writes the launcher, refreshes its own and leaves a user file alone', () => {
+ expect(writeSquadRepoLauncher(root, '.squad', '9.9.9')).toBe('created');
+ const file = path.join(root, '.squad', 'squad.mjs');
+ expect(fs.readFileSync(file, 'utf8')).toContain(SQUAD_REPO_LAUNCHER_MARKER);
+ // Outside any bin/ directory, which repositories often ignore (Copilot review).
+ expect(path.relative(root, file).split(path.sep)).not.toContain('bin');
+ expect(writeSquadRepoLauncher(root, '.squad', '9.9.9')).toBe('unchanged');
+ expect(writeSquadRepoLauncher(root, '.squad', '9.9.10')).toBe('updated');
+ fs.writeFileSync(file, '// mine\n');
+ expect(writeSquadRepoLauncher(root, '.squad', '9.9.10')).toBe('skipped');
+ expect(fs.readFileSync(file, 'utf8')).toBe('// mine\n');
+ });
+
+ it('never writes through a symlink that leaves the workspace (Copilot review)', () => {
+ const outside = fs.mkdtempSync(path.join(os.tmpdir(), 'squad-outside-'));
+ try {
+ // The squad directory itself links outside the workspace.
+ fs.symlinkSync(outside, path.join(root, '.squad'), 'dir');
+ expect(writeSquadRepoLauncher(root, '.squad', '9.9.9')).toBe('skipped');
+ expect(fs.readdirSync(outside)).toEqual([]);
+ fs.rmSync(path.join(root, '.squad'));
+ // A dangling link at the launcher path, pointing outside.
+ fs.mkdirSync(path.join(root, '.squad'));
+ fs.symlinkSync(path.join(outside, 'planted.mjs'), path.join(root, '.squad', 'squad.mjs'));
+ expect(writeSquadRepoLauncher(root, '.squad', '9.9.9')).toBe('skipped');
+ expect(fs.existsSync(path.join(outside, 'planted.mjs'))).toBe(false);
+ } finally {
+ fs.rmSync(outside, { recursive: true, force: true });
+ }
+ });
+
+ it('keeps exact-version npx for a CLI running from a package runner cache (Copilot review)', () => {
+ for (const entry of [
+ '/home/u/.npm/_npx/0a1b2c/node_modules/@bradygaster/squad-cli/dist/cli-entry.js',
+ 'C:\\Users\\u\\AppData\\Local\\npm-cache\\_npx\\0a1b\\node_modules\\@bradygaster\\squad-cli\\dist\\cli-entry.js',
+ '/home/u/.cache/pnpm/dlx/abc/node_modules/@bradygaster/squad-cli/dist/cli-entry.js',
+ '/tmp/xfs-1a2b3c/dlx-5555/node_modules/@bradygaster/squad-cli/dist/cli-entry.js',
+ ]) {
+ expect(isTransientCliEntry(entry), entry).toBe(true);
+ expect(committedSquadStateMcpSpec({ ...localEntry, args: [entry, 'state-mcp'] }, '.squad'))
+ .toEqual({ command: 'npx', args: fallback.args, source: 'pinned' });
+ }
+ expect(isTransientCliEntry('/usr/local/lib/node_modules/@bradygaster/squad-cli/dist/cli-entry.js')).toBe(false);
+ expect(isTransientCliEntry('/home/u/src/dlxtools/squad/dist/cli-entry.js')).toBe(false);
+ });
+
+ it('keeps the machine-specific spec when the launcher path is user-owned', async () => {
+ write('.squad/squad.mjs', '// mine\n');
+ const spec = await resolveCommittedSquadStateMcpSpec('9.9.9', root, path.join(root, '.squad'), {
+ standaloneCheck: () => null,
+ localEntryCheck: () => '/home/someone/squad/dist/cli-entry.js',
+ });
+ expect(spec.source).toBe('local-entry');
+ });
+
+ it('read-only callers get the launcher spec without a file being written', async () => {
+ const spec = await resolveCommittedSquadStateMcpSpec('9.9.9', root, path.join(root, '.squad'), {
+ standaloneCheck: () => null,
+ localEntryCheck: () => '/x/cli-entry.js',
+ write: false,
+ });
+ expect(spec.source).toBe('repo-launcher');
+ expect(fs.existsSync(path.join(root, '.squad'))).toBe(false);
+ });
+});
+
+describe('Claude hooks through the repository launcher (#2462)', () => {
+ it('runs the launcher from $CLAUDE_PROJECT_DIR as a shell command', () => {
+ expect(claudeHookLaunch(repoLauncher, 'Stop')).toEqual({
+ command: 'node "$CLAUDE_PROJECT_DIR/.squad/squad.mjs" hook claude Stop',
+ args: [],
+ });
+ // Anything else keeps the argv form.
+ expect(claudeHookLaunch({ command: 'node', args: ['/abs/.squad/squad.mjs', 'state-mcp'] }, 'Stop')!.args)
+ .toEqual(['/abs/.squad/squad.mjs', 'hook', 'claude', 'Stop']);
+ expect(claudeHookLaunch({ command: 'node', args: ['../x/bin/squad.mjs', 'state-mcp'] }, 'Stop')!.args.length).toBe(4);
+ });
+
+ it('replaces old machine-specific handlers, keeps user hooks, and strips cleanly', () => {
+ const user = { type: 'command', command: 'echo user' };
+ const old = {
+ type: 'command',
+ command: '/opt/node/bin/node',
+ args: ['/home/someone/squad/dist/cli-entry.js', 'hook', 'claude', 'Stop'],
+ timeout: 15,
+ };
+ const merged = mergeClaudeHooks({ hooks: { Stop: [{ hooks: [user] }, { hooks: [old] }] } }, repoLauncher);
+ const text = JSON.stringify(merged);
+ expect(text).not.toContain('/home/someone');
+ expect(text).toContain('echo user');
+ const handlers = (merged['hooks'] as Record[] }[]>)['Stop']!.flatMap(g => g.hooks);
+ const squad = handlers.filter(isSquadHookHandler);
+ expect(squad).toEqual([{ type: 'command', command: 'node "$CLAUDE_PROJECT_DIR/.squad/squad.mjs" hook claude Stop', timeout: 15 }]);
+ expect(stripClaudeHooks(merged)).toEqual({ hooks: { Stop: [{ hooks: [user] }] } });
+ });
+
+ it('does not take a look-alike user command for Squad\'s', () => {
+ expect(isSquadHookHandler({ type: 'command', command: 'node "$CLAUDE_PROJECT_DIR/.squad/squad.mjs" hook claude Stop; rm -rf x' })).toBe(false);
+ expect(isSquadHookHandler({ type: 'command', command: 'node "$CLAUDE_PROJECT_DIR/.squad/squad.mjs" hook claude Nope' })).toBe(false);
+ expect(isSquadHookHandler({ type: 'command', command: 'squad hook claude Stop' })).toBe(false);
+ });
+});
+
+describe('the repository launcher script (#2462)', () => {
+ /** A fake CLI that prints its argv, at `/node_modules/@bradygaster/squad-cli`. */
+ function fakeCli(dir: string, version: string): void {
+ const pkg = path.join(dir, 'node_modules', '@bradygaster', 'squad-cli');
+ fs.mkdirSync(path.join(pkg, 'dist'), { recursive: true });
+ fs.writeFileSync(path.join(pkg, 'package.json'), JSON.stringify({ name: '@bradygaster/squad-cli', version }));
+ fs.writeFileSync(path.join(pkg, 'dist', 'cli-entry.js'), `console.log('fake ${version}', JSON.stringify(process.argv.slice(2)));\n`);
+ }
+
+ function run(args: string[], env: Record = {}, cwd = os.tmpdir()) {
+ return spawnSync(process.execPath, [path.join(root, '.squad', 'squad.mjs'), ...args], {
+ cwd,
+ encoding: 'utf8',
+ // PATH without a real squad, so the result depends only on the repository.
+ env: { PATH: path.dirname(process.execPath), ...env },
+ });
+ }
+
+ beforeEach(() => {
+ write('.squad/squad.mjs', squadRepoLauncher('2.0.0', '.squad'));
+ });
+
+ it('runs the repository\'s own install from any working directory', () => {
+ fakeCli(root, '2.0.1');
+ const out = run(['state-mcp']);
+ expect(out.status).toBe(0);
+ expect(out.stdout.trim()).toBe('fake 2.0.1 ["state-mcp"]');
+ });
+
+ it('skips a CLI older than the version that wrote it, and says how to install', () => {
+ fakeCli(root, '1.9.0');
+ const out = run(['state-mcp']);
+ expect(out.status).toBe(1);
+ expect(out.stderr).toContain('no Squad CLI 2.0.0 or newer found');
+ expect(out.stderr).toContain('npm install -g @bradygaster/squad-cli@2.0.0');
+ });
+
+ it('falls back to the CLI recorded on this machine, and skips an older one', async () => {
+ const { recordSquadCli } = await import('../packages/squad-cli/src/cli/core/mcp-spec.js');
+ const other = path.join(root, 'other-machine-dir');
+ fakeCli(other, '2.0.2');
+ const home = path.join(root, 'squad-home');
+ const entry = path.join(other, 'node_modules', '@bradygaster', 'squad-cli', 'dist', 'cli-entry.js');
+ recordSquadCli(entry, '2.0.2', { SQUAD_HOME: home });
+ expect(JSON.parse(fs.readFileSync(path.join(home, 'cli.json'), 'utf8'))).toEqual({ entry, version: '2.0.2' });
+ expect(run(['state-mcp'], { SQUAD_HOME: home }).stdout.trim()).toBe('fake 2.0.2 ["state-mcp"]');
+ fs.rmSync(other, { recursive: true });
+ fakeCli(other, '1.0.0');
+ expect(run(['state-mcp'], { SQUAD_HOME: home }).status).toBe(1);
+ });
+
+ it('honours SQUAD_CLI', () => {
+ const entry = write('elsewhere/cli.js', "console.log('override', process.argv.slice(2).join(' '));\n");
+ expect(run(['--version'], { SQUAD_CLI: entry }).stdout.trim()).toBe('override --version');
+ });
+
+ it('is a no-op for hooks unless the team opted in', () => {
+ write('.squad/config.json', JSON.stringify({ version: 1 }));
+ const off = run(['hook', 'claude', 'Stop']);
+ expect(off.status).toBe(0);
+ expect(off.stdout).toBe('');
+ write('.squad/config.json', JSON.stringify({ version: 1, claudeHooks: 'advisory' }));
+ fakeCli(root, '2.0.0');
+ expect(run(['hook', 'claude', 'Stop']).stdout.trim()).toBe('fake 2.0.0 ["hook","claude","Stop"]');
+ });
+});
+
+describe('squad doctor: portable launch commands (#2462)', () => {
+ const mcp = (command: string, args: string[]) => JSON.stringify({ mcpServers: { squad_state: { command, args } } });
+
+ it('is silent when nothing is committed', () => {
+ expect(checkPortableSquadLaunch(root)).toBeUndefined();
+ });
+
+ it('fails on a path from another machine and warns on this machine\'s own path', () => {
+ write('.mcp.json', mcp('/nowhere/bin/node', ['/nowhere/cli-entry.js', 'state-mcp']));
+ expect(checkPortableSquadLaunch(root)).toMatchObject({ status: 'fail' });
+ const entry = write('install/dist/cli-entry.js', '');
+ write('.mcp.json', mcp(process.execPath, [entry, 'state-mcp']));
+ expect(checkPortableSquadLaunch(root)).toMatchObject({ status: 'warn' });
+ });
+
+ it('recognises Windows paths on any OS, and finds a bare node on PATH (Copilot review)', () => {
+ write('.mcp.json', mcp('C:\\Program Files\\nodejs\\node.exe', ['C:\\Users\\u\\squad\\dist\\cli-entry.js', 'state-mcp']));
+ expect(checkPortableSquadLaunch(root)).toMatchObject({ status: process.platform === 'win32' ? expect.any(String) : 'fail' });
+ const entry = write('install/dist/cli-entry.js', '');
+ write('.mcp.json', mcp('node', [entry, 'state-mcp']));
+ expect(checkPortableSquadLaunch(root)).toMatchObject({ status: 'warn' });
+ });
+
+ it('checks Claude hooks too, and that the launcher exists', () => {
+ write('.mcp.json', mcp('node', ['.squad/squad.mjs', 'state-mcp']));
+ write('.claude/settings.json', JSON.stringify({
+ hooks: { Stop: [{ hooks: [{ type: 'command', command: 'node "$CLAUDE_PROJECT_DIR/.squad/squad.mjs" hook claude Stop' }] }] },
+ }));
+ expect(checkPortableSquadLaunch(root)).toMatchObject({ status: 'fail', message: expect.stringContaining('missing') });
+ write('.squad/squad.mjs', squadRepoLauncher('2.0.0', '.squad'));
+ expect(checkPortableSquadLaunch(root)).toMatchObject({ status: 'pass', message: '2 committed launch command(s) are portable' });
+ write('.claude/settings.json', JSON.stringify({
+ hooks: { Stop: [{ hooks: [{ type: 'command', command: '/nowhere/node', args: ['/nowhere/cli-entry.js', 'hook', 'claude', 'Stop'] }] }] },
+ }));
+ expect(checkPortableSquadLaunch(root)).toMatchObject({ status: 'fail', message: expect.stringContaining('.claude/settings.json') });
+ });
+});
diff --git a/test/squad-20-upgrade-matrix.test.ts b/test/squad-20-upgrade-matrix.test.ts
index 7a452b8fa..30e5caa28 100644
--- a/test/squad-20-upgrade-matrix.test.ts
+++ b/test/squad-20-upgrade-matrix.test.ts
@@ -206,7 +206,8 @@ describe('upgrade-matrix.json integrity', () => {
} else if (p.source === 'github-release') {
expect('release' in p.artifacts, `${p.version}: release producer needs artifacts.release`).toBe(true);
const rel = (p.artifacts as { release: { repository: string; tag: string; assets: Record } }).release;
- expect(rel.repository).toBe('bradygaster/squad');
+ // The repository moved from bradygaster/squad to github/squad; release asset ids are unchanged.
+ expect(rel.repository).toBe('github/squad');
expect(rel.tag).toBe(`v${p.version}`);
for (const name of ['squad-linux-x64.tar.gz', 'squad-linux-arm64.tar.gz', 'squad-darwin-x64.tar.gz', 'squad-darwin-arm64.tar.gz', 'squad-win32-x64.zip', 'squad-win32-arm64.zip']) {
const a = rel.assets[name];