agent-yes 1.237.0 → 1.238.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (28) hide show
  1. package/dist/{SUPPORTED_CLIS-C0RwjYrz.js → SUPPORTED_CLIS-CtgC_d_l.js} +3 -3
  2. package/dist/{SUPPORTED_CLIS-CDrJz9Xo.js → SUPPORTED_CLIS-NpYW9OaR.js} +2 -2
  3. package/dist/{agentShare-Cl_J3dfx.js → agentShare-549Zwi_B.js} +2 -2
  4. package/dist/{callback-CFbkvqTh.js → callback-B-ojDckO.js} +2 -2
  5. package/dist/{callback-D0_AeyN1.js → callback-BNJMOVlW.js} +3 -3
  6. package/dist/cli.js +4 -4
  7. package/dist/index.js +2 -2
  8. package/dist/{notifyDaemon-D_8TRVHt.js → notifyDaemon-CjBVeWRg.js} +2 -2
  9. package/dist/{rustBinary-Bb9qJZ5w.js → rustBinary-DSorJMBV.js} +2 -2
  10. package/dist/{schedule-B8Erb3y6.js → schedule-Bw3SL5Hv.js} +4 -4
  11. package/dist/{serve-QejbNTr-.js → serve-BLxmap1e.js} +217 -37
  12. package/dist/{setup-Dzi5Cc3g.js → setup-DlFVw_1n.js} +2 -2
  13. package/dist/{subcommands-ymJWO2iv.js → subcommands-A0uOpmco.js} +1 -1
  14. package/dist/{subcommands-DFr-5FOL.js → subcommands-BdBCxZVu.js} +20 -10
  15. package/dist/{terminal-vNeFNLT8.js → terminal-w7drEaJc.js} +2 -2
  16. package/dist/{ts-Dd1FK7sR.js → ts-EvHuyNA9.js} +2 -2
  17. package/dist/{versionChecker-XfEBINhH.js → versionChecker-DNLNn_SL.js} +2 -2
  18. package/dist/widget-Coav85Lx.js +172 -0
  19. package/dist/widget.js +162 -0
  20. package/dist/widgets.js +2 -1
  21. package/dist/{ws-Dun8gGiV.js → ws-3prv2in5.js} +2 -2
  22. package/package.json +5 -1
  23. package/ts/serve.ts +234 -19
  24. package/ts/subcommands.ts +12 -0
  25. package/ts/termToken.spec.ts +25 -3
  26. package/ts/termToken.ts +35 -8
  27. package/ts/widget.ts +207 -0
  28. package/ts/widgets.ts +2 -0
@@ -1,11 +1,11 @@
1
1
  import "./logger-CDIsZ-Pp.js";
2
- import "./versionChecker-XfEBINhH.js";
3
- import "./ts-Dd1FK7sR.js";
2
+ import "./versionChecker-DNLNn_SL.js";
3
+ import "./ts-EvHuyNA9.js";
4
4
  import "./todoAutomation-Buo457VO.js";
5
5
  import "./JsonlStore-CPGIR0Wy.js";
6
6
  import "./globalPidIndex-D9DOSd-c.js";
7
7
  import "./pidStore-6EZd5DUv.js";
8
8
  import "./messageLog-C-YIzhRj.js";
9
- import { t as SUPPORTED_CLIS } from "./SUPPORTED_CLIS-CDrJz9Xo.js";
9
+ import { t as SUPPORTED_CLIS } from "./SUPPORTED_CLIS-NpYW9OaR.js";
10
10
 
11
11
  export { SUPPORTED_CLIS };
@@ -1,8 +1,8 @@
1
- import { t as CLIS_CONFIG } from "./ts-Dd1FK7sR.js";
1
+ import { t as CLIS_CONFIG } from "./ts-EvHuyNA9.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-CDrJz9Xo.js.map
8
+ //# sourceMappingURL=SUPPORTED_CLIS-NpYW9OaR.js.map
@@ -3,7 +3,7 @@ import "./globalPidIndex-D9DOSd-c.js";
3
3
  import "./messageLog-C-YIzhRj.js";
4
4
  import "./e2e-CEIdJGZ7.js";
5
5
  import "./configShared-9wVlbPyC.js";
6
- import { N as resolveOne } from "./subcommands-DFr-5FOL.js";
6
+ import { N as resolveOne } from "./subcommands-BdBCxZVu.js";
7
7
  import "./webrtcLink-VQhWmKOw.js";
8
8
  import "./remotes-Bem6WIyU.js";
9
9
  import { a as startShare } from "./share-B9u8-I3y.js";
@@ -229,4 +229,4 @@ function transformEvent(rawEvent, agentId, forwarded) {
229
229
 
230
230
  //#endregion
231
231
  export { createScopedShare, listShares, revokeAllShares, revokeShare };
232
- //# sourceMappingURL=agentShare-Cl_J3dfx.js.map
232
+ //# sourceMappingURL=agentShare-549Zwi_B.js.map
@@ -3,10 +3,10 @@ import "./globalPidIndex-D9DOSd-c.js";
3
3
  import "./messageLog-C-YIzhRj.js";
4
4
  import "./e2e-CEIdJGZ7.js";
5
5
  import "./configShared-9wVlbPyC.js";
6
- import "./subcommands-DFr-5FOL.js";
6
+ import "./subcommands-BdBCxZVu.js";
7
7
  import "./webrtcLink-VQhWmKOw.js";
8
8
  import "./remotes-Bem6WIyU.js";
9
9
  import "./callbackCore-DAYcemCC.js";
10
- import { i as loadOrCreateCallbackSecret, n as isCallbackRevoked, r as loadCallbackSecretReadOnly, t as cmdCallback } from "./callback-D0_AeyN1.js";
10
+ import { i as loadOrCreateCallbackSecret, n as isCallbackRevoked, r as loadCallbackSecretReadOnly, t as cmdCallback } from "./callback-BNJMOVlW.js";
11
11
 
12
12
  export { cmdCallback };
@@ -1,5 +1,5 @@
1
1
  import { t as agentYesHome } from "./agentYesHome-CtmsY6I-.js";
2
- import { N as resolveOne } from "./subcommands-DFr-5FOL.js";
2
+ import { N as resolveOne } from "./subcommands-BdBCxZVu.js";
3
3
  import { a as mintCapability, o as parseExpires } from "./callbackCore-DAYcemCC.js";
4
4
  import { randomBytes } from "node:crypto";
5
5
  import { mkdir, readFile, writeFile } from "node:fs/promises";
@@ -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-QejbNTr-.js");
75
+ const { resolveLocalServeUrl } = await import("./serve-BLxmap1e.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-D0_AeyN1.js.map
190
+ //# sourceMappingURL=callback-BNJMOVlW.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-XfEBINhH.js";
5
- import { n as getRustBinary } from "./rustBinary-Bb9qJZ5w.js";
4
+ import { i as versionString, n as displayVersion, t as checkAndAutoUpdate } from "./versionChecker-DNLNn_SL.js";
5
+ import { n as getRustBinary } from "./rustBinary-DSorJMBV.js";
6
6
  import { argv } from "process";
7
7
  import { spawn } from "child_process";
8
8
  import ms from "ms";
@@ -285,7 +285,7 @@ function buildRustArgs(argv, cliFromScript, supportedClis) {
285
285
  const rawArg = process.argv[2];
286
286
  const managerCommands = !invokedCliName(process.argv);
287
287
  const isHelpFlag = rawArg === "-h" || rawArg === "--help";
288
- const { isSubcommand, runSubcommand, cmdHelp } = await import("./subcommands-ymJWO2iv.js");
288
+ const { isSubcommand, runSubcommand, cmdHelp } = await import("./subcommands-A0uOpmco.js");
289
289
  if (isHelpFlag && process.argv.length === 3) {
290
290
  await cmdHelp(managerCommands);
291
291
  process.exit(0);
@@ -339,7 +339,7 @@ if (config.useRust) {
339
339
  }
340
340
  }
341
341
  if (rustBinary) {
342
- const { SUPPORTED_CLIS } = await import("./SUPPORTED_CLIS-C0RwjYrz.js");
342
+ const { SUPPORTED_CLIS } = await import("./SUPPORTED_CLIS-CtgC_d_l.js");
343
343
  const rustArgs = buildRustArgs(process.argv, config.cli, SUPPORTED_CLIS);
344
344
  if (config.verbose) {
345
345
  console.log(`[rust] Using binary: ${rustBinary}`);
package/dist/index.js CHANGED
@@ -1,6 +1,6 @@
1
1
  import "./logger-CDIsZ-Pp.js";
2
- import "./versionChecker-XfEBINhH.js";
3
- import { a as hasTodoStore, c as AgentContext, i as answerAsk, n as agentYes, o as listAsks, r as config, s as listAsksForProject, t as CLIS_CONFIG } from "./ts-Dd1FK7sR.js";
2
+ import "./versionChecker-DNLNn_SL.js";
3
+ import { a as hasTodoStore, c as AgentContext, i as answerAsk, n as agentYes, o as listAsks, r as config, s as listAsksForProject, t as CLIS_CONFIG } from "./ts-EvHuyNA9.js";
4
4
  import { _ as isKnownKind, a as renderTree, b as statesOf, c as monitorHint, d as openStore, f as DONE_STATE, g as initialState, h as canTransition, i as renderDigest, l as CycleError, m as ORPHANED_STATE, o as unblockedTasks, p as LIFECYCLES, r as openBlockers, s as describeBlock, t as reconcileTodos, u as TodoStore, v as nextStates, x as removeControlCharacters, y as requiredGate } from "./todoAutomation-Buo457VO.js";
5
5
  import "./JsonlStore-CPGIR0Wy.js";
6
6
  import "./globalPidIndex-D9DOSd-c.js";
@@ -3,7 +3,7 @@ import "./globalPidIndex-D9DOSd-c.js";
3
3
  import "./messageLog-C-YIzhRj.js";
4
4
  import "./e2e-CEIdJGZ7.js";
5
5
  import "./configShared-9wVlbPyC.js";
6
- import { $ as daemonLockDir, A as renderLogTailLines, G as appendEvent, K as gcInboxes, Q as shouldStealLock, S as listRecords, X as liveWatchers, Y as listInboxParents, Z as readInbox, _ as isPidAlive, c as deriveLiveState, et as daemonLockOwnerPath, q as hostId, tt as notifyDir } from "./subcommands-DFr-5FOL.js";
6
+ import { $ as daemonLockDir, A as renderLogTailLines, G as appendEvent, K as gcInboxes, Q as shouldStealLock, S as listRecords, X as liveWatchers, Y as listInboxParents, Z as readInbox, _ as isPidAlive, c as deriveLiveState, et as daemonLockOwnerPath, q as hostId, tt as notifyDir } from "./subcommands-BdBCxZVu.js";
7
7
  import "./webrtcLink-VQhWmKOw.js";
8
8
  import "./remotes-Bem6WIyU.js";
9
9
  import { mkdir, readFile, rename, rm, stat, writeFile } from "fs/promises";
@@ -589,4 +589,4 @@ async function ensureDaemon() {
589
589
 
590
590
  //#endregion
591
591
  export { daemonStatus, ensureDaemon, requestDaemonStop, runDaemon };
592
- //# sourceMappingURL=notifyDaemon-D_8TRVHt.js.map
592
+ //# sourceMappingURL=notifyDaemon-CjBVeWRg.js.map
@@ -1,4 +1,4 @@
1
- import { r as getInstalledPackage } from "./versionChecker-XfEBINhH.js";
1
+ import { r as getInstalledPackage } from "./versionChecker-DNLNn_SL.js";
2
2
  import { execFileSync } from "child_process";
3
3
  import { existsSync, mkdirSync, unlinkSync } from "fs";
4
4
  import { chmod, copyFile } from "fs/promises";
@@ -225,4 +225,4 @@ async function getRustBinary(options = {}) {
225
225
 
226
226
  //#endregion
227
227
  export { getRustBinary as n, findSpawnHiddenLauncher as t };
228
- //# sourceMappingURL=rustBinary-Bb9qJZ5w.js.map
228
+ //# sourceMappingURL=rustBinary-DSorJMBV.js.map
@@ -1,12 +1,12 @@
1
1
  import "./logger-CDIsZ-Pp.js";
2
- import "./versionChecker-XfEBINhH.js";
3
- import "./ts-Dd1FK7sR.js";
2
+ import "./versionChecker-DNLNn_SL.js";
3
+ import "./ts-EvHuyNA9.js";
4
4
  import "./todoAutomation-Buo457VO.js";
5
5
  import "./JsonlStore-CPGIR0Wy.js";
6
6
  import "./globalPidIndex-D9DOSd-c.js";
7
7
  import "./pidStore-6EZd5DUv.js";
8
8
  import "./messageLog-C-YIzhRj.js";
9
- import { t as SUPPORTED_CLIS } from "./SUPPORTED_CLIS-CDrJz9Xo.js";
9
+ import { t as SUPPORTED_CLIS } from "./SUPPORTED_CLIS-NpYW9OaR.js";
10
10
  import { d as resolveSpawnCwd } from "./workspaceConfig-B7HaQ-MI.js";
11
11
  import { n as liveEnv, t as ensureNodeRuntime } from "./nodeRuntime-Bf88NPqj.js";
12
12
  import { createHash } from "node:crypto";
@@ -153,4 +153,4 @@ async function cmdSchedule(rest) {
153
153
 
154
154
  //#endregion
155
155
  export { cmdSchedule };
156
- //# sourceMappingURL=schedule-B8Erb3y6.js.map
156
+ //# sourceMappingURL=schedule-Bw3SL5Hv.js.map
@@ -1,7 +1,7 @@
1
1
  import "./logger-CDIsZ-Pp.js";
2
- import { r as getInstalledPackage } from "./versionChecker-XfEBINhH.js";
3
- import { t as findSpawnHiddenLauncher } from "./rustBinary-Bb9qJZ5w.js";
4
- import { i as answerAsk, l as CLAUDE_SESSION_PIN_ENV, o as listAsks } from "./ts-Dd1FK7sR.js";
2
+ import { r as getInstalledPackage } from "./versionChecker-DNLNn_SL.js";
3
+ import { t as findSpawnHiddenLauncher } from "./rustBinary-DSorJMBV.js";
4
+ import { i as answerAsk, l as CLAUDE_SESSION_PIN_ENV, o as listAsks } from "./ts-EvHuyNA9.js";
5
5
  import { t as agentYesHome$1 } from "./agentYesHome-CtmsY6I-.js";
6
6
  import { x as removeControlCharacters } from "./todoAutomation-Buo457VO.js";
7
7
  import "./JsonlStore-CPGIR0Wy.js";
@@ -11,12 +11,12 @@ import { r as recordInbox } from "./messageLog-C-YIzhRj.js";
11
11
  import { t as pgidForWrapper } from "./reaper-DP49VCKx.js";
12
12
  import "./e2e-CEIdJGZ7.js";
13
13
  import "./configShared-9wVlbPyC.js";
14
- import { t as SUPPORTED_CLIS } from "./SUPPORTED_CLIS-CDrJz9Xo.js";
15
- import { A as renderLogTailLines, D as readPtysize, E as readNotes, J as isTransientLockMkdirError, M as renderRawLogLines, N as resolveOne, O as recentMessageEdges, R as snapshotStatus, S as listRecords, W as writeToIpc, b as isUserTyping, f as extractNeedsInput, j as renderRawLog, k as recentReadEdges, l as deriveLiveStatus, nt as TYPING_BADGE, o as controlCodeFromName, p as extractTaskCounts, u as extractBadges } from "./subcommands-DFr-5FOL.js";
14
+ import { t as SUPPORTED_CLIS } from "./SUPPORTED_CLIS-NpYW9OaR.js";
15
+ import { A as renderLogTailLines, D as readPtysize, E as readNotes, J as isTransientLockMkdirError, M as renderRawLogLines, N as resolveOne, O as recentMessageEdges, R as snapshotStatus, S as listRecords, W as writeToIpc, b as isUserTyping, f as extractNeedsInput, j as renderRawLog, k as recentReadEdges, l as deriveLiveStatus, nt as TYPING_BADGE, o as controlCodeFromName, p as extractTaskCounts, u as extractBadges } from "./subcommands-BdBCxZVu.js";
16
16
  import "./webrtcLink-VQhWmKOw.js";
17
17
  import "./remotes-Bem6WIyU.js";
18
18
  import { i as frameVisitorMessage, s as verifyCapability, t as MAX_CALLBACK_MSG_BYTES } from "./callbackCore-DAYcemCC.js";
19
- import { n as isCallbackRevoked, r as loadCallbackSecretReadOnly } from "./callback-D0_AeyN1.js";
19
+ import { n as isCallbackRevoked, r as loadCallbackSecretReadOnly } from "./callback-BNJMOVlW.js";
20
20
  import { a as getSpawnHook, c as hasProvisionHook, d as resolveSpawnCwd, i as getProvisionRoot, l as hasSpawnHook, r as getProvisionHook, u as isProvisionAllowed } from "./workspaceConfig-B7HaQ-MI.js";
21
21
  import { n as liveEnv, t as ensureNodeRuntime } from "./nodeRuntime-Bf88NPqj.js";
22
22
  import { r as spawnRejectionReason } from "./spawnGate-Bo_LFgt9.js";
@@ -31,6 +31,17 @@ import { createHash, createHmac, randomBytes, timingSafeEqual } from "crypto";
31
31
 
32
32
  //#region ts/termToken.ts
33
33
  const PREFIX = "ayt1";
34
+ const CAPS_READONLY = ["tail", "size"];
35
+ const CAPS_INTERACTIVE = [
36
+ "tail",
37
+ "size",
38
+ "send",
39
+ "resize"
40
+ ];
41
+ /** Derive caps for a legacy `{w}` token (pre-caps format): w=1 ⇒ interactive. */
42
+ function legacyCaps(w) {
43
+ return w === 1 ? [...CAPS_INTERACTIVE] : [...CAPS_READONLY];
44
+ }
34
45
  /** Dedicated HMAC key derived from the master token (so the token isn't signed with the raw master). */
35
46
  function keyFor(masterToken) {
36
47
  return createHash("sha256").update("ay/term/token/v1\n" + masterToken).digest();
@@ -39,11 +50,17 @@ function keyFor(masterToken) {
39
50
  function isTermToken(tok) {
40
51
  return typeof tok === "string" && tok.startsWith(PREFIX + ".");
41
52
  }
42
- /** Mint a scoped token bound to `scope.pid`, signed with the master token. */
53
+ /**
54
+ * Mint a scoped token bound to `scope.pid` (the subject), signed with the master
55
+ * token. `caps` is authoritative; if omitted it derives from `canSend` (terminal
56
+ * back-compat). Emits the caps-format payload `{s, c, x}` (verified alongside the
57
+ * legacy `{p, w, x}`).
58
+ */
43
59
  function mintTermToken(masterToken, scope) {
60
+ const caps = scope.caps ?? (scope.canSend ? [...CAPS_INTERACTIVE] : [...CAPS_READONLY]);
44
61
  const body = `${PREFIX}.${Buffer.from(JSON.stringify({
45
- p: scope.pid,
46
- w: scope.canSend ? 1 : 0,
62
+ s: scope.pid,
63
+ c: caps,
47
64
  x: Math.floor(scope.exp)
48
65
  })).toString("base64url")}`;
49
66
  return `${body}.${createHmac("sha256", keyFor(masterToken)).update(body).digest().toString("base64url")}`;
@@ -72,11 +89,14 @@ function verifyTermToken(masterToken, tok, nowSec = Math.floor(Date.now() / 1e3)
72
89
  } catch {
73
90
  return null;
74
91
  }
75
- if (typeof obj.p !== "string" || !obj.p) return null;
92
+ const sub = typeof obj.s === "string" && obj.s ? obj.s : obj.p;
93
+ if (typeof sub !== "string" || !sub) return null;
76
94
  if (typeof obj.x !== "number" || !Number.isFinite(obj.x) || obj.x <= nowSec) return null;
95
+ const caps = Array.isArray(obj.c) ? obj.c.filter((x) => typeof x === "string") : legacyCaps(obj.w);
77
96
  return {
78
- pid: obj.p,
79
- canSend: obj.w === 1,
97
+ pid: sub,
98
+ canSend: caps.includes("send"),
99
+ caps,
80
100
  exp: obj.x
81
101
  };
82
102
  }
@@ -473,7 +493,7 @@ function authorizeRequest(req, expectedToken) {
473
493
  return null;
474
494
  }
475
495
  function isTermCorsPath(p) {
476
- return /^\/api\/(tail|size)\/.+$/.test(p) || p === "/api/send";
496
+ return /^\/api\/(tail|size)\/.+$/.test(p) || p === "/api/send" || /^\/api\/resize\/.+$/.test(p) || p.startsWith("/api/widget/");
477
497
  }
478
498
  function withTermCors(req, res) {
479
499
  if (!res) return res;
@@ -511,17 +531,13 @@ async function scopedKeywordOk(keyword, scope) {
511
531
  */
512
532
  async function scopedGate(scope, method, p) {
513
533
  const forbid = (m) => new Response(m, { status: 403 });
534
+ const needs = (cap) => scope.caps.includes(cap) ? null : forbid(`scoped token lacks '${cap}'`);
514
535
  const m = /^\/api\/(?:tail|size)\/(.+)$/.exec(p);
515
- if (method === "GET" && m) return await scopedKeywordOk(decodeURIComponent(m[1]), scope) ? null : forbid("scoped token: not bound to this agent");
516
- if (method === "POST" && p === "/api/send") {
517
- if (!scope.canSend) return forbid("scoped token is read-only");
518
- return null;
519
- }
536
+ if (method === "GET" && m) return needs("tail") ?? (await scopedKeywordOk(decodeURIComponent(m[1]), scope) ? null : forbid("scoped token: not bound to this agent"));
537
+ if (method === "POST" && p === "/api/send") return needs("send");
520
538
  const rz = /^\/api\/resize\/(.+)$/.exec(p);
521
- if (method === "POST" && rz) {
522
- if (!scope.canSend) return forbid("scoped token is read-only");
523
- return await scopedKeywordOk(decodeURIComponent(rz[1]), scope) ? null : forbid("scoped token: not bound to this agent");
524
- }
539
+ if (method === "POST" && rz) return needs("resize") ?? (await scopedKeywordOk(decodeURIComponent(rz[1]), scope) ? null : forbid("scoped token: not bound to this agent"));
540
+ if (p.startsWith("/api/widget/")) return needs("read");
525
541
  return forbid("scoped token: route not permitted");
526
542
  }
527
543
  /**
@@ -529,23 +545,57 @@ async function scopedGate(scope, method, p) {
529
545
  * master token file, resolve the keyword to a concrete pid, and sign. Used by
530
546
  * `ay term mint`. Throws if there's no serve token or the agent can't be resolved.
531
547
  */
532
- async function mintScopedTermToken(keyword, opts) {
548
+ const TERMINAL_CAPS = new Set([
549
+ "tail",
550
+ "size",
551
+ "send",
552
+ "resize"
553
+ ]);
554
+ async function mintScopedTermToken(target, opts) {
533
555
  const master = await loadTokenReadOnly();
534
556
  if (!master) throw new Error("no serve token at ~/.agent-yes/.serve-token — run `ay serve` once on this host to create it");
535
- const rec = await resolveOne(keyword, defaultOpts({ all: true }));
536
- const pid = String(rec.pid);
557
+ const caps = opts.caps ?? (opts.canSend ? [
558
+ "tail",
559
+ "size",
560
+ "send",
561
+ "resize"
562
+ ] : ["tail", "size"]);
563
+ let sub = target;
564
+ if (target !== "*" && caps.some((c) => TERMINAL_CAPS.has(c))) {
565
+ const rec = await resolveOne(target, defaultOpts({ all: true }));
566
+ sub = String(rec.pid);
567
+ }
537
568
  const exp = Math.floor(Date.now() / 1e3) + Math.max(1, Math.floor(opts.ttlSec));
538
569
  return {
539
570
  token: mintTermToken(master, {
540
- pid,
541
- canSend: opts.canSend,
571
+ pid: sub,
572
+ caps,
542
573
  exp
543
574
  }),
544
- pid,
575
+ sub,
576
+ pid: sub,
545
577
  exp,
546
- canSend: opts.canSend
578
+ caps
547
579
  };
548
580
  }
581
+ const widgetViewers = /* @__PURE__ */ new Map();
582
+ const widgetPushers = /* @__PURE__ */ new Map();
583
+ const widgetWaiters = /* @__PURE__ */ new Map();
584
+ let widgetCmdSeq = 0;
585
+ const WIDGET_TTL_MS = 3e4;
586
+ function widgetNewId() {
587
+ return "v_" + randomBytes(4).toString("hex");
588
+ }
589
+ function widgetLive() {
590
+ const now = Date.now();
591
+ for (const [id, v] of widgetViewers) if (now - v.lastSeen >= WIDGET_TTL_MS) widgetViewers.delete(id);
592
+ return [...widgetViewers.values()];
593
+ }
594
+ /** Resolve a `<viewer>` selector: exact id, then id-prefix / url / title substring. */
595
+ function widgetResolve(sel) {
596
+ if (widgetViewers.has(sel) && Date.now() - widgetViewers.get(sel).lastSeen < WIDGET_TTL_MS) return sel;
597
+ return widgetLive().find((v) => v.id.startsWith(sel) || v.url.includes(sel) || v.title.includes(sel))?.id ?? null;
598
+ }
549
599
  const defaultOpts = (overrides = {}) => ({
550
600
  all: false,
551
601
  active: false,
@@ -2179,7 +2229,7 @@ Options:
2179
2229
  }
2180
2230
  });
2181
2231
  if (req.method === "GET" && p === "/api/ws") {
2182
- const ws = await import("./ws-Dun8gGiV.js");
2232
+ const ws = await import("./ws-3prv2in5.js");
2183
2233
  try {
2184
2234
  await ws.loadProvision();
2185
2235
  } catch (e) {
@@ -2199,7 +2249,7 @@ Options:
2199
2249
  if (req.method === "GET" && p === "/api/ws/status") {
2200
2250
  const dirRaw = url.searchParams.get("path");
2201
2251
  if (!dirRaw) return new Response("missing ?path=<workspace dir>", { status: 400 });
2202
- const ws = await import("./ws-Dun8gGiV.js");
2252
+ const ws = await import("./ws-3prv2in5.js");
2203
2253
  let prov;
2204
2254
  try {
2205
2255
  prov = await ws.loadProvision();
@@ -2273,6 +2323,136 @@ Options:
2273
2323
  return new Response(e.message, { status: 404 });
2274
2324
  }
2275
2325
  }
2326
+ const scopedSub = authResult.kind === "scoped" ? authResult.scope.pid : null;
2327
+ const boundOk = (vid) => !scopedSub || scopedSub === "*" || scopedSub === vid;
2328
+ if (req.method === "POST" && p === "/api/widget/register") {
2329
+ let b;
2330
+ try {
2331
+ b = await req.json();
2332
+ } catch {
2333
+ return new Response("invalid JSON body", { status: 400 });
2334
+ }
2335
+ const id = scopedSub && scopedSub !== "*" ? scopedSub : typeof b.id === "string" && b.id ? b.id : widgetNewId();
2336
+ widgetViewers.set(id, {
2337
+ id,
2338
+ url: String(b.url ?? ""),
2339
+ title: String(b.title ?? ""),
2340
+ caps: Array.isArray(b.caps) ? b.caps.filter((c) => typeof c === "string") : [],
2341
+ lastSeen: Date.now()
2342
+ });
2343
+ return Response.json({ viewerId: id });
2344
+ }
2345
+ if (req.method === "GET" && p === "/api/widget/list") {
2346
+ const now = Date.now();
2347
+ return Response.json(widgetLive().map((v) => ({
2348
+ id: v.id,
2349
+ url: v.url,
2350
+ title: v.title,
2351
+ caps: v.caps,
2352
+ age: Math.round((now - v.lastSeen) / 1e3)
2353
+ })));
2354
+ }
2355
+ const pollM = /^\/api\/widget\/poll\/(.+)$/.exec(p);
2356
+ if (req.method === "GET" && pollM) {
2357
+ const vid = decodeURIComponent(pollM[1]);
2358
+ if (!boundOk(vid)) return new Response("token not bound to this viewer", { status: 403 });
2359
+ const enc = new TextEncoder();
2360
+ let hb = null;
2361
+ const stream = new ReadableStream({
2362
+ start(controller) {
2363
+ const push = (obj) => {
2364
+ try {
2365
+ controller.enqueue(enc.encode(`data: ${JSON.stringify(obj)}\n\n`));
2366
+ } catch {}
2367
+ };
2368
+ widgetPushers.set(vid, push);
2369
+ const touch = () => {
2370
+ const v = widgetViewers.get(vid);
2371
+ if (v) v.lastSeen = Date.now();
2372
+ };
2373
+ touch();
2374
+ hb = setInterval(() => {
2375
+ try {
2376
+ controller.enqueue(enc.encode(": ping\n\n"));
2377
+ touch();
2378
+ } catch {}
2379
+ }, 15e3);
2380
+ const cleanup = () => {
2381
+ if (hb) clearInterval(hb);
2382
+ if (widgetPushers.get(vid) === push) widgetPushers.delete(vid);
2383
+ };
2384
+ req.signal.addEventListener("abort", cleanup);
2385
+ },
2386
+ cancel() {
2387
+ if (hb) clearInterval(hb);
2388
+ }
2389
+ });
2390
+ return new Response(stream, { headers: {
2391
+ "Content-Type": "text/event-stream",
2392
+ "Cache-Control": "no-cache",
2393
+ Connection: "keep-alive"
2394
+ } });
2395
+ }
2396
+ if (req.method === "POST" && p === "/api/widget/result") {
2397
+ let b;
2398
+ try {
2399
+ b = await req.json();
2400
+ } catch {
2401
+ return new Response("invalid JSON body", { status: 400 });
2402
+ }
2403
+ const resolve = b.cmdId ? widgetWaiters.get(b.cmdId) : void 0;
2404
+ if (resolve) {
2405
+ widgetWaiters.delete(b.cmdId);
2406
+ resolve({
2407
+ ok: b.ok === true,
2408
+ data: b.data,
2409
+ error: b.error
2410
+ });
2411
+ }
2412
+ return Response.json({ ok: true });
2413
+ }
2414
+ if (req.method === "POST" && p === "/api/widget/read") {
2415
+ let b;
2416
+ try {
2417
+ b = await req.json();
2418
+ } catch {
2419
+ return new Response("invalid JSON body", { status: 400 });
2420
+ }
2421
+ if (!b.viewer || !b.kind) return new Response("missing viewer/kind", { status: 400 });
2422
+ if (authResult.kind === "scoped" && b.kind === "screenshot" && !authResult.scope.caps.includes("screenshot")) return new Response("scoped token lacks 'screenshot'", { status: 403 });
2423
+ const vid = widgetResolve(b.viewer);
2424
+ if (!vid) return new Response(`no online viewer matching "${b.viewer}"`, { status: 404 });
2425
+ if (!boundOk(vid)) return new Response("token not bound to this viewer", { status: 403 });
2426
+ const push = widgetPushers.get(vid);
2427
+ if (!push) return new Response("viewer offline", { status: 409 });
2428
+ const cmdId = `c${++widgetCmdSeq}_${Date.now()}`;
2429
+ const result = await new Promise((resolve) => {
2430
+ const timer = setTimeout(() => {
2431
+ widgetWaiters.delete(cmdId);
2432
+ resolve({
2433
+ ok: false,
2434
+ error: "timeout"
2435
+ });
2436
+ }, 1e4);
2437
+ widgetWaiters.set(cmdId, (r) => {
2438
+ clearTimeout(timer);
2439
+ resolve(r);
2440
+ });
2441
+ push({
2442
+ cmdId,
2443
+ kind: b.kind,
2444
+ args: b.args ?? {}
2445
+ });
2446
+ });
2447
+ const v = widgetViewers.get(vid);
2448
+ return Response.json({
2449
+ viewer: vid,
2450
+ url: v?.url ?? "",
2451
+ ts: Math.floor(Date.now() / 1e3),
2452
+ kind: b.kind,
2453
+ ...result.ok ? { data: result.data } : { error: result.error ?? "failed" }
2454
+ });
2455
+ }
2276
2456
  const tailM = /^\/api\/tail\/(.+)$/.exec(p);
2277
2457
  if (req.method === "GET" && tailM) {
2278
2458
  const keyword = decodeURIComponent(tailM[1]);
@@ -2791,7 +2971,7 @@ Options:
2791
2971
  const perm = body.perm ?? "r";
2792
2972
  if (perm !== "r" && perm !== "rw") return new Response(`invalid perm ${perm} (want r or rw)`, { status: 400 });
2793
2973
  try {
2794
- const { createScopedShare } = await import("./agentShare-Cl_J3dfx.js");
2974
+ const { createScopedShare } = await import("./agentShare-549Zwi_B.js");
2795
2975
  const share = await createScopedShare({
2796
2976
  agent: body.agent,
2797
2977
  perm,
@@ -2806,12 +2986,12 @@ Options:
2806
2986
  }
2807
2987
  }
2808
2988
  if (req.method === "GET" && p === "/api/shares") {
2809
- const { listShares } = await import("./agentShare-Cl_J3dfx.js");
2989
+ const { listShares } = await import("./agentShare-549Zwi_B.js");
2810
2990
  return Response.json(listShares());
2811
2991
  }
2812
2992
  const revokeM = /^\/api\/share\/([^/]+)$/.exec(p);
2813
2993
  if (req.method === "DELETE" && revokeM) {
2814
- const { revokeShare } = await import("./agentShare-Cl_J3dfx.js");
2994
+ const { revokeShare } = await import("./agentShare-549Zwi_B.js");
2815
2995
  const ok = revokeShare(decodeURIComponent(revokeM[1]));
2816
2996
  return new Response(ok ? "revoked" : "no such share", { status: ok ? 200 : 404 });
2817
2997
  }
@@ -3113,7 +3293,7 @@ Options:
3113
3293
  const shutdown = (resolve) => {
3114
3294
  if (heartbeat) clearInterval(heartbeat);
3115
3295
  closeShare?.();
3116
- import("./agentShare-Cl_J3dfx.js").then((m) => m.revokeAllShares()).catch(() => {});
3296
+ import("./agentShare-549Zwi_B.js").then((m) => m.revokeAllShares()).catch(() => {});
3117
3297
  server?.stop();
3118
3298
  Promise.resolve(releaseHostLock?.()).catch(() => {}).then(resolve);
3119
3299
  };
@@ -3125,5 +3305,5 @@ Options:
3125
3305
  }
3126
3306
 
3127
3307
  //#endregion
3128
- export { cmdServe, mintScopedTermToken, resolveLocalServeUrl };
3129
- //# sourceMappingURL=serve-QejbNTr-.js.map
3308
+ export { cmdServe, loadTokenReadOnly, mintScopedTermToken, resolveLocalServeUrl };
3309
+ //# sourceMappingURL=serve-BLxmap1e.js.map
@@ -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-QejbNTr-.js");
35
+ const { cmdServe } = await import("./serve-BLxmap1e.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-Dzi5Cc3g.js.map
45
+ //# sourceMappingURL=setup-DlFVw_1n.js.map
@@ -3,7 +3,7 @@ import "./globalPidIndex-D9DOSd-c.js";
3
3
  import "./messageLog-C-YIzhRj.js";
4
4
  import "./e2e-CEIdJGZ7.js";
5
5
  import "./configShared-9wVlbPyC.js";
6
- import { A as renderLogTailLines, B as stopTipForCli, C as matchKeyword, D as readPtysize, E as readNotes, F as resolveResumeArgs, H as waitForLogQuiet, I as restartHintLines, L as runSubcommand, M as renderRawLogLines, N as resolveOne, O as recentMessageEdges, P as resolveReadWindow, R as snapshotStatus, S as listRecords, T as readAgentPtysize, U as writeKeysPaced, V as submitAndConfirm, W as writeToIpc, _ as isPidAlive, a as cmdHelp, b as isUserTyping, c as deriveLiveState, d as extractMenu, f as extractNeedsInput, g as isExitRequest, h as isAgentStuck, i as backoffWhileTyping, j as renderRawLog, k as recentReadEdges, l as deriveLiveStatus, m as finalizedLines, n as READ_PAGE_DEFAULT, o as controlCodeFromName, p as extractTaskCounts, r as TYPING_WINDOW_MS, s as cursorAbs, t as GRACEFUL_EXIT_COMMANDS, u as extractBadges, v as isSlashCommand, w as menuSelectKeys, x as lastStdinAt, y as isSubcommand, z as stdinActivityPath } from "./subcommands-DFr-5FOL.js";
6
+ import { A as renderLogTailLines, B as stopTipForCli, C as matchKeyword, D as readPtysize, E as readNotes, F as resolveResumeArgs, H as waitForLogQuiet, I as restartHintLines, L as runSubcommand, M as renderRawLogLines, N as resolveOne, O as recentMessageEdges, P as resolveReadWindow, R as snapshotStatus, S as listRecords, T as readAgentPtysize, U as writeKeysPaced, V as submitAndConfirm, W as writeToIpc, _ as isPidAlive, a as cmdHelp, b as isUserTyping, c as deriveLiveState, d as extractMenu, f as extractNeedsInput, g as isExitRequest, h as isAgentStuck, i as backoffWhileTyping, j as renderRawLog, k as recentReadEdges, l as deriveLiveStatus, m as finalizedLines, n as READ_PAGE_DEFAULT, o as controlCodeFromName, p as extractTaskCounts, r as TYPING_WINDOW_MS, s as cursorAbs, t as GRACEFUL_EXIT_COMMANDS, u as extractBadges, v as isSlashCommand, w as menuSelectKeys, x as lastStdinAt, y as isSubcommand, z as stdinActivityPath } from "./subcommands-BdBCxZVu.js";
7
7
  import "./webrtcLink-VQhWmKOw.js";
8
8
  import "./remotes-Bem6WIyU.js";
9
9