replicas-cli 0.2.595 → 0.2.597

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.cjs +94 -11
  2. package/package.json +1 -1
package/dist/index.cjs CHANGED
@@ -7789,6 +7789,11 @@ var CREDENTIAL_TYPE = {
7789
7789
  OPENROUTER_API_KEY: "openrouter_api_key",
7790
7790
  AI_GATEWAY_API_KEY: "ai_gateway_api_key"
7791
7791
  };
7792
+ var INFERENCE_PROVIDER_LABELS = {
7793
+ [CREDENTIAL_METHOD.OPENCODE_GO]: "OpenCode Go",
7794
+ [CREDENTIAL_METHOD.ASTER]: "Aster",
7795
+ [CREDENTIAL_METHOD.OPENROUTER]: "OpenRouter"
7796
+ };
7792
7797
  var AGENT_CREDENTIAL_METHODS_IN_ORDER = {
7793
7798
  [AGENT.CLAUDE]: [
7794
7799
  { method: CREDENTIAL_METHOD.OAUTH, credentialType: CREDENTIAL_TYPE.CLAUDE_OAUTH },
@@ -24508,8 +24513,46 @@ var headlessFilesystemAgentResultSchema = external_exports.object({
24508
24513
  }))
24509
24514
  });
24510
24515
 
24516
+ // ../shared/src/errors.ts
24517
+ var TRANSIENT_NETWORK_ERROR_PATTERNS = [
24518
+ /socket connection was closed unexpectedly/,
24519
+ /fetch failed/,
24520
+ /network error/,
24521
+ /network request failed/,
24522
+ /econnreset/,
24523
+ /econnrefused/,
24524
+ /etimedout/,
24525
+ /enotfound/,
24526
+ /eai_again/,
24527
+ /und_err_socket/,
24528
+ /und_err_connect_timeout/,
24529
+ /headers timeout/,
24530
+ /body timeout/,
24531
+ /connection reset/,
24532
+ /connection closed/,
24533
+ /closed unexpectedly/
24534
+ ];
24535
+ var HTTP_CONTEXT_PATTERN = /(api error|request|response|status|http)/;
24536
+ var HTTP_STATUS_PATTERN = /(^|[^0-9])([1-5][0-9]{2})(?=$|[^0-9])/g;
24537
+ function isTransientErrorText(text, options = {}) {
24538
+ const normalized = text.toLowerCase();
24539
+ if (!normalized) return false;
24540
+ if (TRANSIENT_NETWORK_ERROR_PATTERNS.some((pattern) => pattern.test(normalized))) return true;
24541
+ if (options.includeRateLimit && /rate limit/.test(normalized)) return true;
24542
+ if (options.extraPatterns?.some((pattern) => pattern.test(normalized))) return true;
24543
+ const httpStatuses = new Set(options.httpStatuses ?? []);
24544
+ const httpStatusClasses = new Set(options.httpStatusClasses ?? []);
24545
+ if (httpStatuses.size === 0 && httpStatusClasses.size === 0) return false;
24546
+ if (options.requireHttpContext !== false && !HTTP_CONTEXT_PATTERN.test(normalized)) return false;
24547
+ for (const match of normalized.matchAll(HTTP_STATUS_PATTERN)) {
24548
+ const status = Number(match[2]);
24549
+ if (httpStatuses.has(status) || httpStatusClasses.has(Math.floor(status / 100))) return true;
24550
+ }
24551
+ return false;
24552
+ }
24553
+
24511
24554
  // ../shared/src/cli-version.ts
24512
- var CLI_VERSION = "0.2.595";
24555
+ var CLI_VERSION = "0.2.597";
24513
24556
 
24514
24557
  // ../shared/src/version.ts
24515
24558
  function compareVersions(v1, v2) {
@@ -25146,6 +25189,7 @@ function coerceBackgroundTaskPayload(payload) {
25146
25189
  prompt: optionalString(payload.prompt),
25147
25190
  lastToolName: optionalString(payload.last_tool_name),
25148
25191
  usage,
25192
+ ambient: optionalBoolean(payload.ambient),
25149
25193
  patch
25150
25194
  };
25151
25195
  }
@@ -26063,6 +26107,27 @@ function parseFxEvents(events) {
26063
26107
  return parseAcpEvents(events, "fx");
26064
26108
  }
26065
26109
 
26110
+ // ../shared/src/display-message/parsers/inference-error.ts
26111
+ var TRANSIENT_HTTP_STATUSES = [408, 429, 500, 502, 503, 504, 529];
26112
+ var SERVER_ERROR_TEXT_PATTERN = /internal ?server ?error|server ?error|service unavailable|bad gateway|gateway timeout|overloaded|too many requests/i;
26113
+ var INFERENCE_ERROR_DETAIL_MAX = 600;
26114
+ var INFERENCE_ERROR_RETRY_HINT = "This is usually temporary \u2014 retry the message.";
26115
+ function formatInferenceError(message, context = {}) {
26116
+ const label = context.provider ? INFERENCE_PROVIDER_LABELS[context.provider] ?? context.provider : null;
26117
+ const source = label ? `${label}${context.model ? ` (${context.model})` : ""} request failed${typeof context.status === "number" ? ` with HTTP ${context.status}` : ""}` : null;
26118
+ let body = source ? message ? `${source}: ${message}` : `${source}.` : message;
26119
+ const detail = context.detail?.trim();
26120
+ if (detail && !body.includes(detail)) {
26121
+ body = `${body}
26122
+ ${detail.length > INFERENCE_ERROR_DETAIL_MAX ? `${detail.slice(0, INFERENCE_ERROR_DETAIL_MAX)}\u2026` : detail}`;
26123
+ }
26124
+ const sniffText = `${message}
26125
+ ${detail ?? ""}`;
26126
+ const transient = context.retryable ?? (typeof context.status === "number" ? TRANSIENT_HTTP_STATUSES.includes(context.status) || context.status >= 500 : isTransientErrorText(sniffText, { httpStatuses: TRANSIENT_HTTP_STATUSES, includeRateLimit: true }) || SERVER_ERROR_TEXT_PATTERN.test(sniffText));
26127
+ return transient ? `${body}
26128
+ ${INFERENCE_ERROR_RETRY_HINT}` : body;
26129
+ }
26130
+
26066
26131
  // ../shared/src/display-message/parsers/opencode-parser.ts
26067
26132
  function timestampFromMs(value, fallback) {
26068
26133
  return typeof value === "number" && Number.isFinite(value) ? new Date(value).toISOString() : fallback;
@@ -26076,9 +26141,15 @@ function toolStatus(status) {
26076
26141
  function assistantError(info) {
26077
26142
  if (!isRecord(info) || !isRecord(info.error)) return null;
26078
26143
  const data = isRecord(info.error.data) ? info.error.data : null;
26079
- if (typeof data?.message === "string") return data.message;
26080
- if (typeof info.error.message === "string") return info.error.message;
26081
- return stringifyDisplayValue(info.error) ?? "Opencode run failed";
26144
+ const message = typeof data?.message === "string" ? data.message : typeof info.error.message === "string" ? info.error.message : stringifyDisplayValue(info.error) ?? "Opencode run failed";
26145
+ if (info.error.name === "MessageAbortedError") return message;
26146
+ return formatInferenceError(message, {
26147
+ ...typeof info.providerID === "string" ? { provider: info.providerID } : {},
26148
+ ...typeof info.modelID === "string" ? { model: info.modelID } : {},
26149
+ ...typeof data?.statusCode === "number" ? { status: data.statusCode } : {},
26150
+ ...typeof data?.isRetryable === "boolean" ? { retryable: data.isRetryable } : {},
26151
+ ...typeof data?.responseBody === "string" ? { detail: data.responseBody } : {}
26152
+ });
26082
26153
  }
26083
26154
  function parseOpencodeEvents(events) {
26084
26155
  const messages = [];
@@ -26113,7 +26184,9 @@ function parseOpencodeEvents(events) {
26113
26184
  messages.push({
26114
26185
  id: `opencode-${event.type}-${event.timestamp}`,
26115
26186
  type: "error",
26116
- message,
26187
+ message: formatInferenceError(message, {
26188
+ ...typeof event.payload.status === "number" ? { status: event.payload.status } : {}
26189
+ }),
26117
26190
  timestamp: event.timestamp
26118
26191
  });
26119
26192
  continue;
@@ -26207,7 +26280,11 @@ function toolStatus2(value) {
26207
26280
  }
26208
26281
  function assistantErrorMessage(value) {
26209
26282
  if (!isRecord(value) || value.role !== "assistant" || value.stopReason !== "error") return null;
26210
- return typeof value.errorMessage === "string" && value.errorMessage ? value.errorMessage : "Pi run failed";
26283
+ const message = typeof value.errorMessage === "string" && value.errorMessage ? value.errorMessage : "Pi run failed";
26284
+ return formatInferenceError(message, {
26285
+ ...typeof value.provider === "string" ? { provider: value.provider } : {},
26286
+ ...typeof value.model === "string" ? { model: value.model } : {}
26287
+ });
26211
26288
  }
26212
26289
  function parsePiEvents(events) {
26213
26290
  const messages = [];
@@ -26229,7 +26306,7 @@ function parsePiEvents(events) {
26229
26306
  continue;
26230
26307
  }
26231
26308
  if (event.type === "pi-error") {
26232
- messages.push({ id: `pi-error-${event.timestamp}-${messages.length}`, type: "error", message: String(event.payload.message ?? "Pi run failed"), timestamp: event.timestamp });
26309
+ messages.push({ id: `pi-error-${event.timestamp}-${messages.length}`, type: "error", message: formatInferenceError(String(event.payload.message ?? "Pi run failed")), timestamp: event.timestamp });
26233
26310
  continue;
26234
26311
  }
26235
26312
  if (event.type === "pi-message_end") {
@@ -26446,6 +26523,7 @@ function parseClaudeEvents(events, parentToolUseId) {
26446
26523
  });
26447
26524
  const toolCallMap = /* @__PURE__ */ new Map();
26448
26525
  const taskMessageMap = /* @__PURE__ */ new Map();
26526
+ const ambientTaskIds = /* @__PURE__ */ new Set();
26449
26527
  const partialIndexes = /* @__PURE__ */ new Map();
26450
26528
  const completedStreamIds = /* @__PURE__ */ new Set();
26451
26529
  const supersededStreamIds = /* @__PURE__ */ new Set();
@@ -26454,9 +26532,10 @@ function parseClaudeEvents(events, parentToolUseId) {
26454
26532
  const assistantTextCounts = /* @__PURE__ */ new Map();
26455
26533
  const acceptedUserMessageIndexes = /* @__PURE__ */ new Set();
26456
26534
  const canonicalUserMessageIndexes = /* @__PURE__ */ new Set();
26535
+ const supersededUserMessageIndexes = /* @__PURE__ */ new Set();
26457
26536
  const findMatchingUserMessageIndex = (indexes, content, timestamp, messageId) => {
26458
26537
  if (typeof messageId === "string") {
26459
- const byId = messages.findIndex((message) => message.type === "user" && message.id === messageId);
26538
+ const byId = messages.findIndex((message, index) => message.type === "user" && message.id === messageId && !supersededUserMessageIndexes.has(index));
26460
26539
  if (byId !== -1) return byId;
26461
26540
  }
26462
26541
  return [...indexes].find((index) => {
@@ -26568,9 +26647,12 @@ function parseClaudeEvents(events, parentToolUseId) {
26568
26647
  };
26569
26648
  if (acceptedIndex === void 0) {
26570
26649
  canonicalUserMessageIndexes.add(messages.push(message) - 1);
26650
+ } else if (acceptedUserMessageIndexes.has(acceptedIndex)) {
26651
+ supersededUserMessageIndexes.add(acceptedIndex);
26652
+ acceptedUserMessageIndexes.delete(acceptedIndex);
26653
+ canonicalUserMessageIndexes.add(messages.push(message) - 1);
26571
26654
  } else {
26572
26655
  messages[acceptedIndex] = message;
26573
- acceptedUserMessageIndexes.delete(acceptedIndex);
26574
26656
  }
26575
26657
  }
26576
26658
  }
@@ -26806,7 +26888,8 @@ function parseClaudeEvents(events, parentToolUseId) {
26806
26888
  }
26807
26889
  if (event.type === "claude-system") {
26808
26890
  const payload = coerceBackgroundTaskPayload(event.payload);
26809
- if (payload) {
26891
+ if (payload?.ambient) ambientTaskIds.add(payload.taskId);
26892
+ if (payload && !ambientTaskIds.has(payload.taskId)) {
26810
26893
  const existing = taskMessageMap.get(payload.taskId);
26811
26894
  const nextStatus = payload.subtype === "task_notification" ? normalizeBackgroundTaskStatus(payload.status) : payload.subtype === "task_updated" ? normalizeBackgroundTaskStatus(payload.patch?.status) : existing?.status ?? "in_progress";
26812
26895
  const nextMessage = {
@@ -26923,7 +27006,7 @@ function parseClaudeEvents(events, parentToolUseId) {
26923
27006
  message.targetProvider = target.subagentType;
26924
27007
  }
26925
27008
  }
26926
- const staleIndexes = /* @__PURE__ */ new Set();
27009
+ const staleIndexes = new Set(supersededUserMessageIndexes);
26927
27010
  for (const streamId of [...completedStreamIds, ...supersededStreamIds]) {
26928
27011
  const refs = partialIndexes.get(streamId);
26929
27012
  if (refs?.reasoning !== void 0) staleIndexes.add(refs.reasoning);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "replicas-cli",
3
- "version": "0.2.595",
3
+ "version": "0.2.597",
4
4
  "description": "CLI for managing Replicas workspaces - SSH into cloud dev environments with automatic port forwarding",
5
5
  "main": "dist/index.cjs",
6
6
  "bin": {