agent-yes 1.271.0 → 1.272.0-beta.658.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 (32) hide show
  1. package/dist/{SUPPORTED_CLIS-3wwg1X8T.js → SUPPORTED_CLIS-DNNdMJN_.js} +2 -2
  2. package/dist/{SUPPORTED_CLIS-lreAQcHS.js → SUPPORTED_CLIS-tpJdgRCT.js} +3 -3
  3. package/dist/{agentShare-DnewJUOO.js → agentShare-DJDnjvQc.js} +3 -3
  4. package/dist/{callback-Besk3KFx.js → callback-Dc1PCZUk.js} +3 -3
  5. package/dist/{callback-D521tLFf.js → callback-pDrrtfQ8.js} +3 -3
  6. package/dist/cli.js +5 -5
  7. package/dist/{cmdPs-4An2s2t8.js → cmdPs-YBWZA9q_.js} +3 -3
  8. package/dist/index.js +2 -2
  9. package/dist/{notifyDaemon-kIOLWrEI.js → notifyDaemon-ByJtcbbX.js} +3 -3
  10. package/dist/{parentPingLoop-D2A9Fkhf.js → parentPingLoop-D1oxgeES.js} +2 -2
  11. package/dist/{remotes-IzQHupeo.js → remotes-BL2MegXx.js} +16 -8
  12. package/dist/{remotes-BiftUp09.js → remotes-CNNWole7.js} +1 -1
  13. package/dist/{rustBinary-BK03gMMg.js → rustBinary-DPRR_QOA.js} +2 -2
  14. package/dist/{schedule-BdK4RVQ5.js → schedule-B8S10ci8.js} +4 -4
  15. package/dist/{serve-XWSfUL8i.js → serve-CcVhTYIX.js} +18 -18
  16. package/dist/{setup-B-Cui8R6.js → setup-CJGkmk3P.js} +2 -2
  17. package/dist/{subcommands-ByZspogJ.js → subcommands-C0-NKq4X.js} +2 -2
  18. package/dist/{subcommands-C3NO344d.js → subcommands-DX0iQzwD.js} +24 -24
  19. package/dist/{terminal-BxWNOBW4.js → terminal-CCLw4qIt.js} +2 -2
  20. package/dist/trayApp-10o8DC7r.js +5 -0
  21. package/dist/{trayApp-CcQDIINw.js → trayApp-BxrNX0KY.js} +2 -2
  22. package/dist/{ts-BG759sO1.js → ts-C5yjBnoI.js} +3 -3
  23. package/dist/{versionChecker-DCtcFwZ7.js → versionChecker-DHrDPEw3.js} +2 -2
  24. package/dist/{widget-DobxsxXa.js → widget-Bf-hAxpl.js} +3 -3
  25. package/dist/{ws-Bk2cJphr.js → ws-CWMIHaJ8.js} +3 -3
  26. package/dist/{ws-DO1UpPDw.js → ws-KZfHmxtS.js} +2 -2
  27. package/lab/ui/lab/index.md +16 -0
  28. package/lab/ui/lab/posts/2026-08-11-slack-term-safe-writes.md +240 -0
  29. package/package.json +1 -1
  30. package/ts/remotes.ts +24 -7
  31. package/ts/subcommands.ts +9 -9
  32. package/dist/trayApp-XJit7gRr.js +0 -5
@@ -1,8 +1,8 @@
1
- import { t as CLIS_CONFIG } from "./ts-BG759sO1.js";
1
+ import { t as CLIS_CONFIG } from "./ts-C5yjBnoI.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-3wwg1X8T.js.map
8
+ //# sourceMappingURL=SUPPORTED_CLIS-DNNdMJN_.js.map
@@ -1,12 +1,12 @@
1
1
  import "./logger-CDIsZ-Pp.js";
2
- import "./versionChecker-DCtcFwZ7.js";
3
- import "./ts-BG759sO1.js";
2
+ import "./versionChecker-DHrDPEw3.js";
3
+ import "./ts-C5yjBnoI.js";
4
4
  import "./todoAutomation-BETGOik9.js";
5
5
  import "./JsonlStore-CPGIR0Wy.js";
6
6
  import "./globalPidIndex-Dq4KY2IV.js";
7
7
  import "./pidStore-DJqSZPJi.js";
8
8
  import "./messageLog-BYFwioFY.js";
9
9
  import "./todoStore-Wk8U4zJ8.js";
10
- import { t as SUPPORTED_CLIS } from "./SUPPORTED_CLIS-3wwg1X8T.js";
10
+ import { t as SUPPORTED_CLIS } from "./SUPPORTED_CLIS-DNNdMJN_.js";
11
11
 
12
12
  export { SUPPORTED_CLIS };
@@ -3,10 +3,10 @@ import "./globalPidIndex-Dq4KY2IV.js";
3
3
  import "./messageLog-BYFwioFY.js";
4
4
  import "./e2e-OLfcNxiv.js";
5
5
  import "./configShared-DYxlvrH0.js";
6
- import { B as resolveOne } from "./subcommands-C3NO344d.js";
6
+ import { B as resolveOne } from "./subcommands-DX0iQzwD.js";
7
7
  import "./notifyStore-Dus2D1XA.js";
8
8
  import "./webrtcLink-B72AQ2eb.js";
9
- import "./remotes-IzQHupeo.js";
9
+ import "./remotes-BL2MegXx.js";
10
10
  import { a as startShare } from "./share-RgJUhzqG.js";
11
11
 
12
12
  //#region ts/agentShare.ts
@@ -230,4 +230,4 @@ function transformEvent(rawEvent, agentId, forwarded) {
230
230
 
231
231
  //#endregion
232
232
  export { createScopedShare, listShares, revokeAllShares, revokeShare };
233
- //# sourceMappingURL=agentShare-DnewJUOO.js.map
233
+ //# sourceMappingURL=agentShare-DJDnjvQc.js.map
@@ -3,11 +3,11 @@ import "./globalPidIndex-Dq4KY2IV.js";
3
3
  import "./messageLog-BYFwioFY.js";
4
4
  import "./e2e-OLfcNxiv.js";
5
5
  import "./configShared-DYxlvrH0.js";
6
- import "./subcommands-C3NO344d.js";
6
+ import "./subcommands-DX0iQzwD.js";
7
7
  import "./notifyStore-Dus2D1XA.js";
8
8
  import "./webrtcLink-B72AQ2eb.js";
9
- import "./remotes-IzQHupeo.js";
9
+ import "./remotes-BL2MegXx.js";
10
10
  import "./callbackCore-Bbe7rpN2.js";
11
- import { i as loadOrCreateCallbackSecret, n as isCallbackRevoked, r as loadCallbackSecretReadOnly, t as cmdCallback } from "./callback-D521tLFf.js";
11
+ import { i as loadOrCreateCallbackSecret, n as isCallbackRevoked, r as loadCallbackSecretReadOnly, t as cmdCallback } from "./callback-pDrrtfQ8.js";
12
12
 
13
13
  export { cmdCallback };
@@ -1,5 +1,5 @@
1
1
  import { t as agentYesHome } from "./agentYesHome-CtmsY6I-.js";
2
- import { B as resolveOne } from "./subcommands-C3NO344d.js";
2
+ import { B as resolveOne } from "./subcommands-DX0iQzwD.js";
3
3
  import { a as mintCapability, o as parseExpires } from "./callbackCore-Bbe7rpN2.js";
4
4
  import { randomBytes } from "node:crypto";
5
5
  import { chmodSync, readFileSync, renameSync, writeFileSync } from "node:fs";
@@ -72,7 +72,7 @@ async function resolveBase(flag) {
72
72
  if (flag) return flag;
73
73
  if (process.env.AGENT_YES_CALLBACK_BASE) return process.env.AGENT_YES_CALLBACK_BASE;
74
74
  try {
75
- const { resolveLocalServeUrl } = await import("./serve-XWSfUL8i.js");
75
+ const { resolveLocalServeUrl } = await import("./serve-CcVhTYIX.js");
76
76
  const url = await resolveLocalServeUrl();
77
77
  if (url) return url;
78
78
  } catch {}
@@ -187,4 +187,4 @@ async function cmdCallback(rest) {
187
187
 
188
188
  //#endregion
189
189
  export { loadOrCreateCallbackSecret as i, isCallbackRevoked as n, loadCallbackSecretReadOnly as r, cmdCallback as t };
190
- //# sourceMappingURL=callback-D521tLFf.js.map
190
+ //# sourceMappingURL=callback-pDrrtfQ8.js.map
package/dist/cli.js CHANGED
@@ -1,8 +1,8 @@
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, t as checkAndAutoUpdate } from "./versionChecker-DCtcFwZ7.js";
5
- import { r as getRustBinary } from "./rustBinary-BK03gMMg.js";
4
+ import { i as versionString, n as displayVersion, t as checkAndAutoUpdate } from "./versionChecker-DHrDPEw3.js";
5
+ import { r as getRustBinary } from "./rustBinary-DPRR_QOA.js";
6
6
  import { argv } from "process";
7
7
  import { spawn } from "child_process";
8
8
  import ms from "ms";
@@ -295,7 +295,7 @@ function buildRustArgs(argv, cliFromScript, supportedClis) {
295
295
  const rawArg = process.argv[2];
296
296
  const managerCommands = !invokedCliName(process.argv);
297
297
  const isHelpFlag = rawArg === "-h" || rawArg === "--help";
298
- const { isSubcommand, runSubcommand, cmdHelp, isUnknownManagerToken, isBareManagerInvocation } = await import("./subcommands-ByZspogJ.js");
298
+ const { isSubcommand, runSubcommand, cmdHelp, isUnknownManagerToken, isBareManagerInvocation } = await import("./subcommands-C0-NKq4X.js");
299
299
  if (isHelpFlag && process.argv.length === 3) {
300
300
  await cmdHelp(managerCommands);
301
301
  process.exit(0);
@@ -309,7 +309,7 @@ function buildRustArgs(argv, cliFromScript, supportedClis) {
309
309
  process.exit(code ?? 0);
310
310
  }
311
311
  {
312
- const { SUPPORTED_CLIS } = await import("./SUPPORTED_CLIS-lreAQcHS.js");
312
+ const { SUPPORTED_CLIS } = await import("./SUPPORTED_CLIS-tpJdgRCT.js");
313
313
  if (isUnknownManagerToken(rawArg, managerCommands, SUPPORTED_CLIS)) {
314
314
  process.stderr.write(`ay: unknown subcommand or CLI '${rawArg}'.\n See 'ay help' for subcommands. To run an agent, name a CLI:\n 'ay <cli> …' (e.g. 'ay claude …') or 'ay --cli <cli> …'.\n`);
315
315
  process.exit(1);
@@ -360,7 +360,7 @@ if (config.useRust) {
360
360
  }
361
361
  }
362
362
  if (rustBinary) {
363
- const { SUPPORTED_CLIS } = await import("./SUPPORTED_CLIS-lreAQcHS.js");
363
+ const { SUPPORTED_CLIS } = await import("./SUPPORTED_CLIS-tpJdgRCT.js");
364
364
  const rustArgs = buildRustArgs(process.argv, config.cli, SUPPORTED_CLIS);
365
365
  if (config.verbose) {
366
366
  console.log(`[rust] Using binary: ${rustBinary}`);
@@ -3,10 +3,10 @@ import "./globalPidIndex-Dq4KY2IV.js";
3
3
  import "./messageLog-BYFwioFY.js";
4
4
  import "./e2e-OLfcNxiv.js";
5
5
  import "./configShared-DYxlvrH0.js";
6
- import { O as listRecords, d as deriveLiveState, et as buildAgentForest, tt as flattenForest } from "./subcommands-C3NO344d.js";
6
+ import { O as listRecords, d as deriveLiveState, et as buildAgentForest, tt as flattenForest } from "./subcommands-DX0iQzwD.js";
7
7
  import "./notifyStore-Dus2D1XA.js";
8
8
  import "./webrtcLink-B72AQ2eb.js";
9
- import "./remotes-IzQHupeo.js";
9
+ import "./remotes-BL2MegXx.js";
10
10
  import yargs from "yargs";
11
11
  import { execFile } from "node:child_process";
12
12
  import { readFileSync } from "node:fs";
@@ -574,4 +574,4 @@ function readPpidSync(pid) {
574
574
 
575
575
  //#endregion
576
576
  export { cmdPs };
577
- //# sourceMappingURL=cmdPs-4An2s2t8.js.map
577
+ //# sourceMappingURL=cmdPs-YBWZA9q_.js.map
package/dist/index.js CHANGED
@@ -1,6 +1,6 @@
1
1
  import "./logger-CDIsZ-Pp.js";
2
- import "./versionChecker-DCtcFwZ7.js";
3
- import { a as hasTodoStore, i as answerAsk, l as AgentContext, n as agentYes, o as listAsks, r as config, s as listAsksForProject, t as CLIS_CONFIG } from "./ts-BG759sO1.js";
2
+ import "./versionChecker-DHrDPEw3.js";
3
+ import { a as hasTodoStore, i as answerAsk, l as AgentContext, n as agentYes, o as listAsks, r as config, s as listAsksForProject, t as CLIS_CONFIG } from "./ts-C5yjBnoI.js";
4
4
  import { a as renderTree, c as describeBlock, i as renderDigest, l as monitorHint, o as unblockedTasks, r as openBlockers, t as reconcileTodos, u as removeControlCharacters } from "./todoAutomation-BETGOik9.js";
5
5
  import "./JsonlStore-CPGIR0Wy.js";
6
6
  import "./globalPidIndex-Dq4KY2IV.js";
@@ -3,10 +3,10 @@ import "./globalPidIndex-Dq4KY2IV.js";
3
3
  import "./messageLog-BYFwioFY.js";
4
4
  import "./e2e-OLfcNxiv.js";
5
5
  import "./configShared-DYxlvrH0.js";
6
- import { L as renderLogTailLines, O as listRecords, d as deriveLiveState, x as isPidAlive } from "./subcommands-C3NO344d.js";
6
+ import { L as renderLogTailLines, O as listRecords, d as deriveLiveState, x as isPidAlive } from "./subcommands-DX0iQzwD.js";
7
7
  import { f as readInbox, g as daemonLockOwnerPath, h as daemonLockDir, i as gcInboxes, l as listInboxParents, m as shouldStealLock, n as appendEvent, s as hostId, u as liveWatchers, x as notifyDir } from "./notifyStore-Dus2D1XA.js";
8
8
  import "./webrtcLink-B72AQ2eb.js";
9
- import "./remotes-IzQHupeo.js";
9
+ import "./remotes-BL2MegXx.js";
10
10
  import { mkdir, readFile, rename, rm, stat, writeFile } from "fs/promises";
11
11
  import { randomUUID } from "node:crypto";
12
12
  import { execFile, execFileSync } from "node:child_process";
@@ -863,4 +863,4 @@ async function ensureDaemon() {
863
863
 
864
864
  //#endregion
865
865
  export { daemonStatus, ensureDaemon, requestDaemonStop, runDaemon };
866
- //# sourceMappingURL=notifyDaemon-kIOLWrEI.js.map
866
+ //# sourceMappingURL=notifyDaemon-ByJtcbbX.js.map
@@ -338,7 +338,7 @@ async function isParentWatching(parentWrapperPid, parentAgentPid, selfAgentPid,
338
338
  logger.debug("[parent-ping] watcher lookup failed:", error);
339
339
  }
340
340
  try {
341
- const { lastReadAt, READ_WINDOW_MS } = await import("./subcommands-ByZspogJ.js");
341
+ const { lastReadAt, READ_WINDOW_MS } = await import("./subcommands-C0-NKq4X.js");
342
342
  const last = await lastReadAt(`agent:${parentAgentPid}`, selfAgentPid);
343
343
  if (last !== null && now - last <= READ_WINDOW_MS) return true;
344
344
  } catch (error) {
@@ -466,4 +466,4 @@ function startParentPingLoop(opts) {
466
466
 
467
467
  //#endregion
468
468
  export { startParentPingLoop };
469
- //# sourceMappingURL=parentPingLoop-D2A9Fkhf.js.map
469
+ //# sourceMappingURL=parentPingLoop-D1oxgeES.js.map
@@ -1,4 +1,4 @@
1
- import { n as isWebrtcSpec } from "./webrtcLink-B72AQ2eb.js";
1
+ import { n as isWebrtcSpec, r as parseWebrtcLink } from "./webrtcLink-B72AQ2eb.js";
2
2
  import { mkdir, readFile, writeFile } from "fs/promises";
3
3
  import { homedir } from "os";
4
4
  import path from "path";
@@ -9,6 +9,11 @@ function remotesPath() {
9
9
  const dir = process.env.AGENT_YES_HOME ?? path.join(homedir(), ".agent-yes");
10
10
  return path.join(dir, "remotes.yaml");
11
11
  }
12
+ /** A display label for a WebRTC share link: the room id, never the local bridge. */
13
+ function webrtcLabel(link) {
14
+ const parsed = parseWebrtcLink(link);
15
+ return parsed ? `webrtc:${parsed.room}` : "webrtc";
16
+ }
12
17
  async function readRemotes() {
13
18
  let raw;
14
19
  try {
@@ -61,23 +66,25 @@ function parseDirectRemoteSpec(spec) {
61
66
  * Returns null if the spec doesn't match any remote.
62
67
  */
63
68
  async function resolveRemoteSpec(spec) {
64
- if (isWebrtcSpec(spec)) return resolveWebrtc(spec, void 0);
69
+ if (isWebrtcSpec(spec)) return resolveWebrtc(spec, void 0, webrtcLabel(spec));
65
70
  const direct = parseDirectRemoteSpec(spec);
66
71
  if (direct) return {
67
72
  url: direct.baseUrl,
68
73
  token: direct.token,
69
- keyword: direct.keyword
74
+ keyword: direct.keyword,
75
+ label: `${direct.host}:${direct.port}`
70
76
  };
71
77
  const colonIdx = spec.indexOf(":");
72
78
  const alias = colonIdx >= 0 ? spec.slice(0, colonIdx) : spec;
73
79
  const keyword = colonIdx >= 0 ? spec.slice(colonIdx + 1) || void 0 : void 0;
74
80
  const cfg = (await readRemotes()).get(alias);
75
81
  if (!cfg) return null;
76
- if (isWebrtcSpec(cfg.url)) return resolveWebrtc(cfg.url, keyword);
82
+ if (isWebrtcSpec(cfg.url)) return resolveWebrtc(cfg.url, keyword, alias);
77
83
  return {
78
84
  url: cfg.url,
79
85
  token: cfg.token,
80
- keyword
86
+ keyword,
87
+ label: alias
81
88
  };
82
89
  }
83
90
  /**
@@ -85,13 +92,14 @@ async function resolveRemoteSpec(spec) {
85
92
  * ordinary http remote, so every fetch-based remote command works unchanged.
86
93
  * The bridge lives for the rest of the process (torn down on `process.exit`).
87
94
  */
88
- async function resolveWebrtc(link, keyword) {
95
+ async function resolveWebrtc(link, keyword, label) {
89
96
  const { startWebrtcBridge } = await import("./webrtcRemote-D68dkqFp.js");
90
97
  const bridge = await startWebrtcBridge(link);
91
98
  return {
92
99
  url: bridge.baseUrl,
93
100
  token: bridge.token,
94
- keyword
101
+ keyword,
102
+ label
95
103
  };
96
104
  }
97
105
  async function cmdRemote(rest) {
@@ -173,4 +181,4 @@ async function cmdRemote(rest) {
173
181
 
174
182
  //#endregion
175
183
  export { resolveRemoteSpec as a, readRemotes as i, deleteRemoteAlias as n, writeRemoteAlias as o, parseDirectRemoteSpec as r, cmdRemote as t };
176
- //# sourceMappingURL=remotes-IzQHupeo.js.map
184
+ //# sourceMappingURL=remotes-BL2MegXx.js.map
@@ -1,5 +1,5 @@
1
1
  import "./e2e-OLfcNxiv.js";
2
2
  import "./webrtcLink-B72AQ2eb.js";
3
- import { a as resolveRemoteSpec, i as readRemotes, n as deleteRemoteAlias, o as writeRemoteAlias, r as parseDirectRemoteSpec, t as cmdRemote } from "./remotes-IzQHupeo.js";
3
+ import { a as resolveRemoteSpec, i as readRemotes, n as deleteRemoteAlias, o as writeRemoteAlias, r as parseDirectRemoteSpec, t as cmdRemote } from "./remotes-BL2MegXx.js";
4
4
 
5
5
  export { cmdRemote };
@@ -1,4 +1,4 @@
1
- import { r as getInstalledPackage } from "./versionChecker-DCtcFwZ7.js";
1
+ import { r as getInstalledPackage } from "./versionChecker-DHrDPEw3.js";
2
2
  import { execFileSync } from "child_process";
3
3
  import { existsSync, mkdirSync, unlinkSync } from "fs";
4
4
  import { chmod, copyFile } from "fs/promises";
@@ -243,4 +243,4 @@ async function getRustBinary(options = {}) {
243
243
 
244
244
  //#endregion
245
245
  export { findTrayLauncher as n, getRustBinary as r, findSpawnHiddenLauncher as t };
246
- //# sourceMappingURL=rustBinary-BK03gMMg.js.map
246
+ //# sourceMappingURL=rustBinary-DPRR_QOA.js.map
@@ -1,13 +1,13 @@
1
1
  import "./logger-CDIsZ-Pp.js";
2
- import "./versionChecker-DCtcFwZ7.js";
3
- import "./ts-BG759sO1.js";
2
+ import "./versionChecker-DHrDPEw3.js";
3
+ import "./ts-C5yjBnoI.js";
4
4
  import "./todoAutomation-BETGOik9.js";
5
5
  import "./JsonlStore-CPGIR0Wy.js";
6
6
  import "./globalPidIndex-Dq4KY2IV.js";
7
7
  import "./pidStore-DJqSZPJi.js";
8
8
  import "./messageLog-BYFwioFY.js";
9
9
  import "./todoStore-Wk8U4zJ8.js";
10
- import { t as SUPPORTED_CLIS } from "./SUPPORTED_CLIS-3wwg1X8T.js";
10
+ import { t as SUPPORTED_CLIS } from "./SUPPORTED_CLIS-DNNdMJN_.js";
11
11
  import { f as resolveSpawnCwd } from "./workspaceConfig-EK7XNsgR.js";
12
12
  import { n as liveEnv, t as ensureNodeRuntime } from "./nodeRuntime-CKc1BN5J.js";
13
13
  import { createHash } from "node:crypto";
@@ -154,4 +154,4 @@ async function cmdSchedule(rest) {
154
154
 
155
155
  //#endregion
156
156
  export { cmdSchedule };
157
- //# sourceMappingURL=schedule-BdK4RVQ5.js.map
157
+ //# sourceMappingURL=schedule-B8S10ci8.js.map
@@ -1,7 +1,7 @@
1
1
  import "./logger-CDIsZ-Pp.js";
2
- import { r as getInstalledPackage } from "./versionChecker-DCtcFwZ7.js";
3
- import { t as findSpawnHiddenLauncher } from "./rustBinary-BK03gMMg.js";
4
- import { c as permissionBadge, i as answerAsk, o as listAsks, u as CLAUDE_SESSION_PIN_ENV } from "./ts-BG759sO1.js";
2
+ import { r as getInstalledPackage } from "./versionChecker-DHrDPEw3.js";
3
+ import { t as findSpawnHiddenLauncher } from "./rustBinary-DPRR_QOA.js";
4
+ import { c as permissionBadge, i as answerAsk, o as listAsks, u as CLAUDE_SESSION_PIN_ENV } from "./ts-C5yjBnoI.js";
5
5
  import { t as agentYesHome$1 } from "./agentYesHome-CtmsY6I-.js";
6
6
  import { u as removeControlCharacters } from "./todoAutomation-BETGOik9.js";
7
7
  import "./JsonlStore-CPGIR0Wy.js";
@@ -12,18 +12,18 @@ import { t as pgidForWrapper } from "./reaper-C4BvNylH.js";
12
12
  import "./todoStore-Wk8U4zJ8.js";
13
13
  import "./e2e-OLfcNxiv.js";
14
14
  import "./configShared-DYxlvrH0.js";
15
- import { t as SUPPORTED_CLIS } from "./SUPPORTED_CLIS-3wwg1X8T.js";
16
- import { $ as TYPING_BADGE, B as resolveOne, F as recentMessageEdges, G as snapshotStatus, I as recentReadEdges, L as renderLogTailLines, M as readLogForRender, N as readNotes, O as listRecords, P as readPtysize, Q as withIpcLock, R as renderRawLog, T as isUserTyping, Z as writeToIpc, f as deriveLiveStatus, g as extractTaskCounts, h as extractNeedsInput, l as controlCodeFromName, p as extractBadges, z as renderRawLogLines } from "./subcommands-C3NO344d.js";
15
+ import { t as SUPPORTED_CLIS } from "./SUPPORTED_CLIS-DNNdMJN_.js";
16
+ import { $ as TYPING_BADGE, B as resolveOne, F as recentMessageEdges, G as snapshotStatus, I as recentReadEdges, L as renderLogTailLines, M as readLogForRender, N as readNotes, O as listRecords, P as readPtysize, Q as withIpcLock, R as renderRawLog, T as isUserTyping, Z as writeToIpc, f as deriveLiveStatus, g as extractTaskCounts, h as extractNeedsInput, l as controlCodeFromName, p as extractBadges, z as renderRawLogLines } from "./subcommands-DX0iQzwD.js";
17
17
  import { c as isTransientLockMkdirError } from "./notifyStore-Dus2D1XA.js";
18
18
  import "./webrtcLink-B72AQ2eb.js";
19
- import "./remotes-IzQHupeo.js";
19
+ import "./remotes-BL2MegXx.js";
20
20
  import { i as frameVisitorMessage, s as verifyCapability, t as MAX_CALLBACK_MSG_BYTES } from "./callbackCore-Bbe7rpN2.js";
21
- import { n as isCallbackRevoked, r as loadCallbackSecretReadOnly } from "./callback-D521tLFf.js";
21
+ import { n as isCallbackRevoked, r as loadCallbackSecretReadOnly } from "./callback-pDrrtfQ8.js";
22
22
  import { a as getProvisionRoot, d as isProvisionAllowed, f as resolveSpawnCwd, i as getProvisionHook, l as hasProvisionHook, o as getSpawnHook, t as allowsSkipPermissions, u as hasSpawnHook } from "./workspaceConfig-EK7XNsgR.js";
23
23
  import { n as liveEnv, t as ensureNodeRuntime } from "./nodeRuntime-CKc1BN5J.js";
24
- import { i as importProvisionModule } from "./ws-DO1UpPDw.js";
24
+ import { i as importProvisionModule } from "./ws-KZfHmxtS.js";
25
25
  import { r as spawnRejectionReason } from "./spawnGate-CS3oFdJ9.js";
26
- import { i as launchTray } from "./trayApp-CcQDIINw.js";
26
+ import { i as launchTray } from "./trayApp-BxrNX0KY.js";
27
27
  import yargs from "yargs";
28
28
  import { appendFile, mkdir, open, readFile, readdir, rename, rm, stat, unlink, writeFile } from "fs/promises";
29
29
  import { arch, cpus, freemem, homedir, hostname, loadavg, platform, totalmem, uptime, userInfo } from "os";
@@ -2436,7 +2436,7 @@ Options:
2436
2436
  }
2437
2437
  });
2438
2438
  if (req.method === "GET" && p === "/api/ws") {
2439
- const ws = await import("./ws-Bk2cJphr.js");
2439
+ const ws = await import("./ws-CWMIHaJ8.js");
2440
2440
  try {
2441
2441
  await ws.loadProvision();
2442
2442
  } catch (e) {
@@ -2456,7 +2456,7 @@ Options:
2456
2456
  if (req.method === "GET" && p === "/api/ws/status") {
2457
2457
  const dirRaw = url.searchParams.get("path");
2458
2458
  if (!dirRaw) return new Response("missing ?path=<workspace dir>", { status: 400 });
2459
- const ws = await import("./ws-Bk2cJphr.js");
2459
+ const ws = await import("./ws-CWMIHaJ8.js");
2460
2460
  let prov;
2461
2461
  try {
2462
2462
  prov = await ws.loadProvision();
@@ -2478,7 +2478,7 @@ Options:
2478
2478
  }
2479
2479
  }
2480
2480
  if (req.method === "GET" && p === "/api/ws/repos") {
2481
- const ws = await import("./ws-Bk2cJphr.js");
2481
+ const ws = await import("./ws-CWMIHaJ8.js");
2482
2482
  try {
2483
2483
  await ws.loadProvision();
2484
2484
  } catch (e) {
@@ -2559,7 +2559,7 @@ Options:
2559
2559
  const m = /^([A-Za-z0-9_.-]+)\/([A-Za-z0-9_.-]+)$/.exec(repoParam);
2560
2560
  if (!m || m[1] === "." || m[1] === ".." || m[2] === "." || m[2] === "..") return new Response("missing/invalid ?repo=<owner>/<repo>", { status: 400 });
2561
2561
  const [, owner, repo] = m;
2562
- const ws = await import("./ws-Bk2cJphr.js");
2562
+ const ws = await import("./ws-CWMIHaJ8.js");
2563
2563
  let prov;
2564
2564
  try {
2565
2565
  prov = await ws.loadProvision();
@@ -3470,7 +3470,7 @@ Options:
3470
3470
  const perm = body.perm ?? "r";
3471
3471
  if (perm !== "r" && perm !== "rw") return new Response(`invalid perm ${perm} (want r or rw)`, { status: 400 });
3472
3472
  try {
3473
- const { createScopedShare } = await import("./agentShare-DnewJUOO.js");
3473
+ const { createScopedShare } = await import("./agentShare-DJDnjvQc.js");
3474
3474
  const share = await createScopedShare({
3475
3475
  agent: body.agent,
3476
3476
  perm,
@@ -3485,12 +3485,12 @@ Options:
3485
3485
  }
3486
3486
  }
3487
3487
  if (req.method === "GET" && p === "/api/shares") {
3488
- const { listShares } = await import("./agentShare-DnewJUOO.js");
3488
+ const { listShares } = await import("./agentShare-DJDnjvQc.js");
3489
3489
  return Response.json(listShares());
3490
3490
  }
3491
3491
  const revokeM = /^\/api\/share\/([^/]+)$/.exec(p);
3492
3492
  if (req.method === "DELETE" && revokeM) {
3493
- const { revokeShare } = await import("./agentShare-DnewJUOO.js");
3493
+ const { revokeShare } = await import("./agentShare-DJDnjvQc.js");
3494
3494
  const ok = revokeShare(decodeURIComponent(revokeM[1]));
3495
3495
  return new Response(ok ? "revoked" : "no such share", { status: ok ? 200 : 404 });
3496
3496
  }
@@ -3795,7 +3795,7 @@ Options:
3795
3795
  const shutdown = (resolve) => {
3796
3796
  if (heartbeat) clearInterval(heartbeat);
3797
3797
  closeShare?.();
3798
- import("./agentShare-DnewJUOO.js").then((m) => m.revokeAllShares()).catch(() => {});
3798
+ import("./agentShare-DJDnjvQc.js").then((m) => m.revokeAllShares()).catch(() => {});
3799
3799
  server?.stop();
3800
3800
  Promise.resolve(releaseHostLock?.()).catch(() => {}).then(resolve);
3801
3801
  };
@@ -3808,4 +3808,4 @@ Options:
3808
3808
 
3809
3809
  //#endregion
3810
3810
  export { cmdServe, loadTokenReadOnly, mintScopedTermToken, resolveDaemonHttpBase, resolveLocalServeUrl };
3811
- //# sourceMappingURL=serve-XWSfUL8i.js.map
3811
+ //# sourceMappingURL=serve-CcVhTYIX.js.map
@@ -40,7 +40,7 @@ async function cmdSetup(rest) {
40
40
  } catch {}
41
41
  if (noShare) return 0;
42
42
  process.stdout.write(`\nsharing this machine to agent-yes.com…\n`);
43
- const { cmdServe } = await import("./serve-XWSfUL8i.js");
43
+ const { cmdServe } = await import("./serve-CcVhTYIX.js");
44
44
  return cmdServe([
45
45
  "install",
46
46
  "--share",
@@ -50,4 +50,4 @@ async function cmdSetup(rest) {
50
50
 
51
51
  //#endregion
52
52
  export { cmdSetup };
53
- //# sourceMappingURL=setup-B-Cui8R6.js.map
53
+ //# sourceMappingURL=setup-CJGkmk3P.js.map
@@ -3,9 +3,9 @@ import "./globalPidIndex-Dq4KY2IV.js";
3
3
  import "./messageLog-BYFwioFY.js";
4
4
  import "./e2e-OLfcNxiv.js";
5
5
  import "./configShared-DYxlvrH0.js";
6
- import { A as menuSelectKeys, B as resolveOne, C as isSubcommand, D as lastStdinAt, E as lastReadAt, F as recentMessageEdges, G as snapshotStatus, H as resolveResumeArgs, I as recentReadEdges, J as submitAndConfirm, K as stdinActivityPath, L as renderLogTailLines, M as readLogForRender, N as readNotes, O as listRecords, P as readPtysize, R as renderRawLog, S as isSlashCommand, T as isUserTyping, U as restartHintLines, V as resolveReadWindow, W as runSubcommand, X as writeKeysPaced, Y as waitForLogQuiet, Z as writeToIpc, _ as finalizedLines, a as TYPING_WINDOW_MS, b as isExitRequest, c as cmdHelp, d as deriveLiveState, f as deriveLiveStatus, g as extractTaskCounts, h as extractNeedsInput, i as READ_WINDOW_MS, j as readAgentPtysize, k as matchKeyword, l as controlCodeFromName, m as extractMenu, n as MAX_RENDER_BYTES, o as backoffWhileTyping, p as extractBadges, q as stopTipForCli, r as READ_PAGE_DEFAULT, s as cmdDeepseek, t as GRACEFUL_EXIT_COMMANDS, u as cursorAbs, v as isAgentStuck, w as isUnknownManagerToken, x as isPidAlive, y as isBareManagerInvocation, z as renderRawLogLines } from "./subcommands-C3NO344d.js";
6
+ import { A as menuSelectKeys, B as resolveOne, C as isSubcommand, D as lastStdinAt, E as lastReadAt, F as recentMessageEdges, G as snapshotStatus, H as resolveResumeArgs, I as recentReadEdges, J as submitAndConfirm, K as stdinActivityPath, L as renderLogTailLines, M as readLogForRender, N as readNotes, O as listRecords, P as readPtysize, R as renderRawLog, S as isSlashCommand, T as isUserTyping, U as restartHintLines, V as resolveReadWindow, W as runSubcommand, X as writeKeysPaced, Y as waitForLogQuiet, Z as writeToIpc, _ as finalizedLines, a as TYPING_WINDOW_MS, b as isExitRequest, c as cmdHelp, d as deriveLiveState, f as deriveLiveStatus, g as extractTaskCounts, h as extractNeedsInput, i as READ_WINDOW_MS, j as readAgentPtysize, k as matchKeyword, l as controlCodeFromName, m as extractMenu, n as MAX_RENDER_BYTES, o as backoffWhileTyping, p as extractBadges, q as stopTipForCli, r as READ_PAGE_DEFAULT, s as cmdDeepseek, t as GRACEFUL_EXIT_COMMANDS, u as cursorAbs, v as isAgentStuck, w as isUnknownManagerToken, x as isPidAlive, y as isBareManagerInvocation, z as renderRawLogLines } from "./subcommands-DX0iQzwD.js";
7
7
  import "./notifyStore-Dus2D1XA.js";
8
8
  import "./webrtcLink-B72AQ2eb.js";
9
- import "./remotes-IzQHupeo.js";
9
+ import "./remotes-BL2MegXx.js";
10
10
 
11
11
  export { READ_WINDOW_MS, cmdHelp, isBareManagerInvocation, isSubcommand, isUnknownManagerToken, lastReadAt, runSubcommand };
@@ -7,7 +7,7 @@ import { t as formatIdentity } from "./identity-CLaJ9-uE.js";
7
7
  import { n as isWorkingScreen, r as parseMenu, t as classifyNeedsInput } from "./needsInput-DhfIwxse.js";
8
8
  import { S as postmortemStartedAt, _ as filterSinceSeq, a as getCursor, b as maxSeq, f as readInbox, o as heartbeatWatcher, p as setCursor, r as clearWatcher, s as hostId, v as filterSinceTs, y as filterUnread } from "./notifyStore-Dus2D1XA.js";
9
9
  import { n as isWebrtcSpec } from "./webrtcLink-B72AQ2eb.js";
10
- import { a as resolveRemoteSpec, i as readRemotes } from "./remotes-IzQHupeo.js";
10
+ import { a as resolveRemoteSpec, i as readRemotes } from "./remotes-BL2MegXx.js";
11
11
  import { spawn } from "child_process";
12
12
  import ms from "ms";
13
13
  import yargs from "yargs";
@@ -907,7 +907,7 @@ async function runSubcommand(argv) {
907
907
  switch (sub) {
908
908
  case "ls":
909
909
  case "list": return await cmdLs(rest);
910
- case "ps": return await (await import("./cmdPs-4An2s2t8.js")).cmdPs(rest);
910
+ case "ps": return await (await import("./cmdPs-YBWZA9q_.js")).cmdPs(rest);
911
911
  case "status": return await cmdStatus(rest);
912
912
  case "whoami": return await cmdWhoami(rest);
913
913
  case "result": return await cmdResult(rest);
@@ -954,39 +954,39 @@ async function runSubcommand(argv) {
954
954
  return cmdCh(rest);
955
955
  }
956
956
  case "term": {
957
- const { cmdTerm } = await import("./terminal-BxWNOBW4.js");
957
+ const { cmdTerm } = await import("./terminal-CCLw4qIt.js");
958
958
  return cmdTerm(rest);
959
959
  }
960
960
  case "widget": {
961
- const { cmdWidget } = await import("./widget-DobxsxXa.js");
961
+ const { cmdWidget } = await import("./widget-Bf-hAxpl.js");
962
962
  return cmdWidget(rest);
963
963
  }
964
964
  case "mint": {
965
- const { cmdMint } = await import("./widget-DobxsxXa.js");
965
+ const { cmdMint } = await import("./widget-Bf-hAxpl.js");
966
966
  return cmdMint(rest);
967
967
  }
968
968
  case "serve": {
969
- const { cmdServe } = await import("./serve-XWSfUL8i.js");
969
+ const { cmdServe } = await import("./serve-CcVhTYIX.js");
970
970
  return cmdServe(rest);
971
971
  }
972
972
  case "tray": {
973
- const { cmdTray } = await import("./trayApp-XJit7gRr.js");
973
+ const { cmdTray } = await import("./trayApp-10o8DC7r.js");
974
974
  return cmdTray(rest);
975
975
  }
976
976
  case "setup": {
977
- const { cmdSetup } = await import("./setup-B-Cui8R6.js");
977
+ const { cmdSetup } = await import("./setup-CJGkmk3P.js");
978
978
  return cmdSetup(rest);
979
979
  }
980
980
  case "ws": {
981
- const { cmdWs } = await import("./ws-Bk2cJphr.js");
981
+ const { cmdWs } = await import("./ws-CWMIHaJ8.js");
982
982
  return cmdWs(rest);
983
983
  }
984
984
  case "schedule": {
985
- const { cmdSchedule } = await import("./schedule-BdK4RVQ5.js");
985
+ const { cmdSchedule } = await import("./schedule-B8S10ci8.js");
986
986
  return cmdSchedule(rest);
987
987
  }
988
988
  case "remote": {
989
- const { cmdRemote } = await import("./remotes-BiftUp09.js");
989
+ const { cmdRemote } = await import("./remotes-CNNWole7.js");
990
990
  return cmdRemote(rest);
991
991
  }
992
992
  case "expose": {
@@ -994,7 +994,7 @@ async function runSubcommand(argv) {
994
994
  return cmdExpose(rest);
995
995
  }
996
996
  case "callback": {
997
- const { cmdCallback } = await import("./callback-Besk3KFx.js");
997
+ const { cmdCallback } = await import("./callback-Dc1PCZUk.js");
998
998
  return cmdCallback(rest);
999
999
  }
1000
1000
  case "reap":
@@ -1234,10 +1234,10 @@ async function runRemoteLs(remote, opts) {
1234
1234
  }
1235
1235
  const records = await res.json();
1236
1236
  if (records.length === 0) {
1237
- process.stderr.write(remote.keyword ? `no agents matched "${remote.keyword}" on ${remote.url}\n` : `no running agents on ${remote.url}\n`);
1237
+ process.stderr.write(remote.keyword ? `no agents matched "${remote.keyword}" on ${remote.label}\n` : `no running agents on ${remote.label}\n`);
1238
1238
  return 0;
1239
1239
  }
1240
- process.stderr.write(`[remote ${remote.url}]\n`);
1240
+ process.stderr.write(`[remote ${remote.label}]\n`);
1241
1241
  const termWidth = process.stdout.columns ?? 120;
1242
1242
  const widths = {
1243
1243
  pid: Math.max(3, ...records.map((r) => String(r.pid).length)),
@@ -1280,7 +1280,7 @@ async function runRemoteRead(remote, mode, follow, n, reconnectTimeoutMs = 12e4,
1280
1280
  const deadline = Date.now() + reconnectTimeoutMs;
1281
1281
  let delay = 1e3;
1282
1282
  let attempt = 0;
1283
- process.stderr.write(`[remote ${remote.url} ${keyword}]\nfollowing... (Ctrl-C to stop, timeout: ${Math.round(reconnectTimeoutMs / 1e3)}s)\n`);
1283
+ process.stderr.write(`[remote ${remote.label} ${keyword}]\nfollowing... (Ctrl-C to stop, timeout: ${Math.round(reconnectTimeoutMs / 1e3)}s)\n`);
1284
1284
  while (!ac.signal.aborted) try {
1285
1285
  const res = await fetch(`${remote.url}/api/tail/${encodeURIComponent(keyword)}`, {
1286
1286
  headers: {
@@ -1347,7 +1347,7 @@ async function runRemoteRead(remote, mode, follow, n, reconnectTimeoutMs = 12e4,
1347
1347
  return 1;
1348
1348
  }
1349
1349
  const text = await res.text();
1350
- process.stderr.write(`[remote ${remote.url} ${keyword}]\n`);
1350
+ process.stderr.write(`[remote ${remote.label} ${keyword}]\n`);
1351
1351
  process.stdout.write(text);
1352
1352
  if (!text.endsWith("\n")) process.stdout.write("\n");
1353
1353
  return 0;
@@ -1376,7 +1376,7 @@ async function runRemoteSend(remote, msg, code) {
1376
1376
  return 1;
1377
1377
  }
1378
1378
  const data = await res.json();
1379
- process.stdout.write(`sent to remote pid ${data.pid} (${remote.url} ${keyword})\n`);
1379
+ process.stdout.write(`sent to remote pid ${data.pid} (${remote.label} ${keyword})\n`);
1380
1380
  if (msg && msg !== "-") await recordOutbox({
1381
1381
  at: Date.now(),
1382
1382
  from,
@@ -1390,7 +1390,7 @@ async function runRemoteSend(remote, msg, code) {
1390
1390
  code: code.toLowerCase() === "enter" ? void 0 : code.toLowerCase(),
1391
1391
  confirmed: true,
1392
1392
  wrapped: false,
1393
- remote: remote.url
1393
+ remote: remote.label
1394
1394
  });
1395
1395
  return 0;
1396
1396
  }
@@ -1417,7 +1417,7 @@ async function runRemoteSpawn(remote, hint, spec) {
1417
1417
  } catch (e) {
1418
1418
  const name = e?.name;
1419
1419
  if (name === "TimeoutError" || name === "AbortError") {
1420
- process.stderr.write(`remote spawn: no response from ${remote.url} within ${Math.round(SPAWN_TIMEOUT_MS / 1e3)}s — result UNKNOWN (not retried).\n ay ls ${hint} # check whether it started\n`);
1420
+ process.stderr.write(`remote spawn: no response from ${remote.label} within ${Math.round(SPAWN_TIMEOUT_MS / 1e3)}s — result UNKNOWN (not retried).\n ay ls ${hint} # check whether it started\n`);
1421
1421
  return 2;
1422
1422
  }
1423
1423
  process.stderr.write(`remote spawn failed: ${e.message}\n`);
@@ -1428,7 +1428,7 @@ async function runRemoteSpawn(remote, hint, spec) {
1428
1428
  return 1;
1429
1429
  }
1430
1430
  const r = await res.json();
1431
- process.stdout.write(`spawned ${r.cli} on ${remote.url} in ${r.cwd}${r.hook ? " (via spawn hook)" : ""}${r.provisioned ? ` (${r.provisioned.action})` : ""}\n`);
1431
+ process.stdout.write(`spawned ${r.cli} on ${remote.label} in ${r.cwd}${r.hook ? " (via spawn hook)" : ""}${r.provisioned ? ` (${r.provisioned.action})` : ""}\n`);
1432
1432
  if (r.agentId && !hint.includes("://")) process.stderr.write(`\n ay tail ${hint}:${r.agentId} # watch its output\n ay status ${hint}:${r.agentId} --wait # block until it needs you\n`);
1433
1433
  else process.stderr.write(`\n ay ls ${hint} # the new ${r.cli} agent appears here\n`);
1434
1434
  return 0;
@@ -3500,7 +3500,7 @@ async function cmdAttach(rest) {
3500
3500
  const winsizeDir = path.join(ayHome, "winsize");
3501
3501
  await mkdir(winsizeDir, { recursive: true });
3502
3502
  const winsizePath = path.join(winsizeDir, String(record.pid));
3503
- const { resolveDaemonHttpBase, loadTokenReadOnly } = await import("./serve-XWSfUL8i.js");
3503
+ const { resolveDaemonHttpBase, loadTokenReadOnly } = await import("./serve-CcVhTYIX.js");
3504
3504
  const daemonBase = await resolveDaemonHttpBase().catch(() => null);
3505
3505
  const daemonToken = daemonBase ? await loadTokenReadOnly().catch(() => null) ?? "" : "";
3506
3506
  const capViewer = `attach:${process.pid}`;
@@ -4210,7 +4210,7 @@ async function cmdNotify(rest) {
4210
4210
  }
4211
4211
  const ensure = async () => {
4212
4212
  if (!argv["ensure-daemon"]) return;
4213
- const { ensureDaemon } = await import("./notifyDaemon-kIOLWrEI.js");
4213
+ const { ensureDaemon } = await import("./notifyDaemon-ByJtcbbX.js");
4214
4214
  await ensureDaemon().catch(() => null);
4215
4215
  };
4216
4216
  await heartbeatWatcher(parent, selfStartedAt);
@@ -4284,7 +4284,7 @@ async function cmdNotifyCursor(args) {
4284
4284
  }
4285
4285
  async function cmdNotifyd(rest) {
4286
4286
  const sub = rest[0] ?? "status";
4287
- const daemon = await import("./notifyDaemon-kIOLWrEI.js");
4287
+ const daemon = await import("./notifyDaemon-ByJtcbbX.js");
4288
4288
  switch (sub) {
4289
4289
  case "run": return daemon.runDaemon();
4290
4290
  case "once": return daemon.runDaemon({ once: true });
@@ -4311,4 +4311,4 @@ async function cmdNotifyd(rest) {
4311
4311
 
4312
4312
  //#endregion
4313
4313
  export { TYPING_BADGE as $, menuSelectKeys as A, resolveOne as B, isSubcommand as C, lastStdinAt as D, lastReadAt as E, recentMessageEdges as F, snapshotStatus as G, resolveResumeArgs as H, recentReadEdges as I, submitAndConfirm as J, stdinActivityPath as K, renderLogTailLines as L, readLogForRender as M, readNotes as N, listRecords as O, readPtysize as P, withIpcLock as Q, renderRawLog as R, isSlashCommand as S, isUserTyping as T, restartHintLines as U, resolveReadWindow as V, runSubcommand as W, writeKeysPaced as X, waitForLogQuiet as Y, writeToIpc as Z, finalizedLines as _, TYPING_WINDOW_MS as a, isExitRequest as b, cmdHelp as c, deriveLiveState as d, buildAgentForest as et, deriveLiveStatus as f, extractTaskCounts as g, extractNeedsInput as h, READ_WINDOW_MS as i, readAgentPtysize as j, matchKeyword as k, controlCodeFromName as l, extractMenu as m, MAX_RENDER_BYTES as n, backoffWhileTyping as o, extractBadges as p, stopTipForCli as q, READ_PAGE_DEFAULT as r, cmdDeepseek as s, GRACEFUL_EXIT_COMMANDS as t, flattenForest as tt, cursorAbs as u, isAgentStuck as v, isUnknownManagerToken as w, isPidAlive as x, isBareManagerInvocation as y, renderRawLogLines as z };
4314
- //# sourceMappingURL=subcommands-C3NO344d.js.map
4314
+ //# sourceMappingURL=subcommands-DX0iQzwD.js.map
@@ -98,7 +98,7 @@ async function cmdTermMint(args) {
98
98
  if (flags.ro && flags.interactive) throw new Error("--ro and --interactive are mutually exclusive");
99
99
  const ttlSec = parseTtlSec(typeof flags.ttl === "string" ? flags.ttl : "15m");
100
100
  const canSend = flags.interactive === true;
101
- const { mintScopedTermToken } = await import("./serve-XWSfUL8i.js");
101
+ const { mintScopedTermToken } = await import("./serve-CcVhTYIX.js");
102
102
  const r = await mintScopedTermToken(pid, {
103
103
  ttlSec,
104
104
  canSend
@@ -135,4 +135,4 @@ async function cmdTerm(args) {
135
135
 
136
136
  //#endregion
137
137
  export { cmdTerm };
138
- //# sourceMappingURL=terminal-BxWNOBW4.js.map
138
+ //# sourceMappingURL=terminal-CCLw4qIt.js.map
@@ -0,0 +1,5 @@
1
+ import "./versionChecker-DHrDPEw3.js";
2
+ import "./rustBinary-DPRR_QOA.js";
3
+ import { a as trayHiddenMarker, i as launchTray, n as hasDesktop, r as isTrayHidden, t as cmdTray } from "./trayApp-BxrNX0KY.js";
4
+
5
+ export { cmdTray };
@@ -1,4 +1,4 @@
1
- import { n as findTrayLauncher } from "./rustBinary-BK03gMMg.js";
1
+ import { n as findTrayLauncher } from "./rustBinary-DPRR_QOA.js";
2
2
  import { t as agentYesHome } from "./agentYesHome-CtmsY6I-.js";
3
3
  import { existsSync } from "node:fs";
4
4
  import path from "node:path";
@@ -97,4 +97,4 @@ async function cmdTray(args) {
97
97
 
98
98
  //#endregion
99
99
  export { trayHiddenMarker as a, launchTray as i, hasDesktop as n, isTrayHidden as r, cmdTray as t };
100
- //# sourceMappingURL=trayApp-CcQDIINw.js.map
100
+ //# sourceMappingURL=trayApp-BxrNX0KY.js.map
@@ -1,6 +1,6 @@
1
1
  import { n as __esmMin, r as __exportAll } from "./chunk-cZBX9HZv.js";
2
2
  import { n as logger, t as addTransport } from "./logger-CDIsZ-Pp.js";
3
- import { r as getInstalledPackage } from "./versionChecker-DCtcFwZ7.js";
3
+ import { r as getInstalledPackage } from "./versionChecker-DHrDPEw3.js";
4
4
  import { t as agentYesHome } from "./agentYesHome-CtmsY6I-.js";
5
5
  import { u as removeControlCharacters } from "./todoAutomation-BETGOik9.js";
6
6
  import { i as shouldUseLock, r as releaseLock, t as acquireLock } from "./runningLock-DBoONoM-.js";
@@ -2074,7 +2074,7 @@ async function agentYes({ cli, cliArgs = [], skipPermissions = false, prompt, ro
2074
2074
  }, 100);
2075
2075
  const cleanupHeartbeat = () => clearInterval(heartbeatInterval);
2076
2076
  shell.onExit(cleanupHeartbeat);
2077
- const { startParentPingLoop } = await import("./parentPingLoop-D2A9Fkhf.js");
2077
+ const { startParentPingLoop } = await import("./parentPingLoop-D1oxgeES.js");
2078
2078
  const parentPingLoop = startParentPingLoop({
2079
2079
  parentPid,
2080
2080
  selfWrapperPid: process.pid,
@@ -2338,4 +2338,4 @@ function sleep(ms) {
2338
2338
 
2339
2339
  //#endregion
2340
2340
  export { hasTodoStore as a, permissionBadge as c, answerAsk as i, AgentContext as l, agentYes as n, listAsks as o, config as r, listAsksForProject as s, CLIS_CONFIG as t, CLAUDE_SESSION_PIN_ENV as u };
2341
- //# sourceMappingURL=ts-BG759sO1.js.map
2341
+ //# sourceMappingURL=ts-C5yjBnoI.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.271.0";
10
+ var version = "1.272.0-beta.658.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-DCtcFwZ7.js.map
218
+ //# sourceMappingURL=versionChecker-DHrDPEw3.js.map
@@ -28,7 +28,7 @@ function parseFlags(args, known) {
28
28
  }
29
29
  /** Resolve the local daemon base URL + token (flags override discovery). */
30
30
  async function daemonTarget(flags) {
31
- const { resolveDaemonHttpBase, loadTokenReadOnly } = await import("./serve-XWSfUL8i.js");
31
+ const { resolveDaemonHttpBase, loadTokenReadOnly } = await import("./serve-CcVhTYIX.js");
32
32
  const base = typeof flags.base === "string" ? flags.base : await resolveDaemonHttpBase();
33
33
  if (!base) throw new Error("no running ay serve daemon found — start `ay serve` or pass --base <url> (e.g. http://127.0.0.1:PORT)");
34
34
  const token = typeof flags.token === "string" ? flags.token : await loadTokenReadOnly() ?? "";
@@ -186,7 +186,7 @@ async function cmdMint(args) {
186
186
  const bad = caps.filter((c) => !KNOWN_CAPS.has(c));
187
187
  if (bad.length) throw new Error(`unknown cap(s): ${bad.join(", ")} (valid: ${[...KNOWN_CAPS].join(", ")})`);
188
188
  const ttlSec = parseTtlSec(typeof flags.ttl === "string" ? flags.ttl : "15m");
189
- const { mintScopedTermToken } = await import("./serve-XWSfUL8i.js");
189
+ const { mintScopedTermToken } = await import("./serve-CcVhTYIX.js");
190
190
  const r = await mintScopedTermToken(target, {
191
191
  ttlSec,
192
192
  caps
@@ -202,4 +202,4 @@ async function cmdMint(args) {
202
202
 
203
203
  //#endregion
204
204
  export { cmdMint, cmdWidget };
205
- //# sourceMappingURL=widget-DobxsxXa.js.map
205
+ //# sourceMappingURL=widget-Bf-hAxpl.js.map
@@ -3,10 +3,10 @@ import "./globalPidIndex-Dq4KY2IV.js";
3
3
  import "./messageLog-BYFwioFY.js";
4
4
  import "./e2e-OLfcNxiv.js";
5
5
  import "./configShared-DYxlvrH0.js";
6
- import "./subcommands-C3NO344d.js";
6
+ import "./subcommands-DX0iQzwD.js";
7
7
  import "./notifyStore-Dus2D1XA.js";
8
8
  import "./webrtcLink-B72AQ2eb.js";
9
- import "./remotes-IzQHupeo.js";
10
- import { a as isPathInside, c as walkWorkspaces, i as importProvisionModule, l as workspaceStatus, n as cmdWs, o as loadProvision, r as collectWorkspaces, s as resolveOperand, t as WS_JSON_SCHEMA } from "./ws-DO1UpPDw.js";
9
+ import "./remotes-BL2MegXx.js";
10
+ import { a as isPathInside, c as walkWorkspaces, i as importProvisionModule, l as workspaceStatus, n as cmdWs, o as loadProvision, r as collectWorkspaces, s as resolveOperand, t as WS_JSON_SCHEMA } from "./ws-KZfHmxtS.js";
11
11
 
12
12
  export { WS_JSON_SCHEMA, cmdWs, collectWorkspaces, isPathInside, loadProvision, walkWorkspaces, workspaceStatus };
@@ -1,4 +1,4 @@
1
- import { O as listRecords } from "./subcommands-C3NO344d.js";
1
+ import { O as listRecords } from "./subcommands-DX0iQzwD.js";
2
2
  import { a as getProvisionRoot } from "./workspaceConfig-EK7XNsgR.js";
3
3
  import { existsSync } from "fs";
4
4
  import { lstat, opendir } from "fs/promises";
@@ -424,4 +424,4 @@ async function cmdWs(args) {
424
424
 
425
425
  //#endregion
426
426
  export { isPathInside as a, walkWorkspaces as c, importProvisionModule as i, workspaceStatus as l, cmdWs as n, loadProvision as o, collectWorkspaces as r, resolveOperand as s, WS_JSON_SCHEMA as t };
427
- //# sourceMappingURL=ws-DO1UpPDw.js.map
427
+ //# sourceMappingURL=ws-KZfHmxtS.js.map
@@ -79,6 +79,22 @@ machine, and any one person's attention.** The long version is a post below —
79
79
  address space, a bus that humans are also on, and delegation with accountability, and it is honest
80
80
  about the four places the current system is still cluttered.
81
81
 
82
+ ## The ecosystem
83
+
84
+ agent-yes is the fleet. Around it sit tools that give the fleet somewhere to *reach* — each a
85
+ standalone CLI in its own right, each usable without the others:
86
+
87
+ | | |
88
+ | --- | --- |
89
+ | **[agent-yes](https://github.com/snomiao/agent-yes)** | run, watch, message and delegate to a fleet of AI coding agents |
90
+ | **[slack-term](https://github.com/snomiao/slack-term)** | the human-comms surface — read and write Slack from a terminal, with a confirm gate built for operators who are sometimes machines |
91
+
92
+ The connective tissue is a shared stance rather than a shared library: file-based state over
93
+ daemons, one command surface across two runtimes, gates on the irreversible and warnings on the
94
+ merely unwise, and a hard rule that no real operational data lands in a public repo. Both projects
95
+ arrived at the same interrupt-safety reasoning against completely different substrates — one over
96
+ `pids.jsonl` and a FIFO, the other over Slack reactions.
97
+
82
98
  ---
83
99
 
84
100
  ## Notes
@@ -0,0 +1,240 @@
1
+ ---
2
+ title: A confirm code that goes stale — how slack-term makes agents safe to give a voice
3
+ tag: Ecosystem
4
+ summary: slack-term is the agent-yes fleet's human-comms surface. Its confirm gate hashes the destination, the actor and the conversation's current last message — so it expires the moment anything that mattered moves. Plus what it gets right, and where it is thinner than its README claims.
5
+ ---
6
+
7
+ <p class="lede">An agent that can only read is a curiosity. An agent that can write into the
8
+ channel where your colleagues work is either infrastructure or a hazard, and which one it is
9
+ comes down to a handful of design decisions. <a
10
+ href="https://github.com/snomiao/slack-term">slack-term</a> is the Slack CLI the agent-yes fleet
11
+ uses to talk to humans, and it is worth reading for one idea in particular: a confirmation code
12
+ that <b>goes stale when the conversation moves</b>.</p>
13
+
14
+ ## Where it sits in the ecosystem
15
+
16
+ agent-yes gives a fleet of agents an address space — they can be listed, tailed, messaged and
17
+ delegated to. But a fleet that can only talk to itself is a closed loop. The parts of the system
18
+ that face *humans* are the ones that decide whether any of it is useful: `ay callback` puts a reply
19
+ box on a published report, `ay ch` gives humans and agents one channel, and slack-term takes the
20
+ fleet into the place work already happens.
21
+
22
+ That last one carries a different risk profile from the rest. A callback widget is send-only into a
23
+ terminal you own. Posting to `#general` is irreversible, public, and attributed to *you*. So the
24
+ interesting engineering is not the Slack API wrapper — it is everything built around the moment of
25
+ writing.
26
+
27
+ ## The gate: hash the write, not the intent
28
+
29
+ Every gated write — `send`, `edit`, `delete`, `upload`, `schedule`, `channel create`, `drafts` —
30
+ runs twice. The first run previews and prints a 4-hex code; the second run must present it:
31
+
32
+ ```
33
+ $ slack send "#general" "deploying v2 now"
34
+ From: @alice (U00000001) — Acme
35
+ To: #general
36
+ ...preview of the channel's recent messages...
37
+ Rerun with --code=3f9c
38
+
39
+ $ slack send "#general" "deploying v2 now" --code=3f9c
40
+ ```
41
+
42
+ The code is not a nonce and there is no server, no session, and no stored state. It is
43
+ `sha256(parts.join("\n")).slice(0, 4)` — recomputed from scratch on both runs. What goes into
44
+ `parts` is the whole design (`ts/cli.ts:1433`):
45
+
46
+ ```js
47
+ const code = safetyCode(channelId, threadTs ?? "", lastText, message, self?.userId ?? "");
48
+ ```
49
+
50
+ Read that as a list of things that must not have changed between preview and confirm:
51
+
52
+ - **`channelId` + `threadTs`** — a code minted for one destination cannot confirm a send to another.
53
+ - **`self.userId`** — the acting identity. Preview as one profile, switch, confirm → the code is
54
+ dead. Every gate prints a `From: @handle (Uxxxx) — Workspace` line naming who it will act as, and
55
+ binds that identity into the code, so the label cannot drift from the act.
56
+ - **`lastText`** — **the destination's current last message.**
57
+
58
+ That third one is the good idea. If anyone posts between your preview and your confirm, the code
59
+ you were given no longer verifies, and you are shown the conversation again before you can proceed.
60
+ It is a time-of-check/time-of-use defense built out of content rather than a clock: **no timestamp,
61
+ no expiry, no session — freshness is derived from the thing that would make you change your mind.**
62
+ For `edit` and `delete`, the same trick binds the target's *current remote text*, so you cannot
63
+ edit-over something that was rewritten while you were reading it.
64
+
65
+ ## Gates block, guards warn
66
+
67
+ Four heuristics fire around a send, and not one of them can stop it:
68
+
69
+ | | |
70
+ | --- | --- |
71
+ | **near-duplicate** | character-bigram Dice similarity over normalized text; warns at ≥0.82 against messages already in the thread |
72
+ | **unreplied** | the destination's last message is already yours — you are about to double-post, so it prints a ready-to-paste `slack edit` command for that message instead |
73
+ | **self-DM** | DMing yourself with your own user token delivers but never notifies |
74
+ | **mentions** | `@handle` tokens that could not be resolved will post as plain text and notify nobody |
75
+
76
+ All four are `console.error` and fall through. The only hard stop in the whole path is a missing or
77
+ wrong `--code`.
78
+
79
+ That split is worth stating as a rule, because it is what keeps the system coherent: **irreversible
80
+ things get a gate; advisory things get a line on stderr.** Heuristics that can block teach people to
81
+ reach for a bypass flag — and the moment a bypass flag exists, it will eventually be used on the
82
+ real gate too. Because the fuzzy signals stay advisory, the repo ships **no `--yes`, no `--force`,
83
+ no `SKIP_CONFIRM`** at all.
84
+
85
+ ## The honest part: it is a review gate, not an authorization gate
86
+
87
+ Here is the thing the project is refreshingly clear-eyed about. The gate holds no secret. The
88
+ expected code is deterministic, and the CLI prints it straight back to you on a wrong-code retry:
89
+
90
+ ```
91
+ Code mismatch (got 0000, expected 3f9c)
92
+ Rerun with --code=3f9c
93
+ ```
94
+
95
+ Any script can defeat that in two lines — and the repo's own test suite does exactly that, regexing
96
+ `--code=([0-9a-f]{4})` out of stderr at roughly 19 call sites. The Rust implementation says so in
97
+ its own source: *"Always print the hash so scripts can capture and rerun."*
98
+
99
+ So the gate is not a permission boundary. It is a **forced-review step**: it makes the default path
100
+ one where a human or an agent must look at a rendered preview of exactly what will be posted, where,
101
+ and as whom, before anything happens. An agent determined to route around it can. The value is that
102
+ nothing does so *by accident* — and accident, not malice, is what actually posts to the wrong
103
+ channel at 3am.
104
+
105
+ Calling that out is better engineering than pretending otherwise, because a team that believes a
106
+ review gate is an authorization gate will eventually put something behind it that needed a real one.
107
+
108
+ ## Display names are attacker-controlled
109
+
110
+ Anyone in a Slack workspace can set their own display name, and that name gets drawn into your
111
+ terminal — inside the confirm preview you are about to make a decision from.
112
+ `stripTerminalControls()` (`ts/cli.ts:811`) removes ANSI CSI sequences, all C0/C1 control characters
113
+ including a lone ESC, **and Unicode bidi controls** (LRM/RLM, LRE/RLE/PDF/LRO/RLO, LRI/RLI/FSI/PDI).
114
+
115
+ Stripping ANSI is common. Remembering that a right-to-left override can visually reorder the line
116
+ that is supposed to be telling you what you are about to send is not. Sanitizing *the preview
117
+ itself* follows from taking the gate seriously: a preview that can be made to lie is worse than no
118
+ preview, because it is trusted.
119
+
120
+ The coverage is deliberate but not yet total — it is applied to the sender label and the mention
121
+ previews; the gate's own quoted message previews and channel labels still render Slack-controlled
122
+ text unstripped.
123
+
124
+ ## A denylist stored as hashes
125
+
126
+ The repo is public and its test fixtures come from real Slack recordings, so it treats its own
127
+ corpus as a leak risk. `.githooks/denylist.sha256` holds ~26 SHA-256 hashes and no plaintext, and
128
+ says why in the file:
129
+
130
+ > Stored as hashes on purpose: this repo is public, so it must not spell out the real names and IDs
131
+ > it is protecting.
132
+
133
+ A plaintext list of the names you are protecting is itself the disclosure. There is a second-order
134
+ reason too: plaintext would be rewritten by any future history scrub, silently inverting what the
135
+ hook blocks.
136
+
137
+ Two modes, and the docs are explicit about why both must exist:
138
+
139
+ | mode | sees | role |
140
+ | --- | --- | --- |
141
+ | default | the **staged diff** — added lines only | commit hook |
142
+ | `--all` | **every tracked file** | `prepublishOnly` + CI |
143
+
144
+ The commit hook is *structurally blind* to data already sitting in the tree: committed once, never
145
+ re-added by any later diff, therefore invisible to every future staged scan. That blind spot is not
146
+ hypothetical — it is how real workspace data once reached npm, and the whole-tree gate exists
147
+ specifically to close it. One scanner, three enforcement points (hook, CI, publish), no
148
+ reimplementation per venue.
149
+
150
+ The placeholder scheme deserves a mention because it is *machine-decidable* rather than a style
151
+ guide. A real Slack ID is a type letter followed by 8+ `[A-Z0-9]` **whose tail mixes letters and
152
+ digits**; a `0000` run separately marks an ID as fake. Testing the tail rather than the whole string
153
+ is load-bearing: the leading `C` of `C00000001` would otherwise count as "the letter" and make every
154
+ placeholder read as real. It scans fixture **filenames** as well as bodies.
155
+
156
+ ## Built so an agent is a good citizen
157
+
158
+ The affordances that only make sense when the operator is a machine:
159
+
160
+ - **Reaction-as-ack is deliberately ungated** — "a reaction is trivial and fully reversible, and the
161
+ whole point is a lightweight ack." The cheap polite action stays frictionless while the loud one
162
+ stays gated. 👀 for *seen*, ✅ for *done*, ⏳ for *working on it* — a thread that does not grow.
163
+ - **`--unreplied`** — "only conversations whose last word isn't mine." Whose ball it is, computed
164
+ rather than guessed.
165
+ - **`[+N replies]`** — Slack's history endpoint returns thread parents but no replies, so a naive
166
+ renderer hides entire conversations. Marking them means a reader is never misled into thinking it
167
+ has read everything.
168
+ - **stdout is data, stderr is commentary** in the streaming path, so `slack tail "#general" | grep
169
+ deploy` sees messages and not chrome.
170
+ - **Output is valid input** — a printed permalink or ISO stamp can be pasted straight back as a
171
+ target, with strict parsers that throw rather than guess.
172
+ - **`SKILL.md` ships in the npm tarball** with agent-skill frontmatter, so it triggers on how a user
173
+ *talks* ("any mentions?", "DM @person") rather than on the tool's name.
174
+
175
+ Then there is `ts/todo.ts`, which encodes task state entirely in Slack reactions — 📌 marker,
176
+ ✅/🚫/👀/⏳ progress, stacking reason flags — with no external store, so humans see the same state in
177
+ the Slack UI that the agent queries. Two comments in that file are the best writing in either repo.
178
+
179
+ The first records a **measured negative result**:
180
+
181
+ > the obvious alternative — posting a machine-readable token like `todo:v1 blocked-on=@alice` — does
182
+ > NOT work: Slack's full-text index splits on punctuation, so a quoted search for "blocked-on"
183
+ > returns 0 hits (measured), and "1.91" matches 1.91.0.
184
+
185
+ The second explains an ordering invariant:
186
+
187
+ > **ORDER IS THE WHOLE POINT**: `reactions.add` runs FIRST, then removes. Never invert this.
188
+ > Removing first leaves a window with zero progress reactions; a crash, a 429 or a Ctrl-C inside
189
+ > that window drops the task out of every `todo ls` query permanently, with nothing left to point at
190
+ > it.
191
+
192
+ Add-first's worst case is a message carrying two progress reactions — harmless, *because the
193
+ invariant is "at least one, readers collapse by priority" rather than "exactly one."* Choosing the
194
+ weaker invariant is what makes the operation safe to interrupt. Removes are awaited serially because
195
+ `Promise.all` would drop the ordering guarantee. That is the same reasoning agent-yes applies to its
196
+ own file-based fabric, arrived at independently against a completely different substrate.
197
+
198
+ ## Where it is thinner than it looks
199
+
200
+ A fair reading has to include these.
201
+
202
+ **Credentials at rest are unhardened.** `~/.config/slack-cli/profiles.json` holds tokens and session
203
+ cookies and is written with `writeFileSync` and no `mode` argument, so it lands at the process umask
204
+ — typically world-readable. There is no `chmod` call anywhere in `ts/` or `rs/`. For a project this
205
+ careful about every other boundary, this is the odd one out.
206
+
207
+ **"Verified byte-for-byte" oversells the parity test.** The mechanism is real and well-built —
208
+ byte-identical stdout from both runtimes against a mock server, with an isolated `HOME` so no real
209
+ profile bleeds in — but it covers **2 of 23 commands** (`news`, `search`), and it *skips silently*
210
+ when the Rust binary or the fixtures are absent. A gate that skips by default is not a gate. Worse,
211
+ the one thing that most needs to match across implementations — the write gate — is the thing that
212
+ matches least: the Rust `send` uses `--confirm` rather than `--code`, binds neither the thread nor
213
+ the acting identity, and collapses to `sha256(message)` when its context fetch comes back empty.
214
+
215
+ The two runtimes are not really peers; one is the product and the other is a frozen subset. Compare
216
+ agent-yes, which has the same TS/Rust split and solves it with the opposite polarity: it does not
217
+ diff behavior, it *pins the surface* — a test parses both `ts/subcommands.ts` and `rs/src/cli.rs` as
218
+ text and fails when the subcommand lists disagree, and everything else lives in a parity table
219
+ allowed to say "not planned." Enforce the surface, negotiate the behavior.
220
+
221
+ **`SKILL.md` still points agents at a deprecated package.** It says to install `@snomiao/slack`; the
222
+ README marks that deprecated in favour of `slack-term`. Of the three, this is the one that actively
223
+ misleads, because SKILL.md is the file an agent reads.
224
+
225
+ ## What carries over
226
+
227
+ Three ideas here are worth stealing regardless of Slack:
228
+
229
+ 1. **Bind your confirmation to the state that would change your mind.** Not a nonce, not a
230
+ timestamp — the destination, the actor, and the conversation's current last message. It goes
231
+ stale exactly when it should.
232
+ 2. **Gates block, guards warn — and never mix them.** One hard stop, uniformly applied, is
233
+ comprehensible and needs no bypass flag. The moment a fuzzy heuristic can block, someone builds a
234
+ `--force`, and then it is on the real gate too.
235
+ 3. **Say which one you built.** A forced-review step and an authorization boundary look similar from
236
+ the outside and fail very differently. Naming it correctly is what stops someone putting
237
+ something behind it that needed the other kind.
238
+
239
+ <p class="note">Related: <a href="./2026-08-11-an-address-space-for-agents">an address space for
240
+ agents</a> — why a fleet needs a bus that humans are on too.</p>
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "agent-yes",
3
- "version": "1.271.0",
3
+ "version": "1.272.0-beta.658.1",
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",
package/ts/remotes.ts CHANGED
@@ -2,7 +2,7 @@ import { mkdir, readFile, writeFile } from "fs/promises";
2
2
  import { homedir } from "os";
3
3
  import path from "path";
4
4
  import yaml from "yaml";
5
- import { isWebrtcSpec } from "./webrtcLink.ts";
5
+ import { isWebrtcSpec, parseWebrtcLink } from "./webrtcLink.ts";
6
6
 
7
7
  function remotesPath(): string {
8
8
  const dir = process.env.AGENT_YES_HOME ?? path.join(homedir(), ".agent-yes");
@@ -18,6 +18,14 @@ export interface ResolvedRemote {
18
18
  url: string;
19
19
  token: string;
20
20
  keyword?: string;
21
+ /** Stable, human-readable name for display — never the loopback bridge URL. */
22
+ label: string;
23
+ }
24
+
25
+ /** A display label for a WebRTC share link: the room id, never the local bridge. */
26
+ function webrtcLabel(link: string): string {
27
+ const parsed = parseWebrtcLink(link);
28
+ return parsed ? `webrtc:${parsed.room}` : "webrtc";
21
29
  }
22
30
 
23
31
  export async function readRemotes(): Promise<Map<string, RemoteConfig>> {
@@ -82,11 +90,16 @@ export function parseDirectRemoteSpec(
82
90
  export async function resolveRemoteSpec(spec: string): Promise<ResolvedRemote | null> {
83
91
  // Inline WebRTC share link: `ay ls webrtc://…` or `ay ls https://…/w/#room:token`.
84
92
  // These carry their own secret and have no keyword (use an alias to add one).
85
- if (isWebrtcSpec(spec)) return resolveWebrtc(spec, undefined);
93
+ if (isWebrtcSpec(spec)) return resolveWebrtc(spec, undefined, webrtcLabel(spec));
86
94
 
87
95
  const direct = parseDirectRemoteSpec(spec);
88
96
  if (direct) {
89
- return { url: direct.baseUrl, token: direct.token, keyword: direct.keyword };
97
+ return {
98
+ url: direct.baseUrl,
99
+ token: direct.token,
100
+ keyword: direct.keyword,
101
+ label: `${direct.host}:${direct.port}`,
102
+ };
90
103
  }
91
104
 
92
105
  // alias[:keyword]
@@ -98,8 +111,8 @@ export async function resolveRemoteSpec(spec: string): Promise<ResolvedRemote |
98
111
  const cfg = remotes.get(alias);
99
112
  if (!cfg) return null;
100
113
  // A saved alias may point at a WebRTC link; bridge it just like an inline one.
101
- if (isWebrtcSpec(cfg.url)) return resolveWebrtc(cfg.url, keyword);
102
- return { url: cfg.url, token: cfg.token, keyword };
114
+ if (isWebrtcSpec(cfg.url)) return resolveWebrtc(cfg.url, keyword, alias);
115
+ return { url: cfg.url, token: cfg.token, keyword, label: alias };
103
116
  }
104
117
 
105
118
  /**
@@ -107,10 +120,14 @@ export async function resolveRemoteSpec(spec: string): Promise<ResolvedRemote |
107
120
  * ordinary http remote, so every fetch-based remote command works unchanged.
108
121
  * The bridge lives for the rest of the process (torn down on `process.exit`).
109
122
  */
110
- async function resolveWebrtc(link: string, keyword?: string): Promise<ResolvedRemote> {
123
+ async function resolveWebrtc(
124
+ link: string,
125
+ keyword: string | undefined,
126
+ label: string,
127
+ ): Promise<ResolvedRemote> {
111
128
  const { startWebrtcBridge } = await import("./webrtcRemote.ts");
112
129
  const bridge = await startWebrtcBridge(link);
113
- return { url: bridge.baseUrl, token: bridge.token, keyword };
130
+ return { url: bridge.baseUrl, token: bridge.token, keyword, label };
114
131
  }
115
132
 
116
133
  // ---------------------------------------------------------------------------
package/ts/subcommands.ts CHANGED
@@ -1181,12 +1181,12 @@ async function runRemoteLs(
1181
1181
  if (records.length === 0) {
1182
1182
  process.stderr.write(
1183
1183
  remote.keyword
1184
- ? `no agents matched "${remote.keyword}" on ${remote.url}\n`
1185
- : `no running agents on ${remote.url}\n`,
1184
+ ? `no agents matched "${remote.keyword}" on ${remote.label}\n`
1185
+ : `no running agents on ${remote.label}\n`,
1186
1186
  );
1187
1187
  return 0;
1188
1188
  }
1189
- process.stderr.write(`[remote ${remote.url}]\n`);
1189
+ process.stderr.write(`[remote ${remote.label}]\n`);
1190
1190
  const termWidth = (process.stdout as any).columns ?? 120;
1191
1191
  const widths = {
1192
1192
  pid: Math.max(3, ...records.map((r: any) => String(r.pid).length)),
@@ -1249,7 +1249,7 @@ async function runRemoteRead(
1249
1249
  let attempt = 0;
1250
1250
 
1251
1251
  process.stderr.write(
1252
- `[remote ${remote.url} ${keyword}]\nfollowing... (Ctrl-C to stop, timeout: ${Math.round(reconnectTimeoutMs / 1000)}s)\n`,
1252
+ `[remote ${remote.label} ${keyword}]\nfollowing... (Ctrl-C to stop, timeout: ${Math.round(reconnectTimeoutMs / 1000)}s)\n`,
1253
1253
  );
1254
1254
 
1255
1255
  while (!ac.signal.aborted) {
@@ -1325,7 +1325,7 @@ async function runRemoteRead(
1325
1325
  return 1;
1326
1326
  }
1327
1327
  const text = await res.text();
1328
- process.stderr.write(`[remote ${remote.url} ${keyword}]\n`);
1328
+ process.stderr.write(`[remote ${remote.label} ${keyword}]\n`);
1329
1329
  process.stdout.write(text);
1330
1330
  if (!text.endsWith("\n")) process.stdout.write("\n");
1331
1331
  return 0;
@@ -1359,7 +1359,7 @@ async function runRemoteSend(remote: ResolvedRemote, msg: string, code: string):
1359
1359
  cwd?: string;
1360
1360
  agentId?: string;
1361
1361
  };
1362
- process.stdout.write(`sent to remote pid ${data.pid} (${remote.url} ${keyword})\n`);
1362
+ process.stdout.write(`sent to remote pid ${data.pid} (${remote.label} ${keyword})\n`);
1363
1363
  // Record the sender's half of the exchange locally (the recipient's inbox is
1364
1364
  // recorded on the remote host by its /api/send handler). Only real bodies.
1365
1365
  if (msg && msg !== "-") {
@@ -1376,7 +1376,7 @@ async function runRemoteSend(remote: ResolvedRemote, msg: string, code: string):
1376
1376
  code: code.toLowerCase() === "enter" ? undefined : code.toLowerCase(),
1377
1377
  confirmed: true,
1378
1378
  wrapped: false,
1379
- remote: remote.url,
1379
+ remote: remote.label,
1380
1380
  });
1381
1381
  }
1382
1382
  return 0;
@@ -1419,7 +1419,7 @@ async function runRemoteSpawn(
1419
1419
  if (name === "TimeoutError" || name === "AbortError") {
1420
1420
  // The request may or may not have spawned — do NOT retry. Let the operator check.
1421
1421
  process.stderr.write(
1422
- `remote spawn: no response from ${remote.url} within ${Math.round(SPAWN_TIMEOUT_MS / 1000)}s — ` +
1422
+ `remote spawn: no response from ${remote.label} within ${Math.round(SPAWN_TIMEOUT_MS / 1000)}s — ` +
1423
1423
  `result UNKNOWN (not retried).\n ay ls ${hint} # check whether it started\n`,
1424
1424
  );
1425
1425
  return 2;
@@ -1440,7 +1440,7 @@ async function runRemoteSpawn(
1440
1440
  provisioned?: { action: string };
1441
1441
  };
1442
1442
  process.stdout.write(
1443
- `spawned ${r.cli} on ${remote.url} in ${r.cwd}` +
1443
+ `spawned ${r.cli} on ${remote.label} in ${r.cwd}` +
1444
1444
  `${r.hook ? " (via spawn hook)" : ""}` +
1445
1445
  `${r.provisioned ? ` (${r.provisioned.action})` : ""}\n`,
1446
1446
  );
@@ -1,5 +0,0 @@
1
- import "./versionChecker-DCtcFwZ7.js";
2
- import "./rustBinary-BK03gMMg.js";
3
- import { a as trayHiddenMarker, i as launchTray, n as hasDesktop, r as isTrayHidden, t as cmdTray } from "./trayApp-CcQDIINw.js";
4
-
5
- export { cmdTray };