@proagentstore/cli 0.4.51 → 0.4.53

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.
@@ -84,6 +84,44 @@ export function splitSegments(command) {
84
84
  .map((s) => s.trim())
85
85
  .filter(Boolean);
86
86
  }
87
+ /**
88
+ * The engine's verdict on ONE tool call — the single expression of it (#597).
89
+ *
90
+ * `is_error` is the only outcome Claude Code's stream-json protocol states for a `tool_result`: it
91
+ * sets the flag when the call failed and omits it otherwise, so `!== true` is the protocol's own
92
+ * reading rather than an inference about the result text. This is the fact `settleAct` has always
93
+ * published as a consequential act's `ok`.
94
+ *
95
+ * It is a function because two call sites now need it — the act record and the transcript line the
96
+ * cloud parses — and a verdict stated twice is a verdict that can disagree with itself.
97
+ */
98
+ export function toolCallOk(block) {
99
+ return block.is_error !== true;
100
+ }
101
+ /**
102
+ * The outcome marker on the transcript's `↳` result line — `↳✓` succeeded, `↳✗` failed (#597).
103
+ *
104
+ * The runner computed this and threw it away: `settleAct` read `is_error` while the line pushed
105
+ * into the transcript carried only the result text. The transcript is the ONLY channel the cloud
106
+ * reads for an ordinary tool call (a read, a grep, a file open leaves no `agent_events` row), so
107
+ * the per-tool-call record of #581 AC7 could state the argument and the result and never whether
108
+ * the call worked.
109
+ *
110
+ * ── Why the marker is welded to the arrow, with no space
111
+ *
112
+ * The reader (`workers/api/src/lib/engine-tool-calls.ts`) takes the outcome from the character at a
113
+ * FIXED offset after `↳`, and every runner predating this wrote a space there. So a row written by
114
+ * an old runner reads *unknown* and can never read as a pass, whatever the tool's own output
115
+ * happens to start with — which is the property AC1 asks for and the reason a marker after the
116
+ * space would not do: `toolResult()` collapses a result to one line, and vitest's begins
117
+ * `✓ src/foo.test.ts`. An old row carrying that text must not be read as a success claim.
118
+ *
119
+ * `terminal-render.ts` and `engine-auth-prompt.ts`'s `QUOTED_LINE_RE` both match `↳` unanchored on
120
+ * its right, so the pane still renders and quoted-line filtering still fires.
121
+ */
122
+ export function toolResultMark(block) {
123
+ return toolCallOk(block) ? "✓" : "✗";
124
+ }
87
125
  /** A token that is exactly the trunk, not a branch merely containing the word (`feature/main-fix`). */
88
126
  const TRUNK_TOKEN = /(?:^|\s)(?:HEAD:)?(?:refs\/heads\/)?(?:main|master)(?:\s|$)/;
89
127
  function prRef(segment) {
@@ -1,5 +1,5 @@
1
1
  import { spawn } from "node:child_process";
2
- import { classifyCommand, commandFromToolInput, fillTargetFromResult } from "./engine-acts.js";
2
+ import { classifyCommand, commandFromToolInput, fillTargetFromResult, toolCallOk, toolResultMark } from "./engine-acts.js";
3
3
  import { parseEngineUsage } from "./engine-usage.js";
4
4
  import { turnReportFromExit, turnReportFromResult } from "./engine-turn.js";
5
5
  /**
@@ -605,7 +605,7 @@ export class HeadlessSession {
605
605
  case "user": // tool results come back as a synthetic user message
606
606
  for (const block of ev.message?.content ?? []) {
607
607
  if (block.type === "tool_result") {
608
- this.push(` ↳ ${toolResult(block.content)}`); // ↳
608
+ this.push(` ↳${toolResultMark(block)} ${toolResult(block.content)}`); // ↳✓ / ↳✗ (#597)
609
609
  this.settleAct(block);
610
610
  }
611
611
  }
@@ -679,7 +679,7 @@ export class HeadlessSession {
679
679
  if (!acts)
680
680
  return;
681
681
  this.awaitingResult.delete(id);
682
- const ok = block.is_error !== true;
682
+ const ok = toolCallOk(block);
683
683
  for (const a of fillTargetFromResult(acts, block.content))
684
684
  this.publishAct({ ...a, ok });
685
685
  }
package/dist/index.js CHANGED
@@ -1217,6 +1217,9 @@ function diffMembership(attached, eligible, thisNode, blocked = /* @__PURE__ */
1217
1217
  function shouldRegisterOnOpen(reconnect, alreadyRegistered) {
1218
1218
  return reconnect || !alreadyRegistered;
1219
1219
  }
1220
+ function pendingRegistrations(attached, registered) {
1221
+ return [...attached].filter((id) => !registered.has(id));
1222
+ }
1220
1223
  function instanceLabel(inst) {
1221
1224
  const short = `${inst.id.slice(0, 8)}\u2026`;
1222
1225
  return inst.name ? `${inst.name} (${short})` : short;
@@ -1336,7 +1339,7 @@ async function connectViaRelay(instanceIds, localUrl, runnerToken, opts, force =
1336
1339
  };
1337
1340
  for (const id of instanceIds) attach(id, "");
1338
1341
  reportRegistration();
1339
- writeLine(registered.size === instanceIds.length ? `Runtime registered with PAGS \u2713 (${registered.size}/${instanceIds.length} agents)` : `Runtime registration incomplete: ${registered.size}/${instanceIds.length} agents \u2014 retried on each relay (re)connect.`);
1342
+ writeLine(registered.size === instanceIds.length ? `Runtime registered with PAGS \u2713 (${registered.size}/${instanceIds.length} agents)` : `Runtime registration incomplete: ${registered.size}/${instanceIds.length} agents \u2014 retried on each relay (re)connect${watchInstances ? " and every 20s while this runs" : ""}.`);
1340
1343
  writeLine("");
1341
1344
  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");
1342
1345
  writeLine(` \u2705 CONNECTED \u2014 WebSocket relay \xB7 ${hostname3()}`);
@@ -1406,6 +1409,11 @@ async function connectViaRelay(instanceIds, localUrl, runnerToken, opts, force =
1406
1409
  attach(inst.id, instanceLabel(inst));
1407
1410
  }
1408
1411
  for (const id of toDetach) detach(id);
1412
+ const pending = pendingRegistrations(attached.keys(), registered);
1413
+ if (pending.length) {
1414
+ for (const id of pending) await registerRuntime(id);
1415
+ reportRegistration();
1416
+ }
1409
1417
  } catch {
1410
1418
  }
1411
1419
  tick();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@proagentstore/cli",
3
- "version": "0.4.51",
3
+ "version": "0.4.53",
4
4
  "description": "CLI for creating, publishing, and running ProAgentStore agents",
5
5
  "license": "MIT",
6
6
  "type": "module",