You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Copy file name to clipboardExpand all lines: CHANGELOG.md
+28-2Lines changed: 28 additions & 2 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -5,12 +5,18 @@ 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.1] - 2026-05-06
8
+
## [0.7.1] - 2026-05-20
9
9
10
-
A focused pass on provider error handling, surfaced by a 5-persona pre-release review.
10
+
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.
11
11
12
12
### Fixed
13
13
14
+
- **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)
15
+
-**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)
16
+
-**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)
17
+
-**`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)
18
+
-**`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)
19
+
-**`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)
14
20
-**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)
15
21
-**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`.
16
22
-**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.
@@ -20,6 +26,24 @@ A focused pass on provider error handling, surfaced by a 5-persona pre-release r
20
26
21
27
-**`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.
22
28
-**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.
29
+
-**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.
30
+
31
+
### Changed
32
+
33
+
-**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)
34
+
-**`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)
35
+
-**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)
36
+
-**`Installation.method()` upgrade detection recognises `~/.altimate/bin`** as a curl install (in addition to the legacy `~/.opencode/bin` and `~/.local/bin` paths). (#820)
37
+
-**`_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)
38
+
-**`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)
39
+
-**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)
40
+
-**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)
41
+
-**`install_from_binary` guards against cp-on-self**: `--binary ~/.altimate/bin/altimate` no longer truncates the destination to empty via POSIX `cp` semantics. (#820)
42
+
-**Build matrix and standalone install matrix now align** — only platforms with a published `@altimateai/altimate-core` NAPI prebuild produce a release archive. (#820)
43
+
44
+
### Removed
45
+
46
+
-**`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)
23
47
24
48
### Privacy
25
49
@@ -30,6 +54,8 @@ A focused pass on provider error handling, surfaced by a 5-persona pre-release r
30
54
### Testing
31
55
32
56
- 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).
57
+
- 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*`).
58
+
- 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)
Copy file name to clipboardExpand all lines: README.md
+8Lines changed: 8 additions & 0 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -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://altimate.ai/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):
Copy file name to clipboardExpand all lines: docs/docs/reference/troubleshooting.md
+52Lines changed: 52 additions & 0 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -1,5 +1,57 @@
1
1
# Troubleshooting
2
2
3
+
## Installation
4
+
5
+
### Standalone binary not found after curl install
6
+
7
+
**Symptoms:**`altimate-code: command not found` after running `curl -fsSL https://altimate.ai/install | bash`.
8
+
9
+
As of v0.7.1 the curl-installed binary is named `altimate`, not `altimate-code`. The npm package continues to ship both names. If you scripted against the curl install:
10
+
11
+
```bash
12
+
# Before (v0.7.0 and earlier curl install):
13
+
~/.altimate-code/bin/altimate-code run "..."
14
+
15
+
# After (v0.7.1+ curl install):
16
+
~/.altimate/bin/altimate run "..."
17
+
```
18
+
19
+
Or stay on the `altimate-code` name by installing via npm: `npm install -g altimate-code`.
**Symptoms:** Binary crashes on first run with the above error (curl-installed v0.7.0 and earlier).
24
+
25
+
The v0.7.0 curl install shipped without the NAPI native module. Fixed in v0.7.1 — the native module is now embedded directly into the binary. Re-install with:
26
+
27
+
```bash
28
+
curl -fsSL https://altimate.ai/install | bash
29
+
```
30
+
31
+
### Alpine Linux (musl) not supported
32
+
33
+
**Symptoms:**`Alpine Linux (musl) is not currently supported by the standalone install` during curl install, or `altimate-code is not currently supported on Alpine Linux (musl)` during `npm install` postinstall.
34
+
35
+
`@altimateai/altimate-core` has no NAPI prebuild for musl. Workarounds:
36
+
37
+
```bash
38
+
# Run the glibc binary under Alpine (recommended):
0 commit comments