claude-yes 1.29.2 → 1.30.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/claude-yes.js +12569 -4370
- package/dist/cli.js +12569 -4370
- package/dist/cli.js.map +204 -17
- package/dist/codex-yes.js +12569 -4370
- package/dist/copilot-yes.js +12569 -4370
- package/dist/cursor-yes.js +12569 -4370
- package/dist/gemini-yes.js +12569 -4370
- package/dist/grok-yes.js +12569 -4370
- package/dist/index.js +8311 -1726
- package/dist/index.js.map +156 -10
- package/dist/qwen-yes.js +12569 -4370
- package/package.json +11 -7
- package/ts/{tryCatch.spec.ts → catcher.spec.ts} +74 -21
- package/ts/catcher.ts +35 -0
- package/ts/cli.ts +23 -3
- package/ts/index.ts +50 -16
- package/ts/parseCliArgs.ts +3 -3
- package/ts/yesLog.ts +1 -1
- package/ts/tryCatch.ts +0 -25
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "claude-yes",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.30.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
|
"claude",
|
|
@@ -50,13 +50,15 @@
|
|
|
50
50
|
},
|
|
51
51
|
"files": [
|
|
52
52
|
"ts/*.ts",
|
|
53
|
-
"dist"
|
|
53
|
+
"dist",
|
|
54
|
+
"scripts"
|
|
54
55
|
],
|
|
55
56
|
"scripts": {
|
|
56
57
|
"build": "bun run build:index && bun run build:cli",
|
|
57
58
|
"postbuild": "bun ./ts/postbuild.ts",
|
|
58
|
-
"build:cli": "bun build ts/cli.ts --outdir=dist --target=node --sourcemap --external=
|
|
59
|
-
"build:index": "bun build ts/index.ts --outdir=dist --target=node --sourcemap --external=
|
|
59
|
+
"build:cli": "bun build ts/cli.ts --outdir=dist --target=node --sourcemap --external=bun-pty --external=node-pty --external=from-node-stream --external=bun",
|
|
60
|
+
"build:index": "bun build ts/index.ts --outdir=dist --target=node --sourcemap --external=bun-pty --external=node-pty --external=from-node-stream --external=bun",
|
|
61
|
+
"demo": "bun run build && bun link && claude-yes -- demo",
|
|
60
62
|
"dev": "bun ts/index.ts",
|
|
61
63
|
"fmt": "bunx @biomejs/biome check --fix && bunx sort-package-json",
|
|
62
64
|
"prepack": "bun run build",
|
|
@@ -89,8 +91,11 @@
|
|
|
89
91
|
]
|
|
90
92
|
},
|
|
91
93
|
"dependencies": {
|
|
94
|
+
"@types/ms": "^2.1.0",
|
|
95
|
+
"bun": "^1.3.1",
|
|
92
96
|
"bun-pty": "^0.3.2",
|
|
93
|
-
"from-node-stream": "^0.0.11"
|
|
97
|
+
"from-node-stream": "^0.0.11",
|
|
98
|
+
"ms": "^2.1.3"
|
|
94
99
|
},
|
|
95
100
|
"devDependencies": {
|
|
96
101
|
"@biomejs/biome": "^2.2.5",
|
|
@@ -103,7 +108,6 @@
|
|
|
103
108
|
"@types/node": "^24.0.10",
|
|
104
109
|
"@types/yargs": "^17.0.33",
|
|
105
110
|
"cpu-wait": "^0.0.10",
|
|
106
|
-
"enhanced-ms": "^4.1.0",
|
|
107
111
|
"execa": "^9.6.0",
|
|
108
112
|
"husky": "^9.1.7",
|
|
109
113
|
"lint-staged": "^16.1.4",
|
|
@@ -119,7 +123,7 @@
|
|
|
119
123
|
"yargs": "^18.0.0"
|
|
120
124
|
},
|
|
121
125
|
"peerDependencies": {
|
|
122
|
-
"node-pty": "^1.
|
|
126
|
+
"node-pty": "^1.1.0-beta38",
|
|
123
127
|
"typescript": "^5.8.3"
|
|
124
128
|
}
|
|
125
129
|
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { describe, expect, it } from 'vitest';
|
|
2
|
-
import { catcher } from './
|
|
2
|
+
import { catcher } from './catcher';
|
|
3
3
|
|
|
4
|
-
describe('
|
|
4
|
+
describe('catcher', () => {
|
|
5
5
|
describe('curried overload', () => {
|
|
6
6
|
it('should return a function when called with only catchFn', () => {
|
|
7
7
|
const catchFn = () => 'error';
|
|
@@ -9,10 +9,14 @@ describe('tryCatch', () => {
|
|
|
9
9
|
expect(typeof result).toBe('function');
|
|
10
10
|
});
|
|
11
11
|
|
|
12
|
-
it('should catch errors and call catchFn', () => {
|
|
12
|
+
it('should catch errors and call catchFn with error, function, and args', () => {
|
|
13
13
|
let catchedError: unknown;
|
|
14
|
-
|
|
14
|
+
let catchedFn: unknown;
|
|
15
|
+
let catchedArgs: unknown[];
|
|
16
|
+
const catchFn = (error: unknown, fn: unknown, ...args: unknown[]) => {
|
|
15
17
|
catchedError = error;
|
|
18
|
+
catchedFn = fn;
|
|
19
|
+
catchedArgs = args;
|
|
16
20
|
return 'caught';
|
|
17
21
|
};
|
|
18
22
|
|
|
@@ -27,6 +31,8 @@ describe('tryCatch', () => {
|
|
|
27
31
|
|
|
28
32
|
expect(result).toBe('caught');
|
|
29
33
|
expect(catchedError).toBeInstanceOf(Error);
|
|
34
|
+
expect(catchedFn).toBe(errorFn);
|
|
35
|
+
expect(catchedArgs).toEqual(['arg1', 'arg2']);
|
|
30
36
|
expect(calledArgs).toEqual(['arg1', 'arg2']);
|
|
31
37
|
});
|
|
32
38
|
|
|
@@ -53,10 +59,14 @@ describe('tryCatch', () => {
|
|
|
53
59
|
});
|
|
54
60
|
|
|
55
61
|
describe('direct overload', () => {
|
|
56
|
-
it('should catch errors and call catchFn directly', () => {
|
|
62
|
+
it('should catch errors and call catchFn with error, function, and args directly', () => {
|
|
57
63
|
let catchedError: unknown;
|
|
58
|
-
|
|
64
|
+
let catchedFn: unknown;
|
|
65
|
+
let catchedArgs: unknown[];
|
|
66
|
+
const catchFn = (error: unknown, fn: unknown, ...args: unknown[]) => {
|
|
59
67
|
catchedError = error;
|
|
68
|
+
catchedFn = fn;
|
|
69
|
+
catchedArgs = args;
|
|
60
70
|
return 'caught';
|
|
61
71
|
};
|
|
62
72
|
|
|
@@ -71,6 +81,8 @@ describe('tryCatch', () => {
|
|
|
71
81
|
|
|
72
82
|
expect(result).toBe('caught');
|
|
73
83
|
expect(catchedError).toBeInstanceOf(Error);
|
|
84
|
+
expect(catchedFn).toBe(errorFn);
|
|
85
|
+
expect(catchedArgs).toEqual(['arg1', 'arg2']);
|
|
74
86
|
expect(calledArgs).toEqual(['arg1', 'arg2']);
|
|
75
87
|
});
|
|
76
88
|
|
|
@@ -97,40 +109,52 @@ describe('tryCatch', () => {
|
|
|
97
109
|
});
|
|
98
110
|
|
|
99
111
|
describe('error handling', () => {
|
|
100
|
-
it('should handle different error types', () => {
|
|
112
|
+
it('should handle different error types and pass function context', () => {
|
|
101
113
|
const results: unknown[] = [];
|
|
102
|
-
const
|
|
114
|
+
const functions: unknown[] = [];
|
|
115
|
+
const catchFn = (error: unknown, fn: unknown, ...args: unknown[]) => {
|
|
103
116
|
results.push(error);
|
|
117
|
+
functions.push(fn);
|
|
104
118
|
return 'handled';
|
|
105
119
|
};
|
|
106
120
|
|
|
107
121
|
// String error
|
|
108
|
-
const stringErrorFn =
|
|
122
|
+
const stringErrorFn = () => {
|
|
109
123
|
throw 'string error';
|
|
110
|
-
}
|
|
111
|
-
|
|
124
|
+
};
|
|
125
|
+
const wrappedStringFn = catcher(catchFn, stringErrorFn);
|
|
126
|
+
expect(wrappedStringFn()).toBe('handled');
|
|
112
127
|
expect(results[0]).toBe('string error');
|
|
128
|
+
expect(functions[0]).toBe(stringErrorFn);
|
|
113
129
|
|
|
114
130
|
// Object error
|
|
115
131
|
const objectError = { message: 'object error' };
|
|
116
|
-
const objectErrorFn =
|
|
132
|
+
const objectErrorFn = () => {
|
|
117
133
|
throw objectError;
|
|
118
|
-
}
|
|
119
|
-
|
|
134
|
+
};
|
|
135
|
+
const wrappedObjectFn = catcher(catchFn, objectErrorFn);
|
|
136
|
+
expect(wrappedObjectFn()).toBe('handled');
|
|
120
137
|
expect(results[1]).toBe(objectError);
|
|
138
|
+
expect(functions[1]).toBe(objectErrorFn);
|
|
121
139
|
|
|
122
140
|
// null error
|
|
123
|
-
const nullErrorFn =
|
|
141
|
+
const nullErrorFn = () => {
|
|
124
142
|
throw null;
|
|
125
|
-
}
|
|
126
|
-
|
|
143
|
+
};
|
|
144
|
+
const wrappedNullFn = catcher(catchFn, nullErrorFn);
|
|
145
|
+
expect(wrappedNullFn()).toBe('handled');
|
|
127
146
|
expect(results[2]).toBe(null);
|
|
147
|
+
expect(functions[2]).toBe(nullErrorFn);
|
|
128
148
|
});
|
|
129
149
|
|
|
130
|
-
it('should preserve function parameters', () => {
|
|
150
|
+
it('should preserve function parameters and pass them to catchFn', () => {
|
|
131
151
|
let caughtError: unknown;
|
|
132
|
-
|
|
152
|
+
let caughtFn: unknown;
|
|
153
|
+
let caughtArgs: unknown[];
|
|
154
|
+
const catchFn = (error: unknown, fn: unknown, ...args: unknown[]) => {
|
|
133
155
|
caughtError = error;
|
|
156
|
+
caughtFn = fn;
|
|
157
|
+
caughtArgs = args;
|
|
134
158
|
return 'caught';
|
|
135
159
|
};
|
|
136
160
|
|
|
@@ -151,12 +175,18 @@ describe('tryCatch', () => {
|
|
|
151
175
|
expect(wrappedFn(10, 'error', false)).toBe('caught');
|
|
152
176
|
expect(testArgs).toEqual([10, 'error', false]);
|
|
153
177
|
expect(caughtError).toBeInstanceOf(Error);
|
|
178
|
+
expect(caughtFn).toBe(testFn);
|
|
179
|
+
expect(caughtArgs).toEqual([10, 'error', false]);
|
|
154
180
|
});
|
|
155
181
|
|
|
156
182
|
it('should handle functions with no parameters', () => {
|
|
157
183
|
let caughtError: unknown;
|
|
158
|
-
|
|
184
|
+
let caughtFn: unknown;
|
|
185
|
+
let caughtArgs: unknown[];
|
|
186
|
+
const catchFn = (error: unknown, fn: unknown, ...args: unknown[]) => {
|
|
159
187
|
caughtError = error;
|
|
188
|
+
caughtFn = fn;
|
|
189
|
+
caughtArgs = args;
|
|
160
190
|
return 'no params caught';
|
|
161
191
|
};
|
|
162
192
|
|
|
@@ -172,6 +202,8 @@ describe('tryCatch', () => {
|
|
|
172
202
|
expect(result).toBe('no params caught');
|
|
173
203
|
expect(called).toBe(true);
|
|
174
204
|
expect(caughtError).toBeInstanceOf(Error);
|
|
205
|
+
expect(caughtFn).toBe(noParamsFn);
|
|
206
|
+
expect(caughtArgs).toEqual([]);
|
|
175
207
|
});
|
|
176
208
|
|
|
177
209
|
it('should handle functions returning different types', () => {
|
|
@@ -194,7 +226,8 @@ describe('tryCatch', () => {
|
|
|
194
226
|
|
|
195
227
|
describe('type safety', () => {
|
|
196
228
|
it('should maintain function signature', () => {
|
|
197
|
-
const catchFn = (error: unknown) =>
|
|
229
|
+
const catchFn = (error: unknown, fn: unknown, ...args: unknown[]) =>
|
|
230
|
+
'error';
|
|
198
231
|
const originalFn = (a: number, b: string): string => `${a}-${b}`;
|
|
199
232
|
|
|
200
233
|
const wrappedFn = catcher(catchFn, originalFn);
|
|
@@ -203,5 +236,25 @@ describe('tryCatch', () => {
|
|
|
203
236
|
const result: string = wrappedFn(1, 'test');
|
|
204
237
|
expect(result).toBe('1-test');
|
|
205
238
|
});
|
|
239
|
+
|
|
240
|
+
it('should pass function reference and arguments to catchFn', () => {
|
|
241
|
+
let capturedFn: unknown;
|
|
242
|
+
let capturedArgs: unknown[];
|
|
243
|
+
const catchFn = (error: unknown, fn: unknown, ...args: unknown[]) => {
|
|
244
|
+
capturedFn = fn;
|
|
245
|
+
capturedArgs = args;
|
|
246
|
+
return 'handled';
|
|
247
|
+
};
|
|
248
|
+
|
|
249
|
+
const testFn = (x: number, y: string) => {
|
|
250
|
+
throw new Error('test');
|
|
251
|
+
};
|
|
252
|
+
|
|
253
|
+
const wrappedFn = catcher(catchFn, testFn);
|
|
254
|
+
wrappedFn(42, 'hello');
|
|
255
|
+
|
|
256
|
+
expect(capturedFn).toBe(testFn);
|
|
257
|
+
expect(capturedArgs).toEqual([42, 'hello']);
|
|
258
|
+
});
|
|
206
259
|
});
|
|
207
260
|
});
|
package/ts/catcher.ts
ADDED
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
// curried overload
|
|
2
|
+
export function catcher<F extends (...args: any[]) => any, R>(
|
|
3
|
+
catchFn: (error: unknown, fn: F, ...args: Parameters<F>) => R,
|
|
4
|
+
): (fn: F) => (...args: Parameters<F>) => ReturnType<F> | R;
|
|
5
|
+
|
|
6
|
+
// direct overload
|
|
7
|
+
export function catcher<F extends (...args: any[]) => any, R>(
|
|
8
|
+
catchFn: (error: unknown, fn: F, ...args: Parameters<F>) => R,
|
|
9
|
+
fn: F,
|
|
10
|
+
): (...args: Parameters<F>) => ReturnType<F> | R;
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* A utility function to wrap another function with a try-catch block.
|
|
14
|
+
* If an error occurs during the execution of the function, the provided
|
|
15
|
+
* catchFn is called with the error, the original function, and its arguments.
|
|
16
|
+
*
|
|
17
|
+
* This function supports both direct invocation and curried usage.
|
|
18
|
+
*
|
|
19
|
+
* @param catchFn - The function to call when an error occurs.
|
|
20
|
+
* @param fn - The function to wrap (optional for curried usage).
|
|
21
|
+
* @returns A new function that wraps the original function with error handling.
|
|
22
|
+
*/
|
|
23
|
+
export function catcher<F extends (...args: any[]) => any, R>(
|
|
24
|
+
catchFn: (error: unknown, fn: F, ...args: Parameters<F>) => R,
|
|
25
|
+
fn?: F,
|
|
26
|
+
) {
|
|
27
|
+
if (!fn) return (fn: F) => catcher(catchFn, fn) as any;
|
|
28
|
+
return (...args: Parameters<F>) => {
|
|
29
|
+
try {
|
|
30
|
+
return fn(...args);
|
|
31
|
+
} catch (error) {
|
|
32
|
+
return catchFn(error, fn, ...args);
|
|
33
|
+
}
|
|
34
|
+
};
|
|
35
|
+
}
|
package/ts/cli.ts
CHANGED
|
@@ -1,14 +1,34 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import DIE from 'phpdie';
|
|
3
|
-
import
|
|
3
|
+
import cliYesConfig from '../cli-yes.config';
|
|
4
4
|
|
|
5
|
-
// if
|
|
5
|
+
// if node-pty is not installed, re-run with bun
|
|
6
|
+
// const hasNodePty = !!await import('node-pty').catch(() => null);
|
|
7
|
+
if (!globalThis.Bun) {
|
|
8
|
+
// run with same arguments in Bun if not already
|
|
9
|
+
console.log('Re-running with Bun...', process.argv);
|
|
10
|
+
(await import('child_process')).spawnSync(
|
|
11
|
+
'node_modules/.bin/bun',
|
|
12
|
+
[process.argv[1]!, '--', ...process.argv.slice(2)],
|
|
13
|
+
{ stdio: 'inherit' },
|
|
14
|
+
);
|
|
15
|
+
process.exit(0);
|
|
16
|
+
}
|
|
17
|
+
// check and fix bun-pty on some systems
|
|
18
|
+
if (globalThis.Bun) console.log('Bun detected, using bun-pty');
|
|
19
|
+
// await import("./fix-pty.js")
|
|
20
|
+
|
|
21
|
+
// console.log('Running', process.argv);
|
|
22
|
+
|
|
23
|
+
// Import the CLI module
|
|
24
|
+
const { default: cliYes, parseCliArgs } = await import('./');
|
|
6
25
|
|
|
7
26
|
// Parse CLI arguments
|
|
8
27
|
const config = parseCliArgs(process.argv);
|
|
9
28
|
|
|
10
29
|
// Validate CLI name
|
|
11
|
-
if (!config.cli)
|
|
30
|
+
if (!config.cli)
|
|
31
|
+
DIE`missing cli def, available clis: ${Object.keys((await cliYesConfig).clis).join(', ')}`;
|
|
12
32
|
|
|
13
33
|
if (config.verbose) {
|
|
14
34
|
process.env.VERBOSE = 'true'; // enable verbose logging in yesLog.ts
|
package/ts/index.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { execaCommand, execaCommandSync, parseCommandString } from 'execa';
|
|
1
2
|
import { fromReadable, fromWritable } from 'from-node-stream';
|
|
2
3
|
import { mkdir, writeFile } from 'fs/promises';
|
|
3
4
|
import path from 'path';
|
|
@@ -5,6 +6,7 @@ import DIE from 'phpdie';
|
|
|
5
6
|
import sflow from 'sflow';
|
|
6
7
|
import { TerminalTextRender } from 'terminal-render';
|
|
7
8
|
import rawConfig from '../cli-yes.config.js';
|
|
9
|
+
import { catcher } from './catcher.js';
|
|
8
10
|
import {
|
|
9
11
|
extractSessionId,
|
|
10
12
|
getSessionForCwd,
|
|
@@ -19,7 +21,6 @@ import {
|
|
|
19
21
|
shouldUseLock,
|
|
20
22
|
updateCurrentTaskStatus,
|
|
21
23
|
} from './runningLock';
|
|
22
|
-
import { catcher } from './tryCatch';
|
|
23
24
|
import { yesLog } from './yesLog';
|
|
24
25
|
|
|
25
26
|
export { parseCliArgs } from './parseCliArgs';
|
|
@@ -36,6 +37,7 @@ export type AgentCliConfig = {
|
|
|
36
37
|
defaultArgs?: string[]; // function to ensure certain args are present
|
|
37
38
|
noEOL?: boolean; // if true, do not split lines by \n, used for codex, which uses cursor-move csi code instead of \n to move lines
|
|
38
39
|
promptArg?: (string & {}) | 'first-arg' | 'last-arg'; // argument name to pass the prompt, e.g. --prompt, or first-arg for positional arg
|
|
40
|
+
bunx?: boolean; // if true, use bunx to run the binary
|
|
39
41
|
};
|
|
40
42
|
export type CliYesConfig = {
|
|
41
43
|
clis: { [key: string]: AgentCliConfig };
|
|
@@ -91,6 +93,7 @@ export default async function cliYes({
|
|
|
91
93
|
removeControlCharactersFromStdout = false, // = !process.stdout.isTTY,
|
|
92
94
|
verbose = false,
|
|
93
95
|
queue = true,
|
|
96
|
+
install = false,
|
|
94
97
|
}: {
|
|
95
98
|
cli: SUPPORTED_CLIS;
|
|
96
99
|
cliArgs?: string[];
|
|
@@ -103,6 +106,7 @@ export default async function cliYes({
|
|
|
103
106
|
removeControlCharactersFromStdout?: boolean;
|
|
104
107
|
verbose?: boolean;
|
|
105
108
|
queue?: boolean;
|
|
109
|
+
install?: boolean; // if true, install the cli tool if not installed, e.g. will run `npm install -g cursor-agent`
|
|
106
110
|
}) {
|
|
107
111
|
// those overrides seems only works in bun
|
|
108
112
|
// await Promise.allSettled([
|
|
@@ -118,7 +122,11 @@ export default async function cliYes({
|
|
|
118
122
|
// });
|
|
119
123
|
|
|
120
124
|
if (!cli) throw new Error(`cli is required`);
|
|
121
|
-
const conf =
|
|
125
|
+
const conf =
|
|
126
|
+
CLIS_CONFIG[cli] ||
|
|
127
|
+
DIE(
|
|
128
|
+
`Unsupported cli tool: ${cli}, current process.argv: ${process.argv.join(' ')}`,
|
|
129
|
+
);
|
|
122
130
|
|
|
123
131
|
// Acquire lock before starting agent (if in git repo or same cwd and lock is not disabled)
|
|
124
132
|
const workingDir = cwd ?? process.cwd();
|
|
@@ -157,12 +165,12 @@ export default async function cliYes({
|
|
|
157
165
|
// const pty = await import('node-pty');
|
|
158
166
|
|
|
159
167
|
// its recommened to use bun-pty in windows
|
|
160
|
-
const pty = await (globalThis.Bun
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
)
|
|
165
|
-
|
|
168
|
+
const pty = await (globalThis.Bun
|
|
169
|
+
? import('bun-pty')
|
|
170
|
+
: import('node-pty')
|
|
171
|
+
).catch(async () =>
|
|
172
|
+
DIE('Please install node-pty or bun-pty, run this: bun install bun-pty'),
|
|
173
|
+
);
|
|
166
174
|
|
|
167
175
|
// Detect if running as sub-agent
|
|
168
176
|
const isSubAgent = !!process.env.CLAUDE_PPID;
|
|
@@ -223,34 +231,60 @@ export default async function cliYes({
|
|
|
223
231
|
}
|
|
224
232
|
const cliCommand = cliConf?.binary || cli;
|
|
225
233
|
|
|
234
|
+
const spawn = () => {
|
|
235
|
+
// const [bin, ...args] = [...parseCommandString((cliConf.bunx ? 'bunx --bun ' : '') + cliCommand), ...(cliArgs)];
|
|
236
|
+
// console.log(`Spawning ${bin} with args: ${JSON.stringify(args)}`);
|
|
237
|
+
// return pty.spawn(bin!, args, getPtyOptions());
|
|
238
|
+
return pty.spawn(cliCommand, cliArgs, getPtyOptions());
|
|
239
|
+
};
|
|
226
240
|
let shell = catcher(
|
|
227
|
-
|
|
241
|
+
// error handler
|
|
242
|
+
(error: unknown, fn, ...args) => {
|
|
228
243
|
console.error(`Fatal: Failed to start ${cliCommand}.`);
|
|
244
|
+
|
|
229
245
|
if (cliConf?.install && isCommandNotFoundError(error))
|
|
246
|
+
if (install) {
|
|
247
|
+
console.log(`Attempting to install ${cli}...`);
|
|
248
|
+
execaCommandSync(cliConf.install, { stdio: 'inherit' });
|
|
249
|
+
console.log(
|
|
250
|
+
`${cli} installed successfully. Please rerun the command.`,
|
|
251
|
+
);
|
|
252
|
+
return spawn();
|
|
253
|
+
}
|
|
254
|
+
console.error(
|
|
255
|
+
`If you did not installed it yet, Please install it first: ${cliConf.install}`,
|
|
256
|
+
);
|
|
257
|
+
|
|
258
|
+
if (
|
|
259
|
+
globalThis.Bun &&
|
|
260
|
+
error instanceof Error &&
|
|
261
|
+
error.stack?.includes('bun-pty')
|
|
262
|
+
) {
|
|
263
|
+
// try to fix bun-pty issues
|
|
230
264
|
console.error(
|
|
231
|
-
`
|
|
265
|
+
`Detected bun-pty issue, attempted to fix it. Please try again.`,
|
|
232
266
|
);
|
|
267
|
+
require('./fix-pty.js');
|
|
268
|
+
// unable to retry with same process, so exit here.
|
|
269
|
+
}
|
|
233
270
|
throw error;
|
|
234
271
|
|
|
235
272
|
function isCommandNotFoundError(e: unknown) {
|
|
236
273
|
if (e instanceof Error) {
|
|
237
274
|
return (
|
|
238
|
-
e.message.includes('command not found') ||
|
|
239
|
-
e.message.includes('ENOENT') ||
|
|
275
|
+
e.message.includes('command not found') || // unix
|
|
276
|
+
e.message.includes('ENOENT') || // unix
|
|
240
277
|
e.message.includes('spawn') // windows
|
|
241
278
|
);
|
|
242
279
|
}
|
|
243
280
|
return false;
|
|
244
281
|
}
|
|
245
282
|
},
|
|
246
|
-
|
|
283
|
+
spawn,
|
|
247
284
|
)();
|
|
248
285
|
const pendingExitCode = Promise.withResolvers<number | null>();
|
|
249
286
|
let pendingExitCodeValue = null;
|
|
250
287
|
|
|
251
|
-
// TODO handle error if claude is not installed, show msg:
|
|
252
|
-
// npm install -g @anthropic-ai/claude-code
|
|
253
|
-
|
|
254
288
|
async function onData(data: string) {
|
|
255
289
|
// append data to the buffer, so we can process it later
|
|
256
290
|
await outputWriter.write(data);
|
package/ts/parseCliArgs.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import
|
|
1
|
+
import ms from 'ms';
|
|
2
2
|
import yargs from 'yargs';
|
|
3
3
|
import { hideBin } from 'yargs/helpers';
|
|
4
4
|
import { SUPPORTED_CLIS } from '.';
|
|
@@ -12,7 +12,7 @@ export function parseCliArgs(argv: string[]) {
|
|
|
12
12
|
const scriptName = argv[1]?.split(/[\/\\]/).pop();
|
|
13
13
|
const cliName = ((e?: string) => {
|
|
14
14
|
if (e === 'cli' || e === 'cli.ts' || e === 'cli.js') return undefined;
|
|
15
|
-
return e?.replace(/-yes
|
|
15
|
+
return e?.replace(/-yes(\.[jt]s)?$/, '');
|
|
16
16
|
})(scriptName);
|
|
17
17
|
|
|
18
18
|
// Parse args with yargs (same logic as cli.ts:16-73)
|
|
@@ -105,7 +105,7 @@ export function parseCliArgs(argv: string[]) {
|
|
|
105
105
|
[parsedArgv.prompt, dashPrompt].filter(Boolean).join(' ') || undefined,
|
|
106
106
|
exitOnIdle: Number(
|
|
107
107
|
(parsedArgv.idle || parsedArgv.exitOnIdle)?.replace(/.*/, (e) =>
|
|
108
|
-
String(
|
|
108
|
+
String(ms(e as ms.StringValue)),
|
|
109
109
|
) || 0,
|
|
110
110
|
),
|
|
111
111
|
queue: parsedArgv.queue,
|
package/ts/yesLog.ts
CHANGED
package/ts/tryCatch.ts
DELETED
|
@@ -1,25 +0,0 @@
|
|
|
1
|
-
// curried overload
|
|
2
|
-
export function catcher<F extends (...args: any[]) => any, R>(
|
|
3
|
-
catchFn: (error: unknown) => R,
|
|
4
|
-
): (fn: F) => (...args: Parameters<F>) => ReturnType<F> | R;
|
|
5
|
-
|
|
6
|
-
// direct overload
|
|
7
|
-
export function catcher<F extends (...args: any[]) => any, R>(
|
|
8
|
-
catchFn: (error: unknown) => R,
|
|
9
|
-
fn: F,
|
|
10
|
-
): (...args: Parameters<F>) => ReturnType<F> | R;
|
|
11
|
-
|
|
12
|
-
// implementation
|
|
13
|
-
export function catcher<F extends (...args: any[]) => any, R>(
|
|
14
|
-
catchFn: (error: unknown) => R,
|
|
15
|
-
fn?: F,
|
|
16
|
-
) {
|
|
17
|
-
if (!fn) return (fn: F) => catcher(catchFn, fn) as any;
|
|
18
|
-
return (...args: Parameters<F>) => {
|
|
19
|
-
try {
|
|
20
|
-
return fn(...args);
|
|
21
|
-
} catch (error) {
|
|
22
|
-
return catchFn(error);
|
|
23
|
-
}
|
|
24
|
-
};
|
|
25
|
-
}
|