@proagentstore/cli 0.3.1 → 0.3.3
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/browser-runner/index.js +11 -0
- package/dist/index.js +31 -20
- package/package.json +44 -44
|
@@ -55,6 +55,17 @@ Endpoints:
|
|
|
55
55
|
process.exit(0);
|
|
56
56
|
}
|
|
57
57
|
const config = configFromArgs();
|
|
58
|
+
// SECURITY: the runner's endpoints spawn CLIs and drive a browser as the user.
|
|
59
|
+
// Without a token, `authorize()` allows every request, so a tokenless runner must
|
|
60
|
+
// never be reachable off the local machine. Refuse to start if bound to a
|
|
61
|
+
// non-loopback address without a token. (`pags up` always generates one; this
|
|
62
|
+
// only guards the low-level binary run manually with --host 0.0.0.0 and no token.)
|
|
63
|
+
const LOOPBACK = new Set(["127.0.0.1", "localhost", "::1", "[::1]"]);
|
|
64
|
+
if (!config.token && !LOOPBACK.has(config.host)) {
|
|
65
|
+
process.stderr.write(`Refusing to start: --host ${config.host} exposes the runner off-machine with no --token. ` +
|
|
66
|
+
`Set --token (or PAGS_RUNNER_TOKEN), or bind to 127.0.0.1.\n`);
|
|
67
|
+
process.exit(1);
|
|
68
|
+
}
|
|
58
69
|
const started = await startRunnerServer(config);
|
|
59
70
|
process.stdout.write(`FAGS browser runtime listening at ${started.url}\n`);
|
|
60
71
|
process.stdout.write(`Data dir: ${config.dataDir}\n`);
|
package/dist/index.js
CHANGED
|
@@ -379,7 +379,6 @@ import { Command as Command3 } from "commander";
|
|
|
379
379
|
var CONFIG_DIR = join3(homedir(), ".config", "proagentstore");
|
|
380
380
|
var TOKEN_FILE = join3(CONFIG_DIR, "session.json");
|
|
381
381
|
var API_BASE = "https://api.proagentstore.online";
|
|
382
|
-
var FAS_API = "https://api.freeappstore.online";
|
|
383
382
|
function loadSession() {
|
|
384
383
|
try {
|
|
385
384
|
if (!existsSync3(TOKEN_FILE)) return null;
|
|
@@ -422,34 +421,32 @@ var loginCommand = new Command3("login").description("Sign in with Google or Git
|
|
|
422
421
|
res.end();
|
|
423
422
|
return;
|
|
424
423
|
}
|
|
425
|
-
const
|
|
426
|
-
if (!
|
|
424
|
+
const session = url.searchParams.get("session");
|
|
425
|
+
if (!session) {
|
|
427
426
|
res.writeHead(400, { "Content-Type": "text/html" });
|
|
428
427
|
res.end("<h1>Sign-in failed</h1><p>No session received.</p>");
|
|
429
428
|
clearTimeout(timeout);
|
|
430
429
|
server.close();
|
|
431
|
-
reject(new Error("No
|
|
430
|
+
reject(new Error("No session in callback"));
|
|
432
431
|
return;
|
|
433
432
|
}
|
|
434
433
|
try {
|
|
435
|
-
const
|
|
436
|
-
|
|
437
|
-
headers: { "Content-Type": "application/json" },
|
|
438
|
-
body: JSON.stringify({ fas_session: fasSession })
|
|
434
|
+
const meRes = await fetch(`${API_BASE}/v1/auth/me`, {
|
|
435
|
+
headers: { Authorization: `Bearer ${session}` }
|
|
439
436
|
});
|
|
440
|
-
|
|
441
|
-
|
|
437
|
+
if (!meRes.ok) throw new Error("Session validation failed");
|
|
438
|
+
const me = await meRes.json();
|
|
442
439
|
saveSession({
|
|
443
|
-
token:
|
|
444
|
-
user:
|
|
440
|
+
token: session,
|
|
441
|
+
user: { id: me.id, login: me.login, avatar: me.avatar },
|
|
445
442
|
expiresAt: Date.now() + 29 * 24 * 60 * 60 * 1e3
|
|
446
443
|
// ~29 days
|
|
447
444
|
});
|
|
448
445
|
res.writeHead(200, { "Content-Type": "text/html" });
|
|
449
|
-
res.end(`<h1>Signed in as ${
|
|
446
|
+
res.end(`<h1>Signed in as ${me.login}</h1><p>You can close this tab and return to the terminal.</p><script>window.close()</script>`);
|
|
450
447
|
clearTimeout(timeout);
|
|
451
448
|
server.close();
|
|
452
|
-
resolve5(
|
|
449
|
+
resolve5(session);
|
|
453
450
|
} catch (err) {
|
|
454
451
|
res.writeHead(500, { "Content-Type": "text/html" });
|
|
455
452
|
res.end(`<h1>Sign-in failed</h1><p>${err instanceof Error ? err.message : String(err)}</p>`);
|
|
@@ -460,8 +457,8 @@ var loginCommand = new Command3("login").description("Sign in with Google or Git
|
|
|
460
457
|
});
|
|
461
458
|
server.listen(port, "127.0.0.1");
|
|
462
459
|
});
|
|
463
|
-
const oauthBase = provider === "google" ? `${
|
|
464
|
-
const oauthUrl = `${oauthBase}?
|
|
460
|
+
const oauthBase = provider === "google" ? `${API_BASE}/v1/auth/google/start` : `${API_BASE}/v1/auth/github/start`;
|
|
461
|
+
const oauthUrl = `${oauthBase}?return_to=${encodeURIComponent(callbackUrl)}`;
|
|
465
462
|
const open = (await import("child_process")).exec;
|
|
466
463
|
const cmd = process.platform === "darwin" ? "open" : process.platform === "win32" ? "start" : "xdg-open";
|
|
467
464
|
open(`${cmd} "${oauthUrl}"`);
|
|
@@ -827,7 +824,8 @@ async function connectViaRelay(instanceIds, localUrl, runnerToken, opts, force =
|
|
|
827
824
|
}
|
|
828
825
|
}
|
|
829
826
|
for (const id of instanceIds) {
|
|
830
|
-
|
|
827
|
+
const mintToken = () => requestPags("POST", `/v1/relay/${apiPathSegment(id)}/token`, { ...opts, pagsToken }, {}).then((r) => r.token);
|
|
828
|
+
openRelaySocket(id, apiBase, mintToken, localUrl, runnerToken, force);
|
|
831
829
|
}
|
|
832
830
|
writeLine("Runtime registered with PAGS \u2713");
|
|
833
831
|
writeLine("");
|
|
@@ -847,11 +845,24 @@ async function connectViaRelay(instanceIds, localUrl, runnerToken, opts, force =
|
|
|
847
845
|
};
|
|
848
846
|
heartbeat();
|
|
849
847
|
}
|
|
850
|
-
function openRelaySocket(instanceId, wsBase,
|
|
848
|
+
function openRelaySocket(instanceId, wsBase, mintToken, localUrl, runnerToken, force = false) {
|
|
851
849
|
let backoffMs = 1e3;
|
|
852
850
|
let reconnecting = false;
|
|
853
|
-
const connect = () => {
|
|
854
|
-
|
|
851
|
+
const connect = async () => {
|
|
852
|
+
let relayToken;
|
|
853
|
+
try {
|
|
854
|
+
relayToken = await mintToken();
|
|
855
|
+
} catch (e) {
|
|
856
|
+
const msg = e instanceof Error ? e.message : String(e);
|
|
857
|
+
const hint = /401|token|sign/i.test(msg) ? " (run `pags login`)" : "";
|
|
858
|
+
writeLine(`Relay token mint failed: ${instanceId.slice(0, 8)}\u2026${hint} \u2014 retrying in ${Math.round(backoffMs / 1e3)}s`);
|
|
859
|
+
setTimeout(() => {
|
|
860
|
+
connect();
|
|
861
|
+
}, backoffMs);
|
|
862
|
+
backoffMs = Math.min(backoffMs * 2, 3e4);
|
|
863
|
+
return;
|
|
864
|
+
}
|
|
865
|
+
const url = `${wsBase}/v1/relay/${encodeURIComponent(instanceId)}/connect?token=${encodeURIComponent(relayToken)}${force ? "&force=1" : ""}`;
|
|
855
866
|
const ws = new WebSocket(url);
|
|
856
867
|
ws.onopen = () => {
|
|
857
868
|
backoffMs = 1e3;
|
package/package.json
CHANGED
|
@@ -1,46 +1,46 @@
|
|
|
1
1
|
{
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
2
|
+
"name": "@proagentstore/cli",
|
|
3
|
+
"version": "0.3.3",
|
|
4
|
+
"description": "CLI for creating, publishing, and running ProAgentStore agents",
|
|
5
|
+
"license": "MIT",
|
|
6
|
+
"type": "module",
|
|
7
|
+
"bin": {
|
|
8
|
+
"pags": "dist/index.js"
|
|
9
|
+
},
|
|
10
|
+
"homepage": "https://github.com/ProAgentStore/platform#readme",
|
|
11
|
+
"repository": {
|
|
12
|
+
"type": "git",
|
|
13
|
+
"url": "git+https://github.com/ProAgentStore/platform.git",
|
|
14
|
+
"directory": "packages/cli"
|
|
15
|
+
},
|
|
16
|
+
"keywords": [
|
|
17
|
+
"proagentstore",
|
|
18
|
+
"pags",
|
|
19
|
+
"cli",
|
|
20
|
+
"agents",
|
|
21
|
+
"mcp",
|
|
22
|
+
"browser-runner"
|
|
23
|
+
],
|
|
24
|
+
"publishConfig": {
|
|
25
|
+
"access": "public"
|
|
26
|
+
},
|
|
27
|
+
"scripts": {
|
|
28
|
+
"build": "pnpm --filter @proagentstore/browser-runner build && tsup src/index.ts --format esm --dts && node scripts/copy-browser-runner.mjs",
|
|
29
|
+
"dev": "tsx src/index.ts",
|
|
30
|
+
"typecheck": "tsc --noEmit"
|
|
31
|
+
},
|
|
32
|
+
"dependencies": {
|
|
33
|
+
"chalk": "^5.6.2",
|
|
34
|
+
"commander": "^13.0.0",
|
|
35
|
+
"playwright": "^1.60.0"
|
|
36
|
+
},
|
|
37
|
+
"devDependencies": {
|
|
38
|
+
"@types/node": "^22.0.0",
|
|
39
|
+
"tsup": "^8.4.0",
|
|
40
|
+
"tsx": "^4.21.0",
|
|
41
|
+
"typescript": "^5.7.0"
|
|
42
|
+
},
|
|
43
|
+
"files": [
|
|
44
|
+
"dist"
|
|
45
|
+
]
|
|
46
46
|
}
|