@proagentstore/cli 0.4.63 → 0.4.65
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/index.js +77 -45
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -1097,7 +1097,7 @@ var publishCommand = new Command6("publish").description("Publish an agent to Pr
|
|
|
1097
1097
|
});
|
|
1098
1098
|
|
|
1099
1099
|
// src/commands/runner/command.ts
|
|
1100
|
-
import { spawn as
|
|
1100
|
+
import { spawn as spawn4 } from "child_process";
|
|
1101
1101
|
import { randomUUID as randomUUID2 } from "crypto";
|
|
1102
1102
|
import { Command as Command7 } from "commander";
|
|
1103
1103
|
|
|
@@ -1205,25 +1205,53 @@ async function waitForLocalRunner(opts, timeoutMs = 15e3) {
|
|
|
1205
1205
|
import { hostname as hostname3 } from "os";
|
|
1206
1206
|
|
|
1207
1207
|
// src/commands/runner/self-update.ts
|
|
1208
|
-
import { execFile } from "child_process";
|
|
1208
|
+
import { execFile, spawn as spawn3 } from "child_process";
|
|
1209
1209
|
import { promisify } from "util";
|
|
1210
1210
|
var run = promisify(execFile);
|
|
1211
1211
|
var RUNNER_UPDATE_PATH = "/pags/runner/update";
|
|
1212
1212
|
var RUNNER_RESTART_EXIT_CODE = 75;
|
|
1213
1213
|
var SUPERVISED_ENV = "PAGS_UP_SUPERVISED";
|
|
1214
|
+
var SUPERVISOR_RESTARTS = "2";
|
|
1215
|
+
var SERVICE_ENV = "PAGS_SERVICE";
|
|
1216
|
+
var RESTART_COMMAND_ENV = "PAGS_RESTART_COMMAND";
|
|
1217
|
+
function restarterFrom(env) {
|
|
1218
|
+
if (env[SUPERVISED_ENV] === SUPERVISOR_RESTARTS) return "pags-up";
|
|
1219
|
+
if (env[SUPERVISED_ENV] === "1") return "pags-up-child-only";
|
|
1220
|
+
if (env[SERVICE_ENV] === "1") return "service";
|
|
1221
|
+
if (env[RESTART_COMMAND_ENV]?.trim()) return "command";
|
|
1222
|
+
return null;
|
|
1223
|
+
}
|
|
1224
|
+
function supervisorNote(restarter) {
|
|
1225
|
+
return restarter === "pags-up-child-only" ? "The `pags up` on this machine predates supervisor restarts (#860): the runner comes back on the new release, but the `pags up` window keeps running its own older code until it is restarted there once." : null;
|
|
1226
|
+
}
|
|
1227
|
+
function leaveForRestart(restarter, deps = { spawn: spawn3, exit: (code) => process.exit(code) }) {
|
|
1228
|
+
if (restarter === "command") {
|
|
1229
|
+
deps.spawn(process.env[RESTART_COMMAND_ENV], { shell: true, detached: true, stdio: "ignore", env: process.env }).unref();
|
|
1230
|
+
deps.exit(0);
|
|
1231
|
+
return;
|
|
1232
|
+
}
|
|
1233
|
+
deps.exit(RUNNER_RESTART_EXIT_CODE);
|
|
1234
|
+
}
|
|
1235
|
+
function restartUpArgs(opts) {
|
|
1236
|
+
const args = ["up"];
|
|
1237
|
+
if (opts.headless) args.push("--headless");
|
|
1238
|
+
if (opts.force) args.push("--force");
|
|
1239
|
+
if (opts.instance) args.push("--instance", opts.instance);
|
|
1240
|
+
return args;
|
|
1241
|
+
}
|
|
1214
1242
|
function planRunnerUpdate(f) {
|
|
1215
1243
|
if (f.fromSource) return { action: "refused", current: f.current, reason: "This runner runs from a source checkout \u2014 update it with `git pull` there, not npm." };
|
|
1216
1244
|
if (!f.latest) return { action: "refused", current: f.current, reason: `npm could not be asked for the latest ${CLI_PACKAGE} from this machine.` };
|
|
1217
1245
|
if (!olderThan(f.current, f.latest)) return { action: "up-to-date", current: f.current };
|
|
1218
|
-
if (!f.
|
|
1246
|
+
if (!f.restarter) {
|
|
1219
1247
|
return {
|
|
1220
1248
|
action: "refused",
|
|
1221
1249
|
current: f.current,
|
|
1222
|
-
reason: `
|
|
1250
|
+
reason: `Nothing would start this runner again after an update: it was not started by \`pags up\`, and neither ${SERVICE_ENV}=1 (a launchd/systemd unit that restarts it on a non-zero exit) nor ${RESTART_COMMAND_ENV} (a command that starts it again) is set. Run it under \`pags up\`, or set one of the two where it is started \u2014 later updates can then be done remotely. (A \`pags up\` older than 0.4.62 cannot restart it either: update once at the machine with \`npm i -g ${CLI_PACKAGE}\`.)`
|
|
1223
1251
|
};
|
|
1224
1252
|
}
|
|
1225
1253
|
if (f.busy.length > 0) return { action: "wait", current: f.current, latest: f.latest, waitingFor: f.busy };
|
|
1226
|
-
return { action: "update", current: f.current, latest: f.latest };
|
|
1254
|
+
return { action: "update", current: f.current, latest: f.latest, restarter: f.restarter };
|
|
1227
1255
|
}
|
|
1228
1256
|
async function installVersion(version2) {
|
|
1229
1257
|
if (process.env[BOOTSTRAP_ENV]) {
|
|
@@ -1270,6 +1298,13 @@ function partitionByPin(instances, thisNode, alsoKnownAs = []) {
|
|
|
1270
1298
|
for (const inst of instances) (isEligible(inst, thisNode, alsoKnownAs) ? here : elsewhere).push(inst);
|
|
1271
1299
|
return { here, elsewhere };
|
|
1272
1300
|
}
|
|
1301
|
+
function pinnedAway(held, instances, thisNode, alsoKnownAs = []) {
|
|
1302
|
+
const pins = new Map(instances.map((i) => [i.id, i.config?.runnerNode]));
|
|
1303
|
+
return [...held].filter((id) => {
|
|
1304
|
+
const pin = pins.get(id);
|
|
1305
|
+
return !!pin && pin !== thisNode && !alsoKnownAs.includes(pin);
|
|
1306
|
+
});
|
|
1307
|
+
}
|
|
1273
1308
|
function registrationStatus(attached, registered) {
|
|
1274
1309
|
const ids = [...attached];
|
|
1275
1310
|
const have = ids.filter((id) => registered.has(id)).length;
|
|
@@ -1283,6 +1318,7 @@ function instanceLabel(inst) {
|
|
|
1283
1318
|
function reattachPlan(request, state) {
|
|
1284
1319
|
const target = typeof request?.attach === "string" && request.attach ? request.attach : null;
|
|
1285
1320
|
const force = target !== null && request?.force === true;
|
|
1321
|
+
if (!state.watching && !target) return { target, unblock: false, detach: false, force: false, release: true };
|
|
1286
1322
|
if (!state.watching && !(target && state.scope.includes(target))) {
|
|
1287
1323
|
return {
|
|
1288
1324
|
target,
|
|
@@ -1380,7 +1416,7 @@ async function connectViaRelay(instanceIds, localUrl, runnerToken, opts, force =
|
|
|
1380
1416
|
current: CLI_VERSION,
|
|
1381
1417
|
latest: await latestPublishedVersion(),
|
|
1382
1418
|
fromSource: runsFromSource(),
|
|
1383
|
-
|
|
1419
|
+
restarter: restarterFrom(process.env),
|
|
1384
1420
|
busy: (sessions.sessions ?? []).filter((s) => s.alive && s.runState && s.runState !== "idle").map((s) => s.sessionId)
|
|
1385
1421
|
};
|
|
1386
1422
|
};
|
|
@@ -1390,7 +1426,7 @@ async function connectViaRelay(instanceIds, localUrl, runnerToken, opts, force =
|
|
|
1390
1426
|
writeLine(`Installed ${plan.latest} \u2014 restarting; every agent re-attaches on the way back up.`);
|
|
1391
1427
|
setTimeout(() => {
|
|
1392
1428
|
for (const id of [...attached.keys()]) detach(id);
|
|
1393
|
-
|
|
1429
|
+
leaveForRestart(plan.restarter);
|
|
1394
1430
|
}, 500).unref();
|
|
1395
1431
|
};
|
|
1396
1432
|
let updateWaiting = false;
|
|
@@ -1421,7 +1457,8 @@ async function connectViaRelay(instanceIds, localUrl, runnerToken, opts, force =
|
|
|
1421
1457
|
} catch (e) {
|
|
1422
1458
|
return { status: 500, result: { error: `npm could not install ${plan.latest}: ${e instanceof Error ? e.message : String(e)}` } };
|
|
1423
1459
|
}
|
|
1424
|
-
|
|
1460
|
+
const supervisor = supervisorNote(plan.restarter);
|
|
1461
|
+
return { status: 200, result: { action: "restarting", current: plan.current, latest: plan.latest, restartedBy: plan.restarter, ...supervisor ? { supervisor } : {} } };
|
|
1425
1462
|
};
|
|
1426
1463
|
const answerControl = async (path, body) => {
|
|
1427
1464
|
if (path === RUNNER_UPDATE_PATH) return answerUpdate(body);
|
|
@@ -1430,6 +1467,13 @@ async function connectViaRelay(instanceIds, localUrl, runnerToken, opts, force =
|
|
|
1430
1467
|
const named = typeof request?.attach === "string" ? request.attach : "";
|
|
1431
1468
|
const plan = reattachPlan(request, { held: attached.has(named), blocked: blocked.has(named), watching: watchInstances, scope: instanceIds });
|
|
1432
1469
|
if (plan.refuse) return { status: 409, result: { error: plan.refuse } };
|
|
1470
|
+
if (plan.release) {
|
|
1471
|
+
const res = await requestPags("GET", "/v1/instances/my/instances", { ...opts, pagsToken });
|
|
1472
|
+
const released = pinnedAway(attached.keys(), res.instances ?? [], runnerNode, machine.names);
|
|
1473
|
+
for (const id of released) detach(id, `${id.slice(0, 8)}\u2026 (pinned to another machine now)`);
|
|
1474
|
+
if (released.length && attached.size === 0) writeLine("This `pags up --instance` holds no agent now \u2014 close it, or restart it without --instance.");
|
|
1475
|
+
return { status: 200, result: { attached: [...attached.keys()], released } };
|
|
1476
|
+
}
|
|
1433
1477
|
if (plan.target) {
|
|
1434
1478
|
if (plan.unblock) blocked.delete(plan.target);
|
|
1435
1479
|
if (plan.detach) detach(plan.target);
|
|
@@ -1728,7 +1772,7 @@ function createRunnerCommand() {
|
|
|
1728
1772
|
const primary = instanceIds[0];
|
|
1729
1773
|
const runnerOpts = { ...opts, host, port, token: runnerToken };
|
|
1730
1774
|
const spec = runnerSpawnSpec(runnerOpts);
|
|
1731
|
-
const runner =
|
|
1775
|
+
const runner = spawn4(spec.command, spec.args, {
|
|
1732
1776
|
cwd: spec.cwd,
|
|
1733
1777
|
stdio: ["ignore", "pipe", "pipe"],
|
|
1734
1778
|
shell: process.platform === "win32"
|
|
@@ -1879,6 +1923,7 @@ function createRunnerCommand() {
|
|
|
1879
1923
|
var runnerCommand = createRunnerCommand();
|
|
1880
1924
|
|
|
1881
1925
|
// src/commands/up.ts
|
|
1926
|
+
import { execFileSync as execFileSync2 } from "child_process";
|
|
1882
1927
|
import { createRequire as createRequire2 } from "module";
|
|
1883
1928
|
import { Command as Command8 } from "commander";
|
|
1884
1929
|
import { hostname as hostname5 } from "os";
|
|
@@ -2005,7 +2050,7 @@ var API_BASE3 = "https://api.proagentstore.online";
|
|
|
2005
2050
|
var CLI_VERSION2 = createRequire2(import.meta.url)("../package.json").version;
|
|
2006
2051
|
async function stopRunnerProcesses() {
|
|
2007
2052
|
if (process.platform === "win32") return false;
|
|
2008
|
-
const { execFileSync:
|
|
2053
|
+
const { execFileSync: execFileSync3 } = await import("child_process");
|
|
2009
2054
|
const patterns = [
|
|
2010
2055
|
"dist/browser-runner/index.js",
|
|
2011
2056
|
"browser-runner/src/index",
|
|
@@ -2014,7 +2059,7 @@ async function stopRunnerProcesses() {
|
|
|
2014
2059
|
let stopped = false;
|
|
2015
2060
|
for (const p of patterns) {
|
|
2016
2061
|
try {
|
|
2017
|
-
|
|
2062
|
+
execFileSync3("pkill", ["-f", p], { stdio: "ignore" });
|
|
2018
2063
|
stopped = true;
|
|
2019
2064
|
} catch {
|
|
2020
2065
|
}
|
|
@@ -2098,17 +2143,16 @@ var upCommand = new Command8("up").description("Start the browser runner for all
|
|
|
2098
2143
|
state.activeInstance = instances.length === 1 ? instances[0].name || instances[0].slug || instances[0].id.slice(0, 8) : `${instances.length} agents`;
|
|
2099
2144
|
printStep(`Connecting ${state.activeInstance}\u2026`, "wait");
|
|
2100
2145
|
await stopRunnerProcesses();
|
|
2101
|
-
const { spawn:
|
|
2146
|
+
const { spawn: spawn5 } = await import("child_process");
|
|
2102
2147
|
const cliPath = process.argv[1];
|
|
2103
2148
|
const args = [cliPath, "runner", "connect", ...instances.map((i) => i.id)];
|
|
2104
2149
|
if (opts.headless) args.push("--headless");
|
|
2105
2150
|
if (opts.force) args.push("--force");
|
|
2106
2151
|
if (!opts.instance) args.push("--watch-instances");
|
|
2107
|
-
const
|
|
2152
|
+
const child = spawn5(process.execPath, args, {
|
|
2108
2153
|
stdio: ["ignore", "pipe", "pipe"],
|
|
2109
|
-
env: { ...process.env, PAGS_TOKEN: session.token, [SUPERVISED_ENV]:
|
|
2154
|
+
env: { ...process.env, PAGS_TOKEN: session.token, [SUPERVISED_ENV]: SUPERVISOR_RESTARTS }
|
|
2110
2155
|
});
|
|
2111
|
-
let child = spawnChild();
|
|
2112
2156
|
const logs = [];
|
|
2113
2157
|
const handleOutput = (data2) => {
|
|
2114
2158
|
const text = data2.toString("utf-8");
|
|
@@ -2167,17 +2211,11 @@ var upCommand = new Command8("up").description("Start the browser runner for all
|
|
|
2167
2211
|
}
|
|
2168
2212
|
};
|
|
2169
2213
|
let childDead = false;
|
|
2170
|
-
|
|
2171
|
-
|
|
2172
|
-
|
|
2173
|
-
child.on("exit", onChildExit);
|
|
2174
|
-
};
|
|
2175
|
-
function onChildExit(code) {
|
|
2214
|
+
child.stdout?.on("data", handleOutput);
|
|
2215
|
+
child.stderr?.on("data", handleOutput);
|
|
2216
|
+
child.on("exit", (code) => {
|
|
2176
2217
|
if (code === RUNNER_RESTART_EXIT_CODE) {
|
|
2177
|
-
|
|
2178
|
-
printStatus(state);
|
|
2179
|
-
child = spawnChild();
|
|
2180
|
-
wire();
|
|
2218
|
+
restartUp("Runner updated remotely \u2014 restarting pags up on the new version\u2026", { PAGS_NO_PROMPT: "1" });
|
|
2181
2219
|
return;
|
|
2182
2220
|
}
|
|
2183
2221
|
childDead = true;
|
|
@@ -2188,8 +2226,20 @@ var upCommand = new Command8("up").description("Start the browser runner for all
|
|
|
2188
2226
|
if (recent.length) state.lastEvent += ": " + recent[recent.length - 1].slice(0, 60);
|
|
2189
2227
|
printStatus(state);
|
|
2190
2228
|
}
|
|
2229
|
+
});
|
|
2230
|
+
function restartUp(why, env = {}) {
|
|
2231
|
+
writeLine(` ${why}`);
|
|
2232
|
+
try {
|
|
2233
|
+
if (process.stdin.isTTY) process.stdin.setRawMode(false);
|
|
2234
|
+
process.stdin.pause();
|
|
2235
|
+
execFileSync2(process.execPath, [process.argv[1], ...restartUpArgs(opts)], { stdio: "inherit", env: { ...process.env, ...env } });
|
|
2236
|
+
} catch (e) {
|
|
2237
|
+
const status = e.status;
|
|
2238
|
+
writeLine(` Restart failed${typeof status === "number" ? ` (exit ${status})` : ""} \u2014 the runner is NOT running. Run 'pags up' again.`);
|
|
2239
|
+
process.exit(typeof status === "number" && status !== 0 ? status : 1);
|
|
2240
|
+
}
|
|
2241
|
+
process.exit(0);
|
|
2191
2242
|
}
|
|
2192
|
-
wire();
|
|
2193
2243
|
const shutdown = () => {
|
|
2194
2244
|
child.kill();
|
|
2195
2245
|
clearScreen();
|
|
@@ -2217,25 +2267,7 @@ var upCommand = new Command8("up").description("Start the browser runner for all
|
|
|
2217
2267
|
printStatus(state);
|
|
2218
2268
|
}
|
|
2219
2269
|
if (key === "r") {
|
|
2220
|
-
if (childDead)
|
|
2221
|
-
writeLine(" Restarting runner...");
|
|
2222
|
-
const { execFileSync: execFileSync2 } = await import("child_process");
|
|
2223
|
-
const restartArgs = [process.argv[1], "up"];
|
|
2224
|
-
if (opts.headless) restartArgs.push("--headless");
|
|
2225
|
-
if (opts.force) restartArgs.push("--force");
|
|
2226
|
-
if (opts.instance) restartArgs.push("--instance", opts.instance);
|
|
2227
|
-
try {
|
|
2228
|
-
execFileSync2(process.execPath, restartArgs, {
|
|
2229
|
-
stdio: "inherit",
|
|
2230
|
-
env: process.env
|
|
2231
|
-
});
|
|
2232
|
-
} catch (e) {
|
|
2233
|
-
const status = e.status;
|
|
2234
|
-
writeLine(` Restart failed${typeof status === "number" ? ` (exit ${status})` : ""} \u2014 the runner is NOT running. Run 'pags up' again.`);
|
|
2235
|
-
process.exit(typeof status === "number" && status !== 0 ? status : 1);
|
|
2236
|
-
}
|
|
2237
|
-
process.exit(0);
|
|
2238
|
-
}
|
|
2270
|
+
if (childDead) restartUp("Restarting runner...");
|
|
2239
2271
|
printStatus(state);
|
|
2240
2272
|
}
|
|
2241
2273
|
}
|