@vm0/cli 9.85.2 → 9.86.0

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.
@@ -47,7 +47,7 @@ if (DSN) {
47
47
  Sentry.init({
48
48
  dsn: DSN,
49
49
  environment: process.env.SENTRY_ENVIRONMENT ?? "production",
50
- release: "9.85.2",
50
+ release: "9.86.0",
51
51
  sendDefaultPii: false,
52
52
  tracesSampleRate: 0,
53
53
  shutdownTimeout: 500,
@@ -66,7 +66,7 @@ if (DSN) {
66
66
  }
67
67
  });
68
68
  Sentry.setContext("cli", {
69
- version: "9.85.2",
69
+ version: "9.86.0",
70
70
  command: process.argv.slice(2).join(" ")
71
71
  });
72
72
  Sentry.setContext("runtime", {
@@ -13949,7 +13949,8 @@ var triggerSourceSchema = z6.enum([
13949
13949
  "email",
13950
13950
  "telegram",
13951
13951
  "github",
13952
- "cli"
13952
+ "cli",
13953
+ "agent"
13953
13954
  ]);
13954
13955
  var logEntrySchema = z6.object({
13955
13956
  id: z6.uuid(),
@@ -19152,18 +19153,49 @@ async function resolveZeroScheduleByAgent(agentIdentifier, scheduleName) {
19152
19153
  );
19153
19154
  }
19154
19155
 
19155
- // src/lib/api/domains/zero-ask-user.ts
19156
+ // src/lib/api/domains/zero-runs.ts
19156
19157
  import { initClient as initClient18 } from "@ts-rest/core";
19158
+ async function createZeroRun(body) {
19159
+ const config = await getClientConfig();
19160
+ const client = initClient18(zeroRunsMainContract, config);
19161
+ const result = await client.create({ body });
19162
+ if (result.status === 201) return result.body;
19163
+ handleError(result, "Failed to create zero run");
19164
+ }
19165
+ async function getZeroRun(id) {
19166
+ const config = await getClientConfig();
19167
+ const client = initClient18(zeroRunsByIdContract, config);
19168
+ const result = await client.getById({ params: { id } });
19169
+ if (result.status === 200) return result.body;
19170
+ handleError(result, `Failed to get zero run "${id}"`);
19171
+ }
19172
+ async function getZeroRunAgentEvents(id, options) {
19173
+ const config = await getClientConfig();
19174
+ const client = initClient18(zeroRunAgentEventsContract, config);
19175
+ const result = await client.getAgentEvents({
19176
+ params: { id },
19177
+ query: {
19178
+ since: options?.since,
19179
+ limit: options?.limit ?? 100,
19180
+ order: options?.order ?? "asc"
19181
+ }
19182
+ });
19183
+ if (result.status === 200) return result.body;
19184
+ handleError(result, `Failed to get zero run events for "${id}"`);
19185
+ }
19186
+
19187
+ // src/lib/api/domains/zero-ask-user.ts
19188
+ import { initClient as initClient19 } from "@ts-rest/core";
19157
19189
  async function postAskUserQuestion(body) {
19158
19190
  const config = await getClientConfig();
19159
- const client = initClient18(zeroAskUserQuestionContract, config);
19191
+ const client = initClient19(zeroAskUserQuestionContract, config);
19160
19192
  const result = await client.postQuestion({ body, headers: {} });
19161
19193
  if (result.status === 200) return result.body;
19162
19194
  handleError(result, "Failed to post question");
19163
19195
  }
19164
19196
  async function getAskUserAnswer(pendingId) {
19165
19197
  const config = await getClientConfig();
19166
- const client = initClient18(zeroAskUserAnswerContract, config);
19198
+ const client = initClient19(zeroAskUserAnswerContract, config);
19167
19199
  const result = await client.getAnswer({
19168
19200
  query: { pendingId },
19169
19201
  headers: {}
@@ -19255,6 +19287,753 @@ async function promptPassword(message) {
19255
19287
  return response.value;
19256
19288
  }
19257
19289
 
19290
+ // src/lib/events/claude-event-parser.ts
19291
+ var ClaudeEventParser = class {
19292
+ /**
19293
+ * Parse a raw Claude Code JSONL event into a simplified format
19294
+ * Returns null if the event type is unknown or malformed
19295
+ */
19296
+ static parse(rawEvent) {
19297
+ if (!rawEvent || typeof rawEvent !== "object" || !("type" in rawEvent)) {
19298
+ return null;
19299
+ }
19300
+ switch (rawEvent.type) {
19301
+ case "system":
19302
+ return this.parseSystemEvent(rawEvent);
19303
+ case "assistant":
19304
+ return this.parseAssistantMessage(rawEvent);
19305
+ case "user":
19306
+ return this.parseUserMessage(rawEvent);
19307
+ case "result":
19308
+ return this.parseResultEvent(rawEvent);
19309
+ default:
19310
+ return null;
19311
+ }
19312
+ }
19313
+ static parseSystemEvent(event) {
19314
+ if (event.subtype !== "init") {
19315
+ return null;
19316
+ }
19317
+ return {
19318
+ type: "init",
19319
+ timestamp: /* @__PURE__ */ new Date(),
19320
+ data: {
19321
+ framework: "claude-code",
19322
+ sessionId: event.session_id,
19323
+ model: event.model,
19324
+ tools: event.tools,
19325
+ ...event.cwd && { cwd: event.cwd }
19326
+ }
19327
+ };
19328
+ }
19329
+ static parseAssistantMessage(event) {
19330
+ if (!event.message?.content || event.message.content.length === 0) {
19331
+ return null;
19332
+ }
19333
+ const content = event.message.content[0];
19334
+ if (!content) {
19335
+ return null;
19336
+ }
19337
+ if (content.type === "text") {
19338
+ return {
19339
+ type: "text",
19340
+ timestamp: /* @__PURE__ */ new Date(),
19341
+ data: { text: content.text }
19342
+ };
19343
+ }
19344
+ if (content.type === "tool_use") {
19345
+ return {
19346
+ type: "tool_use",
19347
+ timestamp: /* @__PURE__ */ new Date(),
19348
+ data: {
19349
+ tool: content.name,
19350
+ toolUseId: content.id,
19351
+ input: content.input || {}
19352
+ }
19353
+ };
19354
+ }
19355
+ return null;
19356
+ }
19357
+ static parseUserMessage(event) {
19358
+ if (!event.message?.content || event.message.content.length === 0) {
19359
+ return null;
19360
+ }
19361
+ const content = event.message.content[0];
19362
+ if (!content) {
19363
+ return null;
19364
+ }
19365
+ if (content.type === "tool_result") {
19366
+ return {
19367
+ type: "tool_result",
19368
+ timestamp: /* @__PURE__ */ new Date(),
19369
+ data: {
19370
+ toolUseId: content.tool_use_id,
19371
+ result: content.content,
19372
+ isError: content.is_error || false
19373
+ }
19374
+ };
19375
+ }
19376
+ return null;
19377
+ }
19378
+ static parseResultEvent(event) {
19379
+ return {
19380
+ type: "result",
19381
+ timestamp: /* @__PURE__ */ new Date(),
19382
+ data: {
19383
+ success: !event.is_error,
19384
+ result: event.result,
19385
+ durationMs: event.duration_ms,
19386
+ numTurns: event.num_turns,
19387
+ cost: event.total_cost_usd,
19388
+ usage: event.usage
19389
+ }
19390
+ };
19391
+ }
19392
+ };
19393
+
19394
+ // src/lib/events/event-renderer.ts
19395
+ import chalk4 from "chalk";
19396
+
19397
+ // src/lib/events/tool-formatters.ts
19398
+ import chalk3 from "chalk";
19399
+ function pluralize(count, singular, plural) {
19400
+ return count === 1 ? singular : plural;
19401
+ }
19402
+ function truncate(text, maxLength) {
19403
+ if (text.length <= maxLength) return text;
19404
+ return text.slice(0, maxLength - 3) + "...";
19405
+ }
19406
+ function formatToolHeader(data) {
19407
+ const { tool, input } = data;
19408
+ const headline = getToolHeadline(tool, input);
19409
+ return [headline];
19410
+ }
19411
+ var toolHeadlineFormatters = {
19412
+ Read: (input) => `Read${chalk3.dim(`(${String(input.file_path || "")})`)}`,
19413
+ Edit: (input) => `Edit${chalk3.dim(`(${String(input.file_path || "")})`)}`,
19414
+ Write: (input) => `Write${chalk3.dim(`(${String(input.file_path || "")})`)}`,
19415
+ Bash: (input) => `Bash${chalk3.dim(`(${truncate(String(input.command || ""), 60)})`)}`,
19416
+ Glob: (input) => `Glob${chalk3.dim(`(${String(input.pattern || "")})`)}`,
19417
+ Grep: (input) => `Grep${chalk3.dim(`(${String(input.pattern || "")})`)}`,
19418
+ Task: (input) => `Task${chalk3.dim(`(${truncate(String(input.description || ""), 60)})`)}`,
19419
+ WebFetch: (input) => `WebFetch${chalk3.dim(`(${truncate(String(input.url || ""), 60)})`)}`,
19420
+ WebSearch: (input) => `WebSearch${chalk3.dim(`(${truncate(String(input.query || ""), 60)})`)}`,
19421
+ TodoWrite: () => "TodoWrite"
19422
+ };
19423
+ function getToolHeadline(tool, input) {
19424
+ const formatter = toolHeadlineFormatters[tool];
19425
+ return formatter ? formatter(input) : tool;
19426
+ }
19427
+ function formatToolResult(toolUse, result, verbose) {
19428
+ const { tool, input } = toolUse;
19429
+ const { result: resultText, isError } = result;
19430
+ const lines = [];
19431
+ if (tool === "Read" && !isError && resultText) {
19432
+ const readLines = formatReadContent(resultText, verbose);
19433
+ lines.push(...readLines);
19434
+ return lines;
19435
+ }
19436
+ if (tool === "TodoWrite" && !isError) {
19437
+ const todoLines = formatTodoList(input);
19438
+ lines.push(...todoLines);
19439
+ return lines;
19440
+ }
19441
+ if (tool === "Edit" && !isError) {
19442
+ const editLines = formatEditDiff(input, verbose);
19443
+ lines.push(...editLines);
19444
+ return lines;
19445
+ }
19446
+ if (tool === "Write" && !isError) {
19447
+ const writeLines = formatWritePreview(input, verbose);
19448
+ lines.push(...writeLines);
19449
+ return lines;
19450
+ }
19451
+ if (isError) {
19452
+ const errorMsg = resultText ? truncate(resultText, 80) : "Error";
19453
+ lines.push(`\u2514 \u2717 ${chalk3.dim(errorMsg)}`);
19454
+ return lines;
19455
+ }
19456
+ if (resultText) {
19457
+ const resultLines = resultText.split("\n");
19458
+ if (verbose) {
19459
+ for (let i = 0; i < resultLines.length; i++) {
19460
+ const prefix = i === 0 ? "\u2514 " : " ";
19461
+ lines.push(`${prefix}${chalk3.dim(resultLines[i])}`);
19462
+ }
19463
+ } else if (resultLines.length > 0) {
19464
+ const previewCount = Math.min(3, resultLines.length);
19465
+ for (let i = 0; i < previewCount; i++) {
19466
+ const prefix = i === 0 ? "\u2514 " : " ";
19467
+ lines.push(`${prefix}${chalk3.dim(resultLines[i])}`);
19468
+ }
19469
+ const remaining = resultLines.length - previewCount;
19470
+ if (remaining > 0) {
19471
+ lines.push(
19472
+ ` ${chalk3.dim(`\u2026 +${remaining} ${pluralize(remaining, "line", "lines")} (vm0 logs <runId> to see all)`)}`
19473
+ );
19474
+ }
19475
+ }
19476
+ } else {
19477
+ lines.push(`\u2514 \u2713 ${chalk3.dim("Done")}`);
19478
+ }
19479
+ return lines;
19480
+ }
19481
+ function formatReadContent(resultText, verbose) {
19482
+ const lines = [];
19483
+ const rawLines = resultText.split("\n");
19484
+ const contentLines = [];
19485
+ const lineNumberPattern = /^\s*\d+→(.*)$/;
19486
+ for (const line of rawLines) {
19487
+ const match = line.match(lineNumberPattern);
19488
+ if (match) {
19489
+ contentLines.push(match[1] ?? "");
19490
+ }
19491
+ }
19492
+ const displayLines = contentLines.length > 0 ? contentLines : rawLines.filter((line) => line.trim().length > 0);
19493
+ const totalLines = displayLines.length;
19494
+ if (totalLines === 0) {
19495
+ lines.push(`\u2514 \u2713 ${chalk3.dim("(empty)")}`);
19496
+ return lines;
19497
+ }
19498
+ if (verbose) {
19499
+ for (let i = 0; i < displayLines.length; i++) {
19500
+ const prefix = i === 0 ? "\u2514 " : " ";
19501
+ lines.push(`${prefix}${chalk3.dim(displayLines[i] ?? "")}`);
19502
+ }
19503
+ } else {
19504
+ const previewCount = Math.min(3, totalLines);
19505
+ for (let i = 0; i < previewCount; i++) {
19506
+ const prefix = i === 0 ? "\u2514 " : " ";
19507
+ lines.push(`${prefix}${chalk3.dim(displayLines[i] ?? "")}`);
19508
+ }
19509
+ const remaining = totalLines - previewCount;
19510
+ if (remaining > 0) {
19511
+ lines.push(
19512
+ ` ${chalk3.dim(`\u2026 +${remaining} ${pluralize(remaining, "line", "lines")} (vm0 logs <runId> to see all)`)}`
19513
+ );
19514
+ }
19515
+ }
19516
+ return lines;
19517
+ }
19518
+ function formatWritePreview(input, verbose) {
19519
+ const lines = [];
19520
+ const content = String(input.content || "");
19521
+ const contentLines = content.split("\n");
19522
+ const totalLines = contentLines.length;
19523
+ if (verbose) {
19524
+ for (let i = 0; i < contentLines.length; i++) {
19525
+ const prefix = i === 0 ? "\u23BF " : " ";
19526
+ lines.push(`${prefix}${chalk3.dim(contentLines[i] ?? "")}`);
19527
+ }
19528
+ } else {
19529
+ const previewCount = Math.min(3, totalLines);
19530
+ for (let i = 0; i < previewCount; i++) {
19531
+ const prefix = i === 0 ? "\u23BF " : " ";
19532
+ lines.push(`${prefix}${chalk3.dim(contentLines[i] ?? "")}`);
19533
+ }
19534
+ const remaining = totalLines - previewCount;
19535
+ if (remaining > 0) {
19536
+ lines.push(
19537
+ ` ${chalk3.dim(`\u2026 +${remaining} ${pluralize(remaining, "line", "lines")} (vm0 logs <runId> to see all)`)}`
19538
+ );
19539
+ }
19540
+ }
19541
+ return lines;
19542
+ }
19543
+ function formatEditDiff(input, verbose) {
19544
+ const lines = [];
19545
+ const oldString = String(input.old_string || "");
19546
+ const newString = String(input.new_string || "");
19547
+ const oldLines = oldString.split("\n");
19548
+ const newLines = newString.split("\n");
19549
+ const removed = oldLines.length;
19550
+ const added = newLines.length;
19551
+ const summary = `Added ${added} ${pluralize(added, "line", "lines")}, removed ${removed} ${pluralize(removed, "line", "lines")}`;
19552
+ lines.push(`\u23BF ${chalk3.dim(summary)}`);
19553
+ if (verbose) {
19554
+ for (const line of oldLines) {
19555
+ lines.push(` - ${chalk3.dim(line)}`);
19556
+ }
19557
+ for (const line of newLines) {
19558
+ lines.push(` + ${chalk3.dim(line)}`);
19559
+ }
19560
+ } else {
19561
+ const previewLimit = 3;
19562
+ const showOld = Math.min(previewLimit, oldLines.length);
19563
+ const showNew = Math.min(previewLimit, newLines.length);
19564
+ for (let i = 0; i < showOld; i++) {
19565
+ lines.push(` - ${chalk3.dim(truncate(oldLines[i] ?? "", 60))}`);
19566
+ }
19567
+ const remainingOld = oldLines.length - previewLimit;
19568
+ if (remainingOld > 0) {
19569
+ lines.push(
19570
+ ` ${chalk3.dim(`\u2026 +${remainingOld} ${pluralize(remainingOld, "line", "lines")} (vm0 logs <runId> to see all)`)}`
19571
+ );
19572
+ }
19573
+ for (let i = 0; i < showNew; i++) {
19574
+ lines.push(` + ${chalk3.dim(truncate(newLines[i] ?? "", 60))}`);
19575
+ }
19576
+ const remainingNew = newLines.length - previewLimit;
19577
+ if (remainingNew > 0) {
19578
+ lines.push(
19579
+ ` ${chalk3.dim(`\u2026 +${remainingNew} ${pluralize(remainingNew, "line", "lines")} (vm0 logs <runId> to see all)`)}`
19580
+ );
19581
+ }
19582
+ }
19583
+ return lines;
19584
+ }
19585
+ function formatTodoList(input) {
19586
+ const lines = [];
19587
+ const todos = input.todos;
19588
+ if (!todos || !Array.isArray(todos)) {
19589
+ lines.push("\u2514 \u2713 Done");
19590
+ return lines;
19591
+ }
19592
+ for (let i = 0; i < todos.length; i++) {
19593
+ const todo = todos[i];
19594
+ const content = todo.content || "Unknown task";
19595
+ const status = todo.status || "pending";
19596
+ const icon = getTodoStatusIcon(status);
19597
+ const styledContent = formatTodoContent(content, status);
19598
+ const prefix = i === 0 ? "\u2514 " : " ";
19599
+ lines.push(`${prefix}${icon} ${styledContent}`);
19600
+ }
19601
+ return lines;
19602
+ }
19603
+ function getTodoStatusIcon(status) {
19604
+ switch (status) {
19605
+ case "completed":
19606
+ return "\u2713";
19607
+ case "in_progress":
19608
+ return "\u25B8";
19609
+ case "pending":
19610
+ default:
19611
+ return "\u25FB";
19612
+ }
19613
+ }
19614
+ function formatTodoContent(content, status) {
19615
+ switch (status) {
19616
+ case "completed":
19617
+ return chalk3.dim.strikethrough(content);
19618
+ case "in_progress":
19619
+ return content;
19620
+ case "pending":
19621
+ default:
19622
+ return chalk3.dim(content);
19623
+ }
19624
+ }
19625
+
19626
+ // src/lib/events/event-renderer.ts
19627
+ var EventRenderer = class _EventRenderer {
19628
+ pendingToolUse = /* @__PURE__ */ new Map();
19629
+ options;
19630
+ lastEventType = null;
19631
+ frameworkDisplayName = "Agent";
19632
+ constructor(options) {
19633
+ this.options = options ?? {};
19634
+ }
19635
+ /**
19636
+ * Render run started info
19637
+ * Called immediately after run is created, before polling events
19638
+ */
19639
+ static renderRunStarted(info) {
19640
+ console.log(chalk4.bold("\u25B6 Run started"));
19641
+ console.log(` Run ID: ${chalk4.dim(info.runId)}`);
19642
+ if (info.sandboxId) {
19643
+ console.log(` Sandbox: ${chalk4.dim(info.sandboxId)}`);
19644
+ }
19645
+ console.log(chalk4.dim(` (use "vm0 logs ${info.runId}" to view logs)`));
19646
+ console.log();
19647
+ }
19648
+ /**
19649
+ * Format timestamp for display (without milliseconds, matching metrics format)
19650
+ */
19651
+ static formatTimestamp(timestamp) {
19652
+ return timestamp.toISOString().replace(/\.\d{3}Z$/, "Z");
19653
+ }
19654
+ /**
19655
+ * Render a parsed event to console
19656
+ */
19657
+ render(event) {
19658
+ const timestampPrefix = this.options.showTimestamp ? `[${_EventRenderer.formatTimestamp(event.timestamp)}] ` : "";
19659
+ switch (event.type) {
19660
+ case "init":
19661
+ this.renderInit(event, timestampPrefix);
19662
+ break;
19663
+ case "text":
19664
+ this.renderText(event, timestampPrefix);
19665
+ break;
19666
+ case "tool_use":
19667
+ this.handleToolUse(event, timestampPrefix);
19668
+ break;
19669
+ case "tool_result":
19670
+ this.handleToolResult(event, timestampPrefix);
19671
+ break;
19672
+ case "result":
19673
+ this.renderResult(event, timestampPrefix);
19674
+ break;
19675
+ }
19676
+ }
19677
+ /**
19678
+ * Render run completed state
19679
+ * Note: This is run lifecycle status, not an event
19680
+ */
19681
+ static renderRunCompleted(result) {
19682
+ console.log("");
19683
+ console.log(chalk4.green("\u2713 Run completed successfully"));
19684
+ if (result) {
19685
+ console.log(` Checkpoint: ${chalk4.dim(result.checkpointId)}`);
19686
+ console.log(` Session: ${chalk4.dim(result.agentSessionId)}`);
19687
+ console.log(` Conversation: ${chalk4.dim(result.conversationId)}`);
19688
+ if (result.artifact && Object.keys(result.artifact).length > 0) {
19689
+ console.log(` Artifact:`);
19690
+ for (const [name, version] of Object.entries(result.artifact)) {
19691
+ console.log(
19692
+ ` ${name}: ${chalk4.dim(_EventRenderer.formatVersion(version))}`
19693
+ );
19694
+ }
19695
+ }
19696
+ if (result.volumes && Object.keys(result.volumes).length > 0) {
19697
+ console.log(` Volumes:`);
19698
+ for (const [name, version] of Object.entries(result.volumes)) {
19699
+ console.log(
19700
+ ` ${name}: ${chalk4.dim(_EventRenderer.formatVersion(version))}`
19701
+ );
19702
+ }
19703
+ }
19704
+ }
19705
+ }
19706
+ /**
19707
+ * Render run failed state
19708
+ * Note: This is run lifecycle status, not an event
19709
+ */
19710
+ static renderRunFailed(error, runId) {
19711
+ console.error("");
19712
+ console.error(chalk4.red("\u2717 Run failed"));
19713
+ console.error(` Error: ${chalk4.red(error || "Unknown error")}`);
19714
+ console.error(
19715
+ chalk4.dim(` (use "vm0 logs ${runId} --system" to view system logs)`)
19716
+ );
19717
+ }
19718
+ /**
19719
+ * Handle tool_use event - buffer it for later grouping with result (when buffered)
19720
+ * or render immediately (when not buffered, e.g., historical log viewing)
19721
+ */
19722
+ handleToolUse(event, prefix) {
19723
+ const toolUseId = String(event.data.toolUseId || "");
19724
+ const tool = String(event.data.tool || "");
19725
+ const input = event.data.input || {};
19726
+ const toolUseData = { tool, input };
19727
+ if (this.options.buffered !== false) {
19728
+ this.pendingToolUse.set(toolUseId, { toolUse: toolUseData, prefix });
19729
+ } else {
19730
+ this.renderToolUseOnly(toolUseData, prefix);
19731
+ }
19732
+ }
19733
+ /**
19734
+ * Render a tool_use event without waiting for result (for historical log viewing)
19735
+ */
19736
+ renderToolUseOnly(toolUse, prefix) {
19737
+ if (this.lastEventType === "text") {
19738
+ console.log();
19739
+ }
19740
+ const cont = this.getContinuationPrefix();
19741
+ const headerLines = formatToolHeader(toolUse);
19742
+ for (let i = 0; i < headerLines.length; i++) {
19743
+ if (i === 0) {
19744
+ console.log(prefix + "\u25CF " + headerLines[i]);
19745
+ } else {
19746
+ console.log(cont + headerLines[i]);
19747
+ }
19748
+ }
19749
+ console.log();
19750
+ this.lastEventType = "tool";
19751
+ }
19752
+ /**
19753
+ * Handle tool_result event - lookup buffered tool_use and render grouped
19754
+ */
19755
+ handleToolResult(event, prefix) {
19756
+ const toolUseId = String(event.data.toolUseId || "");
19757
+ const result = String(event.data.result || "");
19758
+ const isError = Boolean(event.data.isError);
19759
+ const pending = this.pendingToolUse.get(toolUseId);
19760
+ if (pending) {
19761
+ this.renderGroupedTool(pending.toolUse, { result, isError }, prefix);
19762
+ this.pendingToolUse.delete(toolUseId);
19763
+ }
19764
+ }
19765
+ /**
19766
+ * Get continuation prefix (simple indent, no timestamp alignment)
19767
+ */
19768
+ getContinuationPrefix() {
19769
+ return " ";
19770
+ }
19771
+ /**
19772
+ * Render grouped tool output (tool_use + tool_result together)
19773
+ */
19774
+ renderGroupedTool(toolUse, result, prefix) {
19775
+ if (this.lastEventType === "text") {
19776
+ console.log();
19777
+ }
19778
+ const verbose = this.options.verbose ?? false;
19779
+ const cont = this.getContinuationPrefix();
19780
+ const headerLines = formatToolHeader(toolUse);
19781
+ const resultLines = formatToolResult(toolUse, result, verbose);
19782
+ for (let i = 0; i < headerLines.length; i++) {
19783
+ if (i === 0) {
19784
+ console.log(prefix + "\u25CF " + headerLines[i]);
19785
+ } else {
19786
+ console.log(cont + headerLines[i]);
19787
+ }
19788
+ }
19789
+ for (const line of resultLines) {
19790
+ console.log(cont + line);
19791
+ }
19792
+ console.log();
19793
+ this.lastEventType = "tool";
19794
+ }
19795
+ renderInit(event, prefix) {
19796
+ const frameworkStr = String(event.data.framework || "claude-code");
19797
+ const displayName = isSupportedFramework(frameworkStr) ? getFrameworkDisplayName(frameworkStr) : frameworkStr;
19798
+ this.frameworkDisplayName = displayName;
19799
+ console.log(prefix + chalk4.bold(`\u25B7 ${displayName} Started`));
19800
+ console.log(` Session: ${chalk4.dim(String(event.data.sessionId || ""))}`);
19801
+ if (event.data.model) {
19802
+ console.log(` Model: ${chalk4.dim(String(event.data.model))}`);
19803
+ }
19804
+ console.log(
19805
+ ` Tools: ${chalk4.dim(
19806
+ Array.isArray(event.data.tools) ? event.data.tools.join(", ") : String(event.data.tools || "")
19807
+ )}`
19808
+ );
19809
+ console.log();
19810
+ this.lastEventType = "init";
19811
+ }
19812
+ renderText(event, prefix) {
19813
+ const text = String(event.data.text || "");
19814
+ console.log(prefix + "\u25CF " + text);
19815
+ this.lastEventType = "text";
19816
+ }
19817
+ renderResult(event, prefix) {
19818
+ console.log();
19819
+ const success = Boolean(event.data.success);
19820
+ if (success) {
19821
+ console.log(
19822
+ prefix + chalk4.bold(`\u25C6 ${this.frameworkDisplayName} Completed`)
19823
+ );
19824
+ } else {
19825
+ console.log(prefix + chalk4.bold(`\u25C6 ${this.frameworkDisplayName} Failed`));
19826
+ }
19827
+ const durationMs = Number(event.data.durationMs || 0);
19828
+ const durationSec = (durationMs / 1e3).toFixed(1);
19829
+ console.log(` Duration: ${chalk4.dim(durationSec + "s")}`);
19830
+ const numTurns = Number(event.data.numTurns || 0);
19831
+ console.log(` Turns: ${chalk4.dim(String(numTurns))}`);
19832
+ const usage = event.data.usage;
19833
+ if (usage && typeof usage === "object") {
19834
+ const inputTokens = Number(usage.input_tokens || 0);
19835
+ const outputTokens = Number(usage.output_tokens || 0);
19836
+ const formatTokens = (count) => {
19837
+ if (count >= 1e3) {
19838
+ return Math.floor(count / 1e3) + "k";
19839
+ }
19840
+ return String(count);
19841
+ };
19842
+ console.log(
19843
+ ` Tokens: ${chalk4.dim(
19844
+ `input=${formatTokens(inputTokens)} output=${formatTokens(outputTokens)}`
19845
+ )}`
19846
+ );
19847
+ }
19848
+ this.lastEventType = "result";
19849
+ }
19850
+ /**
19851
+ * Format version ID for display (show short 8-character prefix)
19852
+ */
19853
+ static formatVersion(version) {
19854
+ if (version.length === 64 && /^[a-f0-9]+$/i.test(version)) {
19855
+ return version.slice(0, 8);
19856
+ }
19857
+ return version;
19858
+ }
19859
+ };
19860
+
19861
+ // src/commands/run/shared.ts
19862
+ import chalk5 from "chalk";
19863
+ import * as fs from "fs";
19864
+ import { config as dotenvConfig } from "dotenv";
19865
+
19866
+ // src/lib/events/event-parser-factory.ts
19867
+ function parseEvent(rawEvent) {
19868
+ return ClaudeEventParser.parse(rawEvent);
19869
+ }
19870
+
19871
+ // src/commands/run/shared.ts
19872
+ function collectKeyValue(value, previous) {
19873
+ const [key, ...valueParts] = value.split("=");
19874
+ const val = valueParts.join("=");
19875
+ if (!key || val === void 0 || val === "") {
19876
+ throw new Error(`Invalid format: ${value} (expected KEY=value)`);
19877
+ }
19878
+ return { ...previous, [key]: val };
19879
+ }
19880
+ function collectVolumeVersions(value, previous) {
19881
+ const [volumeName, ...versionParts] = value.split("=");
19882
+ const version = versionParts.join("=");
19883
+ if (!volumeName || version === void 0 || version === "") {
19884
+ throw new Error(
19885
+ `Invalid volume-version format: ${value} (expected volumeName=version)`
19886
+ );
19887
+ }
19888
+ return { ...previous, [volumeName]: version };
19889
+ }
19890
+ function isUUID(str) {
19891
+ return /^[0-9a-f-]{36}$/i.test(str);
19892
+ }
19893
+ function extractVarNames(composeContent) {
19894
+ const grouped = extractAndGroupVariables(composeContent);
19895
+ return grouped.vars.map((r) => r.name);
19896
+ }
19897
+ function extractSecretNames(composeContent) {
19898
+ const grouped = extractAndGroupVariables(composeContent);
19899
+ return grouped.secrets.map((r) => r.name);
19900
+ }
19901
+ function loadValues(cliValues, configNames, envFilePath) {
19902
+ const result = { ...cliValues };
19903
+ const missingNames = configNames.filter((name) => !(name in result));
19904
+ if (missingNames.length > 0) {
19905
+ const envValues = {};
19906
+ for (const name of missingNames) {
19907
+ const envValue = process.env[name];
19908
+ if (envValue !== void 0) {
19909
+ envValues[name] = envValue;
19910
+ }
19911
+ }
19912
+ let fileValues = {};
19913
+ if (envFilePath) {
19914
+ if (!fs.existsSync(envFilePath)) {
19915
+ throw new Error(`Environment file not found: ${envFilePath}`);
19916
+ }
19917
+ const dotenvResult = dotenvConfig({ path: envFilePath, quiet: true });
19918
+ if (dotenvResult.parsed) {
19919
+ fileValues = Object.fromEntries(
19920
+ Object.entries(dotenvResult.parsed).filter(
19921
+ ([key]) => missingNames.includes(key)
19922
+ )
19923
+ );
19924
+ }
19925
+ }
19926
+ Object.assign(result, envValues, fileValues);
19927
+ }
19928
+ return Object.keys(result).length > 0 ? result : void 0;
19929
+ }
19930
+ function parseIdentifier(identifier) {
19931
+ if (isUUID(identifier)) {
19932
+ return { name: identifier };
19933
+ }
19934
+ let org;
19935
+ let rest = identifier;
19936
+ const slashIndex = identifier.indexOf("/");
19937
+ if (slashIndex > 0) {
19938
+ org = identifier.slice(0, slashIndex);
19939
+ rest = identifier.slice(slashIndex + 1);
19940
+ }
19941
+ const colonIndex = rest.indexOf(":");
19942
+ if (colonIndex > 0 && colonIndex < rest.length - 1) {
19943
+ return {
19944
+ org,
19945
+ name: rest.slice(0, colonIndex),
19946
+ version: rest.slice(colonIndex + 1)
19947
+ };
19948
+ }
19949
+ return { org, name: rest };
19950
+ }
19951
+ function renderRunCreated(response) {
19952
+ if (response.status === "queued") {
19953
+ console.log(chalk5.yellow("\u26A0 Run queued \u2014 concurrency limit reached"));
19954
+ console.log(` Run ID: ${chalk5.dim(response.runId)}`);
19955
+ console.log(
19956
+ chalk5.dim(" Will start automatically when a slot is available")
19957
+ );
19958
+ console.log();
19959
+ } else {
19960
+ EventRenderer.renderRunStarted({
19961
+ runId: response.runId,
19962
+ sandboxId: response.sandboxId
19963
+ });
19964
+ }
19965
+ }
19966
+ async function pollEvents(runId, options) {
19967
+ const renderer = new EventRenderer({ verbose: options?.verbose });
19968
+ let nextSequence = -1;
19969
+ let complete = false;
19970
+ let result = { succeeded: true, runId };
19971
+ const pollIntervalMs = 1e3;
19972
+ while (!complete) {
19973
+ const response = await getEvents(runId, {
19974
+ since: nextSequence
19975
+ });
19976
+ for (const event of response.events) {
19977
+ const eventData = event.eventData;
19978
+ const parsed = parseEvent(eventData);
19979
+ if (parsed) {
19980
+ renderer.render(parsed);
19981
+ }
19982
+ }
19983
+ nextSequence = response.nextSequence;
19984
+ const runStatus = response.run.status;
19985
+ if (runStatus === "completed") {
19986
+ complete = true;
19987
+ EventRenderer.renderRunCompleted(response.run.result);
19988
+ result = {
19989
+ succeeded: true,
19990
+ runId,
19991
+ sessionId: response.run.result?.agentSessionId,
19992
+ checkpointId: response.run.result?.checkpointId
19993
+ };
19994
+ } else if (runStatus === "failed") {
19995
+ complete = true;
19996
+ EventRenderer.renderRunFailed(response.run.error, runId);
19997
+ result = { succeeded: false, runId };
19998
+ } else if (runStatus === "timeout") {
19999
+ complete = true;
20000
+ console.error(chalk5.red("\n\u2717 Run timed out"));
20001
+ console.error(
20002
+ chalk5.dim(` (use "vm0 logs ${runId} --system" to view system logs)`)
20003
+ );
20004
+ result = { succeeded: false, runId };
20005
+ } else if (runStatus === "cancelled") {
20006
+ complete = true;
20007
+ console.error(chalk5.yellow("\n\u2717 Run cancelled"));
20008
+ result = { succeeded: false, runId };
20009
+ }
20010
+ if (!complete) {
20011
+ await new Promise((resolve) => setTimeout(resolve, pollIntervalMs));
20012
+ }
20013
+ }
20014
+ return result;
20015
+ }
20016
+ function showNextSteps(result) {
20017
+ const { runId, sessionId, checkpointId } = result;
20018
+ console.log();
20019
+ console.log(" View agent logs:");
20020
+ console.log(chalk5.cyan(` vm0 logs ${runId}`));
20021
+ if (sessionId) {
20022
+ console.log(" Continue with session (latest conversation and artifact):");
20023
+ console.log(
20024
+ chalk5.cyan(` vm0 run continue ${sessionId} "your next prompt"`)
20025
+ );
20026
+ }
20027
+ if (checkpointId) {
20028
+ console.log(
20029
+ " Resume from checkpoint (snapshotted conversation and artifact):"
20030
+ );
20031
+ console.log(
20032
+ chalk5.cyan(` vm0 run resume ${checkpointId} "your next prompt"`)
20033
+ );
20034
+ }
20035
+ }
20036
+
19258
20037
  export {
19259
20038
  configureGlobalProxyFromEnv,
19260
20039
  decodeZeroTokenPayload,
@@ -19291,8 +20070,6 @@ export {
19291
20070
  expandFirewallConfigs,
19292
20071
  getInstructionsStorageName,
19293
20072
  getSkillStorageName,
19294
- isSupportedFramework,
19295
- getFrameworkDisplayName,
19296
20073
  getInstructionsFilename,
19297
20074
  isFeatureEnabled,
19298
20075
  parseSkillFrontmatter,
@@ -19305,7 +20082,6 @@ export {
19305
20082
  getComposeVersion,
19306
20083
  createOrUpdateCompose,
19307
20084
  createRun,
19308
- getEvents,
19309
20085
  listRuns,
19310
20086
  getRunQueue,
19311
20087
  cancelRun,
@@ -19365,6 +20141,9 @@ export {
19365
20141
  enableZeroSchedule,
19366
20142
  disableZeroSchedule,
19367
20143
  resolveZeroScheduleByAgent,
20144
+ createZeroRun,
20145
+ getZeroRun,
20146
+ getZeroRunAgentEvents,
19368
20147
  getSystemLog,
19369
20148
  getMetrics,
19370
20149
  getAgentEvents,
@@ -19376,6 +20155,19 @@ export {
19376
20155
  promptText,
19377
20156
  promptConfirm,
19378
20157
  promptSelect,
19379
- promptPassword
20158
+ promptPassword,
20159
+ ClaudeEventParser,
20160
+ parseEvent,
20161
+ EventRenderer,
20162
+ collectKeyValue,
20163
+ collectVolumeVersions,
20164
+ isUUID,
20165
+ extractVarNames,
20166
+ extractSecretNames,
20167
+ loadValues,
20168
+ parseIdentifier,
20169
+ renderRunCreated,
20170
+ pollEvents,
20171
+ showNextSteps
19380
20172
  };
19381
- //# sourceMappingURL=chunk-HODD5NE4.js.map
20173
+ //# sourceMappingURL=chunk-MAYVCUG7.js.map