claude-yes 1.168.0 → 1.169.1

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 (42) hide show
  1. package/dist/{SUPPORTED_CLIS-D0nNJGNj.js → SUPPORTED_CLIS-CrkCHeYI.js} +2 -2
  2. package/dist/SUPPORTED_CLIS-D6axJyiC.js +8 -0
  3. package/dist/cli.js +47 -6
  4. package/dist/{e2e-Bfw7qL9O.js → e2e-BeKjLhmO.js} +1 -1
  5. package/dist/forkNested-UCKPEgSI.js +59 -0
  6. package/dist/index.js +2 -2
  7. package/dist/{openBrowser-CuOlFtow.js → openBrowser-CCF1iuQK.js} +1 -1
  8. package/dist/{remotes-T6nf0t3K.js → remotes-BmAPylU_.js} +3 -3
  9. package/dist/{remotes-ClT1bq16.js → remotes-cx_GDFPj.js} +3 -3
  10. package/dist/{runningLock-V4qvXgAw.js → runningLock-BobVW1_A.js} +2 -1
  11. package/dist/{schedule-BPUyALF_.js → schedule-Bh5bm1xO.js} +5 -5
  12. package/dist/{serve-DAuLdt_d.js → serve-Bt_KljpT.js} +34 -15
  13. package/dist/{setup-YLHUtCC0.js → setup-D5f1lmYF.js} +3 -3
  14. package/dist/{share-BjqQBWM-.js → share-D_e2Fwiy.js} +2 -2
  15. package/dist/{spawnGate-UH73I2le.js → spawnGate-CQ1Il3Xk.js} +1 -1
  16. package/dist/{spawnGate-B_VDMXYL.js → spawnGate-DzPfa1PZ.js} +2 -2
  17. package/dist/subcommands-B23lSYPq.js +9 -0
  18. package/dist/{subcommands-VimbMSTG.js → subcommands-fp7kfr7p.js} +45 -11
  19. package/dist/{tray-CZarCA2Q.js → tray-CWUpaZF4.js} +2 -2
  20. package/dist/{ts-DBwi5BWW.js → ts-hUFVxJMw.js} +5 -5
  21. package/dist/{versionChecker-DVv-WHIp.js → versionChecker-IuFreIkZ.js} +2 -2
  22. package/dist/{webrtcLink-CBZkZ-LT.js → webrtcLink-BG0Xc4-W.js} +2 -2
  23. package/dist/{webrtcRemote-GAgF5K45.js → webrtcRemote-SybKurg9.js} +3 -3
  24. package/dist/{workspaceConfig-D3OH7and.js → workspaceConfig-BC03X4Y1.js} +1 -1
  25. package/lab/ui/console-logic.js +16 -0
  26. package/lab/ui/index.html +28 -0
  27. package/package.json +1 -1
  28. package/ts/badges.spec.ts +54 -0
  29. package/ts/badges.ts +42 -0
  30. package/ts/cli.ts +46 -0
  31. package/ts/forkNested.spec.ts +34 -0
  32. package/ts/forkNested.ts +64 -0
  33. package/ts/index.ts +13 -4
  34. package/ts/needsInput.ts +1 -1
  35. package/ts/parseCliArgs.spec.ts +18 -0
  36. package/ts/parseCliArgs.ts +8 -0
  37. package/ts/runningLock.ts +1 -0
  38. package/ts/serve.ts +24 -0
  39. package/ts/subcommands.spec.ts +22 -0
  40. package/ts/subcommands.ts +40 -13
  41. package/dist/SUPPORTED_CLIS-Dy_o9sj6.js +0 -8
  42. package/dist/subcommands-B2QAXBkH.js +0 -9
@@ -1,8 +1,8 @@
1
- import { t as CLIS_CONFIG } from "./ts-DBwi5BWW.js";
1
+ import { t as CLIS_CONFIG } from "./ts-hUFVxJMw.js";
2
2
 
3
3
  //#region ts/SUPPORTED_CLIS.ts
4
4
  const SUPPORTED_CLIS = Object.keys(CLIS_CONFIG);
5
5
 
6
6
  //#endregion
7
7
  export { SUPPORTED_CLIS as t };
8
- //# sourceMappingURL=SUPPORTED_CLIS-D0nNJGNj.js.map
8
+ //# sourceMappingURL=SUPPORTED_CLIS-CrkCHeYI.js.map
@@ -0,0 +1,8 @@
1
+ import "./ts-hUFVxJMw.js";
2
+ import "./logger-CDIsZ-Pp.js";
3
+ import "./versionChecker-IuFreIkZ.js";
4
+ import "./pidStore-BfoBWUjc.js";
5
+ import "./globalPidIndex-DlmmJlO8.js";
6
+ import { t as SUPPORTED_CLIS } from "./SUPPORTED_CLIS-CrkCHeYI.js";
7
+
8
+ export { SUPPORTED_CLIS };
package/dist/cli.js CHANGED
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env bun
2
2
  import { t as invokedCliName } from "./invokedCli-uqM2YYA7.js";
3
3
  import { n as logger } from "./logger-CDIsZ-Pp.js";
4
- import { i as versionString, n as displayVersion, r as getInstalledPackage, t as checkAndAutoUpdate } from "./versionChecker-DVv-WHIp.js";
4
+ import { i as versionString, n as displayVersion, r as getInstalledPackage, t as checkAndAutoUpdate } from "./versionChecker-IuFreIkZ.js";
5
5
  import { argv } from "process";
6
6
  import { execFileSync, spawn } from "child_process";
7
7
  import ms from "ms";
@@ -23,6 +23,11 @@ function parseCliArgs(argv, supportedClis) {
23
23
  default: true,
24
24
  description: "re-spawn Claude with --continue if it crashes, only works for claude yet",
25
25
  alias: "r"
26
+ }).option("attach", {
27
+ type: "boolean",
28
+ default: false,
29
+ description: "Run the agent in the foreground even when nested inside another agent (disables fork-by-default; also AGENT_YES_ATTACH=1).",
30
+ alias: "foreground"
26
31
  }).option("logFile", {
27
32
  type: "string",
28
33
  description: "Rendered log file to write to."
@@ -218,6 +223,7 @@ function parseCliArgs(argv, supportedClis) {
218
223
  exitOnIdle: Number((parsedArgv.timeout || parsedArgv.idle || parsedArgv.exitOnIdle)?.replace(/.*/, (e) => String(ms(e))) || 0),
219
224
  queue: parsedArgv.queue,
220
225
  robust: parsedArgv.robust,
226
+ attach: parsedArgv.attach,
221
227
  logFile: parsedArgv.logFile,
222
228
  verbose: parsedArgv.verbose,
223
229
  resume: parsedArgv.continue,
@@ -481,7 +487,7 @@ function buildRustArgs(argv, cliFromScript, supportedClis) {
481
487
  const rawArg = process.argv[2];
482
488
  const managerCommands = !invokedCliName(process.argv);
483
489
  const isHelpFlag = rawArg === "-h" || rawArg === "--help";
484
- const { isSubcommand, runSubcommand, cmdHelp } = await import("./subcommands-B2QAXBkH.js");
490
+ const { isSubcommand, runSubcommand, cmdHelp } = await import("./subcommands-B23lSYPq.js");
485
491
  if (isHelpFlag && process.argv.length === 3) {
486
492
  await cmdHelp(managerCommands);
487
493
  process.exit(0);
@@ -495,16 +501,16 @@ await checkAndAutoUpdate();
495
501
  logger.info(versionString());
496
502
  const config = parseCliArgs(process.argv);
497
503
  if (config.tray) {
498
- const { startTray } = await import("./tray-CZarCA2Q.js");
504
+ const { startTray } = await import("./tray-CWUpaZF4.js");
499
505
  await startTray();
500
506
  await new Promise(() => {});
501
507
  }
502
508
  {
503
- const { ensureTray } = await import("./tray-CZarCA2Q.js");
509
+ const { ensureTray } = await import("./tray-CWUpaZF4.js");
504
510
  ensureTray();
505
511
  }
506
512
  if (!config.showVersion && !config.appendPrompt && !config.tray) {
507
- const { waitForSpawnCapacity } = await import("./spawnGate-UH73I2le.js");
513
+ const { waitForSpawnCapacity } = await import("./spawnGate-CQ1Il3Xk.js");
508
514
  await waitForSpawnCapacity({
509
515
  onWait: (reason, waitedMs) => {
510
516
  if (config.verbose || waitedMs === 0) console.error(`[agent-yes] spawn gate: ${reason} — waiting…`);
@@ -523,12 +529,47 @@ if (config.useRust) {
523
529
  }
524
530
  }
525
531
  if (rustBinary) {
526
- const { SUPPORTED_CLIS } = await import("./SUPPORTED_CLIS-Dy_o9sj6.js");
532
+ const { SUPPORTED_CLIS } = await import("./SUPPORTED_CLIS-D6axJyiC.js");
527
533
  const rustArgs = buildRustArgs(process.argv, config.cli, SUPPORTED_CLIS);
528
534
  if (config.verbose) {
529
535
  console.log(`[rust] Using binary: ${rustBinary}`);
530
536
  console.log(`[rust] Args: ${rustArgs.join(" ")}`);
531
537
  }
538
+ const attach = config.attach || process.env.AGENT_YES_ATTACH === "1";
539
+ const { shouldForkNested, buildSpawnTutorial, waitForFifo } = await import("./forkNested-UCKPEgSI.js");
540
+ if (shouldForkNested({
541
+ isTTY: Boolean(process.stdout.isTTY),
542
+ ayPid: process.env.AGENT_YES_PID,
543
+ attach
544
+ })) {
545
+ const forked = spawn(rustBinary, rustArgs, {
546
+ detached: true,
547
+ stdio: "ignore",
548
+ env: process.env,
549
+ cwd: process.cwd()
550
+ });
551
+ const forkedPid = forked.pid;
552
+ if (!forkedPid) {
553
+ console.error("Failed to spawn agent: no pid.");
554
+ process.exit(1);
555
+ }
556
+ let deathMsg = null;
557
+ forked.on("error", (err) => {
558
+ deathMsg ??= `Failed to spawn agent: ${err.message}`;
559
+ });
560
+ forked.on("exit", (code, signal) => {
561
+ deathMsg ??= `Agent exited immediately (${signal ?? `code ${code}`}). See: ay tail ${forkedPid}`;
562
+ });
563
+ const registered = await waitForFifo(forkedPid, 2e3, () => deathMsg !== null);
564
+ if (deathMsg) {
565
+ console.error(deathMsg);
566
+ process.exit(1);
567
+ }
568
+ forked.unref();
569
+ console.log(buildSpawnTutorial(config.cli || "agent", forkedPid));
570
+ if (!registered) console.log(`(note: still registering — give ay send/tail a moment)`);
571
+ process.exit(0);
572
+ }
532
573
  const child = spawn(rustBinary, rustArgs, {
533
574
  stdio: "inherit",
534
575
  env: process.env,
@@ -172,4 +172,4 @@ function randomHex(n) {
172
172
 
173
173
  //#endregion
174
174
  export { computeTranscriptHash as a, open as c, randomHex as d, seal as f, MAX_CHUNK as i, packEnvelope as l, FLAG_CONFIRM as n, deriveAuthToken as o, unpackEnvelope as p, MARKER as r, deriveDirKeys as s, CONFIRM_TIMEOUT_MS as t, parseSecret as u };
175
- //# sourceMappingURL=e2e-Bfw7qL9O.js.map
175
+ //# sourceMappingURL=e2e-BeKjLhmO.js.map
@@ -0,0 +1,59 @@
1
+ import { t as agentYesHome } from "./agentYesHome-_eJa3DaX.js";
2
+ import { existsSync } from "fs";
3
+ import path from "path";
4
+
5
+ //#region ts/forkNested.ts
6
+ /**
7
+ * Should a nested agent-run detach (fork) instead of blocking the caller?
8
+ *
9
+ * A claude/codex agent that runs `ay <cli> -- <task>` inside its Bash tool would
10
+ * otherwise block that Bash call for the whole (possibly very long) session and
11
+ * time out. When we detect that context we spawn the agent detached, print a
12
+ * tutorial, and return immediately so the parent stays responsive.
13
+ *
14
+ * The context is: we are NESTED inside another agent (`AGENT_YES_PID` is injected
15
+ * into an agent's environment by its wrapper — a human shell never has it) AND
16
+ * stdout is not a TTY (captured/piped, e.g. a tool's Bash). A human piping output
17
+ * (`ay claude | cat`) has no `AGENT_YES_PID`, so they still block as before.
18
+ * `attach` (the `--attach` flag or `AGENT_YES_ATTACH=1`) forces foreground.
19
+ */
20
+ function shouldForkNested(opts) {
21
+ if (opts.attach) return false;
22
+ if (opts.isTTY) return false;
23
+ return Boolean(opts.ayPid && opts.ayPid.trim());
24
+ }
25
+ /** The tutorial printed to the parent agent after a detached spawn, telling it
26
+ * exactly how to drive the agent it just started. */
27
+ function buildSpawnTutorial(cli, pid) {
28
+ return [
29
+ `Spawned ${cli} agent as pid ${pid} (detached — this shell returned immediately).`,
30
+ `It runs in the background; drive it with:`,
31
+ ` ay tail ${pid} # watch its output (live)`,
32
+ ` ay send ${pid} "..." # send it a message / instruction`,
33
+ ` ay send ${pid} /compact # send a slash command`,
34
+ ` ay ls # list running agents`,
35
+ ` ay result get ${pid} # read its final result when done`,
36
+ ` ay exit ${pid} # stop it`
37
+ ].join("\n");
38
+ }
39
+ /**
40
+ * Poll for the spawned wrapper's stdin FIFO to appear, so the tutorial's
41
+ * `ay send`/`ay tail` work the instant we print them (the wrapper registers its
42
+ * FIFO a moment after spawn). Resolves true once registered, false on timeout or
43
+ * if `aborted()` reports the child already died (so a startup failure fails fast
44
+ * instead of waiting out the whole window).
45
+ */
46
+ async function waitForFifo(pid, timeoutMs = 2e3, aborted) {
47
+ const fifo = path.join(agentYesHome(), "fifo", `${pid}.stdin`);
48
+ const deadline = Date.now() + timeoutMs;
49
+ while (Date.now() < deadline) {
50
+ if (aborted?.()) return false;
51
+ if (existsSync(fifo)) return true;
52
+ await new Promise((r) => setTimeout(r, 50));
53
+ }
54
+ return existsSync(fifo);
55
+ }
56
+
57
+ //#endregion
58
+ export { buildSpawnTutorial, shouldForkNested, waitForFifo };
59
+ //# sourceMappingURL=forkNested-UCKPEgSI.js.map
package/dist/index.js CHANGED
@@ -1,6 +1,6 @@
1
- import { a as removeControlCharacters, i as AgentContext, n as agentYes, r as config, t as CLIS_CONFIG } from "./ts-DBwi5BWW.js";
1
+ import { a as removeControlCharacters, i as AgentContext, n as agentYes, r as config, t as CLIS_CONFIG } from "./ts-hUFVxJMw.js";
2
2
  import "./logger-CDIsZ-Pp.js";
3
- import "./versionChecker-DVv-WHIp.js";
3
+ import "./versionChecker-IuFreIkZ.js";
4
4
  import "./pidStore-BfoBWUjc.js";
5
5
  import "./globalPidIndex-DlmmJlO8.js";
6
6
 
@@ -68,4 +68,4 @@ async function offerOpenInBrowser(url, prompt = "Open in browser now? [Y/n] ") {
68
68
 
69
69
  //#endregion
70
70
  export { offerOpenInBrowser };
71
- //# sourceMappingURL=openBrowser-CuOlFtow.js.map
71
+ //# sourceMappingURL=openBrowser-CCF1iuQK.js.map
@@ -1,4 +1,4 @@
1
- import { n as isWebrtcSpec } from "./webrtcLink-CBZkZ-LT.js";
1
+ import { n as isWebrtcSpec } from "./webrtcLink-BG0Xc4-W.js";
2
2
  import { mkdir, readFile, writeFile } from "fs/promises";
3
3
  import { homedir } from "os";
4
4
  import path from "path";
@@ -86,7 +86,7 @@ async function resolveRemoteSpec(spec) {
86
86
  * The bridge lives for the rest of the process (torn down on `process.exit`).
87
87
  */
88
88
  async function resolveWebrtc(link, keyword) {
89
- const { startWebrtcBridge } = await import("./webrtcRemote-GAgF5K45.js");
89
+ const { startWebrtcBridge } = await import("./webrtcRemote-SybKurg9.js");
90
90
  const bridge = await startWebrtcBridge(link);
91
91
  return {
92
92
  url: bridge.baseUrl,
@@ -173,4 +173,4 @@ async function cmdRemote(rest) {
173
173
 
174
174
  //#endregion
175
175
  export { resolveRemoteSpec as a, readRemotes as i, deleteRemoteAlias as n, writeRemoteAlias as o, parseDirectRemoteSpec as r, cmdRemote as t };
176
- //# sourceMappingURL=remotes-T6nf0t3K.js.map
176
+ //# sourceMappingURL=remotes-BmAPylU_.js.map
@@ -1,5 +1,5 @@
1
- import "./e2e-Bfw7qL9O.js";
2
- import "./webrtcLink-CBZkZ-LT.js";
3
- import { a as resolveRemoteSpec, i as readRemotes, n as deleteRemoteAlias, o as writeRemoteAlias, r as parseDirectRemoteSpec, t as cmdRemote } from "./remotes-T6nf0t3K.js";
1
+ import "./e2e-BeKjLhmO.js";
2
+ import "./webrtcLink-BG0Xc4-W.js";
3
+ import { a as resolveRemoteSpec, i as readRemotes, n as deleteRemoteAlias, o as writeRemoteAlias, r as parseDirectRemoteSpec, t as cmdRemote } from "./remotes-BmAPylU_.js";
4
4
 
5
5
  export { cmdRemote };
@@ -134,6 +134,7 @@ async function checkLock(cwd, _prompt) {
134
134
  const gitRoot = isGitRepo(resolvedCwd) ? getGitRoot(resolvedCwd) : null;
135
135
  const lockKey = gitRoot || resolvedCwd;
136
136
  const blockingTasks = (await readLockFile()).tasks.filter((task) => {
137
+ if (task.pid === process.pid) return false;
137
138
  if (!isProcessRunning(task.pid)) return false;
138
139
  if (task.status !== "running") return false;
139
140
  if (gitRoot && task.gitRoot) return task.gitRoot === gitRoot;
@@ -276,4 +277,4 @@ function shouldUseLock(_cwd) {
276
277
 
277
278
  //#endregion
278
279
  export { shouldUseLock as i, getRunningAgentCount as n, releaseLock as r, acquireLock as t };
279
- //# sourceMappingURL=runningLock-V4qvXgAw.js.map
280
+ //# sourceMappingURL=runningLock-BobVW1_A.js.map
@@ -1,10 +1,10 @@
1
- import "./ts-DBwi5BWW.js";
1
+ import "./ts-hUFVxJMw.js";
2
2
  import "./logger-CDIsZ-Pp.js";
3
- import "./versionChecker-DVv-WHIp.js";
3
+ import "./versionChecker-IuFreIkZ.js";
4
4
  import "./pidStore-BfoBWUjc.js";
5
5
  import "./globalPidIndex-DlmmJlO8.js";
6
- import { t as SUPPORTED_CLIS } from "./SUPPORTED_CLIS-D0nNJGNj.js";
7
- import { l as resolveSpawnCwd } from "./workspaceConfig-D3OH7and.js";
6
+ import { t as SUPPORTED_CLIS } from "./SUPPORTED_CLIS-CrkCHeYI.js";
7
+ import { l as resolveSpawnCwd } from "./workspaceConfig-BC03X4Y1.js";
8
8
  import { createHash } from "node:crypto";
9
9
 
10
10
  //#region ts/oxmgrService.ts
@@ -141,4 +141,4 @@ async function cmdSchedule(rest) {
141
141
 
142
142
  //#endregion
143
143
  export { cmdSchedule };
144
- //# sourceMappingURL=schedule-BPUyALF_.js.map
144
+ //# sourceMappingURL=schedule-Bh5bm1xO.js.map
@@ -1,17 +1,17 @@
1
- import "./ts-DBwi5BWW.js";
1
+ import "./ts-hUFVxJMw.js";
2
2
  import "./logger-CDIsZ-Pp.js";
3
- import { r as getInstalledPackage } from "./versionChecker-DVv-WHIp.js";
3
+ import { r as getInstalledPackage } from "./versionChecker-IuFreIkZ.js";
4
4
  import "./pidStore-BfoBWUjc.js";
5
5
  import { a as updateGlobalPidStatus } from "./globalPidIndex-DlmmJlO8.js";
6
6
  import { t as pgidForWrapper } from "./reaper-C-eWAxIj.js";
7
7
  import "./configShared-CEyhl0WH.js";
8
- import { t as SUPPORTED_CLIS } from "./SUPPORTED_CLIS-D0nNJGNj.js";
9
- import "./e2e-Bfw7qL9O.js";
10
- import "./webrtcLink-CBZkZ-LT.js";
11
- import "./remotes-T6nf0t3K.js";
12
- import { c as isProvisionAllowed, i as getSpawnHook, l as resolveSpawnCwd, r as getProvisionRoot, s as hasSpawnHook } from "./workspaceConfig-D3OH7and.js";
13
- import { A as writeToIpc, D as snapshotStatus, S as resolveOne, b as renderRawLog, c as extractNeedsInput, h as listRecords, i as controlCodeFromName, l as extractTaskCounts, o as deriveLiveStatus, v as readNotes, y as readPtysize } from "./subcommands-VimbMSTG.js";
14
- import { r as spawnRejectionReason } from "./spawnGate-B_VDMXYL.js";
8
+ import { t as SUPPORTED_CLIS } from "./SUPPORTED_CLIS-CrkCHeYI.js";
9
+ import "./e2e-BeKjLhmO.js";
10
+ import "./webrtcLink-BG0Xc4-W.js";
11
+ import "./remotes-BmAPylU_.js";
12
+ import { c as isProvisionAllowed, i as getSpawnHook, l as resolveSpawnCwd, r as getProvisionRoot, s as hasSpawnHook } from "./workspaceConfig-BC03X4Y1.js";
13
+ import { M as writeToIpc, S as renderRawLog, _ as listRecords, b as readNotes, i as controlCodeFromName, k as snapshotStatus, l as extractNeedsInput, o as deriveLiveStatus, s as extractBadges, u as extractTaskCounts, w as resolveOne, x as readPtysize } from "./subcommands-fp7kfr7p.js";
14
+ import { r as spawnRejectionReason } from "./spawnGate-DzPfa1PZ.js";
15
15
  import yargs from "yargs";
16
16
  import { mkdir, open, readFile, stat, unlink, writeFile } from "fs/promises";
17
17
  import { homedir, hostname, userInfo } from "os";
@@ -308,7 +308,7 @@ async function cmdServeDaemon(sub, args) {
308
308
  let shareLink = null;
309
309
  let shareLinkMinted = false;
310
310
  if (webrtcDaemon) try {
311
- const { loadOrCreateShareRoom, shareLinkFromRoomUrl } = await import("./share-BjqQBWM-.js");
311
+ const { loadOrCreateShareRoom, shareLinkFromRoomUrl } = await import("./share-D_e2Fwiy.js");
312
312
  const explicit = explicitWebrtcUrl(effArgs);
313
313
  shareLink = shareLinkFromRoomUrl(explicit ?? await loadOrCreateShareRoom());
314
314
  shareLinkMinted = !explicit;
@@ -317,7 +317,7 @@ async function cmdServeDaemon(sub, args) {
317
317
  if (!webrtcDaemon) return;
318
318
  if (shareLink) {
319
319
  process.stdout.write(`\nshared over WebRTC — open this link (the token is eaten from the URL on open):\n ${shareLink}\n` + (shareLinkMinted ? ` (persistent room — same link across restarts; delete ~/.agent-yes/.share-room to rotate)\n` : ``));
320
- const { offerOpenInBrowser } = await import("./openBrowser-CuOlFtow.js");
320
+ const { offerOpenInBrowser } = await import("./openBrowser-CCF1iuQK.js");
321
321
  await offerOpenInBrowser(shareLink);
322
322
  } else process.stdout.write("\nthe WebRTC share link carries a secret, so the daemon does NOT log it —\nread it from ~/.agent-yes/.share-link (mode 0600). The room persists in\n~/.agent-yes/.share-room, so the link survives restarts.\n");
323
323
  };
@@ -626,6 +626,24 @@ Options:
626
626
  return null;
627
627
  }
628
628
  };
629
+ const badgeCache = /* @__PURE__ */ new Map();
630
+ const logBadges = async (logFile) => {
631
+ if (!logFile) return [];
632
+ try {
633
+ const { size, mtimeMs } = await stat(logFile);
634
+ const hit = badgeCache.get(logFile);
635
+ if (hit && hit.size === size && hit.mtimeMs === mtimeMs) return hit.badges;
636
+ const badges = await extractBadges(logFile);
637
+ badgeCache.set(logFile, {
638
+ size,
639
+ mtimeMs,
640
+ badges
641
+ });
642
+ return badges;
643
+ } catch {
644
+ return [];
645
+ }
646
+ };
629
647
  const niCache = /* @__PURE__ */ new Map();
630
648
  const logNeedsInput = async (logFile, cli) => {
631
649
  if (!logFile) return null;
@@ -769,7 +787,8 @@ Options:
769
787
  question,
770
788
  title: await logTitle(r.log_file),
771
789
  git: status === "exited" ? null : await gitStatus(r.cwd),
772
- tasks: status === "exited" ? null : await logTasks(r.log_file)
790
+ tasks: status === "exited" ? null : await logTasks(r.log_file),
791
+ badges: status === "exited" ? [] : await logBadges(r.log_file)
773
792
  };
774
793
  };
775
794
  const presence = /* @__PURE__ */ new Map();
@@ -1386,7 +1405,7 @@ Options:
1386
1405
  const webrtcVal = argv.webrtc ?? argv.share;
1387
1406
  const explicitUrl = typeof webrtcVal === "string" && webrtcVal.startsWith("webrtc://") ? webrtcVal : void 0;
1388
1407
  try {
1389
- const { startShare, loadOrCreateShareRoom } = await import("./share-BjqQBWM-.js");
1408
+ const { startShare, loadOrCreateShareRoom } = await import("./share-D_e2Fwiy.js");
1390
1409
  const linkFile = path.join(process.env.AGENT_YES_HOME ?? path.join(homedir(), ".agent-yes"), ".share-link");
1391
1410
  const announce = async (room, link, rotated) => {
1392
1411
  const lead = rotated ? "the room was rejected by signaling (stale generation) — rotated to a fresh link" : "shared over WebRTC — open this link (the token is eaten from the URL on open)";
@@ -1394,7 +1413,7 @@ Options:
1394
1413
  const persistNote = explicitUrl ? "\n" : ` (persistent room — same link across restarts; delete ~/.agent-yes/.share-room to rotate)\n\n`;
1395
1414
  process.stdout.write(`${wantHttp ? "\n" : ""}${lead}:\n ${link}\n` + persistNote);
1396
1415
  if (!rotated) {
1397
- const { offerOpenInBrowser } = await import("./openBrowser-CuOlFtow.js");
1416
+ const { offerOpenInBrowser } = await import("./openBrowser-CCF1iuQK.js");
1398
1417
  await offerOpenInBrowser(link);
1399
1418
  }
1400
1419
  } else {
@@ -1445,4 +1464,4 @@ Options:
1445
1464
 
1446
1465
  //#endregion
1447
1466
  export { cmdServe };
1448
- //# sourceMappingURL=serve-DAuLdt_d.js.map
1467
+ //# sourceMappingURL=serve-Bt_KljpT.js.map
@@ -1,4 +1,4 @@
1
- import { o as getWorkspaceRoot, u as setWorkspaceRoot } from "./workspaceConfig-D3OH7and.js";
1
+ import { o as getWorkspaceRoot, u as setWorkspaceRoot } from "./workspaceConfig-BC03X4Y1.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-DAuLdt_d.js");
35
+ const { cmdServe } = await import("./serve-Bt_KljpT.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-YLHUtCC0.js.map
45
+ //# sourceMappingURL=setup-D5f1lmYF.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-Bfw7qL9O.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-BeKjLhmO.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 { loadOrCreateShareRoom, shareLinkFromRoomUrl, startShare };
537
- //# sourceMappingURL=share-BjqQBWM-.js.map
537
+ //# sourceMappingURL=share-D_e2Fwiy.js.map
@@ -1,5 +1,5 @@
1
1
  import "./logger-CDIsZ-Pp.js";
2
2
  import "./globalPidIndex-DlmmJlO8.js";
3
- import { i as waitForSpawnCapacity, n as spawnGateEnabled, r as spawnRejectionReason, t as memAvailableMb } from "./spawnGate-B_VDMXYL.js";
3
+ import { i as waitForSpawnCapacity, n as spawnGateEnabled, r as spawnRejectionReason, t as memAvailableMb } from "./spawnGate-DzPfa1PZ.js";
4
4
 
5
5
  export { waitForSpawnCapacity };
@@ -1,5 +1,5 @@
1
1
  import { i as readGlobalPids } from "./globalPidIndex-DlmmJlO8.js";
2
- import { a as getSpawnWaitMs, n as getMinFreeMb, t as getMaxAgents } from "./workspaceConfig-D3OH7and.js";
2
+ import { a as getSpawnWaitMs, n as getMinFreeMb, t as getMaxAgents } from "./workspaceConfig-BC03X4Y1.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-B_VDMXYL.js.map
107
+ //# sourceMappingURL=spawnGate-DzPfa1PZ.js.map
@@ -0,0 +1,9 @@
1
+ import "./logger-CDIsZ-Pp.js";
2
+ import "./globalPidIndex-DlmmJlO8.js";
3
+ import "./configShared-CEyhl0WH.js";
4
+ import "./e2e-BeKjLhmO.js";
5
+ import "./webrtcLink-BG0Xc4-W.js";
6
+ import "./remotes-BmAPylU_.js";
7
+ import { A as stopTipForCli, C as renderRawLogLines, D as restartHintLines, E as resolveResumeArgs, M as writeToIpc, O as runSubcommand, S as renderRawLog, T as resolveReadWindow, _ as listRecords, a as cursorAbs, b as readNotes, c as extractMenu, d as finalizedLines, f as isAgentStuck, g as isSubcommand, h as isSlashCommand, i as controlCodeFromName, j as writeKeysPaced, k as snapshotStatus, l as extractNeedsInput, m as isPidAlive, n as READ_PAGE_DEFAULT, o as deriveLiveStatus, p as isExitRequest, r as cmdHelp, s as extractBadges, t as GRACEFUL_EXIT_COMMANDS, u as extractTaskCounts, v as matchKeyword, w as resolveOne, x as readPtysize, y as menuSelectKeys } from "./subcommands-fp7kfr7p.js";
8
+
9
+ export { cmdHelp, isSubcommand, runSubcommand };
@@ -2,8 +2,8 @@ import { t as invokedCliName } from "./invokedCli-uqM2YYA7.js";
2
2
  import { t as agentYesHome } from "./agentYesHome-_eJa3DaX.js";
3
3
  import { a as updateGlobalPidStatus, i as readGlobalPids } from "./globalPidIndex-DlmmJlO8.js";
4
4
  import { t as loadSharedCliDefaults } from "./configShared-CEyhl0WH.js";
5
- import { n as isWebrtcSpec } from "./webrtcLink-CBZkZ-LT.js";
6
- import { a as resolveRemoteSpec, i as readRemotes } from "./remotes-T6nf0t3K.js";
5
+ import { n as isWebrtcSpec } from "./webrtcLink-BG0Xc4-W.js";
6
+ import { a as resolveRemoteSpec, i as readRemotes } from "./remotes-BmAPylU_.js";
7
7
  import ms from "ms";
8
8
  import yargs from "yargs";
9
9
  import { appendFile, mkdir, open, readFile, stat, writeFile } from "fs/promises";
@@ -157,6 +157,23 @@ function parseTaskCounts(lines) {
157
157
  return best;
158
158
  }
159
159
 
160
+ //#endregion
161
+ //#region ts/badges.ts
162
+ const BADGE_DEFS = [{
163
+ id: "goal-active",
164
+ label: "goal",
165
+ title: "A /goal Stop-hook loop is active on this agent",
166
+ pattern: /\/goal active/i
167
+ }];
168
+ /**
169
+ * Which badge ids match the given rendered screen lines. Pure so it's
170
+ * unit-tested without a live PTY/log file.
171
+ */
172
+ function matchBadges(lines, defs = BADGE_DEFS) {
173
+ const text = lines.join("\n");
174
+ return defs.filter((d) => d.pattern.test(text)).map((d) => d.id);
175
+ }
176
+
160
177
  //#endregion
161
178
  //#region ts/needsInput.ts
162
179
  function reTest(re, s) {
@@ -183,7 +200,7 @@ function classifyNeedsInput(lines, cfg) {
183
200
  const end = Math.min(lines.length, last + 6);
184
201
  return { question: lines.slice(start, end).map((l) => l.trim()).filter((l) => l && !isChromeLine(l)).join(" • ").slice(0, 400) };
185
202
  }
186
- const OPTION_LINE = /^[\s❯›>▶◉○●·*\-]*?(\d+)\.\s/;
203
+ const OPTION_LINE = /^[\s❯›>▶◉○●·*-]*?(\d+)\.\s/;
187
204
  /**
188
205
  * Parse the selection menu a `needs_input` agent is parked on into a cursor
189
206
  * position + the available option numbers, so a caller can compute how far the
@@ -597,19 +614,19 @@ async function runSubcommand(argv) {
597
614
  case "restart": return await cmdRestart(rest);
598
615
  case "note": return await cmdNote(rest);
599
616
  case "serve": {
600
- const { cmdServe } = await import("./serve-DAuLdt_d.js");
617
+ const { cmdServe } = await import("./serve-Bt_KljpT.js");
601
618
  return cmdServe(rest);
602
619
  }
603
620
  case "setup": {
604
- const { cmdSetup } = await import("./setup-YLHUtCC0.js");
621
+ const { cmdSetup } = await import("./setup-D5f1lmYF.js");
605
622
  return cmdSetup(rest);
606
623
  }
607
624
  case "schedule": {
608
- const { cmdSchedule } = await import("./schedule-BPUyALF_.js");
625
+ const { cmdSchedule } = await import("./schedule-Bh5bm1xO.js");
609
626
  return cmdSchedule(rest);
610
627
  }
611
628
  case "remote": {
612
- const { cmdRemote } = await import("./remotes-ClT1bq16.js");
629
+ const { cmdRemote } = await import("./remotes-cx_GDFPj.js");
613
630
  return cmdRemote(rest);
614
631
  }
615
632
  case "reap":
@@ -1002,7 +1019,7 @@ async function fetchRemoteRecordsRaw(url, token, opts) {
1002
1019
  let base = url;
1003
1020
  let bearer = token;
1004
1021
  if (isWebrtcSpec(url)) {
1005
- const { startWebrtcBridge } = await import("./webrtcRemote-GAgF5K45.js");
1022
+ const { startWebrtcBridge } = await import("./webrtcRemote-SybKurg9.js");
1006
1023
  bridge = await startWebrtcBridge(url);
1007
1024
  base = bridge.baseUrl;
1008
1025
  bearer = bridge.token;
@@ -1868,6 +1885,16 @@ async function extractNeedsInput(logPath, cli) {
1868
1885
  });
1869
1886
  }
1870
1887
  /**
1888
+ * Which badges (see badges.ts) match an agent's current screen — the same 32 KB
1889
+ * tail window `ay tail` renders, no CLI-specific config needed. Returns [] on
1890
+ * any read/render error or an empty log, same failure shape as extractNeedsInput.
1891
+ */
1892
+ async function extractBadges(logPath) {
1893
+ const lines = await renderLogTailLines(logPath, 40);
1894
+ if (!lines) return [];
1895
+ return matchBadges(lines);
1896
+ }
1897
+ /**
1871
1898
  * Whether an alive agent is wedged: its log has been silent for at least
1872
1899
  * STUCK_THRESHOLD_MS yet its screen still shows a `working` busy marker (a live
1873
1900
  * spinner keeps writing, so busy + long-silent = a mid-stream stall). Pass the
@@ -2074,7 +2101,7 @@ async function cmdSend(rest) {
2074
2101
  process.stdout.write(`pid ${record.pid} (${record.cli}): exit requested — sent ${strategy} (${reason})\n`);
2075
2102
  return 0;
2076
2103
  }
2077
- const fullBody = (sender.agent ? `[from ${sender.agent.cli} #${sender.agent.pid} @ ${shortenPath(sender.agent.cwd)} — reply: ay send ${sender.agent.pid} "..."]\n` : "") + body;
2104
+ const fullBody = (sender.agent && !isSlashCommand(body) ? `[from ${sender.agent.cli} #${sender.agent.pid} @ ${shortenPath(sender.agent.cwd)} — reply: ay send ${sender.agent.pid} "..."]\n` : "") + body;
2078
2105
  if (fullBody && trailing) {
2079
2106
  await writeToIpc(fifoPath, fullBody);
2080
2107
  await new Promise((r) => setTimeout(r, 200));
@@ -2355,6 +2382,13 @@ function isExitRequest(body) {
2355
2382
  const t = body.trim().toLowerCase();
2356
2383
  return t === "exit" || t === "/exit";
2357
2384
  }
2385
+ /** A body that the CLI will parse as a slash command — `/` as the very first
2386
+ * character (claude requires column 0, no leading whitespace, then a letter).
2387
+ * Such a body must be sent verbatim: any prefix line bumps the `/` off column 0
2388
+ * and the CLI types the command as plain text instead of running it. */
2389
+ function isSlashCommand(body) {
2390
+ return /^\/[A-Za-z]/.test(body);
2391
+ }
2358
2392
  /**
2359
2393
  * Gracefully terminate a live agent and record WHY in its note (the audit trail
2360
2394
  * shown by `ay ls`). Sends the CLI's graceful-exit command (e.g. claude's
@@ -3024,5 +3058,5 @@ async function cmdResultSet(rest) {
3024
3058
  }
3025
3059
 
3026
3060
  //#endregion
3027
- export { writeToIpc as A, resolveReadWindow as C, snapshotStatus as D, runSubcommand as E, stopTipForCli as O, resolveOne as S, restartHintLines as T, menuSelectKeys as _, cursorAbs as a, renderRawLog as b, extractNeedsInput as c, isAgentStuck as d, isExitRequest as f, matchKeyword as g, listRecords as h, controlCodeFromName as i, writeKeysPaced as k, extractTaskCounts as l, isSubcommand as m, READ_PAGE_DEFAULT as n, deriveLiveStatus as o, isPidAlive as p, cmdHelp as r, extractMenu as s, GRACEFUL_EXIT_COMMANDS as t, finalizedLines as u, readNotes as v, resolveResumeArgs as w, renderRawLogLines as x, readPtysize as y };
3028
- //# sourceMappingURL=subcommands-VimbMSTG.js.map
3061
+ export { stopTipForCli as A, renderRawLogLines as C, restartHintLines as D, resolveResumeArgs as E, writeToIpc as M, runSubcommand as O, renderRawLog as S, resolveReadWindow as T, listRecords as _, cursorAbs as a, readNotes as b, extractMenu as c, finalizedLines as d, isAgentStuck as f, isSubcommand as g, isSlashCommand as h, controlCodeFromName as i, writeKeysPaced as j, snapshotStatus as k, extractNeedsInput as l, isPidAlive as m, READ_PAGE_DEFAULT as n, deriveLiveStatus as o, isExitRequest as p, cmdHelp as r, extractBadges as s, GRACEFUL_EXIT_COMMANDS as t, extractTaskCounts as u, matchKeyword as v, resolveOne as w, readPtysize as x, menuSelectKeys as y };
3062
+ //# sourceMappingURL=subcommands-fp7kfr7p.js.map
@@ -1,4 +1,4 @@
1
- import { n as getRunningAgentCount } from "./runningLock-V4qvXgAw.js";
1
+ import { n as getRunningAgentCount } from "./runningLock-BobVW1_A.js";
2
2
  import { existsSync } from "fs";
3
3
  import { mkdir, readFile, unlink, writeFile } from "fs/promises";
4
4
  import { homedir } from "os";
@@ -187,4 +187,4 @@ async function startTray() {
187
187
 
188
188
  //#endregion
189
189
  export { ensureTray, startTray };
190
- //# sourceMappingURL=tray-CZarCA2Q.js.map
190
+ //# sourceMappingURL=tray-CWUpaZF4.js.map
@@ -1,7 +1,7 @@
1
1
  import { n as logger, t as addTransport } from "./logger-CDIsZ-Pp.js";
2
- import { r as getInstalledPackage } from "./versionChecker-DVv-WHIp.js";
2
+ import { r as getInstalledPackage } from "./versionChecker-IuFreIkZ.js";
3
3
  import { t as agentYesHome } from "./agentYesHome-_eJa3DaX.js";
4
- import { i as shouldUseLock, r as releaseLock, t as acquireLock } from "./runningLock-V4qvXgAw.js";
4
+ import { i as shouldUseLock, r as releaseLock, t as acquireLock } from "./runningLock-BobVW1_A.js";
5
5
  import { t as PidStore } from "./pidStore-BfoBWUjc.js";
6
6
  import { i as readGlobalPids } from "./globalPidIndex-DlmmJlO8.js";
7
7
  import { n as register, r as sweep } from "./reaper-C-eWAxIj.js";
@@ -1579,7 +1579,7 @@ async function agentYes({ cli, cliArgs = [], skipPermissions = false, prompt, ro
1579
1579
  } catch (error) {
1580
1580
  logger.debug(`heartbeat|error: ${error}`);
1581
1581
  }
1582
- }, 800);
1582
+ }, 100);
1583
1583
  const cleanupHeartbeat = () => clearInterval(heartbeatInterval);
1584
1584
  shell.onExit(cleanupHeartbeat);
1585
1585
  if (exitOnIdle) (async () => {
@@ -1805,7 +1805,7 @@ async function agentYes({ cli, cliArgs = [], skipPermissions = false, prompt, ro
1805
1805
  if (exited) return;
1806
1806
  shell.kill();
1807
1807
  resolve();
1808
- }, 5e3))]);
1808
+ }, 2e3))]);
1809
1809
  }
1810
1810
  function getTerminalDimensions() {
1811
1811
  if (!process.stdout.isTTY) return {
@@ -1824,4 +1824,4 @@ function sleep(ms) {
1824
1824
 
1825
1825
  //#endregion
1826
1826
  export { removeControlCharacters as a, AgentContext as i, agentYes as n, config as r, CLIS_CONFIG as t };
1827
- //# sourceMappingURL=ts-DBwi5BWW.js.map
1827
+ //# sourceMappingURL=ts-hUFVxJMw.js.map
@@ -7,7 +7,7 @@ import { fileURLToPath } from "url";
7
7
 
8
8
  //#region package.json
9
9
  var name = "claude-yes";
10
- var version = "1.168.0";
10
+ var version = "1.169.1";
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-DVv-WHIp.js.map
218
+ //# sourceMappingURL=versionChecker-IuFreIkZ.js.map