@vm0/cli 9.151.0 → 9.153.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/zero.js CHANGED
@@ -17,11 +17,13 @@ import {
17
17
  configureGlobalProxyFromEnv,
18
18
  connectorTypeSchema,
19
19
  createLocalBrowserReadCommand,
20
+ createLocalBrowserWriteCommand,
20
21
  createSkill,
21
22
  createZeroAgent,
22
23
  createZeroRun,
23
24
  decodeCliTokenPayload,
24
25
  decodeZeroTokenPayload,
26
+ deleteLocalBrowserHost,
25
27
  deleteSkill,
26
28
  deleteZeroAgent,
27
29
  deleteZeroOrg,
@@ -79,6 +81,8 @@ import {
79
81
  isInteractive,
80
82
  isUUID,
81
83
  leaveZeroOrg,
84
+ listLocalBrowserAuditEvents,
85
+ listLocalBrowserHosts,
82
86
  listSkills,
83
87
  listTelegramBots,
84
88
  listZeroAgents,
@@ -134,7 +138,7 @@ import {
134
138
  withErrorHandler,
135
139
  zeroAgentCustomSkillNameSchema,
136
140
  zeroRemoteAgentCommand
137
- } from "./chunk-VUZYX6DE.js";
141
+ } from "./chunk-7B5CZ4YO.js";
138
142
  import {
139
143
  __toESM,
140
144
  init_esm_shims
@@ -2538,9 +2542,51 @@ init_esm_shims();
2538
2542
  var BUILT_IN_GENERATION_PROVIDERS = {
2539
2543
  image: [
2540
2544
  {
2541
- label: "Built-in",
2545
+ label: "Built-in OpenAI",
2542
2546
  model: "gpt-image-2",
2543
- command: "zero built-in generate image -h",
2547
+ command: "zero built-in generate image --model gpt-image-2 -h",
2548
+ reason: "available without connector setup"
2549
+ },
2550
+ {
2551
+ label: "Built-in OpenAI",
2552
+ model: "gpt-image-1.5",
2553
+ command: "zero built-in generate image --model gpt-image-1.5 -h",
2554
+ reason: "available without connector setup"
2555
+ },
2556
+ {
2557
+ label: "Built-in OpenAI",
2558
+ model: "gpt-image-1",
2559
+ command: "zero built-in generate image --model gpt-image-1 -h",
2560
+ reason: "available without connector setup"
2561
+ },
2562
+ {
2563
+ label: "Built-in OpenAI",
2564
+ model: "gpt-image-1-mini",
2565
+ command: "zero built-in generate image --model gpt-image-1-mini -h",
2566
+ reason: "available without connector setup"
2567
+ },
2568
+ {
2569
+ label: "Built-in fal.ai",
2570
+ model: "fal-ai/flux-pro/v1.1",
2571
+ command: "zero built-in generate image --model flux-pro-1.1 -h",
2572
+ reason: "available without connector setup"
2573
+ },
2574
+ {
2575
+ label: "Built-in fal.ai",
2576
+ model: "fal-ai/flux-pro/v1.1-ultra",
2577
+ command: "zero built-in generate image --model flux-pro-1.1-ultra -h",
2578
+ reason: "available without connector setup"
2579
+ },
2580
+ {
2581
+ label: "Built-in fal.ai",
2582
+ model: "fal-ai/qwen-image",
2583
+ command: "zero built-in generate image --model qwen-image -h",
2584
+ reason: "available without connector setup"
2585
+ },
2586
+ {
2587
+ label: "Built-in fal.ai",
2588
+ model: "fal-ai/bytedance/seedream/v4/text-to-image",
2589
+ command: "zero built-in generate image --model seedream4 -h",
2544
2590
  reason: "available without connector setup"
2545
2591
  }
2546
2592
  ],
@@ -2599,6 +2645,28 @@ var BUILT_IN_GENERATION_PROVIDERS = {
2599
2645
  }
2600
2646
  ]
2601
2647
  };
2648
+ var BUILT_IN_GENERATION_COMMANDS = {
2649
+ image: {
2650
+ label: "Built-in image generation",
2651
+ command: "zero built-in generate image -h",
2652
+ models: "OpenAI: gpt-image-2, gpt-image-1.5, gpt-image-1, gpt-image-1-mini; fal.ai: flux-pro-1.1, flux-pro-1.1-ultra, qwen-image, seedream4"
2653
+ },
2654
+ video: {
2655
+ label: "Built-in video generation",
2656
+ command: "zero built-in generate video -h",
2657
+ models: "veo3.1-fast, veo3.1, kling-o3-standard, kling-v3-4k, seedance2.0, seedance2.0-fast"
2658
+ },
2659
+ presentation: {
2660
+ label: "Built-in presentation generation",
2661
+ command: "zero built-in generate presentation -h",
2662
+ models: "gpt-5.5"
2663
+ },
2664
+ voice: {
2665
+ label: "Built-in voice generation",
2666
+ command: "zero built-in generate voice -h",
2667
+ models: "gpt-4o-mini-tts"
2668
+ }
2669
+ };
2602
2670
  var GENERATION_TYPE_ORDER = [
2603
2671
  "image",
2604
2672
  "video",
@@ -2630,6 +2698,9 @@ function getConnectorGenerationType(generationType) {
2630
2698
  function getBuiltInProviders(generationType) {
2631
2699
  return BUILT_IN_GENERATION_PROVIDERS[generationType] ?? [];
2632
2700
  }
2701
+ function getBuiltInCommand(generationType) {
2702
+ return BUILT_IN_GENERATION_COMMANDS[generationType] ?? null;
2703
+ }
2633
2704
  function getAvailableGenerationTypes() {
2634
2705
  const available = /* @__PURE__ */ new Set();
2635
2706
  for (const config of Object.values(CONNECTOR_TYPES)) {
@@ -2760,6 +2831,15 @@ function renderActions(candidates) {
2760
2831
  }
2761
2832
  }
2762
2833
  function renderBuiltInProvider(generationType) {
2834
+ const command = getBuiltInCommand(generationType);
2835
+ if (command) {
2836
+ console.log("");
2837
+ console.log("Built-in command:");
2838
+ console.log(` vm0 ${command.label}`);
2839
+ console.log(` Models: ${command.models}`);
2840
+ console.log(` Use: ${command.command}`);
2841
+ return;
2842
+ }
2763
2843
  const providers = getBuiltInProviders(generationType);
2764
2844
  if (providers.length === 0) return;
2765
2845
  console.log("");
@@ -7223,20 +7303,35 @@ function parseCompression(value) {
7223
7303
  }
7224
7304
  return compression;
7225
7305
  }
7306
+ function parseSeed(value) {
7307
+ const seed = Number(value);
7308
+ if (!Number.isInteger(seed) || seed < 0 || !Number.isSafeInteger(seed)) {
7309
+ throw new InvalidArgumentError("seed must be a non-negative safe integer");
7310
+ }
7311
+ return seed;
7312
+ }
7226
7313
  function createImageGenerateCommand(config) {
7227
7314
  return new Command().name(config.name).description("Generate a billed image file from a prompt").option("--prompt <text>", "Image prompt; can also be piped via stdin").option(
7315
+ "--model <model>",
7316
+ "Model: gpt-image-2, gpt-image-1.5, gpt-image-1, gpt-image-1-mini, flux-pro-1.1, flux-pro-1.1-ultra, qwen-image, or seedream4",
7317
+ "gpt-image-2"
7318
+ ).option(
7228
7319
  "--size <size>",
7229
- "Image size: auto or any valid WIDTHxHEIGHT for GPT Image 2",
7320
+ "Image size: auto or WIDTHxHEIGHT; support varies by model",
7230
7321
  "1024x1024"
7231
7322
  ).option(
7232
7323
  "--quality <quality>",
7233
7324
  "Image quality: low, medium, high, or auto",
7234
7325
  "medium"
7235
- ).option("--background <background>", "Background: auto or opaque", "auto").option("--format <format>", "Output format: png, webp, or jpeg", "png").option("--compression <0-100>", "Output compression for jpeg/webp only").option(
7326
+ ).option(
7327
+ "--background <background>",
7328
+ "Background: auto, opaque, or transparent when supported",
7329
+ "auto"
7330
+ ).option("--format <format>", "Output format: png, webp, or jpeg", "png").option("--compression <0-100>", "Output compression for jpeg/webp only").option(
7236
7331
  "--moderation <moderation>",
7237
7332
  "Moderation strictness: auto or low",
7238
7333
  "auto"
7239
- ).option("--json", "Print metadata as JSON").addHelpText(
7334
+ ).option("--seed <integer>", "Deterministic seed for fal models", parseSeed).option("--safety-tolerance <level>", "fal safety tolerance: 1-6", "4").option("--enhance-prompt", "Enable fal prompt enhancement when supported").option("--json", "Print metadata as JSON").addHelpText(
7240
7335
  "after",
7241
7336
  `
7242
7337
  Examples:
@@ -7248,23 +7343,34 @@ Output:
7248
7343
  Notes:
7249
7344
  - Authenticates via ZERO_TOKEN (requires file:write capability)
7250
7345
  - Charges org credits after successful image generation
7251
- - Uses OpenAI gpt-image-2 and bills returned usage tokens
7346
+ - Uses OpenAI for GPT Image models and fal.ai for non-OpenAI models
7347
+
7348
+ Models:
7349
+ - OpenAI: gpt-image-2 (default), gpt-image-1.5, gpt-image-1,
7350
+ gpt-image-1-mini. OpenAI generations bill returned text/image/output
7351
+ token usage.
7352
+ - fal.ai: flux-pro-1.1, flux-pro-1.1-ultra, qwen-image, seedream4.
7353
+ fal generations bill by output image or rounded-up output megapixel,
7354
+ depending on the model.
7252
7355
 
7253
- GPT Image 2 options:
7356
+ Options:
7254
7357
  - Prompt: required, up to 32,000 characters; stdin is supported.
7255
- - Size: use auto or WIDTHxHEIGHT. Popular sizes include 1024x1024,
7358
+ - Size: gpt-image-2 accepts auto or WIDTHxHEIGHT. Popular sizes include
7359
+ 1024x1024,
7256
7360
  1536x1024, 1024x1536, 2048x2048, 2048x1152, 3840x2160,
7257
7361
  and 2160x3840. Custom sizes must have edges <= 3840px, both
7258
7362
  edges divisible by 16, long:short ratio <= 3:1, and total pixels
7259
- between 655,360 and 8,294,400. Outputs larger than 2560x1440
7260
- total pixels are experimental.
7363
+ between 655,360 and 8,294,400. gpt-image-1.5, gpt-image-1, and
7364
+ gpt-image-1-mini use auto, 1024x1024, 1536x1024, or 1024x1536.
7261
7365
  - Quality: low, medium, high, or auto. Low is fastest for drafts.
7262
- - Background: auto or opaque. GPT Image 2 does not support transparent
7263
- backgrounds.
7264
- - Format: png, jpeg, or webp. Use --compression 0-100 only with jpeg
7265
- or webp; jpeg is usually lower latency than png.
7266
- - Moderation: auto or low.
7267
- - This command generates one text-to-image result. GPT Image 2 also
7366
+ - Background: auto, opaque, or transparent. gpt-image-2 and fal models do
7367
+ not support transparent backgrounds.
7368
+ - Format: png, jpeg, or webp for OpenAI; png or jpeg for fal. Use
7369
+ --compression 0-100 only with OpenAI jpeg or webp outputs.
7370
+ - Moderation: auto or low for OpenAI models.
7371
+ - fal-only controls: --seed, --safety-tolerance for Flux, and
7372
+ --enhance-prompt for flux-pro-1.1.
7373
+ - This command generates one text-to-image result. GPT Image also
7268
7374
  supports image edits, reference images, masks, partial-image streaming,
7269
7375
  and multiple images per request, but those are not exposed by this
7270
7376
  built-in Zero command yet.`
@@ -7274,12 +7380,16 @@ GPT Image 2 options:
7274
7380
  const compression = parseCompression(options.compression);
7275
7381
  const result = await generateWebImage({
7276
7382
  prompt,
7383
+ model: options.model,
7277
7384
  size: options.size,
7278
7385
  quality: options.quality,
7279
7386
  background: options.background,
7280
7387
  outputFormat: options.format,
7281
7388
  outputCompression: compression,
7282
- moderation: options.moderation
7389
+ moderation: options.moderation,
7390
+ seed: options.seed,
7391
+ safetyTolerance: options.safetyTolerance,
7392
+ enhancePrompt: options.enhancePrompt
7283
7393
  });
7284
7394
  if (options.json) {
7285
7395
  console.log(JSON.stringify(result));
@@ -7296,8 +7406,17 @@ GPT Image 2 options:
7296
7406
  if (result.moderation) {
7297
7407
  console.log(source_default.dim(` Moderation: ${result.moderation}`));
7298
7408
  }
7409
+ if (result.safetyTolerance) {
7410
+ console.log(
7411
+ source_default.dim(` Safety tolerance: ${result.safetyTolerance}`)
7412
+ );
7413
+ }
7414
+ if (result.seed !== void 0) {
7415
+ console.log(source_default.dim(` Seed: ${result.seed}`));
7416
+ }
7299
7417
  console.log(source_default.dim(` Credits charged: ${result.creditsCharged}`));
7300
7418
  console.log(source_default.dim(` Model: ${result.model}`));
7419
+ console.log(source_default.dim(` Provider: ${result.provider}`));
7301
7420
  })
7302
7421
  );
7303
7422
  }
@@ -7308,7 +7427,8 @@ var imageCommand = createImageGenerateCommand({
7308
7427
  usageCommand: "zero built-in generate image",
7309
7428
  examples: ` Generate image: zero built-in generate image --prompt "A watercolor fox"
7310
7429
  Pipe prompt: cat prompt.txt | zero built-in generate image
7311
- Pick size/quality: zero built-in generate image --prompt "A poster" --size 1024x1536 --quality high`
7430
+ OpenAI model: zero built-in generate image --model gpt-image-1.5 --prompt "A poster" --size 1024x1536 --quality high
7431
+ fal model: zero built-in generate image --model flux-pro-1.1 --prompt "A product hero shot" --seed 42`
7312
7432
  });
7313
7433
 
7314
7434
  // src/commands/zero/built-in/generate/presentation.ts
@@ -7421,7 +7541,7 @@ init_esm_shims();
7421
7541
  // src/commands/zero/shared/video-generate.ts
7422
7542
  init_esm_shims();
7423
7543
  import { readFileSync as readFileSync14 } from "fs";
7424
- function parseSeed(value) {
7544
+ function parseSeed2(value) {
7425
7545
  const seed = Number(value);
7426
7546
  if (!Number.isInteger(seed) || seed < 0 || !Number.isSafeInteger(seed)) {
7427
7547
  throw new InvalidArgumentError("seed must be a non-negative safe integer");
@@ -7455,7 +7575,7 @@ function createVideoGenerateCommand(config) {
7455
7575
  "--duration <duration>",
7456
7576
  "Duration: 3s-15s; Veo supports 4s/6s/8s",
7457
7577
  "8s"
7458
- ).option("--resolution <resolution>", "Resolution: 720p, 1080p, or 4k").option("--no-audio", "Generate a silent video").option("--negative-prompt <text>", "Negative prompt").option("--seed <integer>", "Deterministic seed", parseSeed).option("--no-auto-fix", "Disable fal prompt auto-fix").option("--safety-tolerance <level>", "Safety tolerance: 1-6", "4").option("--json", "Print metadata as JSON").addHelpText(
7578
+ ).option("--resolution <resolution>", "Resolution: 720p, 1080p, or 4k").option("--no-audio", "Generate a silent video").option("--negative-prompt <text>", "Negative prompt").option("--seed <integer>", "Deterministic seed", parseSeed2).option("--no-auto-fix", "Disable fal prompt auto-fix").option("--safety-tolerance <level>", "Safety tolerance: 1-6", "4").option("--json", "Print metadata as JSON").addHelpText(
7459
7579
  "after",
7460
7580
  `
7461
7581
  Examples:
@@ -7467,7 +7587,18 @@ Output:
7467
7587
  Notes:
7468
7588
  - Authenticates via ZERO_TOKEN (requires file:write capability)
7469
7589
  - Charges org credits after successful video generation
7470
- - Uses fal video models with configured usage pricing`
7590
+ - Uses fal video models with configured usage pricing
7591
+
7592
+ Models:
7593
+ - Veo: veo3.1-fast (default), veo3.1. Supports 4s/6s/8s,
7594
+ 16:9 or 9:16, 720p/1080p/4k, negative prompts, seed,
7595
+ auto-fix, safety tolerance, and optional audio.
7596
+ - Kling: kling-o3-standard, kling-v3-4k. Supports 3s-15s and
7597
+ 16:9 or 9:16. kling-v3-4k uses 4k output; kling-o3-standard
7598
+ uses 1080p output.
7599
+ - Seedance: seedance2.0, seedance2.0-fast. Supports 4s-15s,
7600
+ 480p/720p, seed, and aspect ratios 21:9, 16:9, 4:3, 1:1,
7601
+ 3:4, or 9:16.`
7471
7602
  ).action(
7472
7603
  withErrorHandler(async (options) => {
7473
7604
  const prompt = readPrompt3(options, config.usageCommand);
@@ -7700,6 +7831,34 @@ function parseTimeoutSeconds(value) {
7700
7831
  }
7701
7832
  return seconds;
7702
7833
  }
7834
+ function parseOptionalNonNegativeInteger(value, label) {
7835
+ if (value === void 0) return void 0;
7836
+ const parsed = Number.parseInt(value, 10);
7837
+ if (!Number.isFinite(parsed) || parsed < 0) {
7838
+ throw new Error(`${label} must be a non-negative integer`);
7839
+ }
7840
+ return parsed;
7841
+ }
7842
+ function parsePositiveInteger2(value, label) {
7843
+ if (value === void 0) {
7844
+ throw new Error(`${label} is required`);
7845
+ }
7846
+ const parsed = Number.parseInt(value, 10);
7847
+ if (!Number.isFinite(parsed) || parsed <= 0) {
7848
+ throw new Error(`${label} must be a positive integer`);
7849
+ }
7850
+ return parsed;
7851
+ }
7852
+ function parseLimit4(value) {
7853
+ if (value === void 0) {
7854
+ return 50;
7855
+ }
7856
+ const parsed = parsePositiveInteger2(value, "limit");
7857
+ if (parsed > 200) {
7858
+ throw new Error("limit must be 200 or less");
7859
+ }
7860
+ return parsed;
7861
+ }
7703
7862
  function resultText(command) {
7704
7863
  if (!command.result) {
7705
7864
  return "";
@@ -7741,9 +7900,52 @@ async function runReadCommand(kind, options) {
7741
7900
  }
7742
7901
  throw new Error(`Local-browser command timed out: ${created.commandId}`);
7743
7902
  }
7903
+ async function waitForCommand(commandId, timeoutSeconds) {
7904
+ const deadline = Date.now() + timeoutSeconds * 1e3;
7905
+ while (Date.now() <= deadline) {
7906
+ const command = await getLocalBrowserReadCommand(commandId);
7907
+ if (command.status === "pending_approval" || command.status === "queued" || command.status === "running") {
7908
+ if (process.stdout.isTTY) {
7909
+ process.stdout.write(".");
7910
+ }
7911
+ await sleep3(1e3);
7912
+ continue;
7913
+ }
7914
+ if (process.stdout.isTTY) {
7915
+ process.stdout.write("\n");
7916
+ }
7917
+ if (command.status === "failed") {
7918
+ throw new Error(
7919
+ command.error ? `${command.error.code}: ${command.error.message}` : "Local-browser command failed"
7920
+ );
7921
+ }
7922
+ const text = resultText(command);
7923
+ if (text) {
7924
+ console.log(text);
7925
+ }
7926
+ return;
7927
+ }
7928
+ throw new Error(`Local-browser command timed out: ${commandId}`);
7929
+ }
7930
+ async function runWriteCommand(kind, options, payload) {
7931
+ const timeoutSeconds = parseTimeoutSeconds(options.timeout);
7932
+ const created = await createLocalBrowserWriteCommand({
7933
+ kind,
7934
+ timeoutMs: timeoutSeconds * 1e3,
7935
+ ...options.tabId ? { tabId: options.tabId } : {},
7936
+ ...options.host ? { hostName: options.host } : {},
7937
+ ...options.hostId ? { hostId: options.hostId } : {},
7938
+ ...payload
7939
+ });
7940
+ await waitForCommand(created.commandId, timeoutSeconds);
7941
+ }
7744
7942
  function addReadOptions(command) {
7745
7943
  return command.option("--host <name>", "Run on a named local-browser host").option("--host-id <id>", "Run on a specific local-browser host id").option("--tab-id <id>", "Target a specific browser tab").option("--timeout <seconds>", "Maximum time to wait", "30");
7746
7944
  }
7945
+ function addWriteOptions(command, options = {}) {
7946
+ const withHostOptions = command.option("--host <name>", "Run on a named local-browser host").option("--host-id <id>", "Run on a specific local-browser host id").option("--timeout <seconds>", "Maximum time to wait", "30");
7947
+ return options.tabId === false ? withHostOptions : withHostOptions.option("--tab-id <id>", "Target a specific browser tab");
7948
+ }
7747
7949
  function readCommand(name, kind) {
7748
7950
  return addReadOptions(
7749
7951
  new Command().name(name).description(`Run ${kind}`).action(
@@ -7753,17 +7955,187 @@ function readCommand(name, kind) {
7753
7955
  )
7754
7956
  );
7755
7957
  }
7756
- var tabsCommand = new Command().name("tabs").description("Read browser tabs").addCommand(readCommand("list", "tabs.list")).addCommand(readCommand("current", "tabs.current"));
7757
- var pageCommand = new Command().name("page").description("Read the active browser page").addCommand(readCommand("snapshot", "page.snapshot")).addCommand(readCommand("screenshot", "page.screenshot")).addCommand(readCommand("selection", "page.selection")).addCommand(readCommand("metadata", "page.metadata"));
7758
- var zeroLocalBrowserCommand = new Command().name("local-browser").description("Read authorized browser context").addHelpText(
7958
+ function formatCapabilities(capabilities) {
7959
+ return capabilities.length > 0 ? capabilities.join(", ") : "none";
7960
+ }
7961
+ function formatHost(host) {
7962
+ const status = host.status === "online" ? source_default.green("online") : source_default.dim("offline");
7963
+ return [
7964
+ `${status} ${host.displayName}`,
7965
+ ` id: ${host.id}`,
7966
+ ` browser: ${host.browser}`,
7967
+ ` extension: ${host.extensionVersion}`,
7968
+ ` last seen: ${host.lastSeenAt}`,
7969
+ ` capabilities: ${formatCapabilities(host.supportedCapabilities)}`
7970
+ ].join("\n");
7971
+ }
7972
+ function formatAuditEvent(event) {
7973
+ const parts = [
7974
+ event.createdAt,
7975
+ event.event,
7976
+ event.kind,
7977
+ `command=${event.commandId}`
7978
+ ];
7979
+ if (event.hostId) {
7980
+ parts.push(`host=${event.hostId}`);
7981
+ }
7982
+ if (event.runId) {
7983
+ parts.push(`run=${event.runId}`);
7984
+ }
7985
+ if (event.tabId) {
7986
+ parts.push(`tab=${event.tabId}`);
7987
+ }
7988
+ if (event.targetUrl) {
7989
+ parts.push(`url=${event.targetUrl}`);
7990
+ }
7991
+ if (event.approvalOutcome) {
7992
+ parts.push(`approval=${event.approvalOutcome}`);
7993
+ }
7994
+ if (event.error) {
7995
+ parts.push(`error=${JSON.stringify(event.error)}`);
7996
+ }
7997
+ return parts.join(" ");
7998
+ }
7999
+ var hostsCommand = new Command().name("hosts").description("List and revoke linked local-browser hosts").addCommand(
8000
+ new Command().name("list").description("List linked local-browser hosts").option("--json", "Output hosts as JSON").action(
8001
+ withErrorHandler(async (options) => {
8002
+ const result = await listLocalBrowserHosts();
8003
+ if (options.json) {
8004
+ console.log(JSON.stringify(result));
8005
+ return;
8006
+ }
8007
+ if (result.hosts.length === 0) {
8008
+ console.log(source_default.dim("No linked local-browser hosts."));
8009
+ return;
8010
+ }
8011
+ console.log(result.hosts.map(formatHost).join("\n\n"));
8012
+ })
8013
+ )
8014
+ ).addCommand(
8015
+ new Command().name("revoke").description("Revoke a linked local-browser host").argument("<host-id>", "Local-browser host id").option("--json", "Output the revoke result as JSON").action(
8016
+ withErrorHandler(async (hostId, options) => {
8017
+ const result = await deleteLocalBrowserHost(hostId);
8018
+ if (options.json) {
8019
+ console.log(JSON.stringify(result));
8020
+ return;
8021
+ }
8022
+ console.log(source_default.green("Local-browser host revoked"));
8023
+ console.log(source_default.dim(` Host: ${hostId}`));
8024
+ })
8025
+ )
8026
+ );
8027
+ var auditCommand = new Command().name("audit").description("Inspect local-browser write command audit events").addCommand(
8028
+ new Command().name("list").description("List local-browser write command audit events").option("--limit <count>", "Maximum events to show", "50").option("--command-id <id>", "Filter by command id").option("--host-id <id>", "Filter by host id").option("--run-id <id>", "Filter by run id").option("--json", "Output audit events as JSON").action(
8029
+ withErrorHandler(async (options) => {
8030
+ const result = await listLocalBrowserAuditEvents({
8031
+ limit: parseLimit4(options.limit),
8032
+ ...options.commandId ? { commandId: options.commandId } : {},
8033
+ ...options.hostId ? { hostId: options.hostId } : {},
8034
+ ...options.runId ? { runId: options.runId } : {}
8035
+ });
8036
+ if (options.json) {
8037
+ console.log(JSON.stringify(result));
8038
+ return;
8039
+ }
8040
+ if (result.auditEvents.length === 0) {
8041
+ console.log(source_default.dim("No local-browser audit events found."));
8042
+ return;
8043
+ }
8044
+ console.log(result.auditEvents.map(formatAuditEvent).join("\n"));
8045
+ })
8046
+ )
8047
+ );
8048
+ var tabsCommand = new Command().name("tabs").description("Read and control browser tabs").addCommand(readCommand("list", "tabs.list")).addCommand(readCommand("current", "tabs.current")).addCommand(
8049
+ addWriteOptions(
8050
+ new Command().name("activate").description("Run tabs.activate").requiredOption("--tab-id <id>", "Tab to activate").action(
8051
+ withErrorHandler(async (options) => {
8052
+ await runWriteCommand("tabs.activate", options, {});
8053
+ })
8054
+ ),
8055
+ { tabId: false }
8056
+ )
8057
+ ).addCommand(
8058
+ addWriteOptions(
8059
+ new Command().name("open").description("Run tabs.open").requiredOption("--url <url>", "URL to open").action(
8060
+ withErrorHandler(async (options) => {
8061
+ await runWriteCommand("tabs.open", options, { url: options.url });
8062
+ })
8063
+ )
8064
+ )
8065
+ ).addCommand(
8066
+ addWriteOptions(
8067
+ new Command().name("close").description("Run tabs.close").requiredOption("--tab-id <id>", "Tab to close").action(
8068
+ withErrorHandler(async (options) => {
8069
+ await runWriteCommand("tabs.close", options, {});
8070
+ })
8071
+ ),
8072
+ { tabId: false }
8073
+ )
8074
+ );
8075
+ var pageCommand = new Command().name("page").description("Read and control the active browser page").addCommand(readCommand("snapshot", "page.snapshot")).addCommand(readCommand("screenshot", "page.screenshot")).addCommand(readCommand("selection", "page.selection")).addCommand(readCommand("metadata", "page.metadata")).addCommand(
8076
+ addWriteOptions(
8077
+ new Command().name("click").description("Run page.click").option("--selector <selector>", "CSS selector to click").option("--x <pixels>", "X coordinate to click").option("--y <pixels>", "Y coordinate to click").action(
8078
+ withErrorHandler(async (options) => {
8079
+ await runWriteCommand("page.click", options, {
8080
+ ...options.selector ? { selector: options.selector } : {},
8081
+ ...options.x !== void 0 ? { x: parseOptionalNonNegativeInteger(options.x, "x") } : {},
8082
+ ...options.y !== void 0 ? { y: parseOptionalNonNegativeInteger(options.y, "y") } : {}
8083
+ });
8084
+ })
8085
+ )
8086
+ )
8087
+ ).addCommand(
8088
+ addWriteOptions(
8089
+ new Command().name("type").description("Run page.type").requiredOption("--selector <selector>", "CSS selector to type into").requiredOption("--text <text>", "Text to type").action(
8090
+ withErrorHandler(async (options) => {
8091
+ await runWriteCommand("page.type", options, {
8092
+ selector: options.selector,
8093
+ text: options.text
8094
+ });
8095
+ })
8096
+ )
8097
+ )
8098
+ ).addCommand(
8099
+ addWriteOptions(
8100
+ new Command().name("scroll").description("Run page.scroll").option(
8101
+ "--direction <direction>",
8102
+ "Scroll direction: up or down",
8103
+ "down"
8104
+ ).option("--amount <pixels>", "Scroll amount in pixels", "600").action(
8105
+ withErrorHandler(async (options) => {
8106
+ if (options.direction !== "up" && options.direction !== "down") {
8107
+ throw new Error("direction must be up or down");
8108
+ }
8109
+ await runWriteCommand("page.scroll", options, {
8110
+ direction: options.direction,
8111
+ amount: parsePositiveInteger2(options.amount, "amount")
8112
+ });
8113
+ })
8114
+ )
8115
+ )
8116
+ ).addCommand(
8117
+ addWriteOptions(
8118
+ new Command().name("navigate").description("Run page.navigate").requiredOption("--url <url>", "URL to navigate to").action(
8119
+ withErrorHandler(async (options) => {
8120
+ await runWriteCommand("page.navigate", options, {
8121
+ url: options.url
8122
+ });
8123
+ })
8124
+ )
8125
+ )
8126
+ );
8127
+ var zeroLocalBrowserCommand = new Command().name("local-browser").description("Read and manage authorized browser context").addHelpText(
7759
8128
  "after",
7760
8129
  `
7761
8130
  Examples:
8131
+ List hosts? zero local-browser hosts list
8132
+ Revoke host? zero local-browser hosts revoke <host-id>
7762
8133
  List tabs? zero local-browser tabs list
7763
8134
  Current tab? zero local-browser tabs current
7764
- Page metadata? zero local-browser page metadata
7765
- Page selection? zero local-browser page selection`
7766
- ).addCommand(tabsCommand).addCommand(pageCommand);
8135
+ Click page? zero local-browser page click --selector button
8136
+ Open tab? zero local-browser tabs open --url https://example.com
8137
+ Audit actions? zero local-browser audit list`
8138
+ ).addCommand(hostsCommand).addCommand(auditCommand).addCommand(tabsCommand).addCommand(pageCommand);
7767
8139
 
7768
8140
  // src/commands/zero/host/index.ts
7769
8141
  init_esm_shims();
@@ -8084,7 +8456,7 @@ var COMMAND_CAPABILITY_MAP = {
8084
8456
  web: null,
8085
8457
  host: "host:write",
8086
8458
  "remote-agent": ["remote-agent:read", "remote-agent:write"],
8087
- "local-browser": "local-browser:read"
8459
+ "local-browser": ["local-browser:read", "local-browser:write"]
8088
8460
  };
8089
8461
  var DEFAULT_COMMANDS = [
8090
8462
  zeroOrgCommand,
@@ -8159,7 +8531,7 @@ function registerZeroCommands(prog, commands) {
8159
8531
  var program = new Command();
8160
8532
  program.name("zero").description(
8161
8533
  "Zero CLI \u2014 interact with the zero platform from inside the sandbox"
8162
- ).version("9.151.0").addHelpText("after", () => {
8534
+ ).version("9.153.0").addHelpText("after", () => {
8163
8535
  return buildZeroHelpText();
8164
8536
  });
8165
8537
  if (process.argv[1]?.endsWith("zero.js") || process.argv[1]?.endsWith("zero.ts") || process.argv[1]?.endsWith("zero")) {