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
@@ -1177,6 +1177,8 @@ const SUBCOMMANDS = new Set([
1177
1177
  "ch",
1178
1178
  "channels",
1179
1179
  "term",
1180
+ "widget",
1181
+ "mint",
1180
1182
  "serve",
1181
1183
  "schedule",
1182
1184
  "remote",
@@ -1251,23 +1253,31 @@ async function runSubcommand(argv) {
1251
1253
  return cmdCh(rest);
1252
1254
  }
1253
1255
  case "term": {
1254
- const { cmdTerm } = await import("./terminal-vNeFNLT8.js");
1256
+ const { cmdTerm } = await import("./terminal-w7drEaJc.js");
1255
1257
  return cmdTerm(rest);
1256
1258
  }
1259
+ case "widget": {
1260
+ const { cmdWidget } = await import("./widget-Coav85Lx.js");
1261
+ return cmdWidget(rest);
1262
+ }
1263
+ case "mint": {
1264
+ const { cmdMint } = await import("./widget-Coav85Lx.js");
1265
+ return cmdMint(rest);
1266
+ }
1257
1267
  case "serve": {
1258
- const { cmdServe } = await import("./serve-QejbNTr-.js");
1268
+ const { cmdServe } = await import("./serve-BLxmap1e.js");
1259
1269
  return cmdServe(rest);
1260
1270
  }
1261
1271
  case "setup": {
1262
- const { cmdSetup } = await import("./setup-Dzi5Cc3g.js");
1272
+ const { cmdSetup } = await import("./setup-DlFVw_1n.js");
1263
1273
  return cmdSetup(rest);
1264
1274
  }
1265
1275
  case "ws": {
1266
- const { cmdWs } = await import("./ws-Dun8gGiV.js");
1276
+ const { cmdWs } = await import("./ws-3prv2in5.js");
1267
1277
  return cmdWs(rest);
1268
1278
  }
1269
1279
  case "schedule": {
1270
- const { cmdSchedule } = await import("./schedule-B8Erb3y6.js");
1280
+ const { cmdSchedule } = await import("./schedule-Bw3SL5Hv.js");
1271
1281
  return cmdSchedule(rest);
1272
1282
  }
1273
1283
  case "remote": {
@@ -1279,7 +1289,7 @@ async function runSubcommand(argv) {
1279
1289
  return cmdExpose(rest);
1280
1290
  }
1281
1291
  case "callback": {
1282
- const { cmdCallback } = await import("./callback-CFbkvqTh.js");
1292
+ const { cmdCallback } = await import("./callback-B-ojDckO.js");
1283
1293
  return cmdCallback(rest);
1284
1294
  }
1285
1295
  case "reap":
@@ -1317,7 +1327,7 @@ async function cmdHelp(managerCommands = true) {
1317
1327
  const wsLines = managerCommands ? " ay ws ls [--status] list <owner>/<repo>/tree/<branch> workspaces\n ay ws new <owner>/<repo>[@branch] clone/refresh a workspace (ay ws help for more)\n" : ``;
1318
1328
  const self = process.env.AGENT_YES_PID ? await resolveSender() : null;
1319
1329
  const agentSection = self ? await buildAgentContextSection(self) : "";
1320
- process.stdout.write(agentSection + "ay - agent-yes CLI\n\nManagement:\n ay ls [keyword] list running agents\n ay tail [-f] [-n N] <keyword> last N lines (96), -f to follow\n ay read <keyword> [page opts] paginate: --last/--head N, --range A:B,\n --before-line L [--limit N]\n ay cat <keyword> full log\n ay head <keyword> first N lines\n ay send <keyword> <msg> send a message (keyword '.' = agent in this cwd)\n ay msgs [keyword] [--in|--out] inter-agent message log (sent + received)\n ay ch mk|join|send|read|tail <topic> local-first E2E channels: AI ↔ humans on a topic (ay ch help)\n ay term embed <pid> <script> to embed a live read-only agent terminal in a page (ay term help)\n ay key <keyword> <key...> send raw keystrokes (down/up/enter/esc/…) — drives menus\n ay select <keyword> <N> pick option N of a needs_input selection menu\n ay attach <keyword> interactive attach (detach: Ctrl-\\)\n ay stop <keyword> graceful shutdown (/exit for claude/codex)\n ay exit <keyword> [reason] graceful shutdown, recording who/why (= 'ay send <kw> exit')\n ay restart <keyword> [--fresh] stop (if live) + relaunch resuming the session; --fresh replays the prompt\n ay status <keyword> agent status snapshot\n ay result <keyword> [--wait] pull an agent's structured result envelope\n ay result set '<json>' (inside an agent) deposit your result envelope\n ay reap kill process groups leaked by dead agents\n" + wsLines + "\nRemote:\n" + setupLine + " ay schedule <when> <cli> -- <msg> run an agent on a schedule (HH:MM or cron)\n ay serve [--port N] start HTTP API server (prints token)\n ay serve status show serve daemon/server status\n ay remote add <alias> http://<token>@<host>:<port>\n ay remote ls / rm <alias> manage saved remotes\n ay expose <port> share localhost:<port> at https://<id>.agent-yes.com (private link)\n ay callback --expires 7d mint an embeddable message-me widget for one agent\n ay ls <token>@<host>:<port> connect inline (no alias needed)\n ay send <token>@<host>:<port>:<kw> <msg>\n\nRun an agent:\n ay [claude|codex|gemini|...] [options] -- [prompt]\n ay claude -- \"fix the bug in auth.ts\"\n ay claude --help full agent-runner options\n\nLabs (examples at https://github.com/snomiao/agent-yes/tree/main/lab):\n local-role-play/ designer + builder on one machine\n http-remote/ ay serve remote access demo\n p2p-pairing/ libp2p P2P (needs: cargo build --features swarm)\n");
1330
+ process.stdout.write(agentSection + "ay - agent-yes CLI\n\nManagement:\n ay ls [keyword] list running agents\n ay tail [-f] [-n N] <keyword> last N lines (96), -f to follow\n ay read <keyword> [page opts] paginate: --last/--head N, --range A:B,\n --before-line L [--limit N]\n ay cat <keyword> full log\n ay head <keyword> first N lines\n ay send <keyword> <msg> send a message (keyword '.' = agent in this cwd)\n ay msgs [keyword] [--in|--out] inter-agent message log (sent + received)\n ay ch mk|join|send|read|tail <topic> local-first E2E channels: AI ↔ humans on a topic (ay ch help)\n ay term embed <pid> <script> to embed a live read-only agent terminal in a page (ay term help)\n ay widget ls | read selection|dom read an opted-in page widget's context (selection/DOM) (ay widget help)\n ay mint <target> --caps ... mint a scoped, short-TTL capability token (embeddable in a page)\n ay key <keyword> <key...> send raw keystrokes (down/up/enter/esc/…) — drives menus\n ay select <keyword> <N> pick option N of a needs_input selection menu\n ay attach <keyword> interactive attach (detach: Ctrl-\\)\n ay stop <keyword> graceful shutdown (/exit for claude/codex)\n ay exit <keyword> [reason] graceful shutdown, recording who/why (= 'ay send <kw> exit')\n ay restart <keyword> [--fresh] stop (if live) + relaunch resuming the session; --fresh replays the prompt\n ay status <keyword> agent status snapshot\n ay result <keyword> [--wait] pull an agent's structured result envelope\n ay result set '<json>' (inside an agent) deposit your result envelope\n ay reap kill process groups leaked by dead agents\n" + wsLines + "\nRemote:\n" + setupLine + " ay schedule <when> <cli> -- <msg> run an agent on a schedule (HH:MM or cron)\n ay serve [--port N] start HTTP API server (prints token)\n ay serve status show serve daemon/server status\n ay remote add <alias> http://<token>@<host>:<port>\n ay remote ls / rm <alias> manage saved remotes\n ay expose <port> share localhost:<port> at https://<id>.agent-yes.com (private link)\n ay callback --expires 7d mint an embeddable message-me widget for one agent\n ay ls <token>@<host>:<port> connect inline (no alias needed)\n ay send <token>@<host>:<port>:<kw> <msg>\n\nRun an agent:\n ay [claude|codex|gemini|...] [options] -- [prompt]\n ay claude -- \"fix the bug in auth.ts\"\n ay claude --help full agent-runner options\n\nLabs (examples at https://github.com/snomiao/agent-yes/tree/main/lab):\n local-role-play/ designer + builder on one machine\n http-remote/ ay serve remote access demo\n p2p-pairing/ libp2p P2P (needs: cargo build --features swarm)\n");
1321
1331
  return 0;
1322
1332
  }
1323
1333
  function matchKeyword(record, keyword) {
@@ -4317,7 +4327,7 @@ async function cmdNotify(rest) {
4317
4327
  }
4318
4328
  const ensure = async () => {
4319
4329
  if (!argv["ensure-daemon"]) return;
4320
- const { ensureDaemon } = await import("./notifyDaemon-D_8TRVHt.js");
4330
+ const { ensureDaemon } = await import("./notifyDaemon-CjBVeWRg.js");
4321
4331
  await ensureDaemon().catch(() => null);
4322
4332
  };
4323
4333
  await heartbeatWatcher(parent, selfStartedAt);
@@ -4391,7 +4401,7 @@ async function cmdNotifyCursor(args) {
4391
4401
  }
4392
4402
  async function cmdNotifyd(rest) {
4393
4403
  const sub = rest[0] ?? "status";
4394
- const daemon = await import("./notifyDaemon-D_8TRVHt.js");
4404
+ const daemon = await import("./notifyDaemon-CjBVeWRg.js");
4395
4405
  switch (sub) {
4396
4406
  case "run": return daemon.runDaemon();
4397
4407
  case "once": return daemon.runDaemon({ once: true });
@@ -4418,4 +4428,4 @@ async function cmdNotifyd(rest) {
4418
4428
 
4419
4429
  //#endregion
4420
4430
  export { daemonLockDir as $, renderLogTailLines as A, stopTipForCli as B, matchKeyword as C, readPtysize as D, readNotes as E, resolveResumeArgs as F, appendEvent as G, waitForLogQuiet as H, restartHintLines as I, isTransientLockMkdirError as J, gcInboxes as K, runSubcommand as L, renderRawLogLines as M, resolveOne as N, recentMessageEdges as O, resolveReadWindow as P, shouldStealLock as Q, snapshotStatus as R, listRecords as S, readAgentPtysize as T, writeKeysPaced as U, submitAndConfirm as V, writeToIpc as W, liveWatchers as X, listInboxParents as Y, readInbox as Z, isPidAlive as _, cmdHelp as a, isUserTyping as b, deriveLiveState as c, extractMenu as d, daemonLockOwnerPath as et, extractNeedsInput as f, isExitRequest as g, isAgentStuck as h, backoffWhileTyping as i, renderRawLog as j, recentReadEdges as k, deriveLiveStatus as l, finalizedLines as m, READ_PAGE_DEFAULT as n, TYPING_BADGE as nt, controlCodeFromName as o, extractTaskCounts as p, hostId as q, TYPING_WINDOW_MS as r, cursorAbs as s, GRACEFUL_EXIT_COMMANDS as t, notifyDir as tt, extractBadges as u, isSlashCommand as v, menuSelectKeys as w, lastStdinAt as x, isSubcommand as y, stdinActivityPath as z };
4421
- //# sourceMappingURL=subcommands-DFr-5FOL.js.map
4431
+ //# sourceMappingURL=subcommands-BdBCxZVu.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-QejbNTr-.js");
101
+ const { mintScopedTermToken } = await import("./serve-BLxmap1e.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-vNeFNLT8.js.map
138
+ //# sourceMappingURL=terminal-w7drEaJc.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-XfEBINhH.js";
3
+ import { r as getInstalledPackage } from "./versionChecker-DNLNn_SL.js";
4
4
  import { t as agentYesHome } from "./agentYesHome-CtmsY6I-.js";
5
5
  import { d as openStore, p as LIFECYCLES, x as removeControlCharacters } from "./todoAutomation-Buo457VO.js";
6
6
  import { i as shouldUseLock, r as releaseLock, t as acquireLock } from "./runningLock-DBoONoM-.js";
@@ -2027,4 +2027,4 @@ function sleep(ms) {
2027
2027
 
2028
2028
  //#endregion
2029
2029
  export { hasTodoStore as a, AgentContext as c, answerAsk as i, CLAUDE_SESSION_PIN_ENV as l, agentYes as n, listAsks as o, config as r, listAsksForProject as s, CLIS_CONFIG as t };
2030
- //# sourceMappingURL=ts-Dd1FK7sR.js.map
2030
+ //# sourceMappingURL=ts-EvHuyNA9.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.237.0";
10
+ var version = "1.238.0";
11
11
 
12
12
  //#endregion
13
13
  //#region ts/versionChecker.ts
@@ -215,4 +215,4 @@ async function displayVersion() {
215
215
 
216
216
  //#endregion
217
217
  export { versionString as i, displayVersion as n, getInstalledPackage as r, checkAndAutoUpdate as t };
218
- //# sourceMappingURL=versionChecker-XfEBINhH.js.map
218
+ //# sourceMappingURL=versionChecker-DNLNn_SL.js.map
@@ -0,0 +1,172 @@
1
+ //#region ts/widget.ts
2
+ function parseFlags(args, known) {
3
+ const flags = {};
4
+ const positional = [];
5
+ for (let i = 0; i < args.length; i++) {
6
+ const a = args[i];
7
+ if (!a.startsWith("-") || a === "-") {
8
+ positional.push(a);
9
+ continue;
10
+ }
11
+ const eq = a.indexOf("=");
12
+ const name = eq === -1 ? a.replace(/^--?/, "") : a.slice(a.startsWith("--") ? 2 : 1, eq);
13
+ const kind = known[name];
14
+ if (!kind) throw new Error(`unknown flag ${a}`);
15
+ if (kind === "bool") {
16
+ if (eq !== -1) throw new Error(`--${name} takes no value`);
17
+ flags[name] = true;
18
+ } else {
19
+ const v = eq !== -1 ? a.slice(eq + 1) : args[++i];
20
+ if (v === void 0) throw new Error(`${a} requires a value`);
21
+ flags[name] = v;
22
+ }
23
+ }
24
+ return {
25
+ flags,
26
+ positional
27
+ };
28
+ }
29
+ /** Resolve the local daemon base URL + token (flags override discovery). */
30
+ async function daemonTarget(flags) {
31
+ const { resolveLocalServeUrl, loadTokenReadOnly } = await import("./serve-BLxmap1e.js");
32
+ const base = typeof flags.base === "string" ? flags.base : await resolveLocalServeUrl();
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
+ const token = typeof flags.token === "string" ? flags.token : await loadTokenReadOnly() ?? "";
35
+ if (!token) throw new Error("no serve token — pass --token or run `ay serve` once");
36
+ return {
37
+ base: base.replace(/\/+$/, ""),
38
+ token
39
+ };
40
+ }
41
+ function withTok(url, token) {
42
+ return `${url}${url.includes("?") ? "&" : "?"}token=${encodeURIComponent(token)}`;
43
+ }
44
+ async function cmdWidgetLs(args) {
45
+ const { flags } = parseFlags(args, {
46
+ json: "bool",
47
+ base: "value",
48
+ token: "value"
49
+ });
50
+ const { base, token } = await daemonTarget(flags);
51
+ const res = await fetch(withTok(`${base}/api/widget/list`, token), { headers: { accept: "application/json" } });
52
+ if (!res.ok) throw new Error(`widget list failed: ${res.status} ${await res.text()}`);
53
+ const list = await res.json();
54
+ if (flags.json) {
55
+ process.stdout.write(JSON.stringify(list, null, 2) + "\n");
56
+ return 0;
57
+ }
58
+ if (!list.length) {
59
+ process.stderr.write("no online widgets (a page must embed AyWidget and start() it)\n");
60
+ return 0;
61
+ }
62
+ for (const v of list) process.stdout.write(`${v.id.padEnd(12)} ${(v.title || "(untitled)").slice(0, 28).padEnd(28)} caps:${v.caps.join(",") || "-"} ${v.age}s ${v.url}\n`);
63
+ return 0;
64
+ }
65
+ async function cmdWidgetRead(args) {
66
+ const { flags, positional } = parseFlags(args, {
67
+ selector: "value",
68
+ all: "bool",
69
+ text: "bool",
70
+ html: "bool",
71
+ json: "bool",
72
+ base: "value",
73
+ token: "value"
74
+ });
75
+ const kind = positional[0];
76
+ const viewer = positional[1];
77
+ if (!kind || !viewer) throw new Error("usage: ay widget read <selection|dom> <viewer> [--selector <css>] [--all] [--text|--html]");
78
+ const cmdArgs = {};
79
+ if (kind === "dom") {
80
+ if (typeof flags.selector !== "string") throw new Error("dom read needs --selector <css>");
81
+ cmdArgs.selector = flags.selector;
82
+ cmdArgs.all = flags.all === true;
83
+ }
84
+ const { base, token } = await daemonTarget(flags);
85
+ const res = await fetch(withTok(`${base}/api/widget/read`, token), {
86
+ method: "POST",
87
+ headers: { "content-type": "application/json" },
88
+ body: JSON.stringify({
89
+ viewer,
90
+ kind,
91
+ args: cmdArgs
92
+ })
93
+ });
94
+ const body = await res.json().catch(() => ({}));
95
+ if (!res.ok) throw new Error(`widget read failed: ${res.status} ${JSON.stringify(body)}`);
96
+ if (body.error) {
97
+ process.stderr.write(`read ${kind} @ ${body.viewer ?? viewer}: ${body.error}\n`);
98
+ return 1;
99
+ }
100
+ if (kind === "selection" && !flags.json) {
101
+ process.stdout.write((flags.html ? body.data?.html : body.data?.text) ?? "");
102
+ process.stdout.write("\n");
103
+ return 0;
104
+ }
105
+ process.stdout.write(JSON.stringify(flags.json ? body : body.data, null, 2) + "\n");
106
+ return 0;
107
+ }
108
+ function widgetHelp() {
109
+ process.stdout.write("ay widget — read an opted-in page widget's context (selection / DOM)\n\nUsage:\n ay widget ls [--json]\n ay widget read selection <viewer> [--text|--html|--json]\n ay widget read dom <viewer> --selector <css> [--all] [--json]\n\n <viewer> = an id, or a url/title substring (see `ay widget ls`).\n Common flags: --base <daemon-url> --token <tok> (default: the local daemon).\n The page must embed `new AyWidget({sensors:[...]}).start()` and the token must\n carry the 'read' cap (ay mint <viewer> --caps read) — or use the master token.\n");
110
+ return 0;
111
+ }
112
+ async function cmdWidget(args) {
113
+ const sub = args[0];
114
+ const rest = args.slice(1);
115
+ switch (sub) {
116
+ case "ls":
117
+ case "list": return cmdWidgetLs(rest);
118
+ case "read": return cmdWidgetRead(rest);
119
+ case void 0:
120
+ case "help":
121
+ case "--help":
122
+ case "-h": return widgetHelp();
123
+ default:
124
+ process.stderr.write(`ay widget: unknown subcommand "${sub}"\n\n`);
125
+ widgetHelp();
126
+ return 1;
127
+ }
128
+ }
129
+ function parseTtlSec(s) {
130
+ const m = /^(\d+)(s|m|h)?$/.exec(s.trim());
131
+ if (!m) throw new Error(`bad --ttl "${s}" (use e.g. 900, 30s, 15m, 2h)`);
132
+ const mult = m[2] === "h" ? 3600 : m[2] === "m" ? 60 : 1;
133
+ return Number(m[1]) * mult;
134
+ }
135
+ const KNOWN_CAPS = new Set([
136
+ "tail",
137
+ "size",
138
+ "send",
139
+ "resize",
140
+ "read",
141
+ "screenshot"
142
+ ]);
143
+ async function cmdMint(args) {
144
+ const { flags, positional } = parseFlags(args, {
145
+ caps: "value",
146
+ ttl: "value",
147
+ json: "bool"
148
+ });
149
+ const target = positional[0];
150
+ if (!target || positional.length > 1) throw new Error("usage: ay mint <pid|viewer|url|*> --caps tail,send,read,screenshot [--ttl 15m] [--json]");
151
+ if (typeof flags.caps !== "string") throw new Error("--caps is required, e.g. --caps read or --caps tail,send");
152
+ const caps = flags.caps.split(",").map((c) => c.trim()).filter(Boolean);
153
+ const bad = caps.filter((c) => !KNOWN_CAPS.has(c));
154
+ if (bad.length) throw new Error(`unknown cap(s): ${bad.join(", ")} (valid: ${[...KNOWN_CAPS].join(", ")})`);
155
+ const ttlSec = parseTtlSec(typeof flags.ttl === "string" ? flags.ttl : "15m");
156
+ const { mintScopedTermToken } = await import("./serve-BLxmap1e.js");
157
+ const r = await mintScopedTermToken(target, {
158
+ ttlSec,
159
+ caps
160
+ });
161
+ if (flags.json === true) {
162
+ process.stdout.write(JSON.stringify(r) + "\n");
163
+ return 0;
164
+ }
165
+ process.stdout.write(r.token + "\n");
166
+ process.stderr.write(`\n Scoped token for ${r.sub === "*" ? "ANY subject" : r.sub}, caps [${r.caps.join(", ")}], expires ${(/* @__PURE__ */ new Date(r.exp * 1e3)).toISOString()}.\n It grants ONLY those caps for that subject — safe to embed in a page (not the master token).\n`);
167
+ return 0;
168
+ }
169
+
170
+ //#endregion
171
+ export { cmdMint, cmdWidget };
172
+ //# sourceMappingURL=widget-Coav85Lx.js.map
package/dist/widget.js ADDED
@@ -0,0 +1,162 @@
1
+ //#region ts/widget/browser.ts
2
+ var AyWidget = class {
3
+ origin;
4
+ token;
5
+ wantId;
6
+ viewerId = "";
7
+ sensors;
8
+ snapshots;
9
+ es;
10
+ started = false;
11
+ handlers = /* @__PURE__ */ new Map();
12
+ indicator;
13
+ constructor(info = {}) {
14
+ this.origin = (info.origin ?? "").replace(/\/+$/, "");
15
+ this.token = info.token ?? discoverToken();
16
+ this.wantId = info.id;
17
+ this.sensors = new Set(info.sensors ?? []);
18
+ this.snapshots = info.snapshots ?? {};
19
+ this.handlers.set("ping", async () => ({
20
+ caps: [...this.sensors],
21
+ id: this.viewerId
22
+ }));
23
+ this.handlers.set("selection", readSelection);
24
+ this.handlers.set("dom", readDom);
25
+ }
26
+ url(path) {
27
+ const p = this.token ? `${path}${path.includes("?") ? "&" : "?"}token=${encodeURIComponent(this.token)}` : path;
28
+ return this.origin + p;
29
+ }
30
+ /** Register with the daemon and open the command channel. Idempotent. */
31
+ async start() {
32
+ if (this.started) return this.viewerId;
33
+ this.started = true;
34
+ const g = globalThis;
35
+ const doc = g.document;
36
+ const res = await g.fetch(this.url("/api/widget/register"), {
37
+ method: "POST",
38
+ headers: { "content-type": "application/json" },
39
+ body: JSON.stringify({
40
+ id: this.wantId,
41
+ url: g.location?.href ?? "",
42
+ title: doc?.title ?? "",
43
+ caps: [...this.sensors]
44
+ })
45
+ });
46
+ if (!res.ok) throw new Error(`widget register failed: ${res.status}`);
47
+ this.viewerId = (await res.json()).viewerId;
48
+ this.openPoll();
49
+ return this.viewerId;
50
+ }
51
+ openPoll() {
52
+ const es = new globalThis.EventSource(this.url(`/api/widget/poll/${encodeURIComponent(this.viewerId)}`));
53
+ es.onmessage = (e) => {
54
+ let cmd;
55
+ try {
56
+ cmd = JSON.parse(e.data);
57
+ } catch {
58
+ return;
59
+ }
60
+ if (cmd.cmdId && cmd.kind) this.dispatch(cmd.cmdId, cmd.kind, cmd.args ?? {});
61
+ };
62
+ this.es = es;
63
+ }
64
+ async dispatch(cmdId, kind, args) {
65
+ this.flash();
66
+ const handler = this.handlers.get(kind);
67
+ if (!handler || kind !== "ping" && !this.sensors.has(kind)) return this.postResult(cmdId, {
68
+ ok: false,
69
+ error: `kind '${kind}' not enabled on this widget`
70
+ });
71
+ try {
72
+ const data = await handler(args);
73
+ await this.postResult(cmdId, {
74
+ ok: true,
75
+ data
76
+ });
77
+ } catch (e) {
78
+ await this.postResult(cmdId, {
79
+ ok: false,
80
+ error: String(e?.message ?? e)
81
+ });
82
+ }
83
+ }
84
+ async postResult(cmdId, r) {
85
+ const g = globalThis;
86
+ try {
87
+ await g.fetch(this.url("/api/widget/result"), {
88
+ method: "POST",
89
+ headers: { "content-type": "application/json" },
90
+ body: JSON.stringify({
91
+ cmdId,
92
+ ...r
93
+ })
94
+ });
95
+ } catch {}
96
+ }
97
+ /** A brief visible pulse so the viewer always sees a collection happen. */
98
+ flash() {
99
+ const doc = globalThis.document;
100
+ if (!doc) return;
101
+ if (!this.indicator) {
102
+ const el = doc.createElement("div");
103
+ el.setAttribute("data-aywidget-indicator", this.viewerId || "1");
104
+ el.style.cssText = "position:fixed;right:14px;bottom:14px;width:12px;height:12px;border-radius:50%;background:#1f6feb;box-shadow:0 0 0 0 rgba(31,111,235,.6);z-index:2147483000;opacity:0;transition:opacity .15s;pointer-events:none";
105
+ (doc.body ?? doc.documentElement).appendChild(el);
106
+ this.indicator = el;
107
+ }
108
+ const el = this.indicator;
109
+ el.style.opacity = "1";
110
+ el.animate?.([{ boxShadow: "0 0 0 0 rgba(31,111,235,.6)" }, { boxShadow: "0 0 0 10px rgba(31,111,235,0)" }], { duration: 600 });
111
+ clearTimeout(el._t);
112
+ el._t = setTimeout(() => el.style.opacity = "0", 500);
113
+ }
114
+ stop() {
115
+ this.es?.close?.();
116
+ this.es = void 0;
117
+ this.indicator?.remove?.();
118
+ this.indicator = void 0;
119
+ this.started = false;
120
+ }
121
+ };
122
+ async function readSelection() {
123
+ const g = globalThis;
124
+ const sel = g.getSelection?.();
125
+ const text = sel ? String(sel) : "";
126
+ let html = "";
127
+ if (sel && sel.rangeCount) {
128
+ const div = g.document.createElement("div");
129
+ for (let i = 0; i < sel.rangeCount; i++) div.appendChild(sel.getRangeAt(i).cloneContents());
130
+ html = div.innerHTML;
131
+ }
132
+ return {
133
+ text,
134
+ html
135
+ };
136
+ }
137
+ async function readDom(args) {
138
+ const g = globalThis;
139
+ const selector = args?.selector;
140
+ if (!selector) throw new Error("dom read needs a --selector");
141
+ const nodes = args?.all ? [...g.document.querySelectorAll(selector)] : [g.document.querySelector(selector)].filter(Boolean);
142
+ return {
143
+ matches: nodes.length,
144
+ outerHTML: nodes.map((n) => String(n.outerHTML ?? ""))
145
+ };
146
+ }
147
+ /** window.AY_TERM_TOKEN → page `#k=` hash → localStorage["ay.localToken"]. */
148
+ function discoverToken() {
149
+ const g = globalThis;
150
+ if (g.AY_TERM_TOKEN) return String(g.AY_TERM_TOKEN);
151
+ try {
152
+ const k = (g.location?.hash ?? "").slice(1).split("&").find((s) => s.startsWith("k="));
153
+ if (k) return decodeURIComponent(k.slice(2));
154
+ const stored = g.localStorage?.getItem("ay.localToken");
155
+ if (stored) return stored;
156
+ } catch {}
157
+ return "";
158
+ }
159
+
160
+ //#endregion
161
+ export { AyWidget, AyWidget as default };
162
+ //# sourceMappingURL=widget.js.map
package/dist/widgets.js CHANGED
@@ -3,5 +3,6 @@ import "./channels-BiGUYTuz.js";
3
3
  import "./peer-B5JKF4BP.js";
4
4
  import { t as AyChannel } from "./browser-B3dOptjL.js";
5
5
  import { t as AyTerminal } from "./browser-BRMyG4JA.js";
6
+ import { AyWidget } from "./widget.js";
6
7
 
7
- export { AyChannel, AyTerminal };
8
+ export { AyChannel, AyTerminal, AyWidget };
@@ -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 { S as listRecords } from "./subcommands-DFr-5FOL.js";
6
+ import { S as listRecords } from "./subcommands-BdBCxZVu.js";
7
7
  import "./webrtcLink-VQhWmKOw.js";
8
8
  import "./remotes-Bem6WIyU.js";
9
9
  import { i as getProvisionRoot } from "./workspaceConfig-B7HaQ-MI.js";
@@ -418,4 +418,4 @@ async function cmdWs(args) {
418
418
 
419
419
  //#endregion
420
420
  export { WS_JSON_SCHEMA, cmdWs, collectWorkspaces, isPathInside, loadProvision, workspaceStatus };
421
- //# sourceMappingURL=ws-Dun8gGiV.js.map
421
+ //# sourceMappingURL=ws-3prv2in5.js.map
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "agent-yes",
3
- "version": "1.237.0",
3
+ "version": "1.238.0",
4
4
  "description": "A wrapper tool that automates interactions with various AI CLI tools by automatically handling common prompts and responses.",
5
5
  "keywords": [
6
6
  "ai",
@@ -94,6 +94,10 @@
94
94
  "types": "./ts/terminal/browser.ts",
95
95
  "import": "./dist/terminal.js"
96
96
  },
97
+ "./widget": {
98
+ "types": "./ts/widget/browser.ts",
99
+ "import": "./dist/widget.js"
100
+ },
97
101
  "./widgets": {
98
102
  "types": "./ts/widgets.ts",
99
103
  "import": "./dist/widgets.js"