agent-yes 1.298.1 → 1.299.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 (45) hide show
  1. package/dist/{SUPPORTED_CLIS-AzChegaJ.js → SUPPORTED_CLIS-BIlQQJa6.js} +3 -3
  2. package/dist/{SUPPORTED_CLIS-sxjBFTrE.js → SUPPORTED_CLIS-Ct9reIJH.js} +2 -2
  3. package/dist/{agentShare-CDOvU64K.js → agentShare-uzFuaLUH.js} +4 -4
  4. package/dist/{callback-DBOgmPV6.js → callback-BxTZx3xJ.js} +3 -3
  5. package/dist/{callback-Dr5rqkUu.js → callback-DRrURxmb.js} +4 -4
  6. package/dist/cli.js +7 -7
  7. package/dist/{cmdPs-DKuMlynW.js → cmdPs-BGIWbeBM.js} +4 -4
  8. package/dist/index.js +2 -2
  9. package/dist/{notifyDaemon-Ceyhz4el.js → notifyDaemon-EEbnpoYp.js} +4 -4
  10. package/dist/{parentPingLoop-C0hekeg6.js → parentPingLoop-C1XXpKK7.js} +2 -2
  11. package/dist/remotes-BDMnvGI6.js +5 -0
  12. package/dist/{remotes-5P__pAXA.js → remotes-DrYe_nfw.js} +101 -18
  13. package/dist/{rustBinary-BW3BGZ4y.js → rustBinary--pof-MTj.js} +2 -2
  14. package/dist/{rustBinary-0cD4pQIE.js → rustBinary-B7rq3nuz.js} +2 -2
  15. package/dist/{schedule-BRC5cDkf.js → schedule-BFUe9-Mf.js} +4 -4
  16. package/dist/{serve-BD-7GaKa.js → serve-Q4dnZc5l.js} +40 -21
  17. package/dist/{setup-Dad2A_-o.js → setup-aEuGSFjB.js} +3 -3
  18. package/dist/shareCmd-DkITELaM.js +415 -0
  19. package/dist/{subcommands--9gcc0ew.js → subcommands-CUWPMI_r.js} +36 -22
  20. package/dist/{subcommands-ClQCwxvk.js → subcommands-CuRZt3X6.js} +3 -3
  21. package/dist/{systemPathLink-VV-Vm6y2.js → systemPathLink-DoyBuRQq.js} +1 -1
  22. package/dist/{terminal-Bam4XVWi.js → terminal-CUn1_oPd.js} +2 -2
  23. package/dist/{todoCli-BDttv8mk.js → todoCli-DwYlxIAY.js} +1 -1
  24. package/dist/{tray-DWWsVS7Y.js → tray-BcpHVeMk.js} +1 -1
  25. package/dist/{trayApp-DOgsH0en.js → trayApp-BHwAJFzl.js} +2 -2
  26. package/dist/trayApp-ucuB_j5l.js +5 -0
  27. package/dist/{ts-BePSXUQl.js → ts-oIxnyQbE.js} +3 -3
  28. package/dist/{versionChecker-D6zM6Pdv.js → versionChecker-DOgDaagD.js} +2 -2
  29. package/dist/{webrtcLink-CnQf9pmu.js → webrtcLink-DFRyWNMs.js} +2 -2
  30. package/dist/{webrtcRemote-0RGrSwqd.js → webrtcRemote-Cd4vTrgv.js} +2 -2
  31. package/dist/{widget-DJgiOfgE.js → widget-CuagzQwz.js} +3 -3
  32. package/dist/{ws-Covfyaxn.js → ws-DcJBGzQP.js} +2 -2
  33. package/dist/{ws-DjGQGPCq.js → ws-ID7-zDiJ.js} +4 -4
  34. package/lab/ui/index.html +9 -3
  35. package/package.json +1 -1
  36. package/ts/remotes.ts +128 -13
  37. package/ts/serve.ts +22 -0
  38. package/ts/shareCmd.ts +369 -0
  39. package/ts/shareCore.spec.ts +236 -0
  40. package/ts/shareCore.ts +148 -0
  41. package/ts/subcommands.spec.ts +19 -0
  42. package/ts/subcommands.ts +33 -5
  43. package/ts/webrtcLink.ts +3 -1
  44. package/dist/remotes-CY69MeQB.js +0 -5
  45. package/dist/trayApp-s2VuJUP4.js +0 -5
@@ -1,4 +1,4 @@
1
- import { o as findTrayLauncher } from "./rustBinary-BW3BGZ4y.js";
1
+ import { o as findTrayLauncher } from "./rustBinary--pof-MTj.js";
2
2
  import { t as agentYesHome } from "./agentYesHome-BNtn19J4.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-DOgsH0en.js.map
100
+ //# sourceMappingURL=trayApp-BHwAJFzl.js.map
@@ -0,0 +1,5 @@
1
+ import "./versionChecker-DOgDaagD.js";
2
+ import "./rustBinary--pof-MTj.js";
3
+ import { a as trayHiddenMarker, i as launchTray, n as hasDesktop, r as isTrayHidden, t as cmdTray } from "./trayApp-BHwAJFzl.js";
4
+
5
+ export { cmdTray };
@@ -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 { i as getInstalledPackage } from "./versionChecker-D6zM6Pdv.js";
3
+ import { i as getInstalledPackage } from "./versionChecker-DOgDaagD.js";
4
4
  import { t as agentYesHome } from "./agentYesHome-BNtn19J4.js";
5
5
  import { u as removeControlCharacters } from "./todoAutomation-CbVVS4re.js";
6
6
  import { i as shouldUseLock, r as releaseLock, t as acquireLock } from "./runningLock-BOIPD_Vs.js";
@@ -2086,7 +2086,7 @@ async function agentYes({ cli, cliArgs = [], skipPermissions = false, prompt, ro
2086
2086
  }, 100);
2087
2087
  const cleanupHeartbeat = () => clearInterval(heartbeatInterval);
2088
2088
  shell.onExit(cleanupHeartbeat);
2089
- const { startParentPingLoop } = await import("./parentPingLoop-C0hekeg6.js");
2089
+ const { startParentPingLoop } = await import("./parentPingLoop-C1XXpKK7.js");
2090
2090
  const parentPingLoop = startParentPingLoop({
2091
2091
  parentPid,
2092
2092
  selfWrapperPid: process.pid,
@@ -2349,4 +2349,4 @@ function sleep(ms) {
2349
2349
 
2350
2350
  //#endregion
2351
2351
  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 };
2352
- //# sourceMappingURL=ts-BePSXUQl.js.map
2352
+ //# sourceMappingURL=ts-oIxnyQbE.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.298.1";
10
+ var version = "1.299.0";
11
11
 
12
12
  //#endregion
13
13
  //#region ts/versionChecker.ts
@@ -285,4 +285,4 @@ async function displayVersion() {
285
285
 
286
286
  //#endregion
287
287
  export { versionString as a, getInstalledPackage as i, compareVersions as n, displayVersion as r, checkAndAutoUpdate as t };
288
- //# sourceMappingURL=versionChecker-D6zM6Pdv.js.map
288
+ //# sourceMappingURL=versionChecker-DOgDaagD.js.map
@@ -65,9 +65,9 @@ function toWebrtcUrl(link) {
65
65
  }
66
66
  /** True if `spec` looks like a WebRTC share link (vs. an http remote or alias). */
67
67
  function isWebrtcSpec(spec) {
68
- return spec.startsWith("webrtc://") || /^https?:\/\//.test(spec) && spec.includes("#");
68
+ return spec.startsWith("webrtc://") || parseRaw(spec) !== null;
69
69
  }
70
70
 
71
71
  //#endregion
72
72
  export { toWebrtcUrl as i, isWebrtcSpec as n, parseWebrtcLink as r, SIGNAL_SUBPROTOCOL as t };
73
- //# sourceMappingURL=webrtcLink-CnQf9pmu.js.map
73
+ //# sourceMappingURL=webrtcLink-DFRyWNMs.js.map
@@ -1,5 +1,5 @@
1
1
  import { a as computeTranscriptHash, c as open, d as randomHex, f as seal, l as packEnvelope, n as FLAG_CONFIRM, o as deriveAuthToken, p as unpackEnvelope, s as deriveDirKeys } from "./e2e-z1xpwSAg.js";
2
- import { n as isWebrtcSpec, r as parseWebrtcLink, t as SIGNAL_SUBPROTOCOL } from "./webrtcLink-CnQf9pmu.js";
2
+ import { n as isWebrtcSpec, r as parseWebrtcLink, t as SIGNAL_SUBPROTOCOL } from "./webrtcLink-DFRyWNMs.js";
3
3
  import { RTCPeerConnection } from "node-datachannel/polyfill";
4
4
 
5
5
  //#region ts/signalingHint.ts
@@ -297,4 +297,4 @@ async function startWebrtcBridge(link) {
297
297
 
298
298
  //#endregion
299
299
  export { startWebrtcBridge };
300
- //# sourceMappingURL=webrtcRemote-0RGrSwqd.js.map
300
+ //# sourceMappingURL=webrtcRemote-Cd4vTrgv.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-BD-7GaKa.js");
31
+ const { resolveDaemonHttpBase, loadTokenReadOnly } = await import("./serve-Q4dnZc5l.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-BD-7GaKa.js");
189
+ const { mintScopedTermToken } = await import("./serve-Q4dnZc5l.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-DJgiOfgE.js.map
205
+ //# sourceMappingURL=widget-CuagzQwz.js.map
@@ -1,4 +1,4 @@
1
- import { F as listRecords } from "./subcommands--9gcc0ew.js";
1
+ import { F as listRecords } from "./subcommands-CUWPMI_r.js";
2
2
  import { a as getProvisionRoot } from "./workspaceConfig-DTvPtr5j.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-Covfyaxn.js.map
427
+ //# sourceMappingURL=ws-DcJBGzQP.js.map
@@ -5,10 +5,10 @@ import "./pidStore-DXWqzTSz.js";
5
5
  import "./messageLog-Brx3w6zT.js";
6
6
  import "./e2e-z1xpwSAg.js";
7
7
  import "./configShared-DKTgiz7K.js";
8
- import "./subcommands--9gcc0ew.js";
8
+ import "./subcommands-CUWPMI_r.js";
9
9
  import "./notifyStore-2SWKGwZI.js";
10
- import "./webrtcLink-CnQf9pmu.js";
11
- import "./remotes-5P__pAXA.js";
12
- 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-Covfyaxn.js";
10
+ import "./webrtcLink-DFRyWNMs.js";
11
+ import "./remotes-DrYe_nfw.js";
12
+ 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-DcJBGzQP.js";
13
13
 
14
14
  export { WS_JSON_SCHEMA, cmdWs, collectWorkspaces, isPathInside, loadProvision, walkWorkspaces, workspaceStatus };
package/lab/ui/index.html CHANGED
@@ -3064,11 +3064,17 @@
3064
3064
  // boot() stores the token and local /api calls carry it as ?token= (query,
3065
3065
  // not header — EventSource can't set headers). When served via the lab
3066
3066
  // proxy instead, no token is stored and paths stay bare (proxy injects).
3067
+ // The page may be mounted under a sub-path by a reverse proxy that strips
3068
+ // it before forwarding (`tailscale serve --set-path=/ay` → console at
3069
+ // https://<host>.ts.net/ay/), so local calls resolve against the page's
3070
+ // own directory: "/ay/" → "/ay/api/…", "/" → "/api/…".
3071
+ const LOCAL_BASE = location.pathname.replace(/\/[^/]*$/, "");
3067
3072
  const withTok = (path) => {
3068
3073
  const t = localStorage.getItem("ay.localToken");
3069
- return t
3070
- ? path + (path.includes("?") ? "&" : "?") + "token=" + encodeURIComponent(t)
3071
- : path;
3074
+ return (
3075
+ LOCAL_BASE +
3076
+ (t ? path + (path.includes("?") ? "&" : "?") + "token=" + encodeURIComponent(t) : path)
3077
+ );
3072
3078
  };
3073
3079
 
3074
3080
  // ---- transports: a uniform { fetchJSON, post, subscribe } over each wire ----
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "agent-yes",
3
- "version": "1.298.1",
3
+ "version": "1.299.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",
package/ts/remotes.ts CHANGED
@@ -80,6 +80,47 @@ export function parseDirectRemoteSpec(
80
80
  };
81
81
  }
82
82
 
83
+ /**
84
+ * Parse an http(s) share URL into {url, token}. This is the ONE link `ay share`
85
+ * hands out for both the web console and the CLI:
86
+ * https://host.ts.net/ay/#k=<token> console link (token in the fragment)
87
+ * http://<token>@192.168.1.5:7432 legacy userinfo form (`ay remote add`)
88
+ * The base keeps any path prefix (a reverse proxy mount like /ay), minus a
89
+ * trailing slash / index.html. Null when there's no token or it isn't http(s).
90
+ *
91
+ * Never throws: every http(s) spec reaches here through resolveRemoteSpec, so a
92
+ * malformed one must come back as "not a share URL", not as an exception.
93
+ */
94
+ function decodeMaybe(s: string): string {
95
+ try {
96
+ return decodeURIComponent(s);
97
+ } catch {
98
+ return s; // not valid percent-encoding — take it literally
99
+ }
100
+ }
101
+
102
+ export function parseShareUrl(spec: string): { url: string; token: string } | null {
103
+ if (!/^https?:\/\//i.test(spec)) return null;
104
+ let u: URL;
105
+ try {
106
+ u = new URL(spec);
107
+ } catch {
108
+ return null;
109
+ }
110
+ const hash = new URLSearchParams(u.hash.replace(/^#/, ""));
111
+ // URLSearchParams decodes `#k=` leniently; match that for the userinfo form.
112
+ // `decodeURIComponent` alone THREW a URIError on a stray percent
113
+ // (`http://100%@host/`), which surfaced as a crash from `ay ls <url>`.
114
+ const token = hash.get("k") || decodeMaybe(u.username);
115
+ if (!token) return null;
116
+ u.username = "";
117
+ u.password = "";
118
+ u.hash = "";
119
+ u.search = "";
120
+ u.pathname = u.pathname.replace(/\/index\.html$/, "/").replace(/\/+$/, "");
121
+ return { url: u.toString().replace(/\/+$/, ""), token };
122
+ }
123
+
83
124
  /**
84
125
  * Resolve a spec to connection details.
85
126
  * Accepts:
@@ -92,6 +133,10 @@ export async function resolveRemoteSpec(spec: string): Promise<ResolvedRemote |
92
133
  // These carry their own secret and have no keyword (use an alias to add one).
93
134
  if (isWebrtcSpec(spec)) return resolveWebrtc(spec, undefined, webrtcLabel(spec));
94
135
 
136
+ // Inline http(s) share URL: `ay ls 'https://host.ts.net/ay/#k=<token>'`.
137
+ const shared = parseShareUrl(spec);
138
+ if (shared) return { ...shared, label: new URL(shared.url).host };
139
+
95
140
  const direct = parseDirectRemoteSpec(spec);
96
141
  if (direct) {
97
142
  return {
@@ -146,6 +191,7 @@ export async function cmdRemote(rest: string[]): Promise<number> {
146
191
  ` ay remote add <alias> http://<token>@<host>:<port> add an http remote\n` +
147
192
  ` ay remote add <alias> webrtc://<room>:<token>@<host> add a WebRTC share remote\n` +
148
193
  ` ay remote add <alias> https://agent-yes.com/w/#<room>:<token> (share link form)\n` +
194
+ ` ay remote add <alias> https://<host>/ay/#k=<token> (an \`ay share\` URL)\n` +
149
195
  ` ay remote rm <alias> remove a remote\n\n` +
150
196
  `Once added, use the alias anywhere a keyword is accepted:\n` +
151
197
  ` ay ls <alias>\n` +
@@ -189,23 +235,15 @@ export async function cmdRemote(rest: string[]): Promise<number> {
189
235
  process.stderr.write(`\n ay ls ${alias} # list agents on ${alias}\n`);
190
236
  return 0;
191
237
  }
192
- let url: string, token: string;
193
- try {
194
- const parsed = new URL(rawUrl);
195
- token = parsed.username;
196
- parsed.username = "";
197
- parsed.password = "";
198
- url = parsed.toString().replace(/\/$/, "");
199
- } catch {
200
- process.stderr.write(`ay remote add: invalid URL '${rawUrl}'\n`);
201
- return 1;
202
- }
203
- if (!token) {
238
+ const parsed = parseShareUrl(rawUrl);
239
+ if (!parsed) {
204
240
  process.stderr.write(
205
- `ay remote add: no token in URL — expected http://<token>@<host>:<port>\n`,
241
+ `ay remote add: no token in '${rawUrl}' — expected http://<token>@<host>:<port>\n` +
242
+ ` or a share URL like https://<host>/ay/#k=<token> (from \`ay share\`)\n`,
206
243
  );
207
244
  return 1;
208
245
  }
246
+ const { url, token } = parsed;
209
247
  await writeRemoteAlias(alias, { url, token });
210
248
  process.stdout.write(`remote '${alias}' added → ${url}\n`);
211
249
  process.stderr.write(`\n ay ls ${alias} # list agents on ${alias}\n`);
@@ -236,3 +274,80 @@ export async function cmdRemote(rest: string[]): Promise<number> {
236
274
  );
237
275
  return 1;
238
276
  }
277
+
278
+ /**
279
+ * Default alias for a share URL: the machine's short name. Call only on a link
280
+ * that already parsed (a webrtc link or `parseShareUrl` hit) — it assumes a
281
+ * valid URL and throws otherwise.
282
+ */
283
+ export function defaultConnectAlias(link: string): string {
284
+ const w = parseWebrtcLink(link);
285
+ if (w) return `webrtc-${w.room.slice(0, 8)}`;
286
+ const host = new URL(link).hostname;
287
+ // box.tailnet.ts.net → box; 192.168.1.5 → 192-168-1-5
288
+ if (/^[\d.]+$/.test(host) || host.includes(":")) return host.replace(/[.:]/g, "-");
289
+ return host.split(".")[0] || host;
290
+ }
291
+
292
+ // ay connect <share-url> [alias] — the CLI half of `ay share`: the same URL that
293
+ // opens the web console is saved as a remote alias here (after a reachability
294
+ // check), so `ay ls <alias>` / `ay tail <alias>:<kw>` work from this machine.
295
+ export async function cmdConnect(rest: string[]): Promise<number> {
296
+ const positional = rest.filter((a) => !a.startsWith("-"));
297
+ const [link, aliasArg] = positional;
298
+ if (!link || rest.includes("-h") || rest.includes("--help")) {
299
+ process.stdout.write(
300
+ `Usage: ay connect <share-url> [alias]\n\n` +
301
+ `Save another machine's \`ay share\` URL as a remote, so this CLI can drive it.\n` +
302
+ `The same URL opens that machine's web console in a browser.\n\n` +
303
+ ` ay connect 'https://box.tailnet.ts.net/ay/#k=<token>' # tailscale\n` +
304
+ ` ay connect 'http://192.168.1.5:7432/#k=<token>' # lan\n` +
305
+ ` ay connect 'https://agent-yes.com/w/#<room>:<secret>' box # webrtc\n\n` +
306
+ `alias defaults to the host's short name. Then:\n` +
307
+ ` ay ls <alias> ay tail <alias>:<keyword> ay send <alias>:<keyword> "msg"\n`,
308
+ );
309
+ return link ? 0 : 1;
310
+ }
311
+ // Recognise the link BEFORE naming it: defaultConnectAlias parses it as a URL,
312
+ // so deriving the alias first turned a scheme-less paste
313
+ // (`box.ts.net/ay/#k=…`) into a bare "Invalid URL" and buried the message
314
+ // below, which is the one that explains the actual mistake.
315
+ const webrtc = isWebrtcSpec(link);
316
+ const parsed = webrtc ? null : parseShareUrl(link);
317
+ if (!webrtc && !parsed) {
318
+ process.stderr.write(
319
+ `ay connect: not a share URL: '${link}' — expected https://<host>/ay/#k=<token>\n` +
320
+ ` (quote it: the # starts a comment in most shells)\n`,
321
+ );
322
+ return 1;
323
+ }
324
+ const alias = aliasArg ?? defaultConnectAlias(link);
325
+
326
+ if (!parsed) {
327
+ await writeRemoteAlias(alias, { url: link, token: "" });
328
+ } else {
329
+ try {
330
+ const r = await fetch(`${parsed.url}/api/version`, {
331
+ headers: { Authorization: `Bearer ${parsed.token}` },
332
+ signal: AbortSignal.timeout(5000),
333
+ });
334
+ if (r.status === 401 || r.status === 403) {
335
+ process.stderr.write(`ay connect: ${parsed.url} rejected the token (HTTP ${r.status})\n`);
336
+ return 1;
337
+ }
338
+ if (!r.ok) throw new Error(`HTTP ${r.status}`);
339
+ } catch (e) {
340
+ process.stderr.write(
341
+ `ay connect: warning: ${parsed.url} is not reachable right now (${(e as Error).message}) — saving anyway\n`,
342
+ );
343
+ }
344
+ await writeRemoteAlias(alias, parsed);
345
+ }
346
+ process.stdout.write(`connected '${alias}'\n`);
347
+ process.stderr.write(
348
+ `\n ay ls ${alias} # list its agents\n` +
349
+ ` ay tail ${alias}:<keyword> # read one\n` +
350
+ ` ay remote rm ${alias} # forget it\n`,
351
+ );
352
+ return 0;
353
+ }
package/ts/serve.ts CHANGED
@@ -1139,6 +1139,28 @@ export async function resolveLocalServeUrl(): Promise<string | null> {
1139
1139
  return port ? `http://127.0.0.1:${port}` : null;
1140
1140
  }
1141
1141
 
1142
+ /**
1143
+ * What `ay share` needs to know about this host's daemon: the args it was
1144
+ * installed with (null = none installed), whether its HTTP API answers, and the token.
1145
+ * `port` is the loopback HTTP port (fixed --port, else the portless backend).
1146
+ */
1147
+ export async function inspectServeDaemon(): Promise<{
1148
+ args: string[] | null;
1149
+ port: number | null;
1150
+ httpUp: boolean; // answers /api/version on `port` (a webrtc-only daemon never does)
1151
+ token: string;
1152
+ consoleUrl: string | null;
1153
+ }> {
1154
+ const mgr = await resolveActiveManager();
1155
+ const args = mgr ? await readDaemonServeArgs(mgr) : null;
1156
+ const token = await loadOrCreateToken(undefined);
1157
+ const portless = args !== null && argsUsePortless(args);
1158
+ const port = args === null ? null : portless ? await portlessAppPort() : portFromArgs(args);
1159
+ const httpUp = args !== null && (await fetchDaemonVersion(port, token)) !== null;
1160
+ const consoleUrl = portless ? await resolvedPortlessConsoleUrl(token) : null;
1161
+ return { args, port, httpUp, token, consoleUrl };
1162
+ }
1163
+
1142
1164
  /**
1143
1165
  * Best-effort HTTP base URL of the LOCAL running daemon, for CLI→daemon calls
1144
1166
  * (`ay widget`). More robust than resolveLocalServeUrl for UNMANAGED daemons: it