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

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -113,7 +113,7 @@ codevhub skill office --platform macos --arch arm64 # macOS needs a chip: arm6
codevhub skill office --dir /media/usb/codev-office # download somewhere else
```

Because macOS has one bundle per chip, `--platform macos` from a non-Mac also needs `--arch arm64` or `--arch x86_64` — nothing on a Linux or Windows host implies which Mac the bundle is for, and guessing costs a 1.7 GB download. On a Mac the chip is detected for you (including through Rosetta), and `--arch` is only needed to stage a bundle for the *other* chip. There is still a single macOS setup script: it resolves its own bundle from `uname -m`.
Because macOS has one bundle per chip, `--platform macos` from a non-Mac also needs `--arch arm64` or `--arch x86_64` — nothing on a Linux or Windows host implies which Mac the bundle is for. On a Mac the chip is detected for you (including through Rosetta), and `--arch` is only needed to stage a bundle for the *other* chip. There is still a single macOS setup script: it resolves its own bundle from `uname -m`.

Both files land side by side, and the command prints the exact line to run from that folder (`bash codev-office-<os>-setup.sh`, or `powershell -ExecutionPolicy Bypass -File .\codev-office-windows-setup.ps1`). A bundle downloaded for another OS is never executed on this machine.

Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "codev-ai",
"version": "0.5.14",
"version": "0.5.15",
"description": "CoDev — AI Coding Agent Hub. Install, configure, and manage multiple AI coding agents.",
"keywords": [
"ai",
Expand Down
10 changes: 5 additions & 5 deletions src/lib/office.ts
Original file line number Diff line number Diff line change
Expand Up @@ -65,8 +65,8 @@ export function detectPlatform(
// process.arch is the architecture of the NODE BINARY, not of the machine: an
// x64 node running under Rosetta on Apple Silicon reports "x64". Trusting it
// there would fetch the Intel bundle onto an M-series Mac, and the cost is not
// just the wrong 1.7 GB — the setup script is native bash, sees `uname -m` =
// arm64, finds no bundle it can use and downloads another 1.7 GB. The
// just the wrong 1.6 GB — the setup script is native bash, sees `uname -m` =
// arm64, finds no bundle it can use and downloads another 1.6 GB. The
// sysctl.proc_translated flag is the supported way to detect the translation.
function isRosettaTranslated(): boolean {
if (process.platform !== "darwin" || process.arch !== "x64") return false;
Expand Down Expand Up @@ -236,8 +236,8 @@ export function officeUninstallScriptName(platform: OfficePlatform): string {
const APPROX_BUNDLE_MB: Record<OfficeTarget, number> = {
ubuntu: 1200,
windows: 1400,
"macos-arm64": 1700,
"macos-x86_64": 1700,
"macos-arm64": 1600,
"macos-x86_64": 1600,
};

// Adaptive size for progress lines: the setup script is ~13 KB and rendered
Expand Down Expand Up @@ -431,7 +431,7 @@ export async function runSkillOffice(
// macOS publishes one bundle per chip, so a macOS download needs an arch.
// The host's own arch may only stand in for it when the host IS the target:
// on a Linux/Windows x64 box, detectArch() would confidently answer x86_64
// for a `--platform macos` download and hand the user the wrong 1.7 GB.
// for a `--platform macos` download and hand the user the wrong 1.6 GB.
// --arch always wins, including on a Mac staging a bundle for the other chip.
const arch = parsed.arch ?? (crossPlatform ? null : detectArch());
const target = officeTarget(platform, arch);
Expand Down
2 changes: 1 addition & 1 deletion tests/lib/download.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -353,7 +353,7 @@
return 0;
},
);
expect(code).toBe(0);

Check failure on line 356 in tests/lib/download.test.ts

View workflow job for this annotation

GitHub Actions / matrix (windows-latest)

tests/lib/download.test.ts > runSkillOffice > --download-only stages both files and never spawns

AssertionError: expected 1 to be +0 // Object.is equality - Expected + Received - 0 + 1 ❯ tests/lib/download.test.ts:356:16
expect(spawns).toEqual([]);
expect(readFileSync(join(dir, bundleName)).equals(BUNDLE)).toBe(true);
expect(readFileSync(join(dir, scriptName)).equals(SCRIPT)).toBe(true);
Expand All @@ -370,7 +370,7 @@
return 0;
},
);
expect(code).toBe(0);

Check failure on line 373 in tests/lib/download.test.ts

View workflow job for this annotation

GitHub Actions / matrix (windows-latest)

tests/lib/download.test.ts > runSkillOffice > runs the installer via bash with translated flags

AssertionError: expected 1 to be +0 // Object.is equality - Expected + Received - 0 + 1 ❯ tests/lib/download.test.ts:373:16
expect(spawned).toEqual({
command: "bash",
args: [join(dir, scriptName), "--skip-verify"],
Expand All @@ -381,12 +381,12 @@
test("propagates the installer's exit code", async () => {
const dir = join(tempDir, "office");
const code = await runSkillOffice(["--dir", dir], baseUrl, async () => 7);
expect(code).toBe(7);

Check failure on line 384 in tests/lib/download.test.ts

View workflow job for this annotation

GitHub Actions / matrix (windows-latest)

tests/lib/download.test.ts > runSkillOffice > propagates the installer's exit code

AssertionError: expected 1 to be 7 // Object.is equality - Expected + Received - 7 + 1 ❯ tests/lib/download.test.ts:384:16
});

// macOS publishes one bundle per chip. From another OS nothing implies
// which, and the host's own x64 would be a confident wrong answer costing
// 1.7 GB — so this must fail loudly instead of picking a default.
// 1.6 GB — so this must fail loudly instead of picking a default.
// Pinned to linux so the macOS bundle is always the cross-platform case,
// whichever machine runs the suite.
test("a macOS bundle from another OS refuses without --arch", async () => {
Expand Down Expand Up @@ -511,7 +511,7 @@
const fallback = join(tempDir, "fallback-office");
try {
const dir = ensureStagingDir(preferred, fallback);
expect(dir).toBe(fallback);

Check failure on line 514 in tests/lib/download.test.ts

View workflow job for this annotation

GitHub Actions / matrix (windows-latest)

tests/lib/download.test.ts > runSkillOffice > ensureStagingDir falls back when the preferred dir is unwritable

AssertionError: expected 'C:\Users\RUNNER~1\AppData\Local\Temp\…' to be 'C:\Users\RUNNER~1\AppData\Local\Temp\…' // Object.is equality Expected: "C:\Users\RUNNER~1\AppData\Local\Temp\codev-download-BYG2MY\fallback-office" Received: "C:\Users\RUNNER~1\AppData\Local\Temp\codev-download-BYG2MY\locked\codev-office" ❯ tests/lib/download.test.ts:514:16
expect(existsSync(fallback)).toBe(true);
} finally {
chmodSync(locked, 0o755);
Expand Down Expand Up @@ -548,7 +548,7 @@
["--download-only", "--dir", dir],
baseUrl,
);
expect(code).toBe(0);

Check failure on line 551 in tests/lib/download.test.ts

View workflow job for this annotation

GitHub Actions / matrix (windows-latest)

tests/lib/download.test.ts > runSkillOffice > always refetches the setup script, but reuses a finished bundle

AssertionError: expected 1 to be +0 // Object.is equality - Expected + Received - 0 + 1 ❯ tests/lib/download.test.ts:551:16
expect(readFileSync(join(dir, scriptName)).equals(SCRIPT)).toBe(true);
// No checksum to disagree with, so the existing bundle is trusted as-is.
expect(readFileSync(join(dir, bundleName), "utf8")).toBe("stale-bundle");
Expand All @@ -565,7 +565,7 @@
["--download-only", "--dir", dir],
baseUrl,
);
expect(code).toBe(0);

Check failure on line 568 in tests/lib/download.test.ts

View workflow job for this annotation

GitHub Actions / matrix (windows-latest)

tests/lib/download.test.ts > runSkillOffice > drops a stale .partial for the script instead of resuming onto it

AssertionError: expected 1 to be +0 // Object.is equality - Expected + Received - 0 + 1 ❯ tests/lib/download.test.ts:568:16
expect(readFileSync(join(dir, scriptName)).equals(SCRIPT)).toBe(true);
// Both requests went out without a Range header.
expect(rangeLog).toEqual([undefined, undefined]);
Expand Down Expand Up @@ -628,7 +628,7 @@
return 0;
},
);
expect(code).toBe(0);

Check failure on line 631 in tests/lib/download.test.ts

View workflow job for this annotation

GitHub Actions / matrix (windows-latest)

tests/lib/download.test.ts > runSkillOffice > --uninstall fetches only the uninstall script and runs it with passthroughs

AssertionError: expected 1 to be +0 // Object.is equality - Expected + Received - 0 + 1 ❯ tests/lib/download.test.ts:631:16
expect(spawned).toEqual({
command: "bash",
args: [join(dir, uninstallName), "--yes", "--skills-only"],
Expand Down
4 changes: 2 additions & 2 deletions tests/lib/office.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ describe("detectArch", () => {

// An x64 node under Rosetta reports "x64" on an Apple Silicon Mac. Believing
// it downloads the Intel bundle, which the native-bash setup script then
// refuses — and re-downloads the arm64 one. 3.4 GB to land 1.7.
// refuses — and re-downloads the arm64 one. 3.2 GB to land 1.6.
test("Rosetta translation overrides the reported x64", () => {
expect(detectArch("x64", true)).toBe("arm64");
});
Expand All @@ -54,7 +54,7 @@ describe("officeTarget", () => {
expect(officeTarget("macos", "x86_64")).toBe("macos-x86_64");
});

test("macOS without an arch has no target — never guess a 1.7 GB download", () => {
test("macOS without an arch has no target — never guess a 1.6 GB download", () => {
expect(officeTarget("macos", null)).toBeNull();
});
});
Expand Down
Loading