agent-yes 1.194.0 → 1.196.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-Ca2ffDRy.js +8 -0
- package/dist/{SUPPORTED_CLIS--WH2XfM2.js → SUPPORTED_CLIS-CxLCQtAU.js} +2 -2
- package/dist/{agentShare-BEXN8bNT.js → agentShare-Bi95Xy0S.js} +2 -2
- package/dist/cli.js +4 -4
- package/dist/index.js +2 -2
- package/dist/{notifyDaemon-Deisyrbn.js → notifyDaemon-BdOeFIVl.js} +2 -2
- package/dist/{rustBinary-cTIMKGQp.js → rustBinary-D_ifX2Vd.js} +2 -2
- package/dist/{schedule-MQZjDaY6.js → schedule-rvMgc0tA.js} +4 -4
- package/dist/{serve-hA23xPpg.js → serve-D0-LoTfw.js} +43 -13
- package/dist/{setup-C6grPf1R.js → setup-BC1VjTOf.js} +2 -2
- package/dist/subcommands-Cz8xpc5X.js +9 -0
- package/dist/{subcommands-Ba0V9EEH.js → subcommands-s74ViJcI.js} +305 -12
- package/dist/{ts-6JcbtJh1.js → ts-CP17kUI1.js} +2 -2
- package/dist/{versionChecker-DDNKcQRx.js → versionChecker-DTssk7cU.js} +2 -2
- package/lab/ui/index.html +292 -2
- package/lab/ui/room-client.js +544 -388
- package/lab/ui/sw.js +71 -19
- package/package.json +1 -1
- package/ts/messageLog.spec.ts +145 -0
- package/ts/messageLog.ts +147 -0
- package/ts/serve.ts +55 -8
- package/ts/subcommands.ts +270 -5
- package/dist/SUPPORTED_CLIS-NfXUfiWY.js +0 -8
- package/dist/subcommands-LP1Z8g-h.js +0 -9
|
@@ -161,6 +161,94 @@ function parseTaskCounts(lines) {
|
|
|
161
161
|
return best;
|
|
162
162
|
}
|
|
163
163
|
|
|
164
|
+
//#endregion
|
|
165
|
+
//#region ts/messageLog.ts
|
|
166
|
+
/**
|
|
167
|
+
* Durable inter-agent message log.
|
|
168
|
+
*
|
|
169
|
+
* Every `ay send` that carries a real body is recorded twice — from the two
|
|
170
|
+
* ends' points of view — as append-only JSONL colocated with each agent's
|
|
171
|
+
* project dir (the same `<cwd>/.agent-yes/` convention the session logs use):
|
|
172
|
+
*
|
|
173
|
+
* - the SENDER's `<from.cwd>/.agent-yes/outbox.jsonl`
|
|
174
|
+
* - the RECIPIENT's `<to.cwd>/.agent-yes/inbox.jsonl`
|
|
175
|
+
*
|
|
176
|
+
* A single cwd may host several agents, so records carry the stable `agent_id`
|
|
177
|
+
* (falling back to `pid`) of each end; `ay msgs` filters a mailbox down to one
|
|
178
|
+
* agent by that key. Reading needs no lock (last line wins isn't relevant — a
|
|
179
|
+
* message log keeps every entry); writing is best-effort and never blocks or
|
|
180
|
+
* fails a send.
|
|
181
|
+
*/
|
|
182
|
+
/** Keep at most this many lines per mailbox; older entries are compacted away. */
|
|
183
|
+
const MAILBOX_MAX_LINES = 2e3;
|
|
184
|
+
/** Path to a cwd's mailbox file (`<cwd>/.agent-yes/{inbox,outbox}.jsonl`). */
|
|
185
|
+
function mailboxPath(cwd, box) {
|
|
186
|
+
return path.join(cwd, ".agent-yes", `${box}.jsonl`);
|
|
187
|
+
}
|
|
188
|
+
/** Whether a mail party is the agent identified by (agentId, pid). Prefers the
|
|
189
|
+
* stable agent_id (survives restart); falls back to pid for legacy records. */
|
|
190
|
+
function partyMatches(party, agentId, pid) {
|
|
191
|
+
if (!party) return false;
|
|
192
|
+
if (agentId && party.agent_id && party.agent_id === agentId) return true;
|
|
193
|
+
if (typeof pid === "number" && party.pid === pid) return true;
|
|
194
|
+
return false;
|
|
195
|
+
}
|
|
196
|
+
async function appendCapped(filePath, record) {
|
|
197
|
+
await mkdir(path.dirname(filePath), { recursive: true });
|
|
198
|
+
await appendFile(filePath, JSON.stringify(record) + "\n");
|
|
199
|
+
const lines = (await readFile(filePath, "utf-8").catch(() => "")).split("\n").filter((l) => l.trim());
|
|
200
|
+
if (lines.length > MAILBOX_MAX_LINES) await writeFile(filePath, lines.slice(lines.length - MAILBOX_MAX_LINES).join("\n") + "\n");
|
|
201
|
+
}
|
|
202
|
+
/**
|
|
203
|
+
* Record the SENDER's view in its outbox. Best-effort — a filesystem error is
|
|
204
|
+
* logged and swallowed so persistence never breaks a send. The outbox lives
|
|
205
|
+
* under `from.cwd`; a human sender (from === null) writes under `process.cwd()`.
|
|
206
|
+
*/
|
|
207
|
+
async function recordOutbox(record) {
|
|
208
|
+
const outCwd = record.from?.cwd ?? process.cwd();
|
|
209
|
+
try {
|
|
210
|
+
await appendCapped(mailboxPath(outCwd, "outbox"), record);
|
|
211
|
+
} catch (err) {
|
|
212
|
+
logger.debug(`[messageLog] outbox append failed: ${err}`);
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
/** Record the RECIPIENT's view in its inbox (under `to.cwd`). Best-effort. */
|
|
216
|
+
async function recordInbox(record) {
|
|
217
|
+
try {
|
|
218
|
+
await appendCapped(mailboxPath(record.to.cwd, "inbox"), record);
|
|
219
|
+
} catch (err) {
|
|
220
|
+
logger.debug(`[messageLog] inbox append failed: ${err}`);
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
/**
|
|
224
|
+
* Record a same-host message in both mailboxes — the sender's outbox and the
|
|
225
|
+
* recipient's inbox both live on this machine. For a message that crossed the
|
|
226
|
+
* wire, each end calls `recordOutbox`/`recordInbox` on its own host instead.
|
|
227
|
+
*/
|
|
228
|
+
async function recordMessage(record) {
|
|
229
|
+
await recordOutbox(record);
|
|
230
|
+
await recordInbox(record);
|
|
231
|
+
}
|
|
232
|
+
/** Read and parse a cwd's mailbox, oldest first. Missing/corrupt lines skipped. */
|
|
233
|
+
async function readMailbox(cwd, box) {
|
|
234
|
+
let raw;
|
|
235
|
+
try {
|
|
236
|
+
raw = await readFile(mailboxPath(cwd, box), "utf-8");
|
|
237
|
+
} catch {
|
|
238
|
+
return [];
|
|
239
|
+
}
|
|
240
|
+
const out = [];
|
|
241
|
+
for (const line of raw.split("\n")) {
|
|
242
|
+
const t = line.trim();
|
|
243
|
+
if (!t) continue;
|
|
244
|
+
try {
|
|
245
|
+
const rec = JSON.parse(t);
|
|
246
|
+
if (rec && typeof rec.at === "number" && rec.to) out.push(rec);
|
|
247
|
+
} catch {}
|
|
248
|
+
}
|
|
249
|
+
return out;
|
|
250
|
+
}
|
|
251
|
+
|
|
164
252
|
//#endregion
|
|
165
253
|
//#region ts/badges.ts
|
|
166
254
|
const BADGE_DEFS = [
|
|
@@ -988,6 +1076,40 @@ async function recentReadEdges(windowMs = READ_WINDOW_MS) {
|
|
|
988
1076
|
}
|
|
989
1077
|
return out;
|
|
990
1078
|
}
|
|
1079
|
+
/**
|
|
1080
|
+
* Scan every live agent's outbox for sends within `windowMs` and return them as
|
|
1081
|
+
* directional edges (newest `at` per by→target pair wins). Bounded by the number
|
|
1082
|
+
* of distinct agent cwds — the outbox is per-cwd, so each dir is read once.
|
|
1083
|
+
*/
|
|
1084
|
+
async function recentMessageEdges(windowMs = READ_WINDOW_MS) {
|
|
1085
|
+
const now = Date.now();
|
|
1086
|
+
const records = await listRecords(void 0, {
|
|
1087
|
+
all: true,
|
|
1088
|
+
active: false,
|
|
1089
|
+
json: false,
|
|
1090
|
+
latest: false,
|
|
1091
|
+
cwdScope: null
|
|
1092
|
+
});
|
|
1093
|
+
const cwds = [...new Set(records.map((r) => r.cwd).filter(Boolean))];
|
|
1094
|
+
const best = /* @__PURE__ */ new Map();
|
|
1095
|
+
await Promise.all(cwds.map(async (cwd) => {
|
|
1096
|
+
for (const rec of await readMailbox(cwd, "outbox")) {
|
|
1097
|
+
if (now - rec.at > windowMs) continue;
|
|
1098
|
+
const by = rec.from?.pid;
|
|
1099
|
+
const target = rec.to?.pid;
|
|
1100
|
+
if (!by || !target || by === target) continue;
|
|
1101
|
+
const key = `${by}\0${target}`;
|
|
1102
|
+
const prev = best.get(key);
|
|
1103
|
+
if (!prev || rec.at > prev.at) best.set(key, {
|
|
1104
|
+
by,
|
|
1105
|
+
target,
|
|
1106
|
+
at: rec.at,
|
|
1107
|
+
kind: rec.kind
|
|
1108
|
+
});
|
|
1109
|
+
}
|
|
1110
|
+
}));
|
|
1111
|
+
return [...best.values()];
|
|
1112
|
+
}
|
|
991
1113
|
async function resolveSender() {
|
|
992
1114
|
const envPid = process.env.AGENT_YES_PID ? Number(process.env.AGENT_YES_PID) : null;
|
|
993
1115
|
if (!envPid || Number.isNaN(envPid)) return null;
|
|
@@ -1076,6 +1198,7 @@ const SUBCOMMANDS = new Set([
|
|
|
1076
1198
|
"tail",
|
|
1077
1199
|
"head",
|
|
1078
1200
|
"send",
|
|
1201
|
+
"msgs",
|
|
1079
1202
|
"key",
|
|
1080
1203
|
"select",
|
|
1081
1204
|
"spawn",
|
|
@@ -1138,6 +1261,7 @@ async function runSubcommand(argv) {
|
|
|
1138
1261
|
case "tail": return await cmdRead(rest, { mode: "tail" });
|
|
1139
1262
|
case "head": return await cmdRead(rest, { mode: "head" });
|
|
1140
1263
|
case "send": return await cmdSend(rest);
|
|
1264
|
+
case "msgs": return await cmdMsgs(rest);
|
|
1141
1265
|
case "key": return await cmdKey(rest);
|
|
1142
1266
|
case "select": return await cmdSelect(rest);
|
|
1143
1267
|
case "spawn": return await cmdSpawn(rest);
|
|
@@ -1147,15 +1271,15 @@ async function runSubcommand(argv) {
|
|
|
1147
1271
|
case "restart": return await cmdRestart(rest);
|
|
1148
1272
|
case "note": return await cmdNote(rest);
|
|
1149
1273
|
case "serve": {
|
|
1150
|
-
const { cmdServe } = await import("./serve-
|
|
1274
|
+
const { cmdServe } = await import("./serve-D0-LoTfw.js");
|
|
1151
1275
|
return cmdServe(rest);
|
|
1152
1276
|
}
|
|
1153
1277
|
case "setup": {
|
|
1154
|
-
const { cmdSetup } = await import("./setup-
|
|
1278
|
+
const { cmdSetup } = await import("./setup-BC1VjTOf.js");
|
|
1155
1279
|
return cmdSetup(rest);
|
|
1156
1280
|
}
|
|
1157
1281
|
case "schedule": {
|
|
1158
|
-
const { cmdSchedule } = await import("./schedule-
|
|
1282
|
+
const { cmdSchedule } = await import("./schedule-rvMgc0tA.js");
|
|
1159
1283
|
return cmdSchedule(rest);
|
|
1160
1284
|
}
|
|
1161
1285
|
case "remote": {
|
|
@@ -1200,7 +1324,7 @@ async function cmdHelp(managerCommands = true) {
|
|
|
1200
1324
|
const setupLine = managerCommands ? ` ay setup guided setup: pick a workspace, share to agent-yes.com\n` : ``;
|
|
1201
1325
|
const self = process.env.AGENT_YES_PID ? await resolveSender() : null;
|
|
1202
1326
|
const agentSection = self ? await buildAgentContextSection(self) : "";
|
|
1203
|
-
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\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\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 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");
|
|
1327
|
+
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\n ay msgs [keyword] [--in|--out] inter-agent message log (sent + received)\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\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 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");
|
|
1204
1328
|
return 0;
|
|
1205
1329
|
}
|
|
1206
1330
|
function matchKeyword(record, keyword) {
|
|
@@ -1480,10 +1604,18 @@ async function runRemoteSend(remote, msg, code) {
|
|
|
1480
1604
|
process.stderr.write("remote send requires a keyword (e.g. token@host:port:keyword)\n");
|
|
1481
1605
|
return 1;
|
|
1482
1606
|
}
|
|
1607
|
+
const sender = await senderContext();
|
|
1608
|
+
const from = sender.agent ? {
|
|
1609
|
+
pid: sender.agent.pid,
|
|
1610
|
+
cli: sender.agent.cli,
|
|
1611
|
+
cwd: sender.agent.cwd,
|
|
1612
|
+
agent_id: sender.agent.agent_id
|
|
1613
|
+
} : null;
|
|
1483
1614
|
const res = await remotePost(remote, "/api/send", {
|
|
1484
1615
|
keyword,
|
|
1485
1616
|
msg,
|
|
1486
|
-
code
|
|
1617
|
+
code,
|
|
1618
|
+
from
|
|
1487
1619
|
});
|
|
1488
1620
|
if (!res.ok) {
|
|
1489
1621
|
process.stderr.write(`remote error ${res.status}: ${await res.text()}\n`);
|
|
@@ -1491,6 +1623,21 @@ async function runRemoteSend(remote, msg, code) {
|
|
|
1491
1623
|
}
|
|
1492
1624
|
const data = await res.json();
|
|
1493
1625
|
process.stdout.write(`sent to remote pid ${data.pid} (${remote.url} ${keyword})\n`);
|
|
1626
|
+
if (msg && msg !== "-") await recordOutbox({
|
|
1627
|
+
at: Date.now(),
|
|
1628
|
+
from,
|
|
1629
|
+
to: {
|
|
1630
|
+
pid: data.pid,
|
|
1631
|
+
cli: data.cli ?? keyword,
|
|
1632
|
+
cwd: data.cwd ?? "",
|
|
1633
|
+
agent_id: data.agentId
|
|
1634
|
+
},
|
|
1635
|
+
body: msg,
|
|
1636
|
+
code: code.toLowerCase() === "enter" ? void 0 : code.toLowerCase(),
|
|
1637
|
+
confirmed: true,
|
|
1638
|
+
wrapped: false,
|
|
1639
|
+
remote: remote.url
|
|
1640
|
+
});
|
|
1494
1641
|
return 0;
|
|
1495
1642
|
}
|
|
1496
1643
|
/**
|
|
@@ -2929,8 +3076,9 @@ async function cmdSend(rest) {
|
|
|
2929
3076
|
const replyTarget = sender.agent?.agent_id || sender.agent?.pid;
|
|
2930
3077
|
let prefix = "";
|
|
2931
3078
|
let suffix = "";
|
|
3079
|
+
let nonce;
|
|
2932
3080
|
if (sender.agent && !isSlashCommand(body)) {
|
|
2933
|
-
|
|
3081
|
+
nonce = randomBytes$1(4).toString("hex");
|
|
2934
3082
|
prefix = `<ay-msg ${nonce} from ${sender.agent.cli} #${sender.agent.pid} @ ${shortenPath(sender.agent.cwd)} — reply: ay send ${replyTarget} "...">\n`;
|
|
2935
3083
|
suffix = `\n</ay-msg ${nonce}>`;
|
|
2936
3084
|
}
|
|
@@ -2957,6 +3105,26 @@ async function cmdSend(rest) {
|
|
|
2957
3105
|
const payload = body + trailing;
|
|
2958
3106
|
const status = confirmed ? "sent" : "sent but NOT confirmed submitted";
|
|
2959
3107
|
process.stdout.write(`${status} to pid ${record.pid} (${record.cli}): ${truncate(payload, 80)}\n`);
|
|
3108
|
+
if (body) await recordMessage({
|
|
3109
|
+
at: Date.now(),
|
|
3110
|
+
nonce,
|
|
3111
|
+
from: sender.agent ? {
|
|
3112
|
+
pid: sender.agent.pid,
|
|
3113
|
+
cli: sender.agent.cli,
|
|
3114
|
+
cwd: sender.agent.cwd,
|
|
3115
|
+
agent_id: sender.agent.agent_id
|
|
3116
|
+
} : null,
|
|
3117
|
+
to: {
|
|
3118
|
+
pid: record.pid,
|
|
3119
|
+
cli: record.cli,
|
|
3120
|
+
cwd: record.cwd,
|
|
3121
|
+
agent_id: record.agent_id
|
|
3122
|
+
},
|
|
3123
|
+
body,
|
|
3124
|
+
code: trailing === "\r" ? void 0 : codeName,
|
|
3125
|
+
confirmed,
|
|
3126
|
+
wrapped: Boolean(nonce)
|
|
3127
|
+
});
|
|
2960
3128
|
if (!confirmed) process.stderr.write(`\nwarning: couldn't confirm the CLI acted on it after ${SEND_SUBMIT_MAX_RETRIES + 1} attempt(s) — it may still be sitting unsubmitted in the prompt. Last screen:\n` + lastScreen.slice(-8).map((l) => ` ${l}`).join("\n") + "\n");
|
|
2961
3129
|
const replyHint = sender.agent ? ` ay send ${replyTarget} "..." # reply to sender\n` : "";
|
|
2962
3130
|
process.stderr.write(`\n` + replyHint + ` ay tail ${record.pid} # watch output\n ay ls # list all agents\n`);
|
|
@@ -2966,11 +3134,134 @@ async function cmdSend(rest) {
|
|
|
2966
3134
|
}
|
|
2967
3135
|
return confirmed ? 0 : 1;
|
|
2968
3136
|
}
|
|
3137
|
+
/**
|
|
3138
|
+
* `ay msgs [keyword]` — show the inter-agent messages an agent sent and
|
|
3139
|
+
* received. With no keyword it uses THIS caller's context (the agent running
|
|
3140
|
+
* `ay msgs`, or the human shell's cwd); with a keyword it resolves one agent and
|
|
3141
|
+
* reads that agent's mailboxes. Newest last, like a chat log.
|
|
3142
|
+
*/
|
|
3143
|
+
async function cmdMsgs(rest) {
|
|
3144
|
+
const argv = await yargs(rest).usage("Usage: ay msgs [keyword] [--in|--out] [-n N] [--json]").option("in", {
|
|
3145
|
+
type: "boolean",
|
|
3146
|
+
default: false,
|
|
3147
|
+
description: "Only received messages"
|
|
3148
|
+
}).option("out", {
|
|
3149
|
+
type: "boolean",
|
|
3150
|
+
default: false,
|
|
3151
|
+
description: "Only sent messages"
|
|
3152
|
+
}).option("n", {
|
|
3153
|
+
type: "number",
|
|
3154
|
+
description: "Show the last N messages (default 50)"
|
|
3155
|
+
}).option("json", {
|
|
3156
|
+
type: "boolean",
|
|
3157
|
+
default: false,
|
|
3158
|
+
description: "Emit raw JSONL records"
|
|
3159
|
+
}).option("all", {
|
|
3160
|
+
type: "boolean",
|
|
3161
|
+
default: false,
|
|
3162
|
+
description: "Include exited agents"
|
|
3163
|
+
}).option("latest", {
|
|
3164
|
+
type: "boolean",
|
|
3165
|
+
default: false,
|
|
3166
|
+
description: "Use most recent match when multiple match"
|
|
3167
|
+
}).option("cwd", {
|
|
3168
|
+
type: "string",
|
|
3169
|
+
description: "Restrict to agents under this dir"
|
|
3170
|
+
}).help(false).version(false).exitProcess(false).parseAsync();
|
|
3171
|
+
const keyword = argv._[0] !== void 0 ? String(argv._[0]) : void 0;
|
|
3172
|
+
let ownerCwd;
|
|
3173
|
+
let ownerAgentId;
|
|
3174
|
+
let ownerPid;
|
|
3175
|
+
let ownerLabel;
|
|
3176
|
+
if (keyword) {
|
|
3177
|
+
const record = await resolveOne(keyword, {
|
|
3178
|
+
all: argv.all,
|
|
3179
|
+
active: false,
|
|
3180
|
+
json: false,
|
|
3181
|
+
latest: argv.latest,
|
|
3182
|
+
cwdScope: typeof argv.cwd === "string" ? path.resolve(argv.cwd) : null
|
|
3183
|
+
});
|
|
3184
|
+
ownerCwd = record.cwd;
|
|
3185
|
+
ownerAgentId = record.agent_id;
|
|
3186
|
+
ownerPid = record.pid;
|
|
3187
|
+
ownerLabel = `pid ${record.pid} (${record.cli})`;
|
|
3188
|
+
} else {
|
|
3189
|
+
const sender = await senderContext();
|
|
3190
|
+
ownerCwd = sender.agent?.cwd ?? process.cwd();
|
|
3191
|
+
ownerAgentId = sender.agent?.agent_id;
|
|
3192
|
+
ownerPid = sender.agent?.pid;
|
|
3193
|
+
ownerLabel = sender.agent ? `pid ${sender.agent.pid} (${sender.agent.cli})` : "this shell";
|
|
3194
|
+
}
|
|
3195
|
+
const isOwner = (party) => ownerAgentId || ownerPid ? partyMatches(party, ownerAgentId, ownerPid) : party === null;
|
|
3196
|
+
const messages = [];
|
|
3197
|
+
if (!argv.in) {
|
|
3198
|
+
for (const rec of await readMailbox(ownerCwd, "outbox")) if (isOwner(rec.from)) messages.push({
|
|
3199
|
+
dir: "out",
|
|
3200
|
+
rec
|
|
3201
|
+
});
|
|
3202
|
+
}
|
|
3203
|
+
if (!argv.out) {
|
|
3204
|
+
for (const rec of await readMailbox(ownerCwd, "inbox")) if (isOwner(rec.to)) messages.push({
|
|
3205
|
+
dir: "in",
|
|
3206
|
+
rec
|
|
3207
|
+
});
|
|
3208
|
+
}
|
|
3209
|
+
messages.sort((a, b) => a.rec.at - b.rec.at);
|
|
3210
|
+
const limit = argv.n !== void 0 && Number.isFinite(argv.n) && argv.n > 0 ? Math.floor(argv.n) : 50;
|
|
3211
|
+
const shown = messages.slice(-limit);
|
|
3212
|
+
if (argv.json) {
|
|
3213
|
+
for (const { dir, rec } of shown) process.stdout.write(JSON.stringify({
|
|
3214
|
+
dir,
|
|
3215
|
+
...rec
|
|
3216
|
+
}) + "\n");
|
|
3217
|
+
return 0;
|
|
3218
|
+
}
|
|
3219
|
+
if (shown.length === 0) {
|
|
3220
|
+
process.stderr.write(`no messages for ${ownerLabel}.\n`);
|
|
3221
|
+
return 0;
|
|
3222
|
+
}
|
|
3223
|
+
for (const { dir, rec } of shown) {
|
|
3224
|
+
const when = new Date(rec.at).toLocaleTimeString();
|
|
3225
|
+
const peer = dir === "out" ? `→ ${rec.to.cli} #${rec.to.pid}` : `← ${rec.from ? `${rec.from.cli} #${rec.from.pid}` : "human"}`;
|
|
3226
|
+
const via = rec.remote ? ` (via ${rec.remote})` : "";
|
|
3227
|
+
const flag = rec.confirmed === false ? " (unconfirmed)" : "";
|
|
3228
|
+
const line = (rec.kind ? `[${rec.kind}] ` : "") + truncate(rec.body.replace(/\s+/g, " "), 100);
|
|
3229
|
+
process.stdout.write(`${when} ${peer.padEnd(20)}${via}${flag} ${line}\n`);
|
|
3230
|
+
}
|
|
3231
|
+
return 0;
|
|
3232
|
+
}
|
|
2969
3233
|
async function resolveWritableAgent(keyword, opts) {
|
|
2970
3234
|
const record = await resolveOne(keyword, opts);
|
|
2971
3235
|
if (!record.fifo_file) throw new Error(`pid ${record.pid}: no fifo_file recorded — this agent didn't register a stdin FIFO (an older agent, or one not started with --stdpush). Restarting it (ay restart ${record.pid}) re-registers one.`);
|
|
2972
3236
|
return record;
|
|
2973
3237
|
}
|
|
3238
|
+
/**
|
|
3239
|
+
* Record an `ay key` / `ay select` stdin write in the message log, same as a
|
|
3240
|
+
* text send but tagged with its `kind` (and `body` = the keystroke names /
|
|
3241
|
+
* chosen option). Key/select are local-only (no remote wire), so both mailboxes
|
|
3242
|
+
* are on this host — recordMessage writes both. Best-effort.
|
|
3243
|
+
*/
|
|
3244
|
+
async function recordKeyEvent(sender, record, kind, body) {
|
|
3245
|
+
await recordMessage({
|
|
3246
|
+
at: Date.now(),
|
|
3247
|
+
from: sender.agent ? {
|
|
3248
|
+
pid: sender.agent.pid,
|
|
3249
|
+
cli: sender.agent.cli,
|
|
3250
|
+
cwd: sender.agent.cwd,
|
|
3251
|
+
agent_id: sender.agent.agent_id
|
|
3252
|
+
} : null,
|
|
3253
|
+
to: {
|
|
3254
|
+
pid: record.pid,
|
|
3255
|
+
cli: record.cli,
|
|
3256
|
+
cwd: record.cwd,
|
|
3257
|
+
agent_id: record.agent_id
|
|
3258
|
+
},
|
|
3259
|
+
kind,
|
|
3260
|
+
body,
|
|
3261
|
+
confirmed: true,
|
|
3262
|
+
wrapped: false
|
|
3263
|
+
});
|
|
3264
|
+
}
|
|
2974
3265
|
async function cmdKey(rest) {
|
|
2975
3266
|
const argv = await yargs(rest).usage("Usage: ay key <keyword> <key...> [options]\n\nSend raw named keystrokes to a live agent's TUI — no message framing, no\nauto-Enter. Drives selection menus and other interactive prompts that a\nplain `ay send` (text + Enter) can't. Keys are paced so the CLI registers\neach as a discrete event, not a paste.\n\nKeys: up down left right enter esc tab space backspace delete home end\n pageup pagedown ctrl-c ctrl-d ctrl-y raw:0xNN\n\nExamples:\n ay key 1234 down down enter # move the menu cursor down twice, confirm\n ay key 1234 esc # dismiss a menu\n ay key 1234 raw:0x1b # a literal ESC byte").option("pace", {
|
|
2976
3267
|
type: "number",
|
|
@@ -3003,9 +3294,10 @@ async function cmdKey(rest) {
|
|
|
3003
3294
|
latest: argv.latest,
|
|
3004
3295
|
cwdScope: typeof argv.cwd === "string" ? path.resolve(argv.cwd) : null
|
|
3005
3296
|
});
|
|
3006
|
-
await enforceSendGuards(record, Boolean(argv.force) || process.env.AGENT_YES_FORCE_SEND === "1");
|
|
3297
|
+
const sender = await enforceSendGuards(record, Boolean(argv.force) || process.env.AGENT_YES_FORCE_SEND === "1");
|
|
3007
3298
|
await writeKeysPaced(record.fifo_file, byteSeqs, Math.max(0, argv.pace));
|
|
3008
3299
|
process.stdout.write(`sent to pid ${record.pid} (${record.cli}): ${keyNames.join(" ")}\n`);
|
|
3300
|
+
await recordKeyEvent(sender, record, "key", keyNames.join(" "));
|
|
3009
3301
|
return 0;
|
|
3010
3302
|
}
|
|
3011
3303
|
async function cmdSelect(rest) {
|
|
@@ -3048,7 +3340,7 @@ async function cmdSelect(rest) {
|
|
|
3048
3340
|
cwdScope: typeof argv.cwd === "string" ? path.resolve(argv.cwd) : null
|
|
3049
3341
|
});
|
|
3050
3342
|
if (!record.log_file) throw new Error(`pid ${record.pid}: no log_file recorded — can't read the menu to select from.`);
|
|
3051
|
-
await enforceSendGuards(record, Boolean(argv.force) || process.env.AGENT_YES_FORCE_SEND === "1");
|
|
3343
|
+
const sender = await enforceSendGuards(record, Boolean(argv.force) || process.env.AGENT_YES_FORCE_SEND === "1");
|
|
3052
3344
|
const menu = await extractMenu(record.log_file, record.cli);
|
|
3053
3345
|
if (!menu) throw new Error(`pid ${record.pid} (${record.cli}) is not parked on a selection menu (not needs_input).\n Check with: ay status ${record.pid}`);
|
|
3054
3346
|
if (menu.options.length > 0 && !menu.options.includes(n)) throw new Error(`option ${n} is out of range — this menu offers ${menu.options.join(", ")}.`);
|
|
@@ -3057,6 +3349,7 @@ async function cmdSelect(rest) {
|
|
|
3057
3349
|
const delta = n - menu.cursor;
|
|
3058
3350
|
const moved = delta === 0 ? "cursor already there" : `${Math.abs(delta)}× ${delta > 0 ? "down" : "up"}`;
|
|
3059
3351
|
process.stdout.write(`pid ${record.pid} (${record.cli}): selected option ${n} (${moved} + enter)\n`);
|
|
3352
|
+
await recordKeyEvent(sender, record, "select", `option ${n}`);
|
|
3060
3353
|
if (argv.wait) {
|
|
3061
3354
|
const ok = await waitForNeedsInputClear(record, Math.max(1, argv.timeout) * 1e3);
|
|
3062
3355
|
process.stdout.write(ok ? ` menu cleared — selection accepted.\n` : ` still needs_input after ${argv.timeout}s — re-check with 'ay status ${record.pid}'.\n`);
|
|
@@ -4004,7 +4297,7 @@ async function cmdNotify(rest) {
|
|
|
4004
4297
|
}
|
|
4005
4298
|
const ensure = async () => {
|
|
4006
4299
|
if (!argv["ensure-daemon"]) return;
|
|
4007
|
-
const { ensureDaemon } = await import("./notifyDaemon-
|
|
4300
|
+
const { ensureDaemon } = await import("./notifyDaemon-BdOeFIVl.js");
|
|
4008
4301
|
await ensureDaemon().catch(() => null);
|
|
4009
4302
|
};
|
|
4010
4303
|
await heartbeatWatcher(parent, selfStartedAt);
|
|
@@ -4078,7 +4371,7 @@ async function cmdNotifyCursor(args) {
|
|
|
4078
4371
|
}
|
|
4079
4372
|
async function cmdNotifyd(rest) {
|
|
4080
4373
|
const sub = rest[0] ?? "status";
|
|
4081
|
-
const daemon = await import("./notifyDaemon-
|
|
4374
|
+
const daemon = await import("./notifyDaemon-BdOeFIVl.js");
|
|
4082
4375
|
switch (sub) {
|
|
4083
4376
|
case "run": return daemon.runDaemon();
|
|
4084
4377
|
case "once": return daemon.runDaemon({ once: true });
|
|
@@ -4104,5 +4397,5 @@ async function cmdNotifyd(rest) {
|
|
|
4104
4397
|
}
|
|
4105
4398
|
|
|
4106
4399
|
//#endregion
|
|
4107
|
-
export {
|
|
4108
|
-
//# sourceMappingURL=subcommands-
|
|
4400
|
+
export { notifyDir as $, renderRawLog as A, submitAndConfirm as B, matchKeyword as C, recentMessageEdges as D, readPtysize as E, restartHintLines as F, gcInboxes as G, writeKeysPaced as H, runSubcommand as I, liveWatchers as J, hostId as K, snapshotStatus as L, resolveOne as M, resolveReadWindow as N, recentReadEdges as O, resolveResumeArgs as P, daemonLockOwnerPath as Q, stdinActivityPath as R, listRecords as S, readNotes as T, writeToIpc as U, waitForLogQuiet as V, appendEvent as W, shouldStealLock as X, readInbox as Y, daemonLockDir as Z, isPidAlive as _, cmdHelp as a, isUserTyping as b, deriveLiveState as c, extractMenu as d, TYPING_BADGE as et, extractNeedsInput as f, isExitRequest as g, isAgentStuck as h, backoffWhileTyping as i, renderRawLogLines as j, renderLogTailLines as k, deriveLiveStatus as l, finalizedLines as m, READ_PAGE_DEFAULT as n, controlCodeFromName as o, extractTaskCounts as p, listInboxParents as q, TYPING_WINDOW_MS as r, cursorAbs as s, GRACEFUL_EXIT_COMMANDS as t, recordInbox as tt, extractBadges as u, isSlashCommand as v, menuSelectKeys as w, lastStdinAt as x, isSubcommand as y, stopTipForCli as z };
|
|
4401
|
+
//# sourceMappingURL=subcommands-s74ViJcI.js.map
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { n as logger, t as addTransport } from "./logger-CDIsZ-Pp.js";
|
|
2
|
-
import { r as getInstalledPackage } from "./versionChecker-
|
|
2
|
+
import { r as getInstalledPackage } from "./versionChecker-DTssk7cU.js";
|
|
3
3
|
import { t as agentYesHome } from "./agentYesHome-CtHb5b71.js";
|
|
4
4
|
import { i as shouldUseLock, r as releaseLock, t as acquireLock } from "./runningLock-CNMl13dC.js";
|
|
5
5
|
import { t as PidStore } from "./pidStore-BIvsBQ8X.js";
|
|
@@ -1824,4 +1824,4 @@ function sleep(ms) {
|
|
|
1824
1824
|
|
|
1825
1825
|
//#endregion
|
|
1826
1826
|
export { removeControlCharacters as a, AgentContext as i, agentYes as n, config as r, CLIS_CONFIG as t };
|
|
1827
|
-
//# sourceMappingURL=ts-
|
|
1827
|
+
//# sourceMappingURL=ts-CP17kUI1.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.196.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-
|
|
218
|
+
//# sourceMappingURL=versionChecker-DTssk7cU.js.map
|