@proagentstore/cli 0.4.45 → 0.4.46

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.
@@ -111,6 +111,47 @@ export function runCommand(target, command) {
111
111
  sendText(target, command);
112
112
  sendKey(target, "Enter");
113
113
  }
114
+ /**
115
+ * Settle heuristic constants — mirror the Coder headless.ts values (1.5s quiet = idle;
116
+ * 8s absolute backstop for a slow-booting CLI). The short backstop covers send/run where
117
+ * the pane is already live; the long one is for new-session launches where the CLI may
118
+ * take several seconds to paint its first prompt.
119
+ */
120
+ export const SETTLE_QUIET_MS = 750;
121
+ export const SETTLE_POLL_MS = 120;
122
+ export const SETTLE_TIMEOUT_MS = 8_000;
123
+ /**
124
+ * Poll-capture a pane until its content is unchanged for `quietMs` ms, or until
125
+ * `timeoutMs` elapses (backstop so a continuously-animated pane can't hang the tool).
126
+ *
127
+ * Returns the final pane content. This is the write-side analogue of the read-side labels
128
+ * in `terminal-label.ts`: before returning "Sent", we verify the pane has reacted.
129
+ *
130
+ * Pure behaviour — no side effects beyond calling `capturePane`; tested in unit tests
131
+ * without a real tmux by passing a custom `captureFn`.
132
+ */
133
+ export async function waitForPaneSettle(target, opts = {}) {
134
+ const quietMs = opts.quietMs ?? SETTLE_QUIET_MS;
135
+ const timeoutMs = opts.timeoutMs ?? SETTLE_TIMEOUT_MS;
136
+ const pollMs = opts.pollMs ?? SETTLE_POLL_MS;
137
+ const capture = opts.captureFn ?? ((t) => capturePane(t));
138
+ const deadline = Date.now() + timeoutMs;
139
+ let last = capture(target);
140
+ let lastChangedAt = Date.now();
141
+ while (true) {
142
+ await new Promise((r) => setTimeout(r, pollMs));
143
+ const now = Date.now();
144
+ const current = capture(target);
145
+ if (current !== last) {
146
+ last = current;
147
+ lastChangedAt = now;
148
+ }
149
+ const quietFor = now - lastChangedAt;
150
+ if (quietFor >= quietMs || now >= deadline) {
151
+ return last;
152
+ }
153
+ }
154
+ }
114
155
  // biome-ignore lint/suspicious/noControlCharactersInRegex: matching ANSI escape codes from tmux output.
115
156
  const ANSI = /\x1B\[[0-?]*[ -/]*[@-~]/g;
116
157
  /** Strip ANSI escape codes. */
@@ -305,24 +305,29 @@ async function route(runner, req, res) {
305
305
  return json(res, 200, { session, pane: capturePane(session, lines) });
306
306
  }
307
307
  if (req.method === "POST" && path === "/tmux/send") {
308
- const { sendText, sendKey, capturePane, sessionExists } = await import("./coding/tmux.js");
308
+ const { sendText, sendKey, capturePane, sessionExists, waitForPaneSettle } = await import("./coding/tmux.js");
309
309
  const b = await readJson(req);
310
310
  const session = String(b.session || "").trim();
311
311
  if (!session)
312
312
  return json(res, 400, { error: "A `session` name is required." });
313
313
  if (!sessionExists(session))
314
314
  return json(res, 404, { error: `No tmux session "${session}".` });
315
+ // Capture BEFORE the send so the caller can verify what changed (#481).
316
+ const paneBefore = capturePane(session, 200);
315
317
  if (b.text != null)
316
318
  sendText(session, String(b.text));
317
319
  for (const k of b.keys ?? [])
318
320
  sendKey(session, String(k));
321
+ // Wait for the pane to quiesce (750ms quiet / 3s backstop) instead of returning
322
+ // the pre-reaction snapshot. Mirrors the settle heuristic in headless.ts.
323
+ const pane = await waitForPaneSettle(session, { quietMs: 750, timeoutMs: 3_000 });
319
324
  // `activeCommand` rides along on every WRITE so the cloud can record what it just drove
320
325
  // (#348). It is a process name, never a cost — see activeTerminalCommand's comment.
321
326
  const { activeTerminalCommand } = await import("./coding/terminal.js");
322
- return json(res, 200, { session, pane: capturePane(session, 200), activeCommand: activeTerminalCommand(session, "tmux") });
327
+ return json(res, 200, { session, pane, paneBefore, changed: pane !== paneBefore, activeCommand: activeTerminalCommand(session, "tmux") });
323
328
  }
324
329
  if (req.method === "POST" && path === "/tmux/run") {
325
- const { runCommand, capturePane, sessionExists } = await import("./coding/tmux.js");
330
+ const { runCommand, capturePane, sessionExists, waitForPaneSettle } = await import("./coding/tmux.js");
326
331
  const b = await readJson(req);
327
332
  const session = String(b.session || "").trim();
328
333
  const command = String(b.command ?? "");
@@ -332,12 +337,14 @@ async function route(runner, req, res) {
332
337
  return json(res, 400, { error: "A `command` is required." });
333
338
  if (!sessionExists(session))
334
339
  return json(res, 404, { error: `No tmux session "${session}".` });
340
+ const paneBefore = capturePane(session, 200);
335
341
  runCommand(session, command);
342
+ const pane = await waitForPaneSettle(session, { quietMs: 750, timeoutMs: 3_000 });
336
343
  const { activeTerminalCommand } = await import("./coding/terminal.js");
337
- return json(res, 200, { session, command, pane: capturePane(session, 200), activeCommand: activeTerminalCommand(session, "tmux") });
344
+ return json(res, 200, { session, command, pane, paneBefore, changed: pane !== paneBefore, activeCommand: activeTerminalCommand(session, "tmux") });
338
345
  }
339
346
  if (req.method === "POST" && path === "/tmux/session") {
340
- const { createSession, killSession, sessionExists } = await import("./coding/tmux.js");
347
+ const { createSession, killSession, sessionExists, waitForPaneSettle } = await import("./coding/tmux.js");
341
348
  const { homedir } = await import("node:os");
342
349
  const b = await readJson(req);
343
350
  const session = String(b.session || "").trim();
@@ -352,6 +359,12 @@ async function route(runner, req, res) {
352
359
  const { resolve } = await import("node:path");
353
360
  const workDir = resolve(String(b.workDir || "~").replace(/^~(?=$|\/)/, homedir()));
354
361
  createSession(session, workDir, b.command ? String(b.command) : undefined);
362
+ // When the session starts a command (e.g. "claude"), wait until the pane quiesces
363
+ // (the CLI has painted its initial prompt) before returning "ready" (#481). Without a
364
+ // startup command the pane is already at a shell prompt — no settle needed.
365
+ if (b.command) {
366
+ await waitForPaneSettle(session, { quietMs: 750, timeoutMs: 8_000 });
367
+ }
355
368
  return json(res, 200, { session, created: true, workDir });
356
369
  }
357
370
  // ── generic terminal connector ──────────────────────────────────────────
@@ -373,7 +386,8 @@ async function route(runner, req, res) {
373
386
  return json(res, 200, { target, pane: captureTerminalTarget(target, { backend, lines: b.lines }) });
374
387
  }
375
388
  if (req.method === "POST" && path === "/terminal/run") {
376
- const { runTerminalCommand, activeTerminalCommand } = await import("./coding/terminal.js");
389
+ const { runTerminalCommand, captureTerminalTarget, activeTerminalCommand } = await import("./coding/terminal.js");
390
+ const { waitForPaneSettle, SETTLE_QUIET_MS } = await import("./coding/tmux.js");
377
391
  const b = await readJson(req);
378
392
  const target = String(b.target || "").trim();
379
393
  const command = String(b.command ?? "");
@@ -382,23 +396,48 @@ async function route(runner, req, res) {
382
396
  if (!command.trim())
383
397
  return json(res, 400, { error: "A `command` is required." });
384
398
  const backend = b.backend === "tmux" || b.backend === "kitty" || b.backend === "iterm2" ? b.backend : undefined;
385
- const pane = runTerminalCommand(target, command, backend);
399
+ // Capture BEFORE to detect whether the input landed (#481).
400
+ const paneBefore = captureTerminalTarget(target, { backend });
401
+ runTerminalCommand(target, command, backend);
402
+ // Settle: for tmux targets, use the tmux poll. For other backends, fall back to the
403
+ // just-run snapshot (they don't support a reliable settle poll).
404
+ let pane;
405
+ if (!backend && target.startsWith("tmux:") || backend === "tmux") {
406
+ const { splitTerminalTarget } = await import("./coding/terminal.js");
407
+ const t = splitTerminalTarget(target, backend);
408
+ pane = await waitForPaneSettle(t.id, { quietMs: SETTLE_QUIET_MS, timeoutMs: 3_000 });
409
+ }
410
+ else {
411
+ pane = captureTerminalTarget(target, { backend });
412
+ }
386
413
  // Read AFTER the command lands, so `claude "fix x"` reports `claude` rather than the shell
387
414
  // that was sitting there a moment earlier (#348).
388
- return json(res, 200, { target, command, pane, activeCommand: activeTerminalCommand(target, backend) });
415
+ return json(res, 200, { target, command, pane, paneBefore, changed: pane !== paneBefore, activeCommand: activeTerminalCommand(target, backend) });
389
416
  }
390
417
  if (req.method === "POST" && path === "/terminal/send") {
391
- const { sendTerminalKeys, activeTerminalCommand } = await import("./coding/terminal.js");
418
+ const { sendTerminalKeys, captureTerminalTarget, activeTerminalCommand } = await import("./coding/terminal.js");
419
+ const { waitForPaneSettle, SETTLE_QUIET_MS } = await import("./coding/tmux.js");
392
420
  const b = await readJson(req);
393
421
  const target = String(b.target || "").trim();
394
422
  if (!target)
395
423
  return json(res, 400, { error: "A `target` is required." });
396
424
  const backend = b.backend === "tmux" || b.backend === "kitty" || b.backend === "iterm2" ? b.backend : undefined;
397
- const pane = sendTerminalKeys(target, { backend, text: b.text == null ? undefined : String(b.text), keys: b.keys ?? [] });
398
- return json(res, 200, { target, pane, activeCommand: activeTerminalCommand(target, backend) });
425
+ const paneBefore = captureTerminalTarget(target, { backend });
426
+ sendTerminalKeys(target, { backend, text: b.text == null ? undefined : String(b.text), keys: b.keys ?? [] });
427
+ let pane;
428
+ if (!backend && target.startsWith("tmux:") || backend === "tmux") {
429
+ const { splitTerminalTarget } = await import("./coding/terminal.js");
430
+ const t = splitTerminalTarget(target, backend);
431
+ pane = await waitForPaneSettle(t.id, { quietMs: SETTLE_QUIET_MS, timeoutMs: 3_000 });
432
+ }
433
+ else {
434
+ pane = captureTerminalTarget(target, { backend });
435
+ }
436
+ return json(res, 200, { target, pane, paneBefore, changed: pane !== paneBefore, activeCommand: activeTerminalCommand(target, backend) });
399
437
  }
400
438
  if (req.method === "POST" && path === "/terminal/session") {
401
439
  const { createTerminalTarget, killTerminalTarget } = await import("./coding/terminal.js");
440
+ const { waitForPaneSettle } = await import("./coding/tmux.js");
402
441
  const b = await readJson(req);
403
442
  const backend = b.backend === "tmux" || b.backend === "kitty" || b.backend === "iterm2" ? b.backend : undefined;
404
443
  if (b.action === "kill") {
@@ -410,6 +449,10 @@ async function route(runner, req, res) {
410
449
  if (!backend)
411
450
  return json(res, 400, { error: "`backend` must be tmux, kitty, or iterm2." });
412
451
  const target = createTerminalTarget({ backend, name: b.name, workDir: b.workDir, command: b.command });
452
+ // When the new target starts a command, wait until the pane quiesces (#481).
453
+ if (b.command && backend === "tmux" && !target.existed) {
454
+ await waitForPaneSettle(target.id, { quietMs: 750, timeoutMs: 8_000 });
455
+ }
413
456
  return json(res, 200, { target });
414
457
  }
415
458
  return json(res, 404, { error: "Not found" });
package/dist/index.js CHANGED
@@ -549,6 +549,14 @@ function withClaimedNames(identity, claimed) {
549
549
  declined: (identity.declined ?? []).filter((n) => !add.includes(n))
550
550
  };
551
551
  }
552
+ function withUnclaimedName(identity, name) {
553
+ const unclaim = name.trim();
554
+ if (!unclaim) return identity;
555
+ const names = identity.names.filter((n) => n !== unclaim);
556
+ const declined = [...identity.declined ?? []];
557
+ if (!declined.includes(unclaim)) declined.push(unclaim);
558
+ return { id: identity.id, names, declined: declined.slice(-MAX_DECLINED) };
559
+ }
552
560
  function withDeclinedNames(identity, declined) {
553
561
  const out = [...identity.declined ?? []];
554
562
  for (const raw of declined) {
@@ -699,7 +707,7 @@ function renderCandidates(candidates, nowMs) {
699
707
  });
700
708
  lines.push("");
701
709
  lines.push("Selecting a name merges its agents, pins and sessions onto this machine.");
702
- lines.push("Pick only names THIS machine has used \u2014 a claim cannot be undone from the CLI.");
710
+ lines.push("Pick only names THIS machine has used \u2014 use `pags machines unclaim <name>` to undo a wrong claim.");
703
711
  return lines;
704
712
  }
705
713
  async function fetchNodeSummaries(opts) {
@@ -777,6 +785,96 @@ async function defaultAsk(question) {
777
785
  }
778
786
  }
779
787
 
788
+ // src/commands/runner/http.ts
789
+ import { hostname as hostname2 } from "os";
790
+ function clean(value) {
791
+ const trimmed = value?.trim();
792
+ return trimmed || void 0;
793
+ }
794
+ function runnerBaseUrl(url) {
795
+ return (clean(url) || clean(process.env.PAGS_RUNNER_URL) || "http://127.0.0.1:49171").replace(/\/$/, "");
796
+ }
797
+ function pagsApiBase(url) {
798
+ return (clean(url) || clean(process.env.PAGS_API_BASE) || "https://api.proagentstore.online").replace(/\/$/, "");
799
+ }
800
+ function pagsHeaders(token) {
801
+ const resolved = clean(token) || clean(process.env.PAGS_TOKEN) || clean(loadSession()?.token);
802
+ return resolved ? { Authorization: `Bearer ${resolved}` } : {};
803
+ }
804
+ function runnerRequestHeaders(opts) {
805
+ const resolved = clean(opts.token) || clean(process.env.PAGS_RUNNER_TOKEN);
806
+ const headers = resolved ? { Authorization: `Bearer ${resolved}` } : {};
807
+ const instanceId = clean(opts.instanceId) || clean(process.env.PAGS_INSTANCE_ID);
808
+ if (instanceId) headers["X-PAGS-Instance-Id"] = instanceId;
809
+ return headers;
810
+ }
811
+ function apiPathSegment(value) {
812
+ return encodeURIComponent(value);
813
+ }
814
+ function buildRuntimeRegistrationBody(opts, capabilities = []) {
815
+ const node = hostname2();
816
+ const machine = loadMachineIdentity(node);
817
+ return {
818
+ endpointUrl: clean(opts.endpointUrl) || opts.endpointUrl,
819
+ token: clean(opts.runnerToken) || clean(opts.token) || clean(process.env.PAGS_RUNNER_TOKEN),
820
+ placement: opts.placement === "managed" ? "managed" : "local",
821
+ capabilities,
822
+ runnerVersion: clean(opts.runnerVersion) || "",
823
+ runnerNode: node,
824
+ machineId: machine.id,
825
+ machineNames: machine.names
826
+ };
827
+ }
828
+ async function requestRunner(method, path, opts, body) {
829
+ const headers = {
830
+ ...runnerRequestHeaders(opts)
831
+ };
832
+ if (body !== void 0) headers["Content-Type"] = "application/json";
833
+ const res = await fetch(`${runnerBaseUrl(opts.url)}${path}`, {
834
+ method,
835
+ headers,
836
+ body: body === void 0 ? void 0 : JSON.stringify(body)
837
+ });
838
+ const { text, data } = await readResponse(res);
839
+ if (!res.ok) {
840
+ const message = responseErrorMessage(data, text, res.statusText);
841
+ throw new Error(`${res.status} ${message}`);
842
+ }
843
+ return data;
844
+ }
845
+ async function requestPags(method, path, opts, body) {
846
+ const headers = {
847
+ ...pagsHeaders(opts.pagsToken)
848
+ };
849
+ if (!headers.Authorization) {
850
+ throw new Error("PAGS token required. Set PAGS_TOKEN or pass --pags-token.");
851
+ }
852
+ if (body !== void 0) headers["Content-Type"] = "application/json";
853
+ const res = await fetch(`${pagsApiBase(opts.apiBase)}${path}`, {
854
+ method,
855
+ headers,
856
+ body: body === void 0 ? void 0 : JSON.stringify(body)
857
+ });
858
+ const { text, data } = await readResponse(res);
859
+ if (!res.ok) {
860
+ const message = responseErrorMessage(data, text, res.statusText);
861
+ throw new Error(`${res.status} ${message}`);
862
+ }
863
+ return data;
864
+ }
865
+ async function readResponse(res) {
866
+ const text = await res.text();
867
+ if (!text) return { text, data: {} };
868
+ try {
869
+ return { text, data: JSON.parse(text) };
870
+ } catch {
871
+ return { text, data: {} };
872
+ }
873
+ }
874
+ function responseErrorMessage(data, text, statusText) {
875
+ return typeof data.error === "string" ? data.error : text || statusText;
876
+ }
877
+
780
878
  // src/commands/machines.ts
781
879
  var API_BASE2 = "https://api.proagentstore.online";
782
880
  async function loadNodes(token) {
@@ -804,6 +902,7 @@ var listCommand = new Command4("list").description("List the machines ProAgentSt
804
902
  }
805
903
  writeLine("");
806
904
  writeLine(" Claim a name this machine has used before: pags machines claim <name>");
905
+ writeLine(" Remove a wrong claim: pags machines unclaim <name>");
807
906
  writeLine("");
808
907
  });
809
908
  var claimCommand = new Command4("claim").description("Record that a machine name on this account is THIS machine").argument("<name...>", "Node name(s) to claim, as shown by `pags machines list`").action(async (names) => {
@@ -826,7 +925,51 @@ var claimCommand = new Command4("claim").description("Record that a machine name
826
925
  }
827
926
  writeLine(` \u2713 Claimed ${claim.join(", ")}. Restart \`pags up\` to merge them onto this machine.`);
828
927
  });
829
- var machinesCommand = new Command4("machines").description("Show and claim the machine names ProAgentStore has for this account").addCommand(listCommand, { isDefault: true }).addCommand(claimCommand);
928
+ var unclaimCommand = new Command4("unclaim").description("Remove a mistaken machine name claim from this machine (#467)").argument("<name...>", "Node name(s) to un-claim, as shown by `pags machines list`").action(async (names) => {
929
+ const session = requireSession();
930
+ const identity = loadMachineIdentity();
931
+ if (!identity.id) {
932
+ writeError("This machine has no id \u2014 `~/.config/proagentstore/` is not writable, so the claim record cannot be found.");
933
+ process.exit(1);
934
+ }
935
+ let anyFailed = false;
936
+ for (const raw of names) {
937
+ const name = raw.trim();
938
+ if (!name) continue;
939
+ if (name === identity.names[0]) {
940
+ writeError(` \u2717 ${name}: this is the machine's CURRENT hostname. You cannot un-claim the name it is actively registering under \u2014 stop \`pags up\` and rename the machine first.`);
941
+ anyFailed = true;
942
+ continue;
943
+ }
944
+ if (!identity.names.includes(name)) {
945
+ writeError(` \u2717 ${name}: this machine does not claim that name.`);
946
+ anyFailed = true;
947
+ continue;
948
+ }
949
+ try {
950
+ await requestPags(
951
+ "DELETE",
952
+ `/v1/terminals/nodes/${apiPathSegment(name)}/claim`,
953
+ { pagsToken: session.token, apiBase: pagsApiBase() },
954
+ { machineId: identity.id }
955
+ );
956
+ } catch (e) {
957
+ const msg = e instanceof Error ? e.message : String(e);
958
+ writeError(` \u2717 ${name}: ${msg}`);
959
+ anyFailed = true;
960
+ continue;
961
+ }
962
+ const updated = withUnclaimedName(identity, name);
963
+ if (!saveMachineIdentity(updated)) {
964
+ writeError(` \u2717 Server un-claimed ${name} but could not update ${machineFilePath()} \u2014 the next \`pags up\` may re-stamp it. Edit that file by hand and remove "${name}" from the names array.`);
965
+ anyFailed = true;
966
+ continue;
967
+ }
968
+ writeLine(` \u2713 ${name} \u2014 un-claimed on server and removed from ${machineFilePath()}.`);
969
+ }
970
+ if (anyFailed) process.exit(1);
971
+ });
972
+ 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);
830
973
 
831
974
  // src/commands/mcp.ts
832
975
  import { spawn } from "child_process";
@@ -951,96 +1094,6 @@ import { spawn as spawn3 } from "child_process";
951
1094
  import { randomUUID as randomUUID2 } from "crypto";
952
1095
  import { Command as Command7 } from "commander";
953
1096
 
954
- // src/commands/runner/http.ts
955
- import { hostname as hostname2 } from "os";
956
- function clean(value) {
957
- const trimmed = value?.trim();
958
- return trimmed || void 0;
959
- }
960
- function runnerBaseUrl(url) {
961
- return (clean(url) || clean(process.env.PAGS_RUNNER_URL) || "http://127.0.0.1:49171").replace(/\/$/, "");
962
- }
963
- function pagsApiBase(url) {
964
- return (clean(url) || clean(process.env.PAGS_API_BASE) || "https://api.proagentstore.online").replace(/\/$/, "");
965
- }
966
- function pagsHeaders(token) {
967
- const resolved = clean(token) || clean(process.env.PAGS_TOKEN) || clean(loadSession()?.token);
968
- return resolved ? { Authorization: `Bearer ${resolved}` } : {};
969
- }
970
- function runnerRequestHeaders(opts) {
971
- const resolved = clean(opts.token) || clean(process.env.PAGS_RUNNER_TOKEN);
972
- const headers = resolved ? { Authorization: `Bearer ${resolved}` } : {};
973
- const instanceId = clean(opts.instanceId) || clean(process.env.PAGS_INSTANCE_ID);
974
- if (instanceId) headers["X-PAGS-Instance-Id"] = instanceId;
975
- return headers;
976
- }
977
- function apiPathSegment(value) {
978
- return encodeURIComponent(value);
979
- }
980
- function buildRuntimeRegistrationBody(opts, capabilities = []) {
981
- const node = hostname2();
982
- const machine = loadMachineIdentity(node);
983
- return {
984
- endpointUrl: clean(opts.endpointUrl) || opts.endpointUrl,
985
- token: clean(opts.runnerToken) || clean(opts.token) || clean(process.env.PAGS_RUNNER_TOKEN),
986
- placement: opts.placement === "managed" ? "managed" : "local",
987
- capabilities,
988
- runnerVersion: clean(opts.runnerVersion) || "",
989
- runnerNode: node,
990
- machineId: machine.id,
991
- machineNames: machine.names
992
- };
993
- }
994
- async function requestRunner(method, path, opts, body) {
995
- const headers = {
996
- ...runnerRequestHeaders(opts)
997
- };
998
- if (body !== void 0) headers["Content-Type"] = "application/json";
999
- const res = await fetch(`${runnerBaseUrl(opts.url)}${path}`, {
1000
- method,
1001
- headers,
1002
- body: body === void 0 ? void 0 : JSON.stringify(body)
1003
- });
1004
- const { text, data } = await readResponse(res);
1005
- if (!res.ok) {
1006
- const message = responseErrorMessage(data, text, res.statusText);
1007
- throw new Error(`${res.status} ${message}`);
1008
- }
1009
- return data;
1010
- }
1011
- async function requestPags(method, path, opts, body) {
1012
- const headers = {
1013
- ...pagsHeaders(opts.pagsToken)
1014
- };
1015
- if (!headers.Authorization) {
1016
- throw new Error("PAGS token required. Set PAGS_TOKEN or pass --pags-token.");
1017
- }
1018
- if (body !== void 0) headers["Content-Type"] = "application/json";
1019
- const res = await fetch(`${pagsApiBase(opts.apiBase)}${path}`, {
1020
- method,
1021
- headers,
1022
- body: body === void 0 ? void 0 : JSON.stringify(body)
1023
- });
1024
- const { text, data } = await readResponse(res);
1025
- if (!res.ok) {
1026
- const message = responseErrorMessage(data, text, res.statusText);
1027
- throw new Error(`${res.status} ${message}`);
1028
- }
1029
- return data;
1030
- }
1031
- async function readResponse(res) {
1032
- const text = await res.text();
1033
- if (!text) return { text, data: {} };
1034
- try {
1035
- return { text, data: JSON.parse(text) };
1036
- } catch {
1037
- return { text, data: {} };
1038
- }
1039
- }
1040
- function responseErrorMessage(data, text, statusText) {
1041
- return typeof data.error === "string" ? data.error : text || statusText;
1042
- }
1043
-
1044
1097
  // src/commands/runner/process.ts
1045
1098
  import { spawn as spawn2 } from "child_process";
1046
1099
  import { existsSync as existsSync6 } from "fs";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@proagentstore/cli",
3
- "version": "0.4.45",
3
+ "version": "0.4.46",
4
4
  "description": "CLI for creating, publishing, and running ProAgentStore agents",
5
5
  "license": "MIT",
6
6
  "type": "module",