@vm0/cli 9.30.1 → 9.32.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 +129 -11
  2. package/package.json +1 -1
package/index.js CHANGED
@@ -45,7 +45,7 @@ if (DSN) {
45
45
  Sentry.init({
46
46
  dsn: DSN,
47
47
  environment: process.env.SENTRY_ENVIRONMENT ?? "production",
48
- release: "9.30.1",
48
+ release: "9.32.0",
49
49
  sendDefaultPii: false,
50
50
  tracesSampleRate: 0,
51
51
  shutdownTimeout: 500,
@@ -64,7 +64,7 @@ if (DSN) {
64
64
  }
65
65
  });
66
66
  Sentry.setContext("cli", {
67
- version: "9.30.1",
67
+ version: "9.32.0",
68
68
  command: process.argv.slice(2).join(" ")
69
69
  });
70
70
  Sentry.setContext("runtime", {
@@ -605,7 +605,7 @@ async function waitForSilentUpgrade(timeout = TIMEOUT_MS) {
605
605
  // src/commands/info/index.ts
606
606
  var CONFIG_PATH = join2(homedir2(), ".vm0", "config.json");
607
607
  var infoCommand = new Command6().name("info").description("Display environment and debug information").action(async () => {
608
- console.log(chalk7.bold(`VM0 CLI v${"9.30.1"}`));
608
+ console.log(chalk7.bold(`VM0 CLI v${"9.32.0"}`));
609
609
  console.log();
610
610
  const config = await loadConfig();
611
611
  const hasEnvToken = !!process.env.VM0_TOKEN;
@@ -1097,6 +1097,8 @@ var unifiedRunRequestSchema = z5.object({
1097
1097
  debugNoMockClaude: z5.boolean().optional(),
1098
1098
  // Model provider for automatic credential injection
1099
1099
  modelProvider: z5.string().optional(),
1100
+ // Environment validation flag - when true, validates secrets/vars before running
1101
+ checkEnv: z5.boolean().optional(),
1100
1102
  // Required
1101
1103
  prompt: z5.string().min(1, "Missing prompt")
1102
1104
  });
@@ -3555,9 +3557,41 @@ var CONNECTOR_TYPES = {
3555
3557
  tokenUrl: "https://github.com/login/oauth/access_token",
3556
3558
  scopes: ["repo"]
3557
3559
  }
3560
+ },
3561
+ notion: {
3562
+ label: "Notion",
3563
+ helpText: "Connect your Notion workspace to access pages and databases",
3564
+ authMethods: {
3565
+ oauth: {
3566
+ label: "OAuth (Recommended)",
3567
+ helpText: "Sign in with Notion to grant access.",
3568
+ secrets: {
3569
+ NOTION_ACCESS_TOKEN: {
3570
+ label: "Access Token",
3571
+ required: true
3572
+ },
3573
+ NOTION_REFRESH_TOKEN: {
3574
+ label: "Refresh Token",
3575
+ required: true
3576
+ }
3577
+ }
3578
+ }
3579
+ },
3580
+ defaultAuthMethod: "oauth",
3581
+ environmentMapping: {
3582
+ NOTION_TOKEN: "$secrets.NOTION_ACCESS_TOKEN"
3583
+ },
3584
+ oauth: {
3585
+ authorizationUrl: "https://api.notion.com/v1/oauth/authorize",
3586
+ tokenUrl: "https://api.notion.com/v1/oauth/token",
3587
+ scopes: []
3588
+ }
3558
3589
  }
3559
3590
  };
3560
- var connectorTypeSchema = z23.enum(["github"]);
3591
+ var connectorTypeSchema = z23.enum(["github", "notion"]);
3592
+ function getConnectorEnvironmentMapping(type2) {
3593
+ return CONNECTOR_TYPES[type2].environmentMapping;
3594
+ }
3561
3595
  function getConnectorDerivedNames(secretName) {
3562
3596
  const allTypes = Object.keys(CONNECTOR_TYPES);
3563
3597
  for (const type2 of allTypes) {
@@ -3581,6 +3615,20 @@ function getConnectorDerivedNames(secretName) {
3581
3615
  }
3582
3616
  return null;
3583
3617
  }
3618
+ function getConnectorProvidedSecretNames(connectedTypes) {
3619
+ const provided = /* @__PURE__ */ new Set();
3620
+ for (const rawType of connectedTypes) {
3621
+ const parsed = connectorTypeSchema.safeParse(rawType);
3622
+ if (!parsed.success) {
3623
+ continue;
3624
+ }
3625
+ const mapping = getConnectorEnvironmentMapping(parsed.data);
3626
+ for (const envVar of Object.keys(mapping)) {
3627
+ provided.add(envVar);
3628
+ }
3629
+ }
3630
+ return provided;
3631
+ }
3584
3632
  var connectorResponseSchema = z23.object({
3585
3633
  id: z23.string().uuid(),
3586
3634
  type: connectorTypeSchema,
@@ -5724,6 +5772,11 @@ function getSecretsFromComposeContent(content) {
5724
5772
  const grouped = groupVariablesBySource(refs);
5725
5773
  return new Set(grouped.secrets.map((r) => r.name));
5726
5774
  }
5775
+ function getVarsFromComposeContent(content) {
5776
+ const refs = extractVariableReferences(content);
5777
+ const grouped = groupVariablesBySource(refs);
5778
+ return new Set(grouped.vars.map((r) => r.name));
5779
+ }
5727
5780
  async function loadAndValidateConfig(configFile, jsonMode) {
5728
5781
  if (!existsSync5(configFile)) {
5729
5782
  if (jsonMode) {
@@ -5946,6 +5999,62 @@ function mergeSkillVariables(agent, variables) {
5946
5999
  agent.environment = environment;
5947
6000
  }
5948
6001
  }
6002
+ function getPlatformUrl(apiUrl) {
6003
+ const url = new URL(apiUrl);
6004
+ url.hostname = url.hostname.replace("www", "platform");
6005
+ return url.origin;
6006
+ }
6007
+ async function checkAndPromptMissingItems(config, options) {
6008
+ const requiredSecrets = getSecretsFromComposeContent(config);
6009
+ const requiredVars = getVarsFromComposeContent(config);
6010
+ if (requiredSecrets.size === 0 && requiredVars.size === 0) {
6011
+ return { missingSecrets: [], missingVars: [] };
6012
+ }
6013
+ const [secretsResponse, variablesResponse, connectorsResponse] = await Promise.all([
6014
+ requiredSecrets.size > 0 ? listSecrets() : { secrets: [] },
6015
+ requiredVars.size > 0 ? listVariables() : { variables: [] },
6016
+ listConnectors()
6017
+ ]);
6018
+ const existingSecretNames = new Set(
6019
+ secretsResponse.secrets.map((s) => s.name)
6020
+ );
6021
+ const existingVarNames = new Set(
6022
+ variablesResponse.variables.map((v) => v.name)
6023
+ );
6024
+ const connectorProvided = getConnectorProvidedSecretNames(
6025
+ connectorsResponse.connectors.map((c24) => c24.type)
6026
+ );
6027
+ const missingSecrets = [...requiredSecrets].filter(
6028
+ (name) => !existingSecretNames.has(name) && !connectorProvided.has(name)
6029
+ );
6030
+ const missingVars = [...requiredVars].filter(
6031
+ (name) => !existingVarNames.has(name)
6032
+ );
6033
+ if (missingSecrets.length === 0 && missingVars.length === 0) {
6034
+ return { missingSecrets: [], missingVars: [] };
6035
+ }
6036
+ const apiUrl = await getApiUrl();
6037
+ const platformUrl = getPlatformUrl(apiUrl);
6038
+ const params = new URLSearchParams();
6039
+ if (missingSecrets.length > 0) {
6040
+ params.set("secrets", missingSecrets.join(","));
6041
+ }
6042
+ if (missingVars.length > 0) {
6043
+ params.set("vars", missingVars.join(","));
6044
+ }
6045
+ const setupUrl = `${platformUrl}/environment-variables-setup?${params.toString()}`;
6046
+ if (!options.json) {
6047
+ console.log();
6048
+ console.log(
6049
+ chalk8.yellow(
6050
+ "\u26A0 Missing secrets/variables detected. Set them up before running your agent:"
6051
+ )
6052
+ );
6053
+ console.log(chalk8.cyan(` ${setupUrl}`));
6054
+ console.log();
6055
+ }
6056
+ return { missingSecrets, missingVars, setupUrl };
6057
+ }
5949
6058
  async function finalizeCompose(config, agent, variables, options) {
5950
6059
  const confirmed = await displayAndConfirmVariables(variables, options);
5951
6060
  if (!confirmed) {
@@ -5966,6 +6075,12 @@ async function finalizeCompose(config, agent, variables, options) {
5966
6075
  action: response.action,
5967
6076
  displayName
5968
6077
  };
6078
+ const missingItems = await checkAndPromptMissingItems(config, options);
6079
+ if (missingItems.missingSecrets.length > 0 || missingItems.missingVars.length > 0) {
6080
+ result.missingSecrets = missingItems.missingSecrets;
6081
+ result.missingVars = missingItems.missingVars;
6082
+ result.setupUrl = missingItems.setupUrl;
6083
+ }
5969
6084
  if (!options.json) {
5970
6085
  if (response.action === "created") {
5971
6086
  console.log(chalk8.green(`\u2713 Compose created: ${displayName}`));
@@ -6118,7 +6233,7 @@ var composeCommand = new Command7().name("compose").description("Create or updat
6118
6233
  options.autoUpdate = false;
6119
6234
  }
6120
6235
  if (options.autoUpdate !== false) {
6121
- await startSilentUpgrade("9.30.1");
6236
+ await startSilentUpgrade("9.32.0");
6122
6237
  }
6123
6238
  try {
6124
6239
  let result;
@@ -8311,11 +8426,11 @@ var mainRunCommand = new Command8().name("run").description("Run an agent").argu
8311
8426
  ).option("--verbose", "Show full tool inputs and outputs").option(
8312
8427
  "--experimental-shared-agent",
8313
8428
  "Allow running agents shared by other users (required when running scope/agent format)"
8314
- ).addOption(new Option2("--debug-no-mock-claude").hideHelp()).addOption(new Option2("--no-auto-update").hideHelp()).action(
8429
+ ).option("--check-env", "Validate secrets and vars before running").addOption(new Option2("--debug-no-mock-claude").hideHelp()).addOption(new Option2("--no-auto-update").hideHelp()).action(
8315
8430
  async (identifier, prompt, options) => {
8316
8431
  try {
8317
8432
  if (options.autoUpdate !== false) {
8318
- await startSilentUpgrade("9.30.1");
8433
+ await startSilentUpgrade("9.32.0");
8319
8434
  }
8320
8435
  const { scope, name, version } = parseIdentifier(identifier);
8321
8436
  if (scope && !options.experimentalSharedAgent) {
@@ -8392,6 +8507,7 @@ var mainRunCommand = new Command8().name("run").description("Run an agent").argu
8392
8507
  volumeVersions: Object.keys(options.volumeVersion).length > 0 ? options.volumeVersion : void 0,
8393
8508
  conversationId: options.conversation,
8394
8509
  modelProvider: options.modelProvider,
8510
+ checkEnv: options.checkEnv || void 0,
8395
8511
  debugNoMockClaude: options.debugNoMockClaude || void 0
8396
8512
  });
8397
8513
  if (response.status === "failed") {
@@ -8448,7 +8564,7 @@ var resumeCommand = new Command9().name("resume").description("Resume an agent r
8448
8564
  ).option(
8449
8565
  "--model-provider <type>",
8450
8566
  "Override model provider (e.g., anthropic-api-key)"
8451
- ).option("--verbose", "Show full tool inputs and outputs").addOption(new Option3("--debug-no-mock-claude").hideHelp()).action(
8567
+ ).option("--verbose", "Show full tool inputs and outputs").option("--check-env", "Validate secrets and vars before running").addOption(new Option3("--debug-no-mock-claude").hideHelp()).action(
8452
8568
  async (checkpointId, prompt, options, command) => {
8453
8569
  const allOpts = command.optsWithGlobals();
8454
8570
  const vars = { ...allOpts.vars, ...options.vars };
@@ -8472,6 +8588,7 @@ var resumeCommand = new Command9().name("resume").description("Resume an agent r
8472
8588
  secrets: loadedSecrets,
8473
8589
  volumeVersions: Object.keys(allOpts.volumeVersion).length > 0 ? allOpts.volumeVersion : void 0,
8474
8590
  modelProvider: options.modelProvider || allOpts.modelProvider,
8591
+ checkEnv: options.checkEnv || allOpts.checkEnv || void 0,
8475
8592
  debugNoMockClaude: options.debugNoMockClaude || allOpts.debugNoMockClaude || void 0
8476
8593
  });
8477
8594
  if (response.status === "failed") {
@@ -8527,7 +8644,7 @@ var continueCommand = new Command10().name("continue").description(
8527
8644
  ).option(
8528
8645
  "--model-provider <type>",
8529
8646
  "Override model provider (e.g., anthropic-api-key)"
8530
- ).option("--verbose", "Show full tool inputs and outputs").addOption(new Option4("--debug-no-mock-claude").hideHelp()).action(
8647
+ ).option("--verbose", "Show full tool inputs and outputs").option("--check-env", "Validate secrets and vars before running").addOption(new Option4("--debug-no-mock-claude").hideHelp()).action(
8531
8648
  async (agentSessionId, prompt, options, command) => {
8532
8649
  const allOpts = command.optsWithGlobals();
8533
8650
  const vars = { ...allOpts.vars, ...options.vars };
@@ -8550,6 +8667,7 @@ var continueCommand = new Command10().name("continue").description(
8550
8667
  vars: Object.keys(vars).length > 0 ? vars : void 0,
8551
8668
  secrets: loadedSecrets,
8552
8669
  modelProvider: options.modelProvider || allOpts.modelProvider,
8670
+ checkEnv: options.checkEnv || allOpts.checkEnv || void 0,
8553
8671
  debugNoMockClaude: options.debugNoMockClaude || allOpts.debugNoMockClaude || void 0
8554
8672
  });
8555
8673
  if (response.status === "failed") {
@@ -9888,7 +10006,7 @@ var cookAction = new Command27().name("cook").description("Quick start: prepare,
9888
10006
  ).option("-y, --yes", "Skip confirmation prompts").option("-v, --verbose", "Show full tool inputs and outputs").addOption(new Option5("--debug-no-mock-claude").hideHelp()).addOption(new Option5("--no-auto-update").hideHelp()).action(
9889
10007
  async (prompt, options) => {
9890
10008
  if (options.autoUpdate !== false) {
9891
- const shouldExit = await checkAndUpgrade("9.30.1", prompt);
10009
+ const shouldExit = await checkAndUpgrade("9.32.0", prompt);
9892
10010
  if (shouldExit) {
9893
10011
  process.exit(0);
9894
10012
  }
@@ -14304,7 +14422,7 @@ var devToolCommand = new Command75().name("dev-tool").description("Developer too
14304
14422
 
14305
14423
  // src/index.ts
14306
14424
  var program = new Command76();
14307
- program.name("vm0").description("VM0 CLI - Build and run agents with natural language").version("9.30.1");
14425
+ program.name("vm0").description("VM0 CLI - Build and run agents with natural language").version("9.32.0");
14308
14426
  program.addCommand(authCommand);
14309
14427
  program.addCommand(infoCommand);
14310
14428
  program.addCommand(composeCommand);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@vm0/cli",
3
- "version": "9.30.1",
3
+ "version": "9.32.0",
4
4
  "description": "CLI application",
5
5
  "repository": {
6
6
  "type": "git",