claude-yes 1.20.0 → 1.21.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.
- package/README.md +26 -0
- package/dist/claude-yes.js +43 -37
- package/dist/cli.js +43 -37
- package/dist/cli.js.map +3 -3
- package/dist/codex-yes.js +43 -37
- package/dist/copilot-yes.js +43 -37
- package/dist/cursor-yes.js +43 -37
- package/dist/gemini-yes.js +43 -37
- package/dist/grok-yes.js +338 -0
- package/dist/index.js +43 -37
- package/dist/index.js.map +3 -3
- package/index.ts +58 -57
- package/package.json +14 -13
- package/postbuild.ts +10 -1
package/index.ts
CHANGED
|
@@ -11,29 +11,38 @@ import { removeControlCharacters } from './removeControlCharacters';
|
|
|
11
11
|
export const CLI_CONFIGURES: Record<
|
|
12
12
|
string,
|
|
13
13
|
{
|
|
14
|
+
install?: string; // hint user for install command if not installed
|
|
14
15
|
binary?: string; // actual binary name if different from cli
|
|
15
|
-
ready?: RegExp; // regex matcher for stdin ready, or line index for gemini
|
|
16
|
+
ready?: RegExp[]; // regex matcher for stdin ready, or line index for gemini
|
|
16
17
|
enter?: RegExp[]; // array of regex to match for sending Enter
|
|
17
18
|
fatal?: RegExp[]; // array of regex to match for fatal errors
|
|
18
19
|
ensureArgs?: (args: string[]) => string[]; // function to ensure certain args are present
|
|
19
20
|
}
|
|
20
21
|
> = {
|
|
22
|
+
grok: {
|
|
23
|
+
install: 'npm install -g @vibe-kit/grok-cli',
|
|
24
|
+
ready: [/^ │ ❯ /],
|
|
25
|
+
enter: [/^ 1. Yes/],
|
|
26
|
+
},
|
|
21
27
|
claude: {
|
|
22
|
-
|
|
28
|
+
install: 'npm install -g @anthropic-ai/claude-code',
|
|
29
|
+
ready: [/^> /], // regex matcher for stdin ready,
|
|
23
30
|
enter: [/❯ 1. Yes/, /❯ 1. Dark mode✔/, /Press Enter to continue…/],
|
|
24
31
|
fatal: [
|
|
25
32
|
/No conversation found to continue/,
|
|
26
|
-
/⎿
|
|
33
|
+
/⎿ Claude usage limit reached\./,
|
|
27
34
|
],
|
|
28
35
|
},
|
|
29
36
|
gemini: {
|
|
37
|
+
install: 'npm install -g @google/gemini-cli',
|
|
30
38
|
// match the agent prompt after initial lines; handled by index logic using line index
|
|
31
|
-
ready: /Type your message
|
|
39
|
+
ready: [/Type your message/], // used with line index check
|
|
32
40
|
enter: [/│ ● 1. Yes, allow once/],
|
|
33
41
|
fatal: [],
|
|
34
42
|
},
|
|
35
43
|
codex: {
|
|
36
|
-
|
|
44
|
+
install: 'npm install -g @openai/codex-cli',
|
|
45
|
+
ready: [/⏎ send/],
|
|
37
46
|
enter: [/ > 1. Approve/, /> 1. Yes, allow Codex to work in this folder/],
|
|
38
47
|
fatal: [/Error: The cursor position could not be read within/],
|
|
39
48
|
// add to codex --search by default when not provided by the user
|
|
@@ -43,16 +52,18 @@ export const CLI_CONFIGURES: Record<
|
|
|
43
52
|
},
|
|
44
53
|
},
|
|
45
54
|
copilot: {
|
|
46
|
-
|
|
55
|
+
install: 'npm install -g @github/copilot',
|
|
56
|
+
ready: [/^ > /],
|
|
47
57
|
enter: [/ │ ❯ 1. Yes, proceed/, /❯ 1. Yes/],
|
|
48
58
|
fatal: [],
|
|
49
59
|
},
|
|
50
60
|
cursor: {
|
|
61
|
+
install: 'open https://cursor.com/ja/docs/cli/installation',
|
|
51
62
|
// map logical "cursor" cli name to actual binary name
|
|
52
63
|
binary: 'cursor-agent',
|
|
53
|
-
ready: /\/ commands
|
|
64
|
+
ready: [/\/ commands/],
|
|
54
65
|
enter: [/→ Run \(once\) \(y\) \(enter\)/, /▶ \[a\] Trust this workspace/],
|
|
55
|
-
fatal: [],
|
|
66
|
+
fatal: [/^ Error: You've hit your usage limit/],
|
|
56
67
|
},
|
|
57
68
|
};
|
|
58
69
|
/**
|
|
@@ -131,7 +142,7 @@ export default async function claudeYes({
|
|
|
131
142
|
// );
|
|
132
143
|
|
|
133
144
|
process.stdin.setRawMode?.(true); // must be called any stdout/stdin usage
|
|
134
|
-
let isFatal = false; //
|
|
145
|
+
let isFatal = false; // when true, do not restart on crash, and exit agent
|
|
135
146
|
const stdinReady = new ReadyManager();
|
|
136
147
|
|
|
137
148
|
const shellOutputStream = new TransformStream<string, string>();
|
|
@@ -157,7 +168,17 @@ export default async function claudeYes({
|
|
|
157
168
|
cliArgs = cliConf.ensureArgs?.(cliArgs) ?? cliArgs;
|
|
158
169
|
const cliCommand = cliConf?.binary || cli;
|
|
159
170
|
|
|
160
|
-
let shell =
|
|
171
|
+
let shell = tryCatch(
|
|
172
|
+
() => pty.spawn(cliCommand, cliArgs, getPtyOptions()),
|
|
173
|
+
(error: unknown) => {
|
|
174
|
+
console.error(`Fatal: Failed to start ${cliCommand}.`);
|
|
175
|
+
if (cliConf?.install)
|
|
176
|
+
console.error(
|
|
177
|
+
`If you did not installed it yet, Please install it first: ${cliConf.install}`,
|
|
178
|
+
);
|
|
179
|
+
throw error;
|
|
180
|
+
},
|
|
181
|
+
);
|
|
161
182
|
const pendingExitCode = Promise.withResolvers<number | null>();
|
|
162
183
|
let pendingExitCodeValue = null;
|
|
163
184
|
|
|
@@ -182,11 +203,9 @@ export default async function claudeYes({
|
|
|
182
203
|
);
|
|
183
204
|
}
|
|
184
205
|
if (isFatal) {
|
|
185
|
-
console.log(
|
|
186
|
-
`${cli} crashed with "No conversation found to continue", exiting...`,
|
|
187
|
-
);
|
|
188
206
|
return pendingExitCode.resolve((pendingExitCodeValue = exitCode));
|
|
189
207
|
}
|
|
208
|
+
|
|
190
209
|
console.log(`${cli} crashed, restarting...`);
|
|
191
210
|
|
|
192
211
|
shell = pty.spawn(cli, continueArg, getPtyOptions());
|
|
@@ -269,33 +288,20 @@ export default async function claudeYes({
|
|
|
269
288
|
CLI_CONFIGURES[cli as keyof typeof CLI_CONFIGURES] || null;
|
|
270
289
|
if (!conf) return;
|
|
271
290
|
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
if (
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
if (e.match(rx)) return await sendEnter();
|
|
287
|
-
}
|
|
288
|
-
}
|
|
289
|
-
|
|
290
|
-
// fatal matchers: set isFatal flag when matched
|
|
291
|
-
if (conf.fatal && Array.isArray(conf.fatal)) {
|
|
292
|
-
for (const rx of conf.fatal) {
|
|
293
|
-
if (e.match(rx)) return (isFatal = true);
|
|
294
|
-
}
|
|
295
|
-
}
|
|
296
|
-
} catch (err) {
|
|
297
|
-
// defensive: if e.match throws (e.g., not a string), ignore
|
|
298
|
-
return;
|
|
291
|
+
// ready matcher: if matched, mark stdin ready
|
|
292
|
+
if (conf.ready?.some((rx: RegExp) => e.match(rx))) {
|
|
293
|
+
if (cli === 'gemini' && i <= 80) return; // gemini initial noise, only after many lines
|
|
294
|
+
stdinReady.ready();
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
// enter matchers: send Enter when any enter regex matches
|
|
298
|
+
if (conf.enter?.some((rx: RegExp) => e.match(rx)))
|
|
299
|
+
await sendEnter(300); // send Enter after 300ms idle wait
|
|
300
|
+
|
|
301
|
+
// fatal matchers: set isFatal flag when matched
|
|
302
|
+
if (conf.fatal?.some((rx: RegExp) => e.match(rx))) {
|
|
303
|
+
isFatal = true;
|
|
304
|
+
await exitAgent();
|
|
299
305
|
}
|
|
300
306
|
})
|
|
301
307
|
// .forEach(e => appendFile('.cache/io.log', "output|" + JSON.stringify(e) + '\n')) // for debugging
|
|
@@ -308,22 +314,7 @@ export default async function claudeYes({
|
|
|
308
314
|
.then(() => null); // run it immediately without await
|
|
309
315
|
|
|
310
316
|
// wait for cli ready and send prompt if provided
|
|
311
|
-
if (prompt)
|
|
312
|
-
(async () => {
|
|
313
|
-
// console.log(`[${cli}-yes] Ready to send prompt to ${cli}: ${prompt}`);
|
|
314
|
-
// idleWaiter.ping();
|
|
315
|
-
// console.log(
|
|
316
|
-
// 'await idleWaiter.wait(1000); // wait a bit for claude to start'
|
|
317
|
-
// );
|
|
318
|
-
// await idleWaiter.wait(1000); // wait a bit for claude to start
|
|
319
|
-
// console.log('await stdinReady.wait();');
|
|
320
|
-
// await stdinReady.wait();
|
|
321
|
-
// console.log(`[${cli}-yes] Waiting for ${cli} to be ready...`);
|
|
322
|
-
// console.log('await idleWaiter.wait(200);');
|
|
323
|
-
// await idleWaiter.wait(200);
|
|
324
|
-
// console.log(`[${cli}-yes] Sending prompt to ${cli}: ${prompt}`);
|
|
325
|
-
await sendMessage(prompt);
|
|
326
|
-
})();
|
|
317
|
+
if (prompt) await sendMessage(prompt);
|
|
327
318
|
|
|
328
319
|
const exitCode = await pendingExitCode.promise; // wait for the shell to exit
|
|
329
320
|
console.log(`[${cli}-yes] ${cli} exited with code ${exitCode}`);
|
|
@@ -381,10 +372,20 @@ export default async function claudeYes({
|
|
|
381
372
|
|
|
382
373
|
function getTerminalDimensions() {
|
|
383
374
|
return {
|
|
384
|
-
|
|
375
|
+
// TODO: enforce minimum cols/rows to avoid layout issues
|
|
376
|
+
// cols: Math.max(process.stdout.columns, 80),
|
|
377
|
+
cols: process.stdout.columns,
|
|
385
378
|
rows: process.stdout.rows,
|
|
386
379
|
};
|
|
387
380
|
}
|
|
388
381
|
}
|
|
389
382
|
|
|
390
383
|
export { removeControlCharacters };
|
|
384
|
+
|
|
385
|
+
function tryCatch<T, R>(fn: () => T, catchFn: (error: unknown) => R): T | R {
|
|
386
|
+
try {
|
|
387
|
+
return fn();
|
|
388
|
+
} catch (error) {
|
|
389
|
+
return catchFn(error);
|
|
390
|
+
}
|
|
391
|
+
}
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "claude-yes",
|
|
3
|
-
"version": "1.
|
|
4
|
-
"description": "A wrapper tool that automates interactions with
|
|
3
|
+
"version": "1.21.1",
|
|
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",
|
|
7
7
|
"ai",
|
|
@@ -33,9 +33,10 @@
|
|
|
33
33
|
"bin": {
|
|
34
34
|
"claude-yes": "dist/claude-yes.js",
|
|
35
35
|
"codex-yes": "dist/codex-yes.js",
|
|
36
|
-
"
|
|
36
|
+
"copilot-yes": "dist/copilot-yes.js",
|
|
37
37
|
"cursor-yes": "dist/cursor-yes.js",
|
|
38
|
-
"
|
|
38
|
+
"gemini-yes": "dist/gemini-yes.js",
|
|
39
|
+
"grok-yes": "dist/grok-yes.js"
|
|
39
40
|
},
|
|
40
41
|
"directories": {
|
|
41
42
|
"doc": "docs"
|
|
@@ -48,7 +49,7 @@
|
|
|
48
49
|
"build": "bun build index.ts cli.ts --packages=external --outdir=dist --target=node --sourcemap",
|
|
49
50
|
"postbuild": "bun ./postbuild.ts",
|
|
50
51
|
"dev": "tsx index.ts",
|
|
51
|
-
"fmt": "bunx @biomejs/biome check --fix",
|
|
52
|
+
"fmt": "bunx @biomejs/biome check --fix && bunx sort-package-json",
|
|
52
53
|
"prepack": "bun run build",
|
|
53
54
|
"prepare": "bunx husky",
|
|
54
55
|
"test": "vitest"
|
|
@@ -58,6 +59,11 @@
|
|
|
58
59
|
"bunx @biomejs/biome check --fix"
|
|
59
60
|
]
|
|
60
61
|
},
|
|
62
|
+
"dependencies": {
|
|
63
|
+
"bun-pty": "^0.3.2",
|
|
64
|
+
"p-map": "^7.0.3",
|
|
65
|
+
"phpdie": "^1.7.0"
|
|
66
|
+
},
|
|
61
67
|
"devDependencies": {
|
|
62
68
|
"@biomejs/biome": "^2.2.5",
|
|
63
69
|
"@types/bun": "^1.2.18",
|
|
@@ -73,18 +79,13 @@
|
|
|
73
79
|
"semantic-release": "^24.2.6",
|
|
74
80
|
"sflow": "^1.20.2",
|
|
75
81
|
"strip-ansi-control-characters": "^2.0.0",
|
|
76
|
-
"terminal-render": "^1.
|
|
82
|
+
"terminal-render": "^1.2.0",
|
|
77
83
|
"tsx": "^4.20.3",
|
|
78
84
|
"vitest": "^3.2.4",
|
|
79
85
|
"yargs": "^18.0.0"
|
|
80
86
|
},
|
|
81
87
|
"peerDependencies": {
|
|
82
|
-
"
|
|
83
|
-
"
|
|
84
|
-
},
|
|
85
|
-
"dependencies": {
|
|
86
|
-
"bun-pty": "^0.3.2",
|
|
87
|
-
"p-map": "^7.0.3",
|
|
88
|
-
"phpdie": "^1.7.0"
|
|
88
|
+
"node-pty": "^1.0.0",
|
|
89
|
+
"typescript": "^5.8.3"
|
|
89
90
|
}
|
|
90
91
|
}
|
package/postbuild.ts
CHANGED
|
@@ -1,6 +1,15 @@
|
|
|
1
1
|
#! /usr/bin/env bun
|
|
2
|
+
import { execaCommand } from 'execa';
|
|
2
3
|
import { copyFile } from 'fs/promises';
|
|
4
|
+
import { CLI_CONFIGURES } from '.';
|
|
3
5
|
import * as pkg from './package.json';
|
|
4
6
|
|
|
5
7
|
const src = 'dist/cli.js';
|
|
6
|
-
await Promise.all(
|
|
8
|
+
await Promise.all(
|
|
9
|
+
Object.keys(CLI_CONFIGURES).map(async (cli) => {
|
|
10
|
+
const dst = `dist/${cli}-yes.js`;
|
|
11
|
+
if (!pkg.bin?.[cli as keyof typeof pkg.bin])
|
|
12
|
+
await execaCommand(`npm pkg set bin.${cli}-yes=${dst}`);
|
|
13
|
+
await copyFile(src, dst);
|
|
14
|
+
}),
|
|
15
|
+
);
|