@proagentstore/cli 0.1.7 → 0.1.9

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 CHANGED
@@ -1,25 +1,19 @@
1
1
  #!/usr/bin/env node
2
+ import {
3
+ __require,
4
+ runnerCommand,
5
+ writeError,
6
+ writeLine
7
+ } from "./chunk-LNY7MNUC.js";
2
8
 
3
9
  // src/index.ts
4
10
  import { createRequire } from "module";
5
- import { Command as Command6 } from "commander";
11
+ import { Command as Command7 } from "commander";
6
12
 
7
13
  // src/commands/check.ts
8
14
  import { existsSync, readFileSync } from "fs";
9
15
  import { join, resolve } from "path";
10
16
  import { Command } from "commander";
11
-
12
- // src/output.ts
13
- function writeLine(message = "") {
14
- process.stdout.write(`${message}
15
- `);
16
- }
17
- function writeError(message = "") {
18
- process.stderr.write(`${message}
19
- `);
20
- }
21
-
22
- // src/commands/check.ts
23
17
  var checkCommand = new Command("check").description("Run compliance checks on an agent").option("-d, --dir <path>", "Agent directory", ".").action((opts) => {
24
18
  const dir = resolve(opts.dir);
25
19
  const results = [];
@@ -363,9 +357,143 @@ jobs:
363
357
  writeLine();
364
358
  });
365
359
 
360
+ // src/commands/login.ts
361
+ import { existsSync as existsSync3, mkdirSync as mkdirSync2, readFileSync as readFileSync2, writeFileSync as writeFileSync2 } from "fs";
362
+ import { createServer } from "http";
363
+ import { homedir } from "os";
364
+ import { join as join3 } from "path";
365
+ import { Command as Command3 } from "commander";
366
+ var CONFIG_DIR = join3(homedir(), ".config", "proagentstore");
367
+ var TOKEN_FILE = join3(CONFIG_DIR, "session.json");
368
+ var API_BASE = "https://api.proagentstore.online";
369
+ var FAS_API = "https://api.freeappstore.online";
370
+ function loadSession() {
371
+ try {
372
+ if (!existsSync3(TOKEN_FILE)) return null;
373
+ const data = JSON.parse(readFileSync2(TOKEN_FILE, "utf-8"));
374
+ if (data.expiresAt < Date.now()) {
375
+ writeLine("Session expired. Run: pags login");
376
+ return null;
377
+ }
378
+ return data;
379
+ } catch {
380
+ return null;
381
+ }
382
+ }
383
+ function saveSession(session) {
384
+ mkdirSync2(CONFIG_DIR, { recursive: true });
385
+ writeFileSync2(TOKEN_FILE, JSON.stringify(session, null, 2));
386
+ }
387
+ function requireSession() {
388
+ const session = loadSession();
389
+ if (!session) {
390
+ writeError("Not logged in. Run: pags login");
391
+ process.exit(1);
392
+ }
393
+ return session;
394
+ }
395
+ var loginCommand = new Command3("login").description("Sign in with Google or GitHub (opens browser)").option("--github", "Use GitHub instead of Google").action(async (opts) => {
396
+ const provider = opts.github ? "github" : "google";
397
+ writeLine(`Opening browser for ${provider} sign-in...`);
398
+ const port = await findFreePort();
399
+ const callbackUrl = `http://127.0.0.1:${port}/callback`;
400
+ const tokenPromise = new Promise((resolve4, reject) => {
401
+ const timeout = setTimeout(() => {
402
+ server.close();
403
+ reject(new Error("Login timed out (60s)"));
404
+ }, 6e4);
405
+ const server = createServer(async (req, res) => {
406
+ const url = new URL(req.url || "/", `http://127.0.0.1:${port}`);
407
+ if (url.pathname !== "/callback") {
408
+ res.writeHead(404);
409
+ res.end();
410
+ return;
411
+ }
412
+ const fasSession = url.searchParams.get("fas_session");
413
+ if (!fasSession) {
414
+ res.writeHead(400, { "Content-Type": "text/html" });
415
+ res.end("<h1>Sign-in failed</h1><p>No session received.</p>");
416
+ clearTimeout(timeout);
417
+ server.close();
418
+ reject(new Error("No fas_session in callback"));
419
+ return;
420
+ }
421
+ try {
422
+ const exchangeRes = await fetch(`${API_BASE}/v1/auth/exchange`, {
423
+ method: "POST",
424
+ headers: { "Content-Type": "application/json" },
425
+ body: JSON.stringify({ fas_session: fasSession })
426
+ });
427
+ const data = await exchangeRes.json();
428
+ if (!data.token) throw new Error(data.error || "Exchange failed");
429
+ saveSession({
430
+ token: data.token,
431
+ user: data.user,
432
+ expiresAt: Date.now() + 29 * 24 * 60 * 60 * 1e3
433
+ // ~29 days
434
+ });
435
+ res.writeHead(200, { "Content-Type": "text/html" });
436
+ res.end(`<h1>Signed in as ${data.user?.login}</h1><p>You can close this tab and return to the terminal.</p><script>window.close()</script>`);
437
+ clearTimeout(timeout);
438
+ server.close();
439
+ resolve4(data.token);
440
+ } catch (err) {
441
+ res.writeHead(500, { "Content-Type": "text/html" });
442
+ res.end(`<h1>Sign-in failed</h1><p>${err instanceof Error ? err.message : String(err)}</p>`);
443
+ clearTimeout(timeout);
444
+ server.close();
445
+ reject(err);
446
+ }
447
+ });
448
+ server.listen(port, "127.0.0.1");
449
+ });
450
+ const oauthBase = provider === "google" ? `${FAS_API}/v1/auth/google/start` : `${FAS_API}/v1/auth/github/start`;
451
+ const oauthUrl = `${oauthBase}?app_id=pags-cli&response_mode=query&return_to=${encodeURIComponent(callbackUrl)}`;
452
+ const open = (await import("child_process")).exec;
453
+ const cmd = process.platform === "darwin" ? "open" : process.platform === "win32" ? "start" : "xdg-open";
454
+ open(`${cmd} "${oauthUrl}"`);
455
+ try {
456
+ await tokenPromise;
457
+ const session = loadSession();
458
+ writeLine(`Signed in as ${session?.user.login}. Token stored at ${TOKEN_FILE}`);
459
+ } catch (err) {
460
+ writeError(err instanceof Error ? err.message : String(err));
461
+ process.exit(1);
462
+ }
463
+ });
464
+ var logoutCommand = new Command3("logout").description("Sign out and remove stored session").action(() => {
465
+ try {
466
+ if (existsSync3(TOKEN_FILE)) {
467
+ const { unlinkSync } = __require("fs");
468
+ unlinkSync(TOKEN_FILE);
469
+ }
470
+ writeLine("Signed out.");
471
+ } catch {
472
+ writeLine("Already signed out.");
473
+ }
474
+ });
475
+ var whoamiCommand = new Command3("whoami").description("Show current signed-in user").action(() => {
476
+ const session = loadSession();
477
+ if (session) {
478
+ writeLine(`${session.user.login} (${session.user.id})`);
479
+ } else {
480
+ writeLine("Not logged in. Run: pags login");
481
+ }
482
+ });
483
+ async function findFreePort() {
484
+ return new Promise((resolve4) => {
485
+ const server = createServer();
486
+ server.listen(0, "127.0.0.1", () => {
487
+ const addr = server.address();
488
+ const port = typeof addr === "object" && addr ? addr.port : 0;
489
+ server.close(() => resolve4(port));
490
+ });
491
+ });
492
+ }
493
+
366
494
  // src/commands/mcp.ts
367
495
  import { spawn } from "child_process";
368
- import { Command as Command3 } from "commander";
496
+ import { Command as Command4 } from "commander";
369
497
  var DEFAULT_MCP_URL = "https://mcp.proagentstore.online/mcp";
370
498
  function buildMcpRemoteArgs(opts, extraArgs = []) {
371
499
  return ["-y", "mcp-remote", opts.url || DEFAULT_MCP_URL, ...extraArgs];
@@ -375,31 +503,31 @@ async function runMcpProxy(opts, extraArgs = []) {
375
503
  stdio: "inherit",
376
504
  env: process.env
377
505
  });
378
- await new Promise((resolve5, reject) => {
506
+ await new Promise((resolve4, reject) => {
379
507
  child.on("error", reject);
380
508
  child.on("close", (code) => {
381
509
  if (code && code !== 0) reject(new Error(`mcp proxy exited with code ${code}`));
382
- else resolve5();
510
+ else resolve4();
383
511
  });
384
512
  });
385
513
  }
386
- var mcpCommand = new Command3("mcp").description("Run a local stdio proxy for the official ProAgentStore MCP server").option("--url <url>", "Remote MCP endpoint", DEFAULT_MCP_URL).argument("[args...]", "Extra arguments passed to mcp-remote").action(async (args, opts) => {
514
+ var mcpCommand = new Command4("mcp").description("Run a local stdio proxy for the official ProAgentStore MCP server").option("--url <url>", "Remote MCP endpoint", DEFAULT_MCP_URL).argument("[args...]", "Extra arguments passed to mcp-remote").action(async (args, opts) => {
387
515
  await runMcpProxy(opts, args);
388
516
  });
389
517
 
390
518
  // src/commands/publish.ts
391
519
  import { execFileSync } from "child_process";
392
- import { existsSync as existsSync3, readFileSync as readFileSync2 } from "fs";
393
- import { join as join3, resolve as resolve3 } from "path";
394
- import { Command as Command4 } from "commander";
395
- var publishCommand = new Command4("publish").description("Publish an agent to ProAgentStore").option("-d, --dir <path>", "Agent directory", ".").action(async (opts) => {
520
+ import { existsSync as existsSync4, readFileSync as readFileSync3 } from "fs";
521
+ import { join as join4, resolve as resolve3 } from "path";
522
+ import { Command as Command5 } from "commander";
523
+ var publishCommand = new Command5("publish").description("Publish an agent to ProAgentStore").option("-d, --dir <path>", "Agent directory", ".").action(async (opts) => {
396
524
  const dir = resolve3(opts.dir);
397
- const manifestPath = join3(dir, "agent.json");
398
- if (!existsSync3(manifestPath)) {
525
+ const manifestPath = join4(dir, "agent.json");
526
+ if (!existsSync4(manifestPath)) {
399
527
  writeError("No agent.json found. Run `pags init` first.");
400
528
  process.exit(1);
401
529
  }
402
- const manifest = JSON.parse(readFileSync2(manifestPath, "utf-8"));
530
+ const manifest = JSON.parse(readFileSync3(manifestPath, "utf-8"));
403
531
  const slug = manifest.id;
404
532
  if (!slug) {
405
533
  writeError("agent.json missing id");
@@ -470,393 +598,72 @@ var publishCommand = new Command4("publish").description("Publish an agent to Pr
470
598
  writeLine();
471
599
  });
472
600
 
473
- // src/commands/runner.ts
474
- import { spawn as spawn2 } from "child_process";
475
- import { randomUUID } from "crypto";
476
- import { existsSync as existsSync4 } from "fs";
477
- import { resolve as resolve4 } from "path";
478
- import { fileURLToPath as fileURLToPath2 } from "url";
479
- import { Command as Command5 } from "commander";
480
- var runnerCommand = createRunnerCommand();
481
- function runnerBaseUrl(url) {
482
- return (clean(url) || clean(process.env.PAGS_RUNNER_URL) || "http://127.0.0.1:49171").replace(/\/$/, "");
483
- }
484
- function pagsApiBase(url) {
485
- return (clean(url) || clean(process.env.PAGS_API_BASE) || "https://api.proagentstore.online").replace(/\/$/, "");
486
- }
487
- function pagsHeaders(token) {
488
- const resolved = clean(token) || clean(process.env.PAGS_TOKEN);
489
- return resolved ? { Authorization: `Bearer ${resolved}` } : {};
490
- }
491
- function runnerRequestHeaders(opts) {
492
- const resolved = clean(opts.token) || clean(process.env.PAGS_RUNNER_TOKEN);
493
- const headers = resolved ? { Authorization: `Bearer ${resolved}` } : {};
494
- const instanceId = clean(opts.instanceId) || clean(process.env.PAGS_INSTANCE_ID);
495
- if (instanceId) headers["X-PAGS-Instance-Id"] = instanceId;
496
- return headers;
497
- }
498
- function apiPathSegment(value) {
499
- return encodeURIComponent(value);
500
- }
501
- function buildRunnerArgs(opts) {
502
- const args = [];
503
- if (clean(opts.host)) args.push("--host", clean(opts.host));
504
- if (clean(opts.port)) args.push("--port", clean(opts.port));
505
- if (clean(opts.dataDir)) args.push("--data-dir", clean(opts.dataDir));
506
- if (clean(opts.token)) args.push("--token", clean(opts.token));
507
- if (clean(opts.instanceId)) args.push("--instance-id", clean(opts.instanceId));
508
- if (opts.headless) args.push("--headless");
509
- return args;
510
- }
511
- function buildCloudflaredArgs(localUrl) {
512
- return ["tunnel", "--url", localUrl];
513
- }
514
- function parseCloudflaredTunnelUrl(text) {
515
- return text.match(/https:\/\/[a-z0-9-]+\.trycloudflare\.com/i)?.[0] || null;
516
- }
517
- function buildRuntimeRegistrationBody(opts, capabilities = []) {
518
- return {
519
- endpointUrl: clean(opts.endpointUrl) || opts.endpointUrl,
520
- token: clean(opts.runnerToken) || clean(opts.token) || clean(process.env.PAGS_RUNNER_TOKEN),
521
- placement: opts.placement === "managed" ? "managed" : "local",
522
- capabilities,
523
- runnerVersion: clean(opts.runnerVersion) || ""
524
- };
525
- }
526
- function clean(value) {
527
- const trimmed = value?.trim();
528
- return trimmed || void 0;
529
- }
530
- function findWorkspaceRoot() {
531
- let dir = process.cwd();
532
- for (let i = 0; i < 8; i++) {
533
- if (existsSync4(resolve4(dir, "pnpm-workspace.yaml"))) return dir;
534
- const parent = resolve4(dir, "..");
535
- if (parent === dir) break;
536
- dir = parent;
537
- }
538
- return process.cwd();
539
- }
540
- function bundledRunnerPath() {
541
- return fileURLToPath2(new URL("./browser-runner/index.js", import.meta.url));
542
- }
543
- function runnerSpawnSpec(opts) {
544
- const root = findWorkspaceRoot();
545
- const localPackage = resolve4(root, "packages", "browser-runner", "src", "index.ts");
546
- const bundledPackage = bundledRunnerPath();
547
- const runnerArgs = buildRunnerArgs(opts);
548
- let cwd = root;
549
- let command = "pags-browser-runner";
550
- let args = runnerArgs;
551
- if (existsSync4(localPackage)) {
552
- command = "pnpm";
553
- args = ["--filter", "@proagentstore/browser-runner", "dev", "--", ...runnerArgs];
554
- } else if (existsSync4(bundledPackage)) {
555
- cwd = process.cwd();
556
- command = process.execPath;
557
- args = [bundledPackage, ...runnerArgs];
558
- }
559
- return { command, args, cwd };
560
- }
561
- function startRunnerForeground(opts) {
562
- const spec = runnerSpawnSpec(opts);
563
- return new Promise((resolvePromise, reject) => {
564
- const child = spawn2(spec.command, spec.args, {
565
- cwd: spec.cwd,
566
- stdio: "inherit",
567
- shell: process.platform === "win32"
568
- });
569
- child.on("error", reject);
570
- child.on("exit", (code) => {
571
- if (code && code !== 0) reject(new Error(`runner exited with code ${code}`));
572
- else resolvePromise();
573
- });
574
- });
575
- }
576
- async function waitForLocalRunner(opts, timeoutMs = 15e3) {
577
- const started = Date.now();
578
- let lastError;
579
- while (Date.now() - started < timeoutMs) {
580
- try {
581
- await requestRunner("GET", "/health", opts);
582
- return;
583
- } catch (error) {
584
- lastError = error;
585
- await new Promise((resolvePromise) => setTimeout(resolvePromise, 500));
586
- }
587
- }
588
- throw new Error(`runner did not become healthy: ${lastError instanceof Error ? lastError.message : String(lastError)}`);
589
- }
590
- async function requestRunner(method, path, opts, body) {
591
- const headers = {
592
- ...runnerRequestHeaders(opts)
593
- };
594
- if (body !== void 0) headers["Content-Type"] = "application/json";
595
- const res = await fetch(`${runnerBaseUrl(opts.url)}${path}`, {
596
- method,
597
- headers,
598
- body: body === void 0 ? void 0 : JSON.stringify(body)
601
+ // src/commands/up.ts
602
+ import { Command as Command6 } from "commander";
603
+ var API_BASE2 = "https://api.proagentstore.online";
604
+ var upCommand = new Command6("up").description("Start the browser runner for all your agent instances").option("--headless", "Run browser in headless mode").option("--instance <id>", "Connect to a specific instance only").action(async (opts) => {
605
+ const session = requireSession();
606
+ writeLine(`Signed in as ${session.user.login}`);
607
+ writeLine("Fetching your instances...");
608
+ const res = await fetch(`${API_BASE2}/v1/instances/my/instances`, {
609
+ headers: { Authorization: `Bearer ${session.token}` }
599
610
  });
600
- const { text, data } = await readResponse(res);
601
611
  if (!res.ok) {
602
- const message = responseErrorMessage(data, text, res.statusText);
603
- throw new Error(`${res.status} ${message}`);
612
+ writeError(`Failed to fetch instances: ${res.status}`);
613
+ process.exit(1);
604
614
  }
605
- return data;
606
- }
607
- async function requestPags(method, path, opts, body) {
608
- const headers = {
609
- ...pagsHeaders(opts.pagsToken)
610
- };
611
- if (!headers.Authorization) {
612
- throw new Error("PAGS token required. Set PAGS_TOKEN or pass --pags-token.");
615
+ const data = await res.json();
616
+ let instances = (data.instances || []).filter((i) => i.status === "active");
617
+ if (opts.instance) {
618
+ instances = instances.filter((i) => i.id === opts.instance || i.slug === opts.instance);
613
619
  }
614
- if (body !== void 0) headers["Content-Type"] = "application/json";
615
- const res = await fetch(`${pagsApiBase(opts.apiBase)}${path}`, {
616
- method,
617
- headers,
618
- body: body === void 0 ? void 0 : JSON.stringify(body)
619
- });
620
- const { text, data } = await readResponse(res);
621
- if (!res.ok) {
622
- const message = responseErrorMessage(data, text, res.statusText);
623
- throw new Error(`${res.status} ${message}`);
620
+ if (instances.length === 0) {
621
+ writeError("No active instances found. Subscribe to an agent first at https://proagentstore.online");
622
+ process.exit(1);
624
623
  }
625
- return data;
626
- }
627
- async function readResponse(res) {
628
- const text = await res.text();
629
- if (!text) return { text, data: {} };
624
+ writeLine(`Found ${instances.length} instance${instances.length === 1 ? "" : "s"}:`);
625
+ for (const inst of instances) {
626
+ writeLine(` ${inst.name || inst.slug || inst.id.slice(0, 8)} (${inst.id.slice(0, 8)}...)`);
627
+ }
628
+ const target = instances[0];
629
+ writeLine(`
630
+ Connecting runner to: ${target.name || target.id.slice(0, 8)}...`);
631
+ const { runnerCommand: runnerCommand2 } = await import("./runner-CM72EPKQ.js");
632
+ const connectCmd = runnerCommand2.commands.find((c) => c.name() === "connect");
633
+ if (!connectCmd) {
634
+ writeError("Runner connect command not found");
635
+ process.exit(1);
636
+ }
637
+ const args = [
638
+ "node",
639
+ "pags",
640
+ "runner",
641
+ "connect",
642
+ target.id,
643
+ "--pags-token",
644
+ session.token
645
+ ];
646
+ if (opts.headless) args.push("--headless");
647
+ process.argv = args;
630
648
  try {
631
- return { text, data: JSON.parse(text) };
632
- } catch {
633
- return { text, data: {} };
649
+ await connectCmd.parseAsync(args.slice(2), { from: "user" });
650
+ } catch (err) {
651
+ writeError(err instanceof Error ? err.message : String(err));
652
+ process.exit(1);
634
653
  }
635
- }
636
- function responseErrorMessage(data, text, statusText) {
637
- return typeof data.error === "string" ? data.error : text || statusText;
638
- }
639
- function collectCapability(value, previous = []) {
640
- return [...previous, value];
641
- }
642
- function createRunnerCommand() {
643
- const command = new Command5("runner").description(
644
- "Manage a local ProAgentStore browser runner"
645
- );
646
- command.command("start").description("Start the local browser runner 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) => {
647
- await startRunnerForeground(opts);
648
- });
649
- command.command("connect <instanceId>").description("Start a local runner, open a Cloudflare quick tunnel, and register it with PAGS").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", "cloudflared").option("--runner-version <version>", "Runner version").option("--skip-probe", "Skip PAGS runtime probe after registration").action(async (instanceId, opts) => {
650
- const runnerToken = clean(opts.token) || clean(process.env.PAGS_RUNNER_TOKEN) || `pags_runner_${randomUUID()}`;
651
- const host = clean(opts.host) || "127.0.0.1";
652
- const port = clean(opts.port) || "49171";
653
- const localUrl = `http://${host}:${port}`;
654
- const runnerOpts = {
655
- ...opts,
656
- host,
657
- port,
658
- token: runnerToken,
659
- instanceId
660
- };
661
- const spec = runnerSpawnSpec(runnerOpts);
662
- const runner = spawn2(spec.command, spec.args, {
663
- cwd: spec.cwd,
664
- stdio: ["ignore", "pipe", "pipe"],
665
- shell: process.platform === "win32"
666
- });
667
- runner.stdout?.on("data", (data) => process.stdout.write(data));
668
- runner.stderr?.on("data", (data) => process.stderr.write(data));
669
- runner.on("exit", (code) => {
670
- if (code && code !== 0) writeError(`runner exited with code ${code}`);
671
- });
672
- let tunnel = null;
673
- const shutdown = () => {
674
- if (tunnel && !tunnel.killed) tunnel.kill("SIGTERM");
675
- if (!runner.killed) runner.kill("SIGTERM");
676
- };
677
- process.once("SIGINT", () => {
678
- shutdown();
679
- process.exit(0);
680
- });
681
- process.once("SIGTERM", () => {
682
- shutdown();
683
- process.exit(0);
684
- });
685
- try {
686
- await waitForLocalRunner({ url: localUrl, token: runnerToken, instanceId });
687
- writeLine(`Local runner healthy at ${localUrl}`);
688
- const tunnelUrl = await new Promise((resolveTunnel, reject) => {
689
- let output = "";
690
- const cloudflared = clean(opts.cloudflared) || "cloudflared";
691
- tunnel = spawn2(cloudflared, buildCloudflaredArgs(localUrl), {
692
- stdio: ["ignore", "pipe", "pipe"],
693
- shell: process.platform === "win32"
694
- });
695
- const onData = (data) => {
696
- const text = data.toString("utf-8");
697
- output += text;
698
- process.stderr.write(text);
699
- const parsed = parseCloudflaredTunnelUrl(output);
700
- if (parsed) resolveTunnel(parsed);
701
- };
702
- tunnel.stdout?.on("data", onData);
703
- tunnel.stderr?.on("data", onData);
704
- tunnel.on("error", reject);
705
- tunnel.on("exit", (code) => {
706
- if (code && code !== 0) reject(new Error(`cloudflared exited with code ${code}`));
707
- });
708
- setTimeout(() => reject(new Error("timed out waiting for cloudflared tunnel URL")), 45e3).unref();
709
- });
710
- writeLine(`Tunnel ready: ${tunnelUrl}`);
711
- await waitForLocalRunner({ url: tunnelUrl, token: runnerToken, instanceId }, 3e4);
712
- writeLine("Tunnel health check passed");
713
- const capabilities = await requestRunner("GET", "/capabilities", {
714
- url: tunnelUrl,
715
- token: runnerToken,
716
- instanceId
717
- });
718
- const result = await requestPags("POST", `/v1/instances/${apiPathSegment(instanceId)}/runtime`, opts, {
719
- endpointUrl: tunnelUrl,
720
- token: runnerToken,
721
- placement: "local",
722
- capabilities: Array.isArray(capabilities.capabilities) ? capabilities.capabilities.filter((item) => typeof item === "string") : [],
723
- runnerVersion: clean(opts.runnerVersion) || ""
724
- });
725
- writeLine(JSON.stringify(result, null, 2));
726
- if (!opts.skipProbe) {
727
- const status = await requestPags(
728
- "GET",
729
- `/v1/instances/${apiPathSegment(instanceId)}/runtime/status`,
730
- opts
731
- );
732
- writeLine(JSON.stringify(status, null, 2));
733
- }
734
- writeLine("Connected. Keep this process running while the agent uses your local browser.");
735
- await new Promise((resolvePromise) => {
736
- runner.on("exit", () => resolvePromise());
737
- tunnel?.on("exit", () => resolvePromise());
738
- });
739
- } catch (error) {
740
- shutdown();
741
- throw error;
742
- }
743
- });
744
- command.command("status").description("Check local runner health and capabilities").option("--url <url>", "Runner URL").option("--token <token>", "Runner bearer token").option("--instance-id <id>", "PAGS instance id header").action(async (opts) => {
745
- const health = await requestRunner("GET", "/health", opts);
746
- const capabilities = await requestRunner("GET", "/capabilities", opts);
747
- writeLine(JSON.stringify({ health, capabilities }, null, 2));
748
- });
749
- command.command("task").description("Create a runner task").requiredOption("--type <type>", "Task type, e.g. echo or browser.open").option("--url <url>", "Runner URL").option("--token <token>", "Runner bearer token").option("--instance-id <id>", "PAGS instance id header").option("--input <json>", "Task input JSON").option("--job-url <url>", "Shortcut input for browser.open").option("--approve", "Create task in needs_approval state").option("--approval-prompt <text>", "Approval prompt").action(
750
- async (opts) => {
751
- let input = {};
752
- if (opts.input) {
753
- try {
754
- input = JSON.parse(opts.input);
755
- } catch {
756
- writeError("--input must be valid JSON");
757
- process.exit(1);
758
- }
759
- }
760
- if (opts.jobUrl) input.url = opts.jobUrl;
761
- const task = await requestRunner("POST", "/tasks", opts, {
762
- type: opts.type,
763
- input,
764
- requiresApproval: Boolean(opts.approve),
765
- approvalPrompt: opts.approvalPrompt
766
- });
767
- writeLine(JSON.stringify(task, null, 2));
768
- }
769
- );
770
- command.command("register <instanceId>").description("Register a local or managed runner endpoint with a PAGS instance").requiredOption("--endpoint-url <url>", "Runner endpoint URL to store in PAGS").option("--api-base <url>", "PAGS API base URL").option("--pags-token <token>", "PAGS session token. Defaults to PAGS_TOKEN").option("--runner-token <token>", "Runner bearer token to store in PAGS").option("--url <url>", "Local runner URL to probe for capabilities").option("--token <token>", "Local runner bearer token for capability probe").option("--instance-id <id>", "PAGS instance id header for capability probe").option("--placement <placement>", "Runtime placement: local or managed", "local").option("--runner-version <version>", "Runner version").option("--capability <name>", "Runtime capability; repeatable", collectCapability, []).option("--probe", "Read capabilities from the runner before registering").action(async (instanceId, opts) => {
771
- let capabilities = opts.capability || [];
772
- if (opts.probe) {
773
- const data = await requestRunner("GET", "/capabilities", {
774
- url: opts.url || opts.endpointUrl,
775
- token: opts.token || opts.runnerToken,
776
- instanceId: opts.instanceId || instanceId
777
- });
778
- capabilities = Array.isArray(data.capabilities) ? data.capabilities.filter((item) => typeof item === "string") : capabilities;
779
- }
780
- const body = buildRuntimeRegistrationBody(opts, capabilities);
781
- const result = await requestPags("POST", `/v1/instances/${apiPathSegment(instanceId)}/runtime`, opts, body);
782
- writeLine(JSON.stringify(result, null, 2));
783
- });
784
- command.command("runtime <instanceId>").description("Read the PAGS runtime registration for an instance").option("--api-base <url>", "PAGS API base URL").option("--pags-token <token>", "PAGS session token. Defaults to PAGS_TOKEN").option("--probe", "Ask PAGS to probe /health and /capabilities on the runner").action(async (instanceId, opts) => {
785
- const path = opts.probe ? `/v1/instances/${apiPathSegment(instanceId)}/runtime/status` : `/v1/instances/${apiPathSegment(instanceId)}/runtime`;
786
- const result = await requestPags("GET", path, opts);
787
- writeLine(JSON.stringify(result, null, 2));
788
- });
789
- command.command("unregister <instanceId>").description("Remove the PAGS runtime registration for an instance").option("--api-base <url>", "PAGS API base URL").option("--pags-token <token>", "PAGS session token. Defaults to PAGS_TOKEN").action(async (instanceId, opts) => {
790
- const result = await requestPags("DELETE", `/v1/instances/${apiPathSegment(instanceId)}/runtime`, opts);
791
- writeLine(JSON.stringify(result, null, 2));
792
- });
793
- command.command("run <instanceId>").description("Create a task through PAGS on an instance's registered runner").requiredOption("--type <type>", "Task type, e.g. echo or browser.open").option("--api-base <url>", "PAGS API base URL").option("--pags-token <token>", "PAGS session token. Defaults to PAGS_TOKEN").option("--input <json>", "Task input JSON").option("--job-url <url>", "Shortcut input for browser.open").option("--approve", "Create task in needs_approval state").option("--approval-prompt <text>", "Approval prompt").action(
794
- async (instanceId, opts) => {
795
- let input = {};
796
- if (opts.input) {
797
- try {
798
- input = JSON.parse(opts.input);
799
- } catch {
800
- writeError("--input must be valid JSON");
801
- process.exit(1);
802
- }
803
- }
804
- if (opts.jobUrl) input.url = opts.jobUrl;
805
- const result = await requestPags("POST", `/v1/instances/${apiPathSegment(instanceId)}/tasks`, opts, {
806
- type: opts.type,
807
- input,
808
- requiresApproval: Boolean(opts.approve),
809
- approvalPrompt: opts.approvalPrompt
810
- });
811
- writeLine(JSON.stringify(result, null, 2));
812
- }
813
- );
814
- command.command("approve-task <instanceId> <taskId>").description("Approve a registered-runner task through PAGS").option("--api-base <url>", "PAGS API base URL").option("--pags-token <token>", "PAGS session token. Defaults to PAGS_TOKEN").action(async (instanceId, taskId, opts) => {
815
- const result = await requestPags(
816
- "POST",
817
- `/v1/instances/${apiPathSegment(instanceId)}/tasks/${apiPathSegment(taskId)}/approve`,
818
- opts
819
- );
820
- writeLine(JSON.stringify(result, null, 2));
821
- });
822
- command.command("cancel-task <instanceId> <taskId>").description("Cancel a registered-runner task through PAGS").option("--api-base <url>", "PAGS API base URL").option("--pags-token <token>", "PAGS session token. Defaults to PAGS_TOKEN").action(async (instanceId, taskId, opts) => {
823
- const result = await requestPags(
824
- "POST",
825
- `/v1/instances/${apiPathSegment(instanceId)}/tasks/${apiPathSegment(taskId)}/cancel`,
826
- opts
827
- );
828
- writeLine(JSON.stringify(result, null, 2));
829
- });
830
- command.command("task-events <instanceId>").description("Read registered-runner task events through PAGS").option("--api-base <url>", "PAGS API base URL").option("--pags-token <token>", "PAGS session token. Defaults to PAGS_TOKEN").option("--limit <n>", "Number of events", "50").action(async (instanceId, opts) => {
831
- const result = await requestPags(
832
- "GET",
833
- `/v1/instances/${apiPathSegment(instanceId)}/task-events?limit=${Number(opts.limit) || 50}`,
834
- opts
835
- );
836
- writeLine(JSON.stringify(result, null, 2));
837
- });
838
- command.command("approve <taskId>").description("Approve a task waiting on human approval").option("--url <url>", "Runner URL").option("--token <token>", "Runner bearer token").option("--instance-id <id>", "PAGS instance id header").action(async (taskId, opts) => {
839
- const task = await requestRunner("POST", `/tasks/${apiPathSegment(taskId)}/approve`, opts);
840
- writeLine(JSON.stringify(task, null, 2));
841
- });
842
- command.command("cancel <taskId>").description("Cancel a local runner task").option("--url <url>", "Runner URL").option("--token <token>", "Runner bearer token").option("--instance-id <id>", "PAGS instance id header").action(async (taskId, opts) => {
843
- const task = await requestRunner("POST", `/tasks/${apiPathSegment(taskId)}/cancel`, opts);
844
- writeLine(JSON.stringify(task, null, 2));
845
- });
846
- command.command("events").description("List recent runner events").option("--url <url>", "Runner URL").option("--token <token>", "Runner bearer token").option("--instance-id <id>", "PAGS instance id header").option("--limit <n>", "Number of events", "50").action(async (opts) => {
847
- const events = await requestRunner("GET", `/events?limit=${Number(opts.limit) || 50}`, opts);
848
- writeLine(JSON.stringify(events, null, 2));
849
- });
850
- return command;
851
- }
654
+ });
852
655
 
853
656
  // src/index.ts
854
657
  var require2 = createRequire(import.meta.url);
855
658
  var { version } = require2("../package.json");
856
- var program = new Command6();
659
+ var program = new Command7();
857
660
  program.name("pags").description(
858
661
  "ProAgentStore CLI \u2014 create and publish server-powered AI agents"
859
662
  ).version(version);
663
+ program.addCommand(loginCommand);
664
+ program.addCommand(logoutCommand);
665
+ program.addCommand(whoamiCommand);
666
+ program.addCommand(upCommand);
860
667
  program.addCommand(initCommand);
861
668
  program.addCommand(checkCommand);
862
669
  program.addCommand(publishCommand);