altimate-code 0.7.0 → 0.7.1

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,58 @@ 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-20
9
+
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
+
12
+ ### Fixed
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)
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)
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`.
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.
23
+ - **`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.
24
+
25
+ ### Added
26
+
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.
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)
47
+
48
+ ### Privacy
49
+
50
+ - **`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.
51
+ - **`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.
52
+ - **`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.
53
+
54
+ ### Testing
55
+
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)
59
+
8
60
  ## [0.7.0] - 2026-05-03
9
61
 
10
62
  ### 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://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):
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.1",
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.1",
24
+ "@altimateai/altimate-code-linux-x64": "0.7.1",
25
+ "@altimateai/altimate-code-linux-arm64": "0.7.1",
26
+ "@altimateai/altimate-code-windows-x64-baseline": "0.7.1",
27
+ "@altimateai/altimate-code-darwin-arm64": "0.7.1",
28
+ "@altimateai/altimate-code-linux-x64-baseline": "0.7.1",
29
+ "@altimateai/altimate-code-darwin-x64": "0.7.1",
30
+ "@altimateai/altimate-code-darwin-x64-baseline": "0.7.1"
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