replicas-cli 0.2.206 → 0.2.208

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 +145 -22
  2. package/package.json +1 -1
package/dist/index.mjs CHANGED
@@ -8981,9 +8981,9 @@ var AGENT_MODELS = {
8981
8981
  };
8982
8982
  var MODEL_LABELS = {
8983
8983
  sonnet: "Sonnet 4.5",
8984
- opus: "Opus 4.7",
8985
- [CLAUDE_OPUS_1M_MODEL]: "Opus 4.7 (1M)",
8986
- [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)",
8987
8987
  haiku: "Haiku 4.5",
8988
8988
  "gpt-5.5": "GPT-5.5",
8989
8989
  "gpt-5.4": "GPT-5.4",
@@ -9384,6 +9384,129 @@ function parseCodexEvents(events) {
9384
9384
  return messages;
9385
9385
  }
9386
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
+
9387
9510
  // ../shared/src/display-message/parsers/mcp.ts
9388
9511
  function parseMcpToolName(name) {
9389
9512
  const prefix = "mcp__";
@@ -9398,14 +9521,6 @@ function parseMcpToolName(name) {
9398
9521
  }
9399
9522
 
9400
9523
  // ../shared/src/display-message/parsers/claude-parser.ts
9401
- function extractToolResultContent(content) {
9402
- if (!content) return "";
9403
- if (typeof content === "string") return content;
9404
- if (Array.isArray(content)) {
9405
- return content.filter((item) => item.type === "text").map((item) => item.text || "").join("\n");
9406
- }
9407
- return "";
9408
- }
9409
9524
  function parseClaudeEvents(events, parentToolUseId) {
9410
9525
  const messages = [];
9411
9526
  const filterValue = parentToolUseId !== void 0 ? parentToolUseId : null;
@@ -9415,11 +9530,20 @@ function parseClaudeEvents(events, parentToolUseId) {
9415
9530
  });
9416
9531
  const toolCallMap = /* @__PURE__ */ new Map();
9417
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
+ }));
9418
9539
  filteredEvents.forEach((event) => {
9419
9540
  if (event.type === "claude-user") {
9420
9541
  const content = event.payload.message?.content || [];
9421
9542
  const toolResult = content.find((c) => c.type === "tool_result");
9422
9543
  if (toolResult && toolResult.tool_use_id) {
9544
+ if (!toolResult.is_error) {
9545
+ taskAccumulator.processContentBlock(toolResult);
9546
+ }
9423
9547
  return;
9424
9548
  }
9425
9549
  if (event.payload.isSynthetic) {
@@ -9540,18 +9664,14 @@ function parseClaudeEvents(events, parentToolUseId) {
9540
9664
  status: "in_progress",
9541
9665
  timestamp: event.timestamp
9542
9666
  });
9543
- } else if (toolName === "TodoWrite") {
9544
- const inputObj = typeof toolInput === "string" ? safeJsonParse(toolInput, {}) : toolInput;
9545
- const todos = Array.isArray(inputObj.todos) ? inputObj.todos : [];
9546
- const todoItems = todos.map((todo) => ({
9547
- text: todo.content,
9548
- completed: todo.status === "completed"
9549
- }));
9550
- 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) {
9551
9671
  messages.push({
9552
9672
  id: `todo-${event.timestamp}-${messages.length}`,
9553
9673
  type: "todo_list",
9554
- items: todoItems,
9674
+ items: snapshot,
9555
9675
  status: "completed",
9556
9676
  timestamp: event.timestamp
9557
9677
  });
@@ -9692,9 +9812,12 @@ function parseClaudeEvents(events, parentToolUseId) {
9692
9812
  if (toolResult && toolResult.tool_use_id) {
9693
9813
  const toolInfo = toolCallMap.get(toolResult.tool_use_id);
9694
9814
  if (!toolInfo) return;
9695
- const resultContent = extractToolResultContent(toolResult.content);
9815
+ const resultContent = extractToolResultText(toolResult.content);
9696
9816
  const isError = toolResult.is_error || false;
9697
9817
  const status = isError ? "failed" : "completed";
9818
+ if (toolInfo.toolName === "TaskCreate" && !isError) {
9819
+ taskAccumulator.processContentBlock(toolResult);
9820
+ }
9698
9821
  const message = messages[toolInfo.messageIndex];
9699
9822
  if (!message) return;
9700
9823
  if (message.type === "command") {
@@ -16800,7 +16923,7 @@ Repository start hooks (${response.repositories.length}):
16800
16923
  }
16801
16924
 
16802
16925
  // src/index.ts
16803
- var CLI_VERSION = "0.2.206";
16926
+ var CLI_VERSION = "0.2.208";
16804
16927
  function parseBooleanOption(value) {
16805
16928
  if (value === "true") return true;
16806
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.206",
3
+ "version": "0.2.208",
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": {