agent-yes 1.95.0 → 1.97.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.
@@ -0,0 +1,8 @@
1
+ import "./ts-BAc4Jcrw.js";
2
+ import "./logger-B9h0djqx.js";
3
+ import "./versionChecker-MNvA73o9.js";
4
+ import "./pidStore-DBjlqzo8.js";
5
+ import "./globalPidIndex-yVd3mbsV.js";
6
+ import { t as SUPPORTED_CLIS } from "./SUPPORTED_CLIS-eD-UlqO_.js";
7
+
8
+ export { SUPPORTED_CLIS };
@@ -0,0 +1,8 @@
1
+ import { t as CLIS_CONFIG } from "./ts-BAc4Jcrw.js";
2
+
3
+ //#region ts/SUPPORTED_CLIS.ts
4
+ const SUPPORTED_CLIS = Object.keys(CLIS_CONFIG);
5
+
6
+ //#endregion
7
+ export { SUPPORTED_CLIS as t };
8
+ //# sourceMappingURL=SUPPORTED_CLIS-eD-UlqO_.js.map
package/dist/cli.js CHANGED
@@ -1,6 +1,6 @@
1
1
  #!/usr/bin/env bun
2
2
  import { n as logger } from "./logger-B9h0djqx.js";
3
- import { i as versionString, n as displayVersion, r as getInstalledPackage, t as checkAndAutoUpdate } from "./versionChecker-DfIPG9ui.js";
3
+ import { i as versionString, n as displayVersion, r as getInstalledPackage, t as checkAndAutoUpdate } from "./versionChecker-MNvA73o9.js";
4
4
  import { argv } from "process";
5
5
  import { execFileSync, spawn } from "child_process";
6
6
  import ms from "ms";
@@ -482,7 +482,7 @@ function buildRustArgs(argv, cliFromScript, supportedClis) {
482
482
  {
483
483
  const rawArg = process.argv[2];
484
484
  const isHelpFlag = rawArg === "-h" || rawArg === "--help";
485
- const { isSubcommand, runSubcommand, cmdHelp } = await import("./subcommands-DjrOWqD9.js");
485
+ const { isSubcommand, runSubcommand, cmdHelp } = await import("./subcommands-B4gXEu5I.js");
486
486
  if (isHelpFlag && process.argv.length === 3) {
487
487
  cmdHelp();
488
488
  process.exit(0);
@@ -496,12 +496,12 @@ await checkAndAutoUpdate();
496
496
  logger.info(versionString());
497
497
  const config = parseCliArgs(process.argv);
498
498
  if (config.tray) {
499
- const { startTray } = await import("./tray-DHuD0nEk.js");
499
+ const { startTray } = await import("./tray-CWQe9DMY.js");
500
500
  await startTray();
501
501
  await new Promise(() => {});
502
502
  }
503
503
  {
504
- const { ensureTray } = await import("./tray-DHuD0nEk.js");
504
+ const { ensureTray } = await import("./tray-CWQe9DMY.js");
505
505
  ensureTray();
506
506
  }
507
507
  if (config.useRust) {
@@ -515,7 +515,7 @@ if (config.useRust) {
515
515
  }
516
516
  }
517
517
  if (rustBinary) {
518
- const { SUPPORTED_CLIS } = await import("./SUPPORTED_CLIS-CrlcmUcE.js");
518
+ const { SUPPORTED_CLIS } = await import("./SUPPORTED_CLIS-CNO_pj9f.js");
519
519
  const rustArgs = buildRustArgs(process.argv, config.cli, SUPPORTED_CLIS);
520
520
  if (config.verbose) {
521
521
  console.log(`[rust] Using binary: ${rustBinary}`);
@@ -545,7 +545,7 @@ if (config.showVersion) {
545
545
  process.exit(0);
546
546
  }
547
547
  if (config.appendPrompt) {
548
- const { PidStore } = await import("./pidStore-iJY3JFTn.js");
548
+ const { PidStore } = await import("./pidStore-9b3YTuf4.js");
549
549
  const ipcPath = await PidStore.findActiveFifo(process.cwd());
550
550
  if (!ipcPath) {
551
551
  console.error("No active agent with IPC found in current directory.");
package/dist/index.js CHANGED
@@ -1,7 +1,7 @@
1
- import { a as removeControlCharacters, i as AgentContext, n as agentYes, r as config, t as CLIS_CONFIG } from "./ts-BvWaEGsr.js";
1
+ import { a as removeControlCharacters, i as AgentContext, n as agentYes, r as config, t as CLIS_CONFIG } from "./ts-BAc4Jcrw.js";
2
2
  import "./logger-B9h0djqx.js";
3
- import "./versionChecker-DfIPG9ui.js";
4
- import "./pidStore-DTzl6zeh.js";
3
+ import "./versionChecker-MNvA73o9.js";
4
+ import "./pidStore-DBjlqzo8.js";
5
5
  import "./globalPidIndex-yVd3mbsV.js";
6
6
 
7
7
  export { AgentContext, CLIS_CONFIG, config, agentYes as default, removeControlCharacters };
@@ -0,0 +1,5 @@
1
+ import "./logger-B9h0djqx.js";
2
+ import { t as PidStore } from "./pidStore-DBjlqzo8.js";
3
+ import "./globalPidIndex-yVd3mbsV.js";
4
+
5
+ export { PidStore };
@@ -6,6 +6,26 @@ import { homedir } from "os";
6
6
  import path from "path";
7
7
  import { lock } from "proper-lockfile";
8
8
 
9
+ //#region ts/agentYesHome.ts
10
+ /**
11
+ * Root directory for cross-runtime, machine-global agent-yes state:
12
+ * the pid index (`pids.jsonl`), FIFO/named-pipe IPC endpoints (`fifo/`),
13
+ * winsize signals, notes, and the serve token.
14
+ *
15
+ * Durable per-session *logs* deliberately do NOT live here — they go under
16
+ * `<cwd>/.agent-yes/` so they stay colocated with the project that produced
17
+ * them (see `PidStore`). Only ephemeral IPC + the discovery index are global,
18
+ * which keeps FIFOs on the local home filesystem (reliable `mkfifo`) and lets
19
+ * `ay ls`/`ay attach` find every agent regardless of the caller's cwd.
20
+ *
21
+ * Resolved at call time (not module load) so tests and callers can override
22
+ * via `$AGENT_YES_HOME` without juggling the module cache.
23
+ */
24
+ function agentYesHome() {
25
+ return process.env.AGENT_YES_HOME ?? path.join(homedir(), ".agent-yes");
26
+ }
27
+
28
+ //#endregion
9
29
  //#region ts/JsonlStore.ts
10
30
  /**
11
31
  * A lightweight NeDB-style JSONL persistence layer.
@@ -184,26 +204,6 @@ function generateId() {
184
204
  return Date.now().toString(36) + (idCounter++).toString(36) + Math.random().toString(36).slice(2, 6);
185
205
  }
186
206
 
187
- //#endregion
188
- //#region ts/agentYesHome.ts
189
- /**
190
- * Root directory for cross-runtime, machine-global agent-yes state:
191
- * the pid index (`pids.jsonl`), FIFO/named-pipe IPC endpoints (`fifo/`),
192
- * winsize signals, notes, and the serve token.
193
- *
194
- * Durable per-session *logs* deliberately do NOT live here — they go under
195
- * `<cwd>/.agent-yes/` so they stay colocated with the project that produced
196
- * them (see `PidStore`). Only ephemeral IPC + the discovery index are global,
197
- * which keeps FIFOs on the local home filesystem (reliable `mkfifo`) and lets
198
- * `ay ls`/`ay attach` find every agent regardless of the caller's cwd.
199
- *
200
- * Resolved at call time (not module load) so tests and callers can override
201
- * via `$AGENT_YES_HOME` without juggling the module cache.
202
- */
203
- function agentYesHome() {
204
- return process.env.AGENT_YES_HOME ?? path.join(homedir(), ".agent-yes");
205
- }
206
-
207
207
  //#endregion
208
208
  //#region ts/pidStore.ts
209
209
  var PidStore = class PidStore {
@@ -380,5 +380,5 @@ pid-db/
380
380
  };
381
381
 
382
382
  //#endregion
383
- export { PidStore as t };
384
- //# sourceMappingURL=pidStore-DTzl6zeh.js.map
383
+ export { agentYesHome as n, PidStore as t };
384
+ //# sourceMappingURL=pidStore-DBjlqzo8.js.map
@@ -147,4 +147,4 @@ async function cmdRemote(rest) {
147
147
 
148
148
  //#endregion
149
149
  export { resolveRemoteSpec as a, readRemotes as i, deleteRemoteAlias as n, writeRemoteAlias as o, parseDirectRemoteSpec as r, cmdRemote as t };
150
- //# sourceMappingURL=remotes-Bjp2GYPz.js.map
150
+ //# sourceMappingURL=remotes-C3xPRtfg.js.map
@@ -1,3 +1,3 @@
1
- import { a as resolveRemoteSpec, i as readRemotes, n as deleteRemoteAlias, o as writeRemoteAlias, r as parseDirectRemoteSpec, t as cmdRemote } from "./remotes-Bjp2GYPz.js";
1
+ import { a as resolveRemoteSpec, i as readRemotes, n as deleteRemoteAlias, o as writeRemoteAlias, r as parseDirectRemoteSpec, t as cmdRemote } from "./remotes-C3xPRtfg.js";
2
2
 
3
3
  export { cmdRemote };
@@ -276,4 +276,4 @@ function shouldUseLock(_cwd) {
276
276
 
277
277
  //#endregion
278
278
  export { shouldUseLock as i, getRunningAgentCount as n, releaseLock as r, acquireLock as t };
279
- //# sourceMappingURL=runningLock-C22d9SRJ.js.map
279
+ //# sourceMappingURL=runningLock-CJxsoGdb.js.map
@@ -1,11 +1,16 @@
1
+ import "./ts-BAc4Jcrw.js";
1
2
  import "./logger-B9h0djqx.js";
3
+ import "./versionChecker-MNvA73o9.js";
4
+ import "./pidStore-DBjlqzo8.js";
2
5
  import "./globalPidIndex-yVd3mbsV.js";
3
- import "./remotes-Bjp2GYPz.js";
4
- import { c as readNotes, f as snapshotStatus, l as renderRawLog, m as writeToIpc, o as listRecords, r as controlCodeFromName, u as resolveOne } from "./subcommands-D9wmaZ3U.js";
6
+ import { t as SUPPORTED_CLIS } from "./SUPPORTED_CLIS-eD-UlqO_.js";
7
+ import "./remotes-C3xPRtfg.js";
8
+ import { c as readNotes, f as snapshotStatus, l as renderRawLog, m as writeToIpc, o as listRecords, r as controlCodeFromName, u as resolveOne } from "./subcommands-K242usI5.js";
5
9
  import yargs from "yargs";
6
- import { mkdir, readFile, writeFile } from "fs/promises";
10
+ import { mkdir, open, readFile, writeFile } from "fs/promises";
7
11
  import { homedir } from "os";
8
12
  import path from "path";
13
+ import { watch } from "node:fs";
9
14
  import { randomBytes, timingSafeEqual } from "crypto";
10
15
 
11
16
  //#region ts/serve.ts
@@ -107,7 +112,7 @@ async function cmdServe(rest) {
107
112
  Start an HTTP API server so remote machines can list/tail/send agents.
108
113
 
109
114
  Options:
110
- --port N Port to listen on (default: ${DEFAULT_PORT})\n --host HOST Interface to bind (default: 127.0.0.1; use 0.0.0.0 to expose)\n --token TOKEN Auth token (auto-generated and saved if omitted)\n --tls-cert FILE TLS certificate PEM\n --tls-key FILE TLS private key PEM\n\nSubcommands:\n ay serve install install as background daemon via oxmgr\n ay serve uninstall remove daemon\n ay serve logs view daemon logs\n\nOnce running, connect from another machine:\n ay ls <token>@<host>:${DEFAULT_PORT}\n ay remote add <alias> http://<token>@<host>:${DEFAULT_PORT}\n`);
115
+ --port N Port to listen on (default: ${DEFAULT_PORT})\n --host HOST Interface to bind (default: 127.0.0.1; use 0.0.0.0 to expose)\n --token TOKEN Auth token (auto-generated and saved if omitted)\n --share [URL] Share over WebRTC to agent-yes.com (bare flag mints a room+link)\n --allow-spawn Deprecated no-op — the console can always spawn agents\n --tls-cert FILE TLS certificate PEM\n --tls-key FILE TLS private key PEM\n\nSubcommands:\n ay serve install install as background daemon via oxmgr\n ay serve uninstall remove daemon\n ay serve logs view daemon logs\n\nOnce running, connect from another machine:\n ay ls <token>@<host>:${DEFAULT_PORT}\n ay remote add <alias> http://<token>@<host>:${DEFAULT_PORT}\n`);
111
116
  return 0;
112
117
  }
113
118
  const sub = rest[0];
@@ -129,6 +134,13 @@ Options:
129
134
  }).option("tls-key", {
130
135
  type: "string",
131
136
  description: "TLS private key file (PEM)"
137
+ }).option("share", {
138
+ type: "string",
139
+ description: "Share over WebRTC: bare flag mints a room+link, or pass webrtc://room:token@host"
140
+ }).option("allow-spawn", {
141
+ type: "boolean",
142
+ default: false,
143
+ description: "Deprecated no-op — the console can always spawn agents"
132
144
  }).help(false).version(false).exitProcess(false).parseAsync();
133
145
  const port = argv.port ?? DEFAULT_PORT;
134
146
  const host = argv.host ?? "127.0.0.1";
@@ -194,9 +206,34 @@ Options:
194
206
  return new Response(e.message, { status: 404 });
195
207
  }
196
208
  }
209
+ const sizeM = /^\/api\/size\/(.+)$/.exec(p);
210
+ if (req.method === "GET" && sizeM) {
211
+ const keyword = decodeURIComponent(sizeM[1]);
212
+ try {
213
+ const record = await resolveOne(keyword, defaultOpts());
214
+ const ayHome = process.env.AGENT_YES_HOME ?? path.join(homedir(), ".agent-yes");
215
+ let cols = null;
216
+ let rows = null;
217
+ try {
218
+ const [c, r] = (await readFile(path.join(ayHome, "ptysize", String(record.pid)), "utf-8")).trim().split(/\s+/).map(Number);
219
+ if (c > 0 && r > 0) {
220
+ cols = c;
221
+ rows = r;
222
+ }
223
+ } catch {}
224
+ return Response.json({
225
+ pid: record.pid,
226
+ cols,
227
+ rows
228
+ });
229
+ } catch (e) {
230
+ return new Response(e.message, { status: 404 });
231
+ }
232
+ }
197
233
  const tailM = /^\/api\/tail\/(.+)$/.exec(p);
198
234
  if (req.method === "GET" && tailM) {
199
235
  const keyword = decodeURIComponent(tailM[1]);
236
+ const raw = url.searchParams.get("raw") === "1";
200
237
  try {
201
238
  const record = await resolveOne(keyword, defaultOpts());
202
239
  if (!record.log_file) return new Response(`pid ${record.pid}: no log_file`, { status: 404 });
@@ -206,7 +243,8 @@ Options:
206
243
  const send = (text) => ctrl.enqueue(enc.encode(`data: ${JSON.stringify(text)}\n\n`));
207
244
  const ping = () => ctrl.enqueue(enc.encode(": ping\n\n"));
208
245
  const initBuf = await readFile(logPath).catch(() => Buffer.alloc(0));
209
- send(await renderRawLog(initBuf, {
246
+ if (raw) send(new TextDecoder().decode(initBuf.slice(Math.max(0, initBuf.length - 65536))));
247
+ else send(await renderRawLog(initBuf, {
210
248
  mode: "tail",
211
249
  n: 96
212
250
  }));
@@ -221,24 +259,43 @@ Options:
221
259
  }, 15e3);
222
260
  const ansiRe = /\x1b\[[0-?]*[ -/]*[@-~]|\x1b\][^\x07\x1b]*(?:\x07|\x1b\\)|\x1b[@-Z\\-_]/g;
223
261
  const ctrlRe = /[\x00-\x08\x0b\x0c\x0e-\x1f\x7f]/g;
224
- const poller = setInterval(async () => {
225
- if (closed) {
226
- clearInterval(poller);
227
- return;
228
- }
262
+ const fh = await open(logPath, "r").catch(() => null);
263
+ let reading = false;
264
+ const flush = async () => {
265
+ if (closed || reading || !fh) return;
266
+ reading = true;
229
267
  try {
230
- const full = await readFile(logPath);
231
- if (full.length <= offset) return;
232
- const chunk = full.slice(offset);
233
- offset = full.length;
234
- const text = new TextDecoder().decode(chunk).replace(ansiRe, "").replace(ctrlRe, "");
235
- if (text.trim()) send(text.trimStart());
236
- } catch {}
237
- }, 300);
268
+ const { size } = await fh.stat();
269
+ if (size < offset) offset = size;
270
+ if (size > offset) {
271
+ const len = size - offset;
272
+ const buf = Buffer.allocUnsafe(len);
273
+ const { bytesRead } = await fh.read(buf, 0, len, offset);
274
+ offset += bytesRead;
275
+ const chunk = buf.subarray(0, bytesRead);
276
+ if (raw) send(new TextDecoder().decode(chunk));
277
+ else {
278
+ const text = new TextDecoder().decode(chunk).replace(ansiRe, "").replace(ctrlRe, "");
279
+ if (text.trim()) send(text.trimStart());
280
+ }
281
+ }
282
+ } catch {} finally {
283
+ reading = false;
284
+ }
285
+ };
286
+ let watcher = null;
287
+ try {
288
+ watcher = watch(logPath, () => void flush());
289
+ } catch {}
290
+ const poller = setInterval(() => void flush(), 60);
238
291
  req.signal.addEventListener("abort", () => {
239
292
  closed = true;
240
293
  clearInterval(heartbeat);
241
294
  clearInterval(poller);
295
+ try {
296
+ watcher?.close();
297
+ } catch {}
298
+ fh?.close().catch(() => {});
242
299
  try {
243
300
  ctrl.close();
244
301
  } catch {}
@@ -279,6 +336,71 @@ Options:
279
336
  return new Response(e.message, { status: 404 });
280
337
  }
281
338
  }
339
+ const resizeM = /^\/api\/resize\/(.+)$/.exec(p);
340
+ if (req.method === "POST" && resizeM) {
341
+ const keyword = decodeURIComponent(resizeM[1]);
342
+ let body;
343
+ try {
344
+ body = await req.json();
345
+ } catch {
346
+ return new Response("invalid JSON body", { status: 400 });
347
+ }
348
+ const cols = Math.max(1, Math.floor(Number(body.cols) || 0));
349
+ const rows = Math.max(1, Math.floor(Number(body.rows) || 0));
350
+ if (!cols || !rows) return new Response("missing cols/rows", { status: 400 });
351
+ try {
352
+ const record = await resolveOne(keyword, defaultOpts());
353
+ const ayHome = process.env.AGENT_YES_HOME ?? path.join(homedir(), ".agent-yes");
354
+ const winsizeDir = path.join(ayHome, "winsize");
355
+ await mkdir(winsizeDir, { recursive: true });
356
+ await writeFile(path.join(winsizeDir, String(record.pid)), `${cols} ${rows} ${Date.now()}\n`);
357
+ try {
358
+ process.kill(record.pid, "SIGWINCH");
359
+ } catch {}
360
+ return Response.json({
361
+ ok: true,
362
+ pid: record.pid,
363
+ cols,
364
+ rows
365
+ });
366
+ } catch (e) {
367
+ return new Response(e.message, { status: 404 });
368
+ }
369
+ }
370
+ if (req.method === "POST" && p === "/api/spawn") {
371
+ let body;
372
+ try {
373
+ body = await req.json();
374
+ } catch {
375
+ return new Response("invalid JSON body", { status: 400 });
376
+ }
377
+ const cli = String(body.cli ?? "claude");
378
+ if (!SUPPORTED_CLIS.includes(cli)) return new Response(`unsupported cli: ${cli}`, { status: 400 });
379
+ const cwd = typeof body.cwd === "string" && body.cwd ? body.cwd : process.cwd();
380
+ const prompt = String(body.prompt ?? "");
381
+ process.stderr.write(`→ console spawned: ay ${cli}${prompt ? ` -- "${prompt.slice(0, 60)}"` : ""} (cwd: ${cwd})\n`);
382
+ try {
383
+ const child = Bun.spawn([
384
+ "ay",
385
+ cli,
386
+ ...prompt ? ["--", prompt] : []
387
+ ], {
388
+ cwd,
389
+ stdin: "ignore",
390
+ stdout: "ignore",
391
+ stderr: "ignore"
392
+ });
393
+ child.unref();
394
+ return Response.json({
395
+ ok: true,
396
+ pid: child.pid,
397
+ cli,
398
+ cwd
399
+ });
400
+ } catch (e) {
401
+ return new Response(e.message, { status: 500 });
402
+ }
403
+ }
282
404
  return new Response("Not Found", { status: 404 });
283
405
  }
284
406
  };
@@ -296,6 +418,20 @@ Options:
296
418
  process.stdout.write(`save as alias:\n`);
297
419
  process.stdout.write(` ay remote add <alias> ${scheme}://${token}@<host>:${port}\n\n`);
298
420
  if (!useHttps) process.stdout.write("for HTTPS: ay serve --tls-cert cert.pem --tls-key key.pem\n openssl req -x509 -newkey rsa:2048 -keyout key.pem -out cert.pem -days 365 -nodes -subj '/CN=localhost'\n\n");
421
+ if (argv.share !== void 0) {
422
+ const shareUrl = typeof argv.share === "string" && argv.share.startsWith("webrtc://") ? argv.share : void 0;
423
+ try {
424
+ const { startShare } = await import("./share-DUhUA1Pi.js");
425
+ const { link } = await startShare({
426
+ url: shareUrl,
427
+ apiUrl: `http://127.0.0.1:${port}`,
428
+ apiToken: token
429
+ });
430
+ process.stdout.write(`\nshared over WebRTC — open this link (the token is eaten from the URL on open):\n ${link}\n\n`);
431
+ } catch (e) {
432
+ process.stderr.write(`ay serve --share failed: ${e.message}\n`);
433
+ }
434
+ }
299
435
  process.stdout.write(`(Ctrl-C to stop)\n`);
300
436
  await new Promise((resolve) => {
301
437
  process.on("SIGINT", () => {
@@ -312,4 +448,4 @@ Options:
312
448
 
313
449
  //#endregion
314
450
  export { cmdServe };
315
- //# sourceMappingURL=serve-CixOwENN.js.map
451
+ //# sourceMappingURL=serve-CKcbVPy6.js.map
@@ -0,0 +1,184 @@
1
+ import { randomBytes } from "crypto";
2
+
3
+ //#region ts/share.ts
4
+ const SUB = "ay-signal-1";
5
+ const ICE = [{ urls: "stun:stun.l.google.com:19302" }];
6
+ const MAX_CHUNK = 15e3;
7
+ const DEFAULT_SIGHOST = "s.agent-yes.com";
8
+ function parseShareUrl(s) {
9
+ const m = /^webrtc:\/\/([^:@/]+):([^@/]+)@(.+)$/.exec(s);
10
+ if (!m) throw new Error(`bad --share url: ${s} (want webrtc://room:token@host)`);
11
+ return {
12
+ room: m[1],
13
+ token: m[2],
14
+ host: m[3]
15
+ };
16
+ }
17
+ async function importRTC() {
18
+ try {
19
+ return (await import("node-datachannel/polyfill")).RTCPeerConnection;
20
+ } catch {
21
+ try {
22
+ const { existsSync, symlinkSync, mkdirSync, readdirSync } = await import("fs");
23
+ const path = (await import("path")).default;
24
+ const { createRequire } = await import("module");
25
+ const require = createRequire(import.meta.url);
26
+ const pkg = path.dirname(require.resolve("node-datachannel/package.json"));
27
+ const bin = path.join(pkg, "build", "Release", "node_datachannel.node");
28
+ const cacheRoot = path.join((await import("os")).homedir(), ".bun", "install", "cache");
29
+ if (existsSync(bin) && existsSync(cacheRoot)) for (const d of readdirSync(cacheRoot)) {
30
+ if (!d.startsWith("node-datachannel@")) continue;
31
+ const dst = path.join(cacheRoot, d, "build", "Release");
32
+ mkdirSync(dst, { recursive: true });
33
+ const link = path.join(dst, "node_datachannel.node");
34
+ if (!existsSync(link)) symlinkSync(bin, link);
35
+ }
36
+ } catch {}
37
+ return (await import("node-datachannel/polyfill")).RTCPeerConnection;
38
+ }
39
+ }
40
+ /** Start the share bridge. Resolves once signaling is connected; runs until the
41
+ * process exits, reconnecting signaling on drop. Returns the shareable link. */
42
+ async function startShare(opts) {
43
+ opts.url;
44
+ const sighost = opts.sighost ?? DEFAULT_SIGHOST;
45
+ const { room, token, host } = opts.url ? parseShareUrl(opts.url) : {
46
+ room: "r" + randomBytes(3).toString("hex"),
47
+ token: randomBytes(32).toString("hex"),
48
+ host: sighost
49
+ };
50
+ const RTCPeerConnection = await importRTC();
51
+ const wsScheme = host.startsWith("localhost") || host.startsWith("127.") ? "ws" : "wss";
52
+ const link = `${host === "s.agent-yes.com" ? "https://agent-yes.com" : "http://localhost:7778"}/#${room}:${token}${host === "s.agent-yes.com" ? "" : "@" + host}`;
53
+ const peers = /* @__PURE__ */ new Map();
54
+ const connectSignaling = (onReady) => {
55
+ const ws = new WebSocket(`${wsScheme}://${host}/${room}`, [SUB]);
56
+ let ready = false;
57
+ ws.onopen = () => {
58
+ ws.send(JSON.stringify({
59
+ type: "hello",
60
+ role: "host",
61
+ token
62
+ }));
63
+ ready = true;
64
+ onReady();
65
+ };
66
+ ws.onmessage = async (ev) => {
67
+ const m = JSON.parse(ev.data);
68
+ if (m.type === "peer-join") startPeer(ws, m.peer);
69
+ else if (m.type === "answer") await peers.get(m.from)?.pc.setRemoteDescription({
70
+ type: "answer",
71
+ sdp: m.sdp
72
+ });
73
+ else if (m.type === "candidate") await peers.get(m.from)?.pc.addIceCandidate(m.candidate).catch(() => {});
74
+ else if (m.type === "peer-leave") closePeer(m.peer);
75
+ };
76
+ ws.onclose = () => {
77
+ setTimeout(() => connectSignaling(() => {}), ready ? 1500 : 4e3);
78
+ };
79
+ ws.onerror = () => {};
80
+ return ws;
81
+ };
82
+ function startPeer(ws, peerId) {
83
+ const pc = new RTCPeerConnection({ iceServers: ICE });
84
+ const aborts = /* @__PURE__ */ new Map();
85
+ peers.set(peerId, {
86
+ pc,
87
+ aborts
88
+ });
89
+ pc.onicecandidate = (e) => {
90
+ if (e.candidate) ws.send(JSON.stringify({
91
+ type: "candidate",
92
+ to: peerId,
93
+ candidate: e.candidate
94
+ }));
95
+ };
96
+ pc.onconnectionstatechange = () => {
97
+ if ([
98
+ "failed",
99
+ "closed",
100
+ "disconnected"
101
+ ].includes(pc.connectionState)) closePeer(peerId);
102
+ };
103
+ const dc = pc.createDataChannel("api");
104
+ dc.onmessage = (e) => onReq(dc, aborts, JSON.parse(e.data));
105
+ pc.createOffer().then((o) => pc.setLocalDescription(o)).then(() => ws.send(JSON.stringify({
106
+ type: "offer",
107
+ to: peerId,
108
+ sdp: pc.localDescription.sdp
109
+ })));
110
+ }
111
+ function closePeer(peerId) {
112
+ const p = peers.get(peerId);
113
+ if (!p) return;
114
+ for (const a of p.aborts.values()) a.abort();
115
+ try {
116
+ p.pc.close();
117
+ } catch {}
118
+ peers.delete(peerId);
119
+ }
120
+ function send(dc, obj) {
121
+ if (dc.readyState === "open") dc.send(JSON.stringify(obj));
122
+ }
123
+ async function onReq(dc, aborts, req) {
124
+ if (req.t === "abort") {
125
+ aborts.get(req.id)?.abort();
126
+ aborts.delete(req.id);
127
+ return;
128
+ }
129
+ if (req.t !== "req") return;
130
+ const { id, method, path: p, body } = req;
131
+ const ac = new AbortController();
132
+ aborts.set(id, ac);
133
+ try {
134
+ const res = await fetch(opts.apiUrl + p, {
135
+ method,
136
+ headers: {
137
+ Authorization: `Bearer ${opts.apiToken}`,
138
+ ...body ? { "Content-Type": "application/json" } : {}
139
+ },
140
+ body: body ?? void 0,
141
+ signal: ac.signal
142
+ });
143
+ send(dc, {
144
+ t: "res",
145
+ id,
146
+ status: res.status,
147
+ ct: res.headers.get("content-type") ?? ""
148
+ });
149
+ const reader = res.body.getReader();
150
+ const dec = new TextDecoder();
151
+ for (;;) {
152
+ const { done, value } = await reader.read();
153
+ if (done) break;
154
+ const text = dec.decode(value, { stream: true });
155
+ for (let i = 0; i < text.length; i += MAX_CHUNK) send(dc, {
156
+ t: "data",
157
+ id,
158
+ chunk: text.slice(i, i + MAX_CHUNK)
159
+ });
160
+ }
161
+ send(dc, {
162
+ t: "end",
163
+ id
164
+ });
165
+ } catch (e) {
166
+ if (e.name !== "AbortError") send(dc, {
167
+ t: "end",
168
+ id,
169
+ error: String(e)
170
+ });
171
+ } finally {
172
+ aborts.delete(id);
173
+ }
174
+ }
175
+ await new Promise((resolve) => connectSignaling(resolve));
176
+ return {
177
+ room,
178
+ link
179
+ };
180
+ }
181
+
182
+ //#endregion
183
+ export { startShare };
184
+ //# sourceMappingURL=share-DUhUA1Pi.js.map
@@ -1,6 +1,6 @@
1
1
  import "./logger-B9h0djqx.js";
2
2
  import "./globalPidIndex-yVd3mbsV.js";
3
- import "./remotes-Bjp2GYPz.js";
4
- import { a as isSubcommand, c as readNotes, d as runSubcommand, f as snapshotStatus, i as isPidAlive, l as renderRawLog, m as writeToIpc, n as cmdHelp, o as listRecords, p as stopTipForCli, r as controlCodeFromName, s as matchKeyword, t as GRACEFUL_EXIT_COMMANDS, u as resolveOne } from "./subcommands-D9wmaZ3U.js";
3
+ import "./remotes-C3xPRtfg.js";
4
+ import { a as isSubcommand, c as readNotes, d as runSubcommand, f as snapshotStatus, i as isPidAlive, l as renderRawLog, m as writeToIpc, n as cmdHelp, o as listRecords, p as stopTipForCli, r as controlCodeFromName, s as matchKeyword, t as GRACEFUL_EXIT_COMMANDS, u as resolveOne } from "./subcommands-K242usI5.js";
5
5
 
6
6
  export { cmdHelp, isSubcommand, runSubcommand };
@@ -1,5 +1,5 @@
1
1
  import { i as readGlobalPids } from "./globalPidIndex-yVd3mbsV.js";
2
- import { a as resolveRemoteSpec, i as readRemotes } from "./remotes-Bjp2GYPz.js";
2
+ import { a as resolveRemoteSpec, i as readRemotes } from "./remotes-C3xPRtfg.js";
3
3
  import ms from "ms";
4
4
  import yargs from "yargs";
5
5
  import { appendFile, mkdir, open, readFile, stat, writeFile } from "fs/promises";
@@ -162,11 +162,11 @@ async function runSubcommand(argv) {
162
162
  case "restart": return await cmdRestart(rest);
163
163
  case "note": return await cmdNote(rest);
164
164
  case "serve": {
165
- const { cmdServe } = await import("./serve-CixOwENN.js");
165
+ const { cmdServe } = await import("./serve-CKcbVPy6.js");
166
166
  return cmdServe(rest);
167
167
  }
168
168
  case "remote": {
169
- const { cmdRemote } = await import("./remotes-oNI1fR7_.js");
169
+ const { cmdRemote } = await import("./remotes-C9WMt5PY.js");
170
170
  return cmdRemote(rest);
171
171
  }
172
172
  case "help": return cmdHelp();
@@ -1447,4 +1447,4 @@ async function cmdStatus(rest) {
1447
1447
 
1448
1448
  //#endregion
1449
1449
  export { isSubcommand as a, readNotes as c, runSubcommand as d, snapshotStatus as f, isPidAlive as i, renderRawLog as l, writeToIpc as m, cmdHelp as n, listRecords as o, stopTipForCli as p, controlCodeFromName as r, matchKeyword as s, GRACEFUL_EXIT_COMMANDS as t, resolveOne as u };
1450
- //# sourceMappingURL=subcommands-D9wmaZ3U.js.map
1450
+ //# sourceMappingURL=subcommands-K242usI5.js.map
@@ -1,4 +1,4 @@
1
- import { n as getRunningAgentCount } from "./runningLock-C22d9SRJ.js";
1
+ import { n as getRunningAgentCount } from "./runningLock-CJxsoGdb.js";
2
2
  import { existsSync } from "fs";
3
3
  import { mkdir, readFile, unlink, writeFile } from "fs/promises";
4
4
  import { homedir } from "os";
@@ -175,4 +175,4 @@ async function startTray() {
175
175
 
176
176
  //#endregion
177
177
  export { ensureTray, startTray };
178
- //# sourceMappingURL=tray-DHuD0nEk.js.map
178
+ //# sourceMappingURL=tray-CWQe9DMY.js.map