agent-yes 1.117.0 → 1.118.1
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-Bx3xCmVR.js +8 -0
- package/dist/{SUPPORTED_CLIS-DQYx5cvl.js → SUPPORTED_CLIS-FpD7Ea6s.js} +2 -2
- package/dist/{agent-yes.config-1LMoK18R.js → agent-yes.config-kmtJKJHk.js} +1 -1
- package/dist/agentYesHome-BvaUOzCV.js +25 -0
- package/dist/cli.js +6 -6
- package/dist/{globalPidIndex-yVd3mbsV.js → globalPidIndex-gZuTvTBs.js} +1 -1
- package/dist/index.js +4 -4
- package/dist/pidStore-7y1cTcAE.js +5 -0
- package/dist/{pidStore-DBjlqzo8.js → pidStore-B5vBu8Px.js} +7 -26
- package/dist/{remotes-C3xPRtfg.js → remotes-BufkGk0e.js} +1 -1
- package/dist/{remotes-C9WMt5PY.js → remotes-DavR4Hca.js} +1 -1
- package/dist/{serve-DJthZQAN.js → serve-CBvx2LeV.js} +9 -9
- package/dist/setup-C7BNSEaG.js +82 -0
- package/dist/{share-DwzKXEsJ.js → share-BM-H85FE.js} +1 -1
- package/dist/{subcommands-B_JJRHkV.js → subcommands-3oALzYZW.js} +96 -11
- package/dist/{subcommands-BuLieGot.js → subcommands-Ca1GYIB2.js} +3 -3
- package/dist/{tray-CWQe9DMY.js → tray-B8_rx1iu.js} +1 -1
- package/dist/{ts-B4lhxCQx.js → ts-DSvAXKGk.js} +8 -6
- package/dist/{versionChecker-CS7qsffQ.js → versionChecker-C40LF9-T.js} +2 -2
- package/package.json +1 -1
- package/ts/globalPidIndex.ts +5 -0
- package/ts/index.ts +10 -1
- package/ts/pidStore.ts +3 -0
- package/ts/setup.spec.ts +42 -0
- package/ts/setup.ts +67 -0
- package/ts/subcommands.spec.ts +50 -0
- package/ts/subcommands.ts +0 -0
- package/dist/SUPPORTED_CLIS-DK9PO6Y6.js +0 -8
- package/dist/pidStore-9b3YTuf4.js +0 -5
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import "./ts-DSvAXKGk.js";
|
|
2
|
+
import "./logger-B9h0djqx.js";
|
|
3
|
+
import "./versionChecker-C40LF9-T.js";
|
|
4
|
+
import "./pidStore-B5vBu8Px.js";
|
|
5
|
+
import "./globalPidIndex-gZuTvTBs.js";
|
|
6
|
+
import { t as SUPPORTED_CLIS } from "./SUPPORTED_CLIS-FpD7Ea6s.js";
|
|
7
|
+
|
|
8
|
+
export { SUPPORTED_CLIS };
|
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import { t as CLIS_CONFIG } from "./ts-
|
|
1
|
+
import { t as CLIS_CONFIG } from "./ts-DSvAXKGk.js";
|
|
2
2
|
|
|
3
3
|
//#region ts/SUPPORTED_CLIS.ts
|
|
4
4
|
const SUPPORTED_CLIS = Object.keys(CLIS_CONFIG);
|
|
5
5
|
|
|
6
6
|
//#endregion
|
|
7
7
|
export { SUPPORTED_CLIS as t };
|
|
8
|
-
//# sourceMappingURL=SUPPORTED_CLIS-
|
|
8
|
+
//# sourceMappingURL=SUPPORTED_CLIS-FpD7Ea6s.js.map
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { homedir } from "os";
|
|
2
|
+
import path from "path";
|
|
3
|
+
|
|
4
|
+
//#region ts/agentYesHome.ts
|
|
5
|
+
/**
|
|
6
|
+
* Root directory for cross-runtime, machine-global agent-yes state:
|
|
7
|
+
* the pid index (`pids.jsonl`), FIFO/named-pipe IPC endpoints (`fifo/`),
|
|
8
|
+
* winsize signals, notes, and the serve token.
|
|
9
|
+
*
|
|
10
|
+
* Durable per-session *logs* deliberately do NOT live here — they go under
|
|
11
|
+
* `<cwd>/.agent-yes/` so they stay colocated with the project that produced
|
|
12
|
+
* them (see `PidStore`). Only ephemeral IPC + the discovery index are global,
|
|
13
|
+
* which keeps FIFOs on the local home filesystem (reliable `mkfifo`) and lets
|
|
14
|
+
* `ay ls`/`ay attach` find every agent regardless of the caller's cwd.
|
|
15
|
+
*
|
|
16
|
+
* Resolved at call time (not module load) so tests and callers can override
|
|
17
|
+
* via `$AGENT_YES_HOME` without juggling the module cache.
|
|
18
|
+
*/
|
|
19
|
+
function agentYesHome() {
|
|
20
|
+
return process.env.AGENT_YES_HOME ?? path.join(homedir(), ".agent-yes");
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
//#endregion
|
|
24
|
+
export { agentYesHome as t };
|
|
25
|
+
//# sourceMappingURL=agentYesHome-BvaUOzCV.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-
|
|
3
|
+
import { i as versionString, n as displayVersion, r as getInstalledPackage, t as checkAndAutoUpdate } from "./versionChecker-C40LF9-T.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-
|
|
485
|
+
const { isSubcommand, runSubcommand, cmdHelp } = await import("./subcommands-Ca1GYIB2.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-
|
|
499
|
+
const { startTray } = await import("./tray-B8_rx1iu.js");
|
|
500
500
|
await startTray();
|
|
501
501
|
await new Promise(() => {});
|
|
502
502
|
}
|
|
503
503
|
{
|
|
504
|
-
const { ensureTray } = await import("./tray-
|
|
504
|
+
const { ensureTray } = await import("./tray-B8_rx1iu.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-
|
|
518
|
+
const { SUPPORTED_CLIS } = await import("./SUPPORTED_CLIS-Bx3xCmVR.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-
|
|
548
|
+
const { PidStore } = await import("./pidStore-7y1cTcAE.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.");
|
|
@@ -189,4 +189,4 @@ async function pruneOldLogs(maxAgeMs = retentionMs()) {
|
|
|
189
189
|
|
|
190
190
|
//#endregion
|
|
191
191
|
export { updateGlobalPidStatus as a, readGlobalPids as i, maybeCompactGlobalPids as n, pruneOldLogs as r, appendGlobalPid as t };
|
|
192
|
-
//# sourceMappingURL=globalPidIndex-
|
|
192
|
+
//# sourceMappingURL=globalPidIndex-gZuTvTBs.js.map
|
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-
|
|
1
|
+
import { a as removeControlCharacters, i as AgentContext, n as agentYes, r as config, t as CLIS_CONFIG } from "./ts-DSvAXKGk.js";
|
|
2
2
|
import "./logger-B9h0djqx.js";
|
|
3
|
-
import "./versionChecker-
|
|
4
|
-
import "./pidStore-
|
|
5
|
-
import "./globalPidIndex-
|
|
3
|
+
import "./versionChecker-C40LF9-T.js";
|
|
4
|
+
import "./pidStore-B5vBu8Px.js";
|
|
5
|
+
import "./globalPidIndex-gZuTvTBs.js";
|
|
6
6
|
|
|
7
7
|
export { AgentContext, CLIS_CONFIG, config, agentYes as default, removeControlCharacters };
|
|
@@ -1,31 +1,11 @@
|
|
|
1
1
|
import { n as logger } from "./logger-B9h0djqx.js";
|
|
2
|
-
import {
|
|
2
|
+
import { t as agentYesHome } from "./agentYesHome-BvaUOzCV.js";
|
|
3
|
+
import { a as updateGlobalPidStatus, n as maybeCompactGlobalPids, r as pruneOldLogs, t as appendGlobalPid } from "./globalPidIndex-gZuTvTBs.js";
|
|
3
4
|
import { closeSync, existsSync, fsyncSync, openSync } from "fs";
|
|
4
5
|
import { appendFile, mkdir, readFile, rename, writeFile } from "fs/promises";
|
|
5
|
-
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
|
|
29
9
|
//#region ts/JsonlStore.ts
|
|
30
10
|
/**
|
|
31
11
|
* A lightweight NeDB-style JSONL persistence layer.
|
|
@@ -223,7 +203,7 @@ var PidStore = class PidStore {
|
|
|
223
203
|
logger.warn("[pidStore] Failed to initialize:", error);
|
|
224
204
|
}
|
|
225
205
|
}
|
|
226
|
-
async registerProcess({ pid, cli, args, prompt, cwd }) {
|
|
206
|
+
async registerProcess({ pid, cli, args, prompt, cwd, wrapperPid }) {
|
|
227
207
|
const now = Date.now();
|
|
228
208
|
const argsJson = JSON.stringify(args);
|
|
229
209
|
const logFile = this.getRawLogPath(pid);
|
|
@@ -260,7 +240,8 @@ var PidStore = class PidStore {
|
|
|
260
240
|
status: "active",
|
|
261
241
|
exit_code: null,
|
|
262
242
|
exit_reason: null,
|
|
263
|
-
started_at: now
|
|
243
|
+
started_at: now,
|
|
244
|
+
wrapper_pid: wrapperPid ?? null
|
|
264
245
|
}).then(() => maybeCompactGlobalPids()).catch(() => null);
|
|
265
246
|
return result;
|
|
266
247
|
}
|
|
@@ -380,5 +361,5 @@ pid-db/
|
|
|
380
361
|
};
|
|
381
362
|
|
|
382
363
|
//#endregion
|
|
383
|
-
export {
|
|
384
|
-
//# sourceMappingURL=pidStore-
|
|
364
|
+
export { PidStore as t };
|
|
365
|
+
//# sourceMappingURL=pidStore-B5vBu8Px.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-
|
|
150
|
+
//# sourceMappingURL=remotes-BufkGk0e.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-
|
|
1
|
+
import { a as resolveRemoteSpec, i as readRemotes, n as deleteRemoteAlias, o as writeRemoteAlias, r as parseDirectRemoteSpec, t as cmdRemote } from "./remotes-BufkGk0e.js";
|
|
2
2
|
|
|
3
3
|
export { cmdRemote };
|
|
@@ -1,11 +1,11 @@
|
|
|
1
|
-
import "./ts-
|
|
1
|
+
import "./ts-DSvAXKGk.js";
|
|
2
2
|
import "./logger-B9h0djqx.js";
|
|
3
|
-
import { r as getInstalledPackage } from "./versionChecker-
|
|
4
|
-
import "./pidStore-
|
|
5
|
-
import "./globalPidIndex-
|
|
6
|
-
import { t as SUPPORTED_CLIS } from "./SUPPORTED_CLIS-
|
|
7
|
-
import "./remotes-
|
|
8
|
-
import { c as listRecords, d as renderRawLog, f as resolveOne, g as writeToIpc, m as snapshotStatus, r as controlCodeFromName, u as readNotes } from "./subcommands-
|
|
3
|
+
import { r as getInstalledPackage } from "./versionChecker-C40LF9-T.js";
|
|
4
|
+
import "./pidStore-B5vBu8Px.js";
|
|
5
|
+
import "./globalPidIndex-gZuTvTBs.js";
|
|
6
|
+
import { t as SUPPORTED_CLIS } from "./SUPPORTED_CLIS-FpD7Ea6s.js";
|
|
7
|
+
import "./remotes-BufkGk0e.js";
|
|
8
|
+
import { c as listRecords, d as renderRawLog, f as resolveOne, g as writeToIpc, m as snapshotStatus, r as controlCodeFromName, u as readNotes } from "./subcommands-3oALzYZW.js";
|
|
9
9
|
import yargs from "yargs";
|
|
10
10
|
import { mkdir, open, readFile, writeFile } from "fs/promises";
|
|
11
11
|
import { homedir, hostname, userInfo } from "os";
|
|
@@ -758,7 +758,7 @@ Options:
|
|
|
758
758
|
const webrtcVal = argv.webrtc ?? argv.share;
|
|
759
759
|
const explicitUrl = typeof webrtcVal === "string" && webrtcVal.startsWith("webrtc://") ? webrtcVal : void 0;
|
|
760
760
|
try {
|
|
761
|
-
const { startShare, loadOrCreateShareRoom } = await import("./share-
|
|
761
|
+
const { startShare, loadOrCreateShareRoom } = await import("./share-BM-H85FE.js");
|
|
762
762
|
const { link, close } = await startShare({
|
|
763
763
|
url: explicitUrl ?? await loadOrCreateShareRoom(),
|
|
764
764
|
localFetch: apiFetch,
|
|
@@ -789,4 +789,4 @@ Options:
|
|
|
789
789
|
|
|
790
790
|
//#endregion
|
|
791
791
|
export { cmdServe };
|
|
792
|
-
//# sourceMappingURL=serve-
|
|
792
|
+
//# sourceMappingURL=serve-CBvx2LeV.js.map
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
import { t as agentYesHome } from "./agentYesHome-BvaUOzCV.js";
|
|
2
|
+
import { mkdirSync, readFileSync, writeFileSync } from "fs";
|
|
3
|
+
import { homedir } from "os";
|
|
4
|
+
import path from "path";
|
|
5
|
+
import { existsSync as existsSync$1 } from "node:fs";
|
|
6
|
+
import { stdin, stdout } from "node:process";
|
|
7
|
+
import { createInterface } from "node:readline/promises";
|
|
8
|
+
|
|
9
|
+
//#region ts/workspaceConfig.ts
|
|
10
|
+
function configPath() {
|
|
11
|
+
return path.join(agentYesHome(), "config.json");
|
|
12
|
+
}
|
|
13
|
+
function readConfig() {
|
|
14
|
+
try {
|
|
15
|
+
return JSON.parse(readFileSync(configPath(), "utf-8"));
|
|
16
|
+
} catch {
|
|
17
|
+
return {};
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
/** Expand a leading `~` (`~` or `~/x`) to an absolute home-based path. */
|
|
21
|
+
function expandTilde(p) {
|
|
22
|
+
const s = p.trim();
|
|
23
|
+
if (s === "~") return homedir();
|
|
24
|
+
if (s.startsWith("~/") || s.startsWith("~\\")) return path.join(homedir(), s.slice(2));
|
|
25
|
+
return s;
|
|
26
|
+
}
|
|
27
|
+
/** The configured workspace root (absolute), or the home dir if unset. */
|
|
28
|
+
function getWorkspaceRoot() {
|
|
29
|
+
const w = readConfig().workspace;
|
|
30
|
+
return w && w.trim() ? w : homedir();
|
|
31
|
+
}
|
|
32
|
+
/** Persist the workspace root, tilde-expanded and resolved to an absolute path. */
|
|
33
|
+
function setWorkspaceRoot(dir) {
|
|
34
|
+
const abs = path.resolve(expandTilde(dir));
|
|
35
|
+
const cfg = readConfig();
|
|
36
|
+
cfg.workspace = abs;
|
|
37
|
+
mkdirSync(agentYesHome(), { recursive: true });
|
|
38
|
+
writeFileSync(configPath(), JSON.stringify(cfg, null, 2));
|
|
39
|
+
return abs;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
//#endregion
|
|
43
|
+
//#region ts/setup.ts
|
|
44
|
+
async function cmdSetup(rest) {
|
|
45
|
+
if (rest.includes("-h") || rest.includes("--help")) {
|
|
46
|
+
process.stdout.write("Usage: ay setup [workspace-dir] [--no-share] [--port N]\n\nGuided setup:\n 1. pick the workspace root new agents spawn into (default: your home dir)\n 2. share this machine to the agent-yes.com console (a restart-on-boot daemon)\n\nOptions:\n workspace-dir default directory for new agents (skips the prompt)\n --no-share set the workspace only; don't install the share daemon\n --port N HTTP API port for the share daemon (default: 7432)\n");
|
|
47
|
+
return 0;
|
|
48
|
+
}
|
|
49
|
+
const noShare = rest.includes("--no-share");
|
|
50
|
+
const portIdx = rest.indexOf("--port");
|
|
51
|
+
const port = portIdx >= 0 ? rest[portIdx + 1] : void 0;
|
|
52
|
+
let ws = rest.filter((a, i) => !a.startsWith("-") && i !== portIdx + 1)[0];
|
|
53
|
+
if (!ws) {
|
|
54
|
+
const current = getWorkspaceRoot();
|
|
55
|
+
if (stdin.isTTY && stdout.isTTY) {
|
|
56
|
+
const rl = createInterface({
|
|
57
|
+
input: stdin,
|
|
58
|
+
output: stdout
|
|
59
|
+
});
|
|
60
|
+
try {
|
|
61
|
+
ws = (await rl.question(`Workspace root for new agents [${current}]: `)).trim() || current;
|
|
62
|
+
} finally {
|
|
63
|
+
rl.close();
|
|
64
|
+
}
|
|
65
|
+
} else ws = current;
|
|
66
|
+
}
|
|
67
|
+
const abs = setWorkspaceRoot(ws);
|
|
68
|
+
process.stdout.write(`workspace root: ${abs}\n`);
|
|
69
|
+
if (!existsSync$1(abs)) process.stderr.write(` note: that directory doesn't exist yet — create it, or agents spawned there will fail\n`);
|
|
70
|
+
if (noShare) return 0;
|
|
71
|
+
process.stdout.write(`\nsharing this machine to agent-yes.com…\n`);
|
|
72
|
+
const { cmdServe } = await import("./serve-CBvx2LeV.js");
|
|
73
|
+
return cmdServe([
|
|
74
|
+
"install",
|
|
75
|
+
"--share",
|
|
76
|
+
...port ? ["--port", port] : []
|
|
77
|
+
]);
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
//#endregion
|
|
81
|
+
export { cmdSetup };
|
|
82
|
+
//# sourceMappingURL=setup-C7BNSEaG.js.map
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { i as readGlobalPids } from "./globalPidIndex-
|
|
2
|
-
import { a as resolveRemoteSpec, i as readRemotes } from "./remotes-
|
|
1
|
+
import { i as readGlobalPids } from "./globalPidIndex-gZuTvTBs.js";
|
|
2
|
+
import { a as resolveRemoteSpec, i as readRemotes } from "./remotes-BufkGk0e.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";
|
|
@@ -60,6 +60,74 @@ async function compactNotes() {
|
|
|
60
60
|
})).join("\n");
|
|
61
61
|
await writeFile(notesPath(), lines ? lines + "\n" : "");
|
|
62
62
|
}
|
|
63
|
+
const READ_WINDOW_MS = 6e4;
|
|
64
|
+
const READS_KEY_SEP = "\0";
|
|
65
|
+
function readsPath() {
|
|
66
|
+
const dir = process.env.AGENT_YES_HOME ?? path.join(homedir(), ".agent-yes");
|
|
67
|
+
return path.join(dir, "reads.jsonl");
|
|
68
|
+
}
|
|
69
|
+
async function readReads() {
|
|
70
|
+
let raw;
|
|
71
|
+
try {
|
|
72
|
+
raw = await readFile(readsPath(), "utf-8");
|
|
73
|
+
} catch {
|
|
74
|
+
return /* @__PURE__ */ new Map();
|
|
75
|
+
}
|
|
76
|
+
const map = /* @__PURE__ */ new Map();
|
|
77
|
+
for (const line of raw.split("\n")) {
|
|
78
|
+
const t = line.trim();
|
|
79
|
+
if (!t) continue;
|
|
80
|
+
try {
|
|
81
|
+
const { by, target, at } = JSON.parse(t);
|
|
82
|
+
if (typeof by === "string" && typeof target === "number" && typeof at === "number") map.set(`${by}${READS_KEY_SEP}${target}`, at);
|
|
83
|
+
} catch {}
|
|
84
|
+
}
|
|
85
|
+
return map;
|
|
86
|
+
}
|
|
87
|
+
async function recordRead(by, target) {
|
|
88
|
+
const p = readsPath();
|
|
89
|
+
try {
|
|
90
|
+
await mkdir(path.dirname(p), { recursive: true });
|
|
91
|
+
await appendFile(p, JSON.stringify({
|
|
92
|
+
by,
|
|
93
|
+
target,
|
|
94
|
+
at: Date.now()
|
|
95
|
+
}) + "\n");
|
|
96
|
+
if ((await readFile(p, "utf-8").catch(() => "")).split("\n").length > 200) {
|
|
97
|
+
const lines = [...(await readReads()).entries()].map(([k, at]) => {
|
|
98
|
+
const i = k.indexOf(READS_KEY_SEP);
|
|
99
|
+
return JSON.stringify({
|
|
100
|
+
by: k.slice(0, i),
|
|
101
|
+
target: Number(k.slice(i + 1)),
|
|
102
|
+
at
|
|
103
|
+
});
|
|
104
|
+
}).join("\n");
|
|
105
|
+
await writeFile(p, lines ? lines + "\n" : "");
|
|
106
|
+
}
|
|
107
|
+
} catch {}
|
|
108
|
+
}
|
|
109
|
+
async function lastReadAt(by, target) {
|
|
110
|
+
return (await readReads()).get(`${by}${READS_KEY_SEP}${target}`) ?? null;
|
|
111
|
+
}
|
|
112
|
+
async function resolveSender() {
|
|
113
|
+
const envPid = process.env.AGENT_YES_PID ? Number(process.env.AGENT_YES_PID) : null;
|
|
114
|
+
if (!envPid || Number.isNaN(envPid)) return null;
|
|
115
|
+
const recs = await listRecords(void 0, {
|
|
116
|
+
all: true,
|
|
117
|
+
active: false,
|
|
118
|
+
json: false,
|
|
119
|
+
latest: false,
|
|
120
|
+
cwdScope: null
|
|
121
|
+
});
|
|
122
|
+
return recs.find((r) => r.wrapper_pid === envPid) ?? recs.find((r) => r.pid === envPid) ?? null;
|
|
123
|
+
}
|
|
124
|
+
async function senderContext() {
|
|
125
|
+
const agent = await resolveSender();
|
|
126
|
+
return {
|
|
127
|
+
key: agent ? `agent:${agent.pid}` : "human",
|
|
128
|
+
agent
|
|
129
|
+
};
|
|
130
|
+
}
|
|
63
131
|
/**
|
|
64
132
|
* Read the per-cwd TS PidStore JSONL and convert to the global record shape,
|
|
65
133
|
* so pre-existing TS agents that were spawned before the global-index mirror
|
|
@@ -163,15 +231,15 @@ async function runSubcommand(argv) {
|
|
|
163
231
|
case "restart": return await cmdRestart(rest);
|
|
164
232
|
case "note": return await cmdNote(rest);
|
|
165
233
|
case "serve": {
|
|
166
|
-
const { cmdServe } = await import("./serve-
|
|
234
|
+
const { cmdServe } = await import("./serve-CBvx2LeV.js");
|
|
167
235
|
return cmdServe(rest);
|
|
168
236
|
}
|
|
169
237
|
case "setup": {
|
|
170
|
-
const { cmdSetup } = await import("./setup.
|
|
238
|
+
const { cmdSetup } = await import("./setup-C7BNSEaG.js");
|
|
171
239
|
return cmdSetup(rest);
|
|
172
240
|
}
|
|
173
241
|
case "remote": {
|
|
174
|
-
const { cmdRemote } = await import("./remotes-
|
|
242
|
+
const { cmdRemote } = await import("./remotes-DavR4Hca.js");
|
|
175
243
|
return cmdRemote(rest);
|
|
176
244
|
}
|
|
177
245
|
case "help": return cmdHelp();
|
|
@@ -762,6 +830,8 @@ async function cmdRead(rest, { mode }) {
|
|
|
762
830
|
const record = await resolveOne(keyword, opts);
|
|
763
831
|
const logPath = record.log_file;
|
|
764
832
|
if (!logPath) throw new Error(`pid ${record.pid}: no log_file recorded`);
|
|
833
|
+
const reader = await senderContext();
|
|
834
|
+
await recordRead(reader.key, record.pid);
|
|
765
835
|
let stats;
|
|
766
836
|
try {
|
|
767
837
|
stats = await stat(logPath);
|
|
@@ -779,7 +849,10 @@ async function cmdRead(rest, { mode }) {
|
|
|
779
849
|
process.stderr.write(header + "\n");
|
|
780
850
|
process.stdout.write(rendered);
|
|
781
851
|
if (!rendered.endsWith("\n")) process.stdout.write("\n");
|
|
782
|
-
if (follow)
|
|
852
|
+
if (follow) {
|
|
853
|
+
setInterval(() => void recordRead(reader.key, record.pid), 3e4).unref?.();
|
|
854
|
+
return plain ? followPlainLocal(logPath, buf) : followRawLocal(logPath, buf);
|
|
855
|
+
}
|
|
783
856
|
process.stderr.write(`
|
|
784
857
|
ay ls # list all agents
|
|
785
858
|
ay tail -f ${record.pid} # follow live output\n ay send ${record.pid} "next: ..." # send a prompt\n ay send ${record.pid} "" --code=ctrl-c # interrupt\n`);
|
|
@@ -1067,6 +1140,10 @@ async function cmdSend(rest) {
|
|
|
1067
1140
|
}).option("cwd", {
|
|
1068
1141
|
type: "string",
|
|
1069
1142
|
description: "Restrict to agents under this dir"
|
|
1143
|
+
}).option("force", {
|
|
1144
|
+
type: "boolean",
|
|
1145
|
+
default: false,
|
|
1146
|
+
description: "Skip the 'tailed recently' safety check (also: AGENT_YES_FORCE_SEND=1)"
|
|
1070
1147
|
}).help(false).version(false).exitProcess(false).parseAsync();
|
|
1071
1148
|
const opts = {
|
|
1072
1149
|
all: argv.all,
|
|
@@ -1093,9 +1170,17 @@ async function cmdSend(rest) {
|
|
|
1093
1170
|
for await (const chunk of process.stdin) chunks.push(chunk);
|
|
1094
1171
|
body = Buffer.concat(chunks).toString("utf-8").trimEnd();
|
|
1095
1172
|
} else body = rawMessage;
|
|
1096
|
-
const
|
|
1097
|
-
const
|
|
1098
|
-
|
|
1173
|
+
const sender = await senderContext();
|
|
1174
|
+
const force = Boolean(argv.force) || process.env.AGENT_YES_FORCE_SEND === "1";
|
|
1175
|
+
if (sender.agent && sender.agent.pid === record.pid && !force) throw new Error(`refusing to send to yourself (pid ${record.pid}) — pass --force if you really mean it.`);
|
|
1176
|
+
const last = await lastReadAt(sender.key, record.pid);
|
|
1177
|
+
if (!(last !== null && Date.now() - last <= READ_WINDOW_MS) && !force) {
|
|
1178
|
+
const ago = last === null ? "never read" : `last read ${Math.round((Date.now() - last) / 1e3)}s ago`;
|
|
1179
|
+
const what = `pid ${record.pid} (${record.cli}, ${shortenPath(record.cwd)}) — ${ago}, not within ${READ_WINDOW_MS / 1e3}s`;
|
|
1180
|
+
if (sender.agent) throw new Error(`${what}.\n Confirm it's the right agent first: ay tail ${record.pid}\n then resend, or pass --force to override.`);
|
|
1181
|
+
process.stderr.write(`warning: ${what} — make sure this is the agent you meant (ay tail ${record.pid}).\n`);
|
|
1182
|
+
}
|
|
1183
|
+
const fullBody = (sender.agent ? `[from ${sender.agent.cli} #${sender.agent.pid} @ ${shortenPath(sender.agent.cwd)} — reply: ay send ${sender.agent.pid} "..."]\n` : "") + body;
|
|
1099
1184
|
if (fullBody && trailing) {
|
|
1100
1185
|
await writeToIpc(fifoPath, fullBody);
|
|
1101
1186
|
await new Promise((r) => setTimeout(r, 200));
|
|
@@ -1103,7 +1188,7 @@ async function cmdSend(rest) {
|
|
|
1103
1188
|
} else await writeToIpc(fifoPath, fullBody + trailing);
|
|
1104
1189
|
const payload = body + trailing;
|
|
1105
1190
|
process.stdout.write(`sent to pid ${record.pid} (${record.cli}): ${truncate(payload, 80)}\n`);
|
|
1106
|
-
const replyHint =
|
|
1191
|
+
const replyHint = sender.agent ? ` ay send ${sender.agent.pid} "..." # reply to sender\n` : "";
|
|
1107
1192
|
process.stderr.write(`\n` + replyHint + ` ay tail ${record.pid} # watch output\n ay ls # list all agents\n`);
|
|
1108
1193
|
if (codeName === "ctrl-c" || codeName === "ctrlc") {
|
|
1109
1194
|
const tip = stopTipForCli(record.cli, record.pid);
|
|
@@ -1595,4 +1680,4 @@ async function cmdStatus(rest) {
|
|
|
1595
1680
|
|
|
1596
1681
|
//#endregion
|
|
1597
1682
|
export { finalizedLines as a, listRecords as c, renderRawLog as d, resolveOne as f, writeToIpc as g, stopTipForCli as h, cursorAbs as i, matchKeyword as l, snapshotStatus as m, cmdHelp as n, isPidAlive as o, runSubcommand as p, controlCodeFromName as r, isSubcommand as s, GRACEFUL_EXIT_COMMANDS as t, readNotes as u };
|
|
1598
|
-
//# sourceMappingURL=subcommands-
|
|
1683
|
+
//# sourceMappingURL=subcommands-3oALzYZW.js.map
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import "./logger-B9h0djqx.js";
|
|
2
|
-
import "./globalPidIndex-
|
|
3
|
-
import "./remotes-
|
|
4
|
-
import { a as finalizedLines, c as listRecords, d as renderRawLog, f as resolveOne, g as writeToIpc, h as stopTipForCli, i as cursorAbs, l as matchKeyword, m as snapshotStatus, n as cmdHelp, o as isPidAlive, p as runSubcommand, r as controlCodeFromName, s as isSubcommand, t as GRACEFUL_EXIT_COMMANDS, u as readNotes } from "./subcommands-
|
|
2
|
+
import "./globalPidIndex-gZuTvTBs.js";
|
|
3
|
+
import "./remotes-BufkGk0e.js";
|
|
4
|
+
import { a as finalizedLines, c as listRecords, d as renderRawLog, f as resolveOne, g as writeToIpc, h as stopTipForCli, i as cursorAbs, l as matchKeyword, m as snapshotStatus, n as cmdHelp, o as isPidAlive, p as runSubcommand, r as controlCodeFromName, s as isSubcommand, t as GRACEFUL_EXIT_COMMANDS, u as readNotes } from "./subcommands-3oALzYZW.js";
|
|
5
5
|
|
|
6
6
|
export { cmdHelp, isSubcommand, runSubcommand };
|
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
import { n as logger, t as addTransport } from "./logger-B9h0djqx.js";
|
|
2
|
-
import { r as getInstalledPackage } from "./versionChecker-
|
|
3
|
-
import {
|
|
2
|
+
import { r as getInstalledPackage } from "./versionChecker-C40LF9-T.js";
|
|
3
|
+
import { t as agentYesHome } from "./agentYesHome-BvaUOzCV.js";
|
|
4
4
|
import { i as shouldUseLock, r as releaseLock, t as acquireLock } from "./runningLock-CJxsoGdb.js";
|
|
5
|
-
import {
|
|
5
|
+
import { t as PidStore } from "./pidStore-B5vBu8Px.js";
|
|
6
|
+
import { i as readGlobalPids } from "./globalPidIndex-gZuTvTBs.js";
|
|
6
7
|
import { arch, platform } from "process";
|
|
7
8
|
import { execSync } from "child_process";
|
|
8
9
|
import { closeSync, constants, createReadStream, existsSync, mkdirSync, openSync } from "fs";
|
|
@@ -1039,7 +1040,7 @@ async function notifyWebhook(status, details, cwd = process.cwd()) {
|
|
|
1039
1040
|
|
|
1040
1041
|
//#endregion
|
|
1041
1042
|
//#region ts/index.ts
|
|
1042
|
-
const config = await import("./agent-yes.config-
|
|
1043
|
+
const config = await import("./agent-yes.config-kmtJKJHk.js").then((mod) => mod.default || mod);
|
|
1043
1044
|
const CLIS_CONFIG = config.clis;
|
|
1044
1045
|
/**
|
|
1045
1046
|
* Main function to run agent-cli with automatic yes/no responses
|
|
@@ -1218,7 +1219,8 @@ async function agentYes({ cli, cliArgs = [], prompt, robust = true, cwd, env, ex
|
|
|
1218
1219
|
cli,
|
|
1219
1220
|
args: cliArgs,
|
|
1220
1221
|
prompt,
|
|
1221
|
-
cwd: workingDir
|
|
1222
|
+
cwd: workingDir,
|
|
1223
|
+
wrapperPid: process.pid
|
|
1222
1224
|
});
|
|
1223
1225
|
} catch (error) {
|
|
1224
1226
|
logger.warn(`[pidStore] Failed to register process ${shell.pid}:`, error);
|
|
@@ -1713,4 +1715,4 @@ function sleep(ms) {
|
|
|
1713
1715
|
|
|
1714
1716
|
//#endregion
|
|
1715
1717
|
export { removeControlCharacters as a, AgentContext as i, agentYes as n, config as r, CLIS_CONFIG as t };
|
|
1716
|
-
//# sourceMappingURL=ts-
|
|
1718
|
+
//# sourceMappingURL=ts-DSvAXKGk.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.118.1";
|
|
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-C40LF9-T.js.map
|
package/package.json
CHANGED
package/ts/globalPidIndex.ts
CHANGED
|
@@ -36,6 +36,11 @@ export interface GlobalPidRecord {
|
|
|
36
36
|
exit_code: number | null;
|
|
37
37
|
exit_reason: string | null;
|
|
38
38
|
started_at: number;
|
|
39
|
+
// The `ay` wrapper process pid that spawned this agent. The wrapper injects
|
|
40
|
+
// its own pid as AGENT_YES_PID into the agent's env (the agent's OWN pid isn't
|
|
41
|
+
// known until after spawn), so this maps that env value back to the agent's
|
|
42
|
+
// canonical record — see resolveSender() in subcommands.ts.
|
|
43
|
+
wrapper_pid?: number | null;
|
|
39
44
|
}
|
|
40
45
|
|
|
41
46
|
/**
|
package/ts/index.ts
CHANGED
|
@@ -374,7 +374,16 @@ export default async function agentYes({
|
|
|
374
374
|
|
|
375
375
|
// Register process in pidStore (non-blocking - failures should not prevent agent from running)
|
|
376
376
|
try {
|
|
377
|
-
await pidStore.registerProcess({
|
|
377
|
+
await pidStore.registerProcess({
|
|
378
|
+
pid: shell.pid,
|
|
379
|
+
cli,
|
|
380
|
+
args: cliArgs,
|
|
381
|
+
prompt,
|
|
382
|
+
cwd: workingDir,
|
|
383
|
+
// We inject our own pid as AGENT_YES_PID into the agent's env above; record
|
|
384
|
+
// it so a child `ay send` can map that env value back to this agent.
|
|
385
|
+
wrapperPid: process.pid,
|
|
386
|
+
});
|
|
378
387
|
} catch (error) {
|
|
379
388
|
logger.warn(`[pidStore] Failed to register process ${shell.pid}:`, error);
|
|
380
389
|
}
|
package/ts/pidStore.ts
CHANGED
|
@@ -54,12 +54,14 @@ export class PidStore {
|
|
|
54
54
|
args,
|
|
55
55
|
prompt,
|
|
56
56
|
cwd,
|
|
57
|
+
wrapperPid,
|
|
57
58
|
}: {
|
|
58
59
|
pid: number;
|
|
59
60
|
cli: string;
|
|
60
61
|
args: string[];
|
|
61
62
|
prompt?: string;
|
|
62
63
|
cwd: string;
|
|
64
|
+
wrapperPid?: number;
|
|
63
65
|
}): Promise<PidRecord> {
|
|
64
66
|
const now = Date.now();
|
|
65
67
|
const argsJson = JSON.stringify(args);
|
|
@@ -113,6 +115,7 @@ export class PidStore {
|
|
|
113
115
|
exit_code: null,
|
|
114
116
|
exit_reason: null,
|
|
115
117
|
started_at: now,
|
|
118
|
+
wrapper_pid: wrapperPid ?? null,
|
|
116
119
|
})
|
|
117
120
|
.then(() => maybeCompactGlobalPids())
|
|
118
121
|
.catch(() => null);
|
package/ts/setup.spec.ts
ADDED
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import { afterEach, beforeEach, describe, expect, it } from "vitest";
|
|
2
|
+
import { mkdtempSync, rmSync } from "fs";
|
|
3
|
+
import { tmpdir } from "os";
|
|
4
|
+
import path from "path";
|
|
5
|
+
import { cmdSetup } from "./setup.ts";
|
|
6
|
+
import { getWorkspaceRoot } from "./workspaceConfig.ts";
|
|
7
|
+
|
|
8
|
+
// Guards against the regression where `ay setup` was registered + documented but
|
|
9
|
+
// its module was missing ("Cannot find module './setup.ts'"). Exercises the
|
|
10
|
+
// --no-share path only, so no daemon is installed.
|
|
11
|
+
describe("cmdSetup", () => {
|
|
12
|
+
let original: string | undefined;
|
|
13
|
+
let tmp: string;
|
|
14
|
+
beforeEach(() => {
|
|
15
|
+
original = process.env.AGENT_YES_HOME;
|
|
16
|
+
tmp = mkdtempSync(path.join(tmpdir(), "ay-setup-"));
|
|
17
|
+
process.env.AGENT_YES_HOME = tmp;
|
|
18
|
+
});
|
|
19
|
+
afterEach(() => {
|
|
20
|
+
if (original === undefined) delete process.env.AGENT_YES_HOME;
|
|
21
|
+
else process.env.AGENT_YES_HOME = original;
|
|
22
|
+
rmSync(tmp, { recursive: true, force: true });
|
|
23
|
+
});
|
|
24
|
+
|
|
25
|
+
it("--help returns 0 without touching config", async () => {
|
|
26
|
+
expect(await cmdSetup(["--help"])).toBe(0);
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
it("--no-share sets the workspace root and skips the daemon", async () => {
|
|
30
|
+
const dir = path.join(tmp, "myspace");
|
|
31
|
+
const code = await cmdSetup(["--no-share", dir]);
|
|
32
|
+
expect(code).toBe(0);
|
|
33
|
+
expect(getWorkspaceRoot()).toBe(path.resolve(dir));
|
|
34
|
+
});
|
|
35
|
+
|
|
36
|
+
it("--no-share with a --port flag still treats the path as the workspace", async () => {
|
|
37
|
+
const dir = path.join(tmp, "ws");
|
|
38
|
+
const code = await cmdSetup(["--no-share", "--port", "7440", dir]);
|
|
39
|
+
expect(code).toBe(0);
|
|
40
|
+
expect(getWorkspaceRoot()).toBe(path.resolve(dir));
|
|
41
|
+
});
|
|
42
|
+
});
|
package/ts/setup.ts
ADDED
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
import { existsSync } from "node:fs";
|
|
2
|
+
import { stdin, stdout } from "node:process";
|
|
3
|
+
import { createInterface } from "node:readline/promises";
|
|
4
|
+
import { getWorkspaceRoot, setWorkspaceRoot } from "./workspaceConfig.ts";
|
|
5
|
+
|
|
6
|
+
// `ay setup` — guided onboarding. Two steps:
|
|
7
|
+
// 1. choose the workspace root (the default cwd new agents spawn into when the
|
|
8
|
+
// console doesn't pass one — see workspaceConfig), and
|
|
9
|
+
// 2. share this machine to the agent-yes.com console over WebRTC, installed as a
|
|
10
|
+
// restart-on-boot daemon (delegates to `ay serve install --share`).
|
|
11
|
+
//
|
|
12
|
+
// Designed to degrade gracefully: with a TTY it prompts (defaulting to the
|
|
13
|
+
// current/home workspace); piped or in a script it takes the first positional as
|
|
14
|
+
// the workspace and otherwise keeps the current one — never blocking on input.
|
|
15
|
+
export async function cmdSetup(rest: string[]): Promise<number> {
|
|
16
|
+
if (rest.includes("-h") || rest.includes("--help")) {
|
|
17
|
+
process.stdout.write(
|
|
18
|
+
`Usage: ay setup [workspace-dir] [--no-share] [--port N]\n\n` +
|
|
19
|
+
`Guided setup:\n` +
|
|
20
|
+
` 1. pick the workspace root new agents spawn into (default: your home dir)\n` +
|
|
21
|
+
` 2. share this machine to the agent-yes.com console (a restart-on-boot daemon)\n\n` +
|
|
22
|
+
`Options:\n` +
|
|
23
|
+
` workspace-dir default directory for new agents (skips the prompt)\n` +
|
|
24
|
+
` --no-share set the workspace only; don't install the share daemon\n` +
|
|
25
|
+
` --port N HTTP API port for the share daemon (default: 7432)\n`,
|
|
26
|
+
);
|
|
27
|
+
return 0;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
const noShare = rest.includes("--no-share");
|
|
31
|
+
const portIdx = rest.indexOf("--port");
|
|
32
|
+
const port = portIdx >= 0 ? rest[portIdx + 1] : undefined;
|
|
33
|
+
// The workspace is the first non-flag token (and not the value of --port).
|
|
34
|
+
const positional = rest.filter((a, i) => !a.startsWith("-") && i !== portIdx + 1);
|
|
35
|
+
|
|
36
|
+
// 1. Workspace root.
|
|
37
|
+
let ws = positional[0];
|
|
38
|
+
if (!ws) {
|
|
39
|
+
const current = getWorkspaceRoot();
|
|
40
|
+
if (stdin.isTTY && stdout.isTTY) {
|
|
41
|
+
const rl = createInterface({ input: stdin, output: stdout });
|
|
42
|
+
try {
|
|
43
|
+
const ans = (await rl.question(`Workspace root for new agents [${current}]: `)).trim();
|
|
44
|
+
ws = ans || current;
|
|
45
|
+
} finally {
|
|
46
|
+
rl.close();
|
|
47
|
+
}
|
|
48
|
+
} else {
|
|
49
|
+
ws = current; // non-interactive: keep whatever's configured (home by default)
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
const abs = setWorkspaceRoot(ws);
|
|
53
|
+
process.stdout.write(`workspace root: ${abs}\n`);
|
|
54
|
+
if (!existsSync(abs)) {
|
|
55
|
+
process.stderr.write(
|
|
56
|
+
` note: that directory doesn't exist yet — create it, or agents spawned there will fail\n`,
|
|
57
|
+
);
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
if (noShare) return 0;
|
|
61
|
+
|
|
62
|
+
// 2. Share to agent-yes.com as a boot-persistent daemon. `ay serve install`
|
|
63
|
+
// handles oxmgr registration, version roll-forward, and printing the link.
|
|
64
|
+
process.stdout.write(`\nsharing this machine to agent-yes.com…\n`);
|
|
65
|
+
const { cmdServe } = await import("./serve.ts");
|
|
66
|
+
return cmdServe(["install", "--share", ...(port ? ["--port", port] : [])]);
|
|
67
|
+
}
|
package/ts/subcommands.spec.ts
CHANGED
|
@@ -537,6 +537,13 @@ describe("subcommands.cmdSend writes bytes to FIFO", () => {
|
|
|
537
537
|
stdout.push(String(s));
|
|
538
538
|
return true;
|
|
539
539
|
};
|
|
540
|
+
// Isolate from the send-safety guard: if the suite itself runs inside an
|
|
541
|
+
// ay-managed agent, AGENT_YES_PID would make cmdSend treat this as an agent
|
|
542
|
+
// sender (adding a "from …" prefix / blocking). Force-send to test pure
|
|
543
|
+
// byte delivery. --force keeps the agent prefix off only when no agent
|
|
544
|
+
// context resolves, so also clear AGENT_YES_PID for determinism.
|
|
545
|
+
const savedAyPid = process.env.AGENT_YES_PID;
|
|
546
|
+
delete process.env.AGENT_YES_PID;
|
|
540
547
|
try {
|
|
541
548
|
const code = await runSubcommand([
|
|
542
549
|
"bun",
|
|
@@ -544,11 +551,13 @@ describe("subcommands.cmdSend writes bytes to FIFO", () => {
|
|
|
544
551
|
"send",
|
|
545
552
|
String(process.pid),
|
|
546
553
|
"hello-fifo",
|
|
554
|
+
"--force",
|
|
547
555
|
]);
|
|
548
556
|
expect(code).toBe(0);
|
|
549
557
|
expect(stdout.join("")).toMatch(/sent to pid/);
|
|
550
558
|
} finally {
|
|
551
559
|
process.stdout.write = orig;
|
|
560
|
+
if (savedAyPid !== undefined) process.env.AGENT_YES_PID = savedAyPid;
|
|
552
561
|
}
|
|
553
562
|
|
|
554
563
|
// Now read the bytes back from our RDWR fd.
|
|
@@ -568,6 +577,47 @@ describe("subcommands.cmdSend writes bytes to FIFO", () => {
|
|
|
568
577
|
});
|
|
569
578
|
});
|
|
570
579
|
|
|
580
|
+
describe("subcommands.cmdSend safety guards", () => {
|
|
581
|
+
it("maps AGENT_YES_PID→wrapper_pid and blocks an agent from sending to itself", async () => {
|
|
582
|
+
const { runSubcommand } = await loadModule();
|
|
583
|
+
const { appendGlobalPid } = await import("./globalPidIndex.ts");
|
|
584
|
+
// We register an agent whose wrapper_pid is a known value, then run `ay send`
|
|
585
|
+
// with AGENT_YES_PID set to that wrapper — so resolveSender maps it back to
|
|
586
|
+
// this same agent, and sending to its own pid trips the self-send guard.
|
|
587
|
+
const wrapperPid = 424242;
|
|
588
|
+
await appendGlobalPid({
|
|
589
|
+
pid: process.pid,
|
|
590
|
+
cli: "claude",
|
|
591
|
+
prompt: null,
|
|
592
|
+
cwd: process.cwd(),
|
|
593
|
+
log_file: null,
|
|
594
|
+
fifo_file: "/tmp/ay-guard-test.fifo",
|
|
595
|
+
status: "active",
|
|
596
|
+
exit_code: null,
|
|
597
|
+
exit_reason: null,
|
|
598
|
+
started_at: Date.now(),
|
|
599
|
+
wrapper_pid: wrapperPid,
|
|
600
|
+
});
|
|
601
|
+
const stderr: string[] = [];
|
|
602
|
+
const orig = process.stderr.write.bind(process.stderr);
|
|
603
|
+
(process.stderr as any).write = (s: any) => {
|
|
604
|
+
stderr.push(String(s));
|
|
605
|
+
return true;
|
|
606
|
+
};
|
|
607
|
+
const savedAyPid = process.env.AGENT_YES_PID;
|
|
608
|
+
process.env.AGENT_YES_PID = String(wrapperPid);
|
|
609
|
+
try {
|
|
610
|
+
const code = await runSubcommand(["bun", "cli.js", "send", String(process.pid), "loop?"]);
|
|
611
|
+
expect(code).toBe(1);
|
|
612
|
+
expect(stderr.join("")).toMatch(/refusing to send to yourself/);
|
|
613
|
+
} finally {
|
|
614
|
+
process.stderr.write = orig;
|
|
615
|
+
if (savedAyPid === undefined) delete process.env.AGENT_YES_PID;
|
|
616
|
+
else process.env.AGENT_YES_PID = savedAyPid;
|
|
617
|
+
}
|
|
618
|
+
});
|
|
619
|
+
});
|
|
620
|
+
|
|
571
621
|
// ---------------------------------------------------------------------------
|
|
572
622
|
// cmdLs additional arg coverage
|
|
573
623
|
// ---------------------------------------------------------------------------
|
package/ts/subcommands.ts
CHANGED
|
Binary file
|
|
@@ -1,8 +0,0 @@
|
|
|
1
|
-
import "./ts-B4lhxCQx.js";
|
|
2
|
-
import "./logger-B9h0djqx.js";
|
|
3
|
-
import "./versionChecker-CS7qsffQ.js";
|
|
4
|
-
import "./pidStore-DBjlqzo8.js";
|
|
5
|
-
import "./globalPidIndex-yVd3mbsV.js";
|
|
6
|
-
import { t as SUPPORTED_CLIS } from "./SUPPORTED_CLIS-DQYx5cvl.js";
|
|
7
|
-
|
|
8
|
-
export { SUPPORTED_CLIS };
|