@vm0/cli 9.10.0 → 9.11.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 +225 -103
  2. package/package.json +1 -1
package/index.js CHANGED
@@ -1904,19 +1904,55 @@ var MODEL_PROVIDER_TYPES = {
1904
1904
  label: "Anthropic API Key",
1905
1905
  credentialLabel: "API key",
1906
1906
  helpText: "Get your API key at: https://console.anthropic.com/settings/keys"
1907
+ },
1908
+ "moonshot-api-key": {
1909
+ framework: "claude-code",
1910
+ credentialName: "MOONSHOT_API_KEY",
1911
+ label: "Moonshot API Key (Kimi)",
1912
+ credentialLabel: "API key",
1913
+ helpText: "Get your API key at: https://platform.moonshot.ai/console/api-keys",
1914
+ environmentMapping: {
1915
+ ANTHROPIC_AUTH_TOKEN: "$credential",
1916
+ ANTHROPIC_BASE_URL: "https://api.moonshot.ai/anthropic",
1917
+ ANTHROPIC_MODEL: "$model",
1918
+ ANTHROPIC_DEFAULT_OPUS_MODEL: "$model",
1919
+ ANTHROPIC_DEFAULT_SONNET_MODEL: "$model",
1920
+ ANTHROPIC_DEFAULT_HAIKU_MODEL: "$model",
1921
+ CLAUDE_CODE_SUBAGENT_MODEL: "$model"
1922
+ },
1923
+ models: [
1924
+ "kimi-k2.5",
1925
+ "kimi-k2-thinking-turbo",
1926
+ "kimi-k2-thinking"
1927
+ ],
1928
+ defaultModel: "kimi-k2.5"
1907
1929
  }
1908
1930
  };
1909
1931
  var modelProviderTypeSchema = z14.enum([
1910
1932
  "claude-code-oauth-token",
1911
- "anthropic-api-key"
1933
+ "anthropic-api-key",
1934
+ "moonshot-api-key"
1912
1935
  ]);
1913
1936
  var modelProviderFrameworkSchema = z14.enum(["claude-code", "codex"]);
1937
+ function getModels(type) {
1938
+ const config = MODEL_PROVIDER_TYPES[type];
1939
+ return "models" in config ? config.models : void 0;
1940
+ }
1941
+ function getDefaultModel(type) {
1942
+ const config = MODEL_PROVIDER_TYPES[type];
1943
+ return "defaultModel" in config ? config.defaultModel : void 0;
1944
+ }
1945
+ function hasModelSelection(type) {
1946
+ const config = MODEL_PROVIDER_TYPES[type];
1947
+ return "models" in config && config.models.length > 0;
1948
+ }
1914
1949
  var modelProviderResponseSchema = z14.object({
1915
1950
  id: z14.string().uuid(),
1916
1951
  type: modelProviderTypeSchema,
1917
1952
  framework: modelProviderFrameworkSchema,
1918
1953
  credentialName: z14.string(),
1919
1954
  isDefault: z14.boolean(),
1955
+ selectedModel: z14.string().nullable(),
1920
1956
  createdAt: z14.string(),
1921
1957
  updatedAt: z14.string()
1922
1958
  });
@@ -1926,7 +1962,8 @@ var modelProviderListResponseSchema = z14.object({
1926
1962
  var upsertModelProviderRequestSchema = z14.object({
1927
1963
  type: modelProviderTypeSchema,
1928
1964
  credential: z14.string().min(1, "Credential is required"),
1929
- convert: z14.boolean().optional()
1965
+ convert: z14.boolean().optional(),
1966
+ selectedModel: z14.string().optional()
1930
1967
  });
1931
1968
  var upsertModelProviderResponseSchema = z14.object({
1932
1969
  provider: modelProviderResponseSchema,
@@ -8464,7 +8501,7 @@ var cookAction = new Command27().name("cook").description("Quick start: prepare,
8464
8501
  ).option("-y, --yes", "Skip confirmation prompts").option("-v, --verbose", "Show full tool inputs and outputs").addOption(new Option4("--debug-no-mock-claude").hideHelp()).addOption(new Option4("--no-auto-update").hideHelp()).action(
8465
8502
  async (prompt, options) => {
8466
8503
  if (!options.noAutoUpdate) {
8467
- const shouldExit = await checkAndUpgrade("9.10.0", prompt);
8504
+ const shouldExit = await checkAndUpgrade("9.11.0", prompt);
8468
8505
  if (shouldExit) {
8469
8506
  process.exit(0);
8470
8507
  }
@@ -10842,7 +10879,8 @@ var listCommand7 = new Command51().name("list").alias("ls").description("List al
10842
10879
  console.log(` ${chalk50.cyan(framework)}:`);
10843
10880
  for (const provider of providers) {
10844
10881
  const defaultTag = provider.isDefault ? chalk50.green(" (default)") : "";
10845
- console.log(` ${provider.type}${defaultTag}`);
10882
+ const modelTag = provider.selectedModel ? chalk50.dim(` [${provider.selectedModel}]`) : "";
10883
+ console.log(` ${provider.type}${defaultTag}${modelTag}`);
10846
10884
  console.log(
10847
10885
  chalk50.dim(
10848
10886
  ` Updated: ${new Date(provider.updatedAt).toLocaleString()}`
@@ -10878,122 +10916,184 @@ var providerChoices = Object.entries(MODEL_PROVIDER_TYPES).map(
10878
10916
  value: type
10879
10917
  })
10880
10918
  );
10919
+ function validateProviderType(typeStr) {
10920
+ if (!Object.keys(MODEL_PROVIDER_TYPES).includes(typeStr)) {
10921
+ console.error(chalk51.red(`\u2717 Invalid type "${typeStr}"`));
10922
+ console.log();
10923
+ console.log("Valid types:");
10924
+ for (const [t, config] of Object.entries(MODEL_PROVIDER_TYPES)) {
10925
+ console.log(` ${chalk51.cyan(t)} - ${config.label}`);
10926
+ }
10927
+ process.exit(1);
10928
+ }
10929
+ return typeStr;
10930
+ }
10931
+ function validateModel(type, modelStr) {
10932
+ const models = getModels(type);
10933
+ if (models && !models.includes(modelStr)) {
10934
+ console.error(chalk51.red(`\u2717 Invalid model "${modelStr}"`));
10935
+ console.log();
10936
+ console.log("Valid models:");
10937
+ for (const m of models) {
10938
+ console.log(` ${chalk51.cyan(m)}`);
10939
+ }
10940
+ process.exit(1);
10941
+ }
10942
+ return modelStr;
10943
+ }
10944
+ function handleNonInteractiveMode(options) {
10945
+ const type = validateProviderType(options.type);
10946
+ let selectedModel;
10947
+ if (options.model) {
10948
+ selectedModel = validateModel(type, options.model);
10949
+ } else if (hasModelSelection(type)) {
10950
+ selectedModel = getDefaultModel(type);
10951
+ }
10952
+ return { type, credential: options.credential, selectedModel };
10953
+ }
10954
+ async function promptForModelSelection(type) {
10955
+ if (!hasModelSelection(type)) {
10956
+ return void 0;
10957
+ }
10958
+ const models = getModels(type) ?? [];
10959
+ const defaultModel = getDefaultModel(type);
10960
+ const modelChoices = models.map((model) => ({
10961
+ title: model === defaultModel ? `${model} (Recommended)` : model,
10962
+ value: model
10963
+ }));
10964
+ const modelResponse = await prompts2(
10965
+ {
10966
+ type: "select",
10967
+ name: "model",
10968
+ message: "Select model:",
10969
+ choices: modelChoices
10970
+ },
10971
+ { onCancel: () => process.exit(0) }
10972
+ );
10973
+ return modelResponse.model;
10974
+ }
10975
+ async function handleInteractiveMode() {
10976
+ if (!isInteractive()) {
10977
+ console.error(chalk51.red("\u2717 Interactive mode requires a TTY"));
10978
+ console.log();
10979
+ console.log("Use non-interactive mode:");
10980
+ console.log(
10981
+ chalk51.cyan(
10982
+ ' vm0 model-provider setup --type <type> --credential "<value>"'
10983
+ )
10984
+ );
10985
+ process.exit(1);
10986
+ }
10987
+ const typeResponse = await prompts2(
10988
+ {
10989
+ type: "select",
10990
+ name: "type",
10991
+ message: "Select provider type:",
10992
+ choices: providerChoices
10993
+ },
10994
+ { onCancel: () => process.exit(0) }
10995
+ );
10996
+ const type = typeResponse.type;
10997
+ const checkResult = await checkModelProviderCredential(type);
10998
+ if (checkResult.exists && checkResult.currentType === "user") {
10999
+ const convertResponse = await prompts2(
11000
+ {
11001
+ type: "confirm",
11002
+ name: "convert",
11003
+ message: `Credential "${checkResult.credentialName}" already exists. Convert to model provider?`,
11004
+ initial: true
11005
+ },
11006
+ { onCancel: () => process.exit(0) }
11007
+ );
11008
+ if (convertResponse.convert) {
11009
+ const provider = await convertModelProviderCredential(type);
11010
+ const defaultNote = provider.isDefault ? ` (default for ${provider.framework})` : "";
11011
+ console.log(
11012
+ chalk51.green(
11013
+ `\u2713 Converted "${checkResult.credentialName}" to model provider${defaultNote}`
11014
+ )
11015
+ );
11016
+ return null;
11017
+ }
11018
+ console.log(chalk51.dim("Aborted"));
11019
+ process.exit(0);
11020
+ }
11021
+ const config = MODEL_PROVIDER_TYPES[type];
11022
+ console.log();
11023
+ console.log(chalk51.dim(config.helpText));
11024
+ console.log();
11025
+ const credentialResponse = await prompts2(
11026
+ {
11027
+ type: "password",
11028
+ name: "credential",
11029
+ message: `Enter your ${config.credentialLabel}:`,
11030
+ validate: (value) => value.length > 0 || `${config.credentialLabel} is required`
11031
+ },
11032
+ { onCancel: () => process.exit(0) }
11033
+ );
11034
+ const credential = credentialResponse.credential;
11035
+ const selectedModel = await promptForModelSelection(type);
11036
+ return { type, credential, selectedModel };
11037
+ }
11038
+ function handleSetupError2(error) {
11039
+ if (error instanceof Error) {
11040
+ if (error.message.includes("already exists")) {
11041
+ console.error(chalk51.red(`\u2717 ${error.message}`));
11042
+ console.log();
11043
+ console.log("To convert the existing credential, run:");
11044
+ console.log(chalk51.cyan(" vm0 model-provider setup --convert"));
11045
+ } else if (error.message.includes("Not authenticated")) {
11046
+ console.error(chalk51.red("\u2717 Not authenticated. Run: vm0 auth login"));
11047
+ } else {
11048
+ console.error(chalk51.red(`\u2717 ${error.message}`));
11049
+ }
11050
+ } else {
11051
+ console.error(chalk51.red("\u2717 An unexpected error occurred"));
11052
+ }
11053
+ process.exit(1);
11054
+ }
10881
11055
  var setupCommand2 = new Command52().name("setup").description("Configure a model provider").option("-t, --type <type>", "Provider type (for non-interactive mode)").option(
10882
11056
  "-c, --credential <credential>",
10883
11057
  "Credential value (for non-interactive mode)"
10884
- ).option("--convert", "Convert existing user credential to model provider").action(
11058
+ ).option("-m, --model <model>", "Model selection (for non-interactive mode)").option("--convert", "Convert existing user credential to model provider").action(
10885
11059
  async (options) => {
10886
11060
  try {
10887
- let type;
10888
- let credential;
11061
+ let input;
10889
11062
  const shouldConvert = options.convert ?? false;
10890
11063
  if (options.type && options.credential) {
10891
- if (!Object.keys(MODEL_PROVIDER_TYPES).includes(options.type)) {
10892
- console.error(chalk51.red(`\u2717 Invalid type "${options.type}"`));
10893
- console.log();
10894
- console.log("Valid types:");
10895
- for (const [t, config] of Object.entries(MODEL_PROVIDER_TYPES)) {
10896
- console.log(` ${chalk51.cyan(t)} - ${config.label}`);
10897
- }
10898
- process.exit(1);
10899
- }
10900
- type = options.type;
10901
- credential = options.credential;
11064
+ input = handleNonInteractiveMode({
11065
+ type: options.type,
11066
+ credential: options.credential,
11067
+ model: options.model
11068
+ });
10902
11069
  } else if (options.type || options.credential) {
10903
11070
  console.error(
10904
11071
  chalk51.red("\u2717 Both --type and --credential are required")
10905
11072
  );
10906
11073
  process.exit(1);
10907
11074
  } else {
10908
- if (!isInteractive()) {
10909
- console.error(chalk51.red("\u2717 Interactive mode requires a TTY"));
10910
- console.log();
10911
- console.log("Use non-interactive mode:");
10912
- console.log(
10913
- chalk51.cyan(
10914
- ' vm0 model-provider setup --type <type> --credential "<value>"'
10915
- )
10916
- );
10917
- process.exit(1);
10918
- }
10919
- const typeResponse = await prompts2(
10920
- {
10921
- type: "select",
10922
- name: "type",
10923
- message: "Select provider type:",
10924
- choices: providerChoices
10925
- },
10926
- { onCancel: () => process.exit(0) }
10927
- );
10928
- type = typeResponse.type;
10929
- const checkResult = await checkModelProviderCredential(type);
10930
- if (checkResult.exists && checkResult.currentType === "user") {
10931
- const convertResponse = await prompts2(
10932
- {
10933
- type: "confirm",
10934
- name: "convert",
10935
- message: `Credential "${checkResult.credentialName}" already exists. Convert to model provider?`,
10936
- initial: true
10937
- },
10938
- { onCancel: () => process.exit(0) }
10939
- );
10940
- if (convertResponse.convert) {
10941
- const provider2 = await convertModelProviderCredential(type);
10942
- const defaultNote2 = provider2.isDefault ? ` (default for ${provider2.framework})` : "";
10943
- console.log(
10944
- chalk51.green(
10945
- `\u2713 Converted "${checkResult.credentialName}" to model provider${defaultNote2}`
10946
- )
10947
- );
10948
- return;
10949
- } else {
10950
- console.log(chalk51.dim("Aborted"));
10951
- process.exit(0);
10952
- }
11075
+ const result = await handleInteractiveMode();
11076
+ if (result === null) {
11077
+ return;
10953
11078
  }
10954
- const config = MODEL_PROVIDER_TYPES[type];
10955
- console.log();
10956
- console.log(chalk51.dim(config.helpText));
10957
- console.log();
10958
- const credentialResponse = await prompts2(
10959
- {
10960
- type: "password",
10961
- name: "credential",
10962
- message: `Enter your ${config.credentialLabel}:`,
10963
- validate: (value) => value.length > 0 || `${config.credentialLabel} is required`
10964
- },
10965
- { onCancel: () => process.exit(0) }
10966
- );
10967
- credential = credentialResponse.credential;
11079
+ input = result;
10968
11080
  }
10969
11081
  const { provider, created } = await upsertModelProvider({
10970
- type,
10971
- credential,
10972
- convert: shouldConvert
11082
+ type: input.type,
11083
+ credential: input.credential,
11084
+ convert: shouldConvert,
11085
+ selectedModel: input.selectedModel
10973
11086
  });
10974
11087
  const action = created ? "created" : "updated";
10975
11088
  const defaultNote = provider.isDefault ? ` (default for ${provider.framework})` : "";
11089
+ const modelNote = provider.selectedModel ? ` with model: ${provider.selectedModel}` : "";
10976
11090
  console.log(
10977
- chalk51.green(`\u2713 Model provider "${type}" ${action}${defaultNote}`)
11091
+ chalk51.green(
11092
+ `\u2713 Model provider "${input.type}" ${action}${defaultNote}${modelNote}`
11093
+ )
10978
11094
  );
10979
11095
  } catch (error) {
10980
- if (error instanceof Error) {
10981
- if (error.message.includes("already exists")) {
10982
- console.error(chalk51.red(`\u2717 ${error.message}`));
10983
- console.log();
10984
- console.log("To convert the existing credential, run:");
10985
- console.log(chalk51.cyan(" vm0 model-provider setup --convert"));
10986
- } else if (error.message.includes("Not authenticated")) {
10987
- console.error(
10988
- chalk51.red("\u2717 Not authenticated. Run: vm0 auth login")
10989
- );
10990
- } else {
10991
- console.error(chalk51.red(`\u2717 ${error.message}`));
10992
- }
10993
- } else {
10994
- console.error(chalk51.red("\u2717 An unexpected error occurred"));
10995
- }
10996
- process.exit(1);
11096
+ handleSetupError2(error);
10997
11097
  }
10998
11098
  }
10999
11099
  );
@@ -11299,7 +11399,9 @@ function getProviderChoices() {
11299
11399
  type,
11300
11400
  label: MODEL_PROVIDER_TYPES[type].label,
11301
11401
  helpText: MODEL_PROVIDER_TYPES[type].helpText,
11302
- credentialLabel: MODEL_PROVIDER_TYPES[type].credentialLabel
11402
+ credentialLabel: MODEL_PROVIDER_TYPES[type].credentialLabel,
11403
+ models: getModels(type),
11404
+ defaultModel: getDefaultModel(type)
11303
11405
  })
11304
11406
  );
11305
11407
  }
@@ -11307,7 +11409,8 @@ async function setupModelProvider(type, credential, options) {
11307
11409
  const response = await upsertModelProvider({
11308
11410
  type,
11309
11411
  credential,
11310
- convert: options?.convert
11412
+ convert: options?.convert,
11413
+ selectedModel: options?.selectedModel
11311
11414
  });
11312
11415
  return {
11313
11416
  provider: response.provider,
@@ -11507,10 +11610,29 @@ async function handleModelProvider(ctx) {
11507
11610
  console.log(chalk57.dim("Cancelled"));
11508
11611
  process.exit(0);
11509
11612
  }
11510
- const result = await setupModelProvider(providerType, credential);
11613
+ let selectedModel;
11614
+ if (selectedChoice?.models && selectedChoice.models.length > 0) {
11615
+ selectedModel = await step.prompt(
11616
+ () => promptSelect(
11617
+ "Select model:",
11618
+ selectedChoice.models.map((model) => ({
11619
+ title: model === selectedChoice.defaultModel ? `${model} (Recommended)` : model,
11620
+ value: model
11621
+ }))
11622
+ )
11623
+ );
11624
+ if (!selectedModel) {
11625
+ console.log(chalk57.dim("Cancelled"));
11626
+ process.exit(0);
11627
+ }
11628
+ }
11629
+ const result = await setupModelProvider(providerType, credential, {
11630
+ selectedModel
11631
+ });
11632
+ const modelNote = result.provider.selectedModel ? ` with model: ${result.provider.selectedModel}` : "";
11511
11633
  step.detail(
11512
11634
  chalk57.green(
11513
- `${providerType} ${result.created ? "created" : "updated"}${result.isDefault ? ` (default for ${result.framework})` : ""}`
11635
+ `${providerType} ${result.created ? "created" : "updated"}${result.isDefault ? ` (default for ${result.framework})` : ""}${modelNote}`
11514
11636
  )
11515
11637
  );
11516
11638
  });
@@ -11658,7 +11780,7 @@ var setupClaudeCommand = new Command57().name("setup-claude").description("Insta
11658
11780
 
11659
11781
  // src/index.ts
11660
11782
  var program = new Command58();
11661
- program.name("vm0").description("VM0 CLI - Build and run agents with natural language").version("9.10.0");
11783
+ program.name("vm0").description("VM0 CLI - Build and run agents with natural language").version("9.11.0");
11662
11784
  program.addCommand(authCommand);
11663
11785
  program.addCommand(infoCommand);
11664
11786
  program.addCommand(composeCommand);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@vm0/cli",
3
- "version": "9.10.0",
3
+ "version": "9.11.0",
4
4
  "description": "CLI application",
5
5
  "repository": {
6
6
  "type": "git",