altimate-code 0.7.0 → 0.7.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -5,6 +5,95 @@ All notable changes to this project will be documented in this file.
5
5
  The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
6
6
  and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
7
 
8
+ ## [0.7.2] - 2026-05-21
9
+
10
+ A focused hotfix for v0.7.1's broken install endpoint plus a defensive pass on the upgrade fetch surface. v0.7.1 documented and embedded `https://altimate.ai/install` in the curl install path and in `altimate upgrade`'s in-place upgrader — that host is the marketing-site SPA and returns an HTML 404 for `/install`, so every curl install and every curl-installed user's `altimate upgrade` silently failed end-to-end. v0.7.2 swaps the host to `https://www.altimate.sh/install` (apex `altimate.sh` is still not routed to the Amplify Next.js app — tracked separately, drop the `www.` once apex DNS is fixed), wraps the upgrader fetch with a 15s bounded timeout, replaces the raw `AbortError: The operation was aborted` with an actionable error that names the URL, prints the manual re-install one-liner, and points at the GitHub releases fallback. Realigns the published GitHub Action (`github/action.yml`) with the v0.7.1 binary rename (`altimate-code` → `altimate`) and new install directory (`~/.altimate/bin`) — pre-fix, every Action consumer hit the broken URL on cache miss and then a missing binary even if the URL had worked. 30 adversarial tests pin the regression classes (URL eradication, cross-file host consistency, named-constant invariants, error-surface invariants, action.yml alignment, marker integrity, migration recovery surface, CHANGELOG presence).
11
+
12
+ **If you installed v0.7.1 via curl, your `altimate upgrade` will still fail until you re-install manually once:**
13
+
14
+ ```bash
15
+ curl -fsSL https://www.altimate.sh/install | bash
16
+ ```
17
+
18
+ After that, v0.7.2 and forward self-heal.
19
+
20
+ ### Fixed
21
+
22
+ - **`Installation.upgradeCurl()` now fetches from `https://www.altimate.sh/install` instead of the unreachable `https://altimate.ai/install`.** v0.7.1 had pointed the in-place upgrader at the marketing site, which routes everything through a React Router SPA — `/install` rendered an HTML 404 page, the upgrader's `fetch` succeeded with a 200, the response body was the 404 HTML, and `bash` either executed the HTML and failed cryptically or hung mid-stream. The matching curl install one-liner in `install --help`, `README.md`, and `docs/docs/reference/troubleshooting.md` (three references) was broken the same way. www.altimate.sh now serves the install script via a Next.js route handler with `Content-Type: text/x-shellscript`. (#825, closes #309)
23
+ - **Published GitHub Action (`github/action.yml`) realigned with the v0.7.1 binary rename.** v0.7.1 renamed the curl-installed binary `altimate-code` → `altimate` and moved the install directory `~/.altimate-code/bin` → `~/.altimate/bin`, but the Action's cache `path:`, `$GITHUB_PATH` addition, and final `run:` step still referenced the legacy `altimate-code` name and path. Combined with the broken install URL, every Action consumer hit a 404 on cache miss followed by an empty `$PATH` and a `altimate-code: command not found` even after the install "succeeded". All four references updated in lockstep.
24
+ - **`altimate upgrade` (curl method) no longer hangs indefinitely on a stalled CDN/origin.** The fetch is bounded by `AbortSignal.timeout(UPGRADE_FETCH_TIMEOUT_MS)` (15s) so a TLS-rewriting corporate proxy, a hung CloudFront edge, or a slow-loris-style stall fails fast instead of blocking the user's terminal for minutes. Surfaced via CodeRabbit review on #825.
25
+
26
+ ### Changed
27
+
28
+ - **Curl-upgrade fetch failures now surface an actionable error instead of `AbortError: The operation was aborted`.** Pre-fix, a timeout, a 404, a DNS failure, or a connection refused would propagate as `DOMException: The operation was aborted` (timeout) or `Error: Not Found` (HTTP non-2xx) — neither named the URL, the recovery path, or the fallback. The fetch is now wrapped in `try/catch` and the rethrown error reads: `"Could not download install script from https://www.altimate.sh/install: <cause>. Re-run the install manually: curl -fsSL https://www.altimate.sh/install | bash — or download a release binary directly from https://github.com/AltimateAI/altimate-code/releases/latest"`. HTTP non-2xx now also includes the numeric status (`HTTP 404 Not Found` instead of just `Not Found`).
29
+ - **`UPGRADE_INSTALL_URL` and `UPGRADE_FETCH_TIMEOUT_MS` extracted as named constants** inside the `altimate_change` block in `packages/opencode/src/installation/index.ts`. Pre-fix, the URL and timeout were duplicated string + literal across the source and the test assertion. A future timeout tune (15s → 20s) would have required three coordinated edits; now it's one. The adversarial test asserts the existence of the named constant separately from the literal value so the regression guard isn't brittle to constant extraction itself.
30
+ - **`altimate_change` marker block in `installation/index.ts` extended.** The v0.7.1 release did not mark the line where `upgradeCurl()` fetches the install script; v0.7.2 wraps the URL + timeout constants and the entire fetch+wrap block in a single marker pair so the next upstream bridge merge sees the intent and doesn't silently revert the URL or strip the timeout.
31
+
32
+ ### Testing
33
+
34
+ - 30 adversarial tests in `release-v0.7.2-adversarial.test.ts` pinning the v0.7.2 surface:
35
+ - **URL eradication** — 5 surfaces (`installation/index.ts`, `install`, `README.md`, `troubleshooting.md`, `github/action.yml`) each negative-asserted to not contain `altimate.ai/install`. The intentional `altimate.ai/discord` link in `docs/mkdocs.yml` is positively asserted as still present (different path, marketing-site contact info, intentionally out of scope).
36
+ - **Cross-file host consistency** — the host used in the source `UPGRADE_INSTALL_URL` is automatically compared against every other reference in README, troubleshooting docs, install script, and action.yml. A future "drop the www." that updates the source but misses README will fail loudly.
37
+ - **`install --help` examples** — both examples in the `--help` block asserted (a previous half-fix had updated only the first); negative assertion against the legacy host on the help block specifically.
38
+ - **Bounded timeout** — `AbortSignal.timeout(` is wired, `UPGRADE_FETCH_TIMEOUT_MS = 15_000` is a named constant, the fetch references the constant by name, and a raw `AbortSignal.timeout(15_000)` literal is forbidden (would mean someone reverted the constant extraction).
39
+ - **Error surface** — the fetch lives inside a try/catch, the rethrown error message names the URL, includes the manual re-install one-liner with the URL templated through the constant, points at the GitHub releases fallback, and surfaces HTTP status codes (`HTTP ${res.status} ${res.statusText}`).
40
+ - **`github/action.yml` alignment** — install URL, cache path, `$GITHUB_PATH` addition, and final binary invocation all match the v0.7.1 rename; negative assertions against every legacy form. Action file existence asserted at `github/action.yml` (not `.github/action.yml`) since moving it would silently break every downstream consumer.
41
+ - **Marker integrity** — URL/timeout constants live inside an `altimate_change` block; try/catch wrapper lives inside an `altimate_change` block; balanced start/end count across the file.
42
+ - **Migration recovery surface** — troubleshooting doc still has the install-path section with the new URL; README curl one-liner matches the source's `UPGRADE_INSTALL_URL` host.
43
+ - **CHANGELOG presence** — release-skill backstop that catches a release commit without a 0.7.2 entry.
44
+
45
+ ## [0.7.1] - 2026-05-20
46
+
47
+ A focused provider-error pass plus the standalone-binary fix: the curl-installed binary now starts (previously crashed with `Cannot find module '@altimateai/altimate-core'`), is renamed to match the npm primary `bin` (`altimate-code` → `altimate` for the curl path only), and Alpine + Windows-on-ARM hit a clear early-exit instead of a cryptic gzip failure. Two 5-persona pre-release reviews (provider-error pass, then binary-fix + rename pass) drove the surface — 86 adversarial tests total pin the regression classes.
48
+
49
+ ### Fixed
50
+
51
+ - **Curl-installed standalone binary no longer crashes with `Cannot find module '@altimateai/altimate-core'` on first run.** The `script/build.ts` marked altimate-core as `external` (NAPI native modules can't live inside Bun's single-file bunfs), and the release archive shipped only the raw Bun binary — no companion `node_modules`, no NODE_PATH-aware wrapper. CI smoke tests hid the bug by pre-setting NODE_PATH against the developer checkout before invoking the binary. The fix stages a per-target copy of altimate-core whose loader is rewritten to a one-line shim `module.exports = require('./altimate-core.<platform>.node')`, drops the matching `.node` file next to it, and uses a `Bun.build` `onResolve` plugin to redirect every `@altimateai/altimate-core` import to that shim. Bun statically sees a single require and embeds that one `.node` into bunfs. Result: ~176 MB self-contained binary, no companion files, no NODE_PATH dance. CI smoke tests now run with `NODE_PATH` cleared from `$RUNNER_TEMP`, plus an independent `strings`-based content assertion that exactly one platform `.node` is embedded — the v0.5.10 / v0.7.0 class of regression is pinned by three independent guards. (#820)
52
+ - **Alpine Linux (musl) and Windows on ARM64 install paths now fail fast with actionable messages instead of silent 404 → tar/unzip errors.** Pre-fix, `curl … | bash` on an unsupported target would write GitHub's 404 HTML to disk and die "not in gzip format". The curl `install` script, the npm bin wrapper (`packages/opencode/bin/altimate`), the npm `postinstall.mjs`, and `script/build.ts` all detect these platforms early and point to `apk add gcompat` (Alpine) or x64 emulation / WSL (Windows ARM). The musl-detection logic is also `pipefail`-safe (`ldd --version` exits non-zero on musl by design; the previous pipeline-form inherited that failure and silently missed every non-Alpine musl distro). (#820)
53
+ - **Curl install `--fail` on both download paths.** A 404 / WAF block / TLS-rewriting corporate proxy no longer writes the error page to disk and gets unzipped as a binary; `curl --fail` exits non-zero and the install bails cleanly. (#820)
54
+ - **`script/build.ts --target-index=N` for an out-of-range index exits non-zero.** Pre-fix, after the musl/win32-arm64 cull, an invalid index silently produced zero artifacts and CI "succeeded" with no binary. (#820)
55
+ - **`script/build.ts --single` on a musl-linux host refuses to build the unrunnable glibc target.** Pre-fix the build would succeed but the resulting binary couldn't load on the host. (#820)
56
+ - **`Installation.method()` recognises `~/.altimate/bin` as a curl install.** The same release that renames the curl-install dir would have broken `altimate upgrade` for curl-installed users without this; the `.opencode/bin` and `.local/bin` branches stay for back-compat. (#820)
57
+ - **Provider 4xx errors now show the inner error message instead of a raw JSON dump.** When any provider returned the standard `{error: {message, type, code}}` shape (OpenAI, Azure OpenAI, OpenRouter, etc.), `parseAPICallError`'s extraction chain short-circuited on the truthy parent `error` object, the `typeof errMsg === "string"` guard rejected it, and the parser fell through to dumping the raw response body — which appeared as `APIError: Bad Request: {?:?}` after telemetry redaction collapsed string values to `?`. Telemetry caught users retrying broken model selections 3+ times in the same session because the surfaced error gave no clue about the cause. Users now see actionable text such as `APIError: Bad Request: The model 'gpt-5-codex' does not exist or you do not have access to it.` The OR-chain is replaced with explicit-typeof ternaries that mirror `parseStreamError`'s pattern, so a truthy non-string at any tier cannot block a valid string further down the chain. (#789, closes #788)
58
+ - **Bedrock / AWS Lambda `errorMessage` shape is now extracted.** AWS APIs that return `{errorMessage: "...", errorType: "..."}` (Lambda style) previously fell through the OpenAI/Anthropic-shaped chain to a raw-body dump. Added `body.errorMessage` to the extraction ladder in both `parseAPICallError` and `parseStreamError`.
59
+ - **Streaming error path no longer dumps `Unknown: {"type":"error",...}` for non-OpenAI codes.** `parseStreamError` previously handled only 4 OpenAI error codes (`context_length_exceeded`, `insufficient_quota`, `usage_not_included`, `invalid_prompt`); everything else fell through to `JSON.stringify(e)`. Added a default fallback that runs the same string-typeof chain as `parseAPICallError`, so any extractable provider message becomes a clean api_error.
60
+ - **`model_not_found` no longer triggers a silent retry storm.** OpenAI 404s are forced retryable in general (some legitimate models 404 transiently), but `error.code === "model_not_found"` now short-circuits to `isRetryable: false` — the user sees the actionable error on attempt 1 instead of after 5 silent retries.
61
+
62
+ ### Added
63
+
64
+ - **`altimate models` discoverability hint on model-not-found errors.** When `error.code === "model_not_found"`, the surfaced message now ends with `Run \`altimate models\` to see available models.` so the next step is one command away.
65
+ - **Provider-API-Errors troubleshooting reference** at `docs/docs/reference/troubleshooting.md` covering model-not-found, unauthorized, rate-limited, context-overflow, and HTML-page error classes.
66
+ - **Install-path troubleshooting section** at `docs/docs/reference/troubleshooting.md` covering "standalone binary not found after curl install" (the `altimate-code` → `altimate` rename), the legacy `Cannot find module '@altimateai/altimate-core'` crash with recovery instructions, Alpine/musl unsupported (with `apk add gcompat` workaround), and Windows-on-ARM unsupported (with WSL workaround). README also documents the curl-install option alongside the npm one.
67
+
68
+ ### Changed
69
+
70
+ - **Curl-installed binary renamed `altimate-code` → `altimate`** to match the npm package's primary `bin` entry. The npm path continues to expose **both** `altimate` and `altimate-code`, so existing `npm install -g`/`pnpm i -g` users see no behavioural change. Homebrew installs are unchanged (the formula installs `altimate` and symlinks `altimate-code` for back-compat). Only the standalone (`curl … | bash`) channel is affected — it now ships a single self-contained `altimate` binary to `~/.altimate/bin/` (was `~/.altimate-code/bin/altimate-code`). CI users with scripts that called `altimate-code` after the curl install should switch to `altimate` or install via npm. The install script removes any stale `~/.altimate/bin/altimate-code` left over from a pre-v0.7.1 install. (#820)
71
+ - **`check_version` probes both `altimate` and `altimate-code` on PATH** so an upgrade from v0.7.0 doesn't always re-download even when the version already matches. (#820)
72
+ - **Curl install final banner mirrors the npm postinstall**: `altimate`, `altimate run "hello"`, `altimate --help`, and the same `https://altimate-code.dev` docs URL. Rosetta-detected x64 → arm64 swap now emits a one-line muted notice instead of being silent. (#820)
73
+ - **`Installation.method()` upgrade detection recognises `~/.altimate/bin`** as a curl install (in addition to the legacy `~/.opencode/bin` and `~/.local/bin` paths). (#820)
74
+ - **`_requiredExports` literal extracted from `@altimateai/altimate-core/index.js` is JSON.parsed and shape-checked** before being inlined into the per-target staged shim. Pre-fix, the regex match group was inlined verbatim — a malicious altimate-core that published an `index.js` whose `_requiredExports = ["x"]; <attacker JS>; const _foo = [` form would have embedded attacker JavaScript into every shipped binary. The validator now requires a pure JSON array of non-empty short string literals; anything else aborts the build. (#820)
75
+ - **`build.ts` asserts the on-disk `@altimateai/altimate-core` version matches `package.json` declaration** after `bun install --os=* --cpu=*`. Catches the stale-hoist scenario where a previous version lingers in `node_modules/.bun/` and the new build silently embeds yesterday's `.node`. (#820)
76
+ - **Per-target staging dir is wiped before each build** (pre-loop cleanup), not just after, so a previous build that crashed between staging and post-build cleanup can never leak a stale `.altimate-core-staged/` into the next build's resolution. (#820)
77
+ - **Curl install extracts only the expected binary member** from tar/zip archives (`tar --no-same-owner -xzf … "$binary_name"` / `unzip … "$binary_name"`), so a future build mistake that tars a directory of attacker-controlled paths can't write them outside the explicit member. (#820)
78
+ - **`install_from_binary` guards against cp-on-self**: `--binary ~/.altimate/bin/altimate` no longer truncates the destination to empty via POSIX `cp` semantics. (#820)
79
+ - **Build matrix and standalone install matrix now align** — only platforms with a published `@altimateai/altimate-core` NAPI prebuild produce a release archive. (#820)
80
+
81
+ ### Removed
82
+
83
+ - **`linux-arm64-musl`, `linux-x64-musl`, `linux-x64-baseline-musl`, and `win32-arm64` archives** from the release build matrix. `@altimateai/altimate-core` has no NAPI prebuild for these targets; archives for them were never going to work. The npm wrapper (`bin/altimate`) and npm `postinstall.mjs` hard-error on these platforms with the same `apk add gcompat` / WSL workarounds the curl-install script uses. Re-added when upstream prebuilds ship. (#820)
84
+
85
+ ### Privacy
86
+
87
+ - **`Telemetry.maskString` now redacts email addresses and internal hostnames.** Pre-fix, the JSON-quote masking rule incidentally collapsed everything inside provider error JSON to `?`. The provider-error fix unwraps that JSON, which means provider-side identifiers (caller emails, internal `*.local` / `*.internal` / RFC1918 / IPv6 loopback / ULA / link-local / AWS IMDS endpoints) now flow as plain English. Added explicit redaction patterns so they're masked before reaching telemetry, the share backend, or local session storage. The masker is kept in sync with `parseAPICallError`'s `maskInternalHost` (same internal-endpoint coverage); query-string and fragment characters (`+`, `#`, `,`, `;`) are inside the trailing char class so secrets past the `<internal-host>` marker don't survive. `sk-…` and `Bearer …` token redaction is unchanged.
88
+ - **`metadata.url` on `MessageV2.APIError` masks internal hosts and strips basic-auth userinfo.** When `error.url` points at `localhost`, `*.local`, `*.internal`, an RFC1918 IPv4, IPv6 loopback / ULA / link-local, or the AWS IMDS address (`169.254.169.254`), the host is rewritten to `internal-host.redacted` before the URL lands on the parsed error. Basic-auth userinfo (`user:pass@…`) is stripped on **every** URL — internal or public — since a credential in a public-host URL is at least as risky as one in an internal proxy. Public-host URLs are otherwise preserved verbatim for debugging.
89
+ - **`responseBody` is capped at 4KB** at the `parseAPICallError` boundary. Without this, a hostile or verbose gateway could persist a 100KB+ body into local storage and (for shared sessions) the share backend.
90
+
91
+ ### Testing
92
+
93
+ - 46 adversarial tests covering JSON-scalar bodies, prototype-pollution attempts, 100KB error messages, malformed JSON, every-tier null/numeric extraction, Bedrock `errorMessage` precedence, the `parseStreamError` fallback for unknown codes, the `model_not_found` retry-storm carve-out, the `altimate models` hint, the responseBody cap, the metadata.url internal-host masking (incl. IPv6 loopback/ULA/link-local, AWS IMDS, public-host basic-auth userinfo strip, RFC1918 boundary checks, lookalike-hostname guards), and the new email / internal-host `maskString` patterns (incl. IMDS, IPv6, and query-fragment leak guards).
94
+ - 48 adversarial tests in `release-v0.7.1-binary-adversarial.test.ts` pinning the binary-fix + rename surface — install-method upgrade-path detection (`.altimate`/`.opencode`/`.local` triple-cover), curl-install hardening (Rosetta notice, cp-on-self guard, stale `altimate-code` cleanup, explicit tar/zip member extraction, dual `check_version` probe, musl + npm gcompat messaging, `--fail` on both curl paths, `pipefail`-safe ldd capture, no musl target-suffix construction), `_requiredExports` JSON.parse + shape-check rejection, altimate-core version pinning + actionable rebuild hint, staging-dir pre-loop wipe + post-build cleanup, empty-targets and musl-host build guards, build matrix excluding linux-musl + win32-arm64, smoke-test hermeticity (host-platform `findLocalBinary` filter + tmpdir cwd + content-level `strings` assertion), npm-wrapper + postinstall fail-fast parity for musl + win32-arm64, troubleshooting and README doc surface, archive-name + bin-rename cross-file invariants, and `release.yml` hermetic CI smoke tests + narrowed `publish-npm` permissions. Tests run together with the provider-error suite as the release-critical gate (`test/branding/ test/install/ test/skill/release-v0.7.1*`).
95
+ - Smoke tests (`test/install/smoke-test-binary.test.ts`) gained: hermetic `NODE_PATH`-cleared invocation from a fresh tmpdir (so Bun's compiled binary cannot walk the worktree for `node_modules`), and a content-level `strings`-based assertion that exactly one platform `.node` is embedded in the compiled binary — independent of any runtime resolution path, so a silent `onResolve` regression that embeds 5 platforms' worth of `.node` files would fire here even if the runtime test passes by accident. (#820)
96
+
8
97
  ## [0.7.0] - 2026-05-03
9
98
 
10
99
  ### Changed
package/README.md CHANGED
@@ -28,6 +28,14 @@ into CI pipelines and orchestration DAGs. Precision data tooling for any LLM.
28
28
  npm install -g altimate-code
29
29
  ```
30
30
 
31
+ Or via curl (installs the `altimate` binary to `~/.altimate/bin`):
32
+
33
+ ```bash
34
+ curl -fsSL https://www.altimate.sh/install | bash
35
+ ```
36
+
37
+ The curl install drops a single self-contained binary named `altimate`. The npm install exposes both `altimate` and `altimate-code` on PATH; the curl install only exposes `altimate`. Alpine Linux (musl) and Windows on ARM64 are not currently supported by the standalone binary — use `apk add gcompat` on Alpine, or use WSL on Windows-on-ARM.
38
+
31
39
  Then — in order:
32
40
 
33
41
  **Step 1: Configure your LLM provider** (required before anything works):
package/bin/altimate CHANGED
@@ -153,42 +153,51 @@ function supportsAvx2() {
153
153
  return false
154
154
  }
155
155
 
156
+ function isMusl() {
157
+ if (platform !== "linux") return false
158
+ try {
159
+ if (fs.existsSync("/etc/alpine-release")) return true
160
+ } catch {
161
+ // ignore
162
+ }
163
+ try {
164
+ const result = childProcess.spawnSync("ldd", ["--version"], { encoding: "utf8" })
165
+ const text = ((result.stdout || "") + (result.stderr || "")).toLowerCase()
166
+ if (text.includes("musl")) return true
167
+ } catch {
168
+ // ignore
169
+ }
170
+ return false
171
+ }
172
+
173
+ // @altimateai/altimate-core has no NAPI prebuild for musl or win32-arm64,
174
+ // and the altimate binary embeds altimate-core's .node file at build time.
175
+ // Hard-error early instead of letting findBinary() walk the whole tree and
176
+ // emit a misleading "package manager failed to install the right version"
177
+ // message — the right diagnosis is that these platforms aren't built.
178
+ if (isMusl()) {
179
+ console.error("altimate-code is not currently supported on Alpine Linux (musl).")
180
+ console.error("Workarounds:")
181
+ console.error(" • apk add gcompat # run glibc binaries on Alpine")
182
+ console.error(" • Use a glibc-based container (debian/ubuntu/alpine+gcompat)")
183
+ process.exit(1)
184
+ }
185
+ if (platform === "windows" && arch === "arm64") {
186
+ console.error("altimate-code is not currently built for Windows on ARM64.")
187
+ console.error("Run the x64 build under Windows ARM's x64 emulation, or use WSL.")
188
+ process.exit(1)
189
+ }
190
+
156
191
  const names = (() => {
157
192
  const avx2 = supportsAvx2()
158
193
  const baseline = arch === "x64" && !avx2
159
194
 
160
195
  if (platform === "linux") {
161
- const musl = (() => {
162
- try {
163
- if (fs.existsSync("/etc/alpine-release")) return true
164
- } catch {
165
- // ignore
166
- }
167
-
168
- try {
169
- const result = childProcess.spawnSync("ldd", ["--version"], { encoding: "utf8" })
170
- const text = ((result.stdout || "") + (result.stderr || "")).toLowerCase()
171
- if (text.includes("musl")) return true
172
- } catch {
173
- // ignore
174
- }
175
-
176
- return false
177
- })()
178
-
179
- if (musl) {
180
- if (arch === "x64") {
181
- if (baseline) return [`${base}-baseline-musl`, `${base}-musl`, `${base}-baseline`, base]
182
- return [`${base}-musl`, `${base}-baseline-musl`, base, `${base}-baseline`]
183
- }
184
- return [`${base}-musl`, base]
185
- }
186
-
187
196
  if (arch === "x64") {
188
- if (baseline) return [`${base}-baseline`, base, `${base}-baseline-musl`, `${base}-musl`]
189
- return [base, `${base}-baseline`, `${base}-musl`, `${base}-baseline-musl`]
197
+ if (baseline) return [`${base}-baseline`, base]
198
+ return [base, `${base}-baseline`]
190
199
  }
191
- return [base, `${base}-musl`]
200
+ return [base]
192
201
  }
193
202
 
194
203
  if (arch === "x64") {
package/package.json CHANGED
@@ -14,24 +14,20 @@
14
14
  "scripts": {
15
15
  "postinstall": "bun ./postinstall.mjs || node ./postinstall.mjs"
16
16
  },
17
- "version": "0.7.0",
17
+ "version": "0.7.2",
18
18
  "license": "MIT",
19
19
  "dependencies": {
20
20
  "@altimateai/altimate-core": "0.3.1"
21
21
  },
22
22
  "optionalDependencies": {
23
- "@altimateai/altimate-code-linux-x64-musl": "0.7.0",
24
- "@altimateai/altimate-code-linux-x64-baseline": "0.7.0",
25
- "@altimateai/altimate-code-windows-arm64": "0.7.0",
26
- "@altimateai/altimate-code-darwin-arm64": "0.7.0",
27
- "@altimateai/altimate-code-windows-x64-baseline": "0.7.0",
28
- "@altimateai/altimate-code-linux-arm64": "0.7.0",
29
- "@altimateai/altimate-code-linux-x64-baseline-musl": "0.7.0",
30
- "@altimateai/altimate-code-darwin-x64-baseline": "0.7.0",
31
- "@altimateai/altimate-code-windows-x64": "0.7.0",
32
- "@altimateai/altimate-code-darwin-x64": "0.7.0",
33
- "@altimateai/altimate-code-linux-x64": "0.7.0",
34
- "@altimateai/altimate-code-linux-arm64-musl": "0.7.0"
23
+ "@altimateai/altimate-code-windows-x64": "0.7.2",
24
+ "@altimateai/altimate-code-linux-x64": "0.7.2",
25
+ "@altimateai/altimate-code-linux-arm64": "0.7.2",
26
+ "@altimateai/altimate-code-windows-x64-baseline": "0.7.2",
27
+ "@altimateai/altimate-code-darwin-arm64": "0.7.2",
28
+ "@altimateai/altimate-code-linux-x64-baseline": "0.7.2",
29
+ "@altimateai/altimate-code-darwin-x64": "0.7.2",
30
+ "@altimateai/altimate-code-darwin-x64-baseline": "0.7.2"
35
31
  },
36
32
  "peerDependencies": {
37
33
  "pg": ">=8",
package/postinstall.mjs CHANGED
@@ -47,8 +47,49 @@ function detectPlatformAndArch() {
47
47
  return { platform, arch }
48
48
  }
49
49
 
50
+ function isMuslPlatform() {
51
+ if (os.platform() !== "linux") return false
52
+ try {
53
+ if (fs.existsSync("/etc/alpine-release")) return true
54
+ } catch {
55
+ // ignore
56
+ }
57
+ try {
58
+ // Mirror the detection in packages/opencode/bin/altimate: on musl
59
+ // systems `ldd --version` exits non-zero and prints to stderr.
60
+ // execSync would throw AND only return stdout — silently missing every
61
+ // non-Alpine musl distro. spawnSync gives both streams regardless of
62
+ // exit code.
63
+ const { spawnSync } = require("child_process")
64
+ const result = spawnSync("ldd", ["--version"], { encoding: "utf8" })
65
+ const text = ((result.stdout || "") + (result.stderr || "")).toLowerCase()
66
+ if (text.includes("musl")) return true
67
+ } catch {
68
+ // ignore — ldd may not exist at all
69
+ }
70
+ return false
71
+ }
72
+
50
73
  function findBinary() {
51
74
  const { platform, arch } = detectPlatformAndArch()
75
+
76
+ // @altimateai/altimate-core has no NAPI prebuild for musl or win32-arm64,
77
+ // and the altimate binary embeds altimate-core's .node at build time. Emit
78
+ // a clear, actionable error here rather than the generic
79
+ // "Could not find package" message that would otherwise fall out below.
80
+ if (isMuslPlatform()) {
81
+ throw new Error(
82
+ "altimate-code is not currently supported on Alpine Linux (musl). " +
83
+ "Run 'apk add gcompat' to execute glibc binaries on Alpine, or use a glibc-based base image.",
84
+ )
85
+ }
86
+ if (platform === "windows" && arch === "arm64") {
87
+ throw new Error(
88
+ "altimate-code is not currently built for Windows on ARM64. " +
89
+ "Run the x64 build under Windows ARM's x64 emulation, or use WSL.",
90
+ )
91
+ }
92
+
52
93
  const packageName = `@altimateai/altimate-code-${platform}-${arch}`
53
94
  const binaryName = platform === "windows" ? "altimate-code.exe" : "altimate-code"
54
95