@vm0/cli 9.95.1 → 9.96.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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@vm0/cli",
3
- "version": "9.95.1",
3
+ "version": "9.96.0",
4
4
  "description": "CLI application",
5
5
  "repository": {
6
6
  "type": "git",
package/zero.js CHANGED
@@ -2,6 +2,7 @@
2
2
  import {
3
3
  ApiRequestError,
4
4
  CONNECTOR_TYPES,
5
+ ClaudeEventParser,
5
6
  EventRenderer,
6
7
  MODEL_PROVIDER_TYPES,
7
8
  allowsCustomModel,
@@ -70,6 +71,7 @@ import {
70
71
  listSkills,
71
72
  listZeroAgents,
72
73
  listZeroConnectors,
74
+ listZeroLogs,
73
75
  listZeroOrgModelProviders,
74
76
  listZeroOrgSecrets,
75
77
  listZeroOrgVariables,
@@ -77,7 +79,9 @@ import {
77
79
  listZeroSchedules,
78
80
  listZeroSecrets,
79
81
  listZeroVariables,
82
+ paginate,
80
83
  parseEvent,
84
+ parseTime,
81
85
  postAskUserQuestion,
82
86
  promptConfirm,
83
87
  promptPassword,
@@ -88,6 +92,7 @@ import {
88
92
  resolveCompose,
89
93
  resolveZeroScheduleByAgent,
90
94
  saveConfig,
95
+ searchZeroLogs,
91
96
  sendSlackMessage,
92
97
  setZeroOrgModelProviderDefault,
93
98
  setZeroOrgSecret,
@@ -103,10 +108,10 @@ import {
103
108
  updateZeroUserPreferences,
104
109
  upsertZeroOrgModelProvider,
105
110
  withErrorHandler
106
- } from "./chunk-WN2AD3KW.js";
111
+ } from "./chunk-T53WM66Z.js";
107
112
 
108
113
  // src/zero.ts
109
- import { Command as Command70 } from "commander";
114
+ import { Command as Command73 } from "commander";
110
115
 
111
116
  // src/commands/zero/org/index.ts
112
117
  import { Command as Command23 } from "commander";
@@ -4112,6 +4117,323 @@ Skill Binding:
4112
4117
  Replace all skills: zero agent edit <id> --skills a,b,c`
4113
4118
  );
4114
4119
 
4120
+ // src/commands/zero/logs/index.ts
4121
+ import { Command as Command72 } from "commander";
4122
+ import chalk56 from "chalk";
4123
+
4124
+ // src/commands/zero/logs/list.ts
4125
+ import { Command as Command70 } from "commander";
4126
+ import chalk54 from "chalk";
4127
+ function formatStatus(status) {
4128
+ switch (status) {
4129
+ case "completed":
4130
+ return chalk54.green(status);
4131
+ case "failed":
4132
+ case "timeout":
4133
+ return chalk54.red(status);
4134
+ case "running":
4135
+ case "pending":
4136
+ case "queued":
4137
+ return chalk54.yellow(status);
4138
+ case "cancelled":
4139
+ return chalk54.dim(status);
4140
+ default:
4141
+ return status;
4142
+ }
4143
+ }
4144
+ function formatTime(iso) {
4145
+ return new Date(iso).toISOString().replace(/\.\d{3}Z$/, "Z");
4146
+ }
4147
+ var listCommand11 = new Command70().name("list").alias("ls").description("List agent run logs").option("--agent <name>", "Filter by agent name").option(
4148
+ "--status <status>",
4149
+ "Filter by status (queued|pending|running|completed|failed|timeout|cancelled)"
4150
+ ).option("--limit <n>", "Maximum number of results (default: 20)").addHelpText(
4151
+ "after",
4152
+ `
4153
+ Examples:
4154
+ zero logs list
4155
+ zero logs list --agent my-agent
4156
+ zero logs list --status completed --limit 10`
4157
+ ).action(
4158
+ withErrorHandler(
4159
+ async (options) => {
4160
+ const limit = options.limit ? parseInt(options.limit, 10) : void 0;
4161
+ const result = await listZeroLogs({
4162
+ agent: options.agent,
4163
+ status: options.status,
4164
+ limit
4165
+ });
4166
+ if (result.data.length === 0) {
4167
+ console.log(chalk54.dim("No logs found"));
4168
+ return;
4169
+ }
4170
+ const nameCol = Math.max(
4171
+ 5,
4172
+ ...result.data.map((r) => {
4173
+ return (r.displayName || r.agentId || "-").length;
4174
+ })
4175
+ );
4176
+ const statusCol = Math.max(
4177
+ 6,
4178
+ ...result.data.map((r) => {
4179
+ return r.status.length;
4180
+ })
4181
+ );
4182
+ const header = [
4183
+ "RUN ID".padEnd(10),
4184
+ "AGENT".padEnd(nameCol),
4185
+ "STATUS".padEnd(statusCol),
4186
+ "CREATED"
4187
+ ].join(" ");
4188
+ console.log(chalk54.dim(header));
4189
+ for (const entry of result.data) {
4190
+ const shortId = entry.id.slice(0, 8);
4191
+ const name = entry.displayName || entry.agentId || "-";
4192
+ const row = [
4193
+ shortId.padEnd(10),
4194
+ name.padEnd(nameCol),
4195
+ formatStatus(entry.status).padEnd(statusCol),
4196
+ formatTime(entry.createdAt)
4197
+ ].join(" ");
4198
+ console.log(row);
4199
+ }
4200
+ if (result.pagination.hasMore) {
4201
+ console.log();
4202
+ console.log(
4203
+ chalk54.dim(
4204
+ ` Showing ${result.data.length} of more results. Use --limit to adjust.`
4205
+ )
4206
+ );
4207
+ }
4208
+ }
4209
+ )
4210
+ );
4211
+
4212
+ // src/commands/zero/logs/search.ts
4213
+ import { Command as Command71 } from "commander";
4214
+ import chalk55 from "chalk";
4215
+ var SEVEN_DAYS_MS = 7 * 24 * 60 * 60 * 1e3;
4216
+ function renderEvent(event, renderer) {
4217
+ const eventData = event.eventData;
4218
+ const parsed = ClaudeEventParser.parse(eventData);
4219
+ if (parsed) {
4220
+ parsed.timestamp = new Date(event.createdAt);
4221
+ renderer.render(parsed);
4222
+ }
4223
+ }
4224
+ function formatRunHeader(runId, agentName, timestamp) {
4225
+ const shortId = runId.slice(0, 8);
4226
+ const time = new Date(timestamp).toISOString().replace(/\.\d{3}Z$/, "Z");
4227
+ return `\u2500\u2500 Run ${shortId} (${agentName}, ${time}) \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500`;
4228
+ }
4229
+ function parseContextOptions(options) {
4230
+ const contextN = options.context ? parseInt(options.context, 10) : 0;
4231
+ const before = options.beforeContext ? parseInt(options.beforeContext, 10) : contextN;
4232
+ const after = options.afterContext ? parseInt(options.afterContext, 10) : contextN;
4233
+ if (isNaN(before) || before < 0 || before > 10) {
4234
+ throw new Error("--before-context must be between 0 and 10");
4235
+ }
4236
+ if (isNaN(after) || after < 0 || after > 10) {
4237
+ throw new Error("--after-context must be between 0 and 10");
4238
+ }
4239
+ return { before, after };
4240
+ }
4241
+ function parseLimit(value) {
4242
+ if (!value) return void 0;
4243
+ const limit = parseInt(value, 10);
4244
+ if (isNaN(limit) || limit < 1 || limit > 50) {
4245
+ throw new Error("--limit must be between 1 and 50");
4246
+ }
4247
+ return limit;
4248
+ }
4249
+ function renderResults(response) {
4250
+ const grouped = /* @__PURE__ */ new Map();
4251
+ for (const result of response.results) {
4252
+ const existing = grouped.get(result.runId);
4253
+ if (existing) {
4254
+ existing.results.push(result);
4255
+ } else {
4256
+ grouped.set(result.runId, {
4257
+ agentName: result.agentName,
4258
+ results: [result]
4259
+ });
4260
+ }
4261
+ }
4262
+ let isFirstGroup = true;
4263
+ for (const [runId, group] of grouped) {
4264
+ if (!isFirstGroup) {
4265
+ console.log();
4266
+ }
4267
+ isFirstGroup = false;
4268
+ const firstTimestamp = group.results[0].matchedEvent.createdAt;
4269
+ console.log(
4270
+ chalk55.bold(formatRunHeader(runId, group.agentName, firstTimestamp))
4271
+ );
4272
+ for (const result of group.results) {
4273
+ const renderer = new EventRenderer({
4274
+ showTimestamp: true,
4275
+ verbose: false,
4276
+ buffered: false
4277
+ });
4278
+ for (const event of result.contextBefore) {
4279
+ renderEvent(event, renderer);
4280
+ }
4281
+ renderEvent(result.matchedEvent, renderer);
4282
+ for (const event of result.contextAfter) {
4283
+ renderEvent(event, renderer);
4284
+ }
4285
+ }
4286
+ }
4287
+ if (response.hasMore) {
4288
+ console.log();
4289
+ console.log(
4290
+ chalk55.dim(
4291
+ ` Showing first ${response.results.length} matches. Use --limit to see more.`
4292
+ )
4293
+ );
4294
+ }
4295
+ }
4296
+ var searchCommand = new Command71().name("search").description("Search agent events across runs").argument("<keyword>", "Search keyword").option("-A, --after-context <n>", "Show n events after each match").option("-B, --before-context <n>", "Show n events before each match").option("-C, --context <n>", "Show n events before and after each match").option("--agent <name>", "Filter by agent name").option("--run <id>", "Filter by specific run ID").option("--since <time>", "Search logs since (default: 7d)").option("--limit <n>", "Maximum number of matches (default: 20)").addHelpText(
4297
+ "after",
4298
+ `
4299
+ Examples:
4300
+ zero logs search "error"
4301
+ zero logs search "timeout" --agent my-agent -C 2
4302
+ zero logs search "failed" --since 30d --limit 50`
4303
+ ).action(
4304
+ withErrorHandler(async (keyword, options) => {
4305
+ const { before, after } = parseContextOptions(options);
4306
+ const since = options.since ? parseTime(options.since) : Date.now() - SEVEN_DAYS_MS;
4307
+ const limit = parseLimit(options.limit);
4308
+ const response = await searchZeroLogs({
4309
+ keyword,
4310
+ agent: options.agent,
4311
+ runId: options.run,
4312
+ since,
4313
+ limit,
4314
+ before,
4315
+ after
4316
+ });
4317
+ if (response.results.length === 0) {
4318
+ console.log(chalk55.dim("No matches found"));
4319
+ console.log(
4320
+ chalk55.dim(
4321
+ " Try a broader search with --since 30d or a different keyword"
4322
+ )
4323
+ );
4324
+ return;
4325
+ }
4326
+ renderResults(response);
4327
+ })
4328
+ );
4329
+
4330
+ // src/commands/zero/logs/index.ts
4331
+ var PAGE_LIMIT = 100;
4332
+ function renderAgentEvent(event, renderer) {
4333
+ const eventData = event.eventData;
4334
+ const parsed = ClaudeEventParser.parse(eventData);
4335
+ if (parsed) {
4336
+ parsed.timestamp = new Date(event.createdAt);
4337
+ renderer.render(parsed);
4338
+ }
4339
+ }
4340
+ async function showAgentEvents(runId, options) {
4341
+ const firstResponse = await getZeroRunAgentEvents(runId, {
4342
+ since: options.since,
4343
+ limit: PAGE_LIMIT,
4344
+ order: options.order
4345
+ });
4346
+ if (firstResponse.events.length === 0) {
4347
+ console.log(chalk56.yellow("No agent events found for this run"));
4348
+ return;
4349
+ }
4350
+ let allEvents;
4351
+ if (!firstResponse.hasMore || options.targetCount !== "all" && firstResponse.events.length >= options.targetCount) {
4352
+ allEvents = options.targetCount === "all" ? firstResponse.events : firstResponse.events.slice(0, options.targetCount);
4353
+ } else {
4354
+ const lastEvent = firstResponse.events[firstResponse.events.length - 1];
4355
+ const firstPageTimestamp = lastEvent ? new Date(lastEvent.createdAt).getTime() : void 0;
4356
+ const remainingEvents = await paginate({
4357
+ fetchPage: async (since) => {
4358
+ const response = await getZeroRunAgentEvents(runId, {
4359
+ since,
4360
+ limit: PAGE_LIMIT,
4361
+ order: options.order
4362
+ });
4363
+ return { items: response.events, hasMore: response.hasMore };
4364
+ },
4365
+ getTimestamp: (event) => {
4366
+ return new Date(event.createdAt).getTime();
4367
+ },
4368
+ targetCount: options.targetCount === "all" ? "all" : options.targetCount - firstResponse.events.length,
4369
+ initialSince: firstPageTimestamp
4370
+ });
4371
+ allEvents = [...firstResponse.events, ...remainingEvents];
4372
+ if (options.targetCount !== "all" && allEvents.length > options.targetCount) {
4373
+ allEvents = allEvents.slice(0, options.targetCount);
4374
+ }
4375
+ }
4376
+ const events = options.order === "desc" ? [...allEvents].reverse() : allEvents;
4377
+ const renderer = new EventRenderer({
4378
+ showTimestamp: true,
4379
+ verbose: true
4380
+ });
4381
+ for (const event of events) {
4382
+ renderAgentEvent(event, renderer);
4383
+ }
4384
+ }
4385
+ var zeroLogsCommand = new Command72().name("logs").description("View and search agent run logs").argument("[runId]", "Run ID to view agent events for").addCommand(listCommand11).addCommand(searchCommand).option(
4386
+ "--since <time>",
4387
+ "Show logs since timestamp (e.g., 5m, 2h, 1d, 2024-01-15T10:30:00Z)"
4388
+ ).option("--tail <n>", "Show last N entries (default: 5)").option("--head <n>", "Show first N entries").option("--all", "Fetch all log entries").addHelpText(
4389
+ "after",
4390
+ `
4391
+ Examples:
4392
+ zero logs list
4393
+ zero logs <runId>
4394
+ zero logs <runId> --tail 10
4395
+ zero logs <runId> --all
4396
+ zero logs search "error"`
4397
+ ).action(
4398
+ withErrorHandler(
4399
+ async (runId, options) => {
4400
+ if (!runId) {
4401
+ zeroLogsCommand.help();
4402
+ return;
4403
+ }
4404
+ const countModes = [
4405
+ options.tail !== void 0,
4406
+ options.head !== void 0,
4407
+ options.all === true
4408
+ ].filter(Boolean).length;
4409
+ if (countModes > 1) {
4410
+ throw new Error(
4411
+ "Options --tail, --head, and --all are mutually exclusive"
4412
+ );
4413
+ }
4414
+ let since;
4415
+ if (options.since) {
4416
+ since = parseTime(options.since);
4417
+ }
4418
+ const isAll = options.all === true;
4419
+ const isHead = options.head !== void 0;
4420
+ const isTail = options.tail !== void 0;
4421
+ let targetCount;
4422
+ if (isAll) {
4423
+ targetCount = "all";
4424
+ } else if (isHead) {
4425
+ targetCount = Math.max(1, parseInt(options.head, 10));
4426
+ } else if (isTail) {
4427
+ targetCount = Math.max(1, parseInt(options.tail, 10));
4428
+ } else {
4429
+ targetCount = 5;
4430
+ }
4431
+ const order = isHead ? "asc" : "desc";
4432
+ await showAgentEvents(runId, { since, targetCount, order });
4433
+ }
4434
+ )
4435
+ );
4436
+
4115
4437
  // src/zero.ts
4116
4438
  var COMMAND_CAPABILITY_MAP = {
4117
4439
  agent: "agent:read",
@@ -4119,6 +4441,7 @@ var COMMAND_CAPABILITY_MAP = {
4119
4441
  run: "agent-run:write",
4120
4442
  schedule: "schedule:read",
4121
4443
  doctor: null,
4444
+ logs: "agent-run:read",
4122
4445
  slack: "slack:write",
4123
4446
  whoami: null,
4124
4447
  "ask-user": null
@@ -4134,6 +4457,7 @@ var DEFAULT_COMMANDS = [
4134
4457
  zeroSecretCommand,
4135
4458
  zeroSlackCommand,
4136
4459
  zeroVariableCommand,
4460
+ zeroLogsCommand,
4137
4461
  zeroWhoamiCommand,
4138
4462
  zeroAskUserCommand,
4139
4463
  zeroSkillCommand
@@ -4152,10 +4476,10 @@ function registerZeroCommands(prog, commands) {
4152
4476
  prog.addCommand(cmd, hidden ? { hidden: true } : {});
4153
4477
  }
4154
4478
  }
4155
- var program = new Command70();
4479
+ var program = new Command73();
4156
4480
  program.name("zero").description(
4157
4481
  "Zero CLI \u2014 interact with the zero platform from inside the sandbox"
4158
- ).version("9.95.1").addHelpText(
4482
+ ).version("9.96.0").addHelpText(
4159
4483
  "after",
4160
4484
  `
4161
4485
  Examples: