@vm0/cli 9.212.4 → 9.213.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.
package/index.js CHANGED
@@ -78,7 +78,7 @@ import {
78
78
  uo,
79
79
  volumeConfigSchema,
80
80
  withErrorHandler
81
- } from "./chunk-DNXUAGZZ.js";
81
+ } from "./chunk-AFQMB63J.js";
82
82
  import "./chunk-NR42YJMI.js";
83
83
  import {
84
84
  __toESM,
@@ -412,7 +412,7 @@ function getConfigPath() {
412
412
  return join(os.homedir(), ".vm0", "config.json");
413
413
  }
414
414
  var infoCommand = new Command().name("info").description("Display environment and debug information").action(async () => {
415
- console.log(source_default.bold(`VM0 CLI v${"9.212.4"}`));
415
+ console.log(source_default.bold(`VM0 CLI v${"9.213.1"}`));
416
416
  console.log();
417
417
  const config = await loadConfig();
418
418
  const hasEnvToken = !!process.env.VM0_TOKEN;
@@ -1114,7 +1114,7 @@ var composeCommand = new Command().name("compose").description("Create or update
1114
1114
  options.autoUpdate = false;
1115
1115
  }
1116
1116
  if (options.autoUpdate !== false) {
1117
- await startSilentUpgrade("9.212.4");
1117
+ await startSilentUpgrade("9.213.1");
1118
1118
  }
1119
1119
  try {
1120
1120
  const { config, agentName, agent, basePath } = await loadAndValidateConfig(resolvedConfigFile);
@@ -1211,7 +1211,7 @@ var mainRunCommand = new Command().name("run").description("Run an agent").argum
1211
1211
  withErrorHandler(
1212
1212
  async (identifier, prompt, options) => {
1213
1213
  if (options.autoUpdate !== false) {
1214
- await startSilentUpgrade("9.212.4");
1214
+ await startSilentUpgrade("9.213.1");
1215
1215
  }
1216
1216
  const { name, version } = parseIdentifier(identifier);
1217
1217
  let composeId;
@@ -3070,13 +3070,13 @@ var upgradeCommand = new Command().name("upgrade").description("Upgrade vm0 CLI
3070
3070
  if (latestVersion === null) {
3071
3071
  throw new Error("Could not check for updates. Please try again later.");
3072
3072
  }
3073
- if (latestVersion === "9.212.4") {
3074
- console.log(source_default.green(`\u2713 Already up to date (${"9.212.4"})`));
3073
+ if (latestVersion === "9.213.1") {
3074
+ console.log(source_default.green(`\u2713 Already up to date (${"9.213.1"})`));
3075
3075
  return;
3076
3076
  }
3077
3077
  console.log(
3078
3078
  source_default.yellow(
3079
- `Current version: ${"9.212.4"} -> Latest version: ${latestVersion}`
3079
+ `Current version: ${"9.213.1"} -> Latest version: ${latestVersion}`
3080
3080
  )
3081
3081
  );
3082
3082
  console.log();
@@ -3103,7 +3103,7 @@ var upgradeCommand = new Command().name("upgrade").description("Upgrade vm0 CLI
3103
3103
  const success = await performUpgrade(packageManager);
3104
3104
  if (success) {
3105
3105
  console.log(
3106
- source_default.green(`\u2713 Upgraded from ${"9.212.4"} to ${latestVersion}`)
3106
+ source_default.green(`\u2713 Upgraded from ${"9.213.1"} to ${latestVersion}`)
3107
3107
  );
3108
3108
  return;
3109
3109
  }
@@ -3170,7 +3170,7 @@ var whoamiCommand = new Command().name("whoami").description("Show current ident
3170
3170
 
3171
3171
  // src/index.ts
3172
3172
  var program = new Command();
3173
- program.name("vm0").description("VM0 CLI - Build and run agents with natural language").version("9.212.4");
3173
+ program.name("vm0").description("VM0 CLI - Build and run agents with natural language").version("9.213.1");
3174
3174
  program.addCommand(authCommand);
3175
3175
  program.addCommand(infoCommand);
3176
3176
  program.addCommand(composeCommand);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@vm0/cli",
3
- "version": "9.212.4",
3
+ "version": "9.213.1",
4
4
  "description": "CLI application",
5
5
  "repository": {
6
6
  "type": "git",
package/zero.js CHANGED
@@ -109,6 +109,7 @@ import {
109
109
  getZeroRunAgentEvents,
110
110
  getZeroRunContext,
111
111
  getZeroUserPreferences,
112
+ getZeroWorkflowUserConnectors,
112
113
  hasAuthMethods,
113
114
  hasRequiredConnectorAuthMethodScopes,
114
115
  hostedArtifactKindSchema,
@@ -190,7 +191,7 @@ import {
190
191
  uploadWebFile,
191
192
  upsertZeroOrgModelProvider,
192
193
  withErrorHandler
193
- } from "./chunk-DNXUAGZZ.js";
194
+ } from "./chunk-AFQMB63J.js";
194
195
  import "./chunk-NR42YJMI.js";
195
196
  import {
196
197
  __toESM,
@@ -12948,39 +12949,22 @@ async function getCurrentRunContext() {
12948
12949
  if (!runId) return null;
12949
12950
  return await getZeroRunContext(runId);
12950
12951
  }
12951
- function checkEnvName(ctx) {
12952
- console.log("## Step 1: Sandbox environment name");
12953
- console.log("");
12954
- const envPresent = Boolean(process.env[ctx.envName]);
12955
- console.log(
12956
- `Checking process.env.${ctx.envName}: ${envPresent ? "present" : "not present"}`
12957
- );
12958
- if (envPresent) {
12959
- console.log(
12960
- "A placeholder value is present in the sandbox environment. This value is not the real credential \u2014 it is a stand-in that gets replaced at the network boundary when requests are sent to registered base URLs."
12961
- );
12962
- } else {
12963
- console.log(
12964
- "No value found for this environment name. Note: credential replacement at the network boundary is independent of this name \u2014 the proxy injects auth headers based on the destination URL."
12965
- );
12952
+ function resolveTriggerContext() {
12953
+ const workflowId = process.env.ZERO_WORKFLOW_ID;
12954
+ const triggerId = process.env.ZERO_WORKFLOW_TRIGGER_ID;
12955
+ return workflowId && triggerId ? { workflowId, triggerId } : void 0;
12956
+ }
12957
+ function workflowPermissionUrl(ctx) {
12958
+ if (!ctx.agentId || !ctx.triggerContext) {
12959
+ return null;
12966
12960
  }
12967
- console.log("");
12968
- return envPresent;
12961
+ const params = new URLSearchParams({
12962
+ ref: ctx.connectorType,
12963
+ triggerId: ctx.triggerContext.triggerId
12964
+ });
12965
+ return `${ctx.platformOrigin}/agents/${ctx.agentId}/workflows/${ctx.triggerContext.workflowId}/permissions?${params.toString()}`;
12969
12966
  }
12970
- async function checkConnectorStatus(ctx) {
12971
- console.log("## Step 2: Connector configuration");
12972
- console.log("");
12973
- console.log(
12974
- "A Connector holds the real credentials (OAuth tokens or API keys) for an external service. These credentials are never injected into the sandbox. Instead, when the sandbox sends an HTTP request to a base URL registered by the Connector, the network boundary intercepts the request and replaces the auth headers with real credentials. For this to work, three conditions must be met:"
12975
- );
12976
- console.log("");
12977
- const [connector, enabledTypes] = await Promise.all([
12978
- getZeroConnector(ctx.connectorType),
12979
- ctx.agentId ? getZeroAgentUserConnectors(ctx.agentId) : Promise.resolve(null)
12980
- ]);
12981
- const isConnected = connector !== null;
12982
- const isExpired = connector?.connectionStatus === "reconnect-required";
12983
- const hasPermission = enabledTypes !== null && enabledTypes.includes(ctx.connectorType);
12967
+ function printConnectorConnectionStatus(ctx, isConnected, isExpired, hasPermission) {
12984
12968
  console.log(
12985
12969
  `### 2a: Connector status (user must configure via OAuth login or API key)`
12986
12970
  );
@@ -12991,7 +12975,10 @@ async function checkConnectorStatus(ctx) {
12991
12975
  );
12992
12976
  } else if (!isConnected) {
12993
12977
  console.log(`The ${ctx.label} connector is not connected.`);
12994
- if (ctx.agentId && hasPermission) {
12978
+ if (ctx.triggerContext) {
12979
+ const connectUrl = `${ctx.platformOrigin}/connectors/${ctx.connectorType}/connect`;
12980
+ console.log(`Connect it at: [Connect ${ctx.label}](${connectUrl})`);
12981
+ } else if (ctx.agentId && hasPermission) {
12995
12982
  const connectUrl = `${ctx.platformOrigin}/connectors/${ctx.connectorType}/connect?agentId=${ctx.agentId}`;
12996
12983
  console.log(`Connect it at: [Connect ${ctx.label}](${connectUrl})`);
12997
12984
  } else if (!ctx.agentId) {
@@ -13008,15 +12995,28 @@ async function checkConnectorStatus(ctx) {
13008
12995
  console.log(`The ${ctx.label} connector is connected and active.`);
13009
12996
  }
13010
12997
  console.log("");
12998
+ }
12999
+ function printWorkflowAuthorizationStatus(ctx, isConnected, hasPermission) {
13000
+ const url = workflowPermissionUrl(ctx);
13001
+ if (hasPermission) {
13002
+ console.log(
13003
+ isConnected ? `The ${ctx.label} connector is authorized for this workflow (${ctx.triggerContext.workflowId}).` : `The ${ctx.label} connector is authorized for this workflow (${ctx.triggerContext.workflowId}), but it is not connected.`
13004
+ );
13005
+ return;
13006
+ }
13011
13007
  console.log(
13012
- `### 2b: Agent authorization (user must authorize agent to use this connector)`
13008
+ isConnected ? `The ${ctx.label} connector is not authorized for this workflow (${ctx.triggerContext.workflowId}).` : `The ${ctx.label} connector needs to be connected and authorized for this workflow (${ctx.triggerContext.workflowId}).`
13013
13009
  );
13014
- console.log("");
13015
- if (!ctx.connectorAvailable) {
13010
+ if (url) {
13011
+ console.log(`Authorize it at: [Authorize ${ctx.label}](${url})`);
13012
+ } else {
13016
13013
  console.log(
13017
- `Skipped \u2014 the ${ctx.label} connector is not available for this account.`
13014
+ "ZERO_AGENT_ID is not set \u2014 cannot build a workflow authorization link."
13018
13015
  );
13019
- } else if (!ctx.agentId) {
13016
+ }
13017
+ }
13018
+ function printAgentAuthorizationStatus(ctx, isConnected, isExpired, hasPermission) {
13019
+ if (!ctx.agentId) {
13020
13020
  console.log("ZERO_AGENT_ID is not set \u2014 cannot check agent authorization.");
13021
13021
  } else if (isExpired) {
13022
13022
  console.log(
@@ -13033,7 +13033,65 @@ async function checkConnectorStatus(ctx) {
13033
13033
  );
13034
13034
  console.log(`Authorize it at: [Authorize ${ctx.label}](${url})`);
13035
13035
  }
13036
+ }
13037
+ function printConnectorAuthorizationStatus(ctx, isConnected, isExpired, hasPermission) {
13038
+ console.log(
13039
+ ctx.triggerContext ? `### 2b: Workflow authorization (user must authorize workflow to use this connector)` : `### 2b: Agent authorization (user must authorize agent to use this connector)`
13040
+ );
13036
13041
  console.log("");
13042
+ if (!ctx.connectorAvailable) {
13043
+ console.log(
13044
+ `Skipped \u2014 the ${ctx.label} connector is not available for this account.`
13045
+ );
13046
+ } else if (ctx.triggerContext) {
13047
+ printWorkflowAuthorizationStatus(
13048
+ { ...ctx, triggerContext: ctx.triggerContext },
13049
+ isConnected,
13050
+ hasPermission
13051
+ );
13052
+ } else {
13053
+ printAgentAuthorizationStatus(ctx, isConnected, isExpired, hasPermission);
13054
+ }
13055
+ console.log(
13056
+ ctx.triggerContext ? `This is a workflow-triggered run, so ${ctx.label} access is scoped by the workflow's authorization settings, not the agent's connector authorization.` : `This is an interactive/agent-scoped run, so ${ctx.label} access is scoped by the agent's connector authorization.`
13057
+ );
13058
+ console.log("");
13059
+ }
13060
+ function checkEnvName(ctx) {
13061
+ console.log("## Step 1: Sandbox environment name");
13062
+ console.log("");
13063
+ const envPresent = Boolean(process.env[ctx.envName]);
13064
+ console.log(
13065
+ `Checking process.env.${ctx.envName}: ${envPresent ? "present" : "not present"}`
13066
+ );
13067
+ if (envPresent) {
13068
+ console.log(
13069
+ "A placeholder value is present in the sandbox environment. This value is not the real credential \u2014 it is a stand-in that gets replaced at the network boundary when requests are sent to registered base URLs."
13070
+ );
13071
+ } else {
13072
+ console.log(
13073
+ "No value found for this environment name. Note: credential replacement at the network boundary is independent of this name \u2014 the proxy injects auth headers based on the destination URL."
13074
+ );
13075
+ }
13076
+ console.log("");
13077
+ return envPresent;
13078
+ }
13079
+ async function checkConnectorStatus(ctx) {
13080
+ console.log("## Step 2: Connector configuration");
13081
+ console.log("");
13082
+ console.log(
13083
+ "A Connector holds the real credentials (OAuth tokens or API keys) for an external service. These credentials are never injected into the sandbox. Instead, when the sandbox sends an HTTP request to a base URL registered by the Connector, the network boundary intercepts the request and replaces the auth headers with real credentials. For this to work, three conditions must be met:"
13084
+ );
13085
+ console.log("");
13086
+ const [connector, enabledTypes] = await Promise.all([
13087
+ getZeroConnector(ctx.connectorType),
13088
+ ctx.triggerContext ? getZeroWorkflowUserConnectors(ctx.triggerContext.workflowId) : ctx.agentId ? getZeroAgentUserConnectors(ctx.agentId) : Promise.resolve(null)
13089
+ ]);
13090
+ const isConnected = connector !== null;
13091
+ const isExpired = connector?.connectionStatus === "reconnect-required";
13092
+ const hasPermission = enabledTypes !== null && enabledTypes.includes(ctx.connectorType);
13093
+ printConnectorConnectionStatus(ctx, isConnected, isExpired, hasPermission);
13094
+ printConnectorAuthorizationStatus(ctx, isConnected, isExpired, hasPermission);
13037
13095
  return { isConnected, isExpired, hasPermission };
13038
13096
  }
13039
13097
  async function checkConnectorDomains(ctx, preloadedRunContext) {
@@ -13047,11 +13105,11 @@ async function checkConnectorDomains(ctx, preloadedRunContext) {
13047
13105
  "Cannot determine run ID from ZERO_TOKEN \u2014 skipping base URL check."
13048
13106
  );
13049
13107
  console.log("");
13050
- return null;
13108
+ return { networkPolicies: null, configuredForRun: null };
13051
13109
  }
13052
- await printConnectorDomains(ctx, runContext);
13110
+ const configuredForRun = await printConnectorDomains(ctx, runContext);
13053
13111
  console.log("");
13054
- return runContext.networkPolicies;
13112
+ return { networkPolicies: runContext.networkPolicies, configuredForRun };
13055
13113
  }
13056
13114
  async function printConnectorDomains(ctx, runContext) {
13057
13115
  const matchingEntry = runContext.firewalls.find((fw) => {
@@ -13064,7 +13122,7 @@ async function printConnectorDomains(ctx, runContext) {
13064
13122
  console.log(
13065
13123
  "This means no base URLs are registered for credential replacement for this connector."
13066
13124
  );
13067
- return;
13125
+ return false;
13068
13126
  }
13069
13127
  const routingConfig = await runContextFirewallRoutingConfig(matchingEntry);
13070
13128
  if (!routingConfig) {
@@ -13074,7 +13132,7 @@ async function printConnectorDomains(ctx, runContext) {
13074
13132
  console.log(
13075
13133
  "This means no base URLs are registered for credential replacement for this connector."
13076
13134
  );
13077
- return;
13135
+ return false;
13078
13136
  }
13079
13137
  console.log(
13080
13138
  `The ${ctx.label} connector is configured for this run with the following base URLs:`
@@ -13090,8 +13148,9 @@ async function printConnectorDomains(ctx, runContext) {
13090
13148
  if (secretNames.length > 0) {
13091
13149
  console.log(`Credentials resolved from: ${secretNames.join(", ")}`);
13092
13150
  }
13151
+ return true;
13093
13152
  }
13094
- function checkPermissionPolicy(connectorType, label, permissionName, networkPolicies) {
13153
+ function checkPermissionPolicy(connectorType, label, permissionName, networkPolicies, configuredForRun) {
13095
13154
  console.log("## Step 3: Permission policy check");
13096
13155
  console.log("");
13097
13156
  console.log(
@@ -13110,6 +13169,16 @@ function checkPermissionPolicy(connectorType, label, permissionName, networkPoli
13110
13169
  }
13111
13170
  const connectorPolicies = networkPolicies[connectorType];
13112
13171
  if (!connectorPolicies) {
13172
+ if (configuredForRun === false) {
13173
+ console.log(
13174
+ `No policy entry found because the ${label} connector is not configured for this run.`
13175
+ );
13176
+ console.log(
13177
+ "Requests for this connector cannot receive credentials in the current run."
13178
+ );
13179
+ console.log("");
13180
+ return;
13181
+ }
13113
13182
  console.log(
13114
13183
  `No policy entry found for the ${label} connector in this run's network policies.`
13115
13184
  );
@@ -13144,7 +13213,7 @@ function checkPermissionPolicy(connectorType, label, permissionName, networkPoli
13144
13213
  function unknownPermissionChangeCommand(connectorRef) {
13145
13214
  return `zero doctor permission-change ${connectorRef} --permission ${UNKNOWN_PERMISSION_GRANT} --enable --duration 1h`;
13146
13215
  }
13147
- async function resolvePermissionFromUrl(connectorType, label, method, relativePath, matchedBase, routingConfig, networkPolicies) {
13216
+ async function resolvePermissionFromUrl(connectorType, label, method, relativePath, matchedBase, routingConfig, networkPolicies, configuredForRun) {
13148
13217
  console.log("## Step 3: Permission policy check (auto-detected from URL)");
13149
13218
  console.log("");
13150
13219
  console.log(
@@ -13186,6 +13255,16 @@ async function resolvePermissionFromUrl(connectorType, label, method, relativePa
13186
13255
  }
13187
13256
  const connectorPolicies = networkPolicies[connectorType];
13188
13257
  if (!connectorPolicies) {
13258
+ if (configuredForRun === false) {
13259
+ console.log(
13260
+ `No policy entry found because the ${label} connector is not configured for this run.`
13261
+ );
13262
+ console.log(
13263
+ "Requests for this connector cannot receive credentials in the current run."
13264
+ );
13265
+ console.log("");
13266
+ return;
13267
+ }
13189
13268
  console.log(
13190
13269
  `No policy entry found for the ${label} connector. All requests are fully permissive (allowed).`
13191
13270
  );
@@ -13322,12 +13401,21 @@ How connectors work:
13322
13401
  label,
13323
13402
  connectorAvailable,
13324
13403
  platformOrigin: platformUrl.origin,
13325
- agentId: process.env.ZERO_AGENT_ID || void 0
13404
+ agentId: process.env.ZERO_AGENT_ID || void 0,
13405
+ triggerContext: resolveTriggerContext()
13326
13406
  };
13327
13407
  checkEnvName(ctx);
13328
13408
  const { isConnected, isExpired, hasPermission } = await checkConnectorStatus(ctx);
13329
- const networkPolicies = await checkConnectorDomains(ctx, runContext);
13330
- if (isConnected && !isExpired && hasPermission) {
13409
+ const { networkPolicies, configuredForRun } = await checkConnectorDomains(
13410
+ ctx,
13411
+ runContext
13412
+ );
13413
+ if (configuredForRun === false) {
13414
+ const scope = ctx.triggerContext ? "workflow" : "agent";
13415
+ console.log(
13416
+ `Steps 1-2 summary: The ${label} connector is not configured for this run. Check the ${scope} authorization settings, then start a new run after updating them.`
13417
+ );
13418
+ } else if (isConnected && !isExpired && hasPermission) {
13331
13419
  console.log(
13332
13420
  `Steps 1-2 summary: The ${label} connector is connected, active, and authorized. Outbound requests to the registered base URLs will have credentials injected at the network boundary.`
13333
13421
  );
@@ -13341,14 +13429,16 @@ How connectors work:
13341
13429
  urlLookup.relativePath,
13342
13430
  urlLookup.matchedBase,
13343
13431
  urlLookup.routingConfig,
13344
- networkPolicies
13432
+ networkPolicies,
13433
+ configuredForRun
13345
13434
  );
13346
13435
  } else if (opts.checkPermission) {
13347
13436
  checkPermissionPolicy(
13348
13437
  connectorType,
13349
13438
  label,
13350
13439
  opts.checkPermission,
13351
- networkPolicies
13440
+ networkPolicies,
13441
+ configuredForRun
13352
13442
  );
13353
13443
  }
13354
13444
  const args = [];
@@ -13561,7 +13651,7 @@ async function printComputerUsePermissionChangeMessage(action) {
13561
13651
  printComputerUsePermissionGuidance();
13562
13652
  }
13563
13653
  }
13564
- function resolveTriggerContext() {
13654
+ function resolveTriggerContext2() {
13565
13655
  const triggerId = process.env.ZERO_WORKFLOW_TRIGGER_ID;
13566
13656
  const workflowId = process.env.ZERO_WORKFLOW_ID;
13567
13657
  return triggerId && workflowId ? { workflowId, triggerId } : void 0;
@@ -13570,10 +13660,10 @@ async function outputPermissionChangeMessage(connectorRef, label, permission, ac
13570
13660
  const platformOrigin = await getPlatformOrigin();
13571
13661
  if (triggerContext && agentId) {
13572
13662
  const workflowUrlParams = new URLSearchParams({
13573
- tab: "authorization",
13574
13663
  ref: connectorRef,
13575
13664
  permission,
13576
- action: action === "enable" ? "allow" : "deny"
13665
+ action: action === "enable" ? "allow" : "deny",
13666
+ triggerId: triggerContext.triggerId
13577
13667
  });
13578
13668
  if (action === "enable") {
13579
13669
  workflowUrlParams.set(
@@ -13581,7 +13671,7 @@ async function outputPermissionChangeMessage(connectorRef, label, permission, ac
13581
13671
  duration ?? DEFAULT_PERMISSION_GRANT_DURATION
13582
13672
  );
13583
13673
  }
13584
- const workflowUrl = `${platformOrigin}/agents/${agentId}/workflows/${triggerContext.workflowId}?${workflowUrlParams.toString()}`;
13674
+ const workflowUrl = `${platformOrigin}/agents/${agentId}/workflows/${triggerContext.workflowId}/permissions?${workflowUrlParams.toString()}`;
13585
13675
  printSensitivePermissionGuidance(connectorRef, permission, action);
13586
13676
  printPermissionActionMessage({
13587
13677
  action,
@@ -13691,7 +13781,7 @@ Notes:
13691
13781
  action,
13692
13782
  opts.duration,
13693
13783
  opts.agent ?? process.env.ZERO_AGENT_ID,
13694
- resolveTriggerContext()
13784
+ resolveTriggerContext2()
13695
13785
  );
13696
13786
  }
13697
13787
  )
@@ -22393,7 +22483,7 @@ function registerZeroCommands(prog, commands) {
22393
22483
  var program = new Command();
22394
22484
  program.name("zero").description(
22395
22485
  "Zero CLI \u2014 interact with the zero platform from inside the sandbox"
22396
- ).version("9.212.4").addHelpText("after", () => {
22486
+ ).version("9.213.1").addHelpText("after", () => {
22397
22487
  return buildZeroHelpText();
22398
22488
  });
22399
22489
  if (process.argv[1]?.endsWith("zero.js") || process.argv[1]?.endsWith("zero.ts") || process.argv[1]?.endsWith("zero")) {