agent-yes 1.196.2 → 1.197.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.
Files changed (45) hide show
  1. package/default.config.yaml +51 -12
  2. package/dist/{SUPPORTED_CLIS-BuiThZSF.js → SUPPORTED_CLIS-BY83eM58.js} +2 -2
  3. package/dist/SUPPORTED_CLIS-D4Z--hGm.js +9 -0
  4. package/dist/{agent-yes.config-ugPYTPOd.js → agent-yes.config-whqkqq9P.js} +2 -2
  5. package/dist/{agentShare-BMZVmm7c.js → agentShare-DWioPObE.js} +8 -7
  6. package/dist/cli.js +8 -8
  7. package/dist/{configShared-0MnIQ652.js → configShared-aKTg-sa5.js} +1 -1
  8. package/dist/{e2e-BeKjLhmO.js → e2e-jb0Hp43q.js} +1 -1
  9. package/dist/{expose-B3AGhVhM.js → expose-k9l6ZJDA.js} +1 -1
  10. package/dist/{forkNested-C1kKsXi5.js → forkNested-DOyDAHnC.js} +1 -1
  11. package/dist/index.js +3 -2
  12. package/dist/messageLog-CxrKJj77.js +94 -0
  13. package/dist/{nodeRuntime-DZRjxpNp.js → nodeRuntime-CwNJuwH5.js} +1 -1
  14. package/dist/{notifyDaemon-Cikn_qKr.js → notifyDaemon-CRf_27kE.js} +7 -6
  15. package/dist/{openBrowser-DQVkxCyj.js → openBrowser-CSj21pZE.js} +1 -1
  16. package/dist/{reaper-CWF2_ATd.js → reaper-BUHCyxdF.js} +1 -1
  17. package/dist/{reaper-jfSmog15.js → reaper-CJSu8UVZ.js} +1 -1
  18. package/dist/{remotes-CW-yxSgW.js → remotes-CXqYR0p8.js} +3 -3
  19. package/dist/{remotes-oSmwSYaV.js → remotes-Cim0dBU7.js} +3 -3
  20. package/dist/{rustBinary-Uxkcz3zV.js → rustBinary-5HCt7_0b.js} +2 -2
  21. package/dist/{schedule-cvu-t8uo.js → schedule-CjBcOy-b.js} +7 -6
  22. package/dist/{serve-Cp9XGHAg.js → serve-C3E8uicL.js} +45 -26
  23. package/dist/{setup-onV23tOF.js → setup-C4SKqGy1.js} +3 -3
  24. package/dist/{share-29YbzpbU.js → share-BfIU8t_h.js} +2 -2
  25. package/dist/{share-nvqy64A2.js → share-Ciw1mWVN.js} +2 -2
  26. package/dist/{spawnGate-CWbdnJ5K.js → spawnGate-BkjeS4tg.js} +1 -1
  27. package/dist/{spawnGate-DRWa_Fzj.js → spawnGate-CXjEz6Pf.js} +2 -2
  28. package/dist/{subcommands-Dwzo0rx_.js → subcommands-B7UxIJRw.js} +17 -103
  29. package/dist/{subcommands-BReg256R.js → subcommands-DzWBZ6HE.js} +6 -5
  30. package/dist/{tray-BKTZ5gIf.js → tray-BSFi35Qg.js} +1 -1
  31. package/dist/{ts-ml_9eD1Y.js → ts-B64pNQlI.js} +84 -7
  32. package/dist/{versionChecker-ufJXjxRK.js → versionChecker-DKiSuTSp.js} +2 -2
  33. package/dist/{webrtcLink-BG0Xc4-W.js → webrtcLink-B7REGtK2.js} +2 -2
  34. package/dist/{webrtcRemote-BmuVKcrx.js → webrtcRemote-CvIEfWX8.js} +3 -3
  35. package/dist/{workspaceConfig-_GtAZtsi.js → workspaceConfig-CjaRvTjf.js} +1 -1
  36. package/package.json +1 -1
  37. package/ts/autoRetry.spec.ts +90 -1
  38. package/ts/autoRetry.ts +76 -0
  39. package/ts/index.ts +37 -4
  40. package/ts/messageLog.ts +3 -2
  41. package/ts/serve.ts +4 -5
  42. package/ts/subcommands.ts +9 -5
  43. package/ts/terminalReply.spec.ts +36 -0
  44. package/ts/terminalReply.ts +17 -0
  45. package/dist/SUPPORTED_CLIS-BBTAJQVG.js +0 -8
@@ -1,4 +1,4 @@
1
- import { f as setWorkspaceRoot, s as getWorkspaceRoot } from "./workspaceConfig-_GtAZtsi.js";
1
+ import { f as setWorkspaceRoot, s as getWorkspaceRoot } from "./workspaceConfig-CjaRvTjf.js";
2
2
  import { existsSync } from "node:fs";
3
3
  import { stdin, stdout } from "node:process";
4
4
  import { createInterface } from "node:readline/promises";
@@ -32,7 +32,7 @@ async function cmdSetup(rest) {
32
32
  if (!existsSync(abs)) process.stderr.write(` note: that directory doesn't exist yet — create it, or agents spawned there will fail\n`);
33
33
  if (noShare) return 0;
34
34
  process.stdout.write(`\nsharing this machine to agent-yes.com…\n`);
35
- const { cmdServe } = await import("./serve-Cp9XGHAg.js");
35
+ const { cmdServe } = await import("./serve-C3E8uicL.js");
36
36
  return cmdServe([
37
37
  "install",
38
38
  "--share",
@@ -42,4 +42,4 @@ async function cmdSetup(rest) {
42
42
 
43
43
  //#endregion
44
44
  export { cmdSetup };
45
- //# sourceMappingURL=setup-onV23tOF.js.map
45
+ //# sourceMappingURL=setup-C4SKqGy1.js.map
@@ -1,4 +1,4 @@
1
- import { a as computeTranscriptHash, c as open$1, d as randomHex, f as seal, i as MAX_CHUNK, l as packEnvelope, n as FLAG_CONFIRM, o as deriveAuthToken, p as unpackEnvelope, r as MARKER, s as deriveDirKeys, t as CONFIRM_TIMEOUT_MS, u as parseSecret } from "./e2e-BeKjLhmO.js";
1
+ import { a as computeTranscriptHash, c as open$1, d as randomHex, f as seal, i as MAX_CHUNK, l as packEnvelope, n as FLAG_CONFIRM, o as deriveAuthToken, p as unpackEnvelope, r as MARKER, s as deriveDirKeys, t as CONFIRM_TIMEOUT_MS, u as parseSecret } from "./e2e-jb0Hp43q.js";
2
2
  import { mkdir, readFile, writeFile } from "fs/promises";
3
3
  import { homedir } from "os";
4
4
  import path from "path";
@@ -534,4 +534,4 @@ async function startShare(opts) {
534
534
 
535
535
  //#endregion
536
536
  export { shareLinkFromRoomUrl as n, startShare as r, loadOrCreateShareRoom as t };
537
- //# sourceMappingURL=share-29YbzpbU.js.map
537
+ //# sourceMappingURL=share-BfIU8t_h.js.map
@@ -1,4 +1,4 @@
1
- import "./e2e-BeKjLhmO.js";
2
- import { n as shareLinkFromRoomUrl, r as startShare, t as loadOrCreateShareRoom } from "./share-29YbzpbU.js";
1
+ import "./e2e-jb0Hp43q.js";
2
+ import { n as shareLinkFromRoomUrl, r as startShare, t as loadOrCreateShareRoom } from "./share-BfIU8t_h.js";
3
3
 
4
4
  export { loadOrCreateShareRoom, shareLinkFromRoomUrl, startShare };
@@ -1,5 +1,5 @@
1
1
  import "./logger-CDIsZ-Pp.js";
2
2
  import "./globalPidIndex-CoNr7tS8.js";
3
- import { i as waitForSpawnCapacity, n as spawnGateEnabled, r as spawnRejectionReason, t as memAvailableMb } from "./spawnGate-DRWa_Fzj.js";
3
+ import { i as waitForSpawnCapacity, n as spawnGateEnabled, r as spawnRejectionReason, t as memAvailableMb } from "./spawnGate-CXjEz6Pf.js";
4
4
 
5
5
  export { waitForSpawnCapacity };
@@ -1,5 +1,5 @@
1
1
  import { i as readGlobalPids } from "./globalPidIndex-CoNr7tS8.js";
2
- import { n as getMinFreeMb, o as getSpawnWaitMs, t as getMaxAgents } from "./workspaceConfig-_GtAZtsi.js";
2
+ import { n as getMinFreeMb, o as getSpawnWaitMs, t as getMaxAgents } from "./workspaceConfig-CjaRvTjf.js";
3
3
  import { readFile } from "fs/promises";
4
4
 
5
5
  //#region ts/spawnGate.ts
@@ -104,4 +104,4 @@ async function waitForSpawnCapacity(opts) {
104
104
 
105
105
  //#endregion
106
106
  export { waitForSpawnCapacity as i, spawnGateEnabled as n, spawnRejectionReason as r, memAvailableMb as t };
107
- //# sourceMappingURL=spawnGate-DRWa_Fzj.js.map
107
+ //# sourceMappingURL=spawnGate-CXjEz6Pf.js.map
@@ -2,9 +2,10 @@ import { t as invokedCliName } from "./invokedCli-uqM2YYA7.js";
2
2
  import { n as logger } from "./logger-CDIsZ-Pp.js";
3
3
  import { t as agentYesHome } from "./agentYesHome-CtHb5b71.js";
4
4
  import { a as updateGlobalPidStatus, i as readGlobalPids } from "./globalPidIndex-CoNr7tS8.js";
5
- import { t as loadSharedCliDefaults } from "./configShared-0MnIQ652.js";
6
- import { n as isWebrtcSpec } from "./webrtcLink-BG0Xc4-W.js";
7
- import { a as resolveRemoteSpec, i as readRemotes } from "./remotes-oSmwSYaV.js";
5
+ import { a as recordOutbox, i as recordMessage, n as readMailbox, t as partyMatches } from "./messageLog-CxrKJj77.js";
6
+ import { t as loadSharedCliDefaults } from "./configShared-aKTg-sa5.js";
7
+ import { n as isWebrtcSpec } from "./webrtcLink-B7REGtK2.js";
8
+ import { a as resolveRemoteSpec, i as readRemotes } from "./remotes-Cim0dBU7.js";
8
9
  import ms from "ms";
9
10
  import yargs from "yargs";
10
11
  import { appendFile, mkdir, open, readFile, readdir, rename, rm, stat, writeFile } from "fs/promises";
@@ -161,94 +162,6 @@ function parseTaskCounts(lines) {
161
162
  return best;
162
163
  }
163
164
 
164
- //#endregion
165
- //#region ts/messageLog.ts
166
- /**
167
- * Durable inter-agent message log.
168
- *
169
- * Every `ay send` that carries a real body is recorded twice — from the two
170
- * ends' points of view — as append-only JSONL colocated with each agent's
171
- * project dir (the same `<cwd>/.agent-yes/` convention the session logs use):
172
- *
173
- * - the SENDER's `<from.cwd>/.agent-yes/outbox.jsonl`
174
- * - the RECIPIENT's `<to.cwd>/.agent-yes/inbox.jsonl`
175
- *
176
- * A single cwd may host several agents, so records carry the stable `agent_id`
177
- * (falling back to `pid`) of each end; `ay msgs` filters a mailbox down to one
178
- * agent by that key. Reading needs no lock (last line wins isn't relevant — a
179
- * message log keeps every entry); writing is best-effort and never blocks or
180
- * fails a send.
181
- */
182
- /** Keep at most this many lines per mailbox; older entries are compacted away. */
183
- const MAILBOX_MAX_LINES = 2e3;
184
- /** Path to a cwd's mailbox file (`<cwd>/.agent-yes/{inbox,outbox}.jsonl`). */
185
- function mailboxPath(cwd, box) {
186
- return path.join(cwd, ".agent-yes", `${box}.jsonl`);
187
- }
188
- /** Whether a mail party is the agent identified by (agentId, pid). Prefers the
189
- * stable agent_id (survives restart); falls back to pid for legacy records. */
190
- function partyMatches(party, agentId, pid) {
191
- if (!party) return false;
192
- if (agentId && party.agent_id && party.agent_id === agentId) return true;
193
- if (typeof pid === "number" && party.pid === pid) return true;
194
- return false;
195
- }
196
- async function appendCapped(filePath, record) {
197
- await mkdir(path.dirname(filePath), { recursive: true });
198
- await appendFile(filePath, JSON.stringify(record) + "\n");
199
- const lines = (await readFile(filePath, "utf-8").catch(() => "")).split("\n").filter((l) => l.trim());
200
- if (lines.length > MAILBOX_MAX_LINES) await writeFile(filePath, lines.slice(lines.length - MAILBOX_MAX_LINES).join("\n") + "\n");
201
- }
202
- /**
203
- * Record the SENDER's view in its outbox. Best-effort — a filesystem error is
204
- * logged and swallowed so persistence never breaks a send. The outbox lives
205
- * under `from.cwd`; a human sender (from === null) writes under `process.cwd()`.
206
- */
207
- async function recordOutbox(record) {
208
- const outCwd = record.from?.cwd ?? process.cwd();
209
- try {
210
- await appendCapped(mailboxPath(outCwd, "outbox"), record);
211
- } catch (err) {
212
- logger.debug(`[messageLog] outbox append failed: ${err}`);
213
- }
214
- }
215
- /** Record the RECIPIENT's view in its inbox (under `to.cwd`). Best-effort. */
216
- async function recordInbox(record) {
217
- try {
218
- await appendCapped(mailboxPath(record.to.cwd, "inbox"), record);
219
- } catch (err) {
220
- logger.debug(`[messageLog] inbox append failed: ${err}`);
221
- }
222
- }
223
- /**
224
- * Record a same-host message in both mailboxes — the sender's outbox and the
225
- * recipient's inbox both live on this machine. For a message that crossed the
226
- * wire, each end calls `recordOutbox`/`recordInbox` on its own host instead.
227
- */
228
- async function recordMessage(record) {
229
- await recordOutbox(record);
230
- await recordInbox(record);
231
- }
232
- /** Read and parse a cwd's mailbox, oldest first. Missing/corrupt lines skipped. */
233
- async function readMailbox(cwd, box) {
234
- let raw;
235
- try {
236
- raw = await readFile(mailboxPath(cwd, box), "utf-8");
237
- } catch {
238
- return [];
239
- }
240
- const out = [];
241
- for (const line of raw.split("\n")) {
242
- const t = line.trim();
243
- if (!t) continue;
244
- try {
245
- const rec = JSON.parse(t);
246
- if (rec && typeof rec.at === "number" && rec.to) out.push(rec);
247
- } catch {}
248
- }
249
- return out;
250
- }
251
-
252
165
  //#endregion
253
166
  //#region ts/badges.ts
254
167
  const BADGE_DEFS = [
@@ -1271,27 +1184,27 @@ async function runSubcommand(argv) {
1271
1184
  case "restart": return await cmdRestart(rest);
1272
1185
  case "note": return await cmdNote(rest);
1273
1186
  case "serve": {
1274
- const { cmdServe } = await import("./serve-Cp9XGHAg.js");
1187
+ const { cmdServe } = await import("./serve-C3E8uicL.js");
1275
1188
  return cmdServe(rest);
1276
1189
  }
1277
1190
  case "setup": {
1278
- const { cmdSetup } = await import("./setup-onV23tOF.js");
1191
+ const { cmdSetup } = await import("./setup-C4SKqGy1.js");
1279
1192
  return cmdSetup(rest);
1280
1193
  }
1281
1194
  case "schedule": {
1282
- const { cmdSchedule } = await import("./schedule-cvu-t8uo.js");
1195
+ const { cmdSchedule } = await import("./schedule-CjBcOy-b.js");
1283
1196
  return cmdSchedule(rest);
1284
1197
  }
1285
1198
  case "remote": {
1286
- const { cmdRemote } = await import("./remotes-CW-yxSgW.js");
1199
+ const { cmdRemote } = await import("./remotes-CXqYR0p8.js");
1287
1200
  return cmdRemote(rest);
1288
1201
  }
1289
1202
  case "expose": {
1290
- const { cmdExpose } = await import("./expose-B3AGhVhM.js");
1203
+ const { cmdExpose } = await import("./expose-k9l6ZJDA.js");
1291
1204
  return cmdExpose(rest);
1292
1205
  }
1293
1206
  case "reap":
1294
- await (await import("./reaper-jfSmog15.js")).sweep();
1207
+ await (await import("./reaper-CJSu8UVZ.js")).sweep();
1295
1208
  return 0;
1296
1209
  case "help": return cmdHelp(managerCommands);
1297
1210
  default: return null;
@@ -1703,7 +1616,7 @@ async function fetchRemoteRecordsRaw(url, token, opts) {
1703
1616
  let base = url;
1704
1617
  let bearer = token;
1705
1618
  if (isWebrtcSpec(url)) {
1706
- const { startWebrtcBridge } = await import("./webrtcRemote-BmuVKcrx.js");
1619
+ const { startWebrtcBridge } = await import("./webrtcRemote-CvIEfWX8.js");
1707
1620
  bridge = await startWebrtcBridge(url);
1708
1621
  base = bridge.baseUrl;
1709
1622
  bearer = bridge.token;
@@ -3222,7 +3135,8 @@ async function cmdMsgs(rest) {
3222
3135
  }
3223
3136
  for (const { dir, rec } of shown) {
3224
3137
  const when = new Date(rec.at).toLocaleTimeString();
3225
- const peer = dir === "out" ? `→ ${rec.to.cli} #${rec.to.pid}` : `← ${rec.from ? `${rec.from.cli} #${rec.from.pid}` : "human"}`;
3138
+ const fromLabel = rec.from ? `${rec.from.cli} #${rec.from.pid}` : rec.kind === "auto-retry" ? "agent-yes" : "human";
3139
+ const peer = dir === "out" ? `→ ${rec.to.cli} #${rec.to.pid}` : `← ${fromLabel}`;
3226
3140
  const via = rec.remote ? ` (via ${rec.remote})` : "";
3227
3141
  const flag = rec.confirmed === false ? " (unconfirmed)" : "";
3228
3142
  const line = (rec.kind ? `[${rec.kind}] ` : "") + truncate(rec.body.replace(/\s+/g, " "), 100);
@@ -4297,7 +4211,7 @@ async function cmdNotify(rest) {
4297
4211
  }
4298
4212
  const ensure = async () => {
4299
4213
  if (!argv["ensure-daemon"]) return;
4300
- const { ensureDaemon } = await import("./notifyDaemon-Cikn_qKr.js");
4214
+ const { ensureDaemon } = await import("./notifyDaemon-CRf_27kE.js");
4301
4215
  await ensureDaemon().catch(() => null);
4302
4216
  };
4303
4217
  await heartbeatWatcher(parent, selfStartedAt);
@@ -4371,7 +4285,7 @@ async function cmdNotifyCursor(args) {
4371
4285
  }
4372
4286
  async function cmdNotifyd(rest) {
4373
4287
  const sub = rest[0] ?? "status";
4374
- const daemon = await import("./notifyDaemon-Cikn_qKr.js");
4288
+ const daemon = await import("./notifyDaemon-CRf_27kE.js");
4375
4289
  switch (sub) {
4376
4290
  case "run": return daemon.runDaemon();
4377
4291
  case "once": return daemon.runDaemon({ once: true });
@@ -4397,5 +4311,5 @@ async function cmdNotifyd(rest) {
4397
4311
  }
4398
4312
 
4399
4313
  //#endregion
4400
- export { notifyDir as $, renderRawLog as A, submitAndConfirm as B, matchKeyword as C, recentMessageEdges as D, readPtysize as E, restartHintLines as F, gcInboxes as G, writeKeysPaced as H, runSubcommand as I, liveWatchers as J, hostId as K, snapshotStatus as L, resolveOne as M, resolveReadWindow as N, recentReadEdges as O, resolveResumeArgs as P, daemonLockOwnerPath as Q, stdinActivityPath as R, listRecords as S, readNotes as T, writeToIpc as U, waitForLogQuiet as V, appendEvent as W, shouldStealLock as X, readInbox as Y, daemonLockDir as Z, isPidAlive as _, cmdHelp as a, isUserTyping as b, deriveLiveState as c, extractMenu as d, TYPING_BADGE as et, extractNeedsInput as f, isExitRequest as g, isAgentStuck as h, backoffWhileTyping as i, renderRawLogLines as j, renderLogTailLines as k, deriveLiveStatus as l, finalizedLines as m, READ_PAGE_DEFAULT as n, controlCodeFromName as o, extractTaskCounts as p, listInboxParents as q, TYPING_WINDOW_MS as r, cursorAbs as s, GRACEFUL_EXIT_COMMANDS as t, recordInbox as tt, extractBadges as u, isSlashCommand as v, menuSelectKeys as w, lastStdinAt as x, isSubcommand as y, stopTipForCli as z };
4401
- //# sourceMappingURL=subcommands-Dwzo0rx_.js.map
4314
+ export { notifyDir as $, renderRawLog as A, submitAndConfirm as B, matchKeyword as C, recentMessageEdges as D, readPtysize as E, restartHintLines as F, gcInboxes as G, writeKeysPaced as H, runSubcommand as I, liveWatchers as J, hostId as K, snapshotStatus as L, resolveOne as M, resolveReadWindow as N, recentReadEdges as O, resolveResumeArgs as P, daemonLockOwnerPath as Q, stdinActivityPath as R, listRecords as S, readNotes as T, writeToIpc as U, waitForLogQuiet as V, appendEvent as W, shouldStealLock as X, readInbox as Y, daemonLockDir as Z, isPidAlive as _, cmdHelp as a, isUserTyping as b, deriveLiveState as c, extractMenu as d, TYPING_BADGE as et, extractNeedsInput as f, isExitRequest as g, isAgentStuck as h, backoffWhileTyping as i, renderRawLogLines as j, renderLogTailLines as k, deriveLiveStatus as l, finalizedLines as m, READ_PAGE_DEFAULT as n, controlCodeFromName as o, extractTaskCounts as p, listInboxParents as q, TYPING_WINDOW_MS as r, cursorAbs as s, GRACEFUL_EXIT_COMMANDS as t, extractBadges as u, isSlashCommand as v, menuSelectKeys as w, lastStdinAt as x, isSubcommand as y, stopTipForCli as z };
4315
+ //# sourceMappingURL=subcommands-B7UxIJRw.js.map
@@ -1,9 +1,10 @@
1
1
  import "./logger-CDIsZ-Pp.js";
2
2
  import "./globalPidIndex-CoNr7tS8.js";
3
- import "./configShared-0MnIQ652.js";
4
- import { A as renderRawLog, B as submitAndConfirm, C as matchKeyword, D as recentMessageEdges, E as readPtysize, F as restartHintLines, H as writeKeysPaced, I as runSubcommand, L as snapshotStatus, M as resolveOne, N as resolveReadWindow, O as recentReadEdges, P as resolveResumeArgs, R as stdinActivityPath, S as listRecords, T as readNotes, U as writeToIpc, V as waitForLogQuiet, _ as isPidAlive, a as cmdHelp, b as isUserTyping, c as deriveLiveState, d as extractMenu, f as extractNeedsInput, g as isExitRequest, h as isAgentStuck, i as backoffWhileTyping, j as renderRawLogLines, k as renderLogTailLines, l as deriveLiveStatus, m as finalizedLines, n as READ_PAGE_DEFAULT, o as controlCodeFromName, p as extractTaskCounts, r as TYPING_WINDOW_MS, s as cursorAbs, t as GRACEFUL_EXIT_COMMANDS, u as extractBadges, v as isSlashCommand, w as menuSelectKeys, x as lastStdinAt, y as isSubcommand, z as stopTipForCli } from "./subcommands-Dwzo0rx_.js";
5
- import "./e2e-BeKjLhmO.js";
6
- import "./webrtcLink-BG0Xc4-W.js";
7
- import "./remotes-oSmwSYaV.js";
3
+ import "./messageLog-CxrKJj77.js";
4
+ import "./configShared-aKTg-sa5.js";
5
+ import { A as renderRawLog, B as submitAndConfirm, C as matchKeyword, D as recentMessageEdges, E as readPtysize, F as restartHintLines, H as writeKeysPaced, I as runSubcommand, L as snapshotStatus, M as resolveOne, N as resolveReadWindow, O as recentReadEdges, P as resolveResumeArgs, R as stdinActivityPath, S as listRecords, T as readNotes, U as writeToIpc, V as waitForLogQuiet, _ as isPidAlive, a as cmdHelp, b as isUserTyping, c as deriveLiveState, d as extractMenu, f as extractNeedsInput, g as isExitRequest, h as isAgentStuck, i as backoffWhileTyping, j as renderRawLogLines, k as renderLogTailLines, l as deriveLiveStatus, m as finalizedLines, n as READ_PAGE_DEFAULT, o as controlCodeFromName, p as extractTaskCounts, r as TYPING_WINDOW_MS, s as cursorAbs, t as GRACEFUL_EXIT_COMMANDS, u as extractBadges, v as isSlashCommand, w as menuSelectKeys, x as lastStdinAt, y as isSubcommand, z as stopTipForCli } from "./subcommands-B7UxIJRw.js";
6
+ import "./e2e-jb0Hp43q.js";
7
+ import "./webrtcLink-B7REGtK2.js";
8
+ import "./remotes-Cim0dBU7.js";
8
9
 
9
10
  export { cmdHelp, isSubcommand, runSubcommand };
@@ -187,4 +187,4 @@ async function startTray() {
187
187
 
188
188
  //#endregion
189
189
  export { ensureTray, startTray };
190
- //# sourceMappingURL=tray-BKTZ5gIf.js.map
190
+ //# sourceMappingURL=tray-BSFi35Qg.js.map
@@ -1,10 +1,11 @@
1
1
  import { n as logger, t as addTransport } from "./logger-CDIsZ-Pp.js";
2
- import { r as getInstalledPackage } from "./versionChecker-ufJXjxRK.js";
2
+ import { r as getInstalledPackage } from "./versionChecker-DKiSuTSp.js";
3
3
  import { t as agentYesHome } from "./agentYesHome-CtHb5b71.js";
4
4
  import { i as shouldUseLock, r as releaseLock, t as acquireLock } from "./runningLock-CNMl13dC.js";
5
5
  import { t as PidStore } from "./pidStore-BIvsBQ8X.js";
6
6
  import { i as readGlobalPids } from "./globalPidIndex-CoNr7tS8.js";
7
- import { n as register, r as sweep } from "./reaper-CWF2_ATd.js";
7
+ import { r as recordInbox } from "./messageLog-CxrKJj77.js";
8
+ import { n as register, r as sweep } from "./reaper-BUHCyxdF.js";
8
9
  import { arch, platform } from "process";
9
10
  import { execSync } from "child_process";
10
11
  import { closeSync, constants, createReadStream, existsSync, mkdirSync, openSync } from "fs";
@@ -572,6 +573,64 @@ function autoRetryBackoffMs(streak) {
572
573
  function shouldFireRetry(working, ready, idleMs, minIdleMs) {
573
574
  return !working && ready && idleMs >= minIdleMs;
574
575
  }
576
+ /** Fallback reason when no autoRetry match was captured before firing. */
577
+ const AUTO_RETRY_REASON_FALLBACK = "a transient server-side error";
578
+ /**
579
+ * All reason strings `classifyAutoRetryReason` can produce — used by the
580
+ * self-trigger guard spec to prove every possible typed message is inert
581
+ * against every CLI's screen-scrape patterns. Mirrors Rust's RETRY_REASONS.
582
+ */
583
+ const AUTO_RETRY_REASONS = [
584
+ "the model backend reported it is temporarily busy",
585
+ "the response stream stalled mid-way",
586
+ "the connection dropped mid-response",
587
+ "a usage cap was reached (it may need time to reset)",
588
+ "requests are being throttled by the server",
589
+ AUTO_RETRY_REASON_FALLBACK
590
+ ];
591
+ /**
592
+ * Paraphrase the matched recoverable-error banner into a short reason.
593
+ *
594
+ * Deliberately NEVER echoes the raw banner wording ("API Error", "Overloaded",
595
+ * "rate limit", …): the built message is typed into the PTY and stays visible
596
+ * in the transcript, where raw wording would re-match the autoRetry patterns —
597
+ * keeping the error state true forever, which blocks the streak reset on
598
+ * recovery. Mirrors Rust's classify_retry_reason.
599
+ */
600
+ function classifyAutoRetryReason(screen) {
601
+ const s = screen.toLowerCase();
602
+ if (s.includes("overload")) return AUTO_RETRY_REASONS[0];
603
+ if (s.includes("stalled")) return AUTO_RETRY_REASONS[1];
604
+ if (s.includes("connection closed")) return AUTO_RETRY_REASONS[2];
605
+ if (s.includes("usage limit") || s.includes("session limit")) return AUTO_RETRY_REASONS[3];
606
+ if (s.includes("rate") && s.includes("limit")) return AUTO_RETRY_REASONS[4];
607
+ return AUTO_RETRY_REASON_FALLBACK;
608
+ }
609
+ /** Human-readable duration: "45s", "3m20s", "1h04m", "8h". Mirrors Rust's fmt_dur_secs. */
610
+ function formatDurationSecs(total) {
611
+ const t = Math.max(0, Math.floor(total));
612
+ if (t < 60) return `${t}s`;
613
+ if (t < 3600) {
614
+ const m = Math.floor(t / 60);
615
+ const s = t % 60;
616
+ return s === 0 ? `${m}m` : `${m}m${String(s).padStart(2, "0")}s`;
617
+ }
618
+ const h = Math.floor(t / 3600);
619
+ const m = Math.floor(t % 3600 / 60);
620
+ return m === 0 ? `${h}h` : `${h}h${String(m).padStart(2, "0")}m`;
621
+ }
622
+ /**
623
+ * The single line typed into the agent's prompt instead of a bare "retry":
624
+ * says WHO is nudging (agent-yes, automated), WHY (paraphrased reason), and
625
+ * the backoff state (attempt #, elapsed, next delay, give-up horizon), plus an
626
+ * explicit "ignore if nothing failed" clause so an agent that already
627
+ * recovered — or is mid-question — doesn't burn a turn asking what "retry"
628
+ * refers to. Must stay one line (it is submitted with a single "\r").
629
+ * Mirrors Rust's build_retry_message in rs/src/context.rs.
630
+ */
631
+ function buildAutoRetryMessage(attempt, reason, sinceFirstSecs, nextBackoffSecs) {
632
+ return `retry [auto-retry #${attempt} by agent-yes: ${reason}; first seen ${formatDurationSecs(sinceFirstSecs)} ago; if this attempt fails too, the next nudge comes in ${formatDurationSecs(nextBackoffSecs)} (giving up after ${formatDurationSecs(AUTO_RETRY_GIVE_UP_MS / 1e3)}). This is an automated recovery nudge - if no request actually failed, ignore it and simply continue your previous task.]`;
633
+ }
575
634
 
576
635
  //#endregion
577
636
  //#region ts/core/logging.ts
@@ -1084,7 +1143,7 @@ async function notifyWebhook(status, details, cwd = process.cwd()) {
1084
1143
 
1085
1144
  //#endregion
1086
1145
  //#region ts/index.ts
1087
- const config = await import("./agent-yes.config-ugPYTPOd.js").then((mod) => mod.default || mod);
1146
+ const config = await import("./agent-yes.config-whqkqq9P.js").then((mod) => mod.default || mod);
1088
1147
  const CLIS_CONFIG = config.clis;
1089
1148
  /**
1090
1149
  * Main function to run agent-cli with automatic yes/no responses
@@ -1517,6 +1576,7 @@ async function agentYes({ cli, cliArgs = [], skipPermissions = false, prompt, ro
1517
1576
  let retryStartedAt = null;
1518
1577
  let retryNextAt = null;
1519
1578
  let autoRetryScreen = "";
1579
+ let retryReason = null;
1520
1580
  const heartbeatInterval = setInterval(async () => {
1521
1581
  try {
1522
1582
  const rendered = removeControlCharacters(xtermProxy.tail(12));
@@ -1530,10 +1590,26 @@ async function agentYes({ cli, cliArgs = [], skipPermissions = false, prompt, ro
1530
1590
  } else if (now >= retryNextAt) if (!shouldFireRetry(conf.working?.some((rx) => rx.test(autoRetryScreen)) ?? false, conf.ready?.some((rx) => rx.test(autoRetryScreen)) ?? false, ctx.idleWaiter.idleTimeMs(), AUTO_RETRY_MIN_IDLE_MS)) retryNextAt = now + 500;
1531
1591
  else {
1532
1592
  retryStreak += 1;
1533
- logger.warn(`[${cli}-yes] auto-retry: typing 'retry' (attempt ${retryStreak})`);
1534
- ctx.messageContext.shell.write("retry\r");
1593
+ const nextBackoffMs = autoRetryBackoffMs(retryStreak);
1594
+ const reason = retryReason ?? AUTO_RETRY_REASON_FALLBACK;
1595
+ const sinceFirstSecs = retryStartedAt === null ? 0 : (now - retryStartedAt) / 1e3;
1596
+ const line = buildAutoRetryMessage(retryStreak, reason, sinceFirstSecs, nextBackoffMs / 1e3);
1597
+ logger.warn(`[${cli}-yes] auto-retry: typing retry nudge (attempt ${retryStreak}, reason: ${reason})`);
1598
+ ctx.messageContext.shell.write(line + "\r");
1535
1599
  ctx.idleWaiter.ping();
1536
- retryNextAt = now + autoRetryBackoffMs(retryStreak);
1600
+ recordInbox({
1601
+ at: now,
1602
+ from: null,
1603
+ to: {
1604
+ pid: process.pid,
1605
+ cli,
1606
+ cwd: workingDir
1607
+ },
1608
+ kind: "auto-retry",
1609
+ body: `${reason} (attempt ${retryStreak}, next backoff ${formatDurationSecs(nextBackoffMs / 1e3)})`,
1610
+ wrapped: false
1611
+ });
1612
+ retryNextAt = now + nextBackoffMs;
1537
1613
  }
1538
1614
  }
1539
1615
  if (rendered === lastHeartbeatRendered) return;
@@ -1738,6 +1814,7 @@ async function agentYes({ cli, cliArgs = [], skipPermissions = false, prompt, ro
1738
1814
  const errVisible = conf.autoRetry.some((rx) => rx.test(rendered));
1739
1815
  const readyVisible = conf.ready?.some((rx) => rx.test(rendered)) ?? false;
1740
1816
  if (errVisible && readyVisible) {
1817
+ retryReason = classifyAutoRetryReason(rendered);
1741
1818
  if (retryNextAt === null) {
1742
1819
  if (retryStartedAt === null) retryStartedAt = Date.now();
1743
1820
  const delayMs = autoRetryBackoffMs(retryStreak);
@@ -1824,4 +1901,4 @@ function sleep(ms) {
1824
1901
 
1825
1902
  //#endregion
1826
1903
  export { removeControlCharacters as a, AgentContext as i, agentYes as n, config as r, CLIS_CONFIG as t };
1827
- //# sourceMappingURL=ts-ml_9eD1Y.js.map
1904
+ //# sourceMappingURL=ts-B64pNQlI.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.196.2";
10
+ var version = "1.197.0";
11
11
 
12
12
  //#endregion
13
13
  //#region ts/versionChecker.ts
@@ -215,4 +215,4 @@ async function displayVersion() {
215
215
 
216
216
  //#endregion
217
217
  export { versionString as i, displayVersion as n, getInstalledPackage as r, checkAndAutoUpdate as t };
218
- //# sourceMappingURL=versionChecker-ufJXjxRK.js.map
218
+ //# sourceMappingURL=versionChecker-DKiSuTSp.js.map
@@ -1,4 +1,4 @@
1
- import { u as parseSecret } from "./e2e-BeKjLhmO.js";
1
+ import { u as parseSecret } from "./e2e-jb0Hp43q.js";
2
2
 
3
3
  //#region ts/webrtcLink.ts
4
4
  const SIGNAL_SUBPROTOCOL = "ay-signal-1";
@@ -42,4 +42,4 @@ function isWebrtcSpec(spec) {
42
42
 
43
43
  //#endregion
44
44
  export { isWebrtcSpec as n, parseWebrtcLink as r, SIGNAL_SUBPROTOCOL as t };
45
- //# sourceMappingURL=webrtcLink-BG0Xc4-W.js.map
45
+ //# sourceMappingURL=webrtcLink-B7REGtK2.js.map
@@ -1,5 +1,5 @@
1
- import { a as computeTranscriptHash, c as open, d as randomHex, f as seal, l as packEnvelope, n as FLAG_CONFIRM, o as deriveAuthToken, p as unpackEnvelope, s as deriveDirKeys } from "./e2e-BeKjLhmO.js";
2
- import { n as isWebrtcSpec, r as parseWebrtcLink, t as SIGNAL_SUBPROTOCOL } from "./webrtcLink-BG0Xc4-W.js";
1
+ import { a as computeTranscriptHash, c as open, d as randomHex, f as seal, l as packEnvelope, n as FLAG_CONFIRM, o as deriveAuthToken, p as unpackEnvelope, s as deriveDirKeys } from "./e2e-jb0Hp43q.js";
2
+ import { n as isWebrtcSpec, r as parseWebrtcLink, t as SIGNAL_SUBPROTOCOL } from "./webrtcLink-B7REGtK2.js";
3
3
  import { RTCPeerConnection } from "node-datachannel/polyfill";
4
4
 
5
5
  //#region ts/webrtcRemote.ts
@@ -256,4 +256,4 @@ async function startWebrtcBridge(link) {
256
256
 
257
257
  //#endregion
258
258
  export { startWebrtcBridge };
259
- //# sourceMappingURL=webrtcRemote-BmuVKcrx.js.map
259
+ //# sourceMappingURL=webrtcRemote-CvIEfWX8.js.map
@@ -193,4 +193,4 @@ function resolveSpawnCwd(input) {
193
193
 
194
194
  //#endregion
195
195
  export { getSpawnHook as a, hasProvisionHook as c, resolveSpawnCwd as d, setWorkspaceRoot as f, getProvisionRoot as i, hasSpawnHook as l, getMinFreeMb as n, getSpawnWaitMs as o, getProvisionHook as r, getWorkspaceRoot as s, getMaxAgents as t, isProvisionAllowed as u };
196
- //# sourceMappingURL=workspaceConfig-_GtAZtsi.js.map
196
+ //# sourceMappingURL=workspaceConfig-CjaRvTjf.js.map
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "agent-yes",
3
- "version": "1.196.2",
3
+ "version": "1.197.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",
@@ -1,5 +1,15 @@
1
1
  import { describe, expect, it } from "vitest";
2
- import { AUTO_RETRY_MAX_DELAY_SECS, autoRetryBackoffMs, shouldFireRetry } from "./autoRetry.ts";
2
+ import {
3
+ AUTO_RETRY_MAX_DELAY_SECS,
4
+ AUTO_RETRY_REASON_FALLBACK,
5
+ AUTO_RETRY_REASONS,
6
+ autoRetryBackoffMs,
7
+ buildAutoRetryMessage,
8
+ classifyAutoRetryReason,
9
+ formatDurationSecs,
10
+ shouldFireRetry,
11
+ } from "./autoRetry.ts";
12
+ import { loadSharedCliDefaults } from "./configShared.ts";
3
13
 
4
14
  describe("autoRetryBackoffMs", () => {
5
15
  it("doubles 8,16,32,…,256 then caps", () => {
@@ -32,3 +42,82 @@ describe("shouldFireRetry", () => {
32
42
  expect(shouldFireRetry(false, true, 10_000, 5_000)).toBe(true);
33
43
  });
34
44
  });
45
+
46
+ describe("classifyAutoRetryReason", () => {
47
+ it("maps real banners to inert paraphrases", () => {
48
+ expect(classifyAutoRetryReason("● API Error: 529 Overloaded")).toBe(AUTO_RETRY_REASONS[0]);
49
+ expect(classifyAutoRetryReason("API Error: Response stalled mid-stream.")).toBe(
50
+ AUTO_RETRY_REASONS[1],
51
+ );
52
+ expect(classifyAutoRetryReason("API Error: Connection closed mid-response.")).toBe(
53
+ AUTO_RETRY_REASONS[2],
54
+ );
55
+ expect(classifyAutoRetryReason("Claude usage limit reached")).toBe(AUTO_RETRY_REASONS[3]);
56
+ expect(classifyAutoRetryReason("You are being rate-limited")).toBe(AUTO_RETRY_REASONS[4]);
57
+ expect(classifyAutoRetryReason("API Error: 503 Service Unavailable")).toBe(
58
+ AUTO_RETRY_REASON_FALLBACK,
59
+ );
60
+ });
61
+ });
62
+
63
+ describe("formatDurationSecs", () => {
64
+ it("renders s / m / h forms", () => {
65
+ expect(formatDurationSecs(0)).toBe("0s");
66
+ expect(formatDurationSecs(45)).toBe("45s");
67
+ expect(formatDurationSecs(60)).toBe("1m");
68
+ expect(formatDurationSecs(200)).toBe("3m20s");
69
+ expect(formatDurationSecs(3600)).toBe("1h");
70
+ expect(formatDurationSecs(3900)).toBe("1h05m");
71
+ expect(formatDurationSecs(8 * 3600)).toBe("8h");
72
+ });
73
+ });
74
+
75
+ describe("buildAutoRetryMessage", () => {
76
+ it("is one line and carries attempt/reason/backoff context + ignore clause", () => {
77
+ const msg = buildAutoRetryMessage(3, AUTO_RETRY_REASONS[0], 45, 64);
78
+ expect(msg).not.toContain("\n");
79
+ expect(msg.startsWith("retry [")).toBe(true);
80
+ expect(msg).toContain("#3");
81
+ expect(msg).toContain("45s ago");
82
+ expect(msg).toContain("in 1m04s");
83
+ expect(msg).toContain("giving up after 8h");
84
+ expect(msg).toContain("ignore it");
85
+ });
86
+
87
+ // Self-trigger guard: the message is typed into the PTY and stays visible in
88
+ // the transcript, so if it ever matched a CLI's own screen-scrape patterns
89
+ // it would re-arm the retry loop (autoRetry), block the streak reset, kill
90
+ // the session (fatal), or fake a state (working/enter/needsInput). Mirrors
91
+ // rs/src/config.rs test_auto_retry_message_is_inert_against_all_cli_patterns.
92
+ it("never matches any CLI's screen-scrape patterns", async () => {
93
+ const clis = await loadSharedCliDefaults();
94
+ expect(Object.keys(clis).length).toBeGreaterThan(0);
95
+ for (const [cliName, conf] of Object.entries(clis)) {
96
+ for (const reason of AUTO_RETRY_REASONS) {
97
+ const cases: [number, number, number][] = [
98
+ [1, 0, 8],
99
+ [5, 500, 128],
100
+ [12, 30_000, 256],
101
+ ];
102
+ for (const [attempt, since, next] of cases) {
103
+ const msg = buildAutoRetryMessage(attempt, reason, since, next);
104
+ const groups: [string, RegExp[] | undefined][] = [
105
+ ["autoRetry", conf.autoRetry],
106
+ ["fatal", conf.fatal],
107
+ ["enter", conf.enter],
108
+ ["working", conf.working],
109
+ ["needsInput", conf.needsInput],
110
+ ];
111
+ for (const [kind, patterns] of groups) {
112
+ for (const rx of patterns ?? []) {
113
+ expect(
114
+ rx.test(msg),
115
+ `retry message must not match ${cliName}.${kind} /${rx}/: ${msg}`,
116
+ ).toBe(false);
117
+ }
118
+ }
119
+ }
120
+ }
121
+ }
122
+ });
123
+ });