@vm0/cli 4.5.1 → 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.
- package/index.js +169 -29
- 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();
|
|
@@ -813,35 +835,34 @@ var EventRenderer = class {
|
|
|
813
835
|
return `${(elapsedMs / 1e3).toFixed(1)}s`;
|
|
814
836
|
}
|
|
815
837
|
/**
|
|
816
|
-
* Format timestamp for display
|
|
838
|
+
* Format timestamp for display (without milliseconds, matching metrics format)
|
|
817
839
|
*/
|
|
818
840
|
static formatTimestamp(timestamp) {
|
|
819
|
-
return timestamp.toISOString();
|
|
841
|
+
return timestamp.toISOString().replace(/\.\d{3}Z$/, "Z");
|
|
820
842
|
}
|
|
821
843
|
/**
|
|
822
844
|
* Render a parsed event to console
|
|
823
845
|
*/
|
|
824
846
|
static render(event, options) {
|
|
825
|
-
const timestampPrefix = options?.showTimestamp ?
|
|
826
|
-
const
|
|
847
|
+
const timestampPrefix = options?.showTimestamp ? `[${this.formatTimestamp(event.timestamp)}] ` : "";
|
|
848
|
+
const elapsedSuffix = options?.verbose && options?.previousTimestamp ? " " + chalk3.gray(
|
|
827
849
|
this.formatElapsed(options.previousTimestamp, event.timestamp)
|
|
828
850
|
) : "";
|
|
829
|
-
const prefix = timestampPrefix + elapsedPrefix;
|
|
830
851
|
switch (event.type) {
|
|
831
852
|
case "init":
|
|
832
|
-
this.renderInit(event,
|
|
853
|
+
this.renderInit(event, timestampPrefix, elapsedSuffix);
|
|
833
854
|
break;
|
|
834
855
|
case "text":
|
|
835
|
-
this.renderText(event,
|
|
856
|
+
this.renderText(event, timestampPrefix, elapsedSuffix);
|
|
836
857
|
break;
|
|
837
858
|
case "tool_use":
|
|
838
|
-
this.renderToolUse(event,
|
|
859
|
+
this.renderToolUse(event, timestampPrefix, elapsedSuffix);
|
|
839
860
|
break;
|
|
840
861
|
case "tool_result":
|
|
841
|
-
this.renderToolResult(event,
|
|
862
|
+
this.renderToolResult(event, timestampPrefix, elapsedSuffix);
|
|
842
863
|
break;
|
|
843
864
|
case "result":
|
|
844
|
-
this.renderResult(event,
|
|
865
|
+
this.renderResult(event, timestampPrefix, elapsedSuffix);
|
|
845
866
|
break;
|
|
846
867
|
}
|
|
847
868
|
}
|
|
@@ -888,8 +909,10 @@ var EventRenderer = class {
|
|
|
888
909
|
console.log(chalk3.red("\u2717 Run failed"));
|
|
889
910
|
console.log(` Error: ${chalk3.red(error43 || "Unknown error")}`);
|
|
890
911
|
}
|
|
891
|
-
static renderInit(event, prefix) {
|
|
892
|
-
console.log(
|
|
912
|
+
static renderInit(event, prefix, suffix) {
|
|
913
|
+
console.log(
|
|
914
|
+
prefix + chalk3.cyan("[init]") + suffix + " Starting Claude Code agent"
|
|
915
|
+
);
|
|
893
916
|
console.log(` Session: ${chalk3.gray(String(event.data.sessionId || ""))}`);
|
|
894
917
|
console.log(` Model: ${chalk3.gray(String(event.data.model || ""))}`);
|
|
895
918
|
console.log(
|
|
@@ -898,13 +921,13 @@ var EventRenderer = class {
|
|
|
898
921
|
)}`
|
|
899
922
|
);
|
|
900
923
|
}
|
|
901
|
-
static renderText(event, prefix) {
|
|
924
|
+
static renderText(event, prefix, suffix) {
|
|
902
925
|
const text = String(event.data.text || "");
|
|
903
|
-
console.log(chalk3.blue("[text]") +
|
|
926
|
+
console.log(prefix + chalk3.blue("[text]") + suffix + " " + text);
|
|
904
927
|
}
|
|
905
|
-
static renderToolUse(event, prefix) {
|
|
928
|
+
static renderToolUse(event, prefix, suffix) {
|
|
906
929
|
const tool = String(event.data.tool || "");
|
|
907
|
-
console.log(chalk3.yellow("[tool_use]") +
|
|
930
|
+
console.log(prefix + chalk3.yellow("[tool_use]") + suffix + " " + tool);
|
|
908
931
|
const input = event.data.input;
|
|
909
932
|
if (input && typeof input === "object") {
|
|
910
933
|
for (const [key, value] of Object.entries(input)) {
|
|
@@ -915,19 +938,19 @@ var EventRenderer = class {
|
|
|
915
938
|
}
|
|
916
939
|
}
|
|
917
940
|
}
|
|
918
|
-
static renderToolResult(event, prefix) {
|
|
941
|
+
static renderToolResult(event, prefix, suffix) {
|
|
919
942
|
const isError = Boolean(event.data.isError);
|
|
920
943
|
const status = isError ? "Error" : "Completed";
|
|
921
944
|
const color = isError ? chalk3.red : chalk3.green;
|
|
922
|
-
console.log(color("[tool_result]") +
|
|
945
|
+
console.log(prefix + color("[tool_result]") + suffix + " " + status);
|
|
923
946
|
const result = String(event.data.result || "");
|
|
924
947
|
console.log(` ${chalk3.gray(result)}`);
|
|
925
948
|
}
|
|
926
|
-
static renderResult(event, prefix) {
|
|
949
|
+
static renderResult(event, prefix, suffix) {
|
|
927
950
|
const success2 = Boolean(event.data.success);
|
|
928
951
|
const status = success2 ? "\u2713 completed successfully" : "\u2717 failed";
|
|
929
952
|
const color = success2 ? chalk3.green : chalk3.red;
|
|
930
|
-
console.log(color("[result]") +
|
|
953
|
+
console.log(prefix + color("[result]") + suffix + " " + status);
|
|
931
954
|
const durationMs = Number(event.data.durationMs || 0);
|
|
932
955
|
const durationSec = (durationMs / 1e3).toFixed(1);
|
|
933
956
|
console.log(` Duration: ${chalk3.gray(durationSec + "s")}`);
|
|
@@ -14216,7 +14239,14 @@ var agentDefinitionSchema = external_exports.object({
|
|
|
14216
14239
|
provider: external_exports.string().min(1, "Provider is required"),
|
|
14217
14240
|
volumes: external_exports.array(external_exports.string()).optional(),
|
|
14218
14241
|
working_dir: external_exports.string().min(1, "Working directory is required"),
|
|
14219
|
-
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)
|
|
14220
14250
|
});
|
|
14221
14251
|
var agentComposeContentSchema = external_exports.object({
|
|
14222
14252
|
version: external_exports.string().min(1, "Version is required"),
|
|
@@ -14476,6 +14506,19 @@ var agentEventsResponseSchema = external_exports.object({
|
|
|
14476
14506
|
events: external_exports.array(runEventSchema),
|
|
14477
14507
|
hasMore: external_exports.boolean()
|
|
14478
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
|
+
});
|
|
14479
14522
|
var telemetryResponseSchema = external_exports.object({
|
|
14480
14523
|
systemLog: external_exports.string(),
|
|
14481
14524
|
metrics: external_exports.array(telemetryMetricSchema)
|
|
@@ -14568,6 +14611,29 @@ var runAgentEventsContract = c3.router({
|
|
|
14568
14611
|
summary: "Get agent events with pagination"
|
|
14569
14612
|
}
|
|
14570
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
|
+
});
|
|
14571
14637
|
|
|
14572
14638
|
// ../../packages/core/src/contracts/sessions.ts
|
|
14573
14639
|
var c4 = initContract();
|
|
@@ -14917,10 +14983,19 @@ var metricDataSchema = external_exports.object({
|
|
|
14917
14983
|
disk_used: external_exports.number(),
|
|
14918
14984
|
disk_total: external_exports.number()
|
|
14919
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
|
+
});
|
|
14920
14995
|
var webhookTelemetryContract = c6.router({
|
|
14921
14996
|
/**
|
|
14922
14997
|
* POST /api/webhooks/agent/telemetry
|
|
14923
|
-
* Receive telemetry data (system log and
|
|
14998
|
+
* Receive telemetry data (system log, metrics, and network logs) from sandbox
|
|
14924
14999
|
*/
|
|
14925
15000
|
send: {
|
|
14926
15001
|
method: "POST",
|
|
@@ -14928,7 +15003,8 @@ var webhookTelemetryContract = c6.router({
|
|
|
14928
15003
|
body: external_exports.object({
|
|
14929
15004
|
runId: external_exports.string().min(1, "runId is required"),
|
|
14930
15005
|
systemLog: external_exports.string().optional(),
|
|
14931
|
-
metrics: external_exports.array(metricDataSchema).optional()
|
|
15006
|
+
metrics: external_exports.array(metricDataSchema).optional(),
|
|
15007
|
+
networkLogs: external_exports.array(networkLogSchema).optional()
|
|
14932
15008
|
}),
|
|
14933
15009
|
responses: {
|
|
14934
15010
|
200: external_exports.object({
|
|
@@ -15171,6 +15247,20 @@ var cronCleanupSandboxesContract = c10.router({
|
|
|
15171
15247
|
}
|
|
15172
15248
|
});
|
|
15173
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
|
+
|
|
15174
15264
|
// src/lib/secrets-client.ts
|
|
15175
15265
|
async function getClientConfig() {
|
|
15176
15266
|
const baseUrl = await getApiUrl();
|
|
@@ -15836,6 +15926,27 @@ function formatMetric(metric) {
|
|
|
15836
15926
|
const diskPercent = (metric.disk_used / metric.disk_total * 100).toFixed(1);
|
|
15837
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}%)`;
|
|
15838
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
|
+
}
|
|
15839
15950
|
function renderAgentEvent(event) {
|
|
15840
15951
|
const parsed = ClaudeEventParser.parse(
|
|
15841
15952
|
event.eventData
|
|
@@ -15846,22 +15957,26 @@ function renderAgentEvent(event) {
|
|
|
15846
15957
|
}
|
|
15847
15958
|
}
|
|
15848
15959
|
function getLogType(options) {
|
|
15849
|
-
const selected = [
|
|
15850
|
-
|
|
15851
|
-
|
|
15960
|
+
const selected = [
|
|
15961
|
+
options.agent,
|
|
15962
|
+
options.system,
|
|
15963
|
+
options.metrics,
|
|
15964
|
+
options.network
|
|
15965
|
+
].filter(Boolean).length;
|
|
15852
15966
|
if (selected > 1) {
|
|
15853
15967
|
console.error(
|
|
15854
15968
|
chalk18.red(
|
|
15855
|
-
"Options --agent, --system, and --
|
|
15969
|
+
"Options --agent, --system, --metrics, and --network are mutually exclusive"
|
|
15856
15970
|
)
|
|
15857
15971
|
);
|
|
15858
15972
|
process.exit(1);
|
|
15859
15973
|
}
|
|
15860
15974
|
if (options.system) return "system";
|
|
15861
15975
|
if (options.metrics) return "metrics";
|
|
15976
|
+
if (options.network) return "network";
|
|
15862
15977
|
return "agent";
|
|
15863
15978
|
}
|
|
15864
|
-
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(
|
|
15865
15980
|
"--since <time>",
|
|
15866
15981
|
"Show logs since timestamp (e.g., 5m, 2h, 1d, 2024-01-15T10:30:00Z, 1705312200)"
|
|
15867
15982
|
).option(
|
|
@@ -15890,6 +16005,9 @@ var logsCommand = new Command20().name("logs").description("View logs for an age
|
|
|
15890
16005
|
case "metrics":
|
|
15891
16006
|
await showMetrics(runId, { since, limit });
|
|
15892
16007
|
break;
|
|
16008
|
+
case "network":
|
|
16009
|
+
await showNetworkLogs(runId, { since, limit });
|
|
16010
|
+
break;
|
|
15893
16011
|
}
|
|
15894
16012
|
} catch (error43) {
|
|
15895
16013
|
handleError(error43, runId);
|
|
@@ -15947,6 +16065,28 @@ async function showMetrics(runId, options) {
|
|
|
15947
16065
|
);
|
|
15948
16066
|
}
|
|
15949
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
|
+
}
|
|
15950
16090
|
function handleError(error43, runId) {
|
|
15951
16091
|
if (error43 instanceof Error) {
|
|
15952
16092
|
if (error43.message.includes("Not authenticated")) {
|
|
@@ -15966,7 +16106,7 @@ function handleError(error43, runId) {
|
|
|
15966
16106
|
|
|
15967
16107
|
// src/index.ts
|
|
15968
16108
|
var program = new Command21();
|
|
15969
|
-
program.name("vm0").description("VM0 CLI - A modern build tool").version("4.
|
|
16109
|
+
program.name("vm0").description("VM0 CLI - A modern build tool").version("4.6.0");
|
|
15970
16110
|
program.command("info").description("Display environment information").action(async () => {
|
|
15971
16111
|
console.log(chalk19.cyan("System Information:"));
|
|
15972
16112
|
console.log(`Node Version: ${process.version}`);
|