@proagentstore/cli 0.1.28 → 0.1.30
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 +34 -21
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -912,17 +912,17 @@ function createRunnerCommand() {
|
|
|
912
912
|
command.command("start").description("Start the local FAGS browser runtime in the foreground").option("--host <host>", "Host to bind", "127.0.0.1").option("--port <port>", "Port to bind", "49171").option("--data-dir <path>", "Runner data directory").option("--token <token>", "Require this bearer token").option("--instance-id <id>", "Bind runner requests to a PAGS instance id").option("--headless", "Run Playwright headless").action(async (opts) => {
|
|
913
913
|
await startRunnerForeground(opts);
|
|
914
914
|
});
|
|
915
|
-
command.command("connect <
|
|
915
|
+
command.command("connect <instanceIds...>").description("Start ONE local runtime, open a Cloudflare quick tunnel, and register it for every given PAGS instance").option("--host <host>", "Host to bind", "127.0.0.1").option("--port <port>", "Port to bind", "49171").option("--data-dir <path>", "Runner data directory").option("--token <token>", "Runner bearer token. Defaults to PAGS_RUNNER_TOKEN or a generated token").option("--headless", "Run Playwright headless").option("--api-base <url>", "PAGS API base URL").option("--pags-token <token>", "PAGS session token. Defaults to PAGS_TOKEN").option("--cloudflared <path>", "cloudflared executable").option("--runner-version <version>", "Runner version").option("--skip-probe", "Skip PAGS FAGS-runtime probe after registration").action(async (instanceIds, opts) => {
|
|
916
916
|
const runnerToken = clean(opts.token) || clean(process.env.PAGS_RUNNER_TOKEN) || `pags_runner_${randomUUID()}`;
|
|
917
917
|
const host = clean(opts.host) || "127.0.0.1";
|
|
918
918
|
const port = clean(opts.port) || String(await findFreePort2(49171));
|
|
919
919
|
const localUrl = `http://${host}:${port}`;
|
|
920
|
+
const primary = instanceIds[0];
|
|
920
921
|
const runnerOpts = {
|
|
921
922
|
...opts,
|
|
922
923
|
host,
|
|
923
924
|
port,
|
|
924
|
-
token: runnerToken
|
|
925
|
-
instanceId
|
|
925
|
+
token: runnerToken
|
|
926
926
|
};
|
|
927
927
|
const spec = runnerSpawnSpec(runnerOpts);
|
|
928
928
|
const runner = spawn2(spec.command, spec.args, {
|
|
@@ -949,7 +949,7 @@ function createRunnerCommand() {
|
|
|
949
949
|
process.exit(0);
|
|
950
950
|
});
|
|
951
951
|
try {
|
|
952
|
-
await waitForLocalRunner({ url: localUrl, token: runnerToken, instanceId });
|
|
952
|
+
await waitForLocalRunner({ url: localUrl, token: runnerToken, instanceId: primary });
|
|
953
953
|
writeLine(`Local FAGS runtime healthy at ${localUrl}`);
|
|
954
954
|
const cloudflaredPath = await resolveCloudflaredCommand(opts.cloudflared);
|
|
955
955
|
const openTunnel = () => new Promise((resolveTunnel, reject) => {
|
|
@@ -969,14 +969,21 @@ function createRunnerCommand() {
|
|
|
969
969
|
setTimeout(() => reject(new Error("timed out waiting for cloudflared tunnel URL")), 45e3).unref();
|
|
970
970
|
});
|
|
971
971
|
const registerRuntime = async (url) => {
|
|
972
|
-
const capabilities = await requestRunner("GET", "/capabilities", { url: localUrl, token: runnerToken, instanceId });
|
|
973
|
-
|
|
974
|
-
|
|
975
|
-
|
|
976
|
-
|
|
977
|
-
|
|
978
|
-
|
|
979
|
-
|
|
972
|
+
const capabilities = await requestRunner("GET", "/capabilities", { url: localUrl, token: runnerToken, instanceId: primary });
|
|
973
|
+
const caps = Array.isArray(capabilities.capabilities) ? capabilities.capabilities.filter((item) => typeof item === "string") : [];
|
|
974
|
+
for (const id of instanceIds) {
|
|
975
|
+
try {
|
|
976
|
+
await requestPags("POST", `/v1/instances/${apiPathSegment(id)}/runtime`, opts, {
|
|
977
|
+
endpointUrl: url,
|
|
978
|
+
token: runnerToken,
|
|
979
|
+
placement: "local",
|
|
980
|
+
capabilities: caps,
|
|
981
|
+
runnerVersion: clean(opts.runnerVersion) || ""
|
|
982
|
+
});
|
|
983
|
+
} catch (error) {
|
|
984
|
+
writeError(`register ${id.slice(0, 8)}\u2026 failed (${error instanceof Error ? error.message : String(error)}); will retry`);
|
|
985
|
+
}
|
|
986
|
+
}
|
|
980
987
|
};
|
|
981
988
|
const first = await openTunnel();
|
|
982
989
|
tunnel = first.proc;
|
|
@@ -987,17 +994,16 @@ function createRunnerCommand() {
|
|
|
987
994
|
writeLine("Runtime registered with PAGS \u2713");
|
|
988
995
|
writeLine("");
|
|
989
996
|
writeLine("\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550");
|
|
990
|
-
writeLine(" \u2705 CONNECTED \u2014
|
|
991
|
-
writeLine(`
|
|
997
|
+
writeLine(" \u2705 CONNECTED \u2014 runner is live");
|
|
998
|
+
writeLine(` Agents: ${instanceIds.length} instance${instanceIds.length === 1 ? "" : "s"} served by this runner`);
|
|
992
999
|
writeLine(` Tunnel: ${tunnelUrl}`);
|
|
993
1000
|
writeLine(" Auto-reconnect is on \u2014 keep this terminal open. Ctrl+C to disconnect.");
|
|
994
1001
|
writeLine("\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550");
|
|
995
1002
|
let stopped = false;
|
|
996
|
-
const heartbeatPath = `/v1/instances/${apiPathSegment(instanceId)}/runtime/heartbeat`;
|
|
997
1003
|
const probeTunnel = async (url) => {
|
|
998
1004
|
try {
|
|
999
1005
|
const res = await fetch(`${url.replace(/\/$/, "")}/health`, {
|
|
1000
|
-
headers: { Authorization: `Bearer ${runnerToken}`, "X-PAGS-Instance-Id":
|
|
1006
|
+
headers: { Authorization: `Bearer ${runnerToken}`, "X-PAGS-Instance-Id": primary },
|
|
1001
1007
|
signal: AbortSignal.timeout(8e3)
|
|
1002
1008
|
});
|
|
1003
1009
|
return res.ok;
|
|
@@ -1005,12 +1011,20 @@ function createRunnerCommand() {
|
|
|
1005
1011
|
return false;
|
|
1006
1012
|
}
|
|
1007
1013
|
};
|
|
1014
|
+
const heartbeatAll = async () => {
|
|
1015
|
+
let allOk = true;
|
|
1016
|
+
for (const id of instanceIds) {
|
|
1017
|
+
const ok = await requestPags("POST", `/v1/instances/${apiPathSegment(id)}/runtime/heartbeat`, opts, {}).then(() => true).catch(() => false);
|
|
1018
|
+
if (!ok) allOk = false;
|
|
1019
|
+
}
|
|
1020
|
+
return allOk;
|
|
1021
|
+
};
|
|
1008
1022
|
void (async () => {
|
|
1009
1023
|
while (!stopped) {
|
|
1010
1024
|
await new Promise((r) => setTimeout(r, 3e4));
|
|
1011
1025
|
if (stopped) break;
|
|
1012
1026
|
if (await probeTunnel(tunnelUrl)) {
|
|
1013
|
-
const beat = await
|
|
1027
|
+
const beat = await heartbeatAll();
|
|
1014
1028
|
if (!beat) {
|
|
1015
1029
|
await registerRuntime(tunnelUrl).then(() => writeLine("\u2705 Re-registered with PAGS")).catch(() => void 0);
|
|
1016
1030
|
}
|
|
@@ -1317,13 +1331,12 @@ var upCommand = new Command7("up").description("Start the browser runner for all
|
|
|
1317
1331
|
for (const inst of state.instances) {
|
|
1318
1332
|
writeLine(` ${inst.name} (${inst.id.slice(0, 8)}...)`);
|
|
1319
1333
|
}
|
|
1320
|
-
|
|
1321
|
-
state.activeInstance
|
|
1322
|
-
printStep(`Connecting: ${state.activeInstance}`, "wait");
|
|
1334
|
+
state.activeInstance = instances.length === 1 ? instances[0].name || instances[0].slug || instances[0].id.slice(0, 8) : `${instances.length} agents`;
|
|
1335
|
+
printStep(`Connecting ${state.activeInstance}\u2026`, "wait");
|
|
1323
1336
|
await stopRunnerProcesses();
|
|
1324
1337
|
const { spawn: spawn3 } = await import("child_process");
|
|
1325
1338
|
const cliPath = process.argv[1];
|
|
1326
|
-
const args = [cliPath, "runner", "connect",
|
|
1339
|
+
const args = [cliPath, "runner", "connect", ...instances.map((i) => i.id)];
|
|
1327
1340
|
if (opts.headless) args.push("--headless");
|
|
1328
1341
|
const child = spawn3(process.execPath, args, {
|
|
1329
1342
|
stdio: ["ignore", "pipe", "pipe"],
|