agent-yes 1.31.41

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/ts/logger.ts ADDED
@@ -0,0 +1,17 @@
1
+ import winston from "winston";
2
+
3
+ // Configure Winston logger
4
+ const logFormat = winston.format.combine(
5
+ winston.format.timestamp({ format: "YYYY-MM-DD HH:mm:ss" }),
6
+ winston.format.printf(({ timestamp, level, message, ...meta }) => {
7
+ const metaStr = Object.keys(meta).length ? ` ${JSON.stringify(meta)}` : "";
8
+ return `${timestamp} [${level}]: ${message}${metaStr}`;
9
+ }),
10
+ );
11
+
12
+ export const logger = winston.createLogger({
13
+ level: process.env.VERBOSE ? "debug" : "info",
14
+ format: logFormat,
15
+ transports: [new winston.transports.Console({ format: winston.format.combine(winston.format.colorize(), logFormat), }),],
16
+ silent: false,
17
+ });
@@ -0,0 +1,231 @@
1
+ #!/usr/bin/env bun test
2
+ import { describe, expect, it } from "vitest";
3
+ import { parseCliArgs } from "./parseCliArgs";
4
+
5
+ describe("CLI argument parsing", () => {
6
+ it("should parse cli name from first positional argument", () => {
7
+ const result = parseCliArgs(["node", "/path/to/cli", "claude"]);
8
+
9
+ expect(result.cli).toBe("claude");
10
+ });
11
+
12
+ it("should parse prompt from --prompt flag", () => {
13
+ const result = parseCliArgs(["node", "/path/to/cli", "--prompt", "hello world", "claude"]);
14
+
15
+ expect(result.prompt).toBe("hello world");
16
+ });
17
+
18
+ it("should parse prompt from -- separator", () => {
19
+ const result = parseCliArgs(["node", "/path/to/cli", "claude", "--", "hello", "world"]);
20
+
21
+ expect(result.prompt).toBe("hello world");
22
+ });
23
+
24
+ it("should parse prompt from only -- separator with -yes cli", () => {
25
+ const result = parseCliArgs(["node", "/path/to/claude-yes", "--", "hello", "world"]);
26
+
27
+ expect(result.prompt).toBe("hello world");
28
+ });
29
+
30
+ it("should combine --prompt and -- prompt", () => {
31
+ const result = parseCliArgs([
32
+ "node",
33
+ "/path/to/cli",
34
+ "--prompt",
35
+ "part1",
36
+ "claude",
37
+ "--",
38
+ "part2",
39
+ ]);
40
+
41
+ expect(result.prompt).toBe("part1 part2");
42
+ });
43
+
44
+ it("should parse --idle flag", () => {
45
+ const result = parseCliArgs(["node", "/path/to/cli", "--idle", "30s", "claude"]);
46
+
47
+ expect(result.exitOnIdle).toBe(30000);
48
+ });
49
+
50
+ it("should parse --exit-on-idle flag (deprecated)", () => {
51
+ const result = parseCliArgs(["node", "/path/to/cli", "--exit-on-idle", "1m", "claude"]);
52
+
53
+ expect(result.exitOnIdle).toBe(60000);
54
+ });
55
+
56
+ it("should parse --robust flag", () => {
57
+ const result = parseCliArgs(["node", "/path/to/cli", "--robust", "claude"]);
58
+
59
+ expect(result.robust).toBe(true);
60
+ });
61
+
62
+ it("should parse --no-robust flag", () => {
63
+ const result = parseCliArgs(["node", "/path/to/cli", "--no-robust", "claude"]);
64
+
65
+ expect(result.robust).toBe(false);
66
+ });
67
+
68
+ it("should parse --queue flag", () => {
69
+ const result = parseCliArgs(["node", "/path/to/cli", "--queue", "claude"]);
70
+
71
+ expect(result.queue).toBe(true);
72
+ });
73
+
74
+ it("should parse --no-queue flag", () => {
75
+ const result = parseCliArgs(["node", "/path/to/cli", "--no-queue", "claude"]);
76
+
77
+ expect(result.queue).toBe(false);
78
+ });
79
+
80
+ it("should parse --logFile flag", () => {
81
+ const result = parseCliArgs(["node", "/path/to/cli", "--logFile", "./output.log", "claude"]);
82
+
83
+ expect(result.logFile).toBe("./output.log");
84
+ });
85
+
86
+ it("should parse --verbose flag", () => {
87
+ const result = parseCliArgs(["node", "/path/to/cli", "--verbose", "claude"]);
88
+
89
+ expect(result.verbose).toBe(true);
90
+ });
91
+
92
+ it("should pass through unknown CLI args to cliArgs", () => {
93
+ const result = parseCliArgs(["node", "/path/to/cli", "claude", "--unknown-flag", "value"]);
94
+
95
+ expect(result.cliArgs).toContain("--unknown-flag");
96
+ expect(result.cliArgs).toContain("value");
97
+ });
98
+
99
+ it("should separate agent-yes args from cli args before --", () => {
100
+ const result = parseCliArgs([
101
+ "node",
102
+ "/path/to/cli",
103
+ "--robust",
104
+ "claude",
105
+ "--claude-arg",
106
+ "--",
107
+ "prompt",
108
+ ]);
109
+
110
+ expect(result.cli).toBe("claude");
111
+ expect(result.robust).toBe(true);
112
+ expect(result.cliArgs).toContain("--claude-arg");
113
+ expect(result.prompt).toBe("prompt");
114
+ });
115
+
116
+ it("should detect cli name from script name (claude-yes)", () => {
117
+ const result = parseCliArgs(["/usr/bin/node", "/usr/local/bin/claude-yes", "--prompt", "test"]);
118
+
119
+ expect(result.cli).toBe("claude");
120
+ });
121
+
122
+ it("should detect cli name from script name (codex-yes)", () => {
123
+ const result = parseCliArgs(["/usr/bin/node", "/usr/local/bin/codex-yes", "--prompt", "test"]);
124
+
125
+ expect(result.cli).toBe("codex");
126
+ });
127
+
128
+ it("should prefer script name over explicit cli argument", () => {
129
+ const result = parseCliArgs([
130
+ "/usr/bin/node",
131
+ "/usr/local/bin/claude-yes",
132
+ "--prompt",
133
+ "test",
134
+ "gemini",
135
+ ]);
136
+
137
+ // cliName (from script) takes precedence over positional arg
138
+ expect(result.cli).toBe("claude");
139
+ });
140
+
141
+ it("should handle empty cliArgs when no positional cli is provided", () => {
142
+ const result = parseCliArgs([
143
+ "/usr/bin/node",
144
+ "/usr/local/bin/claude-yes",
145
+ "--prompt",
146
+ "prompt",
147
+ ]);
148
+
149
+ expect(result.cliArgs).toEqual([]);
150
+ expect(result.prompt).toBe("prompt");
151
+ });
152
+
153
+ it("should include all args when no -- separator is present", () => {
154
+ const result = parseCliArgs([
155
+ "node",
156
+ "/path/to/cli",
157
+ "claude",
158
+ "--some-flag",
159
+ "--another-flag",
160
+ ]);
161
+
162
+ expect(result.cliArgs).toContain("--some-flag");
163
+ expect(result.cliArgs).toContain("--another-flag");
164
+ });
165
+
166
+ it("should parse bunx agent-yes command with verbose and dash prompt", () => {
167
+ const result = parseCliArgs([
168
+ "/tmp/bunx-0-agent-yes@beta/node_modules/bun/bin/bun.exe",
169
+ "/tmp/bunx-0-agent-yes@beta/node_modules/agent-yes/dist/cli.js",
170
+ "--verbose",
171
+ "claude",
172
+ "--",
173
+ "lets",
174
+ "fix",
175
+ "signin",
176
+ "page,",
177
+ "setup",
178
+ "shadcn",
179
+ ]);
180
+
181
+ expect(result.cli).toBe("claude");
182
+ expect(result.verbose).toBe(true);
183
+ expect(result.cliArgs).toEqual([]);
184
+ expect(result.prompt).toBe("lets fix signin page, setup shadcn");
185
+ });
186
+
187
+ it("should parse bunx agent-yes command with verbose and dash prompt", () => {
188
+ const result = parseCliArgs([
189
+ "/tmp/bunx-0-agent-yes@beta/node_modules/bun/bin/bun.exe",
190
+ "/tmp/bunx-0-agent-yes@beta/node_modules/agent-yes/dist/claude-yes.js",
191
+ "--",
192
+ "lets",
193
+ "fix",
194
+ "signin",
195
+ "page,",
196
+ "setup",
197
+ "shadcn",
198
+ ]);
199
+
200
+ expect(result.cli).toBe("claude");
201
+ expect(result.verbose).toBe(false);
202
+ expect(result.cliArgs).toEqual([]);
203
+ expect(result.prompt).toBe("lets fix signin page, setup shadcn");
204
+ });
205
+
206
+ it("should pass -h flag to claude CLI args", () => {
207
+ const result = parseCliArgs([
208
+ "/root/.nvm/versions/node/v24.5.0/bin/node",
209
+ "/root/.bun/bin/claude-yes",
210
+ "-h",
211
+ ]);
212
+
213
+ expect(result.cli).toBe("claude");
214
+ expect(result.cliArgs).toEqual(["-h"]);
215
+ });
216
+
217
+ it("should parse --use-skills flag", () => {
218
+ const result = parseCliArgs([
219
+ "node",
220
+ "/path/to/cli",
221
+ "--use-skills",
222
+ "codex",
223
+ "--",
224
+ "Implement feature",
225
+ ]);
226
+
227
+ expect(result.useSkills).toBe(true);
228
+ expect(result.cli).toBe("codex");
229
+ expect(result.prompt).toBe("Implement feature");
230
+ });
231
+ });
@@ -0,0 +1,182 @@
1
+ import ms from "ms";
2
+ import yargs from "yargs";
3
+ import { hideBin } from "yargs/helpers";
4
+ import { SUPPORTED_CLIS } from "./SUPPORTED_CLIS.ts";
5
+ import pkg from "../package.json" with { type: "json" };
6
+
7
+ // const pkg = await JSON.parse(await readFile(path.resolve((import.meta.dir) + "/../package.json"), 'utf8'))
8
+ /**
9
+ * Parse CLI arguments the same way cli.ts does
10
+ * This is a test helper that mirrors the parsing logic in cli.ts
11
+ */
12
+ export function parseCliArgs(argv: string[]) {
13
+ // Detect cli name from script name (same logic as cli.ts:10-14)
14
+ const cliName = (argv[1]?.split(/[/\\]/).at(-1)
15
+ ?.replace(/(\.[jt]s)?$/, "")
16
+ .replace(/^(cli|agent)(-yes$)?/, "")
17
+ .replace(/-yes$/, "") || undefined
18
+ );
19
+
20
+ // Parse args with yargs (same logic as cli.ts:16-73)
21
+ const parsedArgv = yargs(hideBin(argv))
22
+ .usage("Usage: $0 [cli] [agent-yes args] [agent-cli args] [--] [prompts...]")
23
+ .example(
24
+ "$0 claude --idle=30s -- solve all todos in my codebase, commit one by one",
25
+ "Run Claude with a 30 seconds idle timeout, and the prompt is everything after `--`",
26
+ )
27
+ // TODO: add a --docker option, will tell cli.ts to start docker process with tty and handles all stdio forwarding
28
+
29
+ .option("robust", {
30
+ type: "boolean",
31
+ default: true,
32
+ description: "re-spawn Claude with --continue if it crashes, only works for claude yet",
33
+ alias: "r",
34
+ })
35
+ .option("logFile", {
36
+ type: "string",
37
+ description: "Rendered log file to write to.",
38
+ })
39
+ .option("prompt", {
40
+ type: "string",
41
+ description: "Prompt to send to Claude (also can be passed after --)",
42
+ alias: "p",
43
+ })
44
+ .option("verbose", {
45
+ type: "boolean",
46
+ description: "Enable verbose logging, will emit ./agent-yes.log",
47
+ default: false,
48
+ })
49
+ .option("use-skills", {
50
+ type: "boolean",
51
+ description:
52
+ "Prepend SKILL.md header from current directory to the prompt (helpful for non-Claude agents)",
53
+ default: false,
54
+ })
55
+ .option("exit-on-idle", {
56
+ type: "string",
57
+ description: 'Exit after a period of inactivity, e.g., "5s" or "1m"',
58
+ deprecated: "use --idle instead",
59
+ default: "60s",
60
+ alias: "e",
61
+ })
62
+ .option("idle", {
63
+ type: "string",
64
+ description: 'short idle time, will perform idle action when reached, e.g., "5s" or "1m"',
65
+ alias: "i",
66
+ })
67
+ .option("idle-action", {
68
+ type: "string",
69
+ description: 'Idle action to perform when idle time is reached, e.g., "exit" or "TODO.md"',
70
+ })
71
+ .option("queue", {
72
+ type: "boolean",
73
+ description:
74
+ "Queue Agent Commands when spawning multiple agents in the same directory/repo, can be disabled with --no-queue",
75
+ default: false,
76
+ })
77
+ .option("install", {
78
+ type: "boolean",
79
+ description: "Automatically Install/Update the CLI if not found or outdated",
80
+ default: false,
81
+ })
82
+ .option("continue", {
83
+ type: "boolean",
84
+ description:
85
+ "Resume previous session in current cwd if any, note: will exit if no previous session found",
86
+ default: false,
87
+ alias: "c",
88
+ })
89
+ .positional("cli", {
90
+ describe: "The AI CLI to run, e.g., claude, codex, copilot, cursor, gemini",
91
+ type: "string",
92
+ choices: SUPPORTED_CLIS,
93
+ demandOption: false,
94
+ default: cliName,
95
+ })
96
+ .help()
97
+ .version(pkg.version)
98
+ .parserConfiguration({
99
+ "unknown-options-as-args": true,
100
+ "halt-at-non-option": true,
101
+ })
102
+ .parseSync();
103
+
104
+ // Extract cli args and dash prompt (same logic as cli.ts:76-91)
105
+ const optionalIndex = (e: number) => (0 <= e ? e : undefined);
106
+ const rawArgs = argv.slice(2);
107
+ const cliArgIndex = optionalIndex(rawArgs.indexOf(String(parsedArgv._[0])));
108
+ const dashIndex = optionalIndex(rawArgs.indexOf("--"));
109
+
110
+ // Reconstruct what yargs consumed vs what it didn't
111
+ const yargsConsumed = new Set<string>();
112
+
113
+ // Add consumed flags
114
+ Object.keys(parsedArgv).forEach((key) => {
115
+ if (key !== "_" && key !== "$0" && parsedArgv[key as keyof typeof parsedArgv] !== undefined) {
116
+ yargsConsumed.add(`--${key}`);
117
+ // Add short aliases
118
+ if (key === "prompt") yargsConsumed.add("-p");
119
+ if (key === "robust") yargsConsumed.add("-r");
120
+ if (key === "idle") yargsConsumed.add("-i");
121
+ if (key === "exitOnIdle") yargsConsumed.add("-e");
122
+ if (key === "continue") yargsConsumed.add("-c");
123
+ }
124
+ });
125
+
126
+ const cliArgsForSpawn = (() => {
127
+ if (parsedArgv._[0] && !cliName) {
128
+ // Explicit CLI name provided as positional arg
129
+ return rawArgs.slice((cliArgIndex ?? 0) + 1, dashIndex ?? undefined);
130
+ } else if (cliName) {
131
+ // CLI name from script, filter out only what yargs consumed
132
+ const result: string[] = [];
133
+ const argsToCheck = rawArgs.slice(0, dashIndex ?? undefined);
134
+
135
+ for (let i = 0; i < argsToCheck.length; i++) {
136
+ const arg = argsToCheck[i];
137
+ if (!arg) continue;
138
+
139
+ const [flag] = arg.split("=");
140
+
141
+ if (flag && yargsConsumed.has(flag)) {
142
+ // Skip consumed flag and its value if separate
143
+ if (!arg.includes("=") && i + 1 < argsToCheck.length) {
144
+ const nextArg = argsToCheck[i + 1];
145
+ if (nextArg && !nextArg.startsWith("-")) {
146
+ i++; // Skip value
147
+ }
148
+ }
149
+ } else {
150
+ result.push(arg);
151
+ }
152
+ }
153
+ return result;
154
+ }
155
+ return [];
156
+ })();
157
+ const dashPrompt: string | undefined =
158
+ dashIndex === undefined ? undefined : rawArgs.slice(dashIndex + 1).join(" ");
159
+
160
+ // Return the config object that would be passed to cliYes (same logic as cli.ts:99-121)
161
+ return {
162
+ cwd: process.cwd(),
163
+ env: process.env as Record<string, string>,
164
+ cli: (cliName ||
165
+ parsedArgv.cli ||
166
+ parsedArgv._[0]?.toString()?.replace?.(/-yes$/, "")) as (typeof SUPPORTED_CLIS)[number],
167
+ cliArgs: cliArgsForSpawn,
168
+ prompt: [parsedArgv.prompt, dashPrompt].filter(Boolean).join(" ") || undefined,
169
+ install: parsedArgv.install,
170
+ exitOnIdle: Number(
171
+ (parsedArgv.idle || parsedArgv.exitOnIdle)?.replace(/.*/, (e) =>
172
+ String(ms(e as ms.StringValue)),
173
+ ) || 0,
174
+ ),
175
+ queue: parsedArgv.queue,
176
+ robust: parsedArgv.robust,
177
+ logFile: parsedArgv.logFile,
178
+ verbose: parsedArgv.verbose,
179
+ resume: parsedArgv.continue, // Note: intentional use resume here to avoid preserved keyword (continue)
180
+ useSkills: parsedArgv.useSkills,
181
+ };
182
+ }
@@ -0,0 +1,29 @@
1
+ #! /usr/bin/env bun
2
+ /**
3
+ * Postbuild script: Create Node.js wrapper files in dist/
4
+ * These wrappers execute dist/cli.js with the appropriate CLI name
5
+ */
6
+ import { writeFile, chmod } from "fs/promises";
7
+ import { CLIS_CONFIG } from "./index.ts";
8
+ import sflow from "sflow";
9
+ import pkg from "../package.json";
10
+
11
+ // Create copies for each CLI variant (all use the same wrapper logic)
12
+ await sflow([...Object.keys(CLIS_CONFIG), 'agent'])
13
+ .map(async (cli) => {
14
+ const cliName = `${cli}-yes`;
15
+
16
+ const wrapperPath = `./dist/${cliName}.js`;
17
+ await writeFile(wrapperPath, `
18
+ #!/usr/bin/env bun
19
+ await import('./cli.js')
20
+ `.trim());
21
+ await chmod(wrapperPath, 0o755);
22
+
23
+ if (!(pkg.bin as Record<string, string>)?.[cliName]) {
24
+ await Bun.$`npm pkg set ${"bin." + cliName}=${wrapperPath}`;
25
+ console.log(`${wrapperPath} created`);
26
+ }
27
+ })
28
+
29
+ .run();
package/ts/pty-fix.ts ADDED
@@ -0,0 +1,155 @@
1
+ #!/usr/bin/env node
2
+
3
+ import { execSync } from "child_process";
4
+ import { existsSync } from "fs";
5
+ import { dirname, join } from "path";
6
+ import { arch, platform } from "process";
7
+ import { fileURLToPath } from "url";
8
+
9
+ // Determine the platform-specific library name
10
+ function getLibraryName() {
11
+ switch (platform) {
12
+ case "win32":
13
+ return "rust_pty.dll";
14
+ case "darwin":
15
+ return arch === "arm64" ? "librust_pty_arm64.dylib" : "librust_pty.dylib";
16
+ case "linux":
17
+ return arch === "arm64" ? "librust_pty_arm64.so" : "librust_pty.so";
18
+ default:
19
+ return "librust_pty.so";
20
+ }
21
+ }
22
+
23
+ // Check if we need to rebuild bun-pty
24
+ const bunPtyPath = dirname(fileURLToPath(import.meta.resolve("@snomiao/bun-pty"))) + "/..";
25
+ const libName = getLibraryName();
26
+ const libPath = join(bunPtyPath, "rust-pty", "target", "release", libName);
27
+
28
+ if (!existsSync(bunPtyPath)) {
29
+ console.log({ bunPtyPath });
30
+ console.log("bun-pty not found, skipping pty-fix in ");
31
+ process.exit(0);
32
+ }
33
+
34
+ // Platform-specific compatibility check
35
+ if (platform === "linux") {
36
+ // Check if the binary exists and if it has GLIBC compatibility issues
37
+ try {
38
+ const lddOutput = execSync(`ldd "${libPath}" 2>&1`, { encoding: "utf8" });
39
+ if (lddOutput.includes("GLIBC") && lddOutput.includes("not found")) {
40
+ console.log("GLIBC compatibility issue detected, rebuilding bun-pty...");
41
+ rebuildBunPty();
42
+ } else {
43
+ console.log("bun-pty binary is compatible");
44
+ }
45
+ } catch {
46
+ // If ldd fails or file doesn't exist, try to rebuild
47
+ console.log("Checking bun-pty compatibility...");
48
+ rebuildBunPty();
49
+ }
50
+ } else if (platform === "win32") {
51
+ // Windows: Check if DLL exists
52
+ if (!existsSync(libPath)) {
53
+ console.log("Windows DLL not found, attempting to rebuild...");
54
+ rebuildBunPty();
55
+ } else {
56
+ console.log("bun-pty Windows DLL found");
57
+ }
58
+ } else if (platform === "darwin") {
59
+ // macOS: Check if dylib exists
60
+ if (!existsSync(libPath)) {
61
+ console.log("macOS dylib not found, attempting to rebuild...");
62
+ rebuildBunPty();
63
+ } else {
64
+ console.log("bun-pty macOS dylib found");
65
+ }
66
+ } else {
67
+ console.log(`Platform ${platform} may require manual configuration`);
68
+ }
69
+
70
+ function rebuildBunPty() {
71
+ try {
72
+ // Check if cargo is available
73
+ const cargoCmd = platform === "win32" ? "cargo.exe" : "cargo";
74
+ try {
75
+ execSync(`${cargoCmd} --version`, { stdio: "ignore" });
76
+ } catch {
77
+ console.warn("Warning: Rust/Cargo not found. bun-pty native module may not work.");
78
+ console.warn("To fix this, install Rust: https://rustup.rs/");
79
+ return;
80
+ }
81
+
82
+ const rustPtyDir = join(bunPtyPath, "rust-pty");
83
+ const isWindows = platform === "win32";
84
+ const tempBase = isWindows ? process.env.TEMP || "C:\\Temp" : "/tmp";
85
+
86
+ // Check if source code exists
87
+ if (!existsSync(join(rustPtyDir, "Cargo.toml"))) {
88
+ // Try to clone and build from source
89
+ console.log("Source code not found in npm package, cloning from repository...");
90
+ const tmpDir = join(tempBase, `bun-pty-build-${Date.now()}`);
91
+
92
+ try {
93
+ execSync(`git clone https://github.com/snomiao/bun-pty.git "${tmpDir}"`, {
94
+ stdio: "inherit",
95
+ });
96
+
97
+ // Build command varies by platform
98
+ if (isWindows) {
99
+ execSync(
100
+ `cd /d "${tmpDir}" && cargo build --release --manifest-path rust-pty\\Cargo.toml`,
101
+ { stdio: "inherit" },
102
+ );
103
+ } else {
104
+ execSync(`cd "${tmpDir}" && cargo build --release --manifest-path rust-pty/Cargo.toml`, {
105
+ stdio: "inherit",
106
+ });
107
+ }
108
+
109
+ // Copy the built library
110
+ const builtLib = join(tmpDir, "rust-pty", "target", "release", libName);
111
+ if (existsSync(builtLib)) {
112
+ // Ensure target directory exists
113
+ const targetDir = join(rustPtyDir, "target", "release");
114
+ if (isWindows) {
115
+ execSync(`if not exist "${targetDir}" mkdir "${targetDir}"`, {});
116
+ execSync(`copy /Y "${builtLib}" "${libPath}"`, {});
117
+ } else {
118
+ execSync(`mkdir -p "${targetDir}"`, { stdio: "inherit" });
119
+ execSync(`cp "${builtLib}" "${libPath}"`, { stdio: "inherit" });
120
+ }
121
+ console.log("Successfully rebuilt bun-pty native module");
122
+ }
123
+
124
+ // Cleanup
125
+ if (isWindows) {
126
+ execSync(`rmdir /s /q "${tmpDir}"`, { stdio: "ignore" });
127
+ } else {
128
+ execSync(`rm -rf "${tmpDir}"`, { stdio: "ignore" });
129
+ }
130
+ } catch (buildError) {
131
+ console.error(
132
+ "Failed to build bun-pty:",
133
+ buildError instanceof Error ? buildError.message : buildError,
134
+ );
135
+ console.warn("The application may not work correctly without bun-pty");
136
+ }
137
+ } else {
138
+ // Build from included source
139
+ console.log("Building bun-pty from source...");
140
+ if (isWindows) {
141
+ execSync(`cd /d "${rustPtyDir}" && cargo build --release`, {
142
+ stdio: "inherit",
143
+ });
144
+ } else {
145
+ execSync(`cd "${rustPtyDir}" && cargo build --release`, {
146
+ stdio: "inherit",
147
+ });
148
+ }
149
+ console.log("Successfully rebuilt bun-pty native module");
150
+ }
151
+ } catch (error) {
152
+ console.error("Failed to rebuild bun-pty:", error instanceof Error ? error.message : error);
153
+ console.warn("The application may not work correctly without bun-pty");
154
+ }
155
+ }
package/ts/pty.ts ADDED
@@ -0,0 +1,18 @@
1
+ import { logger } from "./logger.ts";
2
+
3
+ // its recommened to use bun-pty in windows, since node-pty is super complex to install there, requires a 10G M$ build tools
4
+
5
+ async function getPty() {
6
+ return globalThis.Bun ? await import("bun-pty").catch((error) => {
7
+ logger.error("Failed to load bun-pty:", error);
8
+ throw error;
9
+ }) : await import("node-pty")
10
+ .catch((error) => {
11
+ logger.error("Failed to load node-pty:", error);
12
+ throw error;
13
+ });
14
+ };
15
+
16
+ const pty = await getPty();
17
+ export const ptyPackage = globalThis.Bun ? "bun-pty" : "node-pty";
18
+ export default pty;