claude-yes 1.23.1 → 1.23.2
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 +13 -15
- package/dist/cli.js +13 -15
- package/dist/cli.js.map +3 -3
- package/dist/codex-yes.js +13 -15
- package/dist/copilot-yes.js +13 -15
- package/dist/cursor-yes.js +13 -15
- package/dist/gemini-yes.js +13 -15
- package/dist/grok-yes.js +13 -15
- package/dist/index.js +13 -15
- package/dist/index.js.map +3 -3
- package/index.ts +21 -12
- package/package.json +1 -1
package/dist/claude-yes.js
CHANGED
|
@@ -25,12 +25,11 @@ import { hideBin } from "yargs/helpers";
|
|
|
25
25
|
|
|
26
26
|
// dist/index.js
|
|
27
27
|
import { fromReadable, fromWritable } from "from-node-stream";
|
|
28
|
-
import {
|
|
28
|
+
import { mkdir, writeFile } from "fs/promises";
|
|
29
29
|
import path from "path";
|
|
30
30
|
import DIE from "phpdie";
|
|
31
31
|
import sflow from "sflow";
|
|
32
32
|
import { TerminalTextRender } from "terminal-render";
|
|
33
|
-
import tsaComposer from "tsa-composer";
|
|
34
33
|
class IdleWaiter {
|
|
35
34
|
lastActivityTime = Date.now();
|
|
36
35
|
checkInterval = 100;
|
|
@@ -94,7 +93,7 @@ var CLI_CONFIGURES = {
|
|
|
94
93
|
ready: [/⏎ send/],
|
|
95
94
|
enter: [
|
|
96
95
|
/> 1. Yes, allow Codex to work in this folder/,
|
|
97
|
-
|
|
96
|
+
/> 1. Approve and run now/
|
|
98
97
|
],
|
|
99
98
|
fatal: [/Error: The cursor position could not be read within/],
|
|
100
99
|
ensureArgs: (args) => {
|
|
@@ -129,11 +128,6 @@ async function claudeYes({
|
|
|
129
128
|
removeControlCharactersFromStdout = false,
|
|
130
129
|
verbose = false
|
|
131
130
|
} = {}) {
|
|
132
|
-
await rm("agent-yes.log").catch(() => null);
|
|
133
|
-
const yesLog = tsaComposer()(async function yesLog(msg) {
|
|
134
|
-
await appendFile("agent-yes.log", `${msg}
|
|
135
|
-
`).catch(() => null);
|
|
136
|
-
});
|
|
137
131
|
const continueArgs = {
|
|
138
132
|
codex: "resume --last".split(" "),
|
|
139
133
|
claude: "--continue".split(" "),
|
|
@@ -142,6 +136,7 @@ async function claudeYes({
|
|
|
142
136
|
process.stdin.setRawMode?.(true);
|
|
143
137
|
let isFatal = false;
|
|
144
138
|
const stdinReady = new ReadyManager;
|
|
139
|
+
const nextStdout = new ReadyManager;
|
|
145
140
|
const shellOutputStream = new TransformStream;
|
|
146
141
|
const outputWriter = shellOutputStream.writable.getWriter();
|
|
147
142
|
const pty = await import("node-pty").catch(async () => await import("bun-pty")).catch(async () => DIE("Please install node-pty or bun-pty, run this: bun install bun-pty"));
|
|
@@ -163,10 +158,12 @@ async function claudeYes({
|
|
|
163
158
|
const pendingExitCode = Promise.withResolvers();
|
|
164
159
|
let pendingExitCodeValue = null;
|
|
165
160
|
async function onData(data) {
|
|
161
|
+
nextStdout.ready();
|
|
166
162
|
await outputWriter.write(data);
|
|
167
163
|
}
|
|
168
164
|
shell.onData(onData);
|
|
169
165
|
shell.onExit(function onExit({ exitCode: exitCode2 }) {
|
|
166
|
+
nextStdout.ready();
|
|
170
167
|
stdinReady.unready();
|
|
171
168
|
const agentCrashed = exitCode2 !== 0;
|
|
172
169
|
const continueArg = continueArgs[cli];
|
|
@@ -218,23 +215,24 @@ async function claudeYes({
|
|
|
218
215
|
const { col, row } = terminalRender.getCursorPosition();
|
|
219
216
|
console.log(`[${cli}-yes] Responding cursor position: row=${row}, col=${col}`);
|
|
220
217
|
shell.write(`\x1B[${row};${col}R`);
|
|
221
|
-
}).forkTo((e) => e.map((e2) => removeControlCharacters(e2)).map((e2) => e2.replaceAll("\r", "")).
|
|
218
|
+
}).forkTo((e) => e.map((e2) => removeControlCharacters(e2)).map((e2) => e2.replaceAll("\r", "")).by((s) => {
|
|
219
|
+
if (cli === "codex")
|
|
220
|
+
return s;
|
|
221
|
+
return s.lines({ EOL: "NONE" });
|
|
222
|
+
}).forEach(async (e2, i) => {
|
|
222
223
|
const conf = CLI_CONFIGURES[cli] || null;
|
|
223
224
|
if (!conf)
|
|
224
225
|
return;
|
|
225
226
|
if (conf.ready?.some((rx) => e2.match(rx))) {
|
|
226
|
-
await yesLog`ready |${e2}`;
|
|
227
227
|
if (cli === "gemini" && i <= 80)
|
|
228
228
|
return;
|
|
229
229
|
stdinReady.ready();
|
|
230
230
|
}
|
|
231
231
|
if (conf.enter?.some((rx) => e2.match(rx))) {
|
|
232
|
-
await yesLog`enter |${e2}`;
|
|
233
232
|
await sendEnter(300);
|
|
234
233
|
return;
|
|
235
234
|
}
|
|
236
235
|
if (conf.fatal?.some((rx) => e2.match(rx))) {
|
|
237
|
-
await yesLog`fatal |${e2}`;
|
|
238
236
|
isFatal = true;
|
|
239
237
|
await exitAgent();
|
|
240
238
|
}
|
|
@@ -256,14 +254,14 @@ async function claudeYes({
|
|
|
256
254
|
const st = Date.now();
|
|
257
255
|
await idleWaiter.wait(waitms);
|
|
258
256
|
const et = Date.now();
|
|
259
|
-
await yesLog`sendEn| idleWaiter.wait(${String(waitms)}) took ${String(et - st)}ms`;
|
|
260
257
|
shell.write("\r");
|
|
261
258
|
}
|
|
262
259
|
async function sendMessage(message) {
|
|
263
260
|
await stdinReady.wait();
|
|
264
|
-
await yesLog`send |${message}`;
|
|
265
261
|
shell.write(message);
|
|
262
|
+
nextStdout.unready();
|
|
266
263
|
idleWaiter.ping();
|
|
264
|
+
await nextStdout.wait();
|
|
267
265
|
await sendEnter();
|
|
268
266
|
}
|
|
269
267
|
async function exitAgent() {
|
|
@@ -350,5 +348,5 @@ var { exitCode, logs } = await claudeYes({
|
|
|
350
348
|
});
|
|
351
349
|
process.exit(exitCode ?? 1);
|
|
352
350
|
|
|
353
|
-
//# debugId=
|
|
351
|
+
//# debugId=C28320E15F2B1F0F64756E2164756E21
|
|
354
352
|
//# sourceMappingURL=cli.js.map
|
package/dist/cli.js
CHANGED
|
@@ -25,12 +25,11 @@ import { hideBin } from "yargs/helpers";
|
|
|
25
25
|
|
|
26
26
|
// dist/index.js
|
|
27
27
|
import { fromReadable, fromWritable } from "from-node-stream";
|
|
28
|
-
import {
|
|
28
|
+
import { mkdir, writeFile } from "fs/promises";
|
|
29
29
|
import path from "path";
|
|
30
30
|
import DIE from "phpdie";
|
|
31
31
|
import sflow from "sflow";
|
|
32
32
|
import { TerminalTextRender } from "terminal-render";
|
|
33
|
-
import tsaComposer from "tsa-composer";
|
|
34
33
|
class IdleWaiter {
|
|
35
34
|
lastActivityTime = Date.now();
|
|
36
35
|
checkInterval = 100;
|
|
@@ -94,7 +93,7 @@ var CLI_CONFIGURES = {
|
|
|
94
93
|
ready: [/⏎ send/],
|
|
95
94
|
enter: [
|
|
96
95
|
/> 1. Yes, allow Codex to work in this folder/,
|
|
97
|
-
|
|
96
|
+
/> 1. Approve and run now/
|
|
98
97
|
],
|
|
99
98
|
fatal: [/Error: The cursor position could not be read within/],
|
|
100
99
|
ensureArgs: (args) => {
|
|
@@ -129,11 +128,6 @@ async function claudeYes({
|
|
|
129
128
|
removeControlCharactersFromStdout = false,
|
|
130
129
|
verbose = false
|
|
131
130
|
} = {}) {
|
|
132
|
-
await rm("agent-yes.log").catch(() => null);
|
|
133
|
-
const yesLog = tsaComposer()(async function yesLog(msg) {
|
|
134
|
-
await appendFile("agent-yes.log", `${msg}
|
|
135
|
-
`).catch(() => null);
|
|
136
|
-
});
|
|
137
131
|
const continueArgs = {
|
|
138
132
|
codex: "resume --last".split(" "),
|
|
139
133
|
claude: "--continue".split(" "),
|
|
@@ -142,6 +136,7 @@ async function claudeYes({
|
|
|
142
136
|
process.stdin.setRawMode?.(true);
|
|
143
137
|
let isFatal = false;
|
|
144
138
|
const stdinReady = new ReadyManager;
|
|
139
|
+
const nextStdout = new ReadyManager;
|
|
145
140
|
const shellOutputStream = new TransformStream;
|
|
146
141
|
const outputWriter = shellOutputStream.writable.getWriter();
|
|
147
142
|
const pty = await import("node-pty").catch(async () => await import("bun-pty")).catch(async () => DIE("Please install node-pty or bun-pty, run this: bun install bun-pty"));
|
|
@@ -163,10 +158,12 @@ async function claudeYes({
|
|
|
163
158
|
const pendingExitCode = Promise.withResolvers();
|
|
164
159
|
let pendingExitCodeValue = null;
|
|
165
160
|
async function onData(data) {
|
|
161
|
+
nextStdout.ready();
|
|
166
162
|
await outputWriter.write(data);
|
|
167
163
|
}
|
|
168
164
|
shell.onData(onData);
|
|
169
165
|
shell.onExit(function onExit({ exitCode: exitCode2 }) {
|
|
166
|
+
nextStdout.ready();
|
|
170
167
|
stdinReady.unready();
|
|
171
168
|
const agentCrashed = exitCode2 !== 0;
|
|
172
169
|
const continueArg = continueArgs[cli];
|
|
@@ -218,23 +215,24 @@ async function claudeYes({
|
|
|
218
215
|
const { col, row } = terminalRender.getCursorPosition();
|
|
219
216
|
console.log(`[${cli}-yes] Responding cursor position: row=${row}, col=${col}`);
|
|
220
217
|
shell.write(`\x1B[${row};${col}R`);
|
|
221
|
-
}).forkTo((e) => e.map((e2) => removeControlCharacters(e2)).map((e2) => e2.replaceAll("\r", "")).
|
|
218
|
+
}).forkTo((e) => e.map((e2) => removeControlCharacters(e2)).map((e2) => e2.replaceAll("\r", "")).by((s) => {
|
|
219
|
+
if (cli === "codex")
|
|
220
|
+
return s;
|
|
221
|
+
return s.lines({ EOL: "NONE" });
|
|
222
|
+
}).forEach(async (e2, i) => {
|
|
222
223
|
const conf = CLI_CONFIGURES[cli] || null;
|
|
223
224
|
if (!conf)
|
|
224
225
|
return;
|
|
225
226
|
if (conf.ready?.some((rx) => e2.match(rx))) {
|
|
226
|
-
await yesLog`ready |${e2}`;
|
|
227
227
|
if (cli === "gemini" && i <= 80)
|
|
228
228
|
return;
|
|
229
229
|
stdinReady.ready();
|
|
230
230
|
}
|
|
231
231
|
if (conf.enter?.some((rx) => e2.match(rx))) {
|
|
232
|
-
await yesLog`enter |${e2}`;
|
|
233
232
|
await sendEnter(300);
|
|
234
233
|
return;
|
|
235
234
|
}
|
|
236
235
|
if (conf.fatal?.some((rx) => e2.match(rx))) {
|
|
237
|
-
await yesLog`fatal |${e2}`;
|
|
238
236
|
isFatal = true;
|
|
239
237
|
await exitAgent();
|
|
240
238
|
}
|
|
@@ -256,14 +254,14 @@ async function claudeYes({
|
|
|
256
254
|
const st = Date.now();
|
|
257
255
|
await idleWaiter.wait(waitms);
|
|
258
256
|
const et = Date.now();
|
|
259
|
-
await yesLog`sendEn| idleWaiter.wait(${String(waitms)}) took ${String(et - st)}ms`;
|
|
260
257
|
shell.write("\r");
|
|
261
258
|
}
|
|
262
259
|
async function sendMessage(message) {
|
|
263
260
|
await stdinReady.wait();
|
|
264
|
-
await yesLog`send |${message}`;
|
|
265
261
|
shell.write(message);
|
|
262
|
+
nextStdout.unready();
|
|
266
263
|
idleWaiter.ping();
|
|
264
|
+
await nextStdout.wait();
|
|
267
265
|
await sendEnter();
|
|
268
266
|
}
|
|
269
267
|
async function exitAgent() {
|
|
@@ -350,5 +348,5 @@ var { exitCode, logs } = await claudeYes({
|
|
|
350
348
|
});
|
|
351
349
|
process.exit(exitCode ?? 1);
|
|
352
350
|
|
|
353
|
-
//# debugId=
|
|
351
|
+
//# debugId=C28320E15F2B1F0F64756E2164756E21
|
|
354
352
|
//# sourceMappingURL=cli.js.map
|
package/dist/cli.js.map
CHANGED
|
@@ -3,9 +3,9 @@
|
|
|
3
3
|
"sources": ["../cli.ts", "index.js"],
|
|
4
4
|
"sourcesContent": [
|
|
5
5
|
"#!/usr/bin/env node\nimport enhancedMs from 'enhanced-ms';\nimport yargs from 'yargs';\nimport { hideBin } from 'yargs/helpers';\nimport claudeYes from '.';\n\n// cli entry point\nconst argv = yargs(hideBin(process.argv))\n .usage('Usage: $0 [options] [claude args] [--] [prompts...]')\n .example(\n '$0 --exit-on-idle=30s --continue-on-crash \"help me solve all todos in my codebase\"',\n 'Run Claude with a 30 seconds idle timeout and continue on crash',\n )\n .option('continue-on-crash', {\n type: 'boolean',\n default: true,\n description:\n 'spawn Claude with --continue if it crashes, only works for claude',\n })\n .option('log-file', {\n type: 'string',\n description: 'Log file to write to',\n })\n .option('cli', {\n type: 'string',\n description:\n 'Claude CLI command, e.g. \"claude,gemini,codex,cursor,copilot\", default is \"claude\"',\n })\n .option('prompt', {\n type: 'string',\n description: 'Prompt to send to Claude',\n alias: 'p',\n })\n .option('verbose', {\n type: 'boolean',\n description: 'Enable verbose logging',\n default: false,\n })\n .option('exit-on-idle', {\n type: 'string',\n description: 'Exit after a period of inactivity, e.g., \"5s\" or \"1m\"',\n })\n .parserConfiguration({\n 'unknown-options-as-args': true,\n 'halt-at-non-option': true,\n })\n .parseSync();\n\n// detect cli name for cli, while package.json have multiple bin link: {\"claude-yes\": \"cli.js\", \"codex-yes\": \"cli.js\", \"gemini-yes\": \"cli.js\"}\nif (!argv.cli) {\n const cliName = process.argv[1]?.split('/').pop()?.split('-')[0];\n argv.cli = cliName || 'claude';\n}\n\n// Support: everything after a literal `--` is a prompt string. Example:\n// claude-yes --exit-on-idle=30s -- \"help me refactor this\"\n// In that example the prompt will be `help me refactor this` and won't be\n// passed as args to the underlying CLI binary.\nconst rawArgs = process.argv.slice(2);\nconst dashIndex = rawArgs.indexOf('--');\nlet promptFromDash: string | undefined = undefined;\nlet cliArgsForSpawn: string[] = [];\nif (dashIndex !== -1) {\n // join everything after `--` into a single prompt string\n const after = rawArgs.slice(dashIndex + 1);\n promptFromDash = after.join(' ');\n // use everything before `--` as the cli args\n cliArgsForSpawn = rawArgs.slice(0, dashIndex).map(String);\n} else {\n // fallback to yargs parsed positional args when `--` is not used\n cliArgsForSpawn = argv._.map((e) => String(e));\n}\n\nconsole.clear();\nconst { exitCode, logs } = await claudeYes({\n cli: argv.cli,\n // prefer explicit --prompt / -p; otherwise use the text after `--` if present\n prompt: argv.prompt || promptFromDash,\n exitOnIdle: argv.exitOnIdle ? enhancedMs(argv.exitOnIdle) : undefined,\n cliArgs: cliArgsForSpawn,\n continueOnCrash: argv.continueOnCrash,\n logFile: argv.logFile,\n verbose: argv.verbose,\n});\n\nprocess.exit(exitCode ?? 1);\n",
|
|
6
|
-
"import { createRequire } from \"node:module\";\nvar __create = Object.create;\nvar __getProtoOf = Object.getPrototypeOf;\nvar __defProp = Object.defineProperty;\nvar __getOwnPropNames = Object.getOwnPropertyNames;\nvar __hasOwnProp = Object.prototype.hasOwnProperty;\nvar __toESM = (mod, isNodeMode, target) => {\n target = mod != null ? __create(__getProtoOf(mod)) : {};\n const to = isNodeMode || !mod || !mod.__esModule ? __defProp(target, \"default\", { value: mod, enumerable: true }) : target;\n for (let key of __getOwnPropNames(mod))\n if (!__hasOwnProp.call(to, key))\n __defProp(to, key, {\n get: () => mod[key],\n enumerable: true\n });\n return to;\n};\nvar __require = /* @__PURE__ */ createRequire(import.meta.url);\n\n// index.ts\nimport { fromReadable, fromWritable } from \"from-node-stream\";\nimport { appendFile, mkdir, rm, writeFile } from \"fs/promises\";\nimport path from \"path\";\nimport DIE from \"phpdie\";\nimport sflow from \"sflow\";\nimport { TerminalTextRender } from \"terminal-render\";\nimport tsaComposer from \"tsa-composer\";\n\n// idleWaiter.ts\nclass IdleWaiter {\n lastActivityTime = Date.now();\n checkInterval = 100;\n constructor() {\n this.ping();\n }\n ping() {\n this.lastActivityTime = Date.now();\n return this;\n }\n async wait(ms) {\n while (this.lastActivityTime >= Date.now() - ms)\n await new Promise((resolve) => setTimeout(resolve, this.checkInterval));\n }\n}\n\n// ReadyManager.ts\nclass ReadyManager {\n isReady = false;\n readyQueue = [];\n wait() {\n if (this.isReady)\n return;\n return new Promise((resolve) => this.readyQueue.push(resolve));\n }\n unready() {\n this.isReady = false;\n }\n ready() {\n this.isReady = true;\n if (!this.readyQueue.length)\n return;\n this.readyQueue.splice(0).map((resolve) => resolve());\n }\n}\n\n// removeControlCharacters.ts\nfunction removeControlCharacters(str) {\n return str.replace(/[\\u001b\\u009b][[()#;?]*(?:[0-9]{1,4}(?:;[0-9]{0,4})*)?[0-9A-ORZcf-nqry=><]/g, \"\");\n}\n\n// index.ts\nvar CLI_CONFIGURES = {\n grok: {\n install: \"npm install -g @vibe-kit/grok-cli\",\n ready: [/^ │ ❯ /],\n enter: [/^ 1. Yes/]\n },\n claude: {\n install: \"npm install -g @anthropic-ai/claude-code\",\n ready: [/\\? for shortcuts/],\n enter: [/❯ 1. Yes/, /❯ 1. Dark mode✔/, /Press Enter to continue…/],\n fatal: [\n /No conversation found to continue/,\n /⎿ Claude usage limit reached\\./\n ]\n },\n gemini: {\n install: \"npm install -g @google/gemini-cli\",\n ready: [/Type your message/],\n enter: [/│ ● 1. Yes, allow once/],\n fatal: []\n },\n codex: {\n install: \"npm install -g @openai/codex-cli\",\n ready: [/⏎ send/],\n enter: [\n /> 1. Yes, allow Codex to work in this folder/,\n /▌ > 1. Approve and run now/\n ],\n fatal: [/Error: The cursor position could not be read within/],\n ensureArgs: (args) => {\n if (!args.includes(\"--search\"))\n return [\"--search\", ...args];\n return args;\n }\n },\n copilot: {\n install: \"npm install -g @github/copilot\",\n ready: [/^ > /],\n enter: [/ │ ❯ 1. Yes, proceed/, /❯ 1. Yes/],\n fatal: []\n },\n cursor: {\n install: \"open https://cursor.com/ja/docs/cli/installation\",\n binary: \"cursor-agent\",\n ready: [/\\/ commands/],\n enter: [/→ Run \\(once\\) \\(y\\) \\(enter\\)/, /▶ \\[a\\] Trust this workspace/],\n fatal: [/^ Error: You've hit your usage limit/]\n }\n};\nasync function claudeYes({\n cli = \"claude\",\n cliArgs = [],\n prompt,\n continueOnCrash,\n cwd,\n env,\n exitOnIdle,\n logFile,\n removeControlCharactersFromStdout = false,\n verbose = false\n} = {}) {\n await rm(\"agent-yes.log\").catch(() => null);\n const yesLog = tsaComposer()(async function yesLog(msg) {\n await appendFile(\"agent-yes.log\", `${msg}\n`).catch(() => null);\n });\n const continueArgs = {\n codex: \"resume --last\".split(\" \"),\n claude: \"--continue\".split(\" \"),\n gemini: []\n };\n process.stdin.setRawMode?.(true);\n let isFatal = false;\n const stdinReady = new ReadyManager;\n const shellOutputStream = new TransformStream;\n const outputWriter = shellOutputStream.writable.getWriter();\n const pty = await import(\"node-pty\").catch(async () => await import(\"bun-pty\")).catch(async () => DIE(\"Please install node-pty or bun-pty, run this: bun install bun-pty\"));\n const getPtyOptions = () => ({\n name: \"xterm-color\",\n ...getTerminalDimensions(),\n cwd: cwd ?? process.cwd(),\n env: env ?? process.env\n });\n const cliConf = CLI_CONFIGURES[cli] || {};\n cliArgs = cliConf.ensureArgs?.(cliArgs) ?? cliArgs;\n const cliCommand = cliConf?.binary || cli;\n let shell = tryCatch(() => pty.spawn(cliCommand, cliArgs, getPtyOptions()), (error) => {\n console.error(`Fatal: Failed to start ${cliCommand}.`);\n if (cliConf?.install)\n console.error(`If you did not installed it yet, Please install it first: ${cliConf.install}`);\n throw error;\n });\n const pendingExitCode = Promise.withResolvers();\n let pendingExitCodeValue = null;\n async function onData(data) {\n await outputWriter.write(data);\n }\n shell.onData(onData);\n shell.onExit(function onExit({ exitCode: exitCode2 }) {\n stdinReady.unready();\n const agentCrashed = exitCode2 !== 0;\n const continueArg = continueArgs[cli];\n if (agentCrashed && continueOnCrash && continueArg) {\n if (!continueArg) {\n return console.warn(`continueOnCrash is only supported for ${Object.keys(continueArgs).join(\", \")} currently, not ${cli}`);\n }\n if (isFatal) {\n return pendingExitCode.resolve(pendingExitCodeValue = exitCode2);\n }\n console.log(`${cli} crashed, restarting...`);\n shell = pty.spawn(cli, continueArg, getPtyOptions());\n shell.onData(onData);\n shell.onExit(onExit);\n return;\n }\n return pendingExitCode.resolve(pendingExitCodeValue = exitCode2);\n });\n process.stdout.on(\"resize\", () => {\n const { cols, rows } = getTerminalDimensions();\n shell.resize(cols, rows);\n });\n const terminalRender = new TerminalTextRender;\n const isStillWorkingQ = () => terminalRender.render().replace(/\\s+/g, \" \").match(/esc to interrupt|to run in background/);\n const idleWaiter = new IdleWaiter;\n if (exitOnIdle)\n idleWaiter.wait(exitOnIdle).then(async () => {\n if (isStillWorkingQ()) {\n console.log(\"[${cli}-yes] ${cli} is idle, but seems still working, not exiting yet\");\n return;\n }\n console.log(\"[${cli}-yes] ${cli} is idle, exiting...\");\n await exitAgent();\n });\n sflow(fromReadable(process.stdin)).map((buffer) => buffer.toString()).by({\n writable: new WritableStream({\n write: async (data) => {\n await stdinReady.wait();\n shell.write(data);\n }\n }),\n readable: shellOutputStream.readable\n }).forEach(() => idleWaiter.ping()).forEach((text) => {\n terminalRender.write(text);\n if (process.stdin.isTTY)\n return;\n if (!text.includes(\"\\x1B[6n\"))\n return;\n const { col, row } = terminalRender.getCursorPosition();\n console.log(`[${cli}-yes] Responding cursor position: row=${row}, col=${col}`);\n shell.write(`\\x1B[${row};${col}R`);\n }).forkTo((e) => e.map((e2) => removeControlCharacters(e2)).map((e2) => e2.replaceAll(\"\\r\", \"\")).lines({ EOL: \"NONE\" }).forEach((e2) => yesLog`output|${e2}`).forEach(async (e2, i) => {\n const conf = CLI_CONFIGURES[cli] || null;\n if (!conf)\n return;\n if (conf.ready?.some((rx) => e2.match(rx))) {\n await yesLog`ready |${e2}`;\n if (cli === \"gemini\" && i <= 80)\n return;\n stdinReady.ready();\n }\n if (conf.enter?.some((rx) => e2.match(rx))) {\n await yesLog`enter |${e2}`;\n await sendEnter(300);\n return;\n }\n if (conf.fatal?.some((rx) => e2.match(rx))) {\n await yesLog`fatal |${e2}`;\n isFatal = true;\n await exitAgent();\n }\n }).run()).map((e) => removeControlCharactersFromStdout ? removeControlCharacters(e) : e).to(fromWritable(process.stdout)).then(() => null);\n if (cli === \"codex\")\n shell.write(`\\x1B[1;1R`);\n if (prompt)\n await sendMessage(prompt);\n const exitCode = await pendingExitCode.promise;\n console.log(`[${cli}-yes] ${cli} exited with code ${exitCode}`);\n if (logFile) {\n verbose && console.log(`[${cli}-yes] Writing rendered logs to ${logFile}`);\n const logFilePath = path.resolve(logFile);\n await mkdir(path.dirname(logFilePath), { recursive: true }).catch(() => null);\n await writeFile(logFilePath, terminalRender.render());\n }\n return { exitCode, logs: terminalRender.render() };\n async function sendEnter(waitms = 1000) {\n const st = Date.now();\n await idleWaiter.wait(waitms);\n const et = Date.now();\n await yesLog`sendEn| idleWaiter.wait(${String(waitms)}) took ${String(et - st)}ms`;\n shell.write(\"\\r\");\n }\n async function sendMessage(message) {\n await stdinReady.wait();\n await yesLog`send |${message}`;\n shell.write(message);\n idleWaiter.ping();\n await sendEnter();\n }\n async function exitAgent() {\n continueOnCrash = false;\n await sendMessage(\"/exit\");\n let exited = false;\n await Promise.race([\n pendingExitCode.promise.then(() => exited = true),\n new Promise((resolve) => setTimeout(() => {\n if (exited)\n return;\n shell.kill();\n resolve();\n }, 5000))\n ]);\n }\n function getTerminalDimensions() {\n if (!process.stdout.isTTY)\n return { cols: 80, rows: 30 };\n return {\n cols: Math.min(Math.max(20, process.stdout.columns), 80),\n rows: process.stdout.rows\n };\n }\n}\nfunction tryCatch(fn, catchFn) {\n try {\n return fn();\n } catch (error) {\n return catchFn(error);\n }\n}\nexport {\n removeControlCharacters,\n claudeYes as default,\n CLI_CONFIGURES\n};\n\n//# debugId=D97240F2071C1DE564756E2164756E21\n//# sourceMappingURL=index.js.map\n"
|
|
6
|
+
"import { createRequire } from \"node:module\";\nvar __create = Object.create;\nvar __getProtoOf = Object.getPrototypeOf;\nvar __defProp = Object.defineProperty;\nvar __getOwnPropNames = Object.getOwnPropertyNames;\nvar __hasOwnProp = Object.prototype.hasOwnProperty;\nvar __toESM = (mod, isNodeMode, target) => {\n target = mod != null ? __create(__getProtoOf(mod)) : {};\n const to = isNodeMode || !mod || !mod.__esModule ? __defProp(target, \"default\", { value: mod, enumerable: true }) : target;\n for (let key of __getOwnPropNames(mod))\n if (!__hasOwnProp.call(to, key))\n __defProp(to, key, {\n get: () => mod[key],\n enumerable: true\n });\n return to;\n};\nvar __require = /* @__PURE__ */ createRequire(import.meta.url);\n\n// index.ts\nimport { fromReadable, fromWritable } from \"from-node-stream\";\nimport { mkdir, writeFile } from \"fs/promises\";\nimport path from \"path\";\nimport DIE from \"phpdie\";\nimport sflow from \"sflow\";\nimport { TerminalTextRender } from \"terminal-render\";\n\n// idleWaiter.ts\nclass IdleWaiter {\n lastActivityTime = Date.now();\n checkInterval = 100;\n constructor() {\n this.ping();\n }\n ping() {\n this.lastActivityTime = Date.now();\n return this;\n }\n async wait(ms) {\n while (this.lastActivityTime >= Date.now() - ms)\n await new Promise((resolve) => setTimeout(resolve, this.checkInterval));\n }\n}\n\n// ReadyManager.ts\nclass ReadyManager {\n isReady = false;\n readyQueue = [];\n wait() {\n if (this.isReady)\n return;\n return new Promise((resolve) => this.readyQueue.push(resolve));\n }\n unready() {\n this.isReady = false;\n }\n ready() {\n this.isReady = true;\n if (!this.readyQueue.length)\n return;\n this.readyQueue.splice(0).map((resolve) => resolve());\n }\n}\n\n// removeControlCharacters.ts\nfunction removeControlCharacters(str) {\n return str.replace(/[\\u001b\\u009b][[()#;?]*(?:[0-9]{1,4}(?:;[0-9]{0,4})*)?[0-9A-ORZcf-nqry=><]/g, \"\");\n}\n\n// index.ts\nvar CLI_CONFIGURES = {\n grok: {\n install: \"npm install -g @vibe-kit/grok-cli\",\n ready: [/^ │ ❯ /],\n enter: [/^ 1. Yes/]\n },\n claude: {\n install: \"npm install -g @anthropic-ai/claude-code\",\n ready: [/\\? for shortcuts/],\n enter: [/❯ 1. Yes/, /❯ 1. Dark mode✔/, /Press Enter to continue…/],\n fatal: [\n /No conversation found to continue/,\n /⎿ Claude usage limit reached\\./\n ]\n },\n gemini: {\n install: \"npm install -g @google/gemini-cli\",\n ready: [/Type your message/],\n enter: [/│ ● 1. Yes, allow once/],\n fatal: []\n },\n codex: {\n install: \"npm install -g @openai/codex-cli\",\n ready: [/⏎ send/],\n enter: [\n /> 1. Yes, allow Codex to work in this folder/,\n /> 1. Approve and run now/\n ],\n fatal: [/Error: The cursor position could not be read within/],\n ensureArgs: (args) => {\n if (!args.includes(\"--search\"))\n return [\"--search\", ...args];\n return args;\n }\n },\n copilot: {\n install: \"npm install -g @github/copilot\",\n ready: [/^ > /],\n enter: [/ │ ❯ 1. Yes, proceed/, /❯ 1. Yes/],\n fatal: []\n },\n cursor: {\n install: \"open https://cursor.com/ja/docs/cli/installation\",\n binary: \"cursor-agent\",\n ready: [/\\/ commands/],\n enter: [/→ Run \\(once\\) \\(y\\) \\(enter\\)/, /▶ \\[a\\] Trust this workspace/],\n fatal: [/^ Error: You've hit your usage limit/]\n }\n};\nasync function claudeYes({\n cli = \"claude\",\n cliArgs = [],\n prompt,\n continueOnCrash,\n cwd,\n env,\n exitOnIdle,\n logFile,\n removeControlCharactersFromStdout = false,\n verbose = false\n} = {}) {\n const continueArgs = {\n codex: \"resume --last\".split(\" \"),\n claude: \"--continue\".split(\" \"),\n gemini: []\n };\n process.stdin.setRawMode?.(true);\n let isFatal = false;\n const stdinReady = new ReadyManager;\n const nextStdout = new ReadyManager;\n const shellOutputStream = new TransformStream;\n const outputWriter = shellOutputStream.writable.getWriter();\n const pty = await import(\"node-pty\").catch(async () => await import(\"bun-pty\")).catch(async () => DIE(\"Please install node-pty or bun-pty, run this: bun install bun-pty\"));\n const getPtyOptions = () => ({\n name: \"xterm-color\",\n ...getTerminalDimensions(),\n cwd: cwd ?? process.cwd(),\n env: env ?? process.env\n });\n const cliConf = CLI_CONFIGURES[cli] || {};\n cliArgs = cliConf.ensureArgs?.(cliArgs) ?? cliArgs;\n const cliCommand = cliConf?.binary || cli;\n let shell = tryCatch(() => pty.spawn(cliCommand, cliArgs, getPtyOptions()), (error) => {\n console.error(`Fatal: Failed to start ${cliCommand}.`);\n if (cliConf?.install)\n console.error(`If you did not installed it yet, Please install it first: ${cliConf.install}`);\n throw error;\n });\n const pendingExitCode = Promise.withResolvers();\n let pendingExitCodeValue = null;\n async function onData(data) {\n nextStdout.ready();\n await outputWriter.write(data);\n }\n shell.onData(onData);\n shell.onExit(function onExit({ exitCode: exitCode2 }) {\n nextStdout.ready();\n stdinReady.unready();\n const agentCrashed = exitCode2 !== 0;\n const continueArg = continueArgs[cli];\n if (agentCrashed && continueOnCrash && continueArg) {\n if (!continueArg) {\n return console.warn(`continueOnCrash is only supported for ${Object.keys(continueArgs).join(\", \")} currently, not ${cli}`);\n }\n if (isFatal) {\n return pendingExitCode.resolve(pendingExitCodeValue = exitCode2);\n }\n console.log(`${cli} crashed, restarting...`);\n shell = pty.spawn(cli, continueArg, getPtyOptions());\n shell.onData(onData);\n shell.onExit(onExit);\n return;\n }\n return pendingExitCode.resolve(pendingExitCodeValue = exitCode2);\n });\n process.stdout.on(\"resize\", () => {\n const { cols, rows } = getTerminalDimensions();\n shell.resize(cols, rows);\n });\n const terminalRender = new TerminalTextRender;\n const isStillWorkingQ = () => terminalRender.render().replace(/\\s+/g, \" \").match(/esc to interrupt|to run in background/);\n const idleWaiter = new IdleWaiter;\n if (exitOnIdle)\n idleWaiter.wait(exitOnIdle).then(async () => {\n if (isStillWorkingQ()) {\n console.log(\"[${cli}-yes] ${cli} is idle, but seems still working, not exiting yet\");\n return;\n }\n console.log(\"[${cli}-yes] ${cli} is idle, exiting...\");\n await exitAgent();\n });\n sflow(fromReadable(process.stdin)).map((buffer) => buffer.toString()).by({\n writable: new WritableStream({\n write: async (data) => {\n await stdinReady.wait();\n shell.write(data);\n }\n }),\n readable: shellOutputStream.readable\n }).forEach(() => idleWaiter.ping()).forEach((text) => {\n terminalRender.write(text);\n if (process.stdin.isTTY)\n return;\n if (!text.includes(\"\\x1B[6n\"))\n return;\n const { col, row } = terminalRender.getCursorPosition();\n console.log(`[${cli}-yes] Responding cursor position: row=${row}, col=${col}`);\n shell.write(`\\x1B[${row};${col}R`);\n }).forkTo((e) => e.map((e2) => removeControlCharacters(e2)).map((e2) => e2.replaceAll(\"\\r\", \"\")).by((s) => {\n if (cli === \"codex\")\n return s;\n return s.lines({ EOL: \"NONE\" });\n }).forEach(async (e2, i) => {\n const conf = CLI_CONFIGURES[cli] || null;\n if (!conf)\n return;\n if (conf.ready?.some((rx) => e2.match(rx))) {\n if (cli === \"gemini\" && i <= 80)\n return;\n stdinReady.ready();\n }\n if (conf.enter?.some((rx) => e2.match(rx))) {\n await sendEnter(300);\n return;\n }\n if (conf.fatal?.some((rx) => e2.match(rx))) {\n isFatal = true;\n await exitAgent();\n }\n }).run()).map((e) => removeControlCharactersFromStdout ? removeControlCharacters(e) : e).to(fromWritable(process.stdout)).then(() => null);\n if (cli === \"codex\")\n shell.write(`\\x1B[1;1R`);\n if (prompt)\n await sendMessage(prompt);\n const exitCode = await pendingExitCode.promise;\n console.log(`[${cli}-yes] ${cli} exited with code ${exitCode}`);\n if (logFile) {\n verbose && console.log(`[${cli}-yes] Writing rendered logs to ${logFile}`);\n const logFilePath = path.resolve(logFile);\n await mkdir(path.dirname(logFilePath), { recursive: true }).catch(() => null);\n await writeFile(logFilePath, terminalRender.render());\n }\n return { exitCode, logs: terminalRender.render() };\n async function sendEnter(waitms = 1000) {\n const st = Date.now();\n await idleWaiter.wait(waitms);\n const et = Date.now();\n shell.write(\"\\r\");\n }\n async function sendMessage(message) {\n await stdinReady.wait();\n shell.write(message);\n nextStdout.unready();\n idleWaiter.ping();\n await nextStdout.wait();\n await sendEnter();\n }\n async function exitAgent() {\n continueOnCrash = false;\n await sendMessage(\"/exit\");\n let exited = false;\n await Promise.race([\n pendingExitCode.promise.then(() => exited = true),\n new Promise((resolve) => setTimeout(() => {\n if (exited)\n return;\n shell.kill();\n resolve();\n }, 5000))\n ]);\n }\n function getTerminalDimensions() {\n if (!process.stdout.isTTY)\n return { cols: 80, rows: 30 };\n return {\n cols: Math.min(Math.max(20, process.stdout.columns), 80),\n rows: process.stdout.rows\n };\n }\n}\nfunction tryCatch(fn, catchFn) {\n try {\n return fn();\n } catch (error) {\n return catchFn(error);\n }\n}\nexport {\n removeControlCharacters,\n claudeYes as default,\n CLI_CONFIGURES\n};\n\n//# debugId=D17BB3E3D1DC936764756E2164756E21\n//# sourceMappingURL=index.js.map\n"
|
|
7
7
|
],
|
|
8
|
-
"mappings": ";;;;;;;;;;;;;;;;;;;;;AACA;AACA;AACA;;;ACiBA;AACA;AACA;AACA;AACA;AACA;
|
|
9
|
-
"debugId": "
|
|
8
|
+
"mappings": "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",
|
|
9
|
+
"debugId": "C28320E15F2B1F0F64756E2164756E21",
|
|
10
10
|
"names": []
|
|
11
11
|
}
|
package/dist/codex-yes.js
CHANGED
|
@@ -25,12 +25,11 @@ import { hideBin } from "yargs/helpers";
|
|
|
25
25
|
|
|
26
26
|
// dist/index.js
|
|
27
27
|
import { fromReadable, fromWritable } from "from-node-stream";
|
|
28
|
-
import {
|
|
28
|
+
import { mkdir, writeFile } from "fs/promises";
|
|
29
29
|
import path from "path";
|
|
30
30
|
import DIE from "phpdie";
|
|
31
31
|
import sflow from "sflow";
|
|
32
32
|
import { TerminalTextRender } from "terminal-render";
|
|
33
|
-
import tsaComposer from "tsa-composer";
|
|
34
33
|
class IdleWaiter {
|
|
35
34
|
lastActivityTime = Date.now();
|
|
36
35
|
checkInterval = 100;
|
|
@@ -94,7 +93,7 @@ var CLI_CONFIGURES = {
|
|
|
94
93
|
ready: [/⏎ send/],
|
|
95
94
|
enter: [
|
|
96
95
|
/> 1. Yes, allow Codex to work in this folder/,
|
|
97
|
-
|
|
96
|
+
/> 1. Approve and run now/
|
|
98
97
|
],
|
|
99
98
|
fatal: [/Error: The cursor position could not be read within/],
|
|
100
99
|
ensureArgs: (args) => {
|
|
@@ -129,11 +128,6 @@ async function claudeYes({
|
|
|
129
128
|
removeControlCharactersFromStdout = false,
|
|
130
129
|
verbose = false
|
|
131
130
|
} = {}) {
|
|
132
|
-
await rm("agent-yes.log").catch(() => null);
|
|
133
|
-
const yesLog = tsaComposer()(async function yesLog(msg) {
|
|
134
|
-
await appendFile("agent-yes.log", `${msg}
|
|
135
|
-
`).catch(() => null);
|
|
136
|
-
});
|
|
137
131
|
const continueArgs = {
|
|
138
132
|
codex: "resume --last".split(" "),
|
|
139
133
|
claude: "--continue".split(" "),
|
|
@@ -142,6 +136,7 @@ async function claudeYes({
|
|
|
142
136
|
process.stdin.setRawMode?.(true);
|
|
143
137
|
let isFatal = false;
|
|
144
138
|
const stdinReady = new ReadyManager;
|
|
139
|
+
const nextStdout = new ReadyManager;
|
|
145
140
|
const shellOutputStream = new TransformStream;
|
|
146
141
|
const outputWriter = shellOutputStream.writable.getWriter();
|
|
147
142
|
const pty = await import("node-pty").catch(async () => await import("bun-pty")).catch(async () => DIE("Please install node-pty or bun-pty, run this: bun install bun-pty"));
|
|
@@ -163,10 +158,12 @@ async function claudeYes({
|
|
|
163
158
|
const pendingExitCode = Promise.withResolvers();
|
|
164
159
|
let pendingExitCodeValue = null;
|
|
165
160
|
async function onData(data) {
|
|
161
|
+
nextStdout.ready();
|
|
166
162
|
await outputWriter.write(data);
|
|
167
163
|
}
|
|
168
164
|
shell.onData(onData);
|
|
169
165
|
shell.onExit(function onExit({ exitCode: exitCode2 }) {
|
|
166
|
+
nextStdout.ready();
|
|
170
167
|
stdinReady.unready();
|
|
171
168
|
const agentCrashed = exitCode2 !== 0;
|
|
172
169
|
const continueArg = continueArgs[cli];
|
|
@@ -218,23 +215,24 @@ async function claudeYes({
|
|
|
218
215
|
const { col, row } = terminalRender.getCursorPosition();
|
|
219
216
|
console.log(`[${cli}-yes] Responding cursor position: row=${row}, col=${col}`);
|
|
220
217
|
shell.write(`\x1B[${row};${col}R`);
|
|
221
|
-
}).forkTo((e) => e.map((e2) => removeControlCharacters(e2)).map((e2) => e2.replaceAll("\r", "")).
|
|
218
|
+
}).forkTo((e) => e.map((e2) => removeControlCharacters(e2)).map((e2) => e2.replaceAll("\r", "")).by((s) => {
|
|
219
|
+
if (cli === "codex")
|
|
220
|
+
return s;
|
|
221
|
+
return s.lines({ EOL: "NONE" });
|
|
222
|
+
}).forEach(async (e2, i) => {
|
|
222
223
|
const conf = CLI_CONFIGURES[cli] || null;
|
|
223
224
|
if (!conf)
|
|
224
225
|
return;
|
|
225
226
|
if (conf.ready?.some((rx) => e2.match(rx))) {
|
|
226
|
-
await yesLog`ready |${e2}`;
|
|
227
227
|
if (cli === "gemini" && i <= 80)
|
|
228
228
|
return;
|
|
229
229
|
stdinReady.ready();
|
|
230
230
|
}
|
|
231
231
|
if (conf.enter?.some((rx) => e2.match(rx))) {
|
|
232
|
-
await yesLog`enter |${e2}`;
|
|
233
232
|
await sendEnter(300);
|
|
234
233
|
return;
|
|
235
234
|
}
|
|
236
235
|
if (conf.fatal?.some((rx) => e2.match(rx))) {
|
|
237
|
-
await yesLog`fatal |${e2}`;
|
|
238
236
|
isFatal = true;
|
|
239
237
|
await exitAgent();
|
|
240
238
|
}
|
|
@@ -256,14 +254,14 @@ async function claudeYes({
|
|
|
256
254
|
const st = Date.now();
|
|
257
255
|
await idleWaiter.wait(waitms);
|
|
258
256
|
const et = Date.now();
|
|
259
|
-
await yesLog`sendEn| idleWaiter.wait(${String(waitms)}) took ${String(et - st)}ms`;
|
|
260
257
|
shell.write("\r");
|
|
261
258
|
}
|
|
262
259
|
async function sendMessage(message) {
|
|
263
260
|
await stdinReady.wait();
|
|
264
|
-
await yesLog`send |${message}`;
|
|
265
261
|
shell.write(message);
|
|
262
|
+
nextStdout.unready();
|
|
266
263
|
idleWaiter.ping();
|
|
264
|
+
await nextStdout.wait();
|
|
267
265
|
await sendEnter();
|
|
268
266
|
}
|
|
269
267
|
async function exitAgent() {
|
|
@@ -350,5 +348,5 @@ var { exitCode, logs } = await claudeYes({
|
|
|
350
348
|
});
|
|
351
349
|
process.exit(exitCode ?? 1);
|
|
352
350
|
|
|
353
|
-
//# debugId=
|
|
351
|
+
//# debugId=C28320E15F2B1F0F64756E2164756E21
|
|
354
352
|
//# sourceMappingURL=cli.js.map
|
package/dist/copilot-yes.js
CHANGED
|
@@ -25,12 +25,11 @@ import { hideBin } from "yargs/helpers";
|
|
|
25
25
|
|
|
26
26
|
// dist/index.js
|
|
27
27
|
import { fromReadable, fromWritable } from "from-node-stream";
|
|
28
|
-
import {
|
|
28
|
+
import { mkdir, writeFile } from "fs/promises";
|
|
29
29
|
import path from "path";
|
|
30
30
|
import DIE from "phpdie";
|
|
31
31
|
import sflow from "sflow";
|
|
32
32
|
import { TerminalTextRender } from "terminal-render";
|
|
33
|
-
import tsaComposer from "tsa-composer";
|
|
34
33
|
class IdleWaiter {
|
|
35
34
|
lastActivityTime = Date.now();
|
|
36
35
|
checkInterval = 100;
|
|
@@ -94,7 +93,7 @@ var CLI_CONFIGURES = {
|
|
|
94
93
|
ready: [/⏎ send/],
|
|
95
94
|
enter: [
|
|
96
95
|
/> 1. Yes, allow Codex to work in this folder/,
|
|
97
|
-
|
|
96
|
+
/> 1. Approve and run now/
|
|
98
97
|
],
|
|
99
98
|
fatal: [/Error: The cursor position could not be read within/],
|
|
100
99
|
ensureArgs: (args) => {
|
|
@@ -129,11 +128,6 @@ async function claudeYes({
|
|
|
129
128
|
removeControlCharactersFromStdout = false,
|
|
130
129
|
verbose = false
|
|
131
130
|
} = {}) {
|
|
132
|
-
await rm("agent-yes.log").catch(() => null);
|
|
133
|
-
const yesLog = tsaComposer()(async function yesLog(msg) {
|
|
134
|
-
await appendFile("agent-yes.log", `${msg}
|
|
135
|
-
`).catch(() => null);
|
|
136
|
-
});
|
|
137
131
|
const continueArgs = {
|
|
138
132
|
codex: "resume --last".split(" "),
|
|
139
133
|
claude: "--continue".split(" "),
|
|
@@ -142,6 +136,7 @@ async function claudeYes({
|
|
|
142
136
|
process.stdin.setRawMode?.(true);
|
|
143
137
|
let isFatal = false;
|
|
144
138
|
const stdinReady = new ReadyManager;
|
|
139
|
+
const nextStdout = new ReadyManager;
|
|
145
140
|
const shellOutputStream = new TransformStream;
|
|
146
141
|
const outputWriter = shellOutputStream.writable.getWriter();
|
|
147
142
|
const pty = await import("node-pty").catch(async () => await import("bun-pty")).catch(async () => DIE("Please install node-pty or bun-pty, run this: bun install bun-pty"));
|
|
@@ -163,10 +158,12 @@ async function claudeYes({
|
|
|
163
158
|
const pendingExitCode = Promise.withResolvers();
|
|
164
159
|
let pendingExitCodeValue = null;
|
|
165
160
|
async function onData(data) {
|
|
161
|
+
nextStdout.ready();
|
|
166
162
|
await outputWriter.write(data);
|
|
167
163
|
}
|
|
168
164
|
shell.onData(onData);
|
|
169
165
|
shell.onExit(function onExit({ exitCode: exitCode2 }) {
|
|
166
|
+
nextStdout.ready();
|
|
170
167
|
stdinReady.unready();
|
|
171
168
|
const agentCrashed = exitCode2 !== 0;
|
|
172
169
|
const continueArg = continueArgs[cli];
|
|
@@ -218,23 +215,24 @@ async function claudeYes({
|
|
|
218
215
|
const { col, row } = terminalRender.getCursorPosition();
|
|
219
216
|
console.log(`[${cli}-yes] Responding cursor position: row=${row}, col=${col}`);
|
|
220
217
|
shell.write(`\x1B[${row};${col}R`);
|
|
221
|
-
}).forkTo((e) => e.map((e2) => removeControlCharacters(e2)).map((e2) => e2.replaceAll("\r", "")).
|
|
218
|
+
}).forkTo((e) => e.map((e2) => removeControlCharacters(e2)).map((e2) => e2.replaceAll("\r", "")).by((s) => {
|
|
219
|
+
if (cli === "codex")
|
|
220
|
+
return s;
|
|
221
|
+
return s.lines({ EOL: "NONE" });
|
|
222
|
+
}).forEach(async (e2, i) => {
|
|
222
223
|
const conf = CLI_CONFIGURES[cli] || null;
|
|
223
224
|
if (!conf)
|
|
224
225
|
return;
|
|
225
226
|
if (conf.ready?.some((rx) => e2.match(rx))) {
|
|
226
|
-
await yesLog`ready |${e2}`;
|
|
227
227
|
if (cli === "gemini" && i <= 80)
|
|
228
228
|
return;
|
|
229
229
|
stdinReady.ready();
|
|
230
230
|
}
|
|
231
231
|
if (conf.enter?.some((rx) => e2.match(rx))) {
|
|
232
|
-
await yesLog`enter |${e2}`;
|
|
233
232
|
await sendEnter(300);
|
|
234
233
|
return;
|
|
235
234
|
}
|
|
236
235
|
if (conf.fatal?.some((rx) => e2.match(rx))) {
|
|
237
|
-
await yesLog`fatal |${e2}`;
|
|
238
236
|
isFatal = true;
|
|
239
237
|
await exitAgent();
|
|
240
238
|
}
|
|
@@ -256,14 +254,14 @@ async function claudeYes({
|
|
|
256
254
|
const st = Date.now();
|
|
257
255
|
await idleWaiter.wait(waitms);
|
|
258
256
|
const et = Date.now();
|
|
259
|
-
await yesLog`sendEn| idleWaiter.wait(${String(waitms)}) took ${String(et - st)}ms`;
|
|
260
257
|
shell.write("\r");
|
|
261
258
|
}
|
|
262
259
|
async function sendMessage(message) {
|
|
263
260
|
await stdinReady.wait();
|
|
264
|
-
await yesLog`send |${message}`;
|
|
265
261
|
shell.write(message);
|
|
262
|
+
nextStdout.unready();
|
|
266
263
|
idleWaiter.ping();
|
|
264
|
+
await nextStdout.wait();
|
|
267
265
|
await sendEnter();
|
|
268
266
|
}
|
|
269
267
|
async function exitAgent() {
|
|
@@ -350,5 +348,5 @@ var { exitCode, logs } = await claudeYes({
|
|
|
350
348
|
});
|
|
351
349
|
process.exit(exitCode ?? 1);
|
|
352
350
|
|
|
353
|
-
//# debugId=
|
|
351
|
+
//# debugId=C28320E15F2B1F0F64756E2164756E21
|
|
354
352
|
//# sourceMappingURL=cli.js.map
|
package/dist/cursor-yes.js
CHANGED
|
@@ -25,12 +25,11 @@ import { hideBin } from "yargs/helpers";
|
|
|
25
25
|
|
|
26
26
|
// dist/index.js
|
|
27
27
|
import { fromReadable, fromWritable } from "from-node-stream";
|
|
28
|
-
import {
|
|
28
|
+
import { mkdir, writeFile } from "fs/promises";
|
|
29
29
|
import path from "path";
|
|
30
30
|
import DIE from "phpdie";
|
|
31
31
|
import sflow from "sflow";
|
|
32
32
|
import { TerminalTextRender } from "terminal-render";
|
|
33
|
-
import tsaComposer from "tsa-composer";
|
|
34
33
|
class IdleWaiter {
|
|
35
34
|
lastActivityTime = Date.now();
|
|
36
35
|
checkInterval = 100;
|
|
@@ -94,7 +93,7 @@ var CLI_CONFIGURES = {
|
|
|
94
93
|
ready: [/⏎ send/],
|
|
95
94
|
enter: [
|
|
96
95
|
/> 1. Yes, allow Codex to work in this folder/,
|
|
97
|
-
|
|
96
|
+
/> 1. Approve and run now/
|
|
98
97
|
],
|
|
99
98
|
fatal: [/Error: The cursor position could not be read within/],
|
|
100
99
|
ensureArgs: (args) => {
|
|
@@ -129,11 +128,6 @@ async function claudeYes({
|
|
|
129
128
|
removeControlCharactersFromStdout = false,
|
|
130
129
|
verbose = false
|
|
131
130
|
} = {}) {
|
|
132
|
-
await rm("agent-yes.log").catch(() => null);
|
|
133
|
-
const yesLog = tsaComposer()(async function yesLog(msg) {
|
|
134
|
-
await appendFile("agent-yes.log", `${msg}
|
|
135
|
-
`).catch(() => null);
|
|
136
|
-
});
|
|
137
131
|
const continueArgs = {
|
|
138
132
|
codex: "resume --last".split(" "),
|
|
139
133
|
claude: "--continue".split(" "),
|
|
@@ -142,6 +136,7 @@ async function claudeYes({
|
|
|
142
136
|
process.stdin.setRawMode?.(true);
|
|
143
137
|
let isFatal = false;
|
|
144
138
|
const stdinReady = new ReadyManager;
|
|
139
|
+
const nextStdout = new ReadyManager;
|
|
145
140
|
const shellOutputStream = new TransformStream;
|
|
146
141
|
const outputWriter = shellOutputStream.writable.getWriter();
|
|
147
142
|
const pty = await import("node-pty").catch(async () => await import("bun-pty")).catch(async () => DIE("Please install node-pty or bun-pty, run this: bun install bun-pty"));
|
|
@@ -163,10 +158,12 @@ async function claudeYes({
|
|
|
163
158
|
const pendingExitCode = Promise.withResolvers();
|
|
164
159
|
let pendingExitCodeValue = null;
|
|
165
160
|
async function onData(data) {
|
|
161
|
+
nextStdout.ready();
|
|
166
162
|
await outputWriter.write(data);
|
|
167
163
|
}
|
|
168
164
|
shell.onData(onData);
|
|
169
165
|
shell.onExit(function onExit({ exitCode: exitCode2 }) {
|
|
166
|
+
nextStdout.ready();
|
|
170
167
|
stdinReady.unready();
|
|
171
168
|
const agentCrashed = exitCode2 !== 0;
|
|
172
169
|
const continueArg = continueArgs[cli];
|
|
@@ -218,23 +215,24 @@ async function claudeYes({
|
|
|
218
215
|
const { col, row } = terminalRender.getCursorPosition();
|
|
219
216
|
console.log(`[${cli}-yes] Responding cursor position: row=${row}, col=${col}`);
|
|
220
217
|
shell.write(`\x1B[${row};${col}R`);
|
|
221
|
-
}).forkTo((e) => e.map((e2) => removeControlCharacters(e2)).map((e2) => e2.replaceAll("\r", "")).
|
|
218
|
+
}).forkTo((e) => e.map((e2) => removeControlCharacters(e2)).map((e2) => e2.replaceAll("\r", "")).by((s) => {
|
|
219
|
+
if (cli === "codex")
|
|
220
|
+
return s;
|
|
221
|
+
return s.lines({ EOL: "NONE" });
|
|
222
|
+
}).forEach(async (e2, i) => {
|
|
222
223
|
const conf = CLI_CONFIGURES[cli] || null;
|
|
223
224
|
if (!conf)
|
|
224
225
|
return;
|
|
225
226
|
if (conf.ready?.some((rx) => e2.match(rx))) {
|
|
226
|
-
await yesLog`ready |${e2}`;
|
|
227
227
|
if (cli === "gemini" && i <= 80)
|
|
228
228
|
return;
|
|
229
229
|
stdinReady.ready();
|
|
230
230
|
}
|
|
231
231
|
if (conf.enter?.some((rx) => e2.match(rx))) {
|
|
232
|
-
await yesLog`enter |${e2}`;
|
|
233
232
|
await sendEnter(300);
|
|
234
233
|
return;
|
|
235
234
|
}
|
|
236
235
|
if (conf.fatal?.some((rx) => e2.match(rx))) {
|
|
237
|
-
await yesLog`fatal |${e2}`;
|
|
238
236
|
isFatal = true;
|
|
239
237
|
await exitAgent();
|
|
240
238
|
}
|
|
@@ -256,14 +254,14 @@ async function claudeYes({
|
|
|
256
254
|
const st = Date.now();
|
|
257
255
|
await idleWaiter.wait(waitms);
|
|
258
256
|
const et = Date.now();
|
|
259
|
-
await yesLog`sendEn| idleWaiter.wait(${String(waitms)}) took ${String(et - st)}ms`;
|
|
260
257
|
shell.write("\r");
|
|
261
258
|
}
|
|
262
259
|
async function sendMessage(message) {
|
|
263
260
|
await stdinReady.wait();
|
|
264
|
-
await yesLog`send |${message}`;
|
|
265
261
|
shell.write(message);
|
|
262
|
+
nextStdout.unready();
|
|
266
263
|
idleWaiter.ping();
|
|
264
|
+
await nextStdout.wait();
|
|
267
265
|
await sendEnter();
|
|
268
266
|
}
|
|
269
267
|
async function exitAgent() {
|
|
@@ -350,5 +348,5 @@ var { exitCode, logs } = await claudeYes({
|
|
|
350
348
|
});
|
|
351
349
|
process.exit(exitCode ?? 1);
|
|
352
350
|
|
|
353
|
-
//# debugId=
|
|
351
|
+
//# debugId=C28320E15F2B1F0F64756E2164756E21
|
|
354
352
|
//# sourceMappingURL=cli.js.map
|
package/dist/gemini-yes.js
CHANGED
|
@@ -25,12 +25,11 @@ import { hideBin } from "yargs/helpers";
|
|
|
25
25
|
|
|
26
26
|
// dist/index.js
|
|
27
27
|
import { fromReadable, fromWritable } from "from-node-stream";
|
|
28
|
-
import {
|
|
28
|
+
import { mkdir, writeFile } from "fs/promises";
|
|
29
29
|
import path from "path";
|
|
30
30
|
import DIE from "phpdie";
|
|
31
31
|
import sflow from "sflow";
|
|
32
32
|
import { TerminalTextRender } from "terminal-render";
|
|
33
|
-
import tsaComposer from "tsa-composer";
|
|
34
33
|
class IdleWaiter {
|
|
35
34
|
lastActivityTime = Date.now();
|
|
36
35
|
checkInterval = 100;
|
|
@@ -94,7 +93,7 @@ var CLI_CONFIGURES = {
|
|
|
94
93
|
ready: [/⏎ send/],
|
|
95
94
|
enter: [
|
|
96
95
|
/> 1. Yes, allow Codex to work in this folder/,
|
|
97
|
-
|
|
96
|
+
/> 1. Approve and run now/
|
|
98
97
|
],
|
|
99
98
|
fatal: [/Error: The cursor position could not be read within/],
|
|
100
99
|
ensureArgs: (args) => {
|
|
@@ -129,11 +128,6 @@ async function claudeYes({
|
|
|
129
128
|
removeControlCharactersFromStdout = false,
|
|
130
129
|
verbose = false
|
|
131
130
|
} = {}) {
|
|
132
|
-
await rm("agent-yes.log").catch(() => null);
|
|
133
|
-
const yesLog = tsaComposer()(async function yesLog(msg) {
|
|
134
|
-
await appendFile("agent-yes.log", `${msg}
|
|
135
|
-
`).catch(() => null);
|
|
136
|
-
});
|
|
137
131
|
const continueArgs = {
|
|
138
132
|
codex: "resume --last".split(" "),
|
|
139
133
|
claude: "--continue".split(" "),
|
|
@@ -142,6 +136,7 @@ async function claudeYes({
|
|
|
142
136
|
process.stdin.setRawMode?.(true);
|
|
143
137
|
let isFatal = false;
|
|
144
138
|
const stdinReady = new ReadyManager;
|
|
139
|
+
const nextStdout = new ReadyManager;
|
|
145
140
|
const shellOutputStream = new TransformStream;
|
|
146
141
|
const outputWriter = shellOutputStream.writable.getWriter();
|
|
147
142
|
const pty = await import("node-pty").catch(async () => await import("bun-pty")).catch(async () => DIE("Please install node-pty or bun-pty, run this: bun install bun-pty"));
|
|
@@ -163,10 +158,12 @@ async function claudeYes({
|
|
|
163
158
|
const pendingExitCode = Promise.withResolvers();
|
|
164
159
|
let pendingExitCodeValue = null;
|
|
165
160
|
async function onData(data) {
|
|
161
|
+
nextStdout.ready();
|
|
166
162
|
await outputWriter.write(data);
|
|
167
163
|
}
|
|
168
164
|
shell.onData(onData);
|
|
169
165
|
shell.onExit(function onExit({ exitCode: exitCode2 }) {
|
|
166
|
+
nextStdout.ready();
|
|
170
167
|
stdinReady.unready();
|
|
171
168
|
const agentCrashed = exitCode2 !== 0;
|
|
172
169
|
const continueArg = continueArgs[cli];
|
|
@@ -218,23 +215,24 @@ async function claudeYes({
|
|
|
218
215
|
const { col, row } = terminalRender.getCursorPosition();
|
|
219
216
|
console.log(`[${cli}-yes] Responding cursor position: row=${row}, col=${col}`);
|
|
220
217
|
shell.write(`\x1B[${row};${col}R`);
|
|
221
|
-
}).forkTo((e) => e.map((e2) => removeControlCharacters(e2)).map((e2) => e2.replaceAll("\r", "")).
|
|
218
|
+
}).forkTo((e) => e.map((e2) => removeControlCharacters(e2)).map((e2) => e2.replaceAll("\r", "")).by((s) => {
|
|
219
|
+
if (cli === "codex")
|
|
220
|
+
return s;
|
|
221
|
+
return s.lines({ EOL: "NONE" });
|
|
222
|
+
}).forEach(async (e2, i) => {
|
|
222
223
|
const conf = CLI_CONFIGURES[cli] || null;
|
|
223
224
|
if (!conf)
|
|
224
225
|
return;
|
|
225
226
|
if (conf.ready?.some((rx) => e2.match(rx))) {
|
|
226
|
-
await yesLog`ready |${e2}`;
|
|
227
227
|
if (cli === "gemini" && i <= 80)
|
|
228
228
|
return;
|
|
229
229
|
stdinReady.ready();
|
|
230
230
|
}
|
|
231
231
|
if (conf.enter?.some((rx) => e2.match(rx))) {
|
|
232
|
-
await yesLog`enter |${e2}`;
|
|
233
232
|
await sendEnter(300);
|
|
234
233
|
return;
|
|
235
234
|
}
|
|
236
235
|
if (conf.fatal?.some((rx) => e2.match(rx))) {
|
|
237
|
-
await yesLog`fatal |${e2}`;
|
|
238
236
|
isFatal = true;
|
|
239
237
|
await exitAgent();
|
|
240
238
|
}
|
|
@@ -256,14 +254,14 @@ async function claudeYes({
|
|
|
256
254
|
const st = Date.now();
|
|
257
255
|
await idleWaiter.wait(waitms);
|
|
258
256
|
const et = Date.now();
|
|
259
|
-
await yesLog`sendEn| idleWaiter.wait(${String(waitms)}) took ${String(et - st)}ms`;
|
|
260
257
|
shell.write("\r");
|
|
261
258
|
}
|
|
262
259
|
async function sendMessage(message) {
|
|
263
260
|
await stdinReady.wait();
|
|
264
|
-
await yesLog`send |${message}`;
|
|
265
261
|
shell.write(message);
|
|
262
|
+
nextStdout.unready();
|
|
266
263
|
idleWaiter.ping();
|
|
264
|
+
await nextStdout.wait();
|
|
267
265
|
await sendEnter();
|
|
268
266
|
}
|
|
269
267
|
async function exitAgent() {
|
|
@@ -350,5 +348,5 @@ var { exitCode, logs } = await claudeYes({
|
|
|
350
348
|
});
|
|
351
349
|
process.exit(exitCode ?? 1);
|
|
352
350
|
|
|
353
|
-
//# debugId=
|
|
351
|
+
//# debugId=C28320E15F2B1F0F64756E2164756E21
|
|
354
352
|
//# sourceMappingURL=cli.js.map
|
package/dist/grok-yes.js
CHANGED
|
@@ -25,12 +25,11 @@ import { hideBin } from "yargs/helpers";
|
|
|
25
25
|
|
|
26
26
|
// dist/index.js
|
|
27
27
|
import { fromReadable, fromWritable } from "from-node-stream";
|
|
28
|
-
import {
|
|
28
|
+
import { mkdir, writeFile } from "fs/promises";
|
|
29
29
|
import path from "path";
|
|
30
30
|
import DIE from "phpdie";
|
|
31
31
|
import sflow from "sflow";
|
|
32
32
|
import { TerminalTextRender } from "terminal-render";
|
|
33
|
-
import tsaComposer from "tsa-composer";
|
|
34
33
|
class IdleWaiter {
|
|
35
34
|
lastActivityTime = Date.now();
|
|
36
35
|
checkInterval = 100;
|
|
@@ -94,7 +93,7 @@ var CLI_CONFIGURES = {
|
|
|
94
93
|
ready: [/⏎ send/],
|
|
95
94
|
enter: [
|
|
96
95
|
/> 1. Yes, allow Codex to work in this folder/,
|
|
97
|
-
|
|
96
|
+
/> 1. Approve and run now/
|
|
98
97
|
],
|
|
99
98
|
fatal: [/Error: The cursor position could not be read within/],
|
|
100
99
|
ensureArgs: (args) => {
|
|
@@ -129,11 +128,6 @@ async function claudeYes({
|
|
|
129
128
|
removeControlCharactersFromStdout = false,
|
|
130
129
|
verbose = false
|
|
131
130
|
} = {}) {
|
|
132
|
-
await rm("agent-yes.log").catch(() => null);
|
|
133
|
-
const yesLog = tsaComposer()(async function yesLog(msg) {
|
|
134
|
-
await appendFile("agent-yes.log", `${msg}
|
|
135
|
-
`).catch(() => null);
|
|
136
|
-
});
|
|
137
131
|
const continueArgs = {
|
|
138
132
|
codex: "resume --last".split(" "),
|
|
139
133
|
claude: "--continue".split(" "),
|
|
@@ -142,6 +136,7 @@ async function claudeYes({
|
|
|
142
136
|
process.stdin.setRawMode?.(true);
|
|
143
137
|
let isFatal = false;
|
|
144
138
|
const stdinReady = new ReadyManager;
|
|
139
|
+
const nextStdout = new ReadyManager;
|
|
145
140
|
const shellOutputStream = new TransformStream;
|
|
146
141
|
const outputWriter = shellOutputStream.writable.getWriter();
|
|
147
142
|
const pty = await import("node-pty").catch(async () => await import("bun-pty")).catch(async () => DIE("Please install node-pty or bun-pty, run this: bun install bun-pty"));
|
|
@@ -163,10 +158,12 @@ async function claudeYes({
|
|
|
163
158
|
const pendingExitCode = Promise.withResolvers();
|
|
164
159
|
let pendingExitCodeValue = null;
|
|
165
160
|
async function onData(data) {
|
|
161
|
+
nextStdout.ready();
|
|
166
162
|
await outputWriter.write(data);
|
|
167
163
|
}
|
|
168
164
|
shell.onData(onData);
|
|
169
165
|
shell.onExit(function onExit({ exitCode: exitCode2 }) {
|
|
166
|
+
nextStdout.ready();
|
|
170
167
|
stdinReady.unready();
|
|
171
168
|
const agentCrashed = exitCode2 !== 0;
|
|
172
169
|
const continueArg = continueArgs[cli];
|
|
@@ -218,23 +215,24 @@ async function claudeYes({
|
|
|
218
215
|
const { col, row } = terminalRender.getCursorPosition();
|
|
219
216
|
console.log(`[${cli}-yes] Responding cursor position: row=${row}, col=${col}`);
|
|
220
217
|
shell.write(`\x1B[${row};${col}R`);
|
|
221
|
-
}).forkTo((e) => e.map((e2) => removeControlCharacters(e2)).map((e2) => e2.replaceAll("\r", "")).
|
|
218
|
+
}).forkTo((e) => e.map((e2) => removeControlCharacters(e2)).map((e2) => e2.replaceAll("\r", "")).by((s) => {
|
|
219
|
+
if (cli === "codex")
|
|
220
|
+
return s;
|
|
221
|
+
return s.lines({ EOL: "NONE" });
|
|
222
|
+
}).forEach(async (e2, i) => {
|
|
222
223
|
const conf = CLI_CONFIGURES[cli] || null;
|
|
223
224
|
if (!conf)
|
|
224
225
|
return;
|
|
225
226
|
if (conf.ready?.some((rx) => e2.match(rx))) {
|
|
226
|
-
await yesLog`ready |${e2}`;
|
|
227
227
|
if (cli === "gemini" && i <= 80)
|
|
228
228
|
return;
|
|
229
229
|
stdinReady.ready();
|
|
230
230
|
}
|
|
231
231
|
if (conf.enter?.some((rx) => e2.match(rx))) {
|
|
232
|
-
await yesLog`enter |${e2}`;
|
|
233
232
|
await sendEnter(300);
|
|
234
233
|
return;
|
|
235
234
|
}
|
|
236
235
|
if (conf.fatal?.some((rx) => e2.match(rx))) {
|
|
237
|
-
await yesLog`fatal |${e2}`;
|
|
238
236
|
isFatal = true;
|
|
239
237
|
await exitAgent();
|
|
240
238
|
}
|
|
@@ -256,14 +254,14 @@ async function claudeYes({
|
|
|
256
254
|
const st = Date.now();
|
|
257
255
|
await idleWaiter.wait(waitms);
|
|
258
256
|
const et = Date.now();
|
|
259
|
-
await yesLog`sendEn| idleWaiter.wait(${String(waitms)}) took ${String(et - st)}ms`;
|
|
260
257
|
shell.write("\r");
|
|
261
258
|
}
|
|
262
259
|
async function sendMessage(message) {
|
|
263
260
|
await stdinReady.wait();
|
|
264
|
-
await yesLog`send |${message}`;
|
|
265
261
|
shell.write(message);
|
|
262
|
+
nextStdout.unready();
|
|
266
263
|
idleWaiter.ping();
|
|
264
|
+
await nextStdout.wait();
|
|
267
265
|
await sendEnter();
|
|
268
266
|
}
|
|
269
267
|
async function exitAgent() {
|
|
@@ -350,5 +348,5 @@ var { exitCode, logs } = await claudeYes({
|
|
|
350
348
|
});
|
|
351
349
|
process.exit(exitCode ?? 1);
|
|
352
350
|
|
|
353
|
-
//# debugId=
|
|
351
|
+
//# debugId=C28320E15F2B1F0F64756E2164756E21
|
|
354
352
|
//# sourceMappingURL=cli.js.map
|
package/dist/index.js
CHANGED
|
@@ -19,12 +19,11 @@ var __require = /* @__PURE__ */ createRequire(import.meta.url);
|
|
|
19
19
|
|
|
20
20
|
// index.ts
|
|
21
21
|
import { fromReadable, fromWritable } from "from-node-stream";
|
|
22
|
-
import {
|
|
22
|
+
import { mkdir, writeFile } from "fs/promises";
|
|
23
23
|
import path from "path";
|
|
24
24
|
import DIE from "phpdie";
|
|
25
25
|
import sflow from "sflow";
|
|
26
26
|
import { TerminalTextRender } from "terminal-render";
|
|
27
|
-
import tsaComposer from "tsa-composer";
|
|
28
27
|
|
|
29
28
|
// idleWaiter.ts
|
|
30
29
|
class IdleWaiter {
|
|
@@ -95,7 +94,7 @@ var CLI_CONFIGURES = {
|
|
|
95
94
|
ready: [/⏎ send/],
|
|
96
95
|
enter: [
|
|
97
96
|
/> 1. Yes, allow Codex to work in this folder/,
|
|
98
|
-
|
|
97
|
+
/> 1. Approve and run now/
|
|
99
98
|
],
|
|
100
99
|
fatal: [/Error: The cursor position could not be read within/],
|
|
101
100
|
ensureArgs: (args) => {
|
|
@@ -130,11 +129,6 @@ async function claudeYes({
|
|
|
130
129
|
removeControlCharactersFromStdout = false,
|
|
131
130
|
verbose = false
|
|
132
131
|
} = {}) {
|
|
133
|
-
await rm("agent-yes.log").catch(() => null);
|
|
134
|
-
const yesLog = tsaComposer()(async function yesLog(msg) {
|
|
135
|
-
await appendFile("agent-yes.log", `${msg}
|
|
136
|
-
`).catch(() => null);
|
|
137
|
-
});
|
|
138
132
|
const continueArgs = {
|
|
139
133
|
codex: "resume --last".split(" "),
|
|
140
134
|
claude: "--continue".split(" "),
|
|
@@ -143,6 +137,7 @@ async function claudeYes({
|
|
|
143
137
|
process.stdin.setRawMode?.(true);
|
|
144
138
|
let isFatal = false;
|
|
145
139
|
const stdinReady = new ReadyManager;
|
|
140
|
+
const nextStdout = new ReadyManager;
|
|
146
141
|
const shellOutputStream = new TransformStream;
|
|
147
142
|
const outputWriter = shellOutputStream.writable.getWriter();
|
|
148
143
|
const pty = await import("node-pty").catch(async () => await import("bun-pty")).catch(async () => DIE("Please install node-pty or bun-pty, run this: bun install bun-pty"));
|
|
@@ -164,10 +159,12 @@ async function claudeYes({
|
|
|
164
159
|
const pendingExitCode = Promise.withResolvers();
|
|
165
160
|
let pendingExitCodeValue = null;
|
|
166
161
|
async function onData(data) {
|
|
162
|
+
nextStdout.ready();
|
|
167
163
|
await outputWriter.write(data);
|
|
168
164
|
}
|
|
169
165
|
shell.onData(onData);
|
|
170
166
|
shell.onExit(function onExit({ exitCode: exitCode2 }) {
|
|
167
|
+
nextStdout.ready();
|
|
171
168
|
stdinReady.unready();
|
|
172
169
|
const agentCrashed = exitCode2 !== 0;
|
|
173
170
|
const continueArg = continueArgs[cli];
|
|
@@ -219,23 +216,24 @@ async function claudeYes({
|
|
|
219
216
|
const { col, row } = terminalRender.getCursorPosition();
|
|
220
217
|
console.log(`[${cli}-yes] Responding cursor position: row=${row}, col=${col}`);
|
|
221
218
|
shell.write(`\x1B[${row};${col}R`);
|
|
222
|
-
}).forkTo((e) => e.map((e2) => removeControlCharacters(e2)).map((e2) => e2.replaceAll("\r", "")).
|
|
219
|
+
}).forkTo((e) => e.map((e2) => removeControlCharacters(e2)).map((e2) => e2.replaceAll("\r", "")).by((s) => {
|
|
220
|
+
if (cli === "codex")
|
|
221
|
+
return s;
|
|
222
|
+
return s.lines({ EOL: "NONE" });
|
|
223
|
+
}).forEach(async (e2, i) => {
|
|
223
224
|
const conf = CLI_CONFIGURES[cli] || null;
|
|
224
225
|
if (!conf)
|
|
225
226
|
return;
|
|
226
227
|
if (conf.ready?.some((rx) => e2.match(rx))) {
|
|
227
|
-
await yesLog`ready |${e2}`;
|
|
228
228
|
if (cli === "gemini" && i <= 80)
|
|
229
229
|
return;
|
|
230
230
|
stdinReady.ready();
|
|
231
231
|
}
|
|
232
232
|
if (conf.enter?.some((rx) => e2.match(rx))) {
|
|
233
|
-
await yesLog`enter |${e2}`;
|
|
234
233
|
await sendEnter(300);
|
|
235
234
|
return;
|
|
236
235
|
}
|
|
237
236
|
if (conf.fatal?.some((rx) => e2.match(rx))) {
|
|
238
|
-
await yesLog`fatal |${e2}`;
|
|
239
237
|
isFatal = true;
|
|
240
238
|
await exitAgent();
|
|
241
239
|
}
|
|
@@ -257,14 +255,14 @@ async function claudeYes({
|
|
|
257
255
|
const st = Date.now();
|
|
258
256
|
await idleWaiter.wait(waitms);
|
|
259
257
|
const et = Date.now();
|
|
260
|
-
await yesLog`sendEn| idleWaiter.wait(${String(waitms)}) took ${String(et - st)}ms`;
|
|
261
258
|
shell.write("\r");
|
|
262
259
|
}
|
|
263
260
|
async function sendMessage(message) {
|
|
264
261
|
await stdinReady.wait();
|
|
265
|
-
await yesLog`send |${message}`;
|
|
266
262
|
shell.write(message);
|
|
263
|
+
nextStdout.unready();
|
|
267
264
|
idleWaiter.ping();
|
|
265
|
+
await nextStdout.wait();
|
|
268
266
|
await sendEnter();
|
|
269
267
|
}
|
|
270
268
|
async function exitAgent() {
|
|
@@ -303,5 +301,5 @@ export {
|
|
|
303
301
|
CLI_CONFIGURES
|
|
304
302
|
};
|
|
305
303
|
|
|
306
|
-
//# debugId=
|
|
304
|
+
//# debugId=D17BB3E3D1DC936764756E2164756E21
|
|
307
305
|
//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
CHANGED
|
@@ -2,12 +2,12 @@
|
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../index.ts", "../idleWaiter.ts", "../ReadyManager.ts", "../removeControlCharacters.ts"],
|
|
4
4
|
"sourcesContent": [
|
|
5
|
-
"import { fromReadable, fromWritable } from 'from-node-stream';\nimport { appendFile, mkdir, rm, writeFile } from 'fs/promises';\nimport path from 'path';\nimport DIE from 'phpdie';\nimport sflow from 'sflow';\nimport { TerminalTextRender } from 'terminal-render';\nimport tsaComposer from 'tsa-composer';\nimport { IdleWaiter } from './idleWaiter';\nimport { ReadyManager } from './ReadyManager';\nimport { removeControlCharacters } from './removeControlCharacters';\n\nexport const CLI_CONFIGURES: Record<\n string,\n {\n install?: string; // hint user for install command if not installed\n binary?: string; // actual binary name if different from cli\n ready?: RegExp[]; // regex matcher for stdin ready, or line index for gemini\n enter?: RegExp[]; // array of regex to match for sending Enter\n fatal?: RegExp[]; // array of regex to match for fatal errors\n ensureArgs?: (args: string[]) => string[]; // function to ensure certain args are present\n }\n> = {\n grok: {\n install: 'npm install -g @vibe-kit/grok-cli',\n ready: [/^ │ ❯ /],\n enter: [/^ 1. Yes/],\n },\n claude: {\n install: 'npm install -g @anthropic-ai/claude-code',\n // ready: [/^> /], // regex matcher for stdin ready\n ready: [/\\? for shortcuts/], // regex matcher for stdin ready\n enter: [/❯ 1. Yes/, /❯ 1. Dark mode✔/, /Press Enter to continue…/],\n fatal: [\n /No conversation found to continue/,\n /⎿ Claude usage limit reached\\./,\n ],\n },\n gemini: {\n install: 'npm install -g @google/gemini-cli',\n // match the agent prompt after initial lines; handled by index logic using line index\n ready: [/Type your message/], // used with line index check\n enter: [/│ ● 1. Yes, allow once/],\n fatal: [],\n },\n codex: {\n install: 'npm install -g @openai/codex-cli',\n ready: [/⏎ send/],\n enter: [\n /> 1. Yes, allow Codex to work in this folder/,\n /▌ > 1. Approve and run now/,\n ],\n fatal: [/Error: The cursor position could not be read within/],\n // add to codex --search by default when not provided by the user\n ensureArgs: (args: string[]) => {\n if (!args.includes('--search')) return ['--search', ...args];\n return args;\n },\n },\n copilot: {\n install: 'npm install -g @github/copilot',\n ready: [/^ > /],\n enter: [/ │ ❯ 1. Yes, proceed/, /❯ 1. Yes/],\n fatal: [],\n },\n cursor: {\n install: 'open https://cursor.com/ja/docs/cli/installation',\n // map logical \"cursor\" cli name to actual binary name\n binary: 'cursor-agent',\n ready: [/\\/ commands/],\n enter: [/→ Run \\(once\\) \\(y\\) \\(enter\\)/, /▶ \\[a\\] Trust this workspace/],\n fatal: [/^ Error: You've hit your usage limit/],\n },\n};\n/**\n * Main function to run agent-cli with automatic yes/no responses\n * @param options Configuration options\n * @param options.continueOnCrash - If true, automatically restart agent-cli when it crashes:\n * 1. Shows message 'agent-cli crashed, restarting..'\n * 2. Spawns a new 'agent-cli --continue' process\n * 3. Re-attaches the new process to the shell stdio (pipes new process stdin/stdout)\n * 4. If it crashes with \"No conversation found to continue\", exits the process\n * @param options.exitOnIdle - Exit when agent-cli is idle. Boolean or timeout in milliseconds, recommended 5000 - 60000, default is false\n * @param options.cliArgs - Additional arguments to pass to the agent-cli CLI\n * @param options.removeControlCharactersFromStdout - Remove ANSI control characters from stdout. Defaults to !process.stdout.isTTY\n *\n * @example\n * ```typescript\n * import claudeYes from 'claude-yes';\n * await claudeYes({\n * prompt: 'help me solve all todos in my codebase',\n *\n * // optional\n * cli: 'claude',\n * cliArgs: ['--verbose'], // additional args to pass to claude\n * exitOnIdle: 30000, // exit after 30 seconds of idle\n * continueOnCrash: true, // restart if claude crashes, default is true\n * logFile: 'claude.log', // save logs to file\n * });\n * ```\n */\nexport default async function claudeYes({\n cli = 'claude',\n cliArgs = [],\n prompt,\n continueOnCrash,\n cwd,\n env,\n exitOnIdle,\n logFile,\n removeControlCharactersFromStdout = false, // = !process.stdout.isTTY,\n verbose = false,\n}: {\n cli?: (string & {}) | keyof typeof CLI_CONFIGURES;\n cliArgs?: string[];\n prompt?: string;\n continueOnCrash?: boolean;\n cwd?: string;\n env?: Record<string, string>;\n exitOnIdle?: number;\n logFile?: string;\n removeControlCharactersFromStdout?: boolean;\n verbose?: boolean;\n} = {}) {\n await rm('agent-yes.log').catch(() => null); // ignore error if file doesn't exist\n const yesLog = tsaComposer()(async function yesLog(msg: string) {\n await appendFile('agent-yes.log', `${msg}\\n`).catch(() => null);\n });\n const continueArgs = {\n codex: 'resume --last'.split(' '),\n claude: '--continue'.split(' '),\n gemini: [], // not possible yet\n };\n\n process.stdin.setRawMode?.(true); // must be called any stdout/stdin usage\n let isFatal = false; // when true, do not restart on crash, and exit agent\n const stdinReady = new ReadyManager();\n\n const shellOutputStream = new TransformStream<string, string>();\n const outputWriter = shellOutputStream.writable.getWriter();\n // const pty = await import('node-pty');\n\n // its recommened to use bun-pty in windows\n const pty = await import('node-pty')\n .catch(async () => await import('bun-pty'))\n .catch(async () =>\n DIE('Please install node-pty or bun-pty, run this: bun install bun-pty'),\n );\n\n const getPtyOptions = () => ({\n name: 'xterm-color',\n ...getTerminalDimensions(),\n cwd: cwd ?? process.cwd(),\n env: env ?? (process.env as Record<string, string>),\n });\n\n // Apply CLI specific configurations (moved to CLI_CONFIGURES)\n const cliConf = (CLI_CONFIGURES as Record<string, any>)[cli] || {};\n cliArgs = cliConf.ensureArgs?.(cliArgs) ?? cliArgs;\n const cliCommand = cliConf?.binary || cli;\n\n let shell = tryCatch(\n () => pty.spawn(cliCommand, cliArgs, getPtyOptions()),\n (error: unknown) => {\n console.error(`Fatal: Failed to start ${cliCommand}.`);\n if (cliConf?.install)\n console.error(\n `If you did not installed it yet, Please install it first: ${cliConf.install}`,\n );\n throw error;\n },\n );\n const pendingExitCode = Promise.withResolvers<number | null>();\n let pendingExitCodeValue = null;\n\n // TODO handle error if claude is not installed, show msg:\n // npm install -g @anthropic-ai/claude-code\n\n async function onData(data: string) {\n // append data to the buffer, so we can process it later\n await outputWriter.write(data);\n }\n\n shell.onData(onData);\n shell.onExit(function onExit({ exitCode }) {\n stdinReady.unready(); // start buffer stdin\n const agentCrashed = exitCode !== 0;\n const continueArg = (continueArgs as Record<string, string[]>)[cli];\n\n if (agentCrashed && continueOnCrash && continueArg) {\n if (!continueArg) {\n return console.warn(\n `continueOnCrash is only supported for ${Object.keys(continueArgs).join(', ')} currently, not ${cli}`,\n );\n }\n if (isFatal) {\n return pendingExitCode.resolve((pendingExitCodeValue = exitCode));\n }\n\n console.log(`${cli} crashed, restarting...`);\n\n shell = pty.spawn(cli, continueArg, getPtyOptions());\n shell.onData(onData);\n shell.onExit(onExit);\n return;\n }\n return pendingExitCode.resolve((pendingExitCodeValue = exitCode));\n });\n\n // when current tty resized, resize the pty\n process.stdout.on('resize', () => {\n const { cols, rows } = getTerminalDimensions(); // minimum 80 columns to avoid layout issues\n shell.resize(cols, rows); // minimum 80 columns to avoid layout issues\n });\n\n const terminalRender = new TerminalTextRender();\n const isStillWorkingQ = () =>\n terminalRender\n .render()\n .replace(/\\s+/g, ' ')\n .match(/esc to interrupt|to run in background/);\n\n const idleWaiter = new IdleWaiter();\n if (exitOnIdle)\n idleWaiter.wait(exitOnIdle).then(async () => {\n if (isStillWorkingQ()) {\n console.log(\n '[${cli}-yes] ${cli} is idle, but seems still working, not exiting yet',\n );\n return;\n }\n\n console.log('[${cli}-yes] ${cli} is idle, exiting...');\n await exitAgent();\n });\n\n // console.log(\n // `[${cli}-yes] Started ${cli} with args: ${[cliCommand, ...cliArgs].join(\" \")}`\n // );\n // Message streaming\n\n sflow(fromReadable<Buffer>(process.stdin))\n .map((buffer) => buffer.toString())\n // .map((e) => e.replaceAll('\\x1a', '')) // remove ctrl+z from user's input (seems bug)\n // .forEach(e => appendFile('.cache/io.log', \"input |\" + JSON.stringify(e) + '\\n')) // for debugging\n // pipe\n .by({\n writable: new WritableStream<string>({\n write: async (data) => {\n await stdinReady.wait();\n // await idleWaiter.wait(20); // wait for idle for 200ms to avoid messing up claude's input\n shell.write(data);\n },\n }),\n readable: shellOutputStream.readable,\n })\n .forEach(() => idleWaiter.ping())\n .forEach((text) => {\n terminalRender.write(text);\n // todo: .onStatus((msg)=> shell.write(msg))\n if (process.stdin.isTTY) return; // only handle it when stdin is not tty\n if (!text.includes('\\u001b[6n')) return; // only asked for cursor position\n // todo: use terminalRender API to get cursor position when new version is available\n // xterm replies CSI row; column R if asked cursor position\n // https://en.wikipedia.org/wiki/ANSI_escape_code#:~:text=citation%20needed%5D-,xterm%20replies,-CSI%20row%C2%A0%3B\n // when agent asking position, respond with row; col\n // const rendered = terminalRender.render();\n const { col, row } = terminalRender.getCursorPosition();\n console.log(\n `[${cli}-yes] Responding cursor position: row=${row}, col=${col}`,\n );\n shell.write(`\\u001b[${row};${col}R`); // reply cli when getting cursor position\n // const row = rendered.split('\\n').length + 1;\n // const col = (rendered.split('\\n').slice(-1)[0]?.length || 0) + 1;\n })\n\n // auto-response\n .forkTo((e) =>\n e\n .map((e) => removeControlCharacters(e))\n .map((e) => e.replaceAll('\\r', '')) // remove carriage return\n .lines({ EOL: 'NONE' })\n .forEach((e) => yesLog`output|${e}`) // for debugging\n // Generic auto-response handler driven by CLI_CONFIGURES\n .forEach(async (e, i) => {\n const conf =\n CLI_CONFIGURES[cli as keyof typeof CLI_CONFIGURES] || null;\n if (!conf) return;\n\n // ready matcher: if matched, mark stdin ready\n if (conf.ready?.some((rx: RegExp) => e.match(rx))) {\n await yesLog`ready |${e}`;\n if (cli === 'gemini' && i <= 80) return; // gemini initial noise, only after many lines\n stdinReady.ready();\n }\n\n // enter matchers: send Enter when any enter regex matches\n if (conf.enter?.some((rx: RegExp) => e.match(rx))) {\n await yesLog`enter |${e}`;\n await sendEnter(300); // send Enter after 300ms idle wait\n return;\n }\n\n // fatal matchers: set isFatal flag when matched\n if (conf.fatal?.some((rx: RegExp) => e.match(rx))) {\n await yesLog`fatal |${e}`;\n isFatal = true;\n await exitAgent();\n }\n })\n .run(),\n )\n .map((e) =>\n removeControlCharactersFromStdout ? removeControlCharacters(e) : e,\n )\n .to(fromWritable(process.stdout))\n .then(() => null); // run it immediately without await\n\n // wait for cli ready and send prompt if provided\n if (cli === 'codex') shell.write(`\\u001b[1;1R`); // send cursor position response when stdin is not tty\n if (prompt) await sendMessage(prompt);\n\n const exitCode = await pendingExitCode.promise; // wait for the shell to exit\n console.log(`[${cli}-yes] ${cli} exited with code ${exitCode}`);\n\n if (logFile) {\n verbose && console.log(`[${cli}-yes] Writing rendered logs to ${logFile}`);\n const logFilePath = path.resolve(logFile);\n await mkdir(path.dirname(logFilePath), { recursive: true }).catch(\n () => null,\n );\n await writeFile(logFilePath, terminalRender.render());\n }\n\n return { exitCode, logs: terminalRender.render() };\n\n async function sendEnter(waitms = 1000) {\n // wait for idle for a bit to let agent cli finish rendering\n const st = Date.now();\n await idleWaiter.wait(waitms);\n const et = Date.now();\n // process.stdout.write(`\\ridleWaiter.wait(${waitms}) took ${et - st}ms\\r`);\n await yesLog`sendEn| idleWaiter.wait(${String(waitms)}) took ${String(et - st)}ms`;\n\n shell.write('\\r');\n }\n\n async function sendMessage(message: string) {\n await stdinReady.wait();\n // show in-place message: write msg and move cursor back start\n await yesLog`send |${message}`;\n shell.write(message);\n idleWaiter.ping(); // just sent a message, wait for echo\n await sendEnter();\n }\n\n async function exitAgent() {\n continueOnCrash = false;\n // send exit command to the shell, must sleep a bit to avoid claude treat it as pasted input\n await sendMessage('/exit');\n\n // wait for shell to exit or kill it with a timeout\n let exited = false;\n await Promise.race([\n pendingExitCode.promise.then(() => (exited = true)), // resolve when shell exits\n\n // if shell doesn't exit in 5 seconds, kill it\n new Promise<void>((resolve) =>\n setTimeout(() => {\n if (exited) return; // if shell already exited, do nothing\n shell.kill(); // kill the shell process if it doesn't exit in time\n resolve();\n }, 5000),\n ), // 5 seconds timeout\n ]);\n }\n\n function getTerminalDimensions() {\n if (!process.stdout.isTTY) return { cols: 80, rows: 30 }; // default size when not tty\n return {\n // TODO: enforce minimum cols/rows to avoid layout issues\n // cols: Math.max(process.stdout.columns, 80),\n cols: Math.min(Math.max(20, process.stdout.columns), 80),\n rows: process.stdout.rows,\n };\n }\n}\n\nexport { removeControlCharacters };\n\nfunction tryCatch<T, R>(fn: () => T, catchFn: (error: unknown) => R): T | R {\n try {\n return fn();\n } catch (error) {\n return catchFn(error);\n }\n}\n",
|
|
5
|
+
"import { fromReadable, fromWritable } from 'from-node-stream';\nimport { appendFile, mkdir, rm, writeFile } from 'fs/promises';\nimport path from 'path';\nimport DIE from 'phpdie';\nimport sflow from 'sflow';\nimport { TerminalTextRender } from 'terminal-render';\nimport tsaComposer from 'tsa-composer';\nimport { IdleWaiter } from './idleWaiter';\nimport { ReadyManager } from './ReadyManager';\nimport { removeControlCharacters } from './removeControlCharacters';\n\n// const yesLog = tsaComposer()(async function yesLog(msg: string) {\n// // await rm('agent-yes.log').catch(() => null); // ignore error if file doesn't exist\n// await appendFile(\"agent-yes.log\", `${msg}\\n`).catch(() => null);\n// });\n\nexport const CLI_CONFIGURES: Record<\n string,\n {\n install?: string; // hint user for install command if not installed\n binary?: string; // actual binary name if different from cli\n ready?: RegExp[]; // regex matcher for stdin ready, or line index for gemini\n enter?: RegExp[]; // array of regex to match for sending Enter\n fatal?: RegExp[]; // array of regex to match for fatal errors\n ensureArgs?: (args: string[]) => string[]; // function to ensure certain args are present\n }\n> = {\n grok: {\n install: 'npm install -g @vibe-kit/grok-cli',\n ready: [/^ │ ❯ /],\n enter: [/^ 1. Yes/],\n },\n claude: {\n install: 'npm install -g @anthropic-ai/claude-code',\n // ready: [/^> /], // regex matcher for stdin ready\n ready: [/\\? for shortcuts/], // regex matcher for stdin ready\n enter: [/❯ 1. Yes/, /❯ 1. Dark mode✔/, /Press Enter to continue…/],\n fatal: [\n /No conversation found to continue/,\n /⎿ Claude usage limit reached\\./,\n ],\n },\n gemini: {\n install: 'npm install -g @google/gemini-cli',\n // match the agent prompt after initial lines; handled by index logic using line index\n ready: [/Type your message/], // used with line index check\n enter: [/│ ● 1. Yes, allow once/],\n fatal: [],\n },\n codex: {\n install: 'npm install -g @openai/codex-cli',\n ready: [/⏎ send/],\n enter: [\n /> 1. Yes, allow Codex to work in this folder/,\n /> 1. Approve and run now/,\n ],\n fatal: [/Error: The cursor position could not be read within/],\n // add to codex --search by default when not provided by the user\n ensureArgs: (args: string[]) => {\n if (!args.includes('--search')) return ['--search', ...args];\n return args;\n },\n },\n copilot: {\n install: 'npm install -g @github/copilot',\n ready: [/^ > /],\n enter: [/ │ ❯ 1. Yes, proceed/, /❯ 1. Yes/],\n fatal: [],\n },\n cursor: {\n install: 'open https://cursor.com/ja/docs/cli/installation',\n // map logical \"cursor\" cli name to actual binary name\n binary: 'cursor-agent',\n ready: [/\\/ commands/],\n enter: [/→ Run \\(once\\) \\(y\\) \\(enter\\)/, /▶ \\[a\\] Trust this workspace/],\n fatal: [/^ Error: You've hit your usage limit/],\n },\n};\n/**\n * Main function to run agent-cli with automatic yes/no responses\n * @param options Configuration options\n * @param options.continueOnCrash - If true, automatically restart agent-cli when it crashes:\n * 1. Shows message 'agent-cli crashed, restarting..'\n * 2. Spawns a new 'agent-cli --continue' process\n * 3. Re-attaches the new process to the shell stdio (pipes new process stdin/stdout)\n * 4. If it crashes with \"No conversation found to continue\", exits the process\n * @param options.exitOnIdle - Exit when agent-cli is idle. Boolean or timeout in milliseconds, recommended 5000 - 60000, default is false\n * @param options.cliArgs - Additional arguments to pass to the agent-cli CLI\n * @param options.removeControlCharactersFromStdout - Remove ANSI control characters from stdout. Defaults to !process.stdout.isTTY\n *\n * @example\n * ```typescript\n * import claudeYes from 'claude-yes';\n * await claudeYes({\n * prompt: 'help me solve all todos in my codebase',\n *\n * // optional\n * cli: 'claude',\n * cliArgs: ['--verbose'], // additional args to pass to claude\n * exitOnIdle: 30000, // exit after 30 seconds of idle\n * continueOnCrash: true, // restart if claude crashes, default is true\n * logFile: 'claude.log', // save logs to file\n * });\n * ```\n */\nexport default async function claudeYes({\n cli = 'claude',\n cliArgs = [],\n prompt,\n continueOnCrash,\n cwd,\n env,\n exitOnIdle,\n logFile,\n removeControlCharactersFromStdout = false, // = !process.stdout.isTTY,\n verbose = false,\n}: {\n cli?: (string & {}) | keyof typeof CLI_CONFIGURES;\n cliArgs?: string[];\n prompt?: string;\n continueOnCrash?: boolean;\n cwd?: string;\n env?: Record<string, string>;\n exitOnIdle?: number;\n logFile?: string;\n removeControlCharactersFromStdout?: boolean;\n verbose?: boolean;\n} = {}) {\n const continueArgs = {\n codex: 'resume --last'.split(' '),\n claude: '--continue'.split(' '),\n gemini: [], // not possible yet\n };\n\n process.stdin.setRawMode?.(true); // must be called any stdout/stdin usage\n let isFatal = false; // when true, do not restart on crash, and exit agent\n const stdinReady = new ReadyManager();\n const nextStdout = new ReadyManager();\n\n const shellOutputStream = new TransformStream<string, string>();\n const outputWriter = shellOutputStream.writable.getWriter();\n // const pty = await import('node-pty');\n\n // its recommened to use bun-pty in windows\n const pty = await import('node-pty')\n .catch(async () => await import('bun-pty'))\n .catch(async () =>\n DIE('Please install node-pty or bun-pty, run this: bun install bun-pty'),\n );\n\n const getPtyOptions = () => ({\n name: 'xterm-color',\n ...getTerminalDimensions(),\n cwd: cwd ?? process.cwd(),\n env: env ?? (process.env as Record<string, string>),\n });\n\n // Apply CLI specific configurations (moved to CLI_CONFIGURES)\n const cliConf = (CLI_CONFIGURES as Record<string, any>)[cli] || {};\n cliArgs = cliConf.ensureArgs?.(cliArgs) ?? cliArgs;\n const cliCommand = cliConf?.binary || cli;\n\n let shell = tryCatch(\n () => pty.spawn(cliCommand, cliArgs, getPtyOptions()),\n (error: unknown) => {\n console.error(`Fatal: Failed to start ${cliCommand}.`);\n if (cliConf?.install)\n console.error(\n `If you did not installed it yet, Please install it first: ${cliConf.install}`,\n );\n throw error;\n },\n );\n const pendingExitCode = Promise.withResolvers<number | null>();\n let pendingExitCodeValue = null;\n\n // TODO handle error if claude is not installed, show msg:\n // npm install -g @anthropic-ai/claude-code\n\n async function onData(data: string) {\n nextStdout.ready();\n // append data to the buffer, so we can process it later\n await outputWriter.write(data);\n }\n\n shell.onData(onData);\n shell.onExit(function onExit({ exitCode }) {\n nextStdout.ready();\n stdinReady.unready(); // start buffer stdin\n const agentCrashed = exitCode !== 0;\n const continueArg = (continueArgs as Record<string, string[]>)[cli];\n\n if (agentCrashed && continueOnCrash && continueArg) {\n if (!continueArg) {\n return console.warn(\n `continueOnCrash is only supported for ${Object.keys(continueArgs).join(', ')} currently, not ${cli}`,\n );\n }\n if (isFatal) {\n return pendingExitCode.resolve((pendingExitCodeValue = exitCode));\n }\n\n console.log(`${cli} crashed, restarting...`);\n\n shell = pty.spawn(cli, continueArg, getPtyOptions());\n shell.onData(onData);\n shell.onExit(onExit);\n return;\n }\n return pendingExitCode.resolve((pendingExitCodeValue = exitCode));\n });\n\n // when current tty resized, resize the pty\n process.stdout.on('resize', () => {\n const { cols, rows } = getTerminalDimensions(); // minimum 80 columns to avoid layout issues\n shell.resize(cols, rows); // minimum 80 columns to avoid layout issues\n });\n\n const terminalRender = new TerminalTextRender();\n const isStillWorkingQ = () =>\n terminalRender\n .render()\n .replace(/\\s+/g, ' ')\n .match(/esc to interrupt|to run in background/);\n\n const idleWaiter = new IdleWaiter();\n if (exitOnIdle)\n idleWaiter.wait(exitOnIdle).then(async () => {\n if (isStillWorkingQ()) {\n console.log(\n '[${cli}-yes] ${cli} is idle, but seems still working, not exiting yet',\n );\n return;\n }\n\n console.log('[${cli}-yes] ${cli} is idle, exiting...');\n await exitAgent();\n });\n\n // console.log(\n // `[${cli}-yes] Started ${cli} with args: ${[cliCommand, ...cliArgs].join(\" \")}`\n // );\n // Message streaming\n\n sflow(fromReadable<Buffer>(process.stdin))\n .map((buffer) => buffer.toString())\n // .map((e) => e.replaceAll('\\x1a', '')) // remove ctrl+z from user's input (seems bug)\n // .forEach(e => appendFile('.cache/io.log', \"input |\" + JSON.stringify(e) + '\\n')) // for debugging\n // pipe\n .by({\n writable: new WritableStream<string>({\n write: async (data) => {\n await stdinReady.wait();\n // await idleWaiter.wait(20); // wait for idle for 200ms to avoid messing up claude's input\n shell.write(data);\n },\n }),\n readable: shellOutputStream.readable,\n })\n .forEach(() => idleWaiter.ping())\n .forEach((text) => {\n terminalRender.write(text);\n // todo: .onStatus((msg)=> shell.write(msg))\n if (process.stdin.isTTY) return; // only handle it when stdin is not tty\n if (!text.includes('\\u001b[6n')) return; // only asked for cursor position\n // todo: use terminalRender API to get cursor position when new version is available\n // xterm replies CSI row; column R if asked cursor position\n // https://en.wikipedia.org/wiki/ANSI_escape_code#:~:text=citation%20needed%5D-,xterm%20replies,-CSI%20row%C2%A0%3B\n // when agent asking position, respond with row; col\n // const rendered = terminalRender.render();\n const { col, row } = terminalRender.getCursorPosition();\n console.log(\n `[${cli}-yes] Responding cursor position: row=${row}, col=${col}`,\n );\n shell.write(`\\u001b[${row};${col}R`); // reply cli when getting cursor position\n // const row = rendered.split('\\n').length + 1;\n // const col = (rendered.split('\\n').slice(-1)[0]?.length || 0) + 1;\n })\n\n // auto-response\n .forkTo((e) =>\n e\n .map((e) => removeControlCharacters(e))\n .map((e) => e.replaceAll('\\r', '')) // remove carriage return\n .by((s) => {\n if (cli === 'codex') return s; // codex use cursor-move csi code insteadof \\n to move lines, so the output have no \\n at all, this hack prevents stuck on unended line\n return s.lines({ EOL: 'NONE' }); // other clis use ink, which is rerendering the block based on \\n lines\n })\n // .forEach((e) => yesLog`output|${e}`) // for debugging\n // Generic auto-response handler driven by CLI_CONFIGURES\n .forEach(async (e, i) => {\n const conf =\n CLI_CONFIGURES[cli as keyof typeof CLI_CONFIGURES] || null;\n if (!conf) return;\n\n // ready matcher: if matched, mark stdin ready\n if (conf.ready?.some((rx: RegExp) => e.match(rx))) {\n // await yesLog`ready |${e}`;\n if (cli === 'gemini' && i <= 80) return; // gemini initial noise, only after many lines\n stdinReady.ready();\n }\n\n // enter matchers: send Enter when any enter regex matches\n if (conf.enter?.some((rx: RegExp) => e.match(rx))) {\n // await yesLog`enter |${e}`;\n await sendEnter(300); // send Enter after 300ms idle wait\n return;\n }\n\n // fatal matchers: set isFatal flag when matched\n if (conf.fatal?.some((rx: RegExp) => e.match(rx))) {\n // await yesLog`fatal |${e}`;\n isFatal = true;\n await exitAgent();\n }\n })\n .run(),\n )\n .map((e) =>\n removeControlCharactersFromStdout ? removeControlCharacters(e) : e,\n )\n .to(fromWritable(process.stdout))\n .then(() => null); // run it immediately without await\n\n // wait for cli ready and send prompt if provided\n if (cli === 'codex') shell.write(`\\u001b[1;1R`); // send cursor position response when stdin is not tty\n if (prompt) await sendMessage(prompt);\n\n const exitCode = await pendingExitCode.promise; // wait for the shell to exit\n console.log(`[${cli}-yes] ${cli} exited with code ${exitCode}`);\n\n if (logFile) {\n verbose && console.log(`[${cli}-yes] Writing rendered logs to ${logFile}`);\n const logFilePath = path.resolve(logFile);\n await mkdir(path.dirname(logFilePath), { recursive: true }).catch(\n () => null,\n );\n await writeFile(logFilePath, terminalRender.render());\n }\n\n return { exitCode, logs: terminalRender.render() };\n\n async function sendEnter(waitms = 1000) {\n // wait for idle for a bit to let agent cli finish rendering\n const st = Date.now();\n await idleWaiter.wait(waitms);\n const et = Date.now();\n // process.stdout.write(`\\ridleWaiter.wait(${waitms}) took ${et - st}ms\\r`);\n // await yesLog`sendEn| idleWaiter.wait(${String(waitms)}) took ${String(et - st)}ms`;\n\n shell.write('\\r');\n }\n\n async function sendMessage(message: string) {\n await stdinReady.wait();\n // show in-place message: write msg and move cursor back start\n // await yesLog`send |${message}`;\n shell.write(message);\n nextStdout.unready();\n idleWaiter.ping(); // just sent a message, wait for echo\n await nextStdout.wait();\n await sendEnter();\n }\n\n async function exitAgent() {\n continueOnCrash = false;\n // send exit command to the shell, must sleep a bit to avoid claude treat it as pasted input\n await sendMessage('/exit');\n\n // wait for shell to exit or kill it with a timeout\n let exited = false;\n await Promise.race([\n pendingExitCode.promise.then(() => (exited = true)), // resolve when shell exits\n\n // if shell doesn't exit in 5 seconds, kill it\n new Promise<void>((resolve) =>\n setTimeout(() => {\n if (exited) return; // if shell already exited, do nothing\n shell.kill(); // kill the shell process if it doesn't exit in time\n resolve();\n }, 5000),\n ), // 5 seconds timeout\n ]);\n }\n\n function getTerminalDimensions() {\n if (!process.stdout.isTTY) return { cols: 80, rows: 30 }; // default size when not tty\n return {\n // TODO: enforce minimum cols/rows to avoid layout issues\n // cols: Math.max(process.stdout.columns, 80),\n cols: Math.min(Math.max(20, process.stdout.columns), 80),\n rows: process.stdout.rows,\n };\n }\n}\n\nexport { removeControlCharacters };\n\nfunction tryCatch<T, R>(fn: () => T, catchFn: (error: unknown) => R): T | R {\n try {\n return fn();\n } catch (error) {\n return catchFn(error);\n }\n}\n",
|
|
6
6
|
"/**\n * A utility class to wait for idle periods based on activity pings.\n *\n * @example\n * const idleWaiter = new IdleWaiter();\n *\n * // Somewhere in your code, when activity occurs:\n * idleWaiter.ping();\n *\n * // To wait for an idle period of 5 seconds:\n * await idleWaiter.wait(5000);\n * console.log('System has been idle for 5 seconds');\n */\nexport class IdleWaiter {\n lastActivityTime = Date.now();\n checkInterval = 100; // Default check interval in milliseconds\n\n constructor() {\n this.ping();\n }\n\n ping() {\n this.lastActivityTime = Date.now();\n return this;\n }\n\n async wait(ms: number) {\n while (this.lastActivityTime >= Date.now() - ms)\n await new Promise((resolve) => setTimeout(resolve, this.checkInterval));\n }\n}\n",
|
|
7
7
|
"export class ReadyManager {\n private isReady = false;\n private readyQueue: (() => void)[] = [];\n wait() {\n if (this.isReady) return;\n return new Promise<void>((resolve) => this.readyQueue.push(resolve));\n }\n unready() {\n this.isReady = false;\n }\n ready() {\n this.isReady = true;\n if (!this.readyQueue.length) return; // check len for performance\n this.readyQueue.splice(0).map((resolve) => resolve());\n }\n}\n",
|
|
8
8
|
"export function removeControlCharacters(str: string): string {\n // Matches control characters in the C0 and C1 ranges, including Delete (U+007F)\n return str.replace(\n /[\\u001b\\u009b][[()#;?]*(?:[0-9]{1,4}(?:;[0-9]{0,4})*)?[0-9A-ORZcf-nqry=><]/g,\n '',\n );\n}\n"
|
|
9
9
|
],
|
|
10
|
-
"mappings": ";;;;;;;;;;;;;;;;;;;;AAAA;AACA;AACA;AACA;AACA;AACA
|
|
11
|
-
"debugId": "
|
|
10
|
+
"mappings": "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",
|
|
11
|
+
"debugId": "D17BB3E3D1DC936764756E2164756E21",
|
|
12
12
|
"names": []
|
|
13
13
|
}
|
package/index.ts
CHANGED
|
@@ -9,6 +9,11 @@ import { IdleWaiter } from './idleWaiter';
|
|
|
9
9
|
import { ReadyManager } from './ReadyManager';
|
|
10
10
|
import { removeControlCharacters } from './removeControlCharacters';
|
|
11
11
|
|
|
12
|
+
// const yesLog = tsaComposer()(async function yesLog(msg: string) {
|
|
13
|
+
// // await rm('agent-yes.log').catch(() => null); // ignore error if file doesn't exist
|
|
14
|
+
// await appendFile("agent-yes.log", `${msg}\n`).catch(() => null);
|
|
15
|
+
// });
|
|
16
|
+
|
|
12
17
|
export const CLI_CONFIGURES: Record<
|
|
13
18
|
string,
|
|
14
19
|
{
|
|
@@ -47,7 +52,7 @@ export const CLI_CONFIGURES: Record<
|
|
|
47
52
|
ready: [/⏎ send/],
|
|
48
53
|
enter: [
|
|
49
54
|
/> 1. Yes, allow Codex to work in this folder/,
|
|
50
|
-
|
|
55
|
+
/> 1. Approve and run now/,
|
|
51
56
|
],
|
|
52
57
|
fatal: [/Error: The cursor position could not be read within/],
|
|
53
58
|
// add to codex --search by default when not provided by the user
|
|
@@ -121,10 +126,6 @@ export default async function claudeYes({
|
|
|
121
126
|
removeControlCharactersFromStdout?: boolean;
|
|
122
127
|
verbose?: boolean;
|
|
123
128
|
} = {}) {
|
|
124
|
-
await rm('agent-yes.log').catch(() => null); // ignore error if file doesn't exist
|
|
125
|
-
const yesLog = tsaComposer()(async function yesLog(msg: string) {
|
|
126
|
-
await appendFile('agent-yes.log', `${msg}\n`).catch(() => null);
|
|
127
|
-
});
|
|
128
129
|
const continueArgs = {
|
|
129
130
|
codex: 'resume --last'.split(' '),
|
|
130
131
|
claude: '--continue'.split(' '),
|
|
@@ -134,6 +135,7 @@ export default async function claudeYes({
|
|
|
134
135
|
process.stdin.setRawMode?.(true); // must be called any stdout/stdin usage
|
|
135
136
|
let isFatal = false; // when true, do not restart on crash, and exit agent
|
|
136
137
|
const stdinReady = new ReadyManager();
|
|
138
|
+
const nextStdout = new ReadyManager();
|
|
137
139
|
|
|
138
140
|
const shellOutputStream = new TransformStream<string, string>();
|
|
139
141
|
const outputWriter = shellOutputStream.writable.getWriter();
|
|
@@ -176,12 +178,14 @@ export default async function claudeYes({
|
|
|
176
178
|
// npm install -g @anthropic-ai/claude-code
|
|
177
179
|
|
|
178
180
|
async function onData(data: string) {
|
|
181
|
+
nextStdout.ready();
|
|
179
182
|
// append data to the buffer, so we can process it later
|
|
180
183
|
await outputWriter.write(data);
|
|
181
184
|
}
|
|
182
185
|
|
|
183
186
|
shell.onData(onData);
|
|
184
187
|
shell.onExit(function onExit({ exitCode }) {
|
|
188
|
+
nextStdout.ready();
|
|
185
189
|
stdinReady.unready(); // start buffer stdin
|
|
186
190
|
const agentCrashed = exitCode !== 0;
|
|
187
191
|
const continueArg = (continueArgs as Record<string, string[]>)[cli];
|
|
@@ -278,8 +282,11 @@ export default async function claudeYes({
|
|
|
278
282
|
e
|
|
279
283
|
.map((e) => removeControlCharacters(e))
|
|
280
284
|
.map((e) => e.replaceAll('\r', '')) // remove carriage return
|
|
281
|
-
.
|
|
282
|
-
|
|
285
|
+
.by((s) => {
|
|
286
|
+
if (cli === 'codex') return s; // codex use cursor-move csi code insteadof \n to move lines, so the output have no \n at all, this hack prevents stuck on unended line
|
|
287
|
+
return s.lines({ EOL: 'NONE' }); // other clis use ink, which is rerendering the block based on \n lines
|
|
288
|
+
})
|
|
289
|
+
// .forEach((e) => yesLog`output|${e}`) // for debugging
|
|
283
290
|
// Generic auto-response handler driven by CLI_CONFIGURES
|
|
284
291
|
.forEach(async (e, i) => {
|
|
285
292
|
const conf =
|
|
@@ -288,21 +295,21 @@ export default async function claudeYes({
|
|
|
288
295
|
|
|
289
296
|
// ready matcher: if matched, mark stdin ready
|
|
290
297
|
if (conf.ready?.some((rx: RegExp) => e.match(rx))) {
|
|
291
|
-
await yesLog`ready |${e}`;
|
|
298
|
+
// await yesLog`ready |${e}`;
|
|
292
299
|
if (cli === 'gemini' && i <= 80) return; // gemini initial noise, only after many lines
|
|
293
300
|
stdinReady.ready();
|
|
294
301
|
}
|
|
295
302
|
|
|
296
303
|
// enter matchers: send Enter when any enter regex matches
|
|
297
304
|
if (conf.enter?.some((rx: RegExp) => e.match(rx))) {
|
|
298
|
-
await yesLog`enter |${e}`;
|
|
305
|
+
// await yesLog`enter |${e}`;
|
|
299
306
|
await sendEnter(300); // send Enter after 300ms idle wait
|
|
300
307
|
return;
|
|
301
308
|
}
|
|
302
309
|
|
|
303
310
|
// fatal matchers: set isFatal flag when matched
|
|
304
311
|
if (conf.fatal?.some((rx: RegExp) => e.match(rx))) {
|
|
305
|
-
await yesLog`fatal |${e}`;
|
|
312
|
+
// await yesLog`fatal |${e}`;
|
|
306
313
|
isFatal = true;
|
|
307
314
|
await exitAgent();
|
|
308
315
|
}
|
|
@@ -339,7 +346,7 @@ export default async function claudeYes({
|
|
|
339
346
|
await idleWaiter.wait(waitms);
|
|
340
347
|
const et = Date.now();
|
|
341
348
|
// process.stdout.write(`\ridleWaiter.wait(${waitms}) took ${et - st}ms\r`);
|
|
342
|
-
await yesLog`sendEn| idleWaiter.wait(${String(waitms)}) took ${String(et - st)}ms`;
|
|
349
|
+
// await yesLog`sendEn| idleWaiter.wait(${String(waitms)}) took ${String(et - st)}ms`;
|
|
343
350
|
|
|
344
351
|
shell.write('\r');
|
|
345
352
|
}
|
|
@@ -347,9 +354,11 @@ export default async function claudeYes({
|
|
|
347
354
|
async function sendMessage(message: string) {
|
|
348
355
|
await stdinReady.wait();
|
|
349
356
|
// show in-place message: write msg and move cursor back start
|
|
350
|
-
await yesLog`send |${message}`;
|
|
357
|
+
// await yesLog`send |${message}`;
|
|
351
358
|
shell.write(message);
|
|
359
|
+
nextStdout.unready();
|
|
352
360
|
idleWaiter.ping(); // just sent a message, wait for echo
|
|
361
|
+
await nextStdout.wait();
|
|
353
362
|
await sendEnter();
|
|
354
363
|
}
|
|
355
364
|
|
package/package.json
CHANGED