@retasc/cli 1.2.2 → 1.2.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.
@@ -57,10 +57,33 @@ export function heartbeatRequest(rpcId, issueId, claimToken) {
57
57
  params: { name: "heartbeat", arguments: { identifier: issueId, claimToken } },
58
58
  };
59
59
  }
60
- /** A heartbeat result of CLAIM_LOST means the lease is gone — stop tracking it. */
60
+ /**
61
+ * A heartbeat CLAIM_LOST means the lease is gone — stop tracking it.
62
+ *
63
+ * The server throws `Error("CLAIM_LOST: …")` (convex/lib/claims.ts), and http.ts
64
+ * surfaces that as an MCP tool ERROR: `{ isError: true, content:[{text:"CLAIM_LOST: …"}] }`.
65
+ * Match ONLY that signal (or a top-level `error`/`code` field, for a future
66
+ * structured shape) — NEVER `JSON.stringify` the whole result and regex it, or a
67
+ * benign payload field that merely CONTAINS "CLAIM_LOST" (an issue title, a
68
+ * checkpoint note quoting an error, a comment body) would silently drop a live
69
+ * lease and let the reclaimer hand our work to someone else (RTSC-150).
70
+ */
61
71
  export function isClaimLost(result) {
62
72
  if (!result || typeof result !== "object")
63
73
  return false;
64
- const text = JSON.stringify(result);
65
- return /CLAIM_LOST/.test(text);
74
+ const r = result;
75
+ // A structured error signal on a top-level field (belt-and-suspenders; also the
76
+ // shape the older unit test asserts). Bounded to top-level scalars, not nested.
77
+ if (r.code === "CLAIM_LOST")
78
+ return true;
79
+ if (typeof r.error === "string" && /CLAIM_LOST/.test(r.error))
80
+ return true;
81
+ // The live shape: only an MCP error envelope, and only its text blocks — success
82
+ // payloads (isError absent/false) are never treated as a lost claim.
83
+ if (r.isError !== true || !Array.isArray(r.content))
84
+ return false;
85
+ return r.content.some((c) => c !== null &&
86
+ typeof c === "object" &&
87
+ typeof c.text === "string" &&
88
+ /CLAIM_LOST/.test(c.text));
66
89
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@retasc/cli",
3
- "version": "1.2.2",
3
+ "version": "1.2.3",
4
4
  "description": "Retasc CLI — sign in with GitHub, create projects, mint agent API keys, and wire your agent to the Retasc MCP server in one command.",
5
5
  "type": "module",
6
6
  "bin": {