replicas-cli 0.2.398 → 0.2.399

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.mjs +104 -24
  2. package/package.json +1 -1
package/dist/index.mjs CHANGED
@@ -7728,6 +7728,7 @@ function getEventSignature(event) {
7728
7728
  var USER_MESSAGE_ID_PAYLOAD_KEY = "replicasMessageId";
7729
7729
  var CODEX_ASP_ITEM_ID_PAYLOAD_KEY = "codexAspItemId";
7730
7730
  var CODEX_QUOTA_STATUS_EVENT_TYPE = "codex-quota-status";
7731
+ var CHAT_INTERRUPTED_EVENT_TYPE = "replicas-interrupted";
7731
7732
 
7732
7733
  // ../node_modules/.bun/zod@4.4.3/node_modules/zod/v4/classic/external.js
7733
7734
  var external_exports = {};
@@ -24376,8 +24377,24 @@ var HOOK_EXEC_MAX_BUFFER_BYTES = 10 * 1024 * 1024;
24376
24377
  // ../shared/src/replicas-config.ts
24377
24378
  var REPLICAS_CONFIG_FILENAMES = ["replicas.json", "replicas.yaml", "replicas.yml"];
24378
24379
 
24380
+ // ../shared/src/format.ts
24381
+ function formatTurnElapsed(ms) {
24382
+ const totalSeconds = Math.max(0, Math.round(ms / 1e3));
24383
+ if (totalSeconds < 60) {
24384
+ return `${totalSeconds}s`;
24385
+ }
24386
+ if (totalSeconds < 3600) {
24387
+ const minutes2 = Math.floor(totalSeconds / 60);
24388
+ const seconds = totalSeconds % 60;
24389
+ return seconds === 0 ? `${minutes2}m` : `${minutes2}m ${seconds}s`;
24390
+ }
24391
+ const hours = Math.floor(totalSeconds / 3600);
24392
+ const minutes = Math.floor(totalSeconds % 3600 / 60);
24393
+ return minutes === 0 ? `${hours}h` : `${hours}h ${minutes}m`;
24394
+ }
24395
+
24379
24396
  // ../shared/src/cli-version.ts
24380
- var CLI_VERSION = "0.2.398";
24397
+ var CLI_VERSION = "0.2.399";
24381
24398
 
24382
24399
  // ../shared/src/version.ts
24383
24400
  function compareVersions(v1, v2) {
@@ -24694,16 +24711,20 @@ function normalizeBackgroundTaskStatus(status) {
24694
24711
  return "in_progress";
24695
24712
  }
24696
24713
 
24697
- // ../shared/src/json.ts
24698
- function safeJsonParse(str, fallback) {
24699
- try {
24700
- return JSON.parse(str);
24701
- } catch {
24702
- return fallback;
24703
- }
24714
+ // ../shared/src/display-message/format.ts
24715
+ function formatStoppedAfter(durationMs) {
24716
+ if (durationMs === void 0) return "You stopped";
24717
+ return `You stopped after ${formatTurnElapsed(durationMs)}`;
24718
+ }
24719
+
24720
+ // ../shared/src/agent-event-utils.ts
24721
+ function parseTimestampMs(timestamp) {
24722
+ const value = Date.parse(timestamp);
24723
+ return Number.isFinite(value) ? value : 0;
24704
24724
  }
24705
24725
 
24706
24726
  // ../shared/src/display-message/parsers/utils.ts
24727
+ var INTERRUPTED_MESSAGE_REGEX = /^\[Request interrupted by user.*\]$/;
24707
24728
  function userMessageImages(value) {
24708
24729
  if (!Array.isArray(value)) return void 0;
24709
24730
  const images = value.filter((item) => isRecord(item) && item.type === "image" && typeof item.mediaType === "string" && typeof item.data === "string");
@@ -24719,6 +24740,15 @@ function stringifyDisplayValue(value) {
24719
24740
  }
24720
24741
  }
24721
24742
 
24743
+ // ../shared/src/json.ts
24744
+ function safeJsonParse(str, fallback) {
24745
+ try {
24746
+ return JSON.parse(str);
24747
+ } catch {
24748
+ return fallback;
24749
+ }
24750
+ }
24751
+
24722
24752
  // ../shared/src/display-message/parsers/codex-parser.ts
24723
24753
  function getStatusFromExitCode(exitCode) {
24724
24754
  return exitCode === 0 ? "completed" : "failed";
@@ -25517,6 +25547,7 @@ function parseClaudeEvents(events, parentToolUseId) {
25517
25547
  const assistantThinking = /* @__PURE__ */ new Map();
25518
25548
  const assistantTextCounts = /* @__PURE__ */ new Map();
25519
25549
  const acceptedUserMessageIndexes = /* @__PURE__ */ new Set();
25550
+ let turnWasInterrupted = false;
25520
25551
  const taskAccumulator = new TaskAccumulator();
25521
25552
  const taskSnapshot = () => taskAccumulator.getTasks().map((task) => ({
25522
25553
  text: task.subject,
@@ -25587,6 +25618,7 @@ function parseClaudeEvents(events, parentToolUseId) {
25587
25618
  if (LOCAL_COMMAND_ECHO_REGEX.test(textContent.trim())) {
25588
25619
  return;
25589
25620
  }
25621
+ turnWasInterrupted = INTERRUPTED_MESSAGE_REGEX.test(textContent.trim());
25590
25622
  const images = content.filter((c) => c.type === "image" && c.source).map((c) => {
25591
25623
  const source = c.source;
25592
25624
  return {
@@ -25834,8 +25866,21 @@ function parseClaudeEvents(events, parentToolUseId) {
25834
25866
  }
25835
25867
  if (event.type === "claude-result") {
25836
25868
  const payload = coerceClaudeResultPayload(event.payload);
25869
+ const errorList = payload.errors || [];
25870
+ if (turnWasInterrupted) {
25871
+ turnWasInterrupted = false;
25872
+ const genuineErrors = errorList.filter((e) => !e.includes("[ede_diagnostic]"));
25873
+ if (genuineErrors.length > 0) {
25874
+ messages.push({
25875
+ id: `error-${event.timestamp}`,
25876
+ type: "error",
25877
+ message: genuineErrors.join("\n"),
25878
+ timestamp: event.timestamp
25879
+ });
25880
+ }
25881
+ return;
25882
+ }
25837
25883
  if (isClaudeResultError(payload)) {
25838
- const errorList = payload.errors || [];
25839
25884
  const errorMessage = errorList.length > 0 ? errorList.join("\n") : "Claude session encountered an unexpected error.";
25840
25885
  messages.push({
25841
25886
  id: `error-${event.timestamp}`,
@@ -25974,12 +26019,6 @@ function parseClaudeEvents(events, parentToolUseId) {
25974
26019
  return messages.filter((_, index) => !staleIndexes.has(index));
25975
26020
  }
25976
26021
 
25977
- // ../shared/src/agent-event-utils.ts
25978
- function parseTimestampMs(timestamp) {
25979
- const value = Date.parse(timestamp);
25980
- return Number.isFinite(value) ? value : 0;
25981
- }
25982
-
25983
26022
  // ../shared/src/display-message/parsers/codex-asp-parser.ts
25984
26023
  var DUPLICATE_WINDOW_MS = 5 * 60 * 1e3;
25985
26024
  function nearTimestamp(a, b) {
@@ -26172,7 +26211,7 @@ function parseCodexAspTranscript(transcript) {
26172
26211
  }
26173
26212
 
26174
26213
  // ../shared/src/display-message/parsers/index.ts
26175
- var INTERRUPTED_MESSAGE_REGEX = /^\[Request interrupted by user.*\]$/;
26214
+ var INTERRUPTION_DEDUP_WINDOW_MS = 15e3;
26176
26215
  function parseAgentEvents(events, agentType) {
26177
26216
  if (agentType === "codex") {
26178
26217
  return parseCodexEvents(events);
@@ -26192,10 +26231,50 @@ function parseDisplayMessages(events, agentType, codexAspTranscript, options = {
26192
26231
  const shouldFilter = options.filter ?? true;
26193
26232
  const legacyMessages = shouldFilter ? filterDisplayMessages(parseAgentEvents(events, agentType), agentType) : parseAgentEvents(events, agentType);
26194
26233
  if (agentType !== "codex" || !codexAspTranscript) {
26195
- return legacyMessages;
26234
+ return shouldFilter ? applyInterruptions(legacyMessages, events) : legacyMessages;
26196
26235
  }
26197
26236
  const nativeCodexMessages = shouldFilter ? filterDisplayMessages(parseCodexAspTranscript(codexAspTranscript), agentType) : parseCodexAspTranscript(codexAspTranscript);
26198
- return mergeCodexAspDisplayMessages(nativeCodexMessages, legacyMessages);
26237
+ const merged = mergeCodexAspDisplayMessages(nativeCodexMessages, legacyMessages);
26238
+ return shouldFilter ? applyInterruptions(merged, events) : merged;
26239
+ }
26240
+ function applyInterruptions(messages, events) {
26241
+ const result = [...messages];
26242
+ for (const event of events) {
26243
+ if (event.type !== CHAT_INTERRUPTED_EVENT_TYPE) continue;
26244
+ const eventMs = parseTimestampMs(event.timestamp);
26245
+ let index = result.length;
26246
+ while (index > 0 && parseTimestampMs(result[index - 1].timestamp) > eventMs) index--;
26247
+ result.splice(index, 0, {
26248
+ id: `interruption-${event.timestamp}`,
26249
+ type: "interruption",
26250
+ timestamp: event.timestamp
26251
+ });
26252
+ }
26253
+ let lastUserMs = null;
26254
+ let lastInterruption = null;
26255
+ const finalized = [];
26256
+ for (const msg of result) {
26257
+ if (msg.type === "user") {
26258
+ lastUserMs = parseTimestampMs(msg.timestamp);
26259
+ lastInterruption = null;
26260
+ finalized.push(msg);
26261
+ continue;
26262
+ }
26263
+ if (msg.type !== "interruption") {
26264
+ finalized.push(msg);
26265
+ continue;
26266
+ }
26267
+ const ms = parseTimestampMs(msg.timestamp);
26268
+ if (lastInterruption && ms - parseTimestampMs(lastInterruption.timestamp) <= INTERRUPTION_DEDUP_WINDOW_MS) {
26269
+ continue;
26270
+ }
26271
+ lastInterruption = {
26272
+ ...msg,
26273
+ ...lastUserMs !== null && ms >= lastUserMs ? { durationMs: ms - lastUserMs } : {}
26274
+ };
26275
+ finalized.push(lastInterruption);
26276
+ }
26277
+ return finalized;
26199
26278
  }
26200
26279
  function isCodexInitializationPrompt(message) {
26201
26280
  return message.type === "user" && removeReplicasInstructions(message.content).trim() === "Hello";
@@ -26230,7 +26309,7 @@ function filterDisplayMessages(messages, provider) {
26230
26309
  if (msg.type !== "user") return msg;
26231
26310
  const cleaned = removeReplicasInstructions(msg.content).trim();
26232
26311
  if (INTERRUPTED_MESSAGE_REGEX.test(cleaned)) {
26233
- return { ...msg, content: "Request interrupted" };
26312
+ return { id: msg.id, type: "interruption", timestamp: msg.timestamp };
26234
26313
  }
26235
26314
  return cleaned !== msg.content ? { ...msg, content: cleaned } : msg;
26236
26315
  });
@@ -34545,12 +34624,13 @@ function UserMessageContent({ content }) {
34545
34624
  }
34546
34625
  function ChatMessage({ message, provider }) {
34547
34626
  switch (message.type) {
34548
- case "user": {
34549
- if (message.content === "Request interrupted") {
34550
- return /* @__PURE__ */ jsx6("box", { paddingX: 1, justifyContent: "center", children: /* @__PURE__ */ jsx6("text", { fg: "#555555", children: "--- Request interrupted ---" }) });
34551
- }
34627
+ case "user":
34552
34628
  return /* @__PURE__ */ jsx6(UserMessageContent, { content: message.content });
34553
- }
34629
+ case "interruption":
34630
+ return /* @__PURE__ */ jsxs6("box", { flexDirection: "column", paddingX: 1, children: [
34631
+ /* @__PURE__ */ jsx6("text", { fg: "#555555", children: formatStoppedAfter(message.durationMs) }),
34632
+ /* @__PURE__ */ jsx6("text", { fg: "#333333", children: "\u2500".repeat(40) })
34633
+ ] });
34554
34634
  case "agent":
34555
34635
  return /* @__PURE__ */ jsxs6("box", { flexDirection: "column", paddingX: 1, children: [
34556
34636
  /* @__PURE__ */ jsx6("text", { children: /* @__PURE__ */ jsx6("span", { fg: "#3eeba3", children: /* @__PURE__ */ jsx6("strong", { children: getProviderDisplayName(provider) }) }) }),
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "replicas-cli",
3
- "version": "0.2.398",
3
+ "version": "0.2.399",
4
4
  "description": "CLI for managing Replicas workspaces - SSH into cloud dev environments with automatic port forwarding",
5
5
  "main": "dist/index.mjs",
6
6
  "bin": {