@shuyhere/bb-agent 0.0.15 → 0.0.17

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,27 +5,83 @@ All notable changes to BB-Agent 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
+ ## [Unreleased]
9
+
10
+ ## [0.0.17] - 2026-04-17
11
+
12
+ ### Added
13
+
14
+ - added the reusable `bb-monitor` backend crate and wired request metrics, session usage summaries, and cache provenance tracking through it
15
+ - added a dedicated under-input TUI cache monitor that shows cache source plus average and latest request hit rate
16
+ - added a profile-aware auth store with saved timestamps, active-profile tracking, and richer provider auth summaries in `/model`
17
+
18
+ ### Changed
19
+
20
+ - `/model` now supports choosing auth source/profile as part of model selection when a provider has multiple usable auth options
21
+ - `/login` now exposes concrete auth-option choosers instead of only coarse method picks, including switching among saved/env-backed auth and starting new provider logins from the same flow
22
+ - providers that support it can now keep multiple saved OAuth profiles and multiple saved API-key profiles side-by-side for the same provider, with safe labels to distinguish saved keys
23
+
24
+ ### Fixed
25
+
26
+ - OpenAI GPT-5 API-key requests now use the Responses API when tools/reasoning are involved instead of failing against chat completions with `reasoning_effort` errors
27
+ - `/session` now reports the live session auth override when auth was explicitly selected in-session instead of falling back to default provider resolution
28
+ - auth/profile menus now disambiguate saved API-key profiles even when labels would otherwise look too similar
29
+
30
+ ### Improved
31
+
32
+ - footer, `/session`, `/login`, and `/model` now present provider auth state more consistently, including explicit auth method/source/account details and safer saved-profile switching flows
33
+ - cache monitor visibility and provider-metric provenance are clearer across session summaries, request tracking, and the TUI monitor line
34
+
35
+ ## [0.0.16] - 2026-04-15
36
+
37
+ ### Added
38
+
39
+ - added `bb setup browser`, including platform-specific guidance and optional shell-profile persistence for configuring `BB_BROWSER`
40
+ - added a dedicated release-notes draft for `v0.0.16` under `docs/release-notes-0.0.16.md`
41
+
42
+ ### Changed
43
+
44
+ - user-facing terminology now consistently uses **TUI** instead of legacy `fullscreen` wording, including CLI/help/docs text and internal module/type naming
45
+ - markdown code blocks and bash tool previews in the TUI now render as raw fenced blocks for easier copying and pasting
46
+ - tool availability, advertised schemas, transcript validation, and tool execution now follow a shared architecture with a single CLI `ToolRegistry`, centralized provider transcript repair, explicit tool lifecycle phases, lifecycle hook events, and mutation-aware scheduling for real tool execution
47
+ - release builds and npm installs now prefer stripped/compressed native binaries, reducing download size and improving install/update behavior
48
+
49
+ ### Fixed
50
+
51
+ - `browser_fetch` now gives actionable missing-browser diagnostics and setup guidance instead of failing opaquely when no local browser is installed
52
+ - TUI footer context usage no longer gets stuck at misleading values like `0.0%/272k (auto)` after resume/rebuild/fork paths
53
+ - queued prompt previews no longer hide compaction/local-action status, and fast local actions no longer flash meaningless `0ms` / `0.0s` timing
54
+ - failed or interrupted tool calls no longer wedge later prompts with provider-side `No tool output found ...` errors; transcript repair and lifecycle finalization now guarantee a valid follow-up turn state
55
+ - join-timeout warnings no longer make an active TUI turn look finished before the runner actually completes
56
+ - clean `bb-cli` builds no longer emit dead-code warnings from the new tool registry surface, and secret-bearing auth/token structs now redact sensitive fields in debug output instead of exposing raw credentials
57
+
58
+ ### Improved
59
+
60
+ - ongoing Rust audit cleanup significantly reduced boolean-heavy APIs, overexposed state, and hotspot modules across `bb-cli`, `bb-core`, `bb-tools`, `bb-session`, `bb-tui`, `bb-provider`, `bb-plugin-host`, and `bb-hooks`, with expanded focused regression coverage throughout
61
+ - npm install now prefers compressed `.gz` GitHub release assets when available, falling back to the legacy uncompressed binaries for older releases
62
+ - release builds now strip debug info before publishing, substantially reducing native binary download size for npm installs and updates
63
+
8
64
  ## [0.0.15] - 2026-04-12
9
65
 
10
66
  ### Fixed
11
67
 
12
- - fullscreen bash output now streams live stdout/stderr and keeps running, finished, historical, and expanded/collapsed tool blocks visually consistent with width-aware tail previews and elapsed/took footer hints
68
+ - tui bash output now streams live stdout/stderr and keeps running, finished, historical, and expanded/collapsed tool blocks visually consistent with width-aware tail previews and elapsed/took footer hints
13
69
  - bash tool titles now skip shell prelude lines like `set -e`, show configured timeout values in the UI, and validate invalid timeout arguments instead of accepting zero or non-finite values
14
70
  - fixed the session getting stuck after interrupted or failed tool calls by flushing synthetic tool results before later prompts, preventing follow-up turns from failing with missing tool output
15
71
  - Codex tool-call request handling is more robust: tool calls are serialized sequentially, orphan tool results are sanitized out of requests, and streamed/done function-call events are deduplicated more safely
16
72
  - plain URLs and hyphenated text no longer trigger accidental markdown horizontal-rule rendering while explicit markdown rules and setext headings still render correctly
17
- - fullscreen resume menu handling now awaits the async resume path correctly instead of dropping back through the synchronous menu flow
73
+ - tui resume menu handling now awaits the async resume path correctly instead of dropping back through the synchronous menu flow
18
74
 
19
75
  ### Added
20
76
 
21
- - regression coverage for interrupted tool-call recovery, Codex orphan-tool sanitization, builtin tool-name normalization, fullscreen bash rendering consistency, and bash timeout validation/visibility
77
+ - regression coverage for interrupted tool-call recovery, Codex orphan-tool sanitization, builtin tool-name normalization, tui bash rendering consistency, and bash timeout validation/visibility
22
78
 
23
79
  ## [0.0.14] - 2026-04-12
24
80
 
25
81
  ### Added
26
82
 
27
- - fullscreen now supports extension-driven workflows and structured slash-command outcomes, including menus, hidden dispatches, and richer command result handling
28
- - `/settings` in fullscreen now exposes compaction controls for `Auto-compact`, `Reserve tokens`, and `Keep recent tokens`
83
+ - tui now supports extension-driven workflows and structured slash-command outcomes, including menus, hidden dispatches, and richer command result handling
84
+ - `/settings` in tui now exposes compaction controls for `Auto-compact`, `Reserve tokens`, and `Keep recent tokens`
29
85
  - skills can now be listed, disabled, and re-enabled from the CLI without deleting their installed files
30
86
  - startup model selection now prefers configured provider/model defaults more consistently, with better OpenAI startup fallback behavior
31
87
  - added a parity test script against installed pi compaction logic to keep BB token accounting aligned with upstream behavior
@@ -33,39 +89,39 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
33
89
  ### Fixed
34
90
 
35
91
  - session resume now restores the prior model and thinking level instead of starting with mismatched runtime defaults
36
- - fullscreen/TUI terminal rendering now sanitizes terminal control text more reliably and avoids ANSI leakage into the UI
92
+ - tui/TUI terminal rendering now sanitizes terminal control text more reliably and avoids ANSI leakage into the UI
37
93
  - auto-compaction token estimation now matches pi more closely by using the last successful assistant usage plus trailing estimates, using ceil-based token heuristics, computing `tokens_before` from rebuilt context instead of raw payload size, and ignoring assistant usage from before the latest compaction boundary
38
- - fullscreen compaction behavior and status reporting are more consistent after auto-compaction and manual compaction events, and local fullscreen actions now show an animated elapsed-time status while they run
94
+ - tui compaction behavior and status reporting are more consistent after auto-compaction and manual compaction events, and local tui actions now show an animated elapsed-time status while they run
39
95
 
40
96
  ### Changed
41
97
 
42
- - fullscreen extension workflows and session compaction support are now merged into the main interaction path on `master`
98
+ - tui extension workflows and session compaction support are now merged into the main interaction path on `master`
43
99
 
44
100
  ## [0.0.13] - 2026-04-09
45
101
 
46
102
  ### Added
47
103
 
48
- - fullscreen screenshot and image clipboard paste now works on the normal paste path, with macOS clipboard fallbacks and Codex image preservation so pasted images reach image-capable models correctly
104
+ - tui screenshot and image clipboard paste now works on the normal paste path, with macOS clipboard fallbacks and Codex image preservation so pasted images reach image-capable models correctly
49
105
  - model registry metadata now tracks image input capability, making `/models` truthful about image support and allowing runtime warnings when users attach images to text-only models
50
106
 
51
107
  ### Fixed
52
108
 
53
- - fullscreen clipboard image attach no longer leaks helper `true` / `false` output or stray follow-up paste text into the input block
109
+ - tui clipboard image attach no longer leaks helper `true` / `false` output or stray follow-up paste text into the input block
54
110
  - attached image chips can now be removed with `Backspace`, image-only prompts can be submitted, and optimistic user messages keep attachment chip previews in the transcript
55
- - rebuilt fullscreen session transcripts now preserve user image attachment markers instead of silently dropping image blocks
111
+ - rebuilt tui session transcripts now preserve user image attachment markers instead of silently dropping image blocks
56
112
  - managed `bb-clipboard-*.png` temp files are now cleaned up after removal or ingestion instead of lingering in `/tmp`
57
- - the fullscreen input block now hides raw `@file` tokens when the corresponding attachment chip is already shown, preventing duplicated `@file` text in the editor
58
- - fullscreen tool-header regression tests now match the intended live bash-header rendering and running-dot animation behavior
113
+ - the tui input block now hides raw `@file` tokens when the corresponding attachment chip is already shown, preventing duplicated `@file` text in the editor
114
+ - tui tool-header regression tests now match the intended live bash-header rendering and running-dot animation behavior
59
115
 
60
116
  ## [0.0.12] - 2026-04-06
61
117
 
62
118
  ### Fixed
63
119
 
64
- - direct `@image` references in print mode and fullscreen now attach real image inputs instead of falling back to UTF-8 read warnings
120
+ - direct `@image` references in print mode and tui now attach real image inputs instead of falling back to UTF-8 read warnings
65
121
  - `@path with spaces` parsing now correctly keeps the full file path before trailing prompt text, including whole-message forms
66
122
  - image tool results are now preserved through provider conversion so models can actually see images returned by tools instead of responding as if no image was provided
67
- - fullscreen `@` folder navigation now keeps the completion menu open when you select a directory and immediately shows the next level, including directories with spaces
68
- - the fullscreen input block now shows attached files as `[name, sizeKB]`, keeps those chips visible, and places the cursor below them so typing starts after the attachments
123
+ - tui `@` folder navigation now keeps the completion menu open when you select a directory and immediately shows the next level, including directories with spaces
124
+ - the tui input block now shows attached files as `[name, sizeKB]`, keeps those chips visible, and places the cursor below them so typing starts after the attachments
69
125
 
70
126
  ### Changed
71
127
 
@@ -75,9 +131,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
75
131
 
76
132
  ### Added
77
133
 
78
- - startup update notices in the fullscreen transcript are now highlighted so available updates stand out clearly during startup
79
- - read-tool line ranges in fullscreen tool activity now highlight the requested span, so values like `2148-2267/5006` stand out while the model is using tools
80
- - fullscreen footer and `/session` info now show the active execution posture so safety vs yolo is visible during a run
134
+ - startup update notices in the tui transcript are now highlighted so available updates stand out clearly during startup
135
+ - read-tool line ranges in tui tool activity now highlight the requested span, so values like `2148-2267/5006` stand out while the model is using tools
136
+ - tui footer and `/session` info now show the active execution posture so safety vs yolo is visible during a run
81
137
 
82
138
  ### Improved
83
139
 
@@ -96,7 +152,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
96
152
 
97
153
  - npm install now uses a longer timeout, retries release-binary downloads, and reports real download errors instead of incorrectly saying no matching prebuilt binary exists
98
154
  - npm install now shows progress logs during native binary download and verification so first-time installs on macOS/Linux are less confusing
99
- - fullscreen `/login` provider-family status now correctly shows OpenAI OAuth state after ChatGPT login instead of incorrectly showing the API key path as not authenticated
155
+ - tui `/login` provider-family status now correctly shows OpenAI OAuth state after ChatGPT login instead of incorrectly showing the API key path as not authenticated
100
156
 
101
157
  ### Changed
102
158
 
@@ -112,9 +168,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
112
168
 
113
169
  ### Fixed
114
170
 
115
- - fullscreen paste in iTerm2/SSH no longer corrupts the input area after paste
171
+ - tui paste in iTerm2/SSH no longer corrupts the input area after paste
116
172
  - pasted file and image paths are normalized more reliably, including quoted paths and `file://` URLs
117
- - fullscreen prompt submission now expands `@file` references consistently
173
+ - tui prompt submission now expands `@file` references consistently
118
174
  - running tool timers continue updating after `TurnEnd` while tools are still executing
119
175
  - sub-second tool durations now display as `ms` instead of `0.0s`
120
176
  - startup Skills/Prompts/Extensions note now only appears at startup or explicit `/reload`
@@ -122,7 +178,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
122
178
 
123
179
  ### Changed
124
180
 
125
- - fullscreen `Ctrl+V` now falls back to clipboard text when no clipboard image is available
181
+ - tui `Ctrl+V` now falls back to clipboard text when no clipboard image is available
126
182
  - `@` autocomplete now inserts quoted file references when paths contain spaces
127
183
 
128
184
  ## [0.0.8] - 2026-04-06
@@ -143,6 +199,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
143
199
 
144
200
  - latest published package includes the post-0.0.7 startup, auth, model-default, and update-notice improvements
145
201
 
202
+ [0.0.17]: https://github.com/shuyhere/bb-agent/releases/tag/v0.0.17
203
+ [0.0.16]: https://github.com/shuyhere/bb-agent/releases/tag/v0.0.16
204
+ [0.0.15]: https://github.com/shuyhere/bb-agent/releases/tag/v0.0.15
146
205
  [0.0.14]: https://github.com/shuyhere/bb-agent/releases/tag/v0.0.14
147
206
  [0.0.13]: https://github.com/shuyhere/bb-agent/releases/tag/v0.0.13
148
207
  [0.0.12]: https://github.com/shuyhere/bb-agent/releases/tag/v0.0.12
package/README.md CHANGED
@@ -4,7 +4,7 @@
4
4
 
5
5
  > BB means Bridge Baby in Death Stranding. I named this project that way because while building it, I was also enjoying Death Stranding and loved the idea of connecting everyone together.
6
6
 
7
- A Rust-native AI coding agent for the terminal — featuring a fullscreen TUI, multi-provider support, tool use, session persistence, branching, extensions, and skills.
7
+ A Rust-native AI coding agent for the terminal — featuring a TUI, multi-provider support, tool use, session persistence, branching, extensions, and skills.
8
8
 
9
9
  ## Install
10
10
 
@@ -17,7 +17,7 @@ npm install -g @shuyhere/bb-agent
17
17
  npm install downloads a small wrapper package first, then fetches the matching native BB-Agent binary from the GitHub release for your platform.
18
18
 
19
19
  What to expect:
20
- - first install can take a bit because npm downloads and verifies the native binary
20
+ - first install can take a bit because npm downloads a compressed native binary, expands it locally, and verifies it
21
21
  - the installer now prints progress and retry information while downloading
22
22
  - after install, run `bb`
23
23
 
@@ -68,7 +68,7 @@ Inside the TUI, run:
68
68
  /login
69
69
  ```
70
70
 
71
- This opens the provider picker and auth flow directly in the fullscreen UI.
71
+ This opens the provider picker and auth flow directly in the TUI.
72
72
 
73
73
  If you prefer, you can also log in from a normal terminal:
74
74
 
@@ -81,12 +81,12 @@ bb login google # Login to Google (API key)
81
81
 
82
82
  Or set environment variables: `ANTHROPIC_API_KEY`, `OPENAI_API_KEY`, `GOOGLE_API_KEY`, etc.
83
83
 
84
- That's it! Run `bb` to launch the fullscreen interactive terminal UI. Type your prompt and press Enter.
84
+ That's it! Run `bb` to launch the interactive TUI. Type your prompt and press Enter.
85
85
 
86
86
  ### More ways to use `bb`
87
87
 
88
88
  ```bash
89
- bb # Launch the fullscreen TUI
89
+ bb # Launch the TUI
90
90
  bb "Explain this codebase" # TUI with an initial prompt
91
91
  bb -p "What is 2+2?" # Print mode (non-interactive, pipe-friendly)
92
92
  bb -c # Continue your last session
@@ -98,7 +98,7 @@ bb --list-models # List all available models
98
98
 
99
99
  ## Features
100
100
 
101
- - **Fullscreen TUI** — rich terminal interface with streaming output, markdown rendering, syntax highlighting
101
+ - **TUI** — rich terminal interface with streaming output, markdown rendering, syntax highlighting
102
102
  - **Multi-provider** — Anthropic (Claude), OpenAI, Google (Gemini), Groq, xAI, OpenRouter, and custom OpenAI-compatible endpoints
103
103
  - **Built-in tools** — `read`, `write`, `edit`, `bash`, `find`, `grep`, `ls`, `web_search`, `web_fetch`, `browser_fetch`
104
104
  - **Safety and yolo execution modes** — default safety posture restricts built-in `write` and `edit` to the active workspace; yolo removes that guard
@@ -165,7 +165,7 @@ BB-Agent uses layered configuration:
165
165
 
166
166
  ### Execution Modes
167
167
 
168
- BB-Agent exposes the active permission posture in fullscreen and `/session`.
168
+ BB-Agent exposes the active permission posture in the TUI and `/session`.
169
169
 
170
170
  - `safety` is the default. Built-in `write` and `edit` stay inside the current workspace, and bash commands use the safer approval/sandboxed posture.
171
171
  - `yolo` is the opt-in less-restrictive mode.
@@ -202,14 +202,14 @@ Example:
202
202
  | `bb-provider` | Model/provider integrations and streaming |
203
203
  | `bb-hooks` | Hook event types for extensions |
204
204
  | `bb-plugin-host` | Plugin discovery and host runtime |
205
- | `bb-tui` | Terminal UI components and fullscreen experience |
205
+ | `bb-tui` | Terminal UI components and the interactive TUI experience |
206
206
  | `bb-cli` | The `bb` command-line application |
207
207
 
208
208
  ## Troubleshooting
209
209
 
210
210
  ### Terminal & Font Compatibility
211
211
 
212
- BB-Agent uses Unicode glyphs and ANSI color in the fullscreen TUI. For the best visual experience, use a modern terminal and a Unicode-capable monospace font such as:
212
+ BB-Agent uses Unicode glyphs and ANSI color in the TUI. For the best visual experience, use a modern terminal and a Unicode-capable monospace font such as:
213
213
 
214
214
  - JetBrains Mono
215
215
  - SF Mono / Menlo
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@shuyhere/bb-agent",
3
- "version": "0.0.15",
3
+ "version": "0.0.17",
4
4
  "description": "BB-Agent — a Rust-native AI coding agent for the terminal",
5
5
  "license": "MIT",
6
6
  "repository": {
@@ -8,6 +8,8 @@ const path = require("path");
8
8
  const os = require("os");
9
9
  const https = require("https");
10
10
  const http = require("http");
11
+ const zlib = require("zlib");
12
+ const { pipeline } = require("stream/promises");
11
13
 
12
14
  const packageJson = require("../package.json");
13
15
  const BINARY_RELEASE_TAG = `v${packageJson.version}`;
@@ -51,6 +53,20 @@ function assetNameForTarget(target) {
51
53
  return isWindows() ? `bb-${target}.exe` : `bb-${target}`;
52
54
  }
53
55
 
56
+ function assetCandidatesForTarget(target) {
57
+ const assetName = assetNameForTarget(target);
58
+ return [
59
+ {
60
+ assetName: `${assetName}.gz`,
61
+ compressed: true,
62
+ },
63
+ {
64
+ assetName,
65
+ compressed: false,
66
+ },
67
+ ];
68
+ }
69
+
54
70
  function logLine(message = "") {
55
71
  try {
56
72
  process.stderr.write(`${message}\n`);
@@ -189,8 +205,14 @@ function copyBinary(src, dest) {
189
205
  function installFromVerifiedCache(target) {
190
206
  const cached = cacheBinaryPath(target);
191
207
  const meta = loadCacheMetadata(target);
192
- if (!fs.existsSync(cached) || !meta) return false;
193
- if (meta.version !== packageJson.version || meta.target !== target) return false;
208
+ if (!fs.existsSync(cached) || !meta) {
209
+ logLine(`No verified cached BB-Agent binary found for ${target} yet.`);
210
+ return false;
211
+ }
212
+ if (meta.version !== packageJson.version || meta.target !== target) {
213
+ logLine(`Ignoring stale cache metadata for ${target}; expected ${packageJson.version}.`);
214
+ return false;
215
+ }
194
216
 
195
217
  let stat;
196
218
  try {
@@ -199,9 +221,13 @@ function installFromVerifiedCache(target) {
199
221
  return false;
200
222
  }
201
223
  if (!stat.isFile() || stat.size <= 0) return false;
202
- if (meta.size && stat.size !== meta.size) return false;
224
+ if (meta.size && stat.size !== meta.size) {
225
+ logLine(`Cached BB-Agent binary for ${target} changed size; re-validating it.`);
226
+ return false;
227
+ }
203
228
 
204
229
  logLine(`Using cached BB-Agent binary for ${target} (${formatBytes(stat.size)}).`);
230
+ logLine(`Installing cached binary to ${nativeBinaryPath()}.`);
205
231
  copyBinary(cached, nativeBinaryPath());
206
232
  return true;
207
233
  }
@@ -230,8 +256,9 @@ function maybeRepairCache(target) {
230
256
  }
231
257
  }
232
258
 
233
- logLine(`Checking cached BB-Agent binary for ${target}...`);
259
+ logLine(`Checking cached BB-Agent binary for ${target} at ${cached}...`);
234
260
  if (!binaryMatchesCurrentVersion(cached)) {
261
+ logLine(`Cached binary for ${target} is stale or invalid; removing cached copy.`);
235
262
  removeIfExists(cached);
236
263
  removeIfExists(cacheMetadataPath(target));
237
264
  return false;
@@ -370,7 +397,7 @@ function requestBinary(url, dest, redirects = 0) {
370
397
  }
371
398
 
372
399
  function verifyBinary(binaryPath) {
373
- logLine("Verifying downloaded binary...");
400
+ logLine(`Verifying downloaded binary at ${binaryPath}...`);
374
401
  const version = binaryVersion(binaryPath);
375
402
  if (!version) {
376
403
  return {
@@ -387,13 +414,31 @@ function verifyBinary(binaryPath) {
387
414
  return { ok: true, version };
388
415
  }
389
416
 
417
+ async function expandCompressedBinary(src, dest) {
418
+ logLine(`Decompressing downloaded BB-Agent binary from ${path.basename(src)}...`);
419
+ ensureParentDir(dest);
420
+ try {
421
+ await pipeline(fs.createReadStream(src), zlib.createGunzip(), fs.createWriteStream(dest));
422
+ const stat = fs.statSync(dest);
423
+ logLine(`Expanded compressed asset to ${formatBytes(stat.size)}.`);
424
+ } catch (err) {
425
+ removeIfExists(dest);
426
+ throw makeDownloadError("decompress", `Failed to decompress ${path.basename(src)}: ${err.message}`);
427
+ } finally {
428
+ removeIfExists(src);
429
+ }
430
+ }
431
+
390
432
  async function tryDownloadPrebuilt(target) {
391
- const assetName = assetNameForTarget(target);
392
- const url = `https://github.com/${REPO}/releases/download/${BINARY_RELEASE_TAG}/${assetName}`;
433
+ const assetCandidates = assetCandidatesForTarget(target);
393
434
 
394
435
  fs.mkdirSync(NATIVE_DIR, { recursive: true });
395
436
  const dest = nativeBinaryPath();
396
437
  const tmpDest = `${dest}.tmp`;
438
+ const cachePath = cacheBinaryPath(target);
439
+
440
+ logLine(`Native binary destination: ${dest}`);
441
+ logLine(`Binary cache path: ${cachePath}`);
397
442
 
398
443
  if (installFromVerifiedCache(target)) {
399
444
  logLine("✓ BB-Agent binary installed successfully from cache.");
@@ -412,37 +457,70 @@ async function tryDownloadPrebuilt(target) {
412
457
  `Downloading BB-Agent ${BINARY_RELEASE_TAG} for ${target} (attempt ${attempt}/${MAX_DOWNLOAD_ATTEMPTS})...`
413
458
  );
414
459
  logLine("This may take a little while on first install because npm downloads the native binary from the GitHub release.");
415
- removeIfExists(tmpDest);
416
- await requestBinary(url, tmpDest, 0);
417
- if (!isWindows()) {
418
- fs.chmodSync(tmpDest, 0o755);
419
- }
420
460
 
421
- const verified = verifyBinary(tmpDest);
422
- if (!verified.ok) {
461
+ let missingCompressedAsset = false;
462
+ for (const asset of assetCandidates) {
463
+ const url = `https://github.com/${REPO}/releases/download/${BINARY_RELEASE_TAG}/${asset.assetName}`;
464
+ const downloadDest = asset.compressed ? `${tmpDest}.gz` : tmpDest;
465
+
423
466
  removeIfExists(tmpDest);
424
- return {
425
- ok: false,
426
- kind: "verify",
427
- message: `Downloaded binary could not run: ${verified.message}`,
428
- };
429
- }
467
+ removeIfExists(`${tmpDest}.gz`);
468
+
469
+ try {
470
+ if (asset.compressed) {
471
+ logLine(`Trying compressed release asset ${asset.assetName} first for a faster download.`);
472
+ } else {
473
+ logLine(`Trying uncompressed release asset ${asset.assetName}.`);
474
+ }
475
+ await requestBinary(url, downloadDest, 0);
476
+ if (asset.compressed) {
477
+ await expandCompressedBinary(downloadDest, tmpDest);
478
+ }
479
+ if (!isWindows()) {
480
+ fs.chmodSync(tmpDest, 0o755);
481
+ }
430
482
 
431
- fs.renameSync(tmpDest, dest);
432
- refreshCacheFromExistingBinary(target, dest);
433
- logLine("Cached verified BB-Agent binary for future installs.");
434
- logLine("✓ BB-Agent binary installed successfully.");
435
- return { ok: true, source: "download" };
483
+ const verified = verifyBinary(tmpDest);
484
+ if (!verified.ok) {
485
+ removeIfExists(tmpDest);
486
+ return {
487
+ ok: false,
488
+ kind: "verify",
489
+ message: `Downloaded binary could not run: ${verified.message}`,
490
+ };
491
+ }
492
+
493
+ fs.renameSync(tmpDest, dest);
494
+ logLine(`Installed BB-Agent binary to ${dest}.`);
495
+ refreshCacheFromExistingBinary(target, dest);
496
+ logLine(`Cached verified BB-Agent binary for future installs at ${cachePath}.`);
497
+ logLine("✓ BB-Agent binary installed successfully.");
498
+ return { ok: true, source: "download" };
499
+ } catch (err) {
500
+ lastError = err;
501
+ removeIfExists(tmpDest);
502
+ removeIfExists(`${tmpDest}.gz`);
503
+ if (err.kind === "not-found") {
504
+ if (asset.compressed) {
505
+ missingCompressedAsset = true;
506
+ logLine(`Compressed asset ${asset.assetName} not found; falling back to the uncompressed release binary.`);
507
+ continue;
508
+ }
509
+ return {
510
+ ok: false,
511
+ kind: "not-found",
512
+ message: missingCompressedAsset
513
+ ? `No release asset named ${asset.assetName} or ${assetCandidates[0].assetName} was found for ${BINARY_RELEASE_TAG}.`
514
+ : `No release asset named ${asset.assetName} was found for ${BINARY_RELEASE_TAG}.`,
515
+ };
516
+ }
517
+ throw err;
518
+ }
519
+ }
436
520
  } catch (err) {
437
521
  lastError = err;
438
522
  removeIfExists(tmpDest);
439
- if (err.kind === "not-found") {
440
- return {
441
- ok: false,
442
- kind: "not-found",
443
- message: `No release asset named ${assetName} was found for ${BINARY_RELEASE_TAG}.`,
444
- };
445
- }
523
+ removeIfExists(`${tmpDest}.gz`);
446
524
  if (attempt < MAX_DOWNLOAD_ATTEMPTS) {
447
525
  logLine(`Download failed (${err.message}). Retrying...`);
448
526
  await new Promise((resolve) => setTimeout(resolve, 1000 * attempt));
@@ -501,7 +579,9 @@ async function main() {
501
579
  const target = getTarget();
502
580
  const platform = `${os.platform()}-${os.arch()}`;
503
581
 
582
+ logLine(`Resolved install platform: ${platform}.`);
504
583
  if (target) {
584
+ logLine(`Resolved native target: ${target}.`);
505
585
  const result = await tryDownloadPrebuilt(target);
506
586
  if (result.ok) {
507
587
  return;