replicas-cli 0.2.397 → 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 +108 -27
  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 = {};
@@ -23417,9 +23418,10 @@ All writes are proposals: a human reviews them in the dashboard, and nothing tak
23417
23418
 
23418
23419
  Use \`replicas learnings --help\` and subcommand help such as \`replicas learnings add --help\`, \`replicas learnings update --help\`, or \`replicas learnings delete --help\` for current command syntax.
23419
23420
 
23420
- **Be very conservative:**
23421
- - Propose \`add\` only for repeatable, org-useful facts likely to matter again: explicit user corrections, hard-won environment or process knowledge.
23422
- - Never store task-specific details, anything derivable by reading the repo, or secrets/credentials.
23421
+ A human approves every proposal before it takes effect, so don't agonize over borderline calls \u2014 but keep proposals genuinely useful rather than reflexive.
23422
+
23423
+ - Propose \`add\` for anything repeatable and org-useful: user corrections and preferences, hard-won environment or process knowledge, conventions and decisions worth following, and gotchas that would waste time again. If you learned it the hard way this task, capture it.
23424
+ - Never store task-specific details that won't recur, facts trivially derivable by reading the repo, or secrets/credentials.
23423
23425
  - Propose \`update\` or \`delete\` when a learning is contradicted by the current code or docs, especially if the outdated guidance would affect future repeated work.
23424
23426
  - Write narrow triggers describing when the entry should surface (e.g. "UI/UX work on the admin panel"), not vague topics.`;
23425
23427
  var LEARNINGS_ABILITY = {
@@ -24375,8 +24377,24 @@ var HOOK_EXEC_MAX_BUFFER_BYTES = 10 * 1024 * 1024;
24375
24377
  // ../shared/src/replicas-config.ts
24376
24378
  var REPLICAS_CONFIG_FILENAMES = ["replicas.json", "replicas.yaml", "replicas.yml"];
24377
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
+
24378
24396
  // ../shared/src/cli-version.ts
24379
- var CLI_VERSION = "0.2.397";
24397
+ var CLI_VERSION = "0.2.399";
24380
24398
 
24381
24399
  // ../shared/src/version.ts
24382
24400
  function compareVersions(v1, v2) {
@@ -24693,16 +24711,20 @@ function normalizeBackgroundTaskStatus(status) {
24693
24711
  return "in_progress";
24694
24712
  }
24695
24713
 
24696
- // ../shared/src/json.ts
24697
- function safeJsonParse(str, fallback) {
24698
- try {
24699
- return JSON.parse(str);
24700
- } catch {
24701
- return fallback;
24702
- }
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;
24703
24724
  }
24704
24725
 
24705
24726
  // ../shared/src/display-message/parsers/utils.ts
24727
+ var INTERRUPTED_MESSAGE_REGEX = /^\[Request interrupted by user.*\]$/;
24706
24728
  function userMessageImages(value) {
24707
24729
  if (!Array.isArray(value)) return void 0;
24708
24730
  const images = value.filter((item) => isRecord(item) && item.type === "image" && typeof item.mediaType === "string" && typeof item.data === "string");
@@ -24718,6 +24740,15 @@ function stringifyDisplayValue(value) {
24718
24740
  }
24719
24741
  }
24720
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
+
24721
24752
  // ../shared/src/display-message/parsers/codex-parser.ts
24722
24753
  function getStatusFromExitCode(exitCode) {
24723
24754
  return exitCode === 0 ? "completed" : "failed";
@@ -25516,6 +25547,7 @@ function parseClaudeEvents(events, parentToolUseId) {
25516
25547
  const assistantThinking = /* @__PURE__ */ new Map();
25517
25548
  const assistantTextCounts = /* @__PURE__ */ new Map();
25518
25549
  const acceptedUserMessageIndexes = /* @__PURE__ */ new Set();
25550
+ let turnWasInterrupted = false;
25519
25551
  const taskAccumulator = new TaskAccumulator();
25520
25552
  const taskSnapshot = () => taskAccumulator.getTasks().map((task) => ({
25521
25553
  text: task.subject,
@@ -25586,6 +25618,7 @@ function parseClaudeEvents(events, parentToolUseId) {
25586
25618
  if (LOCAL_COMMAND_ECHO_REGEX.test(textContent.trim())) {
25587
25619
  return;
25588
25620
  }
25621
+ turnWasInterrupted = INTERRUPTED_MESSAGE_REGEX.test(textContent.trim());
25589
25622
  const images = content.filter((c) => c.type === "image" && c.source).map((c) => {
25590
25623
  const source = c.source;
25591
25624
  return {
@@ -25833,8 +25866,21 @@ function parseClaudeEvents(events, parentToolUseId) {
25833
25866
  }
25834
25867
  if (event.type === "claude-result") {
25835
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
+ }
25836
25883
  if (isClaudeResultError(payload)) {
25837
- const errorList = payload.errors || [];
25838
25884
  const errorMessage = errorList.length > 0 ? errorList.join("\n") : "Claude session encountered an unexpected error.";
25839
25885
  messages.push({
25840
25886
  id: `error-${event.timestamp}`,
@@ -25973,12 +26019,6 @@ function parseClaudeEvents(events, parentToolUseId) {
25973
26019
  return messages.filter((_, index) => !staleIndexes.has(index));
25974
26020
  }
25975
26021
 
25976
- // ../shared/src/agent-event-utils.ts
25977
- function parseTimestampMs(timestamp) {
25978
- const value = Date.parse(timestamp);
25979
- return Number.isFinite(value) ? value : 0;
25980
- }
25981
-
25982
26022
  // ../shared/src/display-message/parsers/codex-asp-parser.ts
25983
26023
  var DUPLICATE_WINDOW_MS = 5 * 60 * 1e3;
25984
26024
  function nearTimestamp(a, b) {
@@ -26171,7 +26211,7 @@ function parseCodexAspTranscript(transcript) {
26171
26211
  }
26172
26212
 
26173
26213
  // ../shared/src/display-message/parsers/index.ts
26174
- var INTERRUPTED_MESSAGE_REGEX = /^\[Request interrupted by user.*\]$/;
26214
+ var INTERRUPTION_DEDUP_WINDOW_MS = 15e3;
26175
26215
  function parseAgentEvents(events, agentType) {
26176
26216
  if (agentType === "codex") {
26177
26217
  return parseCodexEvents(events);
@@ -26191,10 +26231,50 @@ function parseDisplayMessages(events, agentType, codexAspTranscript, options = {
26191
26231
  const shouldFilter = options.filter ?? true;
26192
26232
  const legacyMessages = shouldFilter ? filterDisplayMessages(parseAgentEvents(events, agentType), agentType) : parseAgentEvents(events, agentType);
26193
26233
  if (agentType !== "codex" || !codexAspTranscript) {
26194
- return legacyMessages;
26234
+ return shouldFilter ? applyInterruptions(legacyMessages, events) : legacyMessages;
26195
26235
  }
26196
26236
  const nativeCodexMessages = shouldFilter ? filterDisplayMessages(parseCodexAspTranscript(codexAspTranscript), agentType) : parseCodexAspTranscript(codexAspTranscript);
26197
- 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;
26198
26278
  }
26199
26279
  function isCodexInitializationPrompt(message) {
26200
26280
  return message.type === "user" && removeReplicasInstructions(message.content).trim() === "Hello";
@@ -26229,7 +26309,7 @@ function filterDisplayMessages(messages, provider) {
26229
26309
  if (msg.type !== "user") return msg;
26230
26310
  const cleaned = removeReplicasInstructions(msg.content).trim();
26231
26311
  if (INTERRUPTED_MESSAGE_REGEX.test(cleaned)) {
26232
- return { ...msg, content: "Request interrupted" };
26312
+ return { id: msg.id, type: "interruption", timestamp: msg.timestamp };
26233
26313
  }
26234
26314
  return cleaned !== msg.content ? { ...msg, content: cleaned } : msg;
26235
26315
  });
@@ -34544,12 +34624,13 @@ function UserMessageContent({ content }) {
34544
34624
  }
34545
34625
  function ChatMessage({ message, provider }) {
34546
34626
  switch (message.type) {
34547
- case "user": {
34548
- if (message.content === "Request interrupted") {
34549
- return /* @__PURE__ */ jsx6("box", { paddingX: 1, justifyContent: "center", children: /* @__PURE__ */ jsx6("text", { fg: "#555555", children: "--- Request interrupted ---" }) });
34550
- }
34627
+ case "user":
34551
34628
  return /* @__PURE__ */ jsx6(UserMessageContent, { content: message.content });
34552
- }
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
+ ] });
34553
34634
  case "agent":
34554
34635
  return /* @__PURE__ */ jsxs6("box", { flexDirection: "column", paddingX: 1, children: [
34555
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.397",
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": {