agent-yes 1.118.0 → 1.118.2
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-Bq_fBaXd.js +8 -0
- package/dist/{SUPPORTED_CLIS-CrIGjD28.js → SUPPORTED_CLIS-CNLy57hz.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-BcGnnKQf.js → pidStore-B5vBu8Px.js} +4 -24
- package/dist/{remotes-C3xPRtfg.js → remotes-BufkGk0e.js} +1 -1
- package/dist/{remotes-C9WMt5PY.js → remotes-DavR4Hca.js} +1 -1
- package/dist/{serve-uhfwjvBd.js → serve-DKpVuQyU.js} +117 -55
- package/dist/setup-BFiD3CAi.js +82 -0
- package/dist/{share-DwzKXEsJ.js → share-BM-H85FE.js} +1 -1
- package/dist/{subcommands-tH8JdrBS.js → subcommands-BLSPrqA1.js} +6 -6
- package/dist/{subcommands-FtwGxxtc.js → subcommands-CIrlUP1E.js} +3 -3
- package/dist/{tray-CWQe9DMY.js → tray-B8_rx1iu.js} +1 -1
- package/dist/{ts-DYzATaI_.js → ts-BUpRpKjH.js} +6 -5
- package/dist/{versionChecker-D-OYziVA.js → versionChecker-D-drPifS.js} +2 -2
- package/package.json +1 -1
- package/ts/serve.ts +120 -57
- package/ts/setup.spec.ts +42 -0
- package/ts/setup.ts +67 -0
- package/dist/SUPPORTED_CLIS-BS7EiXxW.js +0 -8
- package/dist/pidStore-BLcnCpkX.js +0 -5
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import "./ts-BUpRpKjH.js";
|
|
2
|
+
import "./logger-B9h0djqx.js";
|
|
3
|
+
import "./versionChecker-D-drPifS.js";
|
|
4
|
+
import "./pidStore-B5vBu8Px.js";
|
|
5
|
+
import "./globalPidIndex-gZuTvTBs.js";
|
|
6
|
+
import { t as SUPPORTED_CLIS } from "./SUPPORTED_CLIS-CNLy57hz.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-BUpRpKjH.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-CNLy57hz.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-D-
|
|
3
|
+
import { i as versionString, n as displayVersion, r as getInstalledPackage, t as checkAndAutoUpdate } from "./versionChecker-D-drPifS.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-CIrlUP1E.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-Bq_fBaXd.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-BUpRpKjH.js";
|
|
2
2
|
import "./logger-B9h0djqx.js";
|
|
3
|
-
import "./versionChecker-D-
|
|
4
|
-
import "./pidStore-
|
|
5
|
-
import "./globalPidIndex-
|
|
3
|
+
import "./versionChecker-D-drPifS.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.
|
|
@@ -381,5 +361,5 @@ pid-db/
|
|
|
381
361
|
};
|
|
382
362
|
|
|
383
363
|
//#endregion
|
|
384
|
-
export {
|
|
385
|
-
//# 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-BUpRpKjH.js";
|
|
2
2
|
import "./logger-B9h0djqx.js";
|
|
3
|
-
import { r as getInstalledPackage } from "./versionChecker-D-
|
|
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-D-drPifS.js";
|
|
4
|
+
import "./pidStore-B5vBu8Px.js";
|
|
5
|
+
import "./globalPidIndex-gZuTvTBs.js";
|
|
6
|
+
import { t as SUPPORTED_CLIS } from "./SUPPORTED_CLIS-CNLy57hz.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-BLSPrqA1.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";
|
|
@@ -67,13 +67,48 @@ function freshAgentEnv() {
|
|
|
67
67
|
return env;
|
|
68
68
|
}
|
|
69
69
|
const DAEMON_NAME = "agent-yes";
|
|
70
|
-
|
|
70
|
+
function resolveDaemonManager() {
|
|
71
|
+
const oxmgr = Bun.which("oxmgr");
|
|
72
|
+
const pm2 = Bun.which("pm2");
|
|
73
|
+
const override = process.env.AGENT_YES_DAEMON_MANAGER?.toLowerCase();
|
|
74
|
+
if (override === "pm2") return pm2 ? {
|
|
75
|
+
id: "pm2",
|
|
76
|
+
bin: pm2
|
|
77
|
+
} : null;
|
|
78
|
+
if (override === "oxmgr") return oxmgr ? {
|
|
79
|
+
id: "oxmgr",
|
|
80
|
+
bin: oxmgr
|
|
81
|
+
} : null;
|
|
82
|
+
return (process.platform === "win32" ? [pm2 && {
|
|
83
|
+
id: "pm2",
|
|
84
|
+
bin: pm2
|
|
85
|
+
}, oxmgr && {
|
|
86
|
+
id: "oxmgr",
|
|
87
|
+
bin: oxmgr
|
|
88
|
+
}] : [oxmgr && {
|
|
89
|
+
id: "oxmgr",
|
|
90
|
+
bin: oxmgr
|
|
91
|
+
}, pm2 && {
|
|
92
|
+
id: "pm2",
|
|
93
|
+
bin: pm2
|
|
94
|
+
}]).find((m) => !!m) ?? null;
|
|
95
|
+
}
|
|
96
|
+
function ayServeArgv(args) {
|
|
97
|
+
const ayBin = Bun.which("ay");
|
|
98
|
+
return [
|
|
99
|
+
...ayBin ? process.platform === "win32" ? [ayBin] : [process.execPath, ayBin] : ["ay"],
|
|
100
|
+
"serve",
|
|
101
|
+
...args
|
|
102
|
+
];
|
|
103
|
+
}
|
|
104
|
+
async function ensureBootAutostart(mgr) {
|
|
71
105
|
try {
|
|
72
|
-
|
|
73
|
-
|
|
106
|
+
const cmd = mgr.id === "oxmgr" ? [
|
|
107
|
+
mgr.bin,
|
|
74
108
|
"service",
|
|
75
109
|
"install"
|
|
76
|
-
]
|
|
110
|
+
] : [mgr.bin, "save"];
|
|
111
|
+
return await Bun.spawn(cmd, { stdio: [
|
|
77
112
|
"ignore",
|
|
78
113
|
"ignore",
|
|
79
114
|
"ignore"
|
|
@@ -93,22 +128,34 @@ async function spawnExit(cmd) {
|
|
|
93
128
|
return 1;
|
|
94
129
|
}
|
|
95
130
|
}
|
|
96
|
-
async function readDaemonServeArgs(
|
|
131
|
+
async function readDaemonServeArgs(mgr) {
|
|
97
132
|
try {
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
133
|
+
if (mgr.id === "oxmgr") {
|
|
134
|
+
const p = Bun.spawn([
|
|
135
|
+
mgr.bin,
|
|
136
|
+
"status",
|
|
137
|
+
DAEMON_NAME
|
|
138
|
+
], {
|
|
139
|
+
stdout: "pipe",
|
|
140
|
+
stderr: "ignore"
|
|
141
|
+
});
|
|
142
|
+
const out = await new Response(p.stdout).text();
|
|
143
|
+
if (await p.exited !== 0) return null;
|
|
144
|
+
const m = /Command:\s*(.+)/.exec(out);
|
|
145
|
+
if (!m) return null;
|
|
146
|
+
const after = /\bserve\b\s*(.*)$/.exec(m[1].trim());
|
|
147
|
+
return after ? after[1].split(/\s+/).filter(Boolean) : [];
|
|
148
|
+
}
|
|
149
|
+
const p = Bun.spawn([mgr.bin, "jlist"], {
|
|
103
150
|
stdout: "pipe",
|
|
104
151
|
stderr: "ignore"
|
|
105
152
|
});
|
|
106
153
|
const out = await new Response(p.stdout).text();
|
|
107
154
|
if (await p.exited !== 0) return null;
|
|
108
|
-
const
|
|
109
|
-
if (!
|
|
110
|
-
const
|
|
111
|
-
return
|
|
155
|
+
const proc = JSON.parse(out).find((x) => x.name === DAEMON_NAME);
|
|
156
|
+
if (!proc) return null;
|
|
157
|
+
const a = proc.pm2_env?.args ?? [];
|
|
158
|
+
return a[0] === "serve" ? a.slice(1) : a;
|
|
112
159
|
} catch {
|
|
113
160
|
return null;
|
|
114
161
|
}
|
|
@@ -130,61 +177,68 @@ async function fetchDaemonVersion(port, token) {
|
|
|
130
177
|
}
|
|
131
178
|
}
|
|
132
179
|
async function cmdServeDaemon(sub, args) {
|
|
133
|
-
const
|
|
134
|
-
if (!
|
|
135
|
-
process.stderr.write("ay serve install:
|
|
180
|
+
const mgr = resolveDaemonManager();
|
|
181
|
+
if (!mgr) {
|
|
182
|
+
process.stderr.write("ay serve install: no process manager found (need pm2 or oxmgr)\n install with: bun add -g pm2\n or: cargo install oxmgr\n");
|
|
136
183
|
return 1;
|
|
137
184
|
}
|
|
138
185
|
if (sub === "install") {
|
|
139
186
|
const token = await loadOrCreateToken(void 0);
|
|
140
|
-
const priorArgs = await readDaemonServeArgs(
|
|
187
|
+
const priorArgs = await readDaemonServeArgs(mgr);
|
|
141
188
|
const effArgs = args.length ? args : priorArgs ?? [];
|
|
142
189
|
const current = getInstalledPackage().version;
|
|
143
190
|
if (priorArgs !== null) {
|
|
144
191
|
const runningVer = await fetchDaemonVersion(portFromArgs(effArgs), token);
|
|
145
192
|
if (runningVer === current) {
|
|
146
|
-
await ensureBootAutostart(
|
|
193
|
+
await ensureBootAutostart(mgr);
|
|
147
194
|
process.stdout.write(`'${DAEMON_NAME}' already running v${current} (up to date)\n`);
|
|
148
195
|
return 0;
|
|
149
196
|
}
|
|
150
197
|
process.stdout.write(`rolling '${DAEMON_NAME}' ${runningVer ? `v${runningVer}` : "(unknown)"} → v${current}…\n`);
|
|
151
198
|
await spawnExit([
|
|
152
|
-
|
|
199
|
+
mgr.bin,
|
|
153
200
|
"stop",
|
|
154
201
|
DAEMON_NAME
|
|
155
202
|
]);
|
|
156
203
|
await spawnExit([
|
|
157
|
-
|
|
204
|
+
mgr.bin,
|
|
158
205
|
"delete",
|
|
159
206
|
DAEMON_NAME
|
|
160
207
|
]);
|
|
161
208
|
}
|
|
162
|
-
const
|
|
163
|
-
const
|
|
164
|
-
|
|
165
|
-
"serve",
|
|
166
|
-
...effArgs
|
|
167
|
-
].join(" ");
|
|
168
|
-
const code = await Bun.spawn([
|
|
169
|
-
oxmgrBin,
|
|
209
|
+
const serveArgv = ayServeArgv(effArgs);
|
|
210
|
+
const startArgv = mgr.id === "oxmgr" ? [
|
|
211
|
+
mgr.bin,
|
|
170
212
|
"start",
|
|
171
|
-
|
|
213
|
+
serveArgv.join(" "),
|
|
172
214
|
"--name",
|
|
173
215
|
DAEMON_NAME,
|
|
174
216
|
"--restart",
|
|
175
217
|
"always"
|
|
176
|
-
]
|
|
218
|
+
] : [
|
|
219
|
+
mgr.bin,
|
|
220
|
+
"start",
|
|
221
|
+
serveArgv[0],
|
|
222
|
+
"--name",
|
|
223
|
+
DAEMON_NAME,
|
|
224
|
+
"--interpreter",
|
|
225
|
+
"none",
|
|
226
|
+
"--",
|
|
227
|
+
...serveArgv.slice(1)
|
|
228
|
+
];
|
|
229
|
+
const code = await Bun.spawn(startArgv, { stdio: [
|
|
177
230
|
"ignore",
|
|
178
231
|
"inherit",
|
|
179
232
|
"inherit"
|
|
180
233
|
] }).exited;
|
|
181
234
|
if (code === 0) {
|
|
182
|
-
const onBoot = await ensureBootAutostart(
|
|
235
|
+
const onBoot = await ensureBootAutostart(mgr);
|
|
183
236
|
const port = portFromArgs(effArgs);
|
|
184
237
|
const webrtcish = effArgs.some((a) => a.startsWith("--webrtc") || a.startsWith("--share"));
|
|
185
238
|
const httpish = effArgs.some((a) => a.startsWith("--http") || a.startsWith("--share")) || !effArgs.some((a) => a.startsWith("--webrtc"));
|
|
186
|
-
process.stdout.write(`\n${priorArgs !== null ? `rolled '${DAEMON_NAME}' forward to` : `installed '${DAEMON_NAME}' as a daemon via
|
|
187
|
-
process.stdout.write(onBoot ? `start-on-boot: enabled (oxmgr registered with the system init)\n` : `start-on-boot: not registered — run \`oxmgr service install\` to enable\n`);
|
|
239
|
+
process.stdout.write(`\n${priorArgs !== null ? `rolled '${DAEMON_NAME}' forward to` : `installed '${DAEMON_NAME}' as a daemon via ${mgr.id} —`} v${current}\n`);
|
|
240
|
+
if (mgr.id === "oxmgr") process.stdout.write(onBoot ? `start-on-boot: enabled (oxmgr registered with the system init)\n` : `start-on-boot: not registered — run \`oxmgr service install\` to enable\n`);
|
|
241
|
+
else process.stdout.write(onBoot ? `start-on-boot: pm2 list saved (run \`pm2 startup\` once for boot resurrect)\n` : `start-on-boot: \`pm2 save\` failed — run it manually to persist across reboots\n`);
|
|
188
242
|
process.stdout.write(`token: ${token}\n\n`);
|
|
189
243
|
if (httpish) {
|
|
190
244
|
process.stdout.write(` ay ls ${token}@<host>:${port}\n`);
|
|
@@ -196,17 +250,25 @@ async function cmdServeDaemon(sub, args) {
|
|
|
196
250
|
}
|
|
197
251
|
return code ?? 1;
|
|
198
252
|
}
|
|
199
|
-
if (sub === "uninstall")
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
253
|
+
if (sub === "uninstall") {
|
|
254
|
+
const code = await Bun.spawn([
|
|
255
|
+
mgr.bin,
|
|
256
|
+
"delete",
|
|
257
|
+
DAEMON_NAME
|
|
258
|
+
], { stdio: [
|
|
259
|
+
"ignore",
|
|
260
|
+
"inherit",
|
|
261
|
+
"inherit"
|
|
262
|
+
] }).exited ?? 1;
|
|
263
|
+
if (mgr.id === "pm2" && code === 0) await Bun.spawn([mgr.bin, "save"], { stdio: [
|
|
264
|
+
"ignore",
|
|
265
|
+
"ignore",
|
|
266
|
+
"ignore"
|
|
267
|
+
] }).exited;
|
|
268
|
+
return code;
|
|
269
|
+
}
|
|
208
270
|
if (sub === "logs") return await Bun.spawn([
|
|
209
|
-
|
|
271
|
+
mgr.bin,
|
|
210
272
|
"logs",
|
|
211
273
|
DAEMON_NAME,
|
|
212
274
|
...args
|
|
@@ -234,7 +296,7 @@ Modes (default: --http):
|
|
|
234
296
|
--share [URL] Legacy alias for --http --webrtc
|
|
235
297
|
|
|
236
298
|
Options:
|
|
237
|
-
--port N Port to listen on (default: ${DEFAULT_PORT})\n --host HOST Interface to bind (default: 127.0.0.1; use 0.0.0.0 to expose)\n --token TOKEN Auth token (auto-generated and saved if omitted)\n -d, --daemon Install these flags as a background daemon
|
|
299
|
+
--port N Port to listen on (default: ${DEFAULT_PORT})\n --host HOST Interface to bind (default: 127.0.0.1; use 0.0.0.0 to expose)\n --token TOKEN Auth token (auto-generated and saved if omitted)\n -d, --daemon Install these flags as a background daemon (pm2/oxmgr)\n (same as: ay serve install <flags>)\n --allow-spawn Deprecated no-op — the console can always spawn agents\n --tls-cert FILE TLS certificate PEM\n --tls-key FILE TLS private key PEM\n\nSubcommands:\n ay serve install install as background daemon (pm2 on Windows, else oxmgr)\n ay serve uninstall remove daemon\n ay serve logs view daemon logs\n\nOnce running, connect from another machine:\n ay ls <token>@<host>:${DEFAULT_PORT}\n ay remote add <alias> http://<token>@<host>:${DEFAULT_PORT}\n`);
|
|
238
300
|
return 0;
|
|
239
301
|
}
|
|
240
302
|
const sub = rest[0];
|
|
@@ -269,7 +331,7 @@ Options:
|
|
|
269
331
|
alias: "d",
|
|
270
332
|
type: "boolean",
|
|
271
333
|
default: false,
|
|
272
|
-
description: "Install as a background daemon
|
|
334
|
+
description: "Install as a background daemon (same as: ay serve install <flags>)"
|
|
273
335
|
}).option("allow-spawn", {
|
|
274
336
|
type: "boolean",
|
|
275
337
|
default: false,
|
|
@@ -758,7 +820,7 @@ Options:
|
|
|
758
820
|
const webrtcVal = argv.webrtc ?? argv.share;
|
|
759
821
|
const explicitUrl = typeof webrtcVal === "string" && webrtcVal.startsWith("webrtc://") ? webrtcVal : void 0;
|
|
760
822
|
try {
|
|
761
|
-
const { startShare, loadOrCreateShareRoom } = await import("./share-
|
|
823
|
+
const { startShare, loadOrCreateShareRoom } = await import("./share-BM-H85FE.js");
|
|
762
824
|
const { link, close } = await startShare({
|
|
763
825
|
url: explicitUrl ?? await loadOrCreateShareRoom(),
|
|
764
826
|
localFetch: apiFetch,
|
|
@@ -789,4 +851,4 @@ Options:
|
|
|
789
851
|
|
|
790
852
|
//#endregion
|
|
791
853
|
export { cmdServe };
|
|
792
|
-
//# sourceMappingURL=serve-
|
|
854
|
+
//# sourceMappingURL=serve-DKpVuQyU.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-DKpVuQyU.js");
|
|
73
|
+
return cmdServe([
|
|
74
|
+
"install",
|
|
75
|
+
"--share",
|
|
76
|
+
...port ? ["--port", port] : []
|
|
77
|
+
]);
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
//#endregion
|
|
81
|
+
export { cmdSetup };
|
|
82
|
+
//# sourceMappingURL=setup-BFiD3CAi.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";
|
|
@@ -231,15 +231,15 @@ async function runSubcommand(argv) {
|
|
|
231
231
|
case "restart": return await cmdRestart(rest);
|
|
232
232
|
case "note": return await cmdNote(rest);
|
|
233
233
|
case "serve": {
|
|
234
|
-
const { cmdServe } = await import("./serve-
|
|
234
|
+
const { cmdServe } = await import("./serve-DKpVuQyU.js");
|
|
235
235
|
return cmdServe(rest);
|
|
236
236
|
}
|
|
237
237
|
case "setup": {
|
|
238
|
-
const { cmdSetup } = await import("./setup.
|
|
238
|
+
const { cmdSetup } = await import("./setup-BFiD3CAi.js");
|
|
239
239
|
return cmdSetup(rest);
|
|
240
240
|
}
|
|
241
241
|
case "remote": {
|
|
242
|
-
const { cmdRemote } = await import("./remotes-
|
|
242
|
+
const { cmdRemote } = await import("./remotes-DavR4Hca.js");
|
|
243
243
|
return cmdRemote(rest);
|
|
244
244
|
}
|
|
245
245
|
case "help": return cmdHelp();
|
|
@@ -1680,4 +1680,4 @@ async function cmdStatus(rest) {
|
|
|
1680
1680
|
|
|
1681
1681
|
//#endregion
|
|
1682
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 };
|
|
1683
|
-
//# sourceMappingURL=subcommands-
|
|
1683
|
+
//# sourceMappingURL=subcommands-BLSPrqA1.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-BLSPrqA1.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-D-
|
|
3
|
-
import {
|
|
2
|
+
import { r as getInstalledPackage } from "./versionChecker-D-drPifS.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
|
|
@@ -1714,4 +1715,4 @@ function sleep(ms) {
|
|
|
1714
1715
|
|
|
1715
1716
|
//#endregion
|
|
1716
1717
|
export { removeControlCharacters as a, AgentContext as i, agentYes as n, config as r, CLIS_CONFIG as t };
|
|
1717
|
-
//# sourceMappingURL=ts-
|
|
1718
|
+
//# sourceMappingURL=ts-BUpRpKjH.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.118.
|
|
10
|
+
var version = "1.118.2";
|
|
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-D-
|
|
224
|
+
//# sourceMappingURL=versionChecker-D-drPifS.js.map
|
package/package.json
CHANGED
package/ts/serve.ts
CHANGED
|
@@ -98,20 +98,53 @@ function freshAgentEnv(): Record<string, string> {
|
|
|
98
98
|
|
|
99
99
|
const DAEMON_NAME = "agent-yes";
|
|
100
100
|
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
// the
|
|
104
|
-
// a
|
|
105
|
-
//
|
|
106
|
-
//
|
|
107
|
-
|
|
101
|
+
type DaemonManager = { id: "oxmgr" | "pm2"; bin: string };
|
|
102
|
+
|
|
103
|
+
// Pick the process manager used to daemonize `ay serve`. oxmgr's daemon talks
|
|
104
|
+
// over a fixed TCP port; on Windows a crashed daemon routinely leaves the
|
|
105
|
+
// socket orphaned on a dead PID, which wedges every subsequent oxmgr command
|
|
106
|
+
// with "daemon did not become ready in time". pm2's named-pipe daemon does not
|
|
107
|
+
// have that failure mode, so we prefer pm2 on Windows. Elsewhere oxmgr stays
|
|
108
|
+
// the default. AGENT_YES_DAEMON_MANAGER=pm2|oxmgr forces a choice.
|
|
109
|
+
function resolveDaemonManager(): DaemonManager | null {
|
|
110
|
+
const oxmgr = Bun.which("oxmgr");
|
|
111
|
+
const pm2 = Bun.which("pm2");
|
|
112
|
+
const override = process.env.AGENT_YES_DAEMON_MANAGER?.toLowerCase();
|
|
113
|
+
if (override === "pm2") return pm2 ? { id: "pm2", bin: pm2 } : null;
|
|
114
|
+
if (override === "oxmgr") return oxmgr ? { id: "oxmgr", bin: oxmgr } : null;
|
|
115
|
+
const order: Array<DaemonManager | null> =
|
|
116
|
+
process.platform === "win32"
|
|
117
|
+
? [pm2 && { id: "pm2", bin: pm2 }, oxmgr && { id: "oxmgr", bin: oxmgr }]
|
|
118
|
+
: [oxmgr && { id: "oxmgr", bin: oxmgr }, pm2 && { id: "pm2", bin: pm2 }];
|
|
119
|
+
return order.find((m): m is DaemonManager => !!m) ?? null;
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
// Resolve the argv that launches `ay serve …` from the daemon. The daemon's
|
|
123
|
+
// environment may not have ~/.bun/bin on PATH, so we use an absolute path.
|
|
124
|
+
// On Windows the `ay` bin is a self-contained launcher (ay.exe) we exec
|
|
125
|
+
// directly; on POSIX it's a `#!/usr/bin/env bun` script we run through bun.
|
|
126
|
+
function ayServeArgv(args: string[]): string[] {
|
|
127
|
+
const ayBin = Bun.which("ay");
|
|
128
|
+
const launcher = ayBin
|
|
129
|
+
? process.platform === "win32"
|
|
130
|
+
? [ayBin]
|
|
131
|
+
: [process.execPath, ayBin]
|
|
132
|
+
: ["ay"];
|
|
133
|
+
return [...launcher, "serve", ...args];
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
// Register the daemon with the platform init system so it comes back after a
|
|
137
|
+
// *reboot*, not just a crash. oxmgr wires launchd/systemd/Task Scheduler via
|
|
138
|
+
// `oxmgr service install`; pm2 persists its process list with `pm2 save` (a
|
|
139
|
+
// once-installed `pm2 startup` hook then resurrects it on boot). Idempotent and
|
|
140
|
+
// best-effort: returns false on any failure without aborting the install — the
|
|
141
|
+
// process is still crash-managed, just not guaranteed boot-persistent.
|
|
142
|
+
async function ensureBootAutostart(mgr: DaemonManager): Promise<boolean> {
|
|
108
143
|
try {
|
|
109
|
-
// --system defaults to "auto" (launchd/systemd/Task Scheduler
|
|
110
|
-
//
|
|
111
|
-
const
|
|
112
|
-
|
|
113
|
-
});
|
|
114
|
-
return (await svc.exited) === 0;
|
|
144
|
+
// oxmgr's --system defaults to "auto" (launchd/systemd/Task Scheduler); it's
|
|
145
|
+
// a `service`-level flag, so it goes before the subcommand, not after.
|
|
146
|
+
const cmd = mgr.id === "oxmgr" ? [mgr.bin, "service", "install"] : [mgr.bin, "save"];
|
|
147
|
+
return (await Bun.spawn(cmd, { stdio: ["ignore", "ignore", "ignore"] }).exited) === 0;
|
|
115
148
|
} catch {
|
|
116
149
|
return false;
|
|
117
150
|
}
|
|
@@ -125,18 +158,29 @@ async function spawnExit(cmd: string[]): Promise<number> {
|
|
|
125
158
|
}
|
|
126
159
|
}
|
|
127
160
|
|
|
128
|
-
// The `serve` args the running daemon was started with,
|
|
129
|
-
//
|
|
130
|
-
// registered.
|
|
131
|
-
|
|
161
|
+
// The `serve` args the running daemon was started with, so a bare
|
|
162
|
+
// `ay serve install` can re-launch with the SAME args. null when no daemon is
|
|
163
|
+
// registered. oxmgr stores the full command line (`… ay serve --share`); pm2
|
|
164
|
+
// keeps the post-`--` argv in pm2_env.args (with a leading "serve" we strip).
|
|
165
|
+
async function readDaemonServeArgs(mgr: DaemonManager): Promise<string[] | null> {
|
|
132
166
|
try {
|
|
133
|
-
|
|
167
|
+
if (mgr.id === "oxmgr") {
|
|
168
|
+
const p = Bun.spawn([mgr.bin, "status", DAEMON_NAME], { stdout: "pipe", stderr: "ignore" });
|
|
169
|
+
const out = await new Response(p.stdout).text();
|
|
170
|
+
if ((await p.exited) !== 0) return null;
|
|
171
|
+
const m = /Command:\s*(.+)/.exec(out);
|
|
172
|
+
if (!m) return null;
|
|
173
|
+
const after = /\bserve\b\s*(.*)$/.exec(m[1]!.trim());
|
|
174
|
+
return after ? after[1]!.split(/\s+/).filter(Boolean) : [];
|
|
175
|
+
}
|
|
176
|
+
const p = Bun.spawn([mgr.bin, "jlist"], { stdout: "pipe", stderr: "ignore" });
|
|
134
177
|
const out = await new Response(p.stdout).text();
|
|
135
178
|
if ((await p.exited) !== 0) return null;
|
|
136
|
-
const
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
179
|
+
const list = JSON.parse(out) as Array<{ name?: string; pm2_env?: { args?: string[] } }>;
|
|
180
|
+
const proc = list.find((x) => x.name === DAEMON_NAME);
|
|
181
|
+
if (!proc) return null;
|
|
182
|
+
const a = proc.pm2_env?.args ?? [];
|
|
183
|
+
return a[0] === "serve" ? a.slice(1) : a;
|
|
140
184
|
} catch {
|
|
141
185
|
return null;
|
|
142
186
|
}
|
|
@@ -164,12 +208,12 @@ async function fetchDaemonVersion(port: number, token: string): Promise<string |
|
|
|
164
208
|
}
|
|
165
209
|
|
|
166
210
|
async function cmdServeDaemon(sub: string, args: string[]): Promise<number> {
|
|
167
|
-
const
|
|
168
|
-
if (!
|
|
211
|
+
const mgr = resolveDaemonManager();
|
|
212
|
+
if (!mgr) {
|
|
169
213
|
process.stderr.write(
|
|
170
|
-
"ay serve install:
|
|
171
|
-
" install with:
|
|
172
|
-
" or:
|
|
214
|
+
"ay serve install: no process manager found (need pm2 or oxmgr)\n" +
|
|
215
|
+
" install with: bun add -g pm2\n" +
|
|
216
|
+
" or: cargo install oxmgr\n",
|
|
173
217
|
);
|
|
174
218
|
return 1;
|
|
175
219
|
}
|
|
@@ -181,7 +225,7 @@ async function cmdServeDaemon(sub: string, args: string[]): Promise<number> {
|
|
|
181
225
|
// started with (so a bare `ay serve install` stays "the same daemon"), unless
|
|
182
226
|
// new args are given. The persisted room + token mean the share link is
|
|
183
227
|
// unchanged across the restart.
|
|
184
|
-
const priorArgs = await readDaemonServeArgs(
|
|
228
|
+
const priorArgs = await readDaemonServeArgs(mgr);
|
|
185
229
|
const effArgs = args.length ? args : (priorArgs ?? []);
|
|
186
230
|
const current = getInstalledPackage().version;
|
|
187
231
|
|
|
@@ -189,34 +233,42 @@ async function cmdServeDaemon(sub: string, args: string[]): Promise<number> {
|
|
|
189
233
|
// A daemon already exists — only disturb it if it's actually outdated.
|
|
190
234
|
const runningVer = await fetchDaemonVersion(portFromArgs(effArgs), token);
|
|
191
235
|
if (runningVer === current) {
|
|
192
|
-
await ensureBootAutostart(
|
|
236
|
+
await ensureBootAutostart(mgr);
|
|
193
237
|
process.stdout.write(`'${DAEMON_NAME}' already running v${current} (up to date)\n`);
|
|
194
238
|
return 0;
|
|
195
239
|
}
|
|
196
240
|
// Outdated (or unreachable/too-old to report) → graceful roll-forward.
|
|
197
|
-
// `
|
|
241
|
+
// `stop` sends SIGTERM, which cmdServe handles cleanly (closing share
|
|
198
242
|
// peers so browsers reconnect fast), then we re-create with the new binary.
|
|
199
243
|
process.stdout.write(
|
|
200
244
|
`rolling '${DAEMON_NAME}' ${runningVer ? `v${runningVer}` : "(unknown)"} → v${current}…\n`,
|
|
201
245
|
);
|
|
202
|
-
await spawnExit([
|
|
203
|
-
await spawnExit([
|
|
246
|
+
await spawnExit([mgr.bin, "stop", DAEMON_NAME]);
|
|
247
|
+
await spawnExit([mgr.bin, "delete", DAEMON_NAME]);
|
|
204
248
|
}
|
|
205
249
|
|
|
206
|
-
//
|
|
207
|
-
//
|
|
208
|
-
//
|
|
209
|
-
const
|
|
210
|
-
const
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
250
|
+
// oxmgr takes the command as one string; pm2 takes the binary plus its
|
|
251
|
+
// args after `--`. Both auto-restart on crash by default (pm2) / via the
|
|
252
|
+
// explicit flag (oxmgr).
|
|
253
|
+
const serveArgv = ayServeArgv(effArgs);
|
|
254
|
+
const startArgv =
|
|
255
|
+
mgr.id === "oxmgr"
|
|
256
|
+
? [mgr.bin, "start", serveArgv.join(" "), "--name", DAEMON_NAME, "--restart", "always"]
|
|
257
|
+
: [
|
|
258
|
+
mgr.bin,
|
|
259
|
+
"start",
|
|
260
|
+
serveArgv[0]!,
|
|
261
|
+
"--name",
|
|
262
|
+
DAEMON_NAME,
|
|
263
|
+
"--interpreter",
|
|
264
|
+
"none",
|
|
265
|
+
"--",
|
|
266
|
+
...serveArgv.slice(1),
|
|
267
|
+
];
|
|
268
|
+
const proc = Bun.spawn(startArgv, { stdio: ["ignore", "inherit", "inherit"] });
|
|
217
269
|
const code = await proc.exited;
|
|
218
270
|
if (code === 0) {
|
|
219
|
-
const onBoot = await ensureBootAutostart(
|
|
271
|
+
const onBoot = await ensureBootAutostart(mgr);
|
|
220
272
|
const port = portFromArgs(effArgs);
|
|
221
273
|
// Mirror cmdServe's mode resolution: webrtc-only daemons open no HTTP port.
|
|
222
274
|
const webrtcish = effArgs.some((a) => a.startsWith("--webrtc") || a.startsWith("--share"));
|
|
@@ -224,13 +276,20 @@ async function cmdServeDaemon(sub: string, args: string[]): Promise<number> {
|
|
|
224
276
|
effArgs.some((a) => a.startsWith("--http") || a.startsWith("--share")) ||
|
|
225
277
|
!effArgs.some((a) => a.startsWith("--webrtc"));
|
|
226
278
|
process.stdout.write(
|
|
227
|
-
`\n${priorArgs !== null ? `rolled '${DAEMON_NAME}' forward to` : `installed '${DAEMON_NAME}' as a daemon via
|
|
228
|
-
);
|
|
229
|
-
process.stdout.write(
|
|
230
|
-
onBoot
|
|
231
|
-
? `start-on-boot: enabled (oxmgr registered with the system init)\n`
|
|
232
|
-
: `start-on-boot: not registered — run \`oxmgr service install\` to enable\n`,
|
|
279
|
+
`\n${priorArgs !== null ? `rolled '${DAEMON_NAME}' forward to` : `installed '${DAEMON_NAME}' as a daemon via ${mgr.id} —`} v${current}\n`,
|
|
233
280
|
);
|
|
281
|
+
if (mgr.id === "oxmgr")
|
|
282
|
+
process.stdout.write(
|
|
283
|
+
onBoot
|
|
284
|
+
? `start-on-boot: enabled (oxmgr registered with the system init)\n`
|
|
285
|
+
: `start-on-boot: not registered — run \`oxmgr service install\` to enable\n`,
|
|
286
|
+
);
|
|
287
|
+
else
|
|
288
|
+
process.stdout.write(
|
|
289
|
+
onBoot
|
|
290
|
+
? `start-on-boot: pm2 list saved (run \`pm2 startup\` once for boot resurrect)\n`
|
|
291
|
+
: `start-on-boot: \`pm2 save\` failed — run it manually to persist across reboots\n`,
|
|
292
|
+
);
|
|
234
293
|
process.stdout.write(`token: ${token}\n\n`);
|
|
235
294
|
if (httpish) {
|
|
236
295
|
process.stdout.write(` ay ls ${token}@<host>:${port}\n`);
|
|
@@ -249,14 +308,18 @@ async function cmdServeDaemon(sub: string, args: string[]): Promise<number> {
|
|
|
249
308
|
}
|
|
250
309
|
|
|
251
310
|
if (sub === "uninstall") {
|
|
252
|
-
const proc = Bun.spawn([
|
|
311
|
+
const proc = Bun.spawn([mgr.bin, "delete", DAEMON_NAME], {
|
|
253
312
|
stdio: ["ignore", "inherit", "inherit"],
|
|
254
313
|
});
|
|
255
|
-
|
|
314
|
+
const code = (await proc.exited) ?? 1;
|
|
315
|
+
// Drop it from the persisted pm2 list too, so `pm2 resurrect` won't revive it.
|
|
316
|
+
if (mgr.id === "pm2" && code === 0)
|
|
317
|
+
await Bun.spawn([mgr.bin, "save"], { stdio: ["ignore", "ignore", "ignore"] }).exited;
|
|
318
|
+
return code;
|
|
256
319
|
}
|
|
257
320
|
|
|
258
321
|
if (sub === "logs") {
|
|
259
|
-
const proc = Bun.spawn([
|
|
322
|
+
const proc = Bun.spawn([mgr.bin, "logs", DAEMON_NAME, ...args], {
|
|
260
323
|
stdio: ["ignore", "inherit", "inherit"],
|
|
261
324
|
});
|
|
262
325
|
return (await proc.exited) ?? 1;
|
|
@@ -287,13 +350,13 @@ export async function cmdServe(rest: string[]): Promise<number> {
|
|
|
287
350
|
` --port N Port to listen on (default: ${DEFAULT_PORT})\n` +
|
|
288
351
|
` --host HOST Interface to bind (default: 127.0.0.1; use 0.0.0.0 to expose)\n` +
|
|
289
352
|
` --token TOKEN Auth token (auto-generated and saved if omitted)\n` +
|
|
290
|
-
` -d, --daemon Install these flags as a background daemon
|
|
353
|
+
` -d, --daemon Install these flags as a background daemon (pm2/oxmgr)\n` +
|
|
291
354
|
` (same as: ay serve install <flags>)\n` +
|
|
292
355
|
` --allow-spawn Deprecated no-op — the console can always spawn agents\n` +
|
|
293
356
|
` --tls-cert FILE TLS certificate PEM\n` +
|
|
294
357
|
` --tls-key FILE TLS private key PEM\n\n` +
|
|
295
358
|
`Subcommands:\n` +
|
|
296
|
-
` ay serve install install as background daemon
|
|
359
|
+
` ay serve install install as background daemon (pm2 on Windows, else oxmgr)\n` +
|
|
297
360
|
` ay serve uninstall remove daemon\n` +
|
|
298
361
|
` ay serve logs view daemon logs\n\n` +
|
|
299
362
|
`Once running, connect from another machine:\n` +
|
|
@@ -337,7 +400,7 @@ export async function cmdServe(rest: string[]): Promise<number> {
|
|
|
337
400
|
alias: "d",
|
|
338
401
|
type: "boolean",
|
|
339
402
|
default: false,
|
|
340
|
-
description: "Install as a background daemon
|
|
403
|
+
description: "Install as a background daemon (same as: ay serve install <flags>)",
|
|
341
404
|
})
|
|
342
405
|
.option("allow-spawn", {
|
|
343
406
|
type: "boolean",
|
|
@@ -350,7 +413,7 @@ export async function cmdServe(rest: string[]): Promise<number> {
|
|
|
350
413
|
|
|
351
414
|
const argv = await y.parseAsync();
|
|
352
415
|
|
|
353
|
-
// --daemon/-d: install these exact flags as the
|
|
416
|
+
// --daemon/-d: install these exact flags as the background daemon instead of
|
|
354
417
|
// serving in the foreground (sugar for `ay serve install <flags>`).
|
|
355
418
|
if (argv.daemon) {
|
|
356
419
|
const fwd = rest.filter((a) => a !== "--daemon" && a !== "-d");
|
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
|
+
}
|
|
@@ -1,8 +0,0 @@
|
|
|
1
|
-
import "./ts-DYzATaI_.js";
|
|
2
|
-
import "./logger-B9h0djqx.js";
|
|
3
|
-
import "./versionChecker-D-OYziVA.js";
|
|
4
|
-
import "./pidStore-BcGnnKQf.js";
|
|
5
|
-
import "./globalPidIndex-yVd3mbsV.js";
|
|
6
|
-
import { t as SUPPORTED_CLIS } from "./SUPPORTED_CLIS-CrIGjD28.js";
|
|
7
|
-
|
|
8
|
-
export { SUPPORTED_CLIS };
|