claude-yes 1.72.3 → 1.73.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{SUPPORTED_CLIS-C-KnmE0Y.js → SUPPORTED_CLIS-DgHs-Q6i.js} +129 -28
- package/dist/cli.js +181 -32
- package/dist/index.js +1 -1
- package/dist/{tray-BQkynk6r.js → tray-CPpdxTV-.js} +1 -10
- package/package.json +8 -3
- package/ts/cli.ts +6 -6
- package/ts/index.ts +86 -99
- package/ts/parseCliArgs.spec.ts +88 -0
- package/ts/parseCliArgs.ts +45 -6
- package/ts/rustBinary.ts +68 -0
- package/ts/tray.spec.ts +0 -56
- package/ts/tray.ts +0 -12
- package/ts/versionChecker.spec.ts +73 -2
- package/ts/versionChecker.ts +118 -27
- package/ts/xterm-proxy.ts +130 -0
|
@@ -8,9 +8,9 @@ import { appendFile, mkdir, readFile, readdir, rename, unlink, writeFile } from
|
|
|
8
8
|
import path, { dirname, join } from "path";
|
|
9
9
|
import DIE from "phpdie";
|
|
10
10
|
import sflow from "sflow";
|
|
11
|
-
import
|
|
12
|
-
import { homedir } from "os";
|
|
11
|
+
import xterm from "@xterm/headless";
|
|
13
12
|
import winston from "winston";
|
|
13
|
+
import { homedir } from "os";
|
|
14
14
|
import { closeSync, constants, createReadStream, existsSync, fsyncSync, mkdirSync, openSync } from "fs";
|
|
15
15
|
import { createServer } from "net";
|
|
16
16
|
import { lock } from "proper-lockfile";
|
|
@@ -37,6 +37,109 @@ var __exportAll = (all, no_symbols) => {
|
|
|
37
37
|
return target;
|
|
38
38
|
};
|
|
39
39
|
|
|
40
|
+
//#endregion
|
|
41
|
+
//#region ts/xterm-proxy.ts
|
|
42
|
+
const { Terminal } = xterm;
|
|
43
|
+
/**
|
|
44
|
+
* XtermProxy wraps @xterm/headless to act as a full xterm terminal emulator
|
|
45
|
+
* between a PTY process and downstream consumers.
|
|
46
|
+
*
|
|
47
|
+
* It automatically responds to ALL terminal queries (DSR, DA, OSC, etc.)
|
|
48
|
+
* by piping xterm's onData responses back to the PTY — so the spawned
|
|
49
|
+
* process never blocks waiting for a terminal reply, even in non-TTY
|
|
50
|
+
* environments or when the real terminal is backgrounded.
|
|
51
|
+
*/
|
|
52
|
+
var XtermProxy = class {
|
|
53
|
+
term;
|
|
54
|
+
writeToPty;
|
|
55
|
+
readableController = null;
|
|
56
|
+
/** Downstream readable — passthrough of PTY output for sflow pipeline */
|
|
57
|
+
readable;
|
|
58
|
+
constructor(opts) {
|
|
59
|
+
const cols = opts.cols ?? 80;
|
|
60
|
+
const rows = opts.rows ?? 24;
|
|
61
|
+
this.writeToPty = opts.writeToPty;
|
|
62
|
+
this.term = new Terminal({
|
|
63
|
+
cols,
|
|
64
|
+
rows,
|
|
65
|
+
allowProposedApi: true,
|
|
66
|
+
scrollback: 1e4
|
|
67
|
+
});
|
|
68
|
+
this.term.onData((data) => {
|
|
69
|
+
logger.debug("xterm-proxy|onData response", data);
|
|
70
|
+
this.writeToPty(data);
|
|
71
|
+
});
|
|
72
|
+
this.readable = new ReadableStream({ start: (controller) => {
|
|
73
|
+
this.readableController = controller;
|
|
74
|
+
} });
|
|
75
|
+
}
|
|
76
|
+
/**
|
|
77
|
+
* Feed PTY output into the xterm emulator.
|
|
78
|
+
* - xterm processes escape sequences and updates internal state
|
|
79
|
+
* - Terminal queries (ESC[6n, ESC[c, etc.) trigger onData → writeToPty
|
|
80
|
+
* - Raw data is pushed to readable for downstream consumption
|
|
81
|
+
*/
|
|
82
|
+
write(data) {
|
|
83
|
+
this.term.write(data, () => {
|
|
84
|
+
try {
|
|
85
|
+
this.readableController?.enqueue(data);
|
|
86
|
+
} catch {}
|
|
87
|
+
});
|
|
88
|
+
}
|
|
89
|
+
/** Get cursor position from xterm's buffer state */
|
|
90
|
+
getCursorPosition() {
|
|
91
|
+
const buf = this.term.buffer.active;
|
|
92
|
+
return {
|
|
93
|
+
row: buf.cursorY,
|
|
94
|
+
col: buf.cursorX
|
|
95
|
+
};
|
|
96
|
+
}
|
|
97
|
+
/**
|
|
98
|
+
* Get the last N lines of rendered terminal content (plain text, no ANSI).
|
|
99
|
+
* Equivalent to terminal-render's tail(n).
|
|
100
|
+
*/
|
|
101
|
+
tail(n) {
|
|
102
|
+
const buf = this.term.buffer.active;
|
|
103
|
+
const totalLines = buf.length;
|
|
104
|
+
const startLine = Math.max(0, totalLines - n);
|
|
105
|
+
const lines = [];
|
|
106
|
+
for (let i = startLine; i < totalLines; i++) {
|
|
107
|
+
const line = buf.getLine(i);
|
|
108
|
+
lines.push(line ? line.translateToString(true) : "");
|
|
109
|
+
}
|
|
110
|
+
while (lines.length > 1 && lines[lines.length - 1] === "") lines.pop();
|
|
111
|
+
return lines.join("\n");
|
|
112
|
+
}
|
|
113
|
+
/**
|
|
114
|
+
* Render the full terminal buffer as plain text.
|
|
115
|
+
* Equivalent to terminal-render's render().
|
|
116
|
+
*/
|
|
117
|
+
render() {
|
|
118
|
+
const buf = this.term.buffer.active;
|
|
119
|
+
const lines = [];
|
|
120
|
+
for (let i = 0; i < buf.length; i++) {
|
|
121
|
+
const line = buf.getLine(i);
|
|
122
|
+
lines.push(line ? line.translateToString(true) : "");
|
|
123
|
+
}
|
|
124
|
+
while (lines.length > 1 && lines[lines.length - 1] === "") lines.pop();
|
|
125
|
+
return lines.join("\n");
|
|
126
|
+
}
|
|
127
|
+
/** Resize the virtual terminal */
|
|
128
|
+
resize(cols, rows) {
|
|
129
|
+
this.term.resize(cols, rows);
|
|
130
|
+
}
|
|
131
|
+
/** Clean up resources */
|
|
132
|
+
dispose() {
|
|
133
|
+
if (this.readableController) {
|
|
134
|
+
try {
|
|
135
|
+
this.readableController.close();
|
|
136
|
+
} catch {}
|
|
137
|
+
this.readableController = null;
|
|
138
|
+
}
|
|
139
|
+
this.term.dispose();
|
|
140
|
+
}
|
|
141
|
+
};
|
|
142
|
+
|
|
40
143
|
//#endregion
|
|
41
144
|
//#region ts/resume/codexSessionManager.ts
|
|
42
145
|
const getSessionsFile = () => process.env.CLI_YES_TEST_HOME ? path.join(process.env.CLI_YES_TEST_HOME, ".config", "agent-yes", "codex-sessions.json") : path.join(homedir(), ".config", "agent-yes", "codex-sessions.json");
|
|
@@ -815,7 +918,7 @@ function tryCatch(catchFn, fn) {
|
|
|
815
918
|
//#endregion
|
|
816
919
|
//#region package.json
|
|
817
920
|
var name = "agent-yes";
|
|
818
|
-
var version = "1.72.
|
|
921
|
+
var version = "1.72.4";
|
|
819
922
|
|
|
820
923
|
//#endregion
|
|
821
924
|
//#region ts/pty-fix.ts
|
|
@@ -1299,9 +1402,11 @@ async function agentYes({ cli, cliArgs = [], prompt, robust = true, cwd, env, ex
|
|
|
1299
1402
|
if (verbose) logger.debug(`[stdin] isTTY: ${process.stdin.isTTY}, setRawMode available: ${!!process.stdin.setRawMode}`);
|
|
1300
1403
|
process.stdin.setRawMode?.(true);
|
|
1301
1404
|
if (verbose) logger.debug(`[stdin] Raw mode set, isRaw: ${process.stdin.isRaw}`);
|
|
1302
|
-
|
|
1303
|
-
const
|
|
1304
|
-
|
|
1405
|
+
let shellWrite = () => {};
|
|
1406
|
+
const xtermProxy = new XtermProxy({
|
|
1407
|
+
...getTerminalDimensions(),
|
|
1408
|
+
writeToPty: (data) => shellWrite(data)
|
|
1409
|
+
});
|
|
1305
1410
|
logger.debug(`Using ${ptyPackage} for pseudo terminal management.`);
|
|
1306
1411
|
if (!!process.env.CLAUDE_PPID) logger.info(`[${cli}-yes] Running as sub-agent (CLAUDE_PPID=${process.env.CLAUDE_PPID})`);
|
|
1307
1412
|
const cliConf = CLIS_CONFIG[cli] || {};
|
|
@@ -1393,9 +1498,10 @@ async function agentYes({ cli, cliArgs = [], prompt, robust = true, cwd, env, ex
|
|
|
1393
1498
|
install,
|
|
1394
1499
|
ptyOptions
|
|
1395
1500
|
});
|
|
1501
|
+
shellWrite = (data) => shell.write(data);
|
|
1396
1502
|
function onData(data) {
|
|
1397
1503
|
const currentPid = shell.pid;
|
|
1398
|
-
|
|
1504
|
+
xtermProxy.write(data);
|
|
1399
1505
|
globalAgentRegistry.appendStdout(currentPid, data);
|
|
1400
1506
|
}
|
|
1401
1507
|
shell.onData(onData);
|
|
@@ -1479,6 +1585,7 @@ async function agentYes({ cli, cliArgs = [], prompt, robust = true, cwd, env, ex
|
|
|
1479
1585
|
env: ptyEnv
|
|
1480
1586
|
};
|
|
1481
1587
|
shell = pty.spawn(bin, args, restartPtyOptions);
|
|
1588
|
+
shellWrite = (data) => shell.write(data);
|
|
1482
1589
|
try {
|
|
1483
1590
|
await pidStore.registerProcess({
|
|
1484
1591
|
pid: shell.pid,
|
|
@@ -1561,6 +1668,7 @@ async function agentYes({ cli, cliArgs = [], prompt, robust = true, cwd, env, ex
|
|
|
1561
1668
|
env: ptyEnv
|
|
1562
1669
|
};
|
|
1563
1670
|
shell = pty.spawn(cli, restoreArgs, restorePtyOptions);
|
|
1671
|
+
shellWrite = (data) => shell.write(data);
|
|
1564
1672
|
try {
|
|
1565
1673
|
await pidStore.registerProcess({
|
|
1566
1674
|
pid: shell.pid,
|
|
@@ -1609,15 +1717,16 @@ async function agentYes({ cli, cliArgs = [], prompt, robust = true, cwd, env, ex
|
|
|
1609
1717
|
process.stdout.on("resize", () => {
|
|
1610
1718
|
const { cols, rows } = getTerminalDimensions();
|
|
1611
1719
|
shell.resize(cols, rows);
|
|
1720
|
+
xtermProxy.resize(cols, rows);
|
|
1612
1721
|
});
|
|
1613
1722
|
const isStillWorkingQ = () => {
|
|
1614
|
-
const rendered =
|
|
1723
|
+
const rendered = xtermProxy.tail(24).replace(/\s+/g, " ");
|
|
1615
1724
|
return conf.working?.some((rgx) => rgx.test(rendered));
|
|
1616
1725
|
};
|
|
1617
1726
|
let lastHeartbeatRendered = "";
|
|
1618
1727
|
const heartbeatInterval = setInterval(async () => {
|
|
1619
1728
|
try {
|
|
1620
|
-
const rendered = removeControlCharacters(
|
|
1729
|
+
const rendered = removeControlCharacters(xtermProxy.tail(12));
|
|
1621
1730
|
if (rendered === lastHeartbeatRendered) return;
|
|
1622
1731
|
lastHeartbeatRendered = rendered;
|
|
1623
1732
|
const lines = rendered.split("\n").filter((line) => line.trim());
|
|
@@ -1792,7 +1901,7 @@ async function agentYes({ cli, cliArgs = [], prompt, robust = true, cwd, env, ex
|
|
|
1792
1901
|
await ctx.stdinReady.wait();
|
|
1793
1902
|
shell.write(data);
|
|
1794
1903
|
} }),
|
|
1795
|
-
readable:
|
|
1904
|
+
readable: xtermProxy.readable
|
|
1796
1905
|
}).forEach(() => {
|
|
1797
1906
|
ctx.idleWaiter.ping();
|
|
1798
1907
|
pidStore.updateStatus(shell.pid, "active").catch(() => null);
|
|
@@ -1808,19 +1917,10 @@ async function agentYes({ cli, cliArgs = [], prompt, robust = true, cwd, env, ex
|
|
|
1808
1917
|
}).catch(() => f.run());
|
|
1809
1918
|
}).by(function consoleResponder(e) {
|
|
1810
1919
|
let lastRendered = "";
|
|
1811
|
-
return e.forEach((
|
|
1812
|
-
|
|
1813
|
-
|
|
1814
|
-
|
|
1815
|
-
return;
|
|
1816
|
-
}
|
|
1817
|
-
if (process.stdin.isTTY) return;
|
|
1818
|
-
if (!chunk.includes("\x1B[6n")) return;
|
|
1819
|
-
const { col, row } = terminalRender.getCursorPosition();
|
|
1820
|
-
shell.write(`\u001b[${row};${col}R`);
|
|
1821
|
-
logger.debug(`cursor|respond position: row=${String(row)}, col=${String(col)}`);
|
|
1822
|
-
}).forEach(async (line, lineIndex) => {
|
|
1823
|
-
if (terminalRender.tail(24) === lastRendered) return;
|
|
1920
|
+
return e.forEach(async (line, lineIndex) => {
|
|
1921
|
+
const rendered = xtermProxy.tail(24);
|
|
1922
|
+
if (rendered === lastRendered) return;
|
|
1923
|
+
lastRendered = rendered;
|
|
1824
1924
|
logger.debug(`stdout|${line}`);
|
|
1825
1925
|
if (conf.ready?.some((rx) => line.match(rx))) {
|
|
1826
1926
|
logger.debug(`ready |${line}`);
|
|
@@ -1854,15 +1954,16 @@ async function agentYes({ cli, cliArgs = [], prompt, robust = true, cwd, env, ex
|
|
|
1854
1954
|
}
|
|
1855
1955
|
});
|
|
1856
1956
|
}).by((s) => removeControlCharactersFromStdout ? s.map((e) => removeControlCharacters(e)) : s).by(createTerminatorStream(pendingExitCode.promise)).to(fromWritable(process.stdout));
|
|
1857
|
-
await saveLogFile(ctx.logPaths.logPath,
|
|
1957
|
+
await saveLogFile(ctx.logPaths.logPath, xtermProxy.render());
|
|
1858
1958
|
const exitCode = await pendingExitCode.promise;
|
|
1859
1959
|
logger.info(`[${cli}-yes] ${cli} exited with code ${exitCode}`);
|
|
1860
1960
|
await pidStore.close();
|
|
1861
|
-
|
|
1862
|
-
|
|
1961
|
+
const finalRender = xtermProxy.render();
|
|
1962
|
+
xtermProxy.dispose();
|
|
1963
|
+
await saveDeprecatedLogFile(logFile, finalRender, verbose);
|
|
1863
1964
|
return {
|
|
1864
1965
|
exitCode,
|
|
1865
|
-
logs:
|
|
1966
|
+
logs: finalRender
|
|
1866
1967
|
};
|
|
1867
1968
|
async function exitAgent() {
|
|
1868
1969
|
ctx.robust = false;
|
|
@@ -1895,4 +1996,4 @@ const SUPPORTED_CLIS = Object.keys(CLIS_CONFIG);
|
|
|
1895
1996
|
|
|
1896
1997
|
//#endregion
|
|
1897
1998
|
export { AgentContext as a, PidStore as c, config as i, removeControlCharacters as l, CLIS_CONFIG as n, name as o, agentYes as r, version as s, SUPPORTED_CLIS as t };
|
|
1898
|
-
//# sourceMappingURL=SUPPORTED_CLIS-
|
|
1999
|
+
//# sourceMappingURL=SUPPORTED_CLIS-DgHs-Q6i.js.map
|
package/dist/cli.js
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
#!/usr/bin/env bun
|
|
2
|
-
import { c as PidStore, o as name, s as version, t as SUPPORTED_CLIS } from "./SUPPORTED_CLIS-
|
|
2
|
+
import { c as PidStore, o as name, s as version, t as SUPPORTED_CLIS } from "./SUPPORTED_CLIS-DgHs-Q6i.js";
|
|
3
3
|
import { t as logger } from "./logger-CX77vJDA.js";
|
|
4
4
|
import { argv } from "process";
|
|
5
|
-
import { spawn } from "child_process";
|
|
5
|
+
import { execFileSync, spawn } from "child_process";
|
|
6
6
|
import ms from "ms";
|
|
7
7
|
import yargs from "yargs";
|
|
8
8
|
import { hideBin } from "yargs/helpers";
|
|
@@ -10,7 +10,7 @@ import { execaCommand } from "execa";
|
|
|
10
10
|
import { chmod, copyFile, mkdir, readFile, writeFile } from "fs/promises";
|
|
11
11
|
import path from "path";
|
|
12
12
|
import { homedir } from "os";
|
|
13
|
-
import { existsSync, mkdirSync, unlinkSync } from "fs";
|
|
13
|
+
import { existsSync, lstatSync, mkdirSync, readlinkSync, unlinkSync } from "fs";
|
|
14
14
|
|
|
15
15
|
//#region ts/parseCliArgs.ts
|
|
16
16
|
/**
|
|
@@ -156,26 +156,53 @@ function parseCliArgs(argv) {
|
|
|
156
156
|
if (key === "continue") yargsConsumed.add("-c");
|
|
157
157
|
}
|
|
158
158
|
});
|
|
159
|
+
const positionalPromptWords = [];
|
|
159
160
|
const cliArgsForSpawn = (() => {
|
|
160
|
-
if (parsedArgv._[0] && !cliName)
|
|
161
|
-
|
|
161
|
+
if (parsedArgv._[0] && !cliName) {
|
|
162
|
+
const allAfterCli = rawArgs.slice((cliArgIndex ?? 0) + 1, dashIndex ?? void 0);
|
|
163
|
+
const result = [];
|
|
164
|
+
for (let i = 0; i < allAfterCli.length; i++) {
|
|
165
|
+
const arg = allAfterCli[i];
|
|
166
|
+
if (arg.startsWith("-")) {
|
|
167
|
+
result.push(arg);
|
|
168
|
+
if (!arg.includes("=") && i + 1 < allAfterCli.length) {
|
|
169
|
+
const nextArg = allAfterCli[i + 1];
|
|
170
|
+
if (nextArg && !nextArg.startsWith("-")) {
|
|
171
|
+
result.push(nextArg);
|
|
172
|
+
i++;
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
} else positionalPromptWords.push(arg);
|
|
176
|
+
}
|
|
177
|
+
return result;
|
|
178
|
+
} else if (cliName) {
|
|
162
179
|
const result = [];
|
|
163
180
|
const argsToCheck = rawArgs.slice(0, dashIndex ?? void 0);
|
|
164
181
|
for (let i = 0; i < argsToCheck.length; i++) {
|
|
165
182
|
const arg = argsToCheck[i];
|
|
166
183
|
if (!arg) continue;
|
|
167
184
|
const [flag] = arg.split("=");
|
|
168
|
-
if (flag && yargsConsumed.has(flag)) {
|
|
185
|
+
if (flag && yargsConsumed.has(flag) || flag?.startsWith("--no-") && yargsConsumed.has(`--${flag.slice(5)}`)) {
|
|
169
186
|
if (!arg.includes("=") && i + 1 < argsToCheck.length) {
|
|
170
187
|
const nextArg = argsToCheck[i + 1];
|
|
171
188
|
if (nextArg && !nextArg.startsWith("-")) i++;
|
|
172
189
|
}
|
|
173
|
-
} else
|
|
190
|
+
} else if (arg.startsWith("-")) {
|
|
191
|
+
result.push(arg);
|
|
192
|
+
if (!arg.includes("=") && i + 1 < argsToCheck.length) {
|
|
193
|
+
const nextArg = argsToCheck[i + 1];
|
|
194
|
+
if (nextArg && !nextArg.startsWith("-")) {
|
|
195
|
+
result.push(nextArg);
|
|
196
|
+
i++;
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
} else positionalPromptWords.push(arg);
|
|
174
200
|
}
|
|
175
201
|
return result;
|
|
176
202
|
}
|
|
177
203
|
return [];
|
|
178
204
|
})();
|
|
205
|
+
const positionalPrompt = positionalPromptWords.join(" ") || void 0;
|
|
179
206
|
const dashPrompt = dashIndex === void 0 ? void 0 : rawArgs.slice(dashIndex + 1).join(" ");
|
|
180
207
|
if (parsedArgv.exitOnIdle !== void 0) console.warn("\x1B[33m⚠ Warning: --exit-on-idle and -e are deprecated. Please use --timeout instead.\x1B[0m");
|
|
181
208
|
return {
|
|
@@ -183,7 +210,11 @@ function parseCliArgs(argv) {
|
|
|
183
210
|
env: process.env,
|
|
184
211
|
cli: cliName || parsedArgv.cli || (dashIndex !== 0 ? parsedArgv._[0]?.toString()?.replace?.(/-yes$/, "") : void 0),
|
|
185
212
|
cliArgs: [...cliArgsForSpawn, ...parsedArgv.yes ? ["--dangerously-skip-permissions"] : []],
|
|
186
|
-
prompt: [
|
|
213
|
+
prompt: [
|
|
214
|
+
parsedArgv.prompt,
|
|
215
|
+
positionalPrompt,
|
|
216
|
+
dashPrompt
|
|
217
|
+
].filter(Boolean).join(" ") || void 0,
|
|
187
218
|
install: parsedArgv.install,
|
|
188
219
|
exitOnIdle: Number((parsedArgv.timeout || parsedArgv.idle || parsedArgv.exitOnIdle)?.replace(/.*/, (e) => String(ms(e))) || 0),
|
|
189
220
|
queue: parsedArgv.queue,
|
|
@@ -225,44 +256,77 @@ async function writeUpdateCache(data) {
|
|
|
225
256
|
await writeFile(CACHE_FILE, JSON.stringify(data));
|
|
226
257
|
}
|
|
227
258
|
function detectPackageManager() {
|
|
228
|
-
if (process.env.BUN_INSTALL || process.env.npm_execpath?.includes("bun")) return "bun";
|
|
259
|
+
if (process.env.BUN_INSTALL || process.execPath?.includes("bun") || process.env.npm_execpath?.includes("bun")) return "bun";
|
|
229
260
|
return "npm";
|
|
230
261
|
}
|
|
231
262
|
/**
|
|
232
|
-
* Check for updates
|
|
263
|
+
* Check for updates, auto-install if newer version is available, and re-exec
|
|
264
|
+
* so the current invocation always runs the latest code.
|
|
265
|
+
*
|
|
233
266
|
* Uses a 1-hour TTL cache to avoid hitting the registry on every run.
|
|
234
267
|
* All errors are swallowed — network issues must never break the tool.
|
|
235
268
|
* Set AGENT_YES_NO_UPDATE=1 to opt out.
|
|
269
|
+
*
|
|
270
|
+
* The AGENT_YES_UPDATED env var prevents infinite re-exec loops:
|
|
271
|
+
* after updating we re-exec with AGENT_YES_UPDATED=<version> so the
|
|
272
|
+
* new process skips the update check.
|
|
236
273
|
*/
|
|
237
274
|
async function checkAndAutoUpdate() {
|
|
238
275
|
if (process.env.AGENT_YES_NO_UPDATE) return;
|
|
276
|
+
if (process.env.AGENT_YES_UPDATED) return;
|
|
277
|
+
if (import.meta.url.startsWith("file://") && !import.meta.url.includes("node_modules")) {
|
|
278
|
+
const scriptDir = path.dirname(new URL(import.meta.url).pathname);
|
|
279
|
+
const repoRoot = path.resolve(scriptDir, "..");
|
|
280
|
+
if (existsSync(path.join(repoRoot, ".git"))) return;
|
|
281
|
+
}
|
|
239
282
|
try {
|
|
283
|
+
let latestVersion;
|
|
240
284
|
const cache = await readUpdateCache();
|
|
241
|
-
if (cache && Date.now() - cache.checkedAt < TTL_MS)
|
|
242
|
-
|
|
243
|
-
|
|
285
|
+
if (cache && Date.now() - cache.checkedAt < TTL_MS) latestVersion = cache.latestVersion;
|
|
286
|
+
else {
|
|
287
|
+
const fetched = await fetchLatestVersion();
|
|
288
|
+
if (!fetched) return;
|
|
289
|
+
latestVersion = fetched;
|
|
290
|
+
await writeUpdateCache({
|
|
291
|
+
checkedAt: Date.now(),
|
|
292
|
+
latestVersion
|
|
293
|
+
});
|
|
294
|
+
}
|
|
295
|
+
if (compareVersions(version, latestVersion) < 0) {
|
|
296
|
+
if (await runInstall(latestVersion)) reExec(latestVersion);
|
|
244
297
|
}
|
|
245
|
-
const latestVersion = await fetchLatestVersion();
|
|
246
|
-
if (!latestVersion) return;
|
|
247
|
-
await writeUpdateCache({
|
|
248
|
-
checkedAt: Date.now(),
|
|
249
|
-
latestVersion
|
|
250
|
-
});
|
|
251
|
-
if (compareVersions(version, latestVersion) < 0) await runInstall(latestVersion);
|
|
252
298
|
} catch {}
|
|
253
299
|
}
|
|
254
300
|
async function runInstall(latestVersion) {
|
|
255
|
-
const
|
|
301
|
+
const installCmd = detectPackageManager() === "bun" ? `bun add -g agent-yes@${latestVersion}` : `npm install -g agent-yes@${latestVersion}`;
|
|
256
302
|
process.stderr.write(`\x1b[33m[agent-yes] Updating ${version} → ${latestVersion}…\x1b[0m\n`);
|
|
257
303
|
try {
|
|
258
|
-
await execaCommand(
|
|
259
|
-
await writeUpdateCache({
|
|
260
|
-
checkedAt: 0,
|
|
261
|
-
latestVersion
|
|
262
|
-
});
|
|
304
|
+
await execaCommand(installCmd, { stdio: "inherit" });
|
|
263
305
|
process.stderr.write(`\x1b[32m[agent-yes] Updated to ${latestVersion}\x1b[0m\n`);
|
|
306
|
+
return true;
|
|
264
307
|
} catch {
|
|
265
|
-
process.stderr.write(`\x1b[31m[agent-yes] Auto-update failed. Run: ${
|
|
308
|
+
process.stderr.write(`\x1b[31m[agent-yes] Auto-update failed. Run: ${installCmd}\x1b[0m\n`);
|
|
309
|
+
return false;
|
|
310
|
+
}
|
|
311
|
+
}
|
|
312
|
+
/**
|
|
313
|
+
* Re-exec the current process so the newly installed version runs.
|
|
314
|
+
* Sets AGENT_YES_UPDATED=<version> to prevent an infinite loop.
|
|
315
|
+
*/
|
|
316
|
+
function reExec(version) {
|
|
317
|
+
const [bin, ...args] = process.argv;
|
|
318
|
+
process.stderr.write(`\x1b[36m[agent-yes] Restarting with v${version}…\x1b[0m\n`);
|
|
319
|
+
try {
|
|
320
|
+
execFileSync(bin, args, {
|
|
321
|
+
stdio: "inherit",
|
|
322
|
+
env: {
|
|
323
|
+
...process.env,
|
|
324
|
+
AGENT_YES_UPDATED: version
|
|
325
|
+
}
|
|
326
|
+
});
|
|
327
|
+
process.exit(0);
|
|
328
|
+
} catch (err) {
|
|
329
|
+
process.exit(err.status ?? 1);
|
|
266
330
|
}
|
|
267
331
|
}
|
|
268
332
|
/**
|
|
@@ -293,10 +357,47 @@ function compareVersions(v1, v2) {
|
|
|
293
357
|
return 0;
|
|
294
358
|
}
|
|
295
359
|
/**
|
|
360
|
+
* Detect how agent-yes was installed.
|
|
361
|
+
* Returns a short label: "git", "bun link", "bun", "npm", "npx", or "unknown"
|
|
362
|
+
*/
|
|
363
|
+
function detectInstallMethod() {
|
|
364
|
+
try {
|
|
365
|
+
const scriptDir = path.dirname(new URL(import.meta.url).pathname);
|
|
366
|
+
if (!scriptDir.includes("node_modules")) {
|
|
367
|
+
const repoRoot = path.resolve(scriptDir, "..");
|
|
368
|
+
if (existsSync(path.join(repoRoot, ".git"))) return "git";
|
|
369
|
+
return "source";
|
|
370
|
+
}
|
|
371
|
+
const nodeModulesEntry = scriptDir.replace(/\/dist$/, "");
|
|
372
|
+
try {
|
|
373
|
+
if (lstatSync(nodeModulesEntry).isSymbolicLink()) {
|
|
374
|
+
const target = readlinkSync(nodeModulesEntry);
|
|
375
|
+
const resolvedTarget = path.resolve(path.dirname(nodeModulesEntry), target);
|
|
376
|
+
if (existsSync(path.join(resolvedTarget, ".git"))) return "bun link (git)";
|
|
377
|
+
return "bun link";
|
|
378
|
+
}
|
|
379
|
+
} catch {}
|
|
380
|
+
if (scriptDir.includes(".bun/")) return "bun";
|
|
381
|
+
if (scriptDir.includes(".npm/")) return "npx";
|
|
382
|
+
if (process.env.npm_execpath?.includes("bun")) return "bun";
|
|
383
|
+
if (process.env.npm_config_user_agent?.startsWith("bun")) return "bun";
|
|
384
|
+
if (process.env.npm_config_user_agent?.startsWith("npm")) return "npm";
|
|
385
|
+
return "npm";
|
|
386
|
+
} catch {
|
|
387
|
+
return "unknown";
|
|
388
|
+
}
|
|
389
|
+
}
|
|
390
|
+
/**
|
|
391
|
+
* Format version string with install method
|
|
392
|
+
*/
|
|
393
|
+
function versionString() {
|
|
394
|
+
return `agent-yes v${version} (${detectInstallMethod()})`;
|
|
395
|
+
}
|
|
396
|
+
/**
|
|
296
397
|
* Display version information with async latest version check
|
|
297
398
|
*/
|
|
298
399
|
async function displayVersion() {
|
|
299
|
-
console.log(
|
|
400
|
+
console.log(versionString());
|
|
300
401
|
const latestVersion = await fetchLatestVersion();
|
|
301
402
|
if (latestVersion) {
|
|
302
403
|
const comparison = compareVersions(version, latestVersion);
|
|
@@ -438,6 +539,53 @@ async function downloadBinary(verbose = false) {
|
|
|
438
539
|
return binaryPath;
|
|
439
540
|
}
|
|
440
541
|
/**
|
|
542
|
+
* Get the version of a Rust binary by running it with --version
|
|
543
|
+
*/
|
|
544
|
+
function getRustBinaryVersion(binaryPath) {
|
|
545
|
+
try {
|
|
546
|
+
const match = execFileSync(binaryPath, ["--version"], {
|
|
547
|
+
timeout: 5e3,
|
|
548
|
+
encoding: "utf8",
|
|
549
|
+
stdio: [
|
|
550
|
+
"ignore",
|
|
551
|
+
"pipe",
|
|
552
|
+
"ignore"
|
|
553
|
+
]
|
|
554
|
+
}).match(/(\d+\.\d+\.\d+)/);
|
|
555
|
+
return match ? match[1] : null;
|
|
556
|
+
} catch {
|
|
557
|
+
return null;
|
|
558
|
+
}
|
|
559
|
+
}
|
|
560
|
+
/**
|
|
561
|
+
* Check if a binary path is inside a git repo (dev build), and rebuild if outdated.
|
|
562
|
+
* Returns the same path if up-to-date or rebuilt, undefined if rebuild failed.
|
|
563
|
+
*/
|
|
564
|
+
function autoRebuildIfOutdated(binaryPath, verbose) {
|
|
565
|
+
if (!binaryPath.includes("/target/release") && !binaryPath.includes("/target/debug")) return true;
|
|
566
|
+
const binaryVersion = getRustBinaryVersion(binaryPath);
|
|
567
|
+
if (verbose) console.log(`[rust] Binary version: ${binaryVersion}, package version: ${version}`);
|
|
568
|
+
if (binaryVersion === version) return true;
|
|
569
|
+
const rsDir = binaryPath.replace(/\/target\/(release|debug)\/agent-yes.*$/, "");
|
|
570
|
+
if (!existsSync(path.join(rsDir, "Cargo.toml"))) {
|
|
571
|
+
if (verbose) console.log(`[rust] Cannot find Cargo.toml at ${rsDir}, skipping rebuild`);
|
|
572
|
+
return true;
|
|
573
|
+
}
|
|
574
|
+
process.stderr.write(`\x1b[33m[rust] Binary outdated (${binaryVersion ?? "unknown"} → ${version}), rebuilding…\x1b[0m\n`);
|
|
575
|
+
try {
|
|
576
|
+
execFileSync("cargo", ["build", ...binaryPath.includes("/target/release") ? ["--release"] : []], {
|
|
577
|
+
cwd: rsDir,
|
|
578
|
+
stdio: "inherit",
|
|
579
|
+
timeout: 3e5
|
|
580
|
+
});
|
|
581
|
+
process.stderr.write(`\x1b[32m[rust] Rebuild complete\x1b[0m\n`);
|
|
582
|
+
return true;
|
|
583
|
+
} catch {
|
|
584
|
+
process.stderr.write(`\x1b[31m[rust] Auto-rebuild failed, using outdated binary\x1b[0m\n`);
|
|
585
|
+
return true;
|
|
586
|
+
}
|
|
587
|
+
}
|
|
588
|
+
/**
|
|
441
589
|
* Get or download the Rust binary
|
|
442
590
|
*/
|
|
443
591
|
async function getRustBinary(options = {}) {
|
|
@@ -446,6 +594,7 @@ async function getRustBinary(options = {}) {
|
|
|
446
594
|
const existing = findRustBinary(verbose);
|
|
447
595
|
if (existing) {
|
|
448
596
|
if (verbose) console.log(`[rust] Using existing binary: ${existing}`);
|
|
597
|
+
autoRebuildIfOutdated(existing, verbose);
|
|
449
598
|
return existing;
|
|
450
599
|
}
|
|
451
600
|
}
|
|
@@ -478,15 +627,16 @@ function buildRustArgs(argv, cliFromScript, supportedClis) {
|
|
|
478
627
|
|
|
479
628
|
//#endregion
|
|
480
629
|
//#region ts/cli.ts
|
|
481
|
-
|
|
630
|
+
await checkAndAutoUpdate();
|
|
631
|
+
logger.info(versionString());
|
|
482
632
|
const config = parseCliArgs(process.argv);
|
|
483
633
|
if (config.tray) {
|
|
484
|
-
const { startTray } = await import("./tray-
|
|
634
|
+
const { startTray } = await import("./tray-CPpdxTV-.js");
|
|
485
635
|
await startTray();
|
|
486
636
|
await new Promise(() => {});
|
|
487
637
|
}
|
|
488
638
|
{
|
|
489
|
-
const { ensureTray } = await import("./tray-
|
|
639
|
+
const { ensureTray } = await import("./tray-CPpdxTV-.js");
|
|
490
640
|
ensureTray();
|
|
491
641
|
}
|
|
492
642
|
if (config.useRust) {
|
|
@@ -581,7 +731,6 @@ const { exitCode } = await cliYes({
|
|
|
581
731
|
...config,
|
|
582
732
|
autoYes: config.autoYes
|
|
583
733
|
});
|
|
584
|
-
await updateCheckPromise;
|
|
585
734
|
console.log("exiting process");
|
|
586
735
|
process.exit(exitCode ?? 1);
|
|
587
736
|
|
package/dist/index.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { a as AgentContext, i as config, l as removeControlCharacters, n as CLIS_CONFIG, r as agentYes } from "./SUPPORTED_CLIS-
|
|
1
|
+
import { a as AgentContext, i as config, l as removeControlCharacters, n as CLIS_CONFIG, r as agentYes } from "./SUPPORTED_CLIS-DgHs-Q6i.js";
|
|
2
2
|
import "./logger-CX77vJDA.js";
|
|
3
3
|
|
|
4
4
|
export { AgentContext, CLIS_CONFIG, config, agentYes as default, removeControlCharacters };
|
|
@@ -6,7 +6,6 @@ import { existsSync } from "fs";
|
|
|
6
6
|
|
|
7
7
|
//#region ts/tray.ts
|
|
8
8
|
const POLL_INTERVAL = 2e3;
|
|
9
|
-
const IDLE_EXIT_POLLS = 15;
|
|
10
9
|
const getTrayDir = () => path.join(process.env.CLAUDE_YES_HOME || homedir(), ".claude-yes");
|
|
11
10
|
const getTrayPidFile = () => path.join(getTrayDir(), "tray.pid");
|
|
12
11
|
const ICON_BASE64 = "iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAjklEQVQ4T2NkoBAwUqifgWoGMDIyNjAyMv5nYGBYQMgVjMgCQM0LGBkZHYDYAY8BDUBxByB2wGcAyAUOQOwAxPYMDAyOeCzAbwBIMyMjowNQsz0ely8ACjng8wJeA0CaGRgY7IHYAZ8hQHEHfF7AawBYMwODPZABRHsBpwEgzUDN9kDsgM8lQHEHfC4gJhwAAM3hMBGq3cNNAAAAAElFTkSuQmCC";
|
|
@@ -153,17 +152,9 @@ async function startTray() {
|
|
|
153
152
|
if (action.item.title === "Quit Tray") cleanup();
|
|
154
153
|
});
|
|
155
154
|
let lastCount = count;
|
|
156
|
-
let idlePolls = count === 0 ? 1 : 0;
|
|
157
155
|
intervalId = setInterval(async () => {
|
|
158
156
|
try {
|
|
159
157
|
const { count: newCount, tasks: newTasks } = await getRunningAgentCount();
|
|
160
|
-
if (newCount === 0) {
|
|
161
|
-
idlePolls++;
|
|
162
|
-
if (idlePolls >= IDLE_EXIT_POLLS) {
|
|
163
|
-
cleanup();
|
|
164
|
-
return;
|
|
165
|
-
}
|
|
166
|
-
} else idlePolls = 0;
|
|
167
158
|
if (newCount !== lastCount) {
|
|
168
159
|
lastCount = newCount;
|
|
169
160
|
systray.sendAction({
|
|
@@ -184,4 +175,4 @@ async function startTray() {
|
|
|
184
175
|
|
|
185
176
|
//#endregion
|
|
186
177
|
export { ensureTray, startTray };
|
|
187
|
-
//# sourceMappingURL=tray-
|
|
178
|
+
//# sourceMappingURL=tray-CPpdxTV-.js.map
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "claude-yes",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.73.0",
|
|
4
4
|
"description": "A wrapper tool that automates interactions with various AI CLI tools by automatically handling common prompts and responses.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"ai",
|
|
@@ -81,10 +81,12 @@
|
|
|
81
81
|
"release": "standard-version && npm publish",
|
|
82
82
|
"release:beta": "standard-version && npm publish --tag beta",
|
|
83
83
|
"test": "vitest run",
|
|
84
|
-
"test:coverage": "vitest run --coverage"
|
|
84
|
+
"test:coverage": "vitest run --coverage",
|
|
85
|
+
"test:ui": "vitest run --config tests/ui-test/vitest.config.ts"
|
|
85
86
|
},
|
|
86
87
|
"dependencies": {
|
|
87
88
|
"@snomiao/bun-pty": "^0.3.4",
|
|
89
|
+
"@xterm/headless": "^6.0.0",
|
|
88
90
|
"bun-pty": "^0.4.8",
|
|
89
91
|
"execa": "^9.6.1",
|
|
90
92
|
"from-node-stream": "^0.2.0",
|
|
@@ -92,12 +94,12 @@
|
|
|
92
94
|
"phpdie": "^1.7.0",
|
|
93
95
|
"proper-lockfile": "^4.1.2",
|
|
94
96
|
"sflow": "^1.27.0",
|
|
95
|
-
"terminal-render": "^1.5.1",
|
|
96
97
|
"winston": "^3.19.0",
|
|
97
98
|
"yaml": "^2.8.2",
|
|
98
99
|
"yargs": "^18.0.0"
|
|
99
100
|
},
|
|
100
101
|
"devDependencies": {
|
|
102
|
+
"@google/generative-ai": "^0.24.1",
|
|
101
103
|
"@semantic-release/exec": "^7.1.0",
|
|
102
104
|
"@semantic-release/git": "^10.0.1",
|
|
103
105
|
"@types/bun": "^1.3.6",
|
|
@@ -105,6 +107,7 @@
|
|
|
105
107
|
"@types/ms": "^2.1.0",
|
|
106
108
|
"@types/node": "^25.0.10",
|
|
107
109
|
"@types/proper-lockfile": "^4.1.4",
|
|
110
|
+
"@types/ws": "^8.18.1",
|
|
108
111
|
"@types/yargs": "^17.0.35",
|
|
109
112
|
"@typescript/native-preview": "^7.0.0-dev.20260124.1",
|
|
110
113
|
"@vitest/coverage-v8": "4.1.0",
|
|
@@ -114,11 +117,13 @@
|
|
|
114
117
|
"oxfmt": "^0.26.0",
|
|
115
118
|
"oxlint": "^1.41.0",
|
|
116
119
|
"patch-package": "^8.0.1",
|
|
120
|
+
"playwright": "^1.58.2",
|
|
117
121
|
"rambda": "^11.0.1",
|
|
118
122
|
"semantic-release": "^25.0.2",
|
|
119
123
|
"standard-version": "^9.5.0",
|
|
120
124
|
"tsdown": "^0.20.3",
|
|
121
125
|
"vitest": "4.1.0",
|
|
126
|
+
"ws": "^8.20.0",
|
|
122
127
|
"zod": "^3.23.0"
|
|
123
128
|
},
|
|
124
129
|
"peerDependencies": {
|