agent-yes 1.45.2 → 1.46.0
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/dist/{SUPPORTED_CLIS-hj4ASwQy.js → SUPPORTED_CLIS-BwukLRmP.js} +2 -2
- package/dist/cli.js +159 -19
- package/dist/index.js +1 -1
- package/package.json +3 -2
- package/scripts/download-rust-binary.ts +44 -0
- package/ts/cli.ts +8 -24
- package/ts/rustBinary.ts +224 -0
|
@@ -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-
|
|
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-
|
|
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/
|
|
4700
|
-
|
|
4701
|
-
|
|
4702
|
-
|
|
4703
|
-
|
|
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
|
-
|
|
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
|
-
|
|
4711
|
-
rustBinary =
|
|
4712
|
-
|
|
4713
|
-
|
|
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
|
|
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-
|
|
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.
|
|
3
|
+
"version": "1.46.0",
|
|
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
|
-
|
|
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
|
-
|
|
40
|
-
|
|
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
|
|
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
|
}
|
package/ts/rustBinary.ts
ADDED
|
@@ -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
|
+
}
|