@proagentstore/cli 0.4.16 → 0.4.18

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.
@@ -319,8 +319,8 @@ export function buildClaudeArgs(userArgs, resumeId) {
319
319
  return args;
320
320
  }
321
321
  /** Strip ANSI/VT escape sequences so a raw CLI's coloured output reads as plain text. */
322
- // biome-ignore lint/suspicious/noControlCharactersInRegex: stripping terminal escape codes
323
322
  function stripAnsi(s) {
323
+ // biome-ignore lint/suspicious/noControlCharactersInRegex: stripping terminal escape/control codes from terminal output.
324
324
  return s.replace(/\x1b\[[0-9;?]*[ -/]*[@-~]/g, "").replace(/\x1b[()][AB0-2]/g, "").replace(/[\x00-\x08\x0b\x0c\x0e-\x1f]/g, "");
325
325
  }
326
326
  /** Compact a tool_use input object to a single readable line. */
@@ -72,6 +72,7 @@ export function listSessions() {
72
72
  return [];
73
73
  }
74
74
  }
75
+ // biome-ignore lint/suspicious/noControlCharactersInRegex: matching ANSI escape codes from tmux output.
75
76
  const ANSI = /\x1B\[[0-?]*[ -/]*[@-~]/g;
76
77
  /** Strip ANSI escape codes. */
77
78
  export function stripAnsi(s) {
@@ -448,7 +448,7 @@ export class LocalRunner {
448
448
  return null;
449
449
  const buf = Buffer.from(await res.arrayBuffer());
450
450
  const disp = res.headers.get("content-disposition") || "";
451
- const name = (disp.match(/filename="?([^"]+)"?/i)?.[1] || "resume.pdf").replace(/[^\w.\-]/g, "_");
451
+ const name = (disp.match(/filename="?([^"]+)"?/i)?.[1] || "resume.pdf").replace(/[^\w.-]/g, "_");
452
452
  const dir = join(this.config.dataDir, "uploads");
453
453
  mkdirSync(dir, { recursive: true });
454
454
  const dest = join(dir, name);
@@ -1050,7 +1050,7 @@ export class LocalRunner {
1050
1050
  // never resolve → the workflow polls until it times out (15-min wedge, "failed").
1051
1051
  // Report failure so the caller (API/MCP) learns it wasn't accepted, like the
1052
1052
  // no-session branch. (The console already blocks empty; this closes the API path.)
1053
- if (!value || !value.trim())
1053
+ if (!value?.trim())
1054
1054
  return { ok: false };
1055
1055
  session.inputValue = value;
1056
1056
  const task = this.store.getTask(taskId);
@@ -177,7 +177,7 @@ async function route(runner, req, res) {
177
177
  }
178
178
  if (req.method === "POST" && path === "/coding/browse") {
179
179
  const { readdirSync, statSync } = await import("node:fs");
180
- const { resolve, basename } = await import("node:path");
180
+ const { resolve } = await import("node:path");
181
181
  const { homedir } = await import("node:os");
182
182
  const b = await readJson(req);
183
183
  const raw = (b.dir || "~").replace(/^~(?=$|\/)/, homedir());
package/dist/index.js CHANGED
@@ -798,6 +798,7 @@ async function connectViaRelay(instanceIds, localUrl, runnerToken, opts, force =
798
798
  const apiBase = pagsApiBase(opts.apiBase).replace(/^http/, "ws");
799
799
  const pagsToken = clean(opts.pagsToken) || clean(process.env.PAGS_TOKEN) || clean(loadSession()?.token);
800
800
  if (!pagsToken) throw new Error("PAGS token required for WebSocket relay");
801
+ const runnerNode = hostname();
801
802
  const capabilities = await requestRunner("GET", "/capabilities", { url: localUrl, token: runnerToken, instanceId: instanceIds[0] });
802
803
  const caps = Array.isArray(capabilities.capabilities) ? capabilities.capabilities.filter((item) => typeof item === "string") : [];
803
804
  for (const id of instanceIds) {
@@ -808,18 +809,11 @@ async function connectViaRelay(instanceIds, localUrl, runnerToken, opts, force =
808
809
  placement: "local",
809
810
  capabilities: caps,
810
811
  runnerVersion: CLI_VERSION,
811
- runnerNode: hostname(),
812
+ runnerNode,
812
813
  force
813
814
  });
814
815
  } catch (e) {
815
816
  const msg = e instanceof Error ? e.message : String(e);
816
- if (msg.includes("409") && msg.includes("Another machine")) {
817
- writeError(msg);
818
- writeLine("");
819
- writeLine(" To take over, run: pags up --tunnel ws --force");
820
- writeLine("");
821
- throw new Error("Another machine is already connected");
822
- }
823
817
  writeError(`register ${id.slice(0, 8)}\u2026 failed: ${msg}`);
824
818
  }
825
819
  }
@@ -837,7 +831,7 @@ async function connectViaRelay(instanceIds, localUrl, runnerToken, opts, force =
837
831
  const heartbeat = () => {
838
832
  const timer = setTimeout(async () => {
839
833
  for (const id of instanceIds) {
840
- await requestPags("POST", `/v1/instances/${apiPathSegment(id)}/runtime/heartbeat`, opts, {}).catch(() => void 0);
834
+ await requestPags("POST", `/v1/instances/${apiPathSegment(id)}/runtime/heartbeat`, opts, { runnerNode }).catch(() => void 0);
841
835
  }
842
836
  heartbeat();
843
837
  }, 3e4);
@@ -854,6 +848,10 @@ function openRelaySocket(instanceId, wsBase, mintToken, localUrl, runnerToken, f
854
848
  relayToken = await mintToken();
855
849
  } catch (e) {
856
850
  const msg = e instanceof Error ? e.message : String(e);
851
+ if (/^402\b/.test(msg)) {
852
+ writeLine(`Runner unavailable for ${instanceId.slice(0, 8)}\u2026: ${msg.replace(/^402\s*/, "")}`);
853
+ return;
854
+ }
857
855
  const hint = /401|token|sign/i.test(msg) ? " (run `pags login`)" : "";
858
856
  writeLine(`Relay token mint failed: ${instanceId.slice(0, 8)}\u2026${hint} \u2014 retrying in ${Math.round(backoffMs / 1e3)}s`);
859
857
  setTimeout(() => {
@@ -862,7 +860,9 @@ function openRelaySocket(instanceId, wsBase, mintToken, localUrl, runnerToken, f
862
860
  backoffMs = Math.min(backoffMs * 2, 3e4);
863
861
  return;
864
862
  }
865
- const url = `${wsBase}/v1/relay/${encodeURIComponent(instanceId)}/connect?token=${encodeURIComponent(relayToken)}${force ? "&force=1" : ""}`;
863
+ const params = new URLSearchParams({ token: relayToken, node: hostname() });
864
+ if (force) params.set("force", "1");
865
+ const url = `${wsBase}/v1/relay/${encodeURIComponent(instanceId)}/connect?${params.toString()}`;
866
866
  const ws = new WebSocket(url);
867
867
  ws.onopen = () => {
868
868
  backoffMs = 1e3;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@proagentstore/cli",
3
- "version": "0.4.16",
3
+ "version": "0.4.18",
4
4
  "description": "CLI for creating, publishing, and running ProAgentStore agents",
5
5
  "license": "MIT",
6
6
  "type": "module",