@proagentstore/cli 0.4.150 → 0.4.152
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 +163 -105
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -381,6 +381,7 @@ jobs:
|
|
|
381
381
|
});
|
|
382
382
|
|
|
383
383
|
// src/commands/login.ts
|
|
384
|
+
import { spawn } from "child_process";
|
|
384
385
|
import { existsSync as existsSync3, mkdirSync as mkdirSync2, readFileSync as readFileSync2, unlinkSync, writeFileSync as writeFileSync2 } from "fs";
|
|
385
386
|
import { createServer } from "http";
|
|
386
387
|
import { homedir } from "os";
|
|
@@ -414,9 +415,21 @@ function requireSession() {
|
|
|
414
415
|
}
|
|
415
416
|
return session;
|
|
416
417
|
}
|
|
418
|
+
function browserCommand(url, platform = process.platform) {
|
|
419
|
+
if (platform === "win32") return { file: "rundll32", args: ["url.dll,FileProtocolHandler", url] };
|
|
420
|
+
return { file: platform === "darwin" ? "open" : "xdg-open", args: [url] };
|
|
421
|
+
}
|
|
422
|
+
function openBrowser(url) {
|
|
423
|
+
const { file, args } = browserCommand(url);
|
|
424
|
+
try {
|
|
425
|
+
const child = spawn(file, args, { stdio: "ignore", detached: true, windowsHide: true });
|
|
426
|
+
child.on("error", () => void 0);
|
|
427
|
+
child.unref();
|
|
428
|
+
} catch {
|
|
429
|
+
}
|
|
430
|
+
}
|
|
417
431
|
var loginCommand = new Command3("login").description("Sign in with Google or GitHub (opens browser)").option("--github", "Use GitHub instead of Google").action(async (opts) => {
|
|
418
432
|
const provider = opts.github ? "github" : "google";
|
|
419
|
-
writeLine(`Opening browser for ${provider} sign-in...`);
|
|
420
433
|
const port = await findFreePort();
|
|
421
434
|
const callbackUrl = `http://127.0.0.1:${port}/callback`;
|
|
422
435
|
const tokenPromise = new Promise((resolve5, reject) => {
|
|
@@ -469,9 +482,9 @@ var loginCommand = new Command3("login").description("Sign in with Google or Git
|
|
|
469
482
|
});
|
|
470
483
|
const oauthBase = provider === "google" ? `${API_BASE}/v1/auth/google/start` : `${API_BASE}/v1/auth/github/start`;
|
|
471
484
|
const oauthUrl = `${oauthBase}?return_to=${encodeURIComponent(callbackUrl)}`;
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
485
|
+
writeLine(`Opening your browser for ${provider} sign-in. If it does not open, paste this URL into a browser on this machine:`);
|
|
486
|
+
writeLine(` ${oauthUrl}`);
|
|
487
|
+
openBrowser(oauthUrl);
|
|
475
488
|
try {
|
|
476
489
|
await tokenPromise;
|
|
477
490
|
const session = loadSession();
|
|
@@ -990,14 +1003,14 @@ var unclaimCommand = new Command4("unclaim").description("Remove a mistaken mach
|
|
|
990
1003
|
var machinesCommand = new Command4("machines").description("Show and claim the machine names ProAgentStore has for this account").addCommand(listCommand, { isDefault: true }).addCommand(claimCommand).addCommand(unclaimCommand);
|
|
991
1004
|
|
|
992
1005
|
// src/commands/mcp.ts
|
|
993
|
-
import { spawn } from "child_process";
|
|
1006
|
+
import { spawn as spawn2 } from "child_process";
|
|
994
1007
|
import { Command as Command5 } from "commander";
|
|
995
1008
|
var DEFAULT_MCP_URL = "https://mcp.proagentstore.online/mcp";
|
|
996
1009
|
function buildMcpRemoteArgs(opts, extraArgs = []) {
|
|
997
1010
|
return ["-y", "mcp-remote", opts.url || DEFAULT_MCP_URL, ...extraArgs];
|
|
998
1011
|
}
|
|
999
1012
|
async function runMcpProxy(opts, extraArgs = []) {
|
|
1000
|
-
const child =
|
|
1013
|
+
const child = spawn2("npx", buildMcpRemoteArgs(opts, extraArgs), {
|
|
1001
1014
|
stdio: "inherit",
|
|
1002
1015
|
env: process.env
|
|
1003
1016
|
});
|
|
@@ -1180,12 +1193,12 @@ var publishCommand = new Command7("publish").description("Publish an agent to Pr
|
|
|
1180
1193
|
});
|
|
1181
1194
|
|
|
1182
1195
|
// src/commands/runner/command.ts
|
|
1183
|
-
import { spawn as
|
|
1196
|
+
import { spawn as spawn5 } from "child_process";
|
|
1184
1197
|
import { randomUUID as randomUUID4 } from "crypto";
|
|
1185
1198
|
import { Command as Command8 } from "commander";
|
|
1186
1199
|
|
|
1187
1200
|
// src/commands/runner/process.ts
|
|
1188
|
-
import { spawn as
|
|
1201
|
+
import { spawn as spawn3 } from "child_process";
|
|
1189
1202
|
import { existsSync as existsSync6 } from "fs";
|
|
1190
1203
|
import { resolve as resolve4, win32 } from "path";
|
|
1191
1204
|
import { createServer as createServer2 } from "net";
|
|
@@ -1260,7 +1273,7 @@ function runnerSpawnSpec(opts) {
|
|
|
1260
1273
|
function startRunnerForeground(opts) {
|
|
1261
1274
|
const spec = runnerSpawnSpec(opts);
|
|
1262
1275
|
return new Promise((resolvePromise, reject) => {
|
|
1263
|
-
const child =
|
|
1276
|
+
const child = spawn3(spec.command, spec.args, {
|
|
1264
1277
|
cwd: spec.cwd,
|
|
1265
1278
|
stdio: "inherit",
|
|
1266
1279
|
shell: spec.shell
|
|
@@ -1336,7 +1349,7 @@ function sampleResources(read = os, now = Date.now(), extra = {}) {
|
|
|
1336
1349
|
}
|
|
1337
1350
|
|
|
1338
1351
|
// src/commands/runner/self-update.ts
|
|
1339
|
-
import { spawn as
|
|
1352
|
+
import { spawn as spawn4 } from "child_process";
|
|
1340
1353
|
var RUNNER_UPDATE_PATH = "/pags/runner/update";
|
|
1341
1354
|
var RUNNER_RESTART_PATH = "/pags/runner/restart";
|
|
1342
1355
|
var RUNNER_RESTART_EXIT_CODE = 75;
|
|
@@ -1367,7 +1380,7 @@ function deferredUpdateLease(value, now = Date.now()) {
|
|
|
1367
1380
|
function deferredUpdateLeaseActive(lease, now = Date.now()) {
|
|
1368
1381
|
return now < lease.expiresAt;
|
|
1369
1382
|
}
|
|
1370
|
-
function leaveForRestart(restarter, deps = { spawn:
|
|
1383
|
+
function leaveForRestart(restarter, deps = { spawn: spawn4, exit: (code) => process.exit(code) }) {
|
|
1371
1384
|
logUpdateStep(`restart: leaving for the ${restarter} restarter (${restarter === "command" ? "restart command started, exit 0" : `exit ${RUNNER_RESTART_EXIT_CODE}`})`);
|
|
1372
1385
|
if (restarter === "command") {
|
|
1373
1386
|
deps.spawn(process.env[RESTART_COMMAND_ENV], { shell: true, detached: true, stdio: "ignore", env: process.env }).unref();
|
|
@@ -2395,6 +2408,101 @@ function releaseTrial(version2, cell, log, env = process.env, root = payloadRoot
|
|
|
2395
2408
|
};
|
|
2396
2409
|
}
|
|
2397
2410
|
|
|
2411
|
+
// src/commands/up-restart.ts
|
|
2412
|
+
import { spawn as nodeSpawn, spawnSync as nodeSpawnSync } from "child_process";
|
|
2413
|
+
var UP_LAUNCHER_ENV = "PAGS_UP_LAUNCHER";
|
|
2414
|
+
var UP_LAUNCHER_PID_ENV = "PAGS_UP_LAUNCHER_PID";
|
|
2415
|
+
var RUNNER_DIED_EXIT_CODE = 76;
|
|
2416
|
+
function upRestartMode(env, parent = { pid: process.ppid, alive: pidAlive }) {
|
|
2417
|
+
if (env[SERVICE_ENV] === "1") return "service";
|
|
2418
|
+
if (env[RESTART_COMMAND_ENV]?.trim()) return "command";
|
|
2419
|
+
const launcher = Number(env[UP_LAUNCHER_PID_ENV]);
|
|
2420
|
+
if (env[UP_LAUNCHER_ENV] === "1" && launcher === parent.pid && parent.alive(launcher)) return "launcher-child";
|
|
2421
|
+
return "launcher";
|
|
2422
|
+
}
|
|
2423
|
+
function runnerExitAction(code, stopping) {
|
|
2424
|
+
if (code === RUNNER_RESTART_EXIT_CODE) return "restart";
|
|
2425
|
+
if (stopping) return "ignore";
|
|
2426
|
+
return code === 0 ? "stop" : "died";
|
|
2427
|
+
}
|
|
2428
|
+
function restartOwner(env = process.env, alive = pidAlive) {
|
|
2429
|
+
if (env[SERVICE_ENV] === "1") return "service";
|
|
2430
|
+
return env[UP_LAUNCHER_ENV] === "1" && alive(Number(env[UP_LAUNCHER_PID_ENV])) ? "launcher" : "none";
|
|
2431
|
+
}
|
|
2432
|
+
function relaunchDelayMs(failures) {
|
|
2433
|
+
return Math.min(5 * 6e4, 1e4 * 2 ** Math.max(0, failures - 1));
|
|
2434
|
+
}
|
|
2435
|
+
var RAN_MS = 6e4;
|
|
2436
|
+
var RESET_MS = 10 * 6e4;
|
|
2437
|
+
function processRestartDeps() {
|
|
2438
|
+
return {
|
|
2439
|
+
env: process.env,
|
|
2440
|
+
execPath: process.execPath,
|
|
2441
|
+
execArgv: process.execArgv,
|
|
2442
|
+
script: process.argv[1],
|
|
2443
|
+
spawn: nodeSpawn,
|
|
2444
|
+
spawnSync: nodeSpawnSync,
|
|
2445
|
+
exit: (code) => process.exit(code),
|
|
2446
|
+
log: () => {
|
|
2447
|
+
},
|
|
2448
|
+
sleep: (ms) => Atomics.wait(new Int32Array(new SharedArrayBuffer(4)), 0, 0, ms),
|
|
2449
|
+
step: (line) => logUpdateStep(line),
|
|
2450
|
+
parent: { pid: process.ppid, alive: pidAlive },
|
|
2451
|
+
pid: process.pid,
|
|
2452
|
+
now: Date.now
|
|
2453
|
+
};
|
|
2454
|
+
}
|
|
2455
|
+
function restartPagsUp(args, extraEnv, deps, opts = {}) {
|
|
2456
|
+
const env = { ...deps.env, ...extraEnv };
|
|
2457
|
+
const argv = [...deps.execArgv, deps.script, ...args];
|
|
2458
|
+
const exitCode = opts.exitCode ?? RUNNER_RESTART_EXIT_CODE;
|
|
2459
|
+
const mode = upRestartMode(env, deps.parent);
|
|
2460
|
+
deps.step(`${opts.initial ? "start" : "restart"}: pags ${args.join(" ")} \u2014 ${opts.initial ? "as" : "leaving via"} ${mode}${exitCode === RUNNER_DIED_EXIT_CODE ? " (the runner died)" : ""}`);
|
|
2461
|
+
if (mode === "service") {
|
|
2462
|
+
deps.exit(exitCode);
|
|
2463
|
+
return;
|
|
2464
|
+
}
|
|
2465
|
+
if (mode === "command") {
|
|
2466
|
+
leaveForRestart(mode, { spawn: deps.spawn, exit: deps.exit });
|
|
2467
|
+
return;
|
|
2468
|
+
}
|
|
2469
|
+
if (mode === "launcher-child") {
|
|
2470
|
+
deps.exit(exitCode);
|
|
2471
|
+
return;
|
|
2472
|
+
}
|
|
2473
|
+
const childEnv = { ...env, [UP_LAUNCHER_ENV]: "1", [UP_LAUNCHER_PID_ENV]: String(deps.pid) };
|
|
2474
|
+
let failures = 0;
|
|
2475
|
+
for (let first = true; ; first = false) {
|
|
2476
|
+
const unattended = !first || env.PAGS_NO_PROMPT === "1";
|
|
2477
|
+
deps.step(`launcher: starting pags up${unattended ? " (unattended)" : ""}`);
|
|
2478
|
+
const startedAt = deps.now();
|
|
2479
|
+
const r = deps.spawnSync(deps.execPath, argv, { stdio: "inherit", env: first ? childEnv : { ...childEnv, PAGS_NO_PROMPT: "1" } });
|
|
2480
|
+
const ran = deps.now() - startedAt;
|
|
2481
|
+
const how = r.error ? `could not start (${r.error.message})` : r.signal ? `was killed by ${r.signal}` : `exited ${r.status}`;
|
|
2482
|
+
deps.step(`launcher: pags up ${how} after ${Math.round(ran / 1e3)}s`);
|
|
2483
|
+
if (ran >= RESET_MS) failures = 0;
|
|
2484
|
+
if (r.status === RUNNER_RESTART_EXIT_CODE) {
|
|
2485
|
+
failures = 0;
|
|
2486
|
+
continue;
|
|
2487
|
+
}
|
|
2488
|
+
if (!r.error && (r.status === 0 || r.signal === "SIGINT")) {
|
|
2489
|
+
deps.exit(0);
|
|
2490
|
+
return;
|
|
2491
|
+
}
|
|
2492
|
+
if (unattended || r.status === RUNNER_DIED_EXIT_CODE || ran >= RAN_MS) {
|
|
2493
|
+
failures++;
|
|
2494
|
+
const wait = relaunchDelayMs(failures);
|
|
2495
|
+
deps.log(`pags up ${how} \u2014 starting it again in ${Math.round(wait / 1e3)}s (attempt ${failures + 1}).`);
|
|
2496
|
+
deps.step(`launcher: retrying in ${Math.round(wait / 1e3)}s (failure ${failures})`);
|
|
2497
|
+
deps.sleep(wait);
|
|
2498
|
+
continue;
|
|
2499
|
+
}
|
|
2500
|
+
if (!opts.initial) deps.log(`Restart failed${typeof r.status === "number" ? ` (exit ${r.status})` : ""} \u2014 the runner is NOT running. Run 'pags up' again.`);
|
|
2501
|
+
deps.exit(typeof r.status === "number" && r.status !== 0 ? r.status : 1);
|
|
2502
|
+
return;
|
|
2503
|
+
}
|
|
2504
|
+
}
|
|
2505
|
+
|
|
2398
2506
|
// src/commands/runner/relay.ts
|
|
2399
2507
|
var MEMBERSHIP_SYNC_PATH = "/pags/membership/sync";
|
|
2400
2508
|
var CLI_CONTROL_PATHS = /* @__PURE__ */ new Set([MEMBERSHIP_SYNC_PATH, RUNNER_UPDATE_PATH, RUNNER_RESTART_PATH]);
|
|
@@ -2690,7 +2798,9 @@ async function connectViaRelay(instanceIds, localUrl, runnerToken, opts, force =
|
|
|
2690
2798
|
// #896: who is heartbeating. Set by `runner connect` from the lock it took.
|
|
2691
2799
|
...process.env.PAGS_RUNNER_RSID ? { rsid: process.env.PAGS_RUNNER_RSID } : {},
|
|
2692
2800
|
pid: process.pid,
|
|
2693
|
-
...process.env.PAGS_RUNNER_LAUNCH ? { launch: process.env.PAGS_RUNNER_LAUNCH } : {}
|
|
2801
|
+
...process.env.PAGS_RUNNER_LAUNCH ? { launch: process.env.PAGS_RUNNER_LAUNCH } : {},
|
|
2802
|
+
supervisor: restartOwner()
|
|
2803
|
+
// #1154: what starts it again if it dies
|
|
2694
2804
|
},
|
|
2695
2805
|
relayRttMs,
|
|
2696
2806
|
sessions: sessions ?? void 0
|
|
@@ -3257,6 +3367,8 @@ function createRunnerCommand() {
|
|
|
3257
3367
|
process.exit(1);
|
|
3258
3368
|
}
|
|
3259
3369
|
lockHeld = { path: taken.path, rsid: taken.lock.rsid, nonce: taken.lock.nonce, launch: taken.lock.launch };
|
|
3370
|
+
process.env.PAGS_RUNNER_RSID = taken.lock.rsid;
|
|
3371
|
+
process.env.PAGS_RUNNER_LAUNCH = taken.lock.launch;
|
|
3260
3372
|
writeLine(`STATUS runner-session=${taken.lock.rsid}`);
|
|
3261
3373
|
}
|
|
3262
3374
|
const releaseHeldLock = () => {
|
|
@@ -3268,7 +3380,7 @@ function createRunnerCommand() {
|
|
|
3268
3380
|
const spec = runnerSpawnSpec(runnerOpts);
|
|
3269
3381
|
const crashAccount = lockAccount || loadSession()?.user.login || "";
|
|
3270
3382
|
const crashes = crashAccount ? crashPaths(configDir(), crashAccount, opts.dataDir) : null;
|
|
3271
|
-
const runner =
|
|
3383
|
+
const runner = spawn5(spec.command, spec.args, {
|
|
3272
3384
|
cwd: spec.cwd,
|
|
3273
3385
|
stdio: ["ignore", "pipe", "pipe"],
|
|
3274
3386
|
shell: spec.shell,
|
|
@@ -3453,7 +3565,7 @@ import { readFileSync as readFileSync11, statSync as statSync2, watchFile } from
|
|
|
3453
3565
|
import { Command as Command9 } from "commander";
|
|
3454
3566
|
|
|
3455
3567
|
// src/background.ts
|
|
3456
|
-
import { spawn as
|
|
3568
|
+
import { spawn as nodeSpawn2 } from "child_process";
|
|
3457
3569
|
import { closeSync as closeSync3, existsSync as existsSync10, mkdirSync as mkdirSync8, openSync as openSync3, readFileSync as readFileSync10, renameSync as renameSync4, statSync, writeFileSync as writeFileSync6 } from "fs";
|
|
3458
3570
|
import { dirname as dirname5, join as join11 } from "path";
|
|
3459
3571
|
var BACKGROUND_ENV = "PAGS_BACKGROUND";
|
|
@@ -3492,12 +3604,12 @@ function backgroundRestartCommand(execPath, script, upArgs, platform = process.p
|
|
|
3492
3604
|
const argv = [execPath, script, ...upArgs, "--background"].map((a) => shellQuote(a, platform)).join(" ");
|
|
3493
3605
|
return platform === "win32" ? `set ${BACKGROUND_RESTART_ENV}=1&& ${argv}` : `${BACKGROUND_RESTART_ENV}=1 ${argv}`;
|
|
3494
3606
|
}
|
|
3495
|
-
function spawnDetached(command, args, env, logPath,
|
|
3607
|
+
function spawnDetached(command, args, env, logPath, spawn6 = nodeSpawn2) {
|
|
3496
3608
|
mkdirSync8(dirname5(logPath), { recursive: true });
|
|
3497
3609
|
rotateLog(logPath);
|
|
3498
3610
|
const fd = openSync3(logPath, "a", 384);
|
|
3499
3611
|
try {
|
|
3500
|
-
const child =
|
|
3612
|
+
const child = spawn6(command, args, { detached: true, stdio: ["ignore", fd, fd], env, windowsHide: true });
|
|
3501
3613
|
child.unref();
|
|
3502
3614
|
if (!child.pid) throw new Error("the runner process did not start");
|
|
3503
3615
|
return child.pid;
|
|
@@ -3709,75 +3821,6 @@ async function waitForKey(keys, onInterrupt) {
|
|
|
3709
3821
|
});
|
|
3710
3822
|
}
|
|
3711
3823
|
|
|
3712
|
-
// src/commands/up-restart.ts
|
|
3713
|
-
import { spawn as nodeSpawn2, spawnSync as nodeSpawnSync } from "child_process";
|
|
3714
|
-
var UP_LAUNCHER_ENV = "PAGS_UP_LAUNCHER";
|
|
3715
|
-
function upRestartMode(env) {
|
|
3716
|
-
if (env[SERVICE_ENV] === "1") return "service";
|
|
3717
|
-
if (env[RESTART_COMMAND_ENV]?.trim()) return "command";
|
|
3718
|
-
if (env[UP_LAUNCHER_ENV] === "1") return "launcher-child";
|
|
3719
|
-
return "launcher";
|
|
3720
|
-
}
|
|
3721
|
-
function relaunchDelayMs(failures) {
|
|
3722
|
-
return Math.min(5 * 6e4, 1e4 * 2 ** Math.max(0, failures - 1));
|
|
3723
|
-
}
|
|
3724
|
-
function processRestartDeps() {
|
|
3725
|
-
return {
|
|
3726
|
-
env: process.env,
|
|
3727
|
-
execPath: process.execPath,
|
|
3728
|
-
execArgv: process.execArgv,
|
|
3729
|
-
script: process.argv[1],
|
|
3730
|
-
spawn: nodeSpawn2,
|
|
3731
|
-
spawnSync: nodeSpawnSync,
|
|
3732
|
-
exit: (code) => process.exit(code),
|
|
3733
|
-
log: () => {
|
|
3734
|
-
},
|
|
3735
|
-
sleep: (ms) => Atomics.wait(new Int32Array(new SharedArrayBuffer(4)), 0, 0, ms),
|
|
3736
|
-
step: (line) => logUpdateStep(line)
|
|
3737
|
-
};
|
|
3738
|
-
}
|
|
3739
|
-
function restartPagsUp(args, extraEnv, deps) {
|
|
3740
|
-
const env = { ...deps.env, ...extraEnv };
|
|
3741
|
-
const argv = [...deps.execArgv, deps.script, ...args];
|
|
3742
|
-
const mode = upRestartMode(env);
|
|
3743
|
-
deps.step(`restart: pags ${args.join(" ")} \u2014 leaving via ${mode}`);
|
|
3744
|
-
if (mode === "service" || mode === "command") {
|
|
3745
|
-
leaveForRestart(mode, { spawn: deps.spawn, exit: deps.exit });
|
|
3746
|
-
return;
|
|
3747
|
-
}
|
|
3748
|
-
if (mode === "launcher-child") {
|
|
3749
|
-
deps.exit(RUNNER_RESTART_EXIT_CODE);
|
|
3750
|
-
return;
|
|
3751
|
-
}
|
|
3752
|
-
let failures = 0;
|
|
3753
|
-
for (let first = true; ; first = false) {
|
|
3754
|
-
const unattended = !first || env.PAGS_NO_PROMPT === "1";
|
|
3755
|
-
deps.step(`launcher: starting pags up${unattended ? " (unattended)" : ""}`);
|
|
3756
|
-
const r = deps.spawnSync(deps.execPath, argv, { stdio: "inherit", env: { ...env, [UP_LAUNCHER_ENV]: "1", ...first ? {} : { PAGS_NO_PROMPT: "1" } } });
|
|
3757
|
-
const how = r.error ? `could not start (${r.error.message})` : r.signal ? `was killed by ${r.signal}` : `exited ${r.status}`;
|
|
3758
|
-
deps.step(`launcher: pags up ${how}`);
|
|
3759
|
-
if (r.status === RUNNER_RESTART_EXIT_CODE) {
|
|
3760
|
-
failures = 0;
|
|
3761
|
-
continue;
|
|
3762
|
-
}
|
|
3763
|
-
if (!r.error && r.status === 0) {
|
|
3764
|
-
deps.exit(0);
|
|
3765
|
-
return;
|
|
3766
|
-
}
|
|
3767
|
-
if (unattended) {
|
|
3768
|
-
failures++;
|
|
3769
|
-
const wait = relaunchDelayMs(failures);
|
|
3770
|
-
deps.log(`pags up ${how} \u2014 starting it again in ${Math.round(wait / 1e3)}s (attempt ${failures + 1}).`);
|
|
3771
|
-
deps.step(`launcher: retrying in ${Math.round(wait / 1e3)}s (failure ${failures})`);
|
|
3772
|
-
deps.sleep(wait);
|
|
3773
|
-
continue;
|
|
3774
|
-
}
|
|
3775
|
-
deps.log(`Restart failed${typeof r.status === "number" ? ` (exit ${r.status})` : ""} \u2014 the runner is NOT running. Run 'pags up' again.`);
|
|
3776
|
-
deps.exit(typeof r.status === "number" && r.status !== 0 ? r.status : 1);
|
|
3777
|
-
return;
|
|
3778
|
-
}
|
|
3779
|
-
}
|
|
3780
|
-
|
|
3781
3824
|
// src/runner-replace.ts
|
|
3782
3825
|
var REPLACE_EXIT_TIMEOUT_MS = 3e4;
|
|
3783
3826
|
function describeWork(work) {
|
|
@@ -3987,6 +4030,15 @@ start();
|
|
|
3987
4030
|
var xml = (s) => s.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, """);
|
|
3988
4031
|
var unitWord = (s) => `"${s.replace(/\\/g, "\\\\").replace(/"/g, '\\"')}"`;
|
|
3989
4032
|
var ps = (s) => `'${s.replace(/'/g, "''")}'`;
|
|
4033
|
+
function versionManagedNode(nodePath) {
|
|
4034
|
+
if (/[\\/]n[\\/]versions[\\/]/.test(nodePath)) return "n";
|
|
4035
|
+
const m = /[\\/]\.?(nvm|fnm|volta|asdf|nodenv)[\\/]/i.exec(nodePath);
|
|
4036
|
+
return m ? m[1].toLowerCase() : null;
|
|
4037
|
+
}
|
|
4038
|
+
var pinnedNodeNote = (ctx) => {
|
|
4039
|
+
const manager = versionManagedNode(ctx.nodePath);
|
|
4040
|
+
return manager ? [`It runs Node ${ctx.nodePath}, installed by ${manager}. Removing or switching away from that Node version stops the service; after changing Node, run \`pags up --install-service\` again.`] : [];
|
|
4041
|
+
};
|
|
3990
4042
|
function servicePlan(ctx) {
|
|
3991
4043
|
const supervisor = supervisorPath(ctx);
|
|
3992
4044
|
const log = serviceLogPath(ctx);
|
|
@@ -4010,6 +4062,7 @@ function servicePlan(ctx) {
|
|
|
4010
4062
|
<key>KeepAlive</key><true/>
|
|
4011
4063
|
<key>ThrottleInterval</key><integer>30</integer>
|
|
4012
4064
|
<key>ProcessType</key><string>Background</string>
|
|
4065
|
+
<key>WorkingDirectory</key><string>${xml(ctx.home)}</string>
|
|
4013
4066
|
<key>StandardOutPath</key><string>${xml(log)}</string>
|
|
4014
4067
|
<key>StandardErrorPath</key><string>${xml(log)}</string>
|
|
4015
4068
|
</dict>
|
|
@@ -4025,6 +4078,7 @@ function servicePlan(ctx) {
|
|
|
4025
4078
|
{ file: "launchctl", args: ["kickstart", "-k", `${domain}/${SERVICE_LABEL}`], why: "start it now" }
|
|
4026
4079
|
],
|
|
4027
4080
|
notes: [
|
|
4081
|
+
...pinnedNodeNote(ctx),
|
|
4028
4082
|
`LaunchAgent ${plist} \u2014 runs while this user is logged in. On a machine that must survive a reboot unattended, turn on automatic login for this user.`,
|
|
4029
4083
|
`Remove it with: pags up --uninstall-service`
|
|
4030
4084
|
]
|
|
@@ -4039,8 +4093,11 @@ function servicePlan(ctx) {
|
|
|
4039
4093
|
$ErrorActionPreference = 'Stop'
|
|
4040
4094
|
$action = New-ScheduledTaskAction -Execute ${ps(ctx.nodePath)} -Argument ${ps(`"${supervisor}"`)}
|
|
4041
4095
|
$trigger = New-ScheduledTaskTrigger -AtStartup
|
|
4096
|
+
# Task Scheduler restarts a task that failed to START; a supervisor killed later just ends. Re-trigger it every five
|
|
4097
|
+
# minutes, forever \u2014 MultipleInstances IgnoreNew makes a trigger that finds it running do nothing (#1154).
|
|
4098
|
+
$trigger.Repetition = (New-ScheduledTaskTrigger -Once -At (Get-Date) -RepetitionInterval (New-TimeSpan -Minutes 5)).Repetition
|
|
4042
4099
|
$principal = New-ScheduledTaskPrincipal -UserId ${ps(principal)} -LogonType S4U -RunLevel Limited
|
|
4043
|
-
$settings = New-ScheduledTaskSettingsSet -ExecutionTimeLimit ([TimeSpan]::Zero) -RestartCount 999 -RestartInterval (New-TimeSpan -Minutes 1) -AllowStartIfOnBatteries -DontStopIfGoingOnBatteries -StartWhenAvailable
|
|
4100
|
+
$settings = New-ScheduledTaskSettingsSet -ExecutionTimeLimit ([TimeSpan]::Zero) -RestartCount 999 -RestartInterval (New-TimeSpan -Minutes 1) -AllowStartIfOnBatteries -DontStopIfGoingOnBatteries -StartWhenAvailable -MultipleInstances IgnoreNew
|
|
4044
4101
|
Unregister-ScheduledTask -TaskName ${ps(WINDOWS_TASK)} -Confirm:$false -ErrorAction SilentlyContinue
|
|
4045
4102
|
Register-ScheduledTask -TaskName ${ps(WINDOWS_TASK)} -Action $action -Trigger $trigger -Principal $principal -Settings $settings | Out-Null
|
|
4046
4103
|
Start-ScheduledTask -TaskName ${ps(WINDOWS_TASK)}
|
|
@@ -4051,6 +4108,7 @@ Start-ScheduledTask -TaskName ${ps(WINDOWS_TASK)}
|
|
|
4051
4108
|
files,
|
|
4052
4109
|
commands: [{ file: "powershell.exe", args: ["-NoProfile", "-ExecutionPolicy", "Bypass", "-File", task], why: "register and start the Scheduled Task" }],
|
|
4053
4110
|
notes: [
|
|
4111
|
+
...pinnedNodeNote(ctx),
|
|
4054
4112
|
`Scheduled Task "${WINDOWS_TASK}" \u2014 starts at boot as ${principal || "this user"}, with nobody logged in. Registering it needs an elevated PowerShell: if it was refused, run ${task} from one.`,
|
|
4055
4113
|
`Remove it with: pags up --uninstall-service`
|
|
4056
4114
|
]
|
|
@@ -4085,7 +4143,7 @@ WantedBy=default.target
|
|
|
4085
4143
|
{ file: "systemctl", args: ["--user", "enable", "--now", SYSTEMD_UNIT], why: "enable and start it" },
|
|
4086
4144
|
{ file: "loginctl", args: ["enable-linger", ...ctx.user ? [ctx.user] : []], optional: true, why: "keep it running with nobody logged in" }
|
|
4087
4145
|
],
|
|
4088
|
-
notes: [`systemd user unit ${unit}. Logs: ${log} (and journalctl --user -u ${SYSTEMD_UNIT}).`, `Remove it with: pags up --uninstall-service`]
|
|
4146
|
+
notes: [...pinnedNodeNote(ctx), `systemd user unit ${unit}. Logs: ${log} (and journalctl --user -u ${SYSTEMD_UNIT}).`, `Remove it with: pags up --uninstall-service`]
|
|
4089
4147
|
};
|
|
4090
4148
|
}
|
|
4091
4149
|
function serviceRemovalPlan(ctx) {
|
|
@@ -4149,6 +4207,10 @@ var upCommand = new Command10("up").description("Start the browser runner for al
|
|
|
4149
4207
|
for (const line of uninstallService(serviceContext()).lines) writeLine(line);
|
|
4150
4208
|
return;
|
|
4151
4209
|
}
|
|
4210
|
+
if (!opts.background && !opts.installService && upRestartMode(process.env) === "launcher") {
|
|
4211
|
+
restartPagsUp(process.argv.slice(2), {}, { ...processRestartDeps(), log: (line) => writeLine(` ${line}`) }, { initial: true });
|
|
4212
|
+
return;
|
|
4213
|
+
}
|
|
4152
4214
|
const session = requireSession();
|
|
4153
4215
|
if (opts.installService) {
|
|
4154
4216
|
const result = installService(serviceContext());
|
|
@@ -4269,7 +4331,7 @@ var upCommand = new Command10("up").description("Start the browser runner for al
|
|
|
4269
4331
|
}
|
|
4270
4332
|
for (const line of replaced.lines) printStep(line, "ok");
|
|
4271
4333
|
}
|
|
4272
|
-
const { spawn:
|
|
4334
|
+
const { spawn: spawn6 } = await import("child_process");
|
|
4273
4335
|
const cliPath = process.argv[1];
|
|
4274
4336
|
const args = [cliPath, "runner", "connect", ...instances.map((i) => i.id)];
|
|
4275
4337
|
if (opts.headless) args.push("--headless");
|
|
@@ -4279,7 +4341,7 @@ var upCommand = new Command10("up").description("Start the browser runner for al
|
|
|
4279
4341
|
const code = await startInBackground({ session, opts, runnerArgs: args, instances: state.instances, lockFile, watching: !opts.instance });
|
|
4280
4342
|
process.exit(code);
|
|
4281
4343
|
}
|
|
4282
|
-
const child =
|
|
4344
|
+
const child = spawn6(process.execPath, args, {
|
|
4283
4345
|
stdio: ["ignore", "pipe", "pipe"],
|
|
4284
4346
|
// The child is the lock HOLDER (#896): it owns the relay sockets, so it is what a
|
|
4285
4347
|
// contender must find and what `--replace` must be able to stop.
|
|
@@ -4355,33 +4417,29 @@ var upCommand = new Command10("up").description("Start the browser runner for al
|
|
|
4355
4417
|
void deliverCrashReports({ apiBase: API_BASE3, token: session.token, account: session.user.login, paths: crashes }).catch(() => void 0);
|
|
4356
4418
|
};
|
|
4357
4419
|
child.on("exit", (code, signal) => {
|
|
4358
|
-
|
|
4420
|
+
const action = runnerExitAction(code, stopping);
|
|
4421
|
+
if (action === "restart") {
|
|
4359
4422
|
logUpdateStep("restart: runner connect asked for a restart (exit 75)");
|
|
4360
4423
|
restartUp("Runner updated remotely \u2014 restarting pags up on the new version\u2026", { PAGS_NO_PROMPT: "1" });
|
|
4361
4424
|
return;
|
|
4362
4425
|
}
|
|
4363
4426
|
childDead = true;
|
|
4364
4427
|
logUpdateStep(`runner connect ${signal ? `was killed by ${signal}` : `exited ${code}`}${stopping ? " (stopping)" : ""}`);
|
|
4365
|
-
if (
|
|
4366
|
-
if (
|
|
4367
|
-
|
|
4368
|
-
|
|
4369
|
-
|
|
4370
|
-
return;
|
|
4371
|
-
}
|
|
4372
|
-
if (code !== 0) {
|
|
4373
|
-
state.runner = "error";
|
|
4374
|
-
state.lastEvent = `Runner exited (code ${code})`;
|
|
4375
|
-
const recent = logs.slice(-5);
|
|
4376
|
-
if (recent.length) state.lastEvent += ": " + recent[recent.length - 1].slice(0, 60);
|
|
4377
|
-
printStatus(state);
|
|
4428
|
+
if (action === "ignore") return;
|
|
4429
|
+
if (action === "stop") {
|
|
4430
|
+
clearScreen();
|
|
4431
|
+
writeLine(" Runner stopped (pags down, or replaced by another pags up).");
|
|
4432
|
+
process.exit(0);
|
|
4378
4433
|
}
|
|
4434
|
+
recordConnectExit(code, signal ?? null, logs.slice(-20));
|
|
4435
|
+
const recent = logs.slice(-5).at(-1);
|
|
4436
|
+
restartUp(`Runner ${signal ? `was killed by ${signal}` : `exited (code ${code})`}${recent ? `: ${recent.slice(0, 60)}` : ""} \u2014 starting it again\u2026`, { PAGS_NO_PROMPT: "1" }, RUNNER_DIED_EXIT_CODE);
|
|
4379
4437
|
});
|
|
4380
|
-
function restartUp(why, env = {}) {
|
|
4438
|
+
function restartUp(why, env = {}, exitCode) {
|
|
4381
4439
|
writeLine(` ${why}`);
|
|
4382
4440
|
if (process.stdin.isTTY) process.stdin.setRawMode(false);
|
|
4383
4441
|
process.stdin.pause();
|
|
4384
|
-
restartPagsUp(restartUpArgs(opts), env, { ...processRestartDeps(), log: (line) => writeLine(` ${line}`) });
|
|
4442
|
+
restartPagsUp(restartUpArgs(opts), env, { ...processRestartDeps(), log: (line) => writeLine(` ${line}`) }, { exitCode });
|
|
4385
4443
|
process.exit(1);
|
|
4386
4444
|
}
|
|
4387
4445
|
const shutdown = () => {
|