agent-yes 1.121.0 → 1.122.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/default.config.yaml +27 -4
- package/dist/SUPPORTED_CLIS-BVqe3k7F.js +8 -0
- package/dist/{SUPPORTED_CLIS-O57LGUEG.js → SUPPORTED_CLIS-DFYbm2uk.js} +2 -2
- package/dist/{agent-yes.config-kmtJKJHk.js → agent-yes.config-z-IPzH5U.js} +3 -2
- package/dist/cli.js +5 -5
- package/dist/index.js +2 -2
- package/dist/reaper-Dj8R7ltI.js +64 -0
- package/dist/reaper-HqcUms2d.js +3 -0
- package/dist/{remotes-DavR4Hca.js → remotes-CpGcTr7A.js} +1 -1
- package/dist/{remotes-BufkGk0e.js → remotes-D2fqaRU8.js} +1 -1
- package/dist/schedule-CJaNc82S.js +144 -0
- package/dist/{serve-D2czcYNC.js → serve-VczpuYDk.js} +121 -26
- package/dist/{setup-f1FIFcZm.js → setup-DveWqmSR.js} +5 -42
- package/dist/{share-B6QVr5D1.js → share-ClsUSd_0.js} +69 -9
- package/dist/{subcommands-CzpZQHO6.js → subcommands-CmNGbbIA.js} +15 -6
- package/dist/{subcommands-DobVXouH.js → subcommands-CzZ4uBIa.js} +2 -2
- package/dist/{tray-B8_rx1iu.js → tray-DjCIyakK.js} +22 -10
- package/dist/{ts-D91dm1E0.js → ts-7kSDmCpQ.js} +76 -7
- package/dist/{versionChecker-CAtpgnoQ.js → versionChecker-B5vxV_hH.js} +13 -19
- package/dist/workspaceConfig-XP2NEWmV.js +56 -0
- package/lab/ui/index.html +63 -32
- package/package.json +1 -1
- package/ts/autoRetry.spec.ts +19 -0
- package/ts/autoRetry.ts +16 -0
- package/ts/configShared.ts +4 -0
- package/ts/index.ts +102 -0
- package/ts/oxmgrService.ts +36 -0
- package/ts/pty.ts +19 -1
- package/ts/reaper.spec.ts +45 -0
- package/ts/reaper.ts +77 -0
- package/ts/schedule.spec.ts +30 -0
- package/ts/schedule.ts +161 -0
- package/ts/serve.ts +174 -19
- package/ts/share.ts +81 -10
- package/ts/subcommands.ts +0 -0
- package/ts/tray.spec.ts +9 -1
- package/ts/tray.ts +30 -14
- package/ts/versionChecker.ts +24 -27
- package/dist/SUPPORTED_CLIS-CegJgoEf.js +0 -8
|
@@ -178,8 +178,39 @@ function randomHex(n) {
|
|
|
178
178
|
//#endregion
|
|
179
179
|
//#region ts/share.ts
|
|
180
180
|
const SUB = "ay-signal-1";
|
|
181
|
-
const ICE = [{ urls: "stun:stun.l.google.com:19302" }];
|
|
182
181
|
const DEFAULT_SIGHOST = "s.agent-yes.com";
|
|
182
|
+
const HOST_HEARTBEAT_MS = 2e4;
|
|
183
|
+
const STUN = [{ urls: "stun:stun.l.google.com:19302" }];
|
|
184
|
+
let iceCache = null;
|
|
185
|
+
async function getIceServers() {
|
|
186
|
+
const keyId = process.env.CF_TURN_KEY_ID;
|
|
187
|
+
const apiToken = process.env.CF_TURN_API_TOKEN;
|
|
188
|
+
if (!keyId || !apiToken) return STUN;
|
|
189
|
+
if (iceCache && iceCache.exp > Date.now()) return iceCache.servers;
|
|
190
|
+
const ttl = 3600;
|
|
191
|
+
try {
|
|
192
|
+
const r = await fetch(`https://rtc.live.cloudflare.com/v1/turn/keys/${keyId}/credentials/generate-ice-servers`, {
|
|
193
|
+
method: "POST",
|
|
194
|
+
headers: {
|
|
195
|
+
Authorization: `Bearer ${apiToken}`,
|
|
196
|
+
"Content-Type": "application/json"
|
|
197
|
+
},
|
|
198
|
+
body: JSON.stringify({ ttl }),
|
|
199
|
+
signal: AbortSignal.timeout(5e3)
|
|
200
|
+
});
|
|
201
|
+
if (!r.ok) throw new Error(`Cloudflare TURN ${r.status}`);
|
|
202
|
+
const j = await r.json();
|
|
203
|
+
const servers = j.iceServers?.length ? j.iceServers : STUN;
|
|
204
|
+
iceCache = {
|
|
205
|
+
servers,
|
|
206
|
+
exp: Date.now() + (ttl - 300) * 1e3
|
|
207
|
+
};
|
|
208
|
+
return servers;
|
|
209
|
+
} catch (e) {
|
|
210
|
+
console.error(`[share] Cloudflare TURN credential fetch failed; using STUN only: ${e}`);
|
|
211
|
+
return STUN;
|
|
212
|
+
}
|
|
213
|
+
}
|
|
183
214
|
function shareRoomPath() {
|
|
184
215
|
const home = process.env.AGENT_YES_HOME ?? path.join(homedir(), ".agent-yes");
|
|
185
216
|
return path.join(home, ".share-room");
|
|
@@ -288,6 +319,14 @@ async function startShare(opts) {
|
|
|
288
319
|
const ws = new WebSocket(`${wsScheme}://${host}/${room}`, [SUB]);
|
|
289
320
|
currentWs = ws;
|
|
290
321
|
let ready = false;
|
|
322
|
+
let lastRecv = Date.now();
|
|
323
|
+
let hb;
|
|
324
|
+
const stopHb = () => {
|
|
325
|
+
if (hb) {
|
|
326
|
+
clearInterval(hb);
|
|
327
|
+
hb = void 0;
|
|
328
|
+
}
|
|
329
|
+
};
|
|
291
330
|
ws.onopen = () => {
|
|
292
331
|
ws.send(JSON.stringify({
|
|
293
332
|
type: "hello",
|
|
@@ -296,12 +335,28 @@ async function startShare(opts) {
|
|
|
296
335
|
token: authToken
|
|
297
336
|
}));
|
|
298
337
|
ready = true;
|
|
338
|
+
lastRecv = Date.now();
|
|
339
|
+
stopHb();
|
|
340
|
+
hb = setInterval(() => {
|
|
341
|
+
if (Date.now() - lastRecv > HOST_HEARTBEAT_MS * 2 + 5e3) {
|
|
342
|
+
stopHb();
|
|
343
|
+
try {
|
|
344
|
+
ws.close();
|
|
345
|
+
} catch {}
|
|
346
|
+
return;
|
|
347
|
+
}
|
|
348
|
+
try {
|
|
349
|
+
ws.send(JSON.stringify({ type: "ping" }));
|
|
350
|
+
} catch {}
|
|
351
|
+
}, HOST_HEARTBEAT_MS);
|
|
299
352
|
onReady();
|
|
300
353
|
};
|
|
301
354
|
ws.onmessage = async (ev) => {
|
|
302
355
|
if (closed) return;
|
|
356
|
+
lastRecv = Date.now();
|
|
303
357
|
const m = JSON.parse(ev.data);
|
|
304
|
-
if (m.type === "
|
|
358
|
+
if (m.type === "pong") return;
|
|
359
|
+
if (m.type === "peer-join") startPeer(ws, m.peer).catch(() => {});
|
|
305
360
|
else if (m.type === "answer") {
|
|
306
361
|
const peer = peers.get(m.from);
|
|
307
362
|
if (!peer) return;
|
|
@@ -322,19 +377,21 @@ async function startShare(opts) {
|
|
|
322
377
|
else if (m.type === "peer-leave") closePeer(m.peer);
|
|
323
378
|
};
|
|
324
379
|
ws.onclose = (ev) => {
|
|
380
|
+
stopHb();
|
|
325
381
|
if (closed) return;
|
|
326
382
|
if (ev?.code === 1008) {
|
|
327
383
|
closed = true;
|
|
328
384
|
process.stderr.write("[share] room rejected by signaling server — delete ~/.agent-yes/.share-room to rotate the room\n");
|
|
329
385
|
return;
|
|
330
386
|
}
|
|
331
|
-
setTimeout(() => connectSignaling(() => {}), ready ?
|
|
387
|
+
setTimeout(() => connectSignaling(() => {}), ready ? 1e3 : 2e3);
|
|
332
388
|
};
|
|
333
389
|
ws.onerror = () => {};
|
|
334
390
|
return ws;
|
|
335
391
|
};
|
|
336
|
-
function startPeer(ws, peerId) {
|
|
337
|
-
const
|
|
392
|
+
async function startPeer(ws, peerId) {
|
|
393
|
+
const iceServers = await getIceServers();
|
|
394
|
+
const pc = new RTCPeerConnection({ iceServers });
|
|
338
395
|
let resolveKeys;
|
|
339
396
|
const keysReady = new Promise((r) => resolveKeys = r);
|
|
340
397
|
const peer = {
|
|
@@ -385,11 +442,14 @@ async function startShare(opts) {
|
|
|
385
442
|
dc.onmessage = (e) => {
|
|
386
443
|
peer.recvChain = peer.recvChain.then(() => onFrame(peerId, dc, peer, e.data)).catch(() => {});
|
|
387
444
|
};
|
|
388
|
-
|
|
445
|
+
const offer = await pc.createOffer();
|
|
446
|
+
await pc.setLocalDescription(offer);
|
|
447
|
+
ws.send(JSON.stringify({
|
|
389
448
|
type: "offer",
|
|
390
449
|
to: peerId,
|
|
391
|
-
sdp: pc.localDescription.sdp
|
|
392
|
-
|
|
450
|
+
sdp: pc.localDescription.sdp,
|
|
451
|
+
iceServers
|
|
452
|
+
}));
|
|
393
453
|
}
|
|
394
454
|
function closePeer(peerId) {
|
|
395
455
|
const p = peers.get(peerId);
|
|
@@ -519,4 +579,4 @@ async function startShare(opts) {
|
|
|
519
579
|
|
|
520
580
|
//#endregion
|
|
521
581
|
export { loadOrCreateShareRoom, startShare };
|
|
522
|
-
//# sourceMappingURL=share-
|
|
582
|
+
//# sourceMappingURL=share-ClsUSd_0.js.map
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { i as readGlobalPids } from "./globalPidIndex-gZuTvTBs.js";
|
|
2
|
-
import { a as resolveRemoteSpec, i as readRemotes } from "./remotes-
|
|
2
|
+
import { a as resolveRemoteSpec, i as readRemotes } from "./remotes-D2fqaRU8.js";
|
|
3
3
|
import ms from "ms";
|
|
4
4
|
import yargs from "yargs";
|
|
5
5
|
import { appendFile, mkdir, open, readFile, stat, writeFile } from "fs/promises";
|
|
@@ -200,7 +200,9 @@ const SUBCOMMANDS = new Set([
|
|
|
200
200
|
"note",
|
|
201
201
|
"serve",
|
|
202
202
|
"setup",
|
|
203
|
+
"schedule",
|
|
203
204
|
"remote",
|
|
205
|
+
"reap",
|
|
204
206
|
"help"
|
|
205
207
|
]);
|
|
206
208
|
const IDLE_THRESHOLD_MS = 60 * 1e3;
|
|
@@ -231,17 +233,24 @@ async function runSubcommand(argv) {
|
|
|
231
233
|
case "restart": return await cmdRestart(rest);
|
|
232
234
|
case "note": return await cmdNote(rest);
|
|
233
235
|
case "serve": {
|
|
234
|
-
const { cmdServe } = await import("./serve-
|
|
236
|
+
const { cmdServe } = await import("./serve-VczpuYDk.js");
|
|
235
237
|
return cmdServe(rest);
|
|
236
238
|
}
|
|
237
239
|
case "setup": {
|
|
238
|
-
const { cmdSetup } = await import("./setup-
|
|
240
|
+
const { cmdSetup } = await import("./setup-DveWqmSR.js");
|
|
239
241
|
return cmdSetup(rest);
|
|
240
242
|
}
|
|
243
|
+
case "schedule": {
|
|
244
|
+
const { cmdSchedule } = await import("./schedule-CJaNc82S.js");
|
|
245
|
+
return cmdSchedule(rest);
|
|
246
|
+
}
|
|
241
247
|
case "remote": {
|
|
242
|
-
const { cmdRemote } = await import("./remotes-
|
|
248
|
+
const { cmdRemote } = await import("./remotes-CpGcTr7A.js");
|
|
243
249
|
return cmdRemote(rest);
|
|
244
250
|
}
|
|
251
|
+
case "reap":
|
|
252
|
+
await (await import("./reaper-HqcUms2d.js")).sweep();
|
|
253
|
+
return 0;
|
|
245
254
|
case "help": return cmdHelp();
|
|
246
255
|
default: return null;
|
|
247
256
|
}
|
|
@@ -252,7 +261,7 @@ async function runSubcommand(argv) {
|
|
|
252
261
|
}
|
|
253
262
|
}
|
|
254
263
|
function cmdHelp() {
|
|
255
|
-
process.stdout.write("ay - agent-yes CLI\n\nManagement:\n ay ls [keyword] list running agents\n ay tail [-f] <keyword> stream output (Ctrl-C to stop)\n ay cat <keyword> full log\n ay head <keyword> first N lines\n ay send <keyword> <msg> send a message\n ay attach <keyword> interactive attach (detach: Ctrl-\\)\n ay stop <keyword> graceful shutdown (/exit for claude/codex)\n ay status <keyword> agent status snapshot\n\nRemote:\n ay setup guided setup: pick a workspace, share to agent-yes.com\n ay serve [--port N] start HTTP API server (prints token)\n ay remote add <alias> http://<token>@<host>:<port>\n ay remote ls / rm <alias> manage saved remotes\n ay ls <token>@<host>:<port> connect inline (no alias needed)\n ay send <token>@<host>:<port>:<kw> <msg>\n\nRun an agent:\n ay [claude|codex|gemini|...] [options] -- [prompt]\n ay claude -- \"fix the bug in auth.ts\"\n ay claude --help full agent-runner options\n\nLabs (examples at https://github.com/snomiao/agent-yes/tree/main/lab):\n local-role-play/ designer + builder on one machine\n http-remote/ ay serve remote access demo\n p2p-pairing/ libp2p P2P (needs: cargo build --features swarm)\n");
|
|
264
|
+
process.stdout.write("ay - agent-yes CLI\n\nManagement:\n ay ls [keyword] list running agents\n ay tail [-f] <keyword> stream output (Ctrl-C to stop)\n ay cat <keyword> full log\n ay head <keyword> first N lines\n ay send <keyword> <msg> send a message\n ay attach <keyword> interactive attach (detach: Ctrl-\\)\n ay stop <keyword> graceful shutdown (/exit for claude/codex)\n ay status <keyword> agent status snapshot\n ay reap kill process groups leaked by dead agents\n\nRemote:\n ay setup guided setup: pick a workspace, share to agent-yes.com\n ay schedule <when> <cli> -- <msg> run an agent on a schedule (HH:MM or cron)\n ay serve [--port N] start HTTP API server (prints token)\n ay serve status show serve daemon/server status\n ay remote add <alias> http://<token>@<host>:<port>\n ay remote ls / rm <alias> manage saved remotes\n ay ls <token>@<host>:<port> connect inline (no alias needed)\n ay send <token>@<host>:<port>:<kw> <msg>\n\nRun an agent:\n ay [claude|codex|gemini|...] [options] -- [prompt]\n ay claude -- \"fix the bug in auth.ts\"\n ay claude --help full agent-runner options\n\nLabs (examples at https://github.com/snomiao/agent-yes/tree/main/lab):\n local-role-play/ designer + builder on one machine\n http-remote/ ay serve remote access demo\n p2p-pairing/ libp2p P2P (needs: cargo build --features swarm)\n");
|
|
256
265
|
return 0;
|
|
257
266
|
}
|
|
258
267
|
function matchKeyword(record, keyword) {
|
|
@@ -1680,4 +1689,4 @@ async function cmdStatus(rest) {
|
|
|
1680
1689
|
|
|
1681
1690
|
//#endregion
|
|
1682
1691
|
export { finalizedLines as a, listRecords as c, renderRawLog as d, resolveOne as f, writeToIpc as g, stopTipForCli as h, cursorAbs as i, matchKeyword as l, snapshotStatus as m, cmdHelp as n, isPidAlive as o, runSubcommand as p, controlCodeFromName as r, isSubcommand as s, GRACEFUL_EXIT_COMMANDS as t, readNotes as u };
|
|
1683
|
-
//# sourceMappingURL=subcommands-
|
|
1692
|
+
//# sourceMappingURL=subcommands-CmNGbbIA.js.map
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import "./logger-B9h0djqx.js";
|
|
2
2
|
import "./globalPidIndex-gZuTvTBs.js";
|
|
3
|
-
import "./remotes-
|
|
4
|
-
import { a as finalizedLines, c as listRecords, d as renderRawLog, f as resolveOne, g as writeToIpc, h as stopTipForCli, i as cursorAbs, l as matchKeyword, m as snapshotStatus, n as cmdHelp, o as isPidAlive, p as runSubcommand, r as controlCodeFromName, s as isSubcommand, t as GRACEFUL_EXIT_COMMANDS, u as readNotes } from "./subcommands-
|
|
3
|
+
import "./remotes-D2fqaRU8.js";
|
|
4
|
+
import { a as finalizedLines, c as listRecords, d as renderRawLog, f as resolveOne, g as writeToIpc, h as stopTipForCli, i as cursorAbs, l as matchKeyword, m as snapshotStatus, n as cmdHelp, o as isPidAlive, p as runSubcommand, r as controlCodeFromName, s as isSubcommand, t as GRACEFUL_EXIT_COMMANDS, u as readNotes } from "./subcommands-CmNGbbIA.js";
|
|
5
5
|
|
|
6
6
|
export { cmdHelp, isSubcommand, runSubcommand };
|
|
@@ -61,13 +61,6 @@ function isTrayProcessRunning(pid) {
|
|
|
61
61
|
}
|
|
62
62
|
}
|
|
63
63
|
/**
|
|
64
|
-
* Write the current process PID to the tray PID file
|
|
65
|
-
*/
|
|
66
|
-
async function writeTrayPid() {
|
|
67
|
-
await mkdir(getTrayDir(), { recursive: true });
|
|
68
|
-
await writeFile(getTrayPidFile(), String(process.pid), "utf8");
|
|
69
|
-
}
|
|
70
|
-
/**
|
|
71
64
|
* Remove the tray PID file
|
|
72
65
|
*/
|
|
73
66
|
async function removeTrayPid() {
|
|
@@ -76,6 +69,25 @@ async function removeTrayPid() {
|
|
|
76
69
|
} catch {}
|
|
77
70
|
}
|
|
78
71
|
/**
|
|
72
|
+
* Atomically claim the tray singleton. Exclusive create (flag "wx") fails if a
|
|
73
|
+
* pidfile already exists, so two trays racing startup can't BOTH pass a
|
|
74
|
+
* check-then-act and survive (that race is how N agents ended up with N trays).
|
|
75
|
+
* If an existing pidfile belongs to a DEAD tray it's stale — take it over.
|
|
76
|
+
* Returns true if this process is now the singleton owner.
|
|
77
|
+
*/
|
|
78
|
+
async function claimTraySingleton() {
|
|
79
|
+
const pidFile = getTrayPidFile();
|
|
80
|
+
await mkdir(getTrayDir(), { recursive: true });
|
|
81
|
+
for (let attempt = 0; attempt < 2; attempt++) try {
|
|
82
|
+
await writeFile(pidFile, String(process.pid), { flag: "wx" });
|
|
83
|
+
return true;
|
|
84
|
+
} catch {
|
|
85
|
+
if (await isTrayRunning()) return false;
|
|
86
|
+
await removeTrayPid();
|
|
87
|
+
}
|
|
88
|
+
return false;
|
|
89
|
+
}
|
|
90
|
+
/**
|
|
79
91
|
* Check if a tray process is already running
|
|
80
92
|
*/
|
|
81
93
|
async function isTrayRunning() {
|
|
@@ -96,6 +108,7 @@ async function isTrayRunning() {
|
|
|
96
108
|
*/
|
|
97
109
|
async function ensureTray() {
|
|
98
110
|
if (!isDesktopOS()) return;
|
|
111
|
+
if (process.env.AGENT_YES_TRAY !== "1") return;
|
|
99
112
|
if (await isTrayRunning()) return;
|
|
100
113
|
try {
|
|
101
114
|
const cliPath = new URL("./cli.ts", import.meta.url).pathname;
|
|
@@ -116,11 +129,10 @@ async function startTray() {
|
|
|
116
129
|
console.error("Tray icon is only supported on macOS and Windows.");
|
|
117
130
|
return;
|
|
118
131
|
}
|
|
119
|
-
if (await
|
|
132
|
+
if (!await claimTraySingleton()) {
|
|
120
133
|
console.error("Tray is already running.");
|
|
121
134
|
return;
|
|
122
135
|
}
|
|
123
|
-
await writeTrayPid();
|
|
124
136
|
let SysTray;
|
|
125
137
|
try {
|
|
126
138
|
SysTray = (await import("systray2")).default;
|
|
@@ -175,4 +187,4 @@ async function startTray() {
|
|
|
175
187
|
|
|
176
188
|
//#endregion
|
|
177
189
|
export { ensureTray, startTray };
|
|
178
|
-
//# sourceMappingURL=tray-
|
|
190
|
+
//# sourceMappingURL=tray-DjCIyakK.js.map
|
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
import { n as logger, t as addTransport } from "./logger-B9h0djqx.js";
|
|
2
|
-
import { r as getInstalledPackage } from "./versionChecker-
|
|
2
|
+
import { r as getInstalledPackage } from "./versionChecker-B5vxV_hH.js";
|
|
3
3
|
import { t as agentYesHome } from "./agentYesHome-BvaUOzCV.js";
|
|
4
4
|
import { i as shouldUseLock, r as releaseLock, t as acquireLock } from "./runningLock-CJxsoGdb.js";
|
|
5
5
|
import { t as PidStore } from "./pidStore-B5vBu8Px.js";
|
|
6
6
|
import { i as readGlobalPids } from "./globalPidIndex-gZuTvTBs.js";
|
|
7
|
+
import { n as sweep, t as register } from "./reaper-Dj8R7ltI.js";
|
|
7
8
|
import { arch, platform } from "process";
|
|
8
9
|
import { execSync } from "child_process";
|
|
9
10
|
import { closeSync, constants, createReadStream, existsSync, mkdirSync, openSync } from "fs";
|
|
@@ -275,8 +276,16 @@ async function getPty() {
|
|
|
275
276
|
throw error;
|
|
276
277
|
});
|
|
277
278
|
}
|
|
278
|
-
|
|
279
|
+
let pty;
|
|
280
|
+
try {
|
|
281
|
+
pty = await getPty();
|
|
282
|
+
} catch (error) {
|
|
283
|
+
pty = new Proxy({}, { get() {
|
|
284
|
+
throw error;
|
|
285
|
+
} });
|
|
286
|
+
}
|
|
279
287
|
const ptyPackage = globalThis.Bun ? "bun-pty" : "node-pty";
|
|
288
|
+
var pty_default = pty;
|
|
280
289
|
|
|
281
290
|
//#endregion
|
|
282
291
|
//#region ts/removeControlCharacters.ts
|
|
@@ -529,6 +538,17 @@ async function sendMessage(context, message, { waitForReady = true } = {}) {
|
|
|
529
538
|
logger.debug(`sent enter`);
|
|
530
539
|
}
|
|
531
540
|
|
|
541
|
+
//#endregion
|
|
542
|
+
//#region ts/autoRetry.ts
|
|
543
|
+
const AUTO_RETRY_BASE_SECS = 8;
|
|
544
|
+
const AUTO_RETRY_MAX_DELAY_SECS = 256;
|
|
545
|
+
const AUTO_RETRY_GIVE_UP_MS = 8 * 3600 * 1e3;
|
|
546
|
+
/** Backoff (ms) before the Nth consecutive auto-retry — doubles, then caps. */
|
|
547
|
+
function autoRetryBackoffMs(streak) {
|
|
548
|
+
const shift = Math.min(streak, 20);
|
|
549
|
+
return Math.min(AUTO_RETRY_BASE_SECS * 2 ** shift, AUTO_RETRY_MAX_DELAY_SECS) * 1e3;
|
|
550
|
+
}
|
|
551
|
+
|
|
532
552
|
//#endregion
|
|
533
553
|
//#region ts/core/logging.ts
|
|
534
554
|
/**
|
|
@@ -782,7 +802,7 @@ function spawnAgent(options) {
|
|
|
782
802
|
const spawn = () => {
|
|
783
803
|
let [bin, ...args] = [...parseCommandString(cliConf?.binary || cli), ...cliArgs];
|
|
784
804
|
logger.debug(`Spawning ${bin} with args: ${JSON.stringify(args)}`);
|
|
785
|
-
const spawned =
|
|
805
|
+
const spawned = pty_default.spawn(bin, args, ptyOptions);
|
|
786
806
|
logger.info(`[${cli}-yes] Spawned ${bin} with PID ${spawned.pid} (agent-yes v${getInstalledPackage().version})`);
|
|
787
807
|
return spawned;
|
|
788
808
|
};
|
|
@@ -1040,7 +1060,7 @@ async function notifyWebhook(status, details, cwd = process.cwd()) {
|
|
|
1040
1060
|
|
|
1041
1061
|
//#endregion
|
|
1042
1062
|
//#region ts/index.ts
|
|
1043
|
-
const config = await import("./agent-yes.config-
|
|
1063
|
+
const config = await import("./agent-yes.config-z-IPzH5U.js").then((mod) => mod.default || mod);
|
|
1044
1064
|
const CLIS_CONFIG = config.clis;
|
|
1045
1065
|
/**
|
|
1046
1066
|
* Main function to run agent-cli with automatic yes/no responses
|
|
@@ -1190,6 +1210,7 @@ async function agentYes({ cli, cliArgs = [], prompt, robust = true, cwd, env, ex
|
|
|
1190
1210
|
];
|
|
1191
1211
|
prompt = void 0;
|
|
1192
1212
|
} else logger.warn(`Unknown promptArg format: ${cliConf.promptArg}`);
|
|
1213
|
+
sweep().catch(() => {});
|
|
1193
1214
|
const ptyEnv = { ...env ?? process.env };
|
|
1194
1215
|
ptyEnv.AGENT_YES_PID = String(process.pid);
|
|
1195
1216
|
const ptyOptions = {
|
|
@@ -1225,6 +1246,7 @@ async function agentYes({ cli, cliArgs = [], prompt, robust = true, cwd, env, ex
|
|
|
1225
1246
|
} catch (error) {
|
|
1226
1247
|
logger.warn(`[pidStore] Failed to register process ${shell.pid}:`, error);
|
|
1227
1248
|
}
|
|
1249
|
+
register(process.pid, shell.pid).catch(() => {});
|
|
1228
1250
|
notifyWebhook("RUNNING", prompt ?? "", workingDir).catch(() => null);
|
|
1229
1251
|
const logPaths = await initializeLogPaths(pidStore, shell.pid);
|
|
1230
1252
|
await setupDebugLogging(logPaths.debuggingLogsPath);
|
|
@@ -1264,6 +1286,9 @@ async function agentYes({ cli, cliArgs = [], prompt, robust = true, cwd, env, ex
|
|
|
1264
1286
|
const pendingExitCode = Promise.withResolvers();
|
|
1265
1287
|
shell.onExit(async function onExit({ exitCode }) {
|
|
1266
1288
|
const exitedPid = shell.pid;
|
|
1289
|
+
if (process.platform !== "win32") try {
|
|
1290
|
+
process.kill(-exitedPid, "SIGKILL");
|
|
1291
|
+
} catch {}
|
|
1267
1292
|
globalAgentRegistry.unregister(exitedPid);
|
|
1268
1293
|
ctx.stdinReady.unready();
|
|
1269
1294
|
const agentCrashed = exitCode !== 0 && !(exitCode === 130 || exitCode === 143 || userSentCtrlC);
|
|
@@ -1294,7 +1319,7 @@ async function agentYes({ cli, cliArgs = [], prompt, robust = true, cwd, env, ex
|
|
|
1294
1319
|
cwd: cwd ?? process.cwd(),
|
|
1295
1320
|
env: ptyEnv
|
|
1296
1321
|
};
|
|
1297
|
-
shell =
|
|
1322
|
+
shell = pty_default.spawn(bin, args, restartPtyOptions);
|
|
1298
1323
|
shellWrite = (data) => shell.write(data);
|
|
1299
1324
|
try {
|
|
1300
1325
|
await pidStore.registerProcess({
|
|
@@ -1307,6 +1332,7 @@ async function agentYes({ cli, cliArgs = [], prompt, robust = true, cwd, env, ex
|
|
|
1307
1332
|
} catch (error) {
|
|
1308
1333
|
logger.warn(`[pidStore] Failed to register restarted process ${shell.pid}:`, error);
|
|
1309
1334
|
}
|
|
1335
|
+
register(process.pid, shell.pid).catch(() => {});
|
|
1310
1336
|
ctx.shell = shell;
|
|
1311
1337
|
try {
|
|
1312
1338
|
globalAgentRegistry.register(shell.pid, {
|
|
@@ -1377,7 +1403,7 @@ async function agentYes({ cli, cliArgs = [], prompt, robust = true, cwd, env, ex
|
|
|
1377
1403
|
cwd: cwd ?? process.cwd(),
|
|
1378
1404
|
env: ptyEnv
|
|
1379
1405
|
};
|
|
1380
|
-
shell =
|
|
1406
|
+
shell = pty_default.spawn(cli, restoreArgs, restorePtyOptions);
|
|
1381
1407
|
shellWrite = (data) => shell.write(data);
|
|
1382
1408
|
try {
|
|
1383
1409
|
await pidStore.registerProcess({
|
|
@@ -1390,6 +1416,7 @@ async function agentYes({ cli, cliArgs = [], prompt, robust = true, cwd, env, ex
|
|
|
1390
1416
|
} catch (error) {
|
|
1391
1417
|
logger.warn(`[pidStore] Failed to register restored process ${shell.pid}:`, error);
|
|
1392
1418
|
}
|
|
1419
|
+
register(process.pid, shell.pid).catch(() => {});
|
|
1393
1420
|
ctx.shell = shell;
|
|
1394
1421
|
try {
|
|
1395
1422
|
globalAgentRegistry.register(shell.pid, {
|
|
@@ -1443,9 +1470,33 @@ async function agentYes({ cli, cliArgs = [], prompt, robust = true, cwd, env, ex
|
|
|
1443
1470
|
return conf.working?.some((rgx) => rgx.test(rendered));
|
|
1444
1471
|
};
|
|
1445
1472
|
let lastHeartbeatRendered = "";
|
|
1473
|
+
let retryStreak = 0;
|
|
1474
|
+
let retryStartedAt = null;
|
|
1475
|
+
let retryNextAt = null;
|
|
1476
|
+
let autoRetryScreen = "";
|
|
1446
1477
|
const heartbeatInterval = setInterval(async () => {
|
|
1447
1478
|
try {
|
|
1448
1479
|
const rendered = removeControlCharacters(xtermProxy.tail(12));
|
|
1480
|
+
if (retryNextAt !== null) {
|
|
1481
|
+
const now = Date.now();
|
|
1482
|
+
if (retryStartedAt !== null && now - retryStartedAt >= AUTO_RETRY_GIVE_UP_MS) {
|
|
1483
|
+
logger.warn(`[${cli}-yes] auto-retry: giving up after 8h with no recovery`);
|
|
1484
|
+
retryNextAt = null;
|
|
1485
|
+
retryStartedAt = null;
|
|
1486
|
+
retryStreak = 0;
|
|
1487
|
+
} else if (now >= retryNextAt) {
|
|
1488
|
+
const working = conf.working?.some((rx) => rx.test(autoRetryScreen)) ?? false;
|
|
1489
|
+
const readyNow = conf.ready?.some((rx) => rx.test(autoRetryScreen)) ?? false;
|
|
1490
|
+
if (working || !readyNow) retryNextAt = now + 500;
|
|
1491
|
+
else {
|
|
1492
|
+
retryStreak += 1;
|
|
1493
|
+
logger.warn(`[${cli}-yes] auto-retry: typing 'retry' (attempt ${retryStreak})`);
|
|
1494
|
+
ctx.messageContext.shell.write("retry\r");
|
|
1495
|
+
ctx.idleWaiter.ping();
|
|
1496
|
+
retryNextAt = now + autoRetryBackoffMs(retryStreak);
|
|
1497
|
+
}
|
|
1498
|
+
}
|
|
1499
|
+
}
|
|
1449
1500
|
if (rendered === lastHeartbeatRendered) return;
|
|
1450
1501
|
lastHeartbeatRendered = rendered;
|
|
1451
1502
|
const lines = rendered.split("\n").filter((line) => line.trim());
|
|
@@ -1642,6 +1693,24 @@ async function agentYes({ cli, cliArgs = [], prompt, robust = true, cwd, env, ex
|
|
|
1642
1693
|
if (rendered === lastRendered) return;
|
|
1643
1694
|
lastRendered = rendered;
|
|
1644
1695
|
logger.debug(`stdout|${line}`);
|
|
1696
|
+
if (conf.autoRetry?.length) {
|
|
1697
|
+
autoRetryScreen = rendered;
|
|
1698
|
+
const errVisible = conf.autoRetry.some((rx) => rx.test(rendered));
|
|
1699
|
+
const readyVisible = conf.ready?.some((rx) => rx.test(rendered)) ?? false;
|
|
1700
|
+
if (errVisible && readyVisible) {
|
|
1701
|
+
if (retryNextAt === null) {
|
|
1702
|
+
if (retryStartedAt === null) retryStartedAt = Date.now();
|
|
1703
|
+
const delayMs = autoRetryBackoffMs(retryStreak);
|
|
1704
|
+
retryNextAt = Date.now() + delayMs;
|
|
1705
|
+
logger.warn(`[${cli}-yes] auto-retry armed: recoverable error detected, retrying in ${delayMs / 1e3}s (attempt ${retryStreak + 1})`);
|
|
1706
|
+
}
|
|
1707
|
+
} else if (readyVisible && !errVisible && retryStartedAt !== null) {
|
|
1708
|
+
logger.debug(`[${cli}-yes] auto-retry: recovered, resetting backoff`);
|
|
1709
|
+
retryStreak = 0;
|
|
1710
|
+
retryStartedAt = null;
|
|
1711
|
+
retryNextAt = null;
|
|
1712
|
+
}
|
|
1713
|
+
}
|
|
1645
1714
|
if (conf.ready?.some((rx) => line.match(rx))) {
|
|
1646
1715
|
logger.debug(`ready |${line}`);
|
|
1647
1716
|
if (cli === "gemini" && lineIndex <= 80) return;
|
|
@@ -1715,4 +1784,4 @@ function sleep(ms) {
|
|
|
1715
1784
|
|
|
1716
1785
|
//#endregion
|
|
1717
1786
|
export { removeControlCharacters as a, AgentContext as i, agentYes as n, config as r, CLIS_CONFIG as t };
|
|
1718
|
-
//# sourceMappingURL=ts-
|
|
1787
|
+
//# sourceMappingURL=ts-7kSDmCpQ.js.map
|
|
@@ -7,7 +7,7 @@ import { fileURLToPath } from "url";
|
|
|
7
7
|
|
|
8
8
|
//#region package.json
|
|
9
9
|
var name = "agent-yes";
|
|
10
|
-
var version = "1.
|
|
10
|
+
var version = "1.122.0";
|
|
11
11
|
|
|
12
12
|
//#endregion
|
|
13
13
|
//#region ts/versionChecker.ts
|
|
@@ -170,29 +170,23 @@ function compareVersions(v1, v2) {
|
|
|
170
170
|
}
|
|
171
171
|
/**
|
|
172
172
|
* Detect how agent-yes was installed.
|
|
173
|
-
* Returns a short label: "git", "bun
|
|
173
|
+
* Returns a short label: "git", "bun", "npm", "npx", "source", or "unknown".
|
|
174
|
+
* A bun-link of a git checkout reports "git" (it runs the working tree).
|
|
174
175
|
*/
|
|
175
176
|
function detectInstallMethod() {
|
|
176
177
|
try {
|
|
177
|
-
const scriptDir = path.dirname(
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
}
|
|
183
|
-
const nodeModulesEntry = scriptDir.replace(/\/dist$/, "");
|
|
178
|
+
const scriptDir = path.dirname(fileURLToPath(import.meta.url));
|
|
179
|
+
const norm = scriptDir.replace(/\\/g, "/");
|
|
180
|
+
const hasGit = (dir) => existsSync(path.join(dir, ".git"));
|
|
181
|
+
if (!norm.includes("node_modules")) return hasGit(path.resolve(scriptDir, "..")) ? "git" : "source";
|
|
182
|
+
const nodeModulesEntry = scriptDir.replace(/[\\/]dist$/, "");
|
|
184
183
|
try {
|
|
185
|
-
if (lstatSync(nodeModulesEntry).isSymbolicLink())
|
|
186
|
-
const target = readlinkSync(nodeModulesEntry);
|
|
187
|
-
const resolvedTarget = path.resolve(path.dirname(nodeModulesEntry), target);
|
|
188
|
-
if (existsSync(path.join(resolvedTarget, ".git"))) return "bun link (git)";
|
|
189
|
-
return "bun link";
|
|
190
|
-
}
|
|
184
|
+
if (lstatSync(nodeModulesEntry).isSymbolicLink()) return hasGit(path.resolve(path.dirname(nodeModulesEntry), readlinkSync(nodeModulesEntry))) ? "git" : "bun";
|
|
191
185
|
} catch {}
|
|
192
|
-
if (
|
|
193
|
-
if (
|
|
194
|
-
if (process.env.npm_execpath?.includes("bun")) return "bun";
|
|
186
|
+
if (norm.includes("/.bun/")) return "bun";
|
|
187
|
+
if (norm.includes("/.npm/")) return "npx";
|
|
195
188
|
if (process.env.npm_config_user_agent?.startsWith("bun")) return "bun";
|
|
189
|
+
if (process.env.npm_execpath?.includes("bun")) return "bun";
|
|
196
190
|
if (process.env.npm_config_user_agent?.startsWith("npm")) return "npm";
|
|
197
191
|
return "npm";
|
|
198
192
|
} catch {
|
|
@@ -221,4 +215,4 @@ async function displayVersion() {
|
|
|
221
215
|
|
|
222
216
|
//#endregion
|
|
223
217
|
export { versionString as i, displayVersion as n, getInstalledPackage as r, checkAndAutoUpdate as t };
|
|
224
|
-
//# sourceMappingURL=versionChecker-
|
|
218
|
+
//# sourceMappingURL=versionChecker-B5vxV_hH.js.map
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import { t as agentYesHome } from "./agentYesHome-BvaUOzCV.js";
|
|
2
|
+
import { mkdirSync, readFileSync, writeFileSync } from "fs";
|
|
3
|
+
import { homedir } from "os";
|
|
4
|
+
import path from "path";
|
|
5
|
+
|
|
6
|
+
//#region ts/workspaceConfig.ts
|
|
7
|
+
function configPath() {
|
|
8
|
+
return path.join(agentYesHome(), "config.json");
|
|
9
|
+
}
|
|
10
|
+
function readConfig() {
|
|
11
|
+
try {
|
|
12
|
+
return JSON.parse(readFileSync(configPath(), "utf-8"));
|
|
13
|
+
} catch {
|
|
14
|
+
return {};
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
/** Expand a leading `~` (`~` or `~/x`) to an absolute home-based path. */
|
|
18
|
+
function expandTilde(p) {
|
|
19
|
+
const s = p.trim();
|
|
20
|
+
if (s === "~") return homedir();
|
|
21
|
+
if (s.startsWith("~/") || s.startsWith("~\\")) return path.join(homedir(), s.slice(2));
|
|
22
|
+
return s;
|
|
23
|
+
}
|
|
24
|
+
/** The configured workspace root (absolute), or the home dir if unset. */
|
|
25
|
+
function getWorkspaceRoot() {
|
|
26
|
+
const w = readConfig().workspace;
|
|
27
|
+
return w && w.trim() ? w : homedir();
|
|
28
|
+
}
|
|
29
|
+
/** Persist the workspace root, tilde-expanded and resolved to an absolute path. */
|
|
30
|
+
function setWorkspaceRoot(dir) {
|
|
31
|
+
const abs = path.resolve(expandTilde(dir));
|
|
32
|
+
const cfg = readConfig();
|
|
33
|
+
cfg.workspace = abs;
|
|
34
|
+
mkdirSync(agentYesHome(), { recursive: true });
|
|
35
|
+
writeFileSync(configPath(), JSON.stringify(cfg, null, 2));
|
|
36
|
+
return abs;
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* Resolve a user-supplied spawn location to an absolute cwd:
|
|
40
|
+
* - empty → the workspace root
|
|
41
|
+
* - a bare name → `<workspace>/<name>` (so "myproject" lands under the root)
|
|
42
|
+
* - `~`-prefixed → home-based absolute
|
|
43
|
+
* - anything with a path separator → resolved as-is
|
|
44
|
+
*/
|
|
45
|
+
function resolveSpawnCwd(input) {
|
|
46
|
+
const root = getWorkspaceRoot();
|
|
47
|
+
const v = (input ?? "").trim();
|
|
48
|
+
if (!v) return root;
|
|
49
|
+
if (v.startsWith("~")) return path.resolve(expandTilde(v));
|
|
50
|
+
if (v.includes("/") || v.includes("\\") || path.isAbsolute(v)) return path.resolve(v);
|
|
51
|
+
return path.join(root, v);
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
//#endregion
|
|
55
|
+
export { resolveSpawnCwd as n, setWorkspaceRoot as r, getWorkspaceRoot as t };
|
|
56
|
+
//# sourceMappingURL=workspaceConfig-XP2NEWmV.js.map
|