@vm0/cli 9.85.2 → 9.86.1

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