replicas-cli 0.2.205 → 0.2.207

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 +233 -41
  2. package/package.json +1 -1
package/dist/index.mjs CHANGED
@@ -7491,6 +7491,11 @@ async function getCurrentUser() {
7491
7491
  };
7492
7492
  }
7493
7493
 
7494
+ // ../shared/src/type-guards.ts
7495
+ function isRecord(value) {
7496
+ return typeof value === "object" && value !== null && !Array.isArray(value);
7497
+ }
7498
+
7494
7499
  // ../shared/src/agent.ts
7495
7500
  var VALID_AGENT_PROVIDERS = ["claude", "codex", "relay"];
7496
7501
  function isValidAgentProvider(value) {
@@ -8976,9 +8981,9 @@ var AGENT_MODELS = {
8976
8981
  };
8977
8982
  var MODEL_LABELS = {
8978
8983
  sonnet: "Sonnet 4.5",
8979
- opus: "Opus 4.7",
8980
- [CLAUDE_OPUS_1M_MODEL]: "Opus 4.7 (1M)",
8981
- [LEGACY_CLAUDE_OPUS_1M_MODEL]: "Opus 4.7 (1M)",
8984
+ opus: "Opus 4.8",
8985
+ [CLAUDE_OPUS_1M_MODEL]: "Opus 4.8 (1M)",
8986
+ [LEGACY_CLAUDE_OPUS_1M_MODEL]: "Opus 4.8 (1M)",
8982
8987
  haiku: "Haiku 4.5",
8983
8988
  "gpt-5.5": "GPT-5.5",
8984
8989
  "gpt-5.4": "GPT-5.4",
@@ -9093,7 +9098,51 @@ var GITHUB_TRIGGER = {
9093
9098
  ]
9094
9099
  };
9095
9100
 
9096
- // ../shared/src/display-message/parsers/codex-parser.ts
9101
+ // ../shared/src/display-message/types.ts
9102
+ var BACKGROUND_TASK_SUBTYPES = /* @__PURE__ */ new Set([
9103
+ "task_started",
9104
+ "task_progress",
9105
+ "task_updated",
9106
+ "task_notification"
9107
+ ]);
9108
+ function isBackgroundTaskSubtype(subtype) {
9109
+ return typeof subtype === "string" && BACKGROUND_TASK_SUBTYPES.has(subtype);
9110
+ }
9111
+ function optionalString(value) {
9112
+ return typeof value === "string" ? value : void 0;
9113
+ }
9114
+ function coerceBackgroundTaskPayload(payload) {
9115
+ if (!isRecord(payload)) return null;
9116
+ const subtype = payload.subtype;
9117
+ if (!isBackgroundTaskSubtype(subtype)) return null;
9118
+ const taskId = payload.task_id;
9119
+ if (typeof taskId !== "string" || !taskId) return null;
9120
+ const patch = isRecord(payload.patch) ? {
9121
+ status: optionalString(payload.patch.status),
9122
+ description: optionalString(payload.patch.description),
9123
+ error: optionalString(payload.patch.error)
9124
+ } : void 0;
9125
+ return {
9126
+ subtype,
9127
+ taskId,
9128
+ description: optionalString(payload.description),
9129
+ summary: optionalString(payload.summary),
9130
+ outputFile: optionalString(payload.output_file),
9131
+ status: optionalString(payload.status),
9132
+ patch
9133
+ };
9134
+ }
9135
+ function normalizeBackgroundTaskStatus(status) {
9136
+ if (status === "completed" || status === "failed" || status === "stopped") {
9137
+ return status;
9138
+ }
9139
+ if (status === "killed") {
9140
+ return "stopped";
9141
+ }
9142
+ return "in_progress";
9143
+ }
9144
+
9145
+ // ../shared/src/json.ts
9097
9146
  function safeJsonParse(str, fallback) {
9098
9147
  try {
9099
9148
  return JSON.parse(str);
@@ -9101,6 +9150,8 @@ function safeJsonParse(str, fallback) {
9101
9150
  return fallback;
9102
9151
  }
9103
9152
  }
9153
+
9154
+ // ../shared/src/display-message/parsers/codex-parser.ts
9104
9155
  function getStatusFromExitCode(exitCode) {
9105
9156
  return exitCode === 0 ? "completed" : "failed";
9106
9157
  }
@@ -9333,6 +9384,129 @@ function parseCodexEvents(events) {
9333
9384
  return messages;
9334
9385
  }
9335
9386
 
9387
+ // ../shared/src/display-message/task-accumulator.ts
9388
+ function mapTaskStatus(status) {
9389
+ if (status === "in_progress" || status === "completed") return status;
9390
+ return "pending";
9391
+ }
9392
+ function toAccumulatorInput(input) {
9393
+ if (typeof input === "string") {
9394
+ try {
9395
+ const parsed = JSON.parse(input);
9396
+ return isRecord(parsed) ? parsed : {};
9397
+ } catch {
9398
+ return {};
9399
+ }
9400
+ }
9401
+ return isRecord(input) ? input : {};
9402
+ }
9403
+ function extractToolResultText(content, separator = "\n") {
9404
+ if (typeof content === "string") return content;
9405
+ if (!Array.isArray(content)) return "";
9406
+ const texts = [];
9407
+ for (const part of content) {
9408
+ if (isRecord(part) && part.type === "text" && typeof part.text === "string") {
9409
+ texts.push(part.text);
9410
+ }
9411
+ }
9412
+ return texts.join(separator);
9413
+ }
9414
+ function parseStringField(value) {
9415
+ if (typeof value !== "string") return null;
9416
+ const trimmed = value.trim();
9417
+ return trimmed ? trimmed : null;
9418
+ }
9419
+ function parseCreateResultTaskId(resultText) {
9420
+ try {
9421
+ const parsed = JSON.parse(resultText);
9422
+ if (isRecord(parsed) && isRecord(parsed.task)) {
9423
+ return parseStringField(parsed.task.id);
9424
+ }
9425
+ } catch {
9426
+ }
9427
+ return resultText.match(/\bTask\s+#?([A-Za-z0-9_-]+)\s+created\b/i)?.[1] ?? null;
9428
+ }
9429
+ var TaskAccumulator = class {
9430
+ constructor() {
9431
+ this.tasksByTaskId = /* @__PURE__ */ new Map();
9432
+ this.tasksByCreateToolUseId = /* @__PURE__ */ new Map();
9433
+ this.orderedKeys = [];
9434
+ }
9435
+ processToolUse(toolName, toolUseId, input) {
9436
+ if (toolName === "TaskCreate") {
9437
+ const subject = parseStringField(input.subject);
9438
+ if (!subject) return false;
9439
+ this.tasksByCreateToolUseId.set(toolUseId, { subject, status: "pending" });
9440
+ this.orderedKeys.push(toolUseId);
9441
+ return true;
9442
+ }
9443
+ if (toolName === "TaskUpdate") {
9444
+ const taskId = parseStringField(input.taskId);
9445
+ if (!taskId) return false;
9446
+ if (input.status === "deleted") {
9447
+ if (!this.tasksByTaskId.delete(taskId)) return false;
9448
+ const idx = this.orderedKeys.indexOf(taskId);
9449
+ if (idx !== -1) this.orderedKeys.splice(idx, 1);
9450
+ return true;
9451
+ }
9452
+ const existing = this.tasksByTaskId.get(taskId);
9453
+ const subject = parseStringField(input.subject) ?? existing?.subject;
9454
+ if (!subject) return false;
9455
+ const status = input.status !== void 0 ? mapTaskStatus(input.status) : existing?.status ?? "pending";
9456
+ this.tasksByTaskId.set(taskId, { subject, status });
9457
+ if (!existing) this.orderedKeys.push(taskId);
9458
+ return true;
9459
+ }
9460
+ if (toolName === "TaskList") {
9461
+ if (!Array.isArray(input.tasks)) return false;
9462
+ let changed = false;
9463
+ for (const raw of input.tasks) {
9464
+ if (!isRecord(raw)) continue;
9465
+ const id = parseStringField(raw.id);
9466
+ const subject = parseStringField(raw.subject);
9467
+ if (!id || !subject) continue;
9468
+ const existing = this.tasksByTaskId.get(id);
9469
+ const next = { subject, status: mapTaskStatus(raw.status) };
9470
+ if (existing && existing.subject === next.subject && existing.status === next.status) continue;
9471
+ this.tasksByTaskId.set(id, next);
9472
+ if (!existing) this.orderedKeys.push(id);
9473
+ changed = true;
9474
+ }
9475
+ return changed;
9476
+ }
9477
+ return false;
9478
+ }
9479
+ processCreateResult(toolUseId, resultText) {
9480
+ const pending = this.tasksByCreateToolUseId.get(toolUseId);
9481
+ if (!pending) return false;
9482
+ const taskId = parseCreateResultTaskId(resultText);
9483
+ if (!taskId) return false;
9484
+ this.tasksByTaskId.set(taskId, pending);
9485
+ this.tasksByCreateToolUseId.delete(toolUseId);
9486
+ const idx = this.orderedKeys.indexOf(toolUseId);
9487
+ if (idx !== -1) this.orderedKeys.splice(idx, 1, taskId);
9488
+ return true;
9489
+ }
9490
+ getTasks() {
9491
+ const out = [];
9492
+ for (const key of this.orderedKeys) {
9493
+ const task = this.tasksByTaskId.get(key) ?? this.tasksByCreateToolUseId.get(key);
9494
+ if (task && task.subject) out.push(task);
9495
+ }
9496
+ return out;
9497
+ }
9498
+ processContentBlock(block) {
9499
+ if (!isRecord(block)) return false;
9500
+ if (block.type === "tool_use" && typeof block.name === "string" && typeof block.id === "string") {
9501
+ return this.processToolUse(block.name, block.id, toAccumulatorInput(block.input));
9502
+ }
9503
+ if (block.type === "tool_result" && typeof block.tool_use_id === "string") {
9504
+ return this.processCreateResult(block.tool_use_id, extractToolResultText(block.content, ""));
9505
+ }
9506
+ return false;
9507
+ }
9508
+ };
9509
+
9336
9510
  // ../shared/src/display-message/parsers/mcp.ts
9337
9511
  function parseMcpToolName(name) {
9338
9512
  const prefix = "mcp__";
@@ -9347,33 +9521,29 @@ function parseMcpToolName(name) {
9347
9521
  }
9348
9522
 
9349
9523
  // ../shared/src/display-message/parsers/claude-parser.ts
9350
- function safeJsonParse2(str, fallback) {
9351
- try {
9352
- return JSON.parse(str);
9353
- } catch {
9354
- return fallback;
9355
- }
9356
- }
9357
- function extractToolResultContent(content) {
9358
- if (!content) return "";
9359
- if (typeof content === "string") return content;
9360
- if (Array.isArray(content)) {
9361
- return content.filter((item) => item.type === "text").map((item) => item.text || "").join("\n");
9362
- }
9363
- return "";
9364
- }
9365
9524
  function parseClaudeEvents(events, parentToolUseId) {
9366
9525
  const messages = [];
9367
9526
  const filterValue = parentToolUseId !== void 0 ? parentToolUseId : null;
9368
- const filteredEvents = events.filter(
9369
- (e) => e.payload.parent_tool_use_id === filterValue
9370
- );
9527
+ const filteredEvents = events.filter((e) => {
9528
+ const eventParentToolUseId = e.payload.parent_tool_use_id ?? null;
9529
+ return eventParentToolUseId === filterValue;
9530
+ });
9371
9531
  const toolCallMap = /* @__PURE__ */ new Map();
9532
+ const taskMessageMap = /* @__PURE__ */ new Map();
9533
+ const taskAccumulator = new TaskAccumulator();
9534
+ const taskSnapshot = () => taskAccumulator.getTasks().map((task) => ({
9535
+ text: task.subject,
9536
+ completed: task.status === "completed",
9537
+ itemStatus: task.status
9538
+ }));
9372
9539
  filteredEvents.forEach((event) => {
9373
9540
  if (event.type === "claude-user") {
9374
9541
  const content = event.payload.message?.content || [];
9375
9542
  const toolResult = content.find((c) => c.type === "tool_result");
9376
9543
  if (toolResult && toolResult.tool_use_id) {
9544
+ if (!toolResult.is_error) {
9545
+ taskAccumulator.processContentBlock(toolResult);
9546
+ }
9377
9547
  return;
9378
9548
  }
9379
9549
  if (event.payload.isSynthetic) {
@@ -9428,7 +9598,7 @@ function parseClaudeEvents(events, parentToolUseId) {
9428
9598
  input: toolInput
9429
9599
  });
9430
9600
  if (toolName === "Task" || toolName === "Agent") {
9431
- const inputObj = typeof toolInput === "string" ? safeJsonParse2(toolInput, {}) : toolInput;
9601
+ const inputObj = typeof toolInput === "string" ? safeJsonParse(toolInput, {}) : toolInput;
9432
9602
  const nestedEvents = events.filter((e) => e.payload.parent_tool_use_id === toolUseId).map((e) => ({
9433
9603
  timestamp: e.timestamp,
9434
9604
  type: e.type,
@@ -9447,7 +9617,7 @@ function parseClaudeEvents(events, parentToolUseId) {
9447
9617
  timestamp: event.timestamp
9448
9618
  });
9449
9619
  } else if (toolName === "Bash" || toolName === "bash" || toolName === "shell") {
9450
- const inputObj = typeof toolInput === "string" ? safeJsonParse2(toolInput, {}) : toolInput;
9620
+ const inputObj = typeof toolInput === "string" ? safeJsonParse(toolInput, {}) : toolInput;
9451
9621
  const command = inputObj.command || "";
9452
9622
  messages.push({
9453
9623
  id: `command-${event.timestamp}-${messages.length}`,
@@ -9458,7 +9628,7 @@ function parseClaudeEvents(events, parentToolUseId) {
9458
9628
  timestamp: event.timestamp
9459
9629
  });
9460
9630
  } else if (toolName === "Write" || toolName === "Edit") {
9461
- const inputObj = typeof toolInput === "string" ? safeJsonParse2(toolInput, {}) : toolInput;
9631
+ const inputObj = typeof toolInput === "string" ? safeJsonParse(toolInput, {}) : toolInput;
9462
9632
  const filePath = inputObj.file_path || "";
9463
9633
  const action = toolName === "Write" ? "add" : "update";
9464
9634
  let diff;
@@ -9494,24 +9664,20 @@ function parseClaudeEvents(events, parentToolUseId) {
9494
9664
  status: "in_progress",
9495
9665
  timestamp: event.timestamp
9496
9666
  });
9497
- } else if (toolName === "TodoWrite") {
9498
- const inputObj = typeof toolInput === "string" ? safeJsonParse2(toolInput, {}) : toolInput;
9499
- const todos = Array.isArray(inputObj.todos) ? inputObj.todos : [];
9500
- const todoItems = todos.map((todo) => ({
9501
- text: todo.content,
9502
- completed: todo.status === "completed"
9503
- }));
9504
- if (todoItems.length > 0) {
9667
+ } else if (toolName === "TaskCreate" || toolName === "TaskUpdate" || toolName === "TaskList") {
9668
+ taskAccumulator.processContentBlock(block);
9669
+ const snapshot = taskSnapshot();
9670
+ if (snapshot.length > 0) {
9505
9671
  messages.push({
9506
9672
  id: `todo-${event.timestamp}-${messages.length}`,
9507
9673
  type: "todo_list",
9508
- items: todoItems,
9674
+ items: snapshot,
9509
9675
  status: "completed",
9510
9676
  timestamp: event.timestamp
9511
9677
  });
9512
9678
  }
9513
9679
  } else if (toolName === "WebSearch") {
9514
- const inputObj = typeof toolInput === "string" ? safeJsonParse2(toolInput, {}) : toolInput;
9680
+ const inputObj = typeof toolInput === "string" ? safeJsonParse(toolInput, {}) : toolInput;
9515
9681
  const query = inputObj.query || "";
9516
9682
  messages.push({
9517
9683
  id: `search-${event.timestamp}-${messages.length}`,
@@ -9521,7 +9687,7 @@ function parseClaudeEvents(events, parentToolUseId) {
9521
9687
  timestamp: event.timestamp
9522
9688
  });
9523
9689
  } else if (toolName === "Skill") {
9524
- const inputObj = typeof toolInput === "string" ? safeJsonParse2(toolInput, {}) : toolInput;
9690
+ const inputObj = typeof toolInput === "string" ? safeJsonParse(toolInput, {}) : toolInput;
9525
9691
  messages.push({
9526
9692
  id: `skill-${event.timestamp}-${messages.length}`,
9527
9693
  type: "skill",
@@ -9531,7 +9697,7 @@ function parseClaudeEvents(events, parentToolUseId) {
9531
9697
  timestamp: event.timestamp
9532
9698
  });
9533
9699
  } else if (toolName === "mcp__relay-subagent-tools__spawn_agent") {
9534
- const inputObj = typeof toolInput === "string" ? safeJsonParse2(toolInput, {}) : toolInput;
9700
+ const inputObj = typeof toolInput === "string" ? safeJsonParse(toolInput, {}) : toolInput;
9535
9701
  messages.push({
9536
9702
  id: `subagent-${event.timestamp}-${messages.length}`,
9537
9703
  type: "subagent",
@@ -9546,7 +9712,7 @@ function parseClaudeEvents(events, parentToolUseId) {
9546
9712
  timestamp: event.timestamp
9547
9713
  });
9548
9714
  } else if (toolName === "mcp__relay-subagent-tools__delete_agent") {
9549
- const inputObj = typeof toolInput === "string" ? safeJsonParse2(toolInput, {}) : toolInput;
9715
+ const inputObj = typeof toolInput === "string" ? safeJsonParse(toolInput, {}) : toolInput;
9550
9716
  const mcp = parseMcpToolName(toolName);
9551
9717
  messages.push({
9552
9718
  id: `toolcall-${event.timestamp}-${messages.length}`,
@@ -9584,6 +9750,29 @@ function parseClaudeEvents(events, parentToolUseId) {
9584
9750
  });
9585
9751
  }
9586
9752
  }
9753
+ if (event.type === "claude-system") {
9754
+ const payload = coerceBackgroundTaskPayload(event.payload);
9755
+ if (payload) {
9756
+ const existing = taskMessageMap.get(payload.taskId);
9757
+ const nextStatus = payload.subtype === "task_notification" ? normalizeBackgroundTaskStatus(payload.status) : payload.subtype === "task_updated" ? normalizeBackgroundTaskStatus(payload.patch?.status) : existing?.status ?? "in_progress";
9758
+ const nextMessage = {
9759
+ id: existing?.id ?? `task-${event.timestamp}-${messages.length}`,
9760
+ type: "background_task",
9761
+ taskId: payload.taskId,
9762
+ status: nextStatus,
9763
+ description: payload.description ?? payload.patch?.description ?? existing?.description,
9764
+ summary: payload.summary ?? payload.patch?.error ?? existing?.summary,
9765
+ outputFile: payload.outputFile ?? existing?.outputFile,
9766
+ timestamp: existing?.timestamp ?? event.timestamp
9767
+ };
9768
+ if (existing) {
9769
+ Object.assign(existing, nextMessage);
9770
+ } else {
9771
+ taskMessageMap.set(payload.taskId, nextMessage);
9772
+ messages.push(nextMessage);
9773
+ }
9774
+ }
9775
+ }
9587
9776
  });
9588
9777
  filteredEvents.forEach((event) => {
9589
9778
  if (event.type === "replicas-tool-input-request") {
@@ -9623,9 +9812,12 @@ function parseClaudeEvents(events, parentToolUseId) {
9623
9812
  if (toolResult && toolResult.tool_use_id) {
9624
9813
  const toolInfo = toolCallMap.get(toolResult.tool_use_id);
9625
9814
  if (!toolInfo) return;
9626
- const resultContent = extractToolResultContent(toolResult.content);
9815
+ const resultContent = extractToolResultText(toolResult.content);
9627
9816
  const isError = toolResult.is_error || false;
9628
9817
  const status = isError ? "failed" : "completed";
9818
+ if (toolInfo.toolName === "TaskCreate" && !isError) {
9819
+ taskAccumulator.processContentBlock(toolResult);
9820
+ }
9629
9821
  const message = messages[toolInfo.messageIndex];
9630
9822
  if (!message) return;
9631
9823
  if (message.type === "command") {
@@ -9650,7 +9842,7 @@ function parseClaudeEvents(events, parentToolUseId) {
9650
9842
  message.output = resultContent;
9651
9843
  message.status = status;
9652
9844
  if (!message.chatId && resultContent) {
9653
- const parsed = safeJsonParse2(resultContent, {});
9845
+ const parsed = safeJsonParse(resultContent, {});
9654
9846
  if (parsed.chatId) {
9655
9847
  message.chatId = parsed.chatId;
9656
9848
  }
@@ -16731,7 +16923,7 @@ Repository start hooks (${response.repositories.length}):
16731
16923
  }
16732
16924
 
16733
16925
  // src/index.ts
16734
- var CLI_VERSION = "0.2.205";
16926
+ var CLI_VERSION = "0.2.207";
16735
16927
  function parseBooleanOption(value) {
16736
16928
  if (value === "true") return true;
16737
16929
  if (value === "false") return false;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "replicas-cli",
3
- "version": "0.2.205",
3
+ "version": "0.2.207",
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": {