agent-yes 1.85.0 → 1.86.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.
- package/dist/{SUPPORTED_CLIS-CawnsTw2.js → SUPPORTED_CLIS-BlWg00sP.js} +3 -3
- package/dist/cli.js +5 -5
- package/dist/index.js +2 -2
- package/dist/remotes-CFrho898.js +131 -0
- package/dist/remotes-kfUzk-JT.js +3 -0
- package/dist/serve-D0NnTXRD.js +303 -0
- package/dist/subcommands-BDiS305D.js +6 -0
- package/dist/{subcommands-BwWcA9uo.js → subcommands-BpGEGOQM.js} +300 -6
- package/dist/{tray-CH_G7aXM.js → tray-DHuD0nEk.js} +1 -1
- package/dist/{ts-D0ddYVke.js → ts-DWuvdSWr.js} +2 -2
- package/dist/{versionChecker-ftOiNICT.js → versionChecker-BCrJk4Zj.js} +2 -2
- package/package.json +1 -1
- package/ts/remotes.ts +161 -0
- package/ts/serve.ts +373 -0
- package/ts/subcommands.ts +380 -9
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import "./logger-B9h0djqx.js";
|
|
2
1
|
import { r as readGlobalPids } from "./globalPidIndex-Cr-g75QF.js";
|
|
2
|
+
import { a as resolveRemoteSpec, i as readRemotes } from "./remotes-CFrho898.js";
|
|
3
3
|
import yargs from "yargs";
|
|
4
4
|
import { appendFile, mkdir, open, readFile, stat, writeFile } from "fs/promises";
|
|
5
5
|
import { homedir } from "os";
|
|
@@ -126,7 +126,9 @@ const SUBCOMMANDS = new Set([
|
|
|
126
126
|
"head",
|
|
127
127
|
"send",
|
|
128
128
|
"restart",
|
|
129
|
-
"note"
|
|
129
|
+
"note",
|
|
130
|
+
"serve",
|
|
131
|
+
"remote"
|
|
130
132
|
]);
|
|
131
133
|
const IDLE_THRESHOLD_MS = 60 * 1e3;
|
|
132
134
|
function isSubcommand(name) {
|
|
@@ -153,6 +155,14 @@ async function runSubcommand(argv) {
|
|
|
153
155
|
case "send": return await cmdSend(rest);
|
|
154
156
|
case "restart": return await cmdRestart(rest);
|
|
155
157
|
case "note": return await cmdNote(rest);
|
|
158
|
+
case "serve": {
|
|
159
|
+
const { cmdServe } = await import("./serve-D0NnTXRD.js");
|
|
160
|
+
return cmdServe(rest);
|
|
161
|
+
}
|
|
162
|
+
case "remote": {
|
|
163
|
+
const { cmdRemote } = await import("./remotes-kfUzk-JT.js");
|
|
164
|
+
return cmdRemote(rest);
|
|
165
|
+
}
|
|
156
166
|
default: return null;
|
|
157
167
|
}
|
|
158
168
|
} catch (err) {
|
|
@@ -199,6 +209,254 @@ async function resolveOne(keyword, opts) {
|
|
|
199
209
|
const lines = matches.slice(0, 10).map((r) => ` ${r.pid} ${r.cli} ${r.cwd}`).join("\n");
|
|
200
210
|
throw new Error(`keyword "${keyword}" matched ${matches.length} agents — disambiguate by pid or pass --latest:\n${lines}`);
|
|
201
211
|
}
|
|
212
|
+
async function remoteGet(remote, pathname) {
|
|
213
|
+
return fetch(`${remote.url}${pathname}`, { headers: { Authorization: `Bearer ${remote.token}` } });
|
|
214
|
+
}
|
|
215
|
+
async function remotePost(remote, pathname, body) {
|
|
216
|
+
return fetch(`${remote.url}${pathname}`, {
|
|
217
|
+
method: "POST",
|
|
218
|
+
headers: {
|
|
219
|
+
Authorization: `Bearer ${remote.token}`,
|
|
220
|
+
"Content-Type": "application/json"
|
|
221
|
+
},
|
|
222
|
+
body: JSON.stringify(body)
|
|
223
|
+
});
|
|
224
|
+
}
|
|
225
|
+
async function runRemoteLs(remote, opts) {
|
|
226
|
+
const params = new URLSearchParams();
|
|
227
|
+
if (remote.keyword) params.set("keyword", remote.keyword);
|
|
228
|
+
if (opts.all) params.set("all", "1");
|
|
229
|
+
if (opts.active) params.set("active", "1");
|
|
230
|
+
const res = await remoteGet(remote, `/api/ls?${params}`);
|
|
231
|
+
if (!res.ok) {
|
|
232
|
+
process.stderr.write(`remote error ${res.status}: ${await res.text()}\n`);
|
|
233
|
+
return 1;
|
|
234
|
+
}
|
|
235
|
+
const records = await res.json();
|
|
236
|
+
if (records.length === 0) {
|
|
237
|
+
process.stderr.write(remote.keyword ? `no agents matched "${remote.keyword}" on ${remote.url}\n` : `no running agents on ${remote.url}\n`);
|
|
238
|
+
return 0;
|
|
239
|
+
}
|
|
240
|
+
process.stderr.write(`[remote ${remote.url}]\n`);
|
|
241
|
+
const termWidth = process.stdout.columns ?? 120;
|
|
242
|
+
const widths = {
|
|
243
|
+
pid: Math.max(3, ...records.map((r) => String(r.pid).length)),
|
|
244
|
+
cli: Math.max(3, ...records.map((r) => String(r.cli).length)),
|
|
245
|
+
status: Math.max(6, ...records.map((r) => String(r.status).length)),
|
|
246
|
+
cwd: Math.max(3, ...records.map((r) => String(r.cwd).length))
|
|
247
|
+
};
|
|
248
|
+
const fixedWidth = widths.pid + widths.cli + widths.status + widths.cwd + 8;
|
|
249
|
+
const promptBudget = Math.max(20, termWidth - fixedWidth - 1);
|
|
250
|
+
const header = [
|
|
251
|
+
"PID".padEnd(widths.pid),
|
|
252
|
+
"CLI".padEnd(widths.cli),
|
|
253
|
+
"STATUS".padEnd(widths.status),
|
|
254
|
+
"CWD".padEnd(widths.cwd),
|
|
255
|
+
"PROMPT"
|
|
256
|
+
].join(" ") + "\n";
|
|
257
|
+
process.stdout.write(header);
|
|
258
|
+
for (const r of records) {
|
|
259
|
+
const label = r.prompt ? truncate(`→ ${r.prompt}`, promptBudget) : "";
|
|
260
|
+
process.stdout.write([
|
|
261
|
+
String(r.pid).padEnd(widths.pid),
|
|
262
|
+
String(r.cli).padEnd(widths.cli),
|
|
263
|
+
String(r.status).padEnd(widths.status),
|
|
264
|
+
String(r.cwd).padEnd(widths.cwd),
|
|
265
|
+
label
|
|
266
|
+
].join(" ") + "\n");
|
|
267
|
+
}
|
|
268
|
+
return 0;
|
|
269
|
+
}
|
|
270
|
+
async function runRemoteRead(remote, mode, follow, n, reconnectTimeoutMs = 12e4) {
|
|
271
|
+
const keyword = remote.keyword ?? "";
|
|
272
|
+
if (!keyword) {
|
|
273
|
+
process.stderr.write("remote tail/cat/head requires a keyword (e.g. token@host:port:keyword)\n");
|
|
274
|
+
return 1;
|
|
275
|
+
}
|
|
276
|
+
if (mode === "tail" && follow) {
|
|
277
|
+
const ac = new AbortController();
|
|
278
|
+
process.on("SIGINT", () => ac.abort());
|
|
279
|
+
const deadline = Date.now() + reconnectTimeoutMs;
|
|
280
|
+
let delay = 1e3;
|
|
281
|
+
let attempt = 0;
|
|
282
|
+
process.stderr.write(`[remote ${remote.url} ${keyword}]\nfollowing... (Ctrl-C to stop, timeout: ${Math.round(reconnectTimeoutMs / 1e3)}s)\n`);
|
|
283
|
+
while (!ac.signal.aborted) try {
|
|
284
|
+
const res = await fetch(`${remote.url}/api/tail/${encodeURIComponent(keyword)}`, {
|
|
285
|
+
headers: {
|
|
286
|
+
Authorization: `Bearer ${remote.token}`,
|
|
287
|
+
Accept: "text/event-stream"
|
|
288
|
+
},
|
|
289
|
+
signal: ac.signal
|
|
290
|
+
});
|
|
291
|
+
if (!res.ok) {
|
|
292
|
+
if (res.status === 401 || res.status === 404) {
|
|
293
|
+
process.stderr.write(`remote error ${res.status}: ${await res.text()}\n`);
|
|
294
|
+
return 1;
|
|
295
|
+
}
|
|
296
|
+
throw new Error(`HTTP ${res.status}`);
|
|
297
|
+
}
|
|
298
|
+
if (attempt > 0) process.stderr.write("remote: reconnected\n");
|
|
299
|
+
delay = 1e3;
|
|
300
|
+
const reader = res.body.getReader();
|
|
301
|
+
const dec = new TextDecoder();
|
|
302
|
+
let buf = "";
|
|
303
|
+
while (true) {
|
|
304
|
+
const { done, value } = await reader.read();
|
|
305
|
+
if (done) break;
|
|
306
|
+
buf += dec.decode(value, { stream: true });
|
|
307
|
+
const lines = buf.split("\n");
|
|
308
|
+
buf = lines.pop() ?? "";
|
|
309
|
+
for (const line of lines) {
|
|
310
|
+
if (!line.startsWith("data: ")) continue;
|
|
311
|
+
try {
|
|
312
|
+
const text = JSON.parse(line.slice(6));
|
|
313
|
+
process.stdout.write(text);
|
|
314
|
+
if (!text.endsWith("\n")) process.stdout.write("\n");
|
|
315
|
+
} catch {}
|
|
316
|
+
}
|
|
317
|
+
}
|
|
318
|
+
break;
|
|
319
|
+
} catch (e) {
|
|
320
|
+
if (e.name === "AbortError" || ac.signal.aborted) return 0;
|
|
321
|
+
if (Date.now() >= deadline) {
|
|
322
|
+
process.stderr.write(`remote: timeout after ${Math.round(reconnectTimeoutMs / 1e3)}s, giving up\n`);
|
|
323
|
+
return 1;
|
|
324
|
+
}
|
|
325
|
+
process.stderr.write(`remote: disconnected (${e.message}), retrying in ${delay / 1e3}s…\n`);
|
|
326
|
+
await new Promise((resolve, reject) => {
|
|
327
|
+
const t = setTimeout(resolve, delay);
|
|
328
|
+
ac.signal.addEventListener("abort", () => {
|
|
329
|
+
clearTimeout(t);
|
|
330
|
+
reject(/* @__PURE__ */ new Error("abort"));
|
|
331
|
+
});
|
|
332
|
+
}).catch(() => {});
|
|
333
|
+
if (ac.signal.aborted) return 0;
|
|
334
|
+
delay = Math.min(delay * 2, 3e4);
|
|
335
|
+
attempt++;
|
|
336
|
+
}
|
|
337
|
+
return 0;
|
|
338
|
+
}
|
|
339
|
+
const params = new URLSearchParams({
|
|
340
|
+
mode,
|
|
341
|
+
n: String(n)
|
|
342
|
+
});
|
|
343
|
+
const res = await remoteGet(remote, `/api/read/${encodeURIComponent(keyword)}?${params}`);
|
|
344
|
+
if (!res.ok) {
|
|
345
|
+
process.stderr.write(`remote error ${res.status}: ${await res.text()}\n`);
|
|
346
|
+
return 1;
|
|
347
|
+
}
|
|
348
|
+
const text = await res.text();
|
|
349
|
+
process.stderr.write(`[remote ${remote.url} ${keyword}]\n`);
|
|
350
|
+
process.stdout.write(text);
|
|
351
|
+
if (!text.endsWith("\n")) process.stdout.write("\n");
|
|
352
|
+
return 0;
|
|
353
|
+
}
|
|
354
|
+
async function runRemoteSend(remote, msg, code) {
|
|
355
|
+
const keyword = remote.keyword ?? "";
|
|
356
|
+
if (!keyword) {
|
|
357
|
+
process.stderr.write("remote send requires a keyword (e.g. token@host:port:keyword)\n");
|
|
358
|
+
return 1;
|
|
359
|
+
}
|
|
360
|
+
const res = await remotePost(remote, "/api/send", {
|
|
361
|
+
keyword,
|
|
362
|
+
msg,
|
|
363
|
+
code
|
|
364
|
+
});
|
|
365
|
+
if (!res.ok) {
|
|
366
|
+
process.stderr.write(`remote error ${res.status}: ${await res.text()}\n`);
|
|
367
|
+
return 1;
|
|
368
|
+
}
|
|
369
|
+
const data = await res.json();
|
|
370
|
+
process.stdout.write(`sent to remote pid ${data.pid} (${remote.url} ${keyword})\n`);
|
|
371
|
+
return 0;
|
|
372
|
+
}
|
|
373
|
+
async function runRemoteStatus(remote) {
|
|
374
|
+
const keyword = remote.keyword ?? "";
|
|
375
|
+
if (!keyword) {
|
|
376
|
+
process.stderr.write("remote status requires a keyword (e.g. token@host:port:keyword)\n");
|
|
377
|
+
return 1;
|
|
378
|
+
}
|
|
379
|
+
const res = await remoteGet(remote, `/api/status/${encodeURIComponent(keyword)}`);
|
|
380
|
+
if (!res.ok) {
|
|
381
|
+
process.stderr.write(`remote error ${res.status}: ${await res.text()}\n`);
|
|
382
|
+
return 1;
|
|
383
|
+
}
|
|
384
|
+
process.stdout.write(JSON.stringify(await res.json(), null, 2) + "\n");
|
|
385
|
+
return 0;
|
|
386
|
+
}
|
|
387
|
+
async function fetchRemoteRecordsRaw(url, token, opts) {
|
|
388
|
+
const params = new URLSearchParams();
|
|
389
|
+
if (opts.all) params.set("all", "1");
|
|
390
|
+
if (opts.active) params.set("active", "1");
|
|
391
|
+
if (opts.keyword) params.set("keyword", opts.keyword);
|
|
392
|
+
try {
|
|
393
|
+
const res = await fetch(`${url}/api/ls?${params}`, {
|
|
394
|
+
headers: { Authorization: `Bearer ${token}` },
|
|
395
|
+
signal: AbortSignal.timeout(5e3)
|
|
396
|
+
});
|
|
397
|
+
if (!res.ok) return [];
|
|
398
|
+
return await res.json();
|
|
399
|
+
} catch {
|
|
400
|
+
return [];
|
|
401
|
+
}
|
|
402
|
+
}
|
|
403
|
+
async function runAllRemotesLs(opts) {
|
|
404
|
+
const remotes = await readRemotes();
|
|
405
|
+
const localOpts = {
|
|
406
|
+
all: opts.all,
|
|
407
|
+
active: opts.active,
|
|
408
|
+
json: true,
|
|
409
|
+
latest: false,
|
|
410
|
+
cwdScope: null
|
|
411
|
+
};
|
|
412
|
+
const [localResult, ...remoteResults] = await Promise.allSettled([listRecords(opts.keyword, localOpts).then((recs) => ({
|
|
413
|
+
host: "local",
|
|
414
|
+
records: recs
|
|
415
|
+
})), ...Array.from(remotes.entries()).map(([alias, cfg]) => fetchRemoteRecordsRaw(cfg.url, cfg.token, opts).then((records) => ({
|
|
416
|
+
host: alias,
|
|
417
|
+
records
|
|
418
|
+
})))]);
|
|
419
|
+
const rows = [];
|
|
420
|
+
if (localResult.status === "fulfilled") for (const r of localResult.value.records) rows.push({
|
|
421
|
+
host: "local",
|
|
422
|
+
rec: r
|
|
423
|
+
});
|
|
424
|
+
for (const res of remoteResults) if (res.status === "fulfilled") for (const r of res.value.records) rows.push({
|
|
425
|
+
host: res.value.host,
|
|
426
|
+
rec: r
|
|
427
|
+
});
|
|
428
|
+
if (rows.length === 0) {
|
|
429
|
+
process.stderr.write("no running agents\n");
|
|
430
|
+
return 0;
|
|
431
|
+
}
|
|
432
|
+
const termWidth = process.stdout.columns ?? 120;
|
|
433
|
+
const hostW = Math.max(4, ...rows.map((r) => r.host.length));
|
|
434
|
+
const pidW = Math.max(3, ...rows.map((r) => String(r.rec.pid).length));
|
|
435
|
+
const cliW = Math.max(3, ...rows.map((r) => String(r.rec.cli).length));
|
|
436
|
+
const statusW = Math.max(6, ...rows.map((r) => String(r.rec.status).length));
|
|
437
|
+
const cwdW = Math.max(3, ...rows.map((r) => shortenPath(String(r.rec.cwd)).length));
|
|
438
|
+
const promptBudget = Math.max(20, termWidth - hostW - pidW - cliW - statusW - cwdW - 10 - 1);
|
|
439
|
+
process.stdout.write([
|
|
440
|
+
"HOST".padEnd(hostW),
|
|
441
|
+
"PID".padEnd(pidW),
|
|
442
|
+
"CLI".padEnd(cliW),
|
|
443
|
+
"STATUS".padEnd(statusW),
|
|
444
|
+
"CWD".padEnd(cwdW),
|
|
445
|
+
"PROMPT"
|
|
446
|
+
].join(" ") + "\n");
|
|
447
|
+
for (const { host, rec } of rows) {
|
|
448
|
+
const label = rec.prompt ? truncate(`→ ${rec.prompt}`, promptBudget) : "";
|
|
449
|
+
process.stdout.write([
|
|
450
|
+
host.padEnd(hostW),
|
|
451
|
+
String(rec.pid).padEnd(pidW),
|
|
452
|
+
String(rec.cli).padEnd(cliW),
|
|
453
|
+
String(rec.status).padEnd(statusW),
|
|
454
|
+
shortenPath(String(rec.cwd)).padEnd(cwdW),
|
|
455
|
+
label
|
|
456
|
+
].join(" ") + "\n");
|
|
457
|
+
}
|
|
458
|
+
return 0;
|
|
459
|
+
}
|
|
202
460
|
async function cmdLs(rest) {
|
|
203
461
|
const y = yargs(rest).usage("Usage: ay ls [keyword] [options]\n ay list [keyword] [options]\n ay ps [keyword] [options]\n\nList running agents. Optionally filter by keyword (pid, cwd substring, or prompt substring).").option("all", {
|
|
204
462
|
type: "boolean",
|
|
@@ -219,18 +477,34 @@ async function cmdLs(rest) {
|
|
|
219
477
|
}).option("cwd", {
|
|
220
478
|
type: "string",
|
|
221
479
|
description: "Restrict to agents whose cwd starts with dir"
|
|
480
|
+
}).option("all-remotes", {
|
|
481
|
+
type: "boolean",
|
|
482
|
+
default: false,
|
|
483
|
+
description: "Include agents from all configured remotes (remotes.yaml)"
|
|
222
484
|
}).option("help", {
|
|
223
485
|
alias: "h",
|
|
224
486
|
type: "boolean",
|
|
225
487
|
default: false,
|
|
226
488
|
description: "Show this help"
|
|
227
|
-
}).example("ay ls", "list running agents").example("ay ls --all", "include exited agents").example("ay ls --json", "machine-readable output").example("ay ls symval", "filter by cwd/prompt keyword").help(false).version(false).exitProcess(false);
|
|
489
|
+
}).example("ay ls", "list running agents").example("ay ls --all-remotes", "include all configured remote machines").example("ay ls --all", "include exited agents").example("ay ls --json", "machine-readable output").example("ay ls symval", "filter by cwd/prompt keyword").help(false).version(false).exitProcess(false);
|
|
228
490
|
const argv = await y.parseAsync();
|
|
229
491
|
if (argv.help || argv.h) {
|
|
230
492
|
process.stdout.write(await y.getHelp() + "\n");
|
|
231
493
|
return 0;
|
|
232
494
|
}
|
|
495
|
+
if (argv["all-remotes"]) return runAllRemotesLs({
|
|
496
|
+
all: argv.all,
|
|
497
|
+
active: argv.active,
|
|
498
|
+
keyword: argv._[0] !== void 0 ? String(argv._[0]) : void 0
|
|
499
|
+
});
|
|
233
500
|
const keyword = argv._[0] !== void 0 ? String(argv._[0]) : void 0;
|
|
501
|
+
if (keyword) {
|
|
502
|
+
const remote = await resolveRemoteSpec(keyword);
|
|
503
|
+
if (remote) return runRemoteLs(remote, {
|
|
504
|
+
all: argv.all,
|
|
505
|
+
active: argv.active
|
|
506
|
+
});
|
|
507
|
+
}
|
|
234
508
|
const opts = {
|
|
235
509
|
all: argv.all,
|
|
236
510
|
active: argv.active,
|
|
@@ -360,6 +634,10 @@ async function cmdRead(rest, { mode }) {
|
|
|
360
634
|
}).option("cwd", {
|
|
361
635
|
type: "string",
|
|
362
636
|
description: "Restrict to agents under this dir"
|
|
637
|
+
}).option("reconnect-timeout", {
|
|
638
|
+
type: "number",
|
|
639
|
+
default: 120,
|
|
640
|
+
description: "Seconds before giving up reconnecting remote SSE (default: 120)"
|
|
363
641
|
}).help(false).version(false).exitProcess(false).parseAsync();
|
|
364
642
|
const opts = {
|
|
365
643
|
all: argv.all,
|
|
@@ -369,6 +647,13 @@ async function cmdRead(rest, { mode }) {
|
|
|
369
647
|
cwdScope: typeof argv.cwd === "string" ? path.resolve(argv.cwd) : null
|
|
370
648
|
};
|
|
371
649
|
const keyword = argv._[0] !== void 0 ? String(argv._[0]) : void 0;
|
|
650
|
+
if (keyword) {
|
|
651
|
+
const remote = await resolveRemoteSpec(keyword);
|
|
652
|
+
const nFlag2 = argv.n;
|
|
653
|
+
const n2 = nFlag2 !== void 0 && Number.isFinite(nFlag2) && nFlag2 > 0 ? Math.floor(nFlag2) : mode === "cat" ? 0 : 96;
|
|
654
|
+
const reconnectTimeoutMs = (argv["reconnect-timeout"] ?? 120) * 1e3;
|
|
655
|
+
if (remote) return runRemoteRead(remote, mode, argv.follow, n2, reconnectTimeoutMs);
|
|
656
|
+
}
|
|
372
657
|
const follow = argv.follow;
|
|
373
658
|
const nFlag = argv.n;
|
|
374
659
|
const n = nFlag !== void 0 && Number.isFinite(nFlag) && nFlag > 0 ? Math.floor(nFlag) : mode === "cat" ? 0 : 96;
|
|
@@ -555,7 +840,12 @@ async function cmdSend(rest) {
|
|
|
555
840
|
const keyword = argv._[0] !== void 0 ? String(argv._[0]) : void 0;
|
|
556
841
|
const rawMessage = argv._.slice(1).map(String).join(" ");
|
|
557
842
|
if (!keyword) throw new Error("usage: ay send <keyword> <msg|-> [--code=enter|esc|ctrl-c|ctrl-y|tab|none]");
|
|
558
|
-
const
|
|
843
|
+
const codeName = argv.code.toLowerCase();
|
|
844
|
+
{
|
|
845
|
+
const remote = await resolveRemoteSpec(keyword);
|
|
846
|
+
if (remote) return runRemoteSend(remote, rawMessage, codeName);
|
|
847
|
+
}
|
|
848
|
+
const trailing = controlCodeFromName(codeName);
|
|
559
849
|
const record = await resolveOne(keyword, opts);
|
|
560
850
|
const fifoPath = record.fifo_file;
|
|
561
851
|
if (!fifoPath) throw new Error(`pid ${record.pid}: no fifo_file recorded — agent was not started with --stdpush (or was spawned by Rust which doesn't yet support FIFO IPC; see ROADMAP item 10)`);
|
|
@@ -743,6 +1033,10 @@ async function cmdStatus(rest) {
|
|
|
743
1033
|
};
|
|
744
1034
|
const keyword = argv._[0] !== void 0 ? String(argv._[0]) : void 0;
|
|
745
1035
|
if (!keyword) throw new Error("usage: ay status <keyword> [--watch] [--interval=N]");
|
|
1036
|
+
{
|
|
1037
|
+
const remote = await resolveRemoteSpec(keyword);
|
|
1038
|
+
if (remote) return runRemoteStatus(remote);
|
|
1039
|
+
}
|
|
746
1040
|
const watch = argv.watch;
|
|
747
1041
|
const intervalFlag = argv.interval;
|
|
748
1042
|
const intervalMs = Math.max(500, (Number.isFinite(intervalFlag) ? intervalFlag : 2) * 1e3);
|
|
@@ -783,5 +1077,5 @@ async function cmdStatus(rest) {
|
|
|
783
1077
|
}
|
|
784
1078
|
|
|
785
1079
|
//#endregion
|
|
786
|
-
export {
|
|
787
|
-
//# sourceMappingURL=subcommands-
|
|
1080
|
+
export { matchKeyword as a, resolveOne as c, writeToIpc as d, listRecords as i, runSubcommand as l, isPidAlive as n, readNotes as o, isSubcommand as r, renderRawLog as s, controlCodeFromName as t, snapshotStatus as u };
|
|
1081
|
+
//# sourceMappingURL=subcommands-BpGEGOQM.js.map
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { n as logger, t as addTransport } from "./logger-B9h0djqx.js";
|
|
2
|
-
import { r as getInstalledPackage } from "./versionChecker-
|
|
2
|
+
import { r as getInstalledPackage } from "./versionChecker-BCrJk4Zj.js";
|
|
3
3
|
import { i as shouldUseLock, r as releaseLock, t as acquireLock } from "./runningLock-C22d9SRJ.js";
|
|
4
4
|
import { t as PidStore } from "./pidStore-C1JXxoPi.js";
|
|
5
5
|
import { r as readGlobalPids } from "./globalPidIndex-Cr-g75QF.js";
|
|
@@ -1693,4 +1693,4 @@ function sleep(ms) {
|
|
|
1693
1693
|
|
|
1694
1694
|
//#endregion
|
|
1695
1695
|
export { removeControlCharacters as a, AgentContext as i, agentYes as n, config as r, CLIS_CONFIG as t };
|
|
1696
|
-
//# sourceMappingURL=ts-
|
|
1696
|
+
//# sourceMappingURL=ts-DWuvdSWr.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.
|
|
10
|
+
var version = "1.86.0";
|
|
11
11
|
|
|
12
12
|
//#endregion
|
|
13
13
|
//#region ts/versionChecker.ts
|
|
@@ -221,4 +221,4 @@ async function displayVersion() {
|
|
|
221
221
|
|
|
222
222
|
//#endregion
|
|
223
223
|
export { versionString as i, displayVersion as n, getInstalledPackage as r, checkAndAutoUpdate as t };
|
|
224
|
-
//# sourceMappingURL=versionChecker-
|
|
224
|
+
//# sourceMappingURL=versionChecker-BCrJk4Zj.js.map
|
package/package.json
CHANGED
package/ts/remotes.ts
ADDED
|
@@ -0,0 +1,161 @@
|
|
|
1
|
+
import { mkdir, readFile, writeFile } from "fs/promises";
|
|
2
|
+
import { homedir } from "os";
|
|
3
|
+
import path from "path";
|
|
4
|
+
import yaml from "yaml";
|
|
5
|
+
|
|
6
|
+
function remotesPath(): string {
|
|
7
|
+
const dir = process.env.AGENT_YES_HOME ?? path.join(homedir(), ".agent-yes");
|
|
8
|
+
return path.join(dir, "remotes.yaml");
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
export interface RemoteConfig {
|
|
12
|
+
url: string; // e.g. "http://192.168.1.5:7432"
|
|
13
|
+
token: string;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
export interface ResolvedRemote {
|
|
17
|
+
url: string;
|
|
18
|
+
token: string;
|
|
19
|
+
keyword?: string;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
export async function readRemotes(): Promise<Map<string, RemoteConfig>> {
|
|
23
|
+
let raw: string;
|
|
24
|
+
try {
|
|
25
|
+
raw = await readFile(remotesPath(), "utf-8");
|
|
26
|
+
} catch {
|
|
27
|
+
return new Map();
|
|
28
|
+
}
|
|
29
|
+
const doc = yaml.parse(raw) ?? {};
|
|
30
|
+
const remotes = doc.remotes ?? {};
|
|
31
|
+
const map = new Map<string, RemoteConfig>();
|
|
32
|
+
for (const [alias, cfg] of Object.entries(remotes)) {
|
|
33
|
+
if (cfg && typeof (cfg as any).url === "string" && typeof (cfg as any).token === "string") {
|
|
34
|
+
map.set(alias, { url: (cfg as any).url, token: (cfg as any).token });
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
return map;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
export async function writeRemoteAlias(alias: string, config: RemoteConfig): Promise<void> {
|
|
41
|
+
const remotes = await readRemotes();
|
|
42
|
+
remotes.set(alias, config);
|
|
43
|
+
const doc: Record<string, any> = {};
|
|
44
|
+
for (const [k, v] of remotes) doc[k] = v;
|
|
45
|
+
await mkdir(path.dirname(remotesPath()), { recursive: true });
|
|
46
|
+
await writeFile(remotesPath(), yaml.stringify({ remotes: doc }));
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
export async function deleteRemoteAlias(alias: string): Promise<void> {
|
|
50
|
+
const remotes = await readRemotes();
|
|
51
|
+
remotes.delete(alias);
|
|
52
|
+
const doc: Record<string, any> = {};
|
|
53
|
+
for (const [k, v] of remotes) doc[k] = v;
|
|
54
|
+
await writeFile(remotesPath(), yaml.stringify({ remotes: doc }));
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
/** Parse token@host:port[:keyword] — the `@` is a hard signal this is remote. */
|
|
58
|
+
export function parseDirectRemoteSpec(
|
|
59
|
+
spec: string,
|
|
60
|
+
): { token: string; host: string; port: number; keyword?: string; baseUrl: string } | null {
|
|
61
|
+
const m = /^([^@]+)@([^:@]+):(\d+)(?::(.+))?$/.exec(spec);
|
|
62
|
+
if (!m) return null;
|
|
63
|
+
const host = m[2]!;
|
|
64
|
+
const port = parseInt(m[3]!, 10);
|
|
65
|
+
return {
|
|
66
|
+
token: m[1]!,
|
|
67
|
+
host,
|
|
68
|
+
port,
|
|
69
|
+
keyword: m[4] || undefined,
|
|
70
|
+
baseUrl: `http://${host}:${port}`,
|
|
71
|
+
};
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
/**
|
|
75
|
+
* Resolve a spec to connection details.
|
|
76
|
+
* Accepts:
|
|
77
|
+
* token@host:port[:keyword] — direct
|
|
78
|
+
* alias[:keyword] — looked up in ~/.agent-yes/remotes.yaml
|
|
79
|
+
* Returns null if the spec doesn't match any remote.
|
|
80
|
+
*/
|
|
81
|
+
export async function resolveRemoteSpec(spec: string): Promise<ResolvedRemote | null> {
|
|
82
|
+
const direct = parseDirectRemoteSpec(spec);
|
|
83
|
+
if (direct) {
|
|
84
|
+
return { url: direct.baseUrl, token: direct.token, keyword: direct.keyword };
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
// alias[:keyword]
|
|
88
|
+
const colonIdx = spec.indexOf(":");
|
|
89
|
+
const alias = colonIdx >= 0 ? spec.slice(0, colonIdx) : spec;
|
|
90
|
+
const keyword = colonIdx >= 0 ? spec.slice(colonIdx + 1) || undefined : undefined;
|
|
91
|
+
|
|
92
|
+
const remotes = await readRemotes();
|
|
93
|
+
const cfg = remotes.get(alias);
|
|
94
|
+
if (!cfg) return null;
|
|
95
|
+
return { url: cfg.url, token: cfg.token, keyword };
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
// ---------------------------------------------------------------------------
|
|
99
|
+
// ay remote subcommand
|
|
100
|
+
// ---------------------------------------------------------------------------
|
|
101
|
+
|
|
102
|
+
export async function cmdRemote(rest: string[]): Promise<number> {
|
|
103
|
+
const sub = rest[0];
|
|
104
|
+
|
|
105
|
+
if (!sub || sub === "ls" || sub === "list") {
|
|
106
|
+
const remotes = await readRemotes();
|
|
107
|
+
if (remotes.size === 0) {
|
|
108
|
+
process.stdout.write("no remotes configured\n");
|
|
109
|
+
process.stderr.write(
|
|
110
|
+
"\n" +
|
|
111
|
+
" ay remote add <alias> <url> <token> # add a remote\n" +
|
|
112
|
+
" ay serve # start server (prints token)\n",
|
|
113
|
+
);
|
|
114
|
+
return 0;
|
|
115
|
+
}
|
|
116
|
+
for (const [alias, cfg] of remotes) {
|
|
117
|
+
const preview = cfg.token.length > 8 ? cfg.token.slice(0, 8) + "..." : cfg.token;
|
|
118
|
+
process.stdout.write(`${alias}\t${cfg.url}\ttoken:${preview}\n`);
|
|
119
|
+
}
|
|
120
|
+
return 0;
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
if (sub === "add") {
|
|
124
|
+
const [, alias, url, token] = rest;
|
|
125
|
+
if (!alias || !url || !token) {
|
|
126
|
+
process.stderr.write("usage: ay remote add <alias> <url> <token>\n");
|
|
127
|
+
process.stderr.write(
|
|
128
|
+
" example: ay remote add work-mac http://192.168.1.5:7432 mytoken123\n",
|
|
129
|
+
);
|
|
130
|
+
return 1;
|
|
131
|
+
}
|
|
132
|
+
await writeRemoteAlias(alias, { url, token });
|
|
133
|
+
process.stdout.write(`remote '${alias}' added → ${url}\n`);
|
|
134
|
+
process.stderr.write(`\n ay ls ${alias} # list agents on ${alias}\n`);
|
|
135
|
+
return 0;
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
if (sub === "rm" || sub === "remove" || sub === "delete") {
|
|
139
|
+
const alias = rest[1];
|
|
140
|
+
if (!alias) {
|
|
141
|
+
process.stderr.write("usage: ay remote rm <alias>\n");
|
|
142
|
+
return 1;
|
|
143
|
+
}
|
|
144
|
+
const remotes = await readRemotes();
|
|
145
|
+
if (!remotes.has(alias)) {
|
|
146
|
+
process.stderr.write(`remote '${alias}' not found\n`);
|
|
147
|
+
return 1;
|
|
148
|
+
}
|
|
149
|
+
await deleteRemoteAlias(alias);
|
|
150
|
+
process.stdout.write(`remote '${alias}' removed\n`);
|
|
151
|
+
return 0;
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
process.stderr.write(`ay remote: unknown subcommand '${sub}'\n`);
|
|
155
|
+
process.stderr.write(
|
|
156
|
+
" ay remote ls # list configured remotes\n" +
|
|
157
|
+
" ay remote add <alias> <url> <token> # add a remote\n" +
|
|
158
|
+
" ay remote rm <alias> # remove a remote\n",
|
|
159
|
+
);
|
|
160
|
+
return 1;
|
|
161
|
+
}
|