@tryarcanist/cli 0.1.100 → 0.1.101

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.
Files changed (2) hide show
  1. package/dist/index.js +49 -1
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -862,6 +862,22 @@ function noChangeOutcomeCopy(reason) {
862
862
  }
863
863
  }
864
864
 
865
+ // ../../shared/session/transient-disconnect.ts
866
+ var TRANSIENT_DISCONNECT_VISIBILITY_MS = 15e3;
867
+ function nextDisconnectMask(mask, previous, current, now) {
868
+ if (!current || current.sandboxSubstate !== "reconnecting") return null;
869
+ if (mask) return mask;
870
+ if (!previous || previous.sandboxSubstate === "reconnecting") return null;
871
+ return { since: now, heldPhase: previous.phase, heldSubstate: previous.sandboxSubstate ?? "none" };
872
+ }
873
+ function isDisconnectMaskActive(mask, now) {
874
+ return mask !== null && now - mask.since < TRANSIENT_DISCONNECT_VISIBILITY_MS;
875
+ }
876
+ function applyDisconnectMask(view, mask, now) {
877
+ if (!isDisconnectMaskActive(mask, now)) return view;
878
+ return { ...view, phase: mask.heldPhase, sandboxSubstate: mask.heldSubstate };
879
+ }
880
+
865
881
  // ../../shared/transcript/malformed-search.ts
866
882
  var MALFORMED_SEARCH_BLOCKED_TRANSCRIPT_PREFIX = "Arcanist blocked this malformed search command before execution.";
867
883
  var BASH_UNMATCHED_QUOTE_EOF_RE = /\/bin\/bash:\s+-c:\s+line\s+\d+:\s+unexpected EOF while looking for matching [`'"][`'"]?/i;
@@ -1244,6 +1260,24 @@ function projectRetryStatus(data, index) {
1244
1260
  ...typeof data?.retryAfterMs === "number" ? { retryAfterMs: data.retryAfterMs } : {}
1245
1261
  };
1246
1262
  }
1263
+ function projectPromptRetrying(data, index) {
1264
+ const attempt = typeof data?.attempt === "number" ? data.attempt : Number(data?.attempt ?? 0);
1265
+ const cap = typeof data?.cap === "number" ? data.cap : void 0;
1266
+ const retryPromptId = typeof data?.retryPromptId === "string" ? data.retryPromptId : resolvePromptId(data);
1267
+ return {
1268
+ type: "retry_status",
1269
+ // Key off retryPromptId (always present in the emitted payload, unique per
1270
+ // retry) rather than the index, so the id is stable across replays. The
1271
+ // event's `timestamp` lives at the top level, not inside `data`.
1272
+ id: `pr-retry-${retryPromptId ?? index}`,
1273
+ ...retryPromptId ? { promptId: retryPromptId } : {},
1274
+ attempt,
1275
+ message: "Sandbox dropped mid-task; retrying on a fresh sandbox",
1276
+ scope: "sandbox_disconnect",
1277
+ ...cap !== void 0 ? { maxAttempts: cap } : {},
1278
+ ...typeof data?.reason === "string" ? { reason: data.reason } : {}
1279
+ };
1280
+ }
1247
1281
  function projectBranchChanged(data, index) {
1248
1282
  return {
1249
1283
  type: "branch_changed",
@@ -1515,6 +1549,9 @@ function flattenSessionEvents(raw) {
1515
1549
  case "retry_status":
1516
1550
  pushEvent(state, projectRetryStatus(data, state.merged.length));
1517
1551
  break;
1552
+ case "prompt_retrying":
1553
+ pushEvent(state, projectPromptRetrying(data, state.merged.length));
1554
+ break;
1518
1555
  case "branch_changed":
1519
1556
  pushEvent(state, projectBranchChanged(data, state.merged.length));
1520
1557
  break;
@@ -2139,6 +2176,12 @@ function formatStatusLine(status) {
2139
2176
  if (status.spawnDurationMs != null) details.push(`spawn ${(status.spawnDurationMs / 1e3).toFixed(1)}s`);
2140
2177
  return details.length > 0 ? `[status] ${phaseLabel} | ${details.join(" | ")}` : `[status] ${phaseLabel}`;
2141
2178
  }
2179
+ function advanceStatusDisconnectMask(status, mask, lastView, now) {
2180
+ const view = status.phase ? { phase: status.phase, sandboxSubstate: status.sandboxSubstate } : null;
2181
+ const nextMask = nextDisconnectMask(mask, lastView, view, now);
2182
+ const displayStatus = view ? { ...status, ...applyDisconnectMask(view, nextMask, now) } : status;
2183
+ return { displayStatus, mask: nextMask, view };
2184
+ }
2142
2185
  async function printNoChangeOutcome(config, sessionId) {
2143
2186
  try {
2144
2187
  const data = await apiFetch(
@@ -2197,6 +2240,8 @@ async function watchCommand(sessionId, options, command) {
2197
2240
  let afterSequence = initialAfterSequence;
2198
2241
  let lastStatusLine = null;
2199
2242
  let textOpen = false;
2243
+ let disconnectMask = null;
2244
+ let lastStatusView = null;
2200
2245
  if (!json) console.log(`Watching session ${sessionId}...`);
2201
2246
  try {
2202
2247
  while (true) {
@@ -2208,7 +2253,10 @@ async function watchCommand(sessionId, options, command) {
2208
2253
  const parsed = parseSsePayload(payload);
2209
2254
  const receivedFullPage = parsed.events.length >= pageSize;
2210
2255
  if (!json && parsed.status) {
2211
- const nextStatusLine = formatStatusLine(parsed.status);
2256
+ const advanced = advanceStatusDisconnectMask(parsed.status, disconnectMask, lastStatusView, Date.now());
2257
+ disconnectMask = advanced.mask;
2258
+ lastStatusView = advanced.view;
2259
+ const nextStatusLine = formatStatusLine(advanced.displayStatus);
2212
2260
  if (nextStatusLine !== lastStatusLine) {
2213
2261
  if (textOpen) {
2214
2262
  process.stdout.write("\n");
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tryarcanist/cli",
3
- "version": "0.1.100",
3
+ "version": "0.1.101",
4
4
  "description": "CLI for Arcanist — create and manage coding agent sessions",
5
5
  "type": "module",
6
6
  "bin": {