replicas-cli 0.2.398 → 0.2.400

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 +123 -25
  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.400";
24381
24398
 
24382
24399
  // ../shared/src/version.ts
24383
24400
  function compareVersions(v1, v2) {
@@ -24511,9 +24528,27 @@ var workspaceChangedEventSchema = external_exports.discriminatedUnion("type", [
24511
24528
  workspaceId: external_exports.string(),
24512
24529
  chatId: external_exports.string(),
24513
24530
  ts: external_exports.string()
24514
- })
24531
+ }),
24532
+ external_exports.object({ type: external_exports.literal("presence.changed"), ts: external_exports.string() })
24515
24533
  ]);
24516
24534
 
24535
+ // ../shared/src/routes/presence.ts
24536
+ var presenceStatusSchema = external_exports.enum(["online", "typing"]);
24537
+ var presenceLocationSchema = external_exports.object({
24538
+ environmentId: external_exports.string().optional(),
24539
+ workspaceId: external_exports.string().optional()
24540
+ });
24541
+ var presenceEntrySchema = external_exports.object({
24542
+ userId: external_exports.string(),
24543
+ status: presenceStatusSchema,
24544
+ location: presenceLocationSchema,
24545
+ ts: external_exports.string()
24546
+ });
24547
+ var updatePresenceRequestSchema = external_exports.object({
24548
+ status: presenceStatusSchema,
24549
+ location: presenceLocationSchema.optional()
24550
+ });
24551
+
24517
24552
  // ../shared/src/audit-log.ts
24518
24553
  var AUDIT_LOG_ACTION = {
24519
24554
  CREATE: "create",
@@ -24694,16 +24729,20 @@ function normalizeBackgroundTaskStatus(status) {
24694
24729
  return "in_progress";
24695
24730
  }
24696
24731
 
24697
- // ../shared/src/json.ts
24698
- function safeJsonParse(str, fallback) {
24699
- try {
24700
- return JSON.parse(str);
24701
- } catch {
24702
- return fallback;
24703
- }
24732
+ // ../shared/src/display-message/format.ts
24733
+ function formatStoppedAfter(durationMs) {
24734
+ if (durationMs === void 0) return "You stopped";
24735
+ return `You stopped after ${formatTurnElapsed(durationMs)}`;
24736
+ }
24737
+
24738
+ // ../shared/src/agent-event-utils.ts
24739
+ function parseTimestampMs(timestamp) {
24740
+ const value = Date.parse(timestamp);
24741
+ return Number.isFinite(value) ? value : 0;
24704
24742
  }
24705
24743
 
24706
24744
  // ../shared/src/display-message/parsers/utils.ts
24745
+ var INTERRUPTED_MESSAGE_REGEX = /^\[Request interrupted by user.*\]$/;
24707
24746
  function userMessageImages(value) {
24708
24747
  if (!Array.isArray(value)) return void 0;
24709
24748
  const images = value.filter((item) => isRecord(item) && item.type === "image" && typeof item.mediaType === "string" && typeof item.data === "string");
@@ -24719,6 +24758,15 @@ function stringifyDisplayValue(value) {
24719
24758
  }
24720
24759
  }
24721
24760
 
24761
+ // ../shared/src/json.ts
24762
+ function safeJsonParse(str, fallback) {
24763
+ try {
24764
+ return JSON.parse(str);
24765
+ } catch {
24766
+ return fallback;
24767
+ }
24768
+ }
24769
+
24722
24770
  // ../shared/src/display-message/parsers/codex-parser.ts
24723
24771
  function getStatusFromExitCode(exitCode) {
24724
24772
  return exitCode === 0 ? "completed" : "failed";
@@ -25517,6 +25565,7 @@ function parseClaudeEvents(events, parentToolUseId) {
25517
25565
  const assistantThinking = /* @__PURE__ */ new Map();
25518
25566
  const assistantTextCounts = /* @__PURE__ */ new Map();
25519
25567
  const acceptedUserMessageIndexes = /* @__PURE__ */ new Set();
25568
+ let turnWasInterrupted = false;
25520
25569
  const taskAccumulator = new TaskAccumulator();
25521
25570
  const taskSnapshot = () => taskAccumulator.getTasks().map((task) => ({
25522
25571
  text: task.subject,
@@ -25587,6 +25636,7 @@ function parseClaudeEvents(events, parentToolUseId) {
25587
25636
  if (LOCAL_COMMAND_ECHO_REGEX.test(textContent.trim())) {
25588
25637
  return;
25589
25638
  }
25639
+ turnWasInterrupted = INTERRUPTED_MESSAGE_REGEX.test(textContent.trim());
25590
25640
  const images = content.filter((c) => c.type === "image" && c.source).map((c) => {
25591
25641
  const source = c.source;
25592
25642
  return {
@@ -25834,8 +25884,21 @@ function parseClaudeEvents(events, parentToolUseId) {
25834
25884
  }
25835
25885
  if (event.type === "claude-result") {
25836
25886
  const payload = coerceClaudeResultPayload(event.payload);
25887
+ const errorList = payload.errors || [];
25888
+ if (turnWasInterrupted) {
25889
+ turnWasInterrupted = false;
25890
+ const genuineErrors = errorList.filter((e) => !e.includes("[ede_diagnostic]"));
25891
+ if (genuineErrors.length > 0) {
25892
+ messages.push({
25893
+ id: `error-${event.timestamp}`,
25894
+ type: "error",
25895
+ message: genuineErrors.join("\n"),
25896
+ timestamp: event.timestamp
25897
+ });
25898
+ }
25899
+ return;
25900
+ }
25837
25901
  if (isClaudeResultError(payload)) {
25838
- const errorList = payload.errors || [];
25839
25902
  const errorMessage = errorList.length > 0 ? errorList.join("\n") : "Claude session encountered an unexpected error.";
25840
25903
  messages.push({
25841
25904
  id: `error-${event.timestamp}`,
@@ -25974,12 +26037,6 @@ function parseClaudeEvents(events, parentToolUseId) {
25974
26037
  return messages.filter((_, index) => !staleIndexes.has(index));
25975
26038
  }
25976
26039
 
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
26040
  // ../shared/src/display-message/parsers/codex-asp-parser.ts
25984
26041
  var DUPLICATE_WINDOW_MS = 5 * 60 * 1e3;
25985
26042
  function nearTimestamp(a, b) {
@@ -26172,7 +26229,7 @@ function parseCodexAspTranscript(transcript) {
26172
26229
  }
26173
26230
 
26174
26231
  // ../shared/src/display-message/parsers/index.ts
26175
- var INTERRUPTED_MESSAGE_REGEX = /^\[Request interrupted by user.*\]$/;
26232
+ var INTERRUPTION_DEDUP_WINDOW_MS = 15e3;
26176
26233
  function parseAgentEvents(events, agentType) {
26177
26234
  if (agentType === "codex") {
26178
26235
  return parseCodexEvents(events);
@@ -26192,10 +26249,50 @@ function parseDisplayMessages(events, agentType, codexAspTranscript, options = {
26192
26249
  const shouldFilter = options.filter ?? true;
26193
26250
  const legacyMessages = shouldFilter ? filterDisplayMessages(parseAgentEvents(events, agentType), agentType) : parseAgentEvents(events, agentType);
26194
26251
  if (agentType !== "codex" || !codexAspTranscript) {
26195
- return legacyMessages;
26252
+ return shouldFilter ? applyInterruptions(legacyMessages, events) : legacyMessages;
26196
26253
  }
26197
26254
  const nativeCodexMessages = shouldFilter ? filterDisplayMessages(parseCodexAspTranscript(codexAspTranscript), agentType) : parseCodexAspTranscript(codexAspTranscript);
26198
- return mergeCodexAspDisplayMessages(nativeCodexMessages, legacyMessages);
26255
+ const merged = mergeCodexAspDisplayMessages(nativeCodexMessages, legacyMessages);
26256
+ return shouldFilter ? applyInterruptions(merged, events) : merged;
26257
+ }
26258
+ function applyInterruptions(messages, events) {
26259
+ const result = [...messages];
26260
+ for (const event of events) {
26261
+ if (event.type !== CHAT_INTERRUPTED_EVENT_TYPE) continue;
26262
+ const eventMs = parseTimestampMs(event.timestamp);
26263
+ let index = result.length;
26264
+ while (index > 0 && parseTimestampMs(result[index - 1].timestamp) > eventMs) index--;
26265
+ result.splice(index, 0, {
26266
+ id: `interruption-${event.timestamp}`,
26267
+ type: "interruption",
26268
+ timestamp: event.timestamp
26269
+ });
26270
+ }
26271
+ let lastUserMs = null;
26272
+ let lastInterruption = null;
26273
+ const finalized = [];
26274
+ for (const msg of result) {
26275
+ if (msg.type === "user") {
26276
+ lastUserMs = parseTimestampMs(msg.timestamp);
26277
+ lastInterruption = null;
26278
+ finalized.push(msg);
26279
+ continue;
26280
+ }
26281
+ if (msg.type !== "interruption") {
26282
+ finalized.push(msg);
26283
+ continue;
26284
+ }
26285
+ const ms = parseTimestampMs(msg.timestamp);
26286
+ if (lastInterruption && ms - parseTimestampMs(lastInterruption.timestamp) <= INTERRUPTION_DEDUP_WINDOW_MS) {
26287
+ continue;
26288
+ }
26289
+ lastInterruption = {
26290
+ ...msg,
26291
+ ...lastUserMs !== null && ms >= lastUserMs ? { durationMs: ms - lastUserMs } : {}
26292
+ };
26293
+ finalized.push(lastInterruption);
26294
+ }
26295
+ return finalized;
26199
26296
  }
26200
26297
  function isCodexInitializationPrompt(message) {
26201
26298
  return message.type === "user" && removeReplicasInstructions(message.content).trim() === "Hello";
@@ -26230,7 +26327,7 @@ function filterDisplayMessages(messages, provider) {
26230
26327
  if (msg.type !== "user") return msg;
26231
26328
  const cleaned = removeReplicasInstructions(msg.content).trim();
26232
26329
  if (INTERRUPTED_MESSAGE_REGEX.test(cleaned)) {
26233
- return { ...msg, content: "Request interrupted" };
26330
+ return { id: msg.id, type: "interruption", timestamp: msg.timestamp };
26234
26331
  }
26235
26332
  return cleaned !== msg.content ? { ...msg, content: cleaned } : msg;
26236
26333
  });
@@ -34545,12 +34642,13 @@ function UserMessageContent({ content }) {
34545
34642
  }
34546
34643
  function ChatMessage({ message, provider }) {
34547
34644
  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
- }
34645
+ case "user":
34552
34646
  return /* @__PURE__ */ jsx6(UserMessageContent, { content: message.content });
34553
- }
34647
+ case "interruption":
34648
+ return /* @__PURE__ */ jsxs6("box", { flexDirection: "column", paddingX: 1, children: [
34649
+ /* @__PURE__ */ jsx6("text", { fg: "#555555", children: formatStoppedAfter(message.durationMs) }),
34650
+ /* @__PURE__ */ jsx6("text", { fg: "#333333", children: "\u2500".repeat(40) })
34651
+ ] });
34554
34652
  case "agent":
34555
34653
  return /* @__PURE__ */ jsxs6("box", { flexDirection: "column", paddingX: 1, children: [
34556
34654
  /* @__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.400",
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": {