agent-yes 1.45.2 → 1.46.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.
@@ -1,7 +1,7 @@
1
1
  import { a as __esmMin, c as __toESM, i as __commonJSMin, n as require_winston, o as __exportAll, s as __require, t as logger } from "./logger-DH1Rx9HI.js";
2
2
  import { arch, platform } from "process";
3
3
  import { execSync } from "child_process";
4
- import { existsSync } from "fs";
4
+ import { existsSync, mkdirSync } from "fs";
5
5
  import path, { dirname, join } from "path";
6
6
  import { constants } from "node:os";
7
7
  import path$1 from "node:path";
@@ -10735,4 +10735,4 @@ const SUPPORTED_CLIS = Object.keys(CLIS_CONFIG);
10735
10735
 
10736
10736
  //#endregion
10737
10737
  export { AgentContext as a, config as i, CLIS_CONFIG as n, PidStore as o, agentYes as r, removeControlCharacters as s, SUPPORTED_CLIS as t };
10738
- //# sourceMappingURL=SUPPORTED_CLIS-hj4ASwQy.js.map
10738
+ //# sourceMappingURL=SUPPORTED_CLIS-BwukLRmP.js.map
package/dist/cli.js CHANGED
@@ -1,16 +1,17 @@
1
1
  #!/usr/bin/env bun
2
2
  import { c as __toESM, i as __commonJSMin, r as require_ms, t as logger } from "./logger-DH1Rx9HI.js";
3
3
  import "./agent-yes.config-CrlZMQo-.js";
4
- import { o as PidStore, t as SUPPORTED_CLIS } from "./SUPPORTED_CLIS-hj4ASwQy.js";
4
+ import { o as PidStore, t as SUPPORTED_CLIS } from "./SUPPORTED_CLIS-BwukLRmP.js";
5
5
  import { createRequire } from "node:module";
6
6
  import { argv } from "process";
7
7
  import { spawn } from "child_process";
8
- import { existsSync, readFileSync, readdirSync, statSync, writeFile } from "fs";
8
+ import { existsSync, mkdirSync, readFileSync, readdirSync, statSync, unlinkSync, writeFile } from "fs";
9
9
  import path, { basename, dirname, extname, join, normalize, relative, resolve } from "path";
10
10
  import { format, inspect } from "util";
11
11
  import { notStrictEqual, strictEqual } from "assert";
12
12
  import { fileURLToPath } from "url";
13
13
  import { readFileSync as readFileSync$1, readdirSync as readdirSync$1 } from "node:fs";
14
+ import { chmod, copyFile, rename } from "fs/promises";
14
15
 
15
16
  //#region node_modules/cliui/build/lib/index.js
16
17
  var import_ms = /* @__PURE__ */ __toESM(require_ms(), 1);
@@ -4696,26 +4697,165 @@ async function displayVersion() {
4696
4697
  }
4697
4698
 
4698
4699
  //#endregion
4699
- //#region ts/cli.ts
4700
- const config = parseCliArgs(process.argv);
4701
- if (config.useRust) {
4702
- const rustBinaryName = config.cli ? `${config.cli}-yes` : "agent-yes";
4703
- const rustBinaryPaths = [
4700
+ //#region ts/rustBinary.ts
4701
+ /**
4702
+ * Rust binary helper - finds or downloads the appropriate prebuilt binary
4703
+ */
4704
+ const PLATFORM_MAP = {
4705
+ "linux-x64": "agent-yes-linux-x64-musl",
4706
+ "linux-arm64": "agent-yes-linux-arm64-musl",
4707
+ "darwin-x64": "agent-yes-darwin-x64",
4708
+ "darwin-arm64": "agent-yes-darwin-arm64",
4709
+ "win32-x64": "agent-yes-win32-x64"
4710
+ };
4711
+ /**
4712
+ * Get the binary name for the current platform
4713
+ */
4714
+ function getBinaryName() {
4715
+ const platform = process.platform;
4716
+ const arch = process.arch;
4717
+ const binaryName = PLATFORM_MAP[`${platform}-${arch}`];
4718
+ if (!binaryName) throw new Error(`Unsupported platform: ${platform}-${arch}. Supported: ${Object.keys(PLATFORM_MAP).join(", ")}`);
4719
+ return binaryName + (platform === "win32" ? ".exe" : "");
4720
+ }
4721
+ /**
4722
+ * Get the directory where binaries are stored
4723
+ */
4724
+ function getBinDir() {
4725
+ const packageBinDir = path.resolve(import.meta.dir, "../bin");
4726
+ if (existsSync(packageBinDir)) return packageBinDir;
4727
+ const cacheDir = process.env.AGENT_YES_CACHE_DIR || path.join(process.env.XDG_CACHE_HOME || path.join(process.env.HOME || "/tmp", ".cache"), "agent-yes");
4728
+ return path.join(cacheDir, "bin");
4729
+ }
4730
+ /**
4731
+ * Find the Rust binary, checking multiple locations
4732
+ */
4733
+ function findRustBinary(verbose = false) {
4734
+ const binaryName = getBinaryName();
4735
+ binaryName.replace(/\.exe$/, "");
4736
+ const searchPaths = [
4737
+ path.join(getBinDir(), binaryName),
4704
4738
  path.resolve(import.meta.dir, "../rs/target/release/agent-yes"),
4705
4739
  path.resolve(import.meta.dir, "../rs/target/debug/agent-yes"),
4706
- rustBinaryName,
4707
- "agent-yes"
4740
+ path.join(getBinDir(), binaryName)
4708
4741
  ];
4742
+ if (verbose) {
4743
+ console.log(`[rust] Looking for binary: ${binaryName}`);
4744
+ console.log(`[rust] Search paths:`);
4745
+ }
4746
+ for (const p of searchPaths) {
4747
+ if (verbose) console.log(`[rust] - ${p}: ${existsSync(p) ? "FOUND" : "not found"}`);
4748
+ if (existsSync(p)) return p;
4749
+ }
4750
+ }
4751
+ /**
4752
+ * Get GitHub release download URL for the binary
4753
+ */
4754
+ function getDownloadUrl(version = "latest") {
4755
+ const binaryName = getBinaryName().replace(/\.exe$/, "");
4756
+ const ext = process.platform === "win32" ? ".zip" : ".tar.gz";
4757
+ if (version === "latest") return `https://github.com/snomiao/agent-yes/releases/latest/download/${binaryName}${ext}`;
4758
+ return `https://github.com/snomiao/agent-yes/releases/download/v${version}/${binaryName}${ext}`;
4759
+ }
4760
+ /**
4761
+ * Download and extract the binary
4762
+ */
4763
+ async function downloadBinary(verbose = false) {
4764
+ const binDir = getBinDir();
4765
+ const binaryName = getBinaryName();
4766
+ const binaryPath = path.join(binDir, binaryName);
4767
+ mkdirSync(binDir, { recursive: true });
4768
+ const url = getDownloadUrl();
4769
+ if (verbose) console.log(`[rust] Downloading binary from: ${url}`);
4770
+ const response = await fetch(url);
4771
+ if (!response.ok) throw new Error(`Failed to download binary: ${response.status} ${response.statusText}`);
4772
+ if (process.platform === "win32") {
4773
+ const tempZipPath = path.join(binDir, "temp.zip");
4774
+ await Bun.write(tempZipPath, await response.arrayBuffer());
4775
+ await Bun.spawn([
4776
+ "powershell",
4777
+ "-Command",
4778
+ `Expand-Archive -Path '${tempZipPath}' -DestinationPath '${binDir}' -Force`
4779
+ ], {
4780
+ cwd: binDir,
4781
+ stdio: [
4782
+ "ignore",
4783
+ "pipe",
4784
+ "pipe"
4785
+ ]
4786
+ }).exited;
4787
+ try {
4788
+ unlinkSync(tempZipPath);
4789
+ } catch {}
4790
+ } else {
4791
+ const tarPath = path.join(binDir, "temp.tar.gz");
4792
+ await Bun.write(tarPath, await response.arrayBuffer());
4793
+ await Bun.spawn([
4794
+ "tar",
4795
+ "-xzf",
4796
+ tarPath,
4797
+ "-C",
4798
+ binDir
4799
+ ], {
4800
+ cwd: binDir,
4801
+ stdio: [
4802
+ "ignore",
4803
+ "pipe",
4804
+ "pipe"
4805
+ ]
4806
+ }).exited;
4807
+ const possibleNames = [
4808
+ "agent-yes",
4809
+ binaryName.replace(/-musl$/, "").replace(/-gnu$/, ""),
4810
+ binaryName
4811
+ ];
4812
+ for (const name of possibleNames) {
4813
+ const extractedPath = path.join(binDir, name);
4814
+ if (existsSync(extractedPath) && extractedPath !== binaryPath) {
4815
+ try {
4816
+ await copyFile(extractedPath, binaryPath);
4817
+ unlinkSync(extractedPath);
4818
+ } catch {}
4819
+ break;
4820
+ }
4821
+ }
4822
+ try {
4823
+ unlinkSync(tarPath);
4824
+ } catch {}
4825
+ await chmod(binaryPath, 493);
4826
+ }
4827
+ if (verbose) console.log(`[rust] Binary downloaded to: ${binaryPath}`);
4828
+ return binaryPath;
4829
+ }
4830
+ /**
4831
+ * Get or download the Rust binary
4832
+ */
4833
+ async function getRustBinary(options = {}) {
4834
+ const { verbose = false, forceDownload = false } = options;
4835
+ if (!forceDownload) {
4836
+ const existing = findRustBinary(verbose);
4837
+ if (existing) {
4838
+ if (verbose) console.log(`[rust] Using existing binary: ${existing}`);
4839
+ return existing;
4840
+ }
4841
+ }
4842
+ if (verbose) console.log(`[rust] Binary not found, downloading...`);
4843
+ try {
4844
+ return await downloadBinary(verbose);
4845
+ } catch (err) {
4846
+ throw new Error(`Failed to get Rust binary: ${err instanceof Error ? err.message : err}\nYou can build manually with: cd rs && cargo build --release`);
4847
+ }
4848
+ }
4849
+
4850
+ //#endregion
4851
+ //#region ts/cli.ts
4852
+ const config = parseCliArgs(process.argv);
4853
+ if (config.useRust) {
4709
4854
  let rustBinary;
4710
- for (const p of rustBinaryPaths) if (p.includes("/") && existsSync(p)) {
4711
- rustBinary = p;
4712
- break;
4713
- } else if (!p.includes("/")) {
4714
- rustBinary = p;
4715
- break;
4716
- }
4717
- if (!rustBinary) {
4718
- console.error("Rust binary not found. Please build with: cd rs && cargo build --release");
4855
+ try {
4856
+ rustBinary = await getRustBinary({ verbose: config.verbose });
4857
+ } catch (err) {
4858
+ console.error(err instanceof Error ? err.message : String(err));
4719
4859
  process.exit(1);
4720
4860
  }
4721
4861
  const rustArgs = process.argv.slice(2).filter((arg) => arg !== "--rust" && !arg.startsWith("--rust="));
@@ -4729,7 +4869,7 @@ if (config.useRust) {
4729
4869
  cwd: process.cwd()
4730
4870
  });
4731
4871
  child.on("error", (err) => {
4732
- if (err.code === "ENOENT") console.error(`Rust binary '${rustBinary}' not found in PATH. Please build with: cd rs && cargo build --release`);
4872
+ if (err.code === "ENOENT") console.error(`Rust binary '${rustBinary}' not found. Try: npx agent-yes --rust --verbose`);
4733
4873
  else console.error(`Failed to spawn Rust binary: ${err.message}`);
4734
4874
  process.exit(1);
4735
4875
  });
package/dist/index.js CHANGED
@@ -1,4 +1,4 @@
1
1
  import "./logger-DH1Rx9HI.js";
2
- import { a as AgentContext, i as config, n as CLIS_CONFIG, r as agentYes, s as removeControlCharacters } from "./SUPPORTED_CLIS-hj4ASwQy.js";
2
+ import { a as AgentContext, i as config, n as CLIS_CONFIG, r as agentYes, s as removeControlCharacters } from "./SUPPORTED_CLIS-BwukLRmP.js";
3
3
 
4
4
  export { AgentContext, CLIS_CONFIG, config, agentYes as default, removeControlCharacters };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "agent-yes",
3
- "version": "1.45.2",
3
+ "version": "1.46.1",
4
4
  "description": "A wrapper tool that automates interactions with various AI CLI tools by automatically handling common prompts and responses.",
5
5
  "keywords": [
6
6
  "ai",
@@ -49,7 +49,8 @@
49
49
  "scripts",
50
50
  "ts/*.ts",
51
51
  "!dist/**/*.map",
52
- "dist/**/*.js"
52
+ "dist/**/*.js",
53
+ "bin"
53
54
  ],
54
55
  "type": "module",
55
56
  "module": "ts/index.ts",
@@ -0,0 +1,44 @@
1
+ #!/usr/bin/env bun
2
+ /**
3
+ * Script to download the prebuilt Rust binary for the current platform
4
+ *
5
+ * Usage:
6
+ * bun scripts/download-rust-binary.ts
7
+ * npx agent-yes download-binary
8
+ */
9
+
10
+ import { downloadBinary, findRustBinary, getBinaryName, getDownloadUrl } from "../ts/rustBinary.ts";
11
+
12
+ async function main() {
13
+ const verbose = process.argv.includes("--verbose") || process.argv.includes("-v");
14
+ const force = process.argv.includes("--force") || process.argv.includes("-f");
15
+
16
+ console.log(`Platform: ${process.platform}-${process.arch}`);
17
+ console.log(`Binary name: ${getBinaryName()}`);
18
+ console.log(`Download URL: ${getDownloadUrl()}`);
19
+ console.log();
20
+
21
+ // Check if binary already exists
22
+ if (!force) {
23
+ const existing = findRustBinary(verbose);
24
+ if (existing) {
25
+ console.log(`Binary already exists at: ${existing}`);
26
+ console.log("Use --force to re-download");
27
+ return;
28
+ }
29
+ }
30
+
31
+ console.log("Downloading binary...");
32
+ try {
33
+ const binaryPath = await downloadBinary(verbose);
34
+ console.log(`\nSuccess! Binary downloaded to: ${binaryPath}`);
35
+ console.log("\nYou can now use: npx agent-yes --rust");
36
+ } catch (err) {
37
+ console.error(`\nFailed to download binary: ${err instanceof Error ? err.message : err}`);
38
+ console.error("\nYou can build manually with:");
39
+ console.error(" cd rs && cargo build --release");
40
+ process.exit(1);
41
+ }
42
+ }
43
+
44
+ main();
package/ts/cli.ts CHANGED
@@ -8,36 +8,20 @@ import { parseCliArgs } from "./parseCliArgs.ts";
8
8
  import { logger } from "./logger.ts";
9
9
  import { PidStore } from "./pidStore.ts";
10
10
  import { displayVersion } from "./versionChecker.ts";
11
+ import { getRustBinary } from "./rustBinary.ts";
11
12
 
12
13
  // Parse CLI arguments
13
14
  const config = parseCliArgs(process.argv);
14
15
 
15
16
  // Handle --rust: spawn the Rust binary instead
16
17
  if (config.useRust) {
17
- const rustBinaryName = config.cli ? `${config.cli}-yes` : "agent-yes";
18
- const rustBinaryPaths = [
19
- // Check relative to this script (in the repo)
20
- path.resolve(import.meta.dir, "../rs/target/release/agent-yes"),
21
- path.resolve(import.meta.dir, "../rs/target/debug/agent-yes"),
22
- // Check in PATH
23
- rustBinaryName,
24
- "agent-yes",
25
- ];
26
-
27
- let rustBinary: string | undefined;
28
- for (const p of rustBinaryPaths) {
29
- if (p.includes("/") && existsSync(p)) {
30
- rustBinary = p;
31
- break;
32
- } else if (!p.includes("/")) {
33
- // For PATH lookup, just use it directly
34
- rustBinary = p;
35
- break;
36
- }
37
- }
18
+ let rustBinary: string;
38
19
 
39
- if (!rustBinary) {
40
- console.error("Rust binary not found. Please build with: cd rs && cargo build --release");
20
+ try {
21
+ // Get or download the Rust binary for the current platform
22
+ rustBinary = await getRustBinary({ verbose: config.verbose });
23
+ } catch (err) {
24
+ console.error(err instanceof Error ? err.message : String(err));
41
25
  process.exit(1);
42
26
  }
43
27
 
@@ -58,7 +42,7 @@ if (config.useRust) {
58
42
 
59
43
  child.on("error", (err) => {
60
44
  if ((err as NodeJS.ErrnoException).code === "ENOENT") {
61
- console.error(`Rust binary '${rustBinary}' not found in PATH. Please build with: cd rs && cargo build --release`);
45
+ console.error(`Rust binary '${rustBinary}' not found. Try: npx agent-yes --rust --verbose`);
62
46
  } else {
63
47
  console.error(`Failed to spawn Rust binary: ${err.message}`);
64
48
  }
@@ -0,0 +1,224 @@
1
+ /**
2
+ * Rust binary helper - finds or downloads the appropriate prebuilt binary
3
+ */
4
+
5
+ import { existsSync, mkdirSync, unlinkSync, renameSync, copyFileSync } from "fs";
6
+ import { chmod, unlink, rename, copyFile } from "fs/promises";
7
+ import path from "path";
8
+
9
+ // Platform/arch to binary name mapping
10
+ const PLATFORM_MAP: Record<string, string> = {
11
+ "linux-x64": "agent-yes-linux-x64-musl", // Use musl for better compatibility
12
+ "linux-arm64": "agent-yes-linux-arm64-musl",
13
+ "darwin-x64": "agent-yes-darwin-x64",
14
+ "darwin-arm64": "agent-yes-darwin-arm64",
15
+ "win32-x64": "agent-yes-win32-x64",
16
+ };
17
+
18
+ /**
19
+ * Get the binary name for the current platform
20
+ */
21
+ export function getBinaryName(): string {
22
+ const platform = process.platform;
23
+ const arch = process.arch;
24
+ const key = `${platform}-${arch}`;
25
+
26
+ const binaryName = PLATFORM_MAP[key];
27
+ if (!binaryName) {
28
+ throw new Error(
29
+ `Unsupported platform: ${platform}-${arch}. ` +
30
+ `Supported: ${Object.keys(PLATFORM_MAP).join(", ")}`
31
+ );
32
+ }
33
+
34
+ return binaryName + (platform === "win32" ? ".exe" : "");
35
+ }
36
+
37
+ /**
38
+ * Get the directory where binaries are stored
39
+ */
40
+ export function getBinDir(): string {
41
+ // First check for binaries in the npm package
42
+ const packageBinDir = path.resolve(import.meta.dir, "../bin");
43
+ if (existsSync(packageBinDir)) {
44
+ return packageBinDir;
45
+ }
46
+
47
+ // Fall back to user's cache directory
48
+ const cacheDir =
49
+ process.env.AGENT_YES_CACHE_DIR ||
50
+ path.join(
51
+ process.env.XDG_CACHE_HOME || path.join(process.env.HOME || "/tmp", ".cache"),
52
+ "agent-yes"
53
+ );
54
+
55
+ return path.join(cacheDir, "bin");
56
+ }
57
+
58
+ /**
59
+ * Find the Rust binary, checking multiple locations
60
+ */
61
+ export function findRustBinary(verbose = false): string | undefined {
62
+ const binaryName = getBinaryName();
63
+ const baseName = binaryName.replace(/\.exe$/, "");
64
+
65
+ const searchPaths = [
66
+ // 1. Check in npm package bin directory
67
+ path.join(getBinDir(), binaryName),
68
+
69
+ // 2. Check relative to this script (in the repo during development)
70
+ path.resolve(import.meta.dir, "../rs/target/release/agent-yes"),
71
+ path.resolve(import.meta.dir, "../rs/target/debug/agent-yes"),
72
+
73
+ // 3. Check in user's cache directory
74
+ path.join(getBinDir(), binaryName),
75
+ ];
76
+
77
+ if (verbose) {
78
+ console.log(`[rust] Looking for binary: ${binaryName}`);
79
+ console.log(`[rust] Search paths:`);
80
+ }
81
+
82
+ for (const p of searchPaths) {
83
+ if (verbose) {
84
+ console.log(`[rust] - ${p}: ${existsSync(p) ? "FOUND" : "not found"}`);
85
+ }
86
+ if (existsSync(p)) {
87
+ return p;
88
+ }
89
+ }
90
+
91
+ return undefined;
92
+ }
93
+
94
+ /**
95
+ * Get GitHub release download URL for the binary
96
+ */
97
+ export function getDownloadUrl(version = "latest"): string {
98
+ const binaryName = getBinaryName().replace(/\.exe$/, "");
99
+ const isWindows = process.platform === "win32";
100
+ const ext = isWindows ? ".zip" : ".tar.gz";
101
+
102
+ if (version === "latest") {
103
+ return `https://github.com/snomiao/agent-yes/releases/latest/download/${binaryName}${ext}`;
104
+ }
105
+
106
+ return `https://github.com/snomiao/agent-yes/releases/download/v${version}/${binaryName}${ext}`;
107
+ }
108
+
109
+ /**
110
+ * Download and extract the binary
111
+ */
112
+ export async function downloadBinary(verbose = false): Promise<string> {
113
+ const binDir = getBinDir();
114
+ const binaryName = getBinaryName();
115
+ const binaryPath = path.join(binDir, binaryName);
116
+
117
+ // Create bin directory if needed
118
+ mkdirSync(binDir, { recursive: true });
119
+
120
+ const url = getDownloadUrl();
121
+ if (verbose) {
122
+ console.log(`[rust] Downloading binary from: ${url}`);
123
+ }
124
+
125
+ const response = await fetch(url);
126
+ if (!response.ok) {
127
+ throw new Error(`Failed to download binary: ${response.status} ${response.statusText}`);
128
+ }
129
+
130
+ const isWindows = process.platform === "win32";
131
+
132
+ if (isWindows) {
133
+ // For Windows, download and extract zip
134
+ const tempZipPath = path.join(binDir, "temp.zip");
135
+ await Bun.write(tempZipPath, await response.arrayBuffer());
136
+
137
+ // Use PowerShell to extract zip
138
+ const proc = Bun.spawn(
139
+ ["powershell", "-Command", `Expand-Archive -Path '${tempZipPath}' -DestinationPath '${binDir}' -Force`],
140
+ { cwd: binDir, stdio: ["ignore", "pipe", "pipe"] }
141
+ );
142
+ await proc.exited;
143
+
144
+ // Clean up
145
+ try {
146
+ unlinkSync(tempZipPath);
147
+ } catch {}
148
+ } else {
149
+ // For Unix, download and extract tar.gz
150
+ const tarPath = path.join(binDir, "temp.tar.gz");
151
+ await Bun.write(tarPath, await response.arrayBuffer());
152
+
153
+ // Extract using tar command
154
+ const proc = Bun.spawn(["tar", "-xzf", tarPath, "-C", binDir], {
155
+ cwd: binDir,
156
+ stdio: ["ignore", "pipe", "pipe"],
157
+ });
158
+ await proc.exited;
159
+
160
+ // The extracted file might have a different name, find and rename it
161
+ const extractedName = binaryName.replace(/-musl$/, "").replace(/-gnu$/, "");
162
+ const possibleNames = ["agent-yes", extractedName, binaryName];
163
+
164
+ for (const name of possibleNames) {
165
+ const extractedPath = path.join(binDir, name);
166
+ if (existsSync(extractedPath) && extractedPath !== binaryPath) {
167
+ try {
168
+ await copyFile(extractedPath, binaryPath);
169
+ unlinkSync(extractedPath);
170
+ } catch {}
171
+ break;
172
+ }
173
+ }
174
+
175
+ // Clean up tar file
176
+ try {
177
+ unlinkSync(tarPath);
178
+ } catch {}
179
+
180
+ // Make executable
181
+ await chmod(binaryPath, 0o755);
182
+ }
183
+
184
+ if (verbose) {
185
+ console.log(`[rust] Binary downloaded to: ${binaryPath}`);
186
+ }
187
+
188
+ return binaryPath;
189
+ }
190
+
191
+ /**
192
+ * Get or download the Rust binary
193
+ */
194
+ export async function getRustBinary(options: {
195
+ verbose?: boolean;
196
+ forceDownload?: boolean;
197
+ } = {}): Promise<string> {
198
+ const { verbose = false, forceDownload = false } = options;
199
+
200
+ // First try to find existing binary
201
+ if (!forceDownload) {
202
+ const existing = findRustBinary(verbose);
203
+ if (existing) {
204
+ if (verbose) {
205
+ console.log(`[rust] Using existing binary: ${existing}`);
206
+ }
207
+ return existing;
208
+ }
209
+ }
210
+
211
+ // Download if not found
212
+ if (verbose) {
213
+ console.log(`[rust] Binary not found, downloading...`);
214
+ }
215
+
216
+ try {
217
+ return await downloadBinary(verbose);
218
+ } catch (err) {
219
+ throw new Error(
220
+ `Failed to get Rust binary: ${err instanceof Error ? err.message : err}\n` +
221
+ `You can build manually with: cd rs && cargo build --release`
222
+ );
223
+ }
224
+ }