@vm0/cli 4.5.2 → 4.6.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.
Files changed (2) hide show
  1. package/index.js +148 -9
  2. package/package.json +1 -1
package/index.js CHANGED
@@ -391,6 +391,28 @@ var ApiClient = class {
391
391
  }
392
392
  return await response.json();
393
393
  }
394
+ async getNetworkLogs(runId, options) {
395
+ const baseUrl = await this.getBaseUrl();
396
+ const headers = await this.getHeaders();
397
+ const params = new URLSearchParams();
398
+ if (options?.since !== void 0) {
399
+ params.set("since", String(options.since));
400
+ }
401
+ if (options?.limit !== void 0) {
402
+ params.set("limit", String(options.limit));
403
+ }
404
+ const queryString = params.toString();
405
+ const url2 = `${baseUrl}/api/agent/runs/${runId}/telemetry/network${queryString ? `?${queryString}` : ""}`;
406
+ const response = await fetch(url2, {
407
+ method: "GET",
408
+ headers
409
+ });
410
+ if (!response.ok) {
411
+ const error43 = await response.json();
412
+ throw new Error(error43.error?.message || "Failed to fetch network logs");
413
+ }
414
+ return await response.json();
415
+ }
394
416
  async createImage(body) {
395
417
  const baseUrl = await this.getBaseUrl();
396
418
  const headers = await this.getHeaders();
@@ -14217,7 +14239,14 @@ var agentDefinitionSchema = external_exports.object({
14217
14239
  provider: external_exports.string().min(1, "Provider is required"),
14218
14240
  volumes: external_exports.array(external_exports.string()).optional(),
14219
14241
  working_dir: external_exports.string().min(1, "Working directory is required"),
14220
- environment: external_exports.record(external_exports.string(), external_exports.string()).optional()
14242
+ environment: external_exports.record(external_exports.string(), external_exports.string()).optional(),
14243
+ /**
14244
+ * Enable network security mode for secrets.
14245
+ * When true, secrets are encrypted into proxy tokens and all traffic
14246
+ * is routed through mitmproxy -> VM0 Proxy for decryption.
14247
+ * Default: false (plaintext secrets in env vars)
14248
+ */
14249
+ beta_network_security: external_exports.boolean().optional().default(false)
14221
14250
  });
14222
14251
  var agentComposeContentSchema = external_exports.object({
14223
14252
  version: external_exports.string().min(1, "Version is required"),
@@ -14477,6 +14506,19 @@ var agentEventsResponseSchema = external_exports.object({
14477
14506
  events: external_exports.array(runEventSchema),
14478
14507
  hasMore: external_exports.boolean()
14479
14508
  });
14509
+ var networkLogEntrySchema = external_exports.object({
14510
+ timestamp: external_exports.string(),
14511
+ method: external_exports.string(),
14512
+ url: external_exports.string(),
14513
+ status: external_exports.number(),
14514
+ latency_ms: external_exports.number(),
14515
+ request_size: external_exports.number(),
14516
+ response_size: external_exports.number()
14517
+ });
14518
+ var networkLogsResponseSchema = external_exports.object({
14519
+ networkLogs: external_exports.array(networkLogEntrySchema),
14520
+ hasMore: external_exports.boolean()
14521
+ });
14480
14522
  var telemetryResponseSchema = external_exports.object({
14481
14523
  systemLog: external_exports.string(),
14482
14524
  metrics: external_exports.array(telemetryMetricSchema)
@@ -14569,6 +14611,29 @@ var runAgentEventsContract = c3.router({
14569
14611
  summary: "Get agent events with pagination"
14570
14612
  }
14571
14613
  });
14614
+ var runNetworkLogsContract = c3.router({
14615
+ /**
14616
+ * GET /api/agent/runs/:id/telemetry/network
14617
+ * Get network logs with pagination (for vm0 logs --network)
14618
+ */
14619
+ getNetworkLogs: {
14620
+ method: "GET",
14621
+ path: "/api/agent/runs/:id/telemetry/network",
14622
+ pathParams: external_exports.object({
14623
+ id: external_exports.string().min(1, "Run ID is required")
14624
+ }),
14625
+ query: external_exports.object({
14626
+ since: external_exports.coerce.number().optional(),
14627
+ limit: external_exports.coerce.number().min(1).max(100).default(5)
14628
+ }),
14629
+ responses: {
14630
+ 200: networkLogsResponseSchema,
14631
+ 401: apiErrorSchema,
14632
+ 404: apiErrorSchema
14633
+ },
14634
+ summary: "Get network logs with pagination"
14635
+ }
14636
+ });
14572
14637
 
14573
14638
  // ../../packages/core/src/contracts/sessions.ts
14574
14639
  var c4 = initContract();
@@ -14918,10 +14983,19 @@ var metricDataSchema = external_exports.object({
14918
14983
  disk_used: external_exports.number(),
14919
14984
  disk_total: external_exports.number()
14920
14985
  });
14986
+ var networkLogSchema = external_exports.object({
14987
+ timestamp: external_exports.string(),
14988
+ method: external_exports.string(),
14989
+ url: external_exports.string(),
14990
+ status: external_exports.number(),
14991
+ latency_ms: external_exports.number(),
14992
+ request_size: external_exports.number(),
14993
+ response_size: external_exports.number()
14994
+ });
14921
14995
  var webhookTelemetryContract = c6.router({
14922
14996
  /**
14923
14997
  * POST /api/webhooks/agent/telemetry
14924
- * Receive telemetry data (system log and metrics) from sandbox
14998
+ * Receive telemetry data (system log, metrics, and network logs) from sandbox
14925
14999
  */
14926
15000
  send: {
14927
15001
  method: "POST",
@@ -14929,7 +15003,8 @@ var webhookTelemetryContract = c6.router({
14929
15003
  body: external_exports.object({
14930
15004
  runId: external_exports.string().min(1, "runId is required"),
14931
15005
  systemLog: external_exports.string().optional(),
14932
- metrics: external_exports.array(metricDataSchema).optional()
15006
+ metrics: external_exports.array(metricDataSchema).optional(),
15007
+ networkLogs: external_exports.array(networkLogSchema).optional()
14933
15008
  }),
14934
15009
  responses: {
14935
15010
  200: external_exports.object({
@@ -15172,6 +15247,20 @@ var cronCleanupSandboxesContract = c10.router({
15172
15247
  }
15173
15248
  });
15174
15249
 
15250
+ // ../../packages/core/src/contracts/proxy.ts
15251
+ var proxyErrorSchema = external_exports.object({
15252
+ error: external_exports.object({
15253
+ message: external_exports.string(),
15254
+ code: external_exports.enum([
15255
+ "UNAUTHORIZED",
15256
+ "BAD_REQUEST",
15257
+ "BAD_GATEWAY",
15258
+ "INTERNAL_ERROR"
15259
+ ]),
15260
+ targetUrl: external_exports.string().optional()
15261
+ })
15262
+ });
15263
+
15175
15264
  // src/lib/secrets-client.ts
15176
15265
  async function getClientConfig() {
15177
15266
  const baseUrl = await getApiUrl();
@@ -15837,6 +15926,27 @@ function formatMetric(metric) {
15837
15926
  const diskPercent = (metric.disk_used / metric.disk_total * 100).toFixed(1);
15838
15927
  return `[${metric.ts}] CPU: ${metric.cpu.toFixed(1)}% | Mem: ${formatBytes5(metric.mem_used)}/${formatBytes5(metric.mem_total)} (${memPercent}%) | Disk: ${formatBytes5(metric.disk_used)}/${formatBytes5(metric.disk_total)} (${diskPercent}%)`;
15839
15928
  }
15929
+ function formatNetworkLog(entry) {
15930
+ let statusColor;
15931
+ if (entry.status >= 200 && entry.status < 300) {
15932
+ statusColor = chalk18.green;
15933
+ } else if (entry.status >= 300 && entry.status < 400) {
15934
+ statusColor = chalk18.yellow;
15935
+ } else if (entry.status >= 400) {
15936
+ statusColor = chalk18.red;
15937
+ } else {
15938
+ statusColor = chalk18.gray;
15939
+ }
15940
+ let latencyColor;
15941
+ if (entry.latency_ms < 500) {
15942
+ latencyColor = chalk18.green;
15943
+ } else if (entry.latency_ms < 2e3) {
15944
+ latencyColor = chalk18.yellow;
15945
+ } else {
15946
+ latencyColor = chalk18.red;
15947
+ }
15948
+ return `[${entry.timestamp}] ${chalk18.cyan(entry.method.padEnd(6))} ${statusColor(entry.status)} ${latencyColor(entry.latency_ms + "ms")} ${formatBytes5(entry.request_size)}/${formatBytes5(entry.response_size)} ${chalk18.gray(entry.url)}`;
15949
+ }
15840
15950
  function renderAgentEvent(event) {
15841
15951
  const parsed = ClaudeEventParser.parse(
15842
15952
  event.eventData
@@ -15847,22 +15957,26 @@ function renderAgentEvent(event) {
15847
15957
  }
15848
15958
  }
15849
15959
  function getLogType(options) {
15850
- const selected = [options.agent, options.system, options.metrics].filter(
15851
- Boolean
15852
- ).length;
15960
+ const selected = [
15961
+ options.agent,
15962
+ options.system,
15963
+ options.metrics,
15964
+ options.network
15965
+ ].filter(Boolean).length;
15853
15966
  if (selected > 1) {
15854
15967
  console.error(
15855
15968
  chalk18.red(
15856
- "Options --agent, --system, and --metrics are mutually exclusive"
15969
+ "Options --agent, --system, --metrics, and --network are mutually exclusive"
15857
15970
  )
15858
15971
  );
15859
15972
  process.exit(1);
15860
15973
  }
15861
15974
  if (options.system) return "system";
15862
15975
  if (options.metrics) return "metrics";
15976
+ if (options.network) return "network";
15863
15977
  return "agent";
15864
15978
  }
15865
- var logsCommand = new Command20().name("logs").description("View logs for an agent run").argument("<runId>", "Run ID to fetch logs for").option("-a, --agent", "Show agent events (default)").option("-s, --system", "Show system log").option("-m, --metrics", "Show metrics").option(
15979
+ var logsCommand = new Command20().name("logs").description("View logs for an agent run").argument("<runId>", "Run ID to fetch logs for").option("-a, --agent", "Show agent events (default)").option("-s, --system", "Show system log").option("-m, --metrics", "Show metrics").option("-n, --network", "Show network logs (proxy traffic)").option(
15866
15980
  "--since <time>",
15867
15981
  "Show logs since timestamp (e.g., 5m, 2h, 1d, 2024-01-15T10:30:00Z, 1705312200)"
15868
15982
  ).option(
@@ -15891,6 +16005,9 @@ var logsCommand = new Command20().name("logs").description("View logs for an age
15891
16005
  case "metrics":
15892
16006
  await showMetrics(runId, { since, limit });
15893
16007
  break;
16008
+ case "network":
16009
+ await showNetworkLogs(runId, { since, limit });
16010
+ break;
15894
16011
  }
15895
16012
  } catch (error43) {
15896
16013
  handleError(error43, runId);
@@ -15948,6 +16065,28 @@ async function showMetrics(runId, options) {
15948
16065
  );
15949
16066
  }
15950
16067
  }
16068
+ async function showNetworkLogs(runId, options) {
16069
+ const response = await apiClient.getNetworkLogs(runId, options);
16070
+ if (response.networkLogs.length === 0) {
16071
+ console.log(
16072
+ chalk18.yellow(
16073
+ "No network logs found for this run. Network logs are only captured when beta_network_security is enabled."
16074
+ )
16075
+ );
16076
+ return;
16077
+ }
16078
+ for (const entry of response.networkLogs) {
16079
+ console.log(formatNetworkLog(entry));
16080
+ }
16081
+ if (response.hasMore) {
16082
+ console.log();
16083
+ console.log(
16084
+ chalk18.gray(
16085
+ `Showing ${response.networkLogs.length} network logs. Use --limit to see more.`
16086
+ )
16087
+ );
16088
+ }
16089
+ }
15951
16090
  function handleError(error43, runId) {
15952
16091
  if (error43 instanceof Error) {
15953
16092
  if (error43.message.includes("Not authenticated")) {
@@ -15967,7 +16106,7 @@ function handleError(error43, runId) {
15967
16106
 
15968
16107
  // src/index.ts
15969
16108
  var program = new Command21();
15970
- program.name("vm0").description("VM0 CLI - A modern build tool").version("4.5.2");
16109
+ program.name("vm0").description("VM0 CLI - A modern build tool").version("4.6.0");
15971
16110
  program.command("info").description("Display environment information").action(async () => {
15972
16111
  console.log(chalk19.cyan("System Information:"));
15973
16112
  console.log(`Node Version: ${process.version}`);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@vm0/cli",
3
- "version": "4.5.2",
3
+ "version": "4.6.0",
4
4
  "description": "CLI application",
5
5
  "repository": {
6
6
  "type": "git",