agent-yes 1.196.3 → 1.198.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-Bhb4JKPv.js +9 -0
  3. package/dist/{SUPPORTED_CLIS-D3knhJ6_.js → SUPPORTED_CLIS-BuScRhc9.js} +2 -2
  4. package/dist/{agent-yes.config-ugPYTPOd.js → agent-yes.config-whqkqq9P.js} +2 -2
  5. package/dist/{agentShare-M6FE9AsI.js → agentShare-CD1AIPMR.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-DgxP6GAn.js → notifyDaemon-DYoMC4tA.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-C9q17obe.js → rustBinary-DLI26u3O.js} +2 -2
  21. package/dist/{schedule-SisMmURQ.js → schedule-DAl2mCc9.js} +7 -6
  22. package/dist/{serve-BOrkFR6H.js → serve-9jP4V1l_.js} +26 -25
  23. package/dist/{setup-CFbckIlf.js → setup-B55UN6xV.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-CMX-dej0.js → subcommands-D7AmlO_6.js} +24 -105
  29. package/dist/{subcommands-DSbYPDt5.js → subcommands-lUi22sO5.js} +6 -5
  30. package/dist/{tray-BKTZ5gIf.js → tray-BSFi35Qg.js} +1 -1
  31. package/dist/{ts-Bqa5HjY3.js → ts-D9RFyHqn.js} +84 -7
  32. package/dist/{versionChecker-ZIgviJ62.js → versionChecker-DQQIK4Og.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/dist/ws-BpHPhcPH.js +399 -0
  37. package/package.json +1 -1
  38. package/ts/autoRetry.spec.ts +90 -1
  39. package/ts/autoRetry.ts +76 -0
  40. package/ts/index.ts +37 -4
  41. package/ts/messageLog.ts +3 -2
  42. package/ts/subcommands.ts +20 -6
  43. package/ts/ws.spec.ts +435 -0
  44. package/ts/ws.ts +522 -0
  45. package/dist/SUPPORTED_CLIS-L3rJRumq.js +0 -8
@@ -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 = [
@@ -1214,7 +1127,7 @@ const SUBCOMMANDS = new Set([
1214
1127
  "reap",
1215
1128
  "help"
1216
1129
  ]);
1217
- const MANAGER_SUBCOMMANDS = new Set(["setup"]);
1130
+ const MANAGER_SUBCOMMANDS = new Set(["setup", "ws"]);
1218
1131
  const IDLE_THRESHOLD_MS = 60 * 1e3;
1219
1132
  const STUCK_THRESHOLD_MS = (() => {
1220
1133
  const n = Number(process.env.AGENT_YES_STUCK_MS);
@@ -1271,27 +1184,31 @@ 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-BOrkFR6H.js");
1187
+ const { cmdServe } = await import("./serve-9jP4V1l_.js");
1275
1188
  return cmdServe(rest);
1276
1189
  }
1277
1190
  case "setup": {
1278
- const { cmdSetup } = await import("./setup-CFbckIlf.js");
1191
+ const { cmdSetup } = await import("./setup-B55UN6xV.js");
1279
1192
  return cmdSetup(rest);
1280
1193
  }
1194
+ case "ws": {
1195
+ const { cmdWs } = await import("./ws-BpHPhcPH.js");
1196
+ return cmdWs(rest);
1197
+ }
1281
1198
  case "schedule": {
1282
- const { cmdSchedule } = await import("./schedule-SisMmURQ.js");
1199
+ const { cmdSchedule } = await import("./schedule-DAl2mCc9.js");
1283
1200
  return cmdSchedule(rest);
1284
1201
  }
1285
1202
  case "remote": {
1286
- const { cmdRemote } = await import("./remotes-CW-yxSgW.js");
1203
+ const { cmdRemote } = await import("./remotes-CXqYR0p8.js");
1287
1204
  return cmdRemote(rest);
1288
1205
  }
1289
1206
  case "expose": {
1290
- const { cmdExpose } = await import("./expose-B3AGhVhM.js");
1207
+ const { cmdExpose } = await import("./expose-k9l6ZJDA.js");
1291
1208
  return cmdExpose(rest);
1292
1209
  }
1293
1210
  case "reap":
1294
- await (await import("./reaper-jfSmog15.js")).sweep();
1211
+ await (await import("./reaper-CJSu8UVZ.js")).sweep();
1295
1212
  return 0;
1296
1213
  case "help": return cmdHelp(managerCommands);
1297
1214
  default: return null;
@@ -1322,9 +1239,10 @@ async function buildAgentContextSection(self) {
1322
1239
  }
1323
1240
  async function cmdHelp(managerCommands = true) {
1324
1241
  const setupLine = managerCommands ? ` ay setup guided setup: pick a workspace, share to agent-yes.com\n` : ``;
1242
+ const wsLines = managerCommands ? " ay ws ls [--status] list <owner>/<repo>/tree/<branch> workspaces\n ay ws new <owner>/<repo>[@branch] clone/refresh a workspace (ay ws help for more)\n" : ``;
1325
1243
  const self = process.env.AGENT_YES_PID ? await resolveSender() : null;
1326
1244
  const agentSection = self ? await buildAgentContextSection(self) : "";
1327
- process.stdout.write(agentSection + "ay - agent-yes CLI\n\nManagement:\n ay ls [keyword] list running agents\n ay tail [-f] [-n N] <keyword> last N lines (96), -f to follow\n ay read <keyword> [page opts] paginate: --last/--head N, --range A:B,\n --before-line L [--limit N]\n ay cat <keyword> full log\n ay head <keyword> first N lines\n ay send <keyword> <msg> send a message\n ay msgs [keyword] [--in|--out] inter-agent message log (sent + received)\n ay key <keyword> <key...> send raw keystrokes (down/up/enter/esc/…) — drives menus\n ay select <keyword> <N> pick option N of a needs_input selection menu\n ay attach <keyword> interactive attach (detach: Ctrl-\\)\n ay stop <keyword> graceful shutdown (/exit for claude/codex)\n ay exit <keyword> [reason] graceful shutdown, recording who/why (= 'ay send <kw> exit')\n ay restart <keyword> [--fresh] stop (if live) + relaunch resuming the session; --fresh replays the prompt\n ay status <keyword> agent status snapshot\n ay result <keyword> [--wait] pull an agent's structured result envelope\n ay result set '<json>' (inside an agent) deposit your result envelope\n ay reap kill process groups leaked by dead agents\n\nRemote:\n" + setupLine + " 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 expose <port> share localhost:<port> at https://<id>.agent-yes.com (private link)\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");
1245
+ process.stdout.write(agentSection + "ay - agent-yes CLI\n\nManagement:\n ay ls [keyword] list running agents\n ay tail [-f] [-n N] <keyword> last N lines (96), -f to follow\n ay read <keyword> [page opts] paginate: --last/--head N, --range A:B,\n --before-line L [--limit N]\n ay cat <keyword> full log\n ay head <keyword> first N lines\n ay send <keyword> <msg> send a message\n ay msgs [keyword] [--in|--out] inter-agent message log (sent + received)\n ay key <keyword> <key...> send raw keystrokes (down/up/enter/esc/…) — drives menus\n ay select <keyword> <N> pick option N of a needs_input selection menu\n ay attach <keyword> interactive attach (detach: Ctrl-\\)\n ay stop <keyword> graceful shutdown (/exit for claude/codex)\n ay exit <keyword> [reason] graceful shutdown, recording who/why (= 'ay send <kw> exit')\n ay restart <keyword> [--fresh] stop (if live) + relaunch resuming the session; --fresh replays the prompt\n ay status <keyword> agent status snapshot\n ay result <keyword> [--wait] pull an agent's structured result envelope\n ay result set '<json>' (inside an agent) deposit your result envelope\n ay reap kill process groups leaked by dead agents\n" + wsLines + "\nRemote:\n" + setupLine + " 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 expose <port> share localhost:<port> at https://<id>.agent-yes.com (private link)\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");
1328
1246
  return 0;
1329
1247
  }
1330
1248
  function matchKeyword(record, keyword) {
@@ -1703,7 +1621,7 @@ async function fetchRemoteRecordsRaw(url, token, opts) {
1703
1621
  let base = url;
1704
1622
  let bearer = token;
1705
1623
  if (isWebrtcSpec(url)) {
1706
- const { startWebrtcBridge } = await import("./webrtcRemote-BmuVKcrx.js");
1624
+ const { startWebrtcBridge } = await import("./webrtcRemote-CvIEfWX8.js");
1707
1625
  bridge = await startWebrtcBridge(url);
1708
1626
  base = bridge.baseUrl;
1709
1627
  bearer = bridge.token;
@@ -3222,7 +3140,8 @@ async function cmdMsgs(rest) {
3222
3140
  }
3223
3141
  for (const { dir, rec } of shown) {
3224
3142
  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"}`;
3143
+ const fromLabel = rec.from ? `${rec.from.cli} #${rec.from.pid}` : rec.kind === "auto-retry" ? "agent-yes" : "human";
3144
+ const peer = dir === "out" ? `→ ${rec.to.cli} #${rec.to.pid}` : `← ${fromLabel}`;
3226
3145
  const via = rec.remote ? ` (via ${rec.remote})` : "";
3227
3146
  const flag = rec.confirmed === false ? " (unconfirmed)" : "";
3228
3147
  const line = (rec.kind ? `[${rec.kind}] ` : "") + truncate(rec.body.replace(/\s+/g, " "), 100);
@@ -4297,7 +4216,7 @@ async function cmdNotify(rest) {
4297
4216
  }
4298
4217
  const ensure = async () => {
4299
4218
  if (!argv["ensure-daemon"]) return;
4300
- const { ensureDaemon } = await import("./notifyDaemon-DgxP6GAn.js");
4219
+ const { ensureDaemon } = await import("./notifyDaemon-DYoMC4tA.js");
4301
4220
  await ensureDaemon().catch(() => null);
4302
4221
  };
4303
4222
  await heartbeatWatcher(parent, selfStartedAt);
@@ -4371,7 +4290,7 @@ async function cmdNotifyCursor(args) {
4371
4290
  }
4372
4291
  async function cmdNotifyd(rest) {
4373
4292
  const sub = rest[0] ?? "status";
4374
- const daemon = await import("./notifyDaemon-DgxP6GAn.js");
4293
+ const daemon = await import("./notifyDaemon-DYoMC4tA.js");
4375
4294
  switch (sub) {
4376
4295
  case "run": return daemon.runDaemon();
4377
4296
  case "once": return daemon.runDaemon({ once: true });
@@ -4397,5 +4316,5 @@ async function cmdNotifyd(rest) {
4397
4316
  }
4398
4317
 
4399
4318
  //#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-CMX-dej0.js.map
4319
+ 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 };
4320
+ //# sourceMappingURL=subcommands-D7AmlO_6.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-CMX-dej0.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-D7AmlO_6.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-ZIgviJ62.js";
2
+ import { r as getInstalledPackage } from "./versionChecker-DQQIK4Og.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-Bqa5HjY3.js.map
1904
+ //# sourceMappingURL=ts-D9RFyHqn.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.3";
10
+ var version = "1.198.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-ZIgviJ62.js.map
218
+ //# sourceMappingURL=versionChecker-DQQIK4Og.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