Skip to content

Commit a402d75

Browse files
feat: fix Squad version detection, implement /squad-update (v0.1.2)
- Read version from squad/package.json (squad/VERSION never existed upstream) - Fix all version reads: version.ts, coordinator.ts, system-prompt.ts, recovery.ts - Rewrite scripts/sync-squad.ts for git submodule model (retire tarball sync) - Fix scripts/check-version.ts path bug - Implement /squad-update command (was a stub) - Add startup update-available check - Fix stale mock in tests/context/recovery.test.ts Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
1 parent 4b07879 commit a402d75

9 files changed

Lines changed: 329 additions & 220 deletions

File tree

CHANGELOG.md

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,22 @@ Format follows [Keep a Changelog](https://keepachangelog.com/en/1.1.0/).
66

77
---
88

9+
## [0.1.2] — 2026-06-03
10+
11+
### Fixed
12+
- `squad/VERSION` never existed in upstream `bradygaster/squad` — all startup version reads were broken. Version now read from `squad/package.json` across all modules (`version.ts`, `coordinator.ts`, `system-prompt.ts`, `context/recovery.ts`)
13+
- `scripts/check-version.ts` pointed to non-existent `{sovereignRoot}/squad/VERSION`; fixed to read `packages/coordinator/squad/package.json`
14+
15+
### Changed
16+
- `scripts/sync-squad.ts` rewritten for git submodule model — replaces legacy tarball download/extract flow with `git fetch --tags` + `git checkout v{version}`
17+
- `src/upstream/sync.ts` tarball sync logic (`syncSquadUpstream()`) retired; `checkForUpdates()` retained
18+
19+
### Added
20+
- `/squad-update` command implemented (previously a stub) — fetches latest Squad submodule tag, checks out, updates `package.json` squad fields, reloads extension
21+
- Startup update-available check: notifies on newer Squad submodule tag or newer `@pi-squad/coordinator` npm version (non-blocking, fire-and-forget)
22+
23+
---
24+
925
## [0.1.1] — 2026-06-03
1026

1127
### Security

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@pi-squad/coordinator",
3-
"version": "0.1.1",
3+
"version": "0.1.2",
44
"description": "Bring Squad's multi-agent coordination to Pi — your whole team, no cloud required",
55
"type": "module",
66
"main": "./dist/index.js",

src/context/recovery.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -415,8 +415,9 @@ function estimateDroppableSections(ctx: RecoveryContext): Map<string, number> {
415415

416416
async function readSquadVersion(): Promise<string> {
417417
try {
418-
const raw = await readFile(new URL("../../squad/VERSION", import.meta.url), "utf8");
419-
return raw.trim() || "unknown";
418+
const raw = await readFile(new URL("../../squad/package.json", import.meta.url), "utf8");
419+
const pkg = JSON.parse(raw) as { version?: string };
420+
return pkg.version?.trim() || "unknown";
420421
} catch {
421422
return "unknown";
422423
}

src/coordinator/coordinator.ts

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
*/
55

66
import { readFile } from "node:fs/promises";
7-
import { join, resolve } from "node:path";
7+
import { join } from "node:path";
88
import { fileURLToPath } from "node:url";
99

1010
import type { ExtensionAPI } from "@earendil-works/pi-coding-agent";
@@ -147,14 +147,15 @@ async function readSquadMeta(): Promise<PackageSquadMeta | null> {
147147
}
148148
}
149149

150-
async function readSquadVersion(teamRoot: string): Promise<string | null> {
151-
const versionPath = resolve(new URL("../../squad/VERSION", import.meta.url).pathname);
152-
const fromVendored = await readFileSafe(versionPath);
153-
if (fromVendored) {
154-
return fromVendored.trim();
150+
async function readSquadVersion(_teamRoot: string): Promise<string | null> {
151+
try {
152+
const packageJsonPath = fileURLToPath(new URL("../../squad/package.json", import.meta.url));
153+
const raw = await readFile(packageJsonPath, "utf8");
154+
const pkg = JSON.parse(raw) as { version?: string };
155+
return pkg.version?.trim() ?? null;
156+
} catch {
157+
return null;
155158
}
156-
157-
return readFileSafe(join(teamRoot, ".squad", "VERSION"));
158159
}
159160

160161
async function readAgentPrompt(): Promise<string> {

src/coordinator/system-prompt.ts

Lines changed: 13 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -13,8 +13,8 @@ import { sanitize } from "../context/ingestion/sanitizer.js";
1313
const SQUAD_AGENT_MD = fileURLToPath(
1414
new URL("../../squad/.github/agents/squad.agent.md", import.meta.url),
1515
);
16-
const SQUAD_VERSION_FILE = fileURLToPath(
17-
new URL("../../squad/VERSION", import.meta.url),
16+
const SQUAD_PACKAGE_JSON = fileURLToPath(
17+
new URL("../../squad/package.json", import.meta.url),
1818
);
1919
const TEAM_MD_FILENAME = "team.md";
2020
const ROUTING_MD_FILENAME = "routing.md";
@@ -189,12 +189,17 @@ export async function getSystemPrompt(teamRoot: string): Promise<string> {
189189
const routingPath = join(teamRoot, ".squad", ROUTING_MD_FILENAME);
190190
const decisionsPath = join(teamRoot, ".squad", DECISIONS_MD_FILENAME);
191191

192-
const squadVersionPromise = readFile(SQUAD_VERSION_FILE, "utf8").catch(() => {
193-
console.warn(
194-
"[pi-squad] Could not read squad/VERSION — version display may show placeholder",
195-
);
196-
return null;
197-
});
192+
const squadVersionPromise = readFile(SQUAD_PACKAGE_JSON, "utf8")
193+
.then((raw) => {
194+
const pkg = JSON.parse(raw) as { version?: string };
195+
return pkg.version?.trim() ?? null;
196+
})
197+
.catch(() => {
198+
console.warn(
199+
"[pi-squad] Could not read squad/package.json — version display may show placeholder",
200+
);
201+
return null;
202+
});
198203

199204
const [squadAgent, squadVersion, team, routing, decisions] = await Promise.all([
200205
readRequiredFile(SQUAD_AGENT_MD),

0 commit comments

Comments
 (0)