@vm0/cli 9.20.2 → 9.21.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 +362 -232
  2. package/package.json +2 -1
package/index.js CHANGED
@@ -1,5 +1,82 @@
1
1
  #!/usr/bin/env node
2
2
 
3
+ // src/instrument.ts
4
+ import * as Sentry from "@sentry/node";
5
+ import * as os from "os";
6
+ var TELEMETRY_DISABLED = process.env.VM0_TELEMETRY === "false";
7
+ var IS_CI = Boolean(process.env.CI || process.env.GITHUB_ACTIONS);
8
+ var IS_DEV = process.env.NODE_ENV === "development";
9
+ var PRODUCTION_API_URL = "https://www.vm0.ai";
10
+ var API_URL = process.env.VM0_API_URL ?? "";
11
+ var IS_PRODUCTION_API = API_URL === "" || API_URL === PRODUCTION_API_URL;
12
+ var DSN = "https://268d9b4cd051531805af76a5b3934dca@o4510583739777024.ingest.us.sentry.io/4510832047947776";
13
+ var OPERATIONAL_ERROR_PATTERNS = [
14
+ // Authentication errors (user needs to login)
15
+ /not authenticated/i,
16
+ // Resource not found (user typo or deleted resource)
17
+ /not found/i,
18
+ /agent not found/i,
19
+ /version not found/i,
20
+ /checkpoint not found/i,
21
+ /session not found/i,
22
+ // File errors (user provided wrong path)
23
+ /file not found/i,
24
+ /environment file not found/i,
25
+ // Validation errors (user input issues)
26
+ /invalid format/i,
27
+ /invalid.*config/i,
28
+ // Rate limiting (expected operational condition)
29
+ /rate limit/i,
30
+ /concurrent run limit/i,
31
+ // Network issues (transient, not bugs)
32
+ /network error/i,
33
+ /network issue/i,
34
+ /connection refused/i,
35
+ /timeout/i,
36
+ /ECONNREFUSED/i,
37
+ /ETIMEDOUT/i,
38
+ // Permission/access errors (operational, not bugs)
39
+ /forbidden/i,
40
+ /access denied/i
41
+ ];
42
+ function isOperationalError(error) {
43
+ if (!(error instanceof Error)) {
44
+ return false;
45
+ }
46
+ const message = error.message;
47
+ return OPERATIONAL_ERROR_PATTERNS.some((pattern) => pattern.test(message));
48
+ }
49
+ if (!TELEMETRY_DISABLED && !IS_CI && !IS_DEV && IS_PRODUCTION_API) {
50
+ Sentry.init({
51
+ dsn: DSN,
52
+ sendDefaultPii: false,
53
+ tracesSampleRate: 0,
54
+ shutdownTimeout: 500,
55
+ initialScope: {
56
+ tags: {
57
+ app: "cli"
58
+ }
59
+ },
60
+ // Filter out operational errors - only send programmer errors (bugs)
61
+ beforeSend(event, hint) {
62
+ const error = hint.originalException;
63
+ if (isOperationalError(error)) {
64
+ return null;
65
+ }
66
+ return event;
67
+ }
68
+ });
69
+ Sentry.setContext("cli", {
70
+ version: "9.21.0",
71
+ command: process.argv.slice(2).join(" ")
72
+ });
73
+ Sentry.setContext("runtime", {
74
+ node_version: process.version,
75
+ os_platform: os.platform(),
76
+ os_release: os.release()
77
+ });
78
+ }
79
+
3
80
  // src/index.ts
4
81
  import { Command as Command68 } from "commander";
5
82
 
@@ -2092,26 +2169,26 @@ var c13 = initContract();
2092
2169
  var MODEL_PROVIDER_TYPES = {
2093
2170
  "claude-code-oauth-token": {
2094
2171
  framework: "claude-code",
2095
- credentialName: "CLAUDE_CODE_OAUTH_TOKEN",
2172
+ secretName: "CLAUDE_CODE_OAUTH_TOKEN",
2096
2173
  label: "Claude Code (OAuth Token)",
2097
- credentialLabel: "OAuth token",
2174
+ secretLabel: "OAuth token",
2098
2175
  helpText: "To get your OAuth token, run: claude setup-token\n(Requires Claude Pro or Max subscription)"
2099
2176
  },
2100
2177
  "anthropic-api-key": {
2101
2178
  framework: "claude-code",
2102
- credentialName: "ANTHROPIC_API_KEY",
2179
+ secretName: "ANTHROPIC_API_KEY",
2103
2180
  label: "Anthropic API Key",
2104
- credentialLabel: "API key",
2181
+ secretLabel: "API key",
2105
2182
  helpText: "Get your API key at: https://console.anthropic.com/settings/keys"
2106
2183
  },
2107
2184
  "openrouter-api-key": {
2108
2185
  framework: "claude-code",
2109
- credentialName: "OPENROUTER_API_KEY",
2186
+ secretName: "OPENROUTER_API_KEY",
2110
2187
  label: "OpenRouter",
2111
- credentialLabel: "API key",
2188
+ secretLabel: "API key",
2112
2189
  helpText: "Get your API key at: https://openrouter.ai/settings/keys",
2113
2190
  environmentMapping: {
2114
- ANTHROPIC_AUTH_TOKEN: "$credential",
2191
+ ANTHROPIC_AUTH_TOKEN: "$secret",
2115
2192
  ANTHROPIC_BASE_URL: "https://openrouter.ai/api",
2116
2193
  ANTHROPIC_API_KEY: "",
2117
2194
  ANTHROPIC_MODEL: "$model",
@@ -2129,12 +2206,12 @@ var MODEL_PROVIDER_TYPES = {
2129
2206
  },
2130
2207
  "moonshot-api-key": {
2131
2208
  framework: "claude-code",
2132
- credentialName: "MOONSHOT_API_KEY",
2209
+ secretName: "MOONSHOT_API_KEY",
2133
2210
  label: "Moonshot (Kimi)",
2134
- credentialLabel: "API key",
2211
+ secretLabel: "API key",
2135
2212
  helpText: "Get your API key at: https://platform.moonshot.ai/console/api-keys",
2136
2213
  environmentMapping: {
2137
- ANTHROPIC_AUTH_TOKEN: "$credential",
2214
+ ANTHROPIC_AUTH_TOKEN: "$secret",
2138
2215
  ANTHROPIC_BASE_URL: "https://api.moonshot.ai/anthropic",
2139
2216
  ANTHROPIC_MODEL: "$model",
2140
2217
  ANTHROPIC_DEFAULT_OPUS_MODEL: "$model",
@@ -2151,12 +2228,12 @@ var MODEL_PROVIDER_TYPES = {
2151
2228
  },
2152
2229
  "minimax-api-key": {
2153
2230
  framework: "claude-code",
2154
- credentialName: "MINIMAX_API_KEY",
2231
+ secretName: "MINIMAX_API_KEY",
2155
2232
  label: "MiniMax",
2156
- credentialLabel: "API key",
2233
+ secretLabel: "API key",
2157
2234
  helpText: "Get your API key at: https://platform.minimax.io/user-center/basic-information/interface-key",
2158
2235
  environmentMapping: {
2159
- ANTHROPIC_AUTH_TOKEN: "$credential",
2236
+ ANTHROPIC_AUTH_TOKEN: "$secret",
2160
2237
  ANTHROPIC_BASE_URL: "https://api.minimax.io/anthropic",
2161
2238
  ANTHROPIC_MODEL: "$model",
2162
2239
  ANTHROPIC_DEFAULT_OPUS_MODEL: "$model",
@@ -2171,12 +2248,12 @@ var MODEL_PROVIDER_TYPES = {
2171
2248
  },
2172
2249
  "deepseek-api-key": {
2173
2250
  framework: "claude-code",
2174
- credentialName: "DEEPSEEK_API_KEY",
2251
+ secretName: "DEEPSEEK_API_KEY",
2175
2252
  label: "DeepSeek",
2176
- credentialLabel: "API key",
2253
+ secretLabel: "API key",
2177
2254
  helpText: "Get your API key at: https://platform.deepseek.com/api_keys",
2178
2255
  environmentMapping: {
2179
- ANTHROPIC_AUTH_TOKEN: "$credential",
2256
+ ANTHROPIC_AUTH_TOKEN: "$secret",
2180
2257
  ANTHROPIC_BASE_URL: "https://api.deepseek.com/anthropic",
2181
2258
  ANTHROPIC_MODEL: "$model",
2182
2259
  ANTHROPIC_DEFAULT_OPUS_MODEL: "$model",
@@ -2191,12 +2268,12 @@ var MODEL_PROVIDER_TYPES = {
2191
2268
  },
2192
2269
  "zai-api-key": {
2193
2270
  framework: "claude-code",
2194
- credentialName: "ZAI_API_KEY",
2271
+ secretName: "ZAI_API_KEY",
2195
2272
  label: "Z.AI (GLM)",
2196
- credentialLabel: "API key",
2273
+ secretLabel: "API key",
2197
2274
  helpText: "Get your API key at: https://z.ai/model-api",
2198
2275
  environmentMapping: {
2199
- ANTHROPIC_AUTH_TOKEN: "$credential",
2276
+ ANTHROPIC_AUTH_TOKEN: "$secret",
2200
2277
  ANTHROPIC_BASE_URL: "https://api.z.ai/api/anthropic",
2201
2278
  ANTHROPIC_MODEL: "$model",
2202
2279
  ANTHROPIC_DEFAULT_OPUS_MODEL: "$model",
@@ -2216,7 +2293,7 @@ var MODEL_PROVIDER_TYPES = {
2216
2293
  "api-key": {
2217
2294
  label: "API Key",
2218
2295
  helpText: "Use an Azure Foundry API key for authentication",
2219
- credentials: {
2296
+ secrets: {
2220
2297
  ANTHROPIC_FOUNDRY_API_KEY: {
2221
2298
  label: "ANTHROPIC_FOUNDRY_API_KEY",
2222
2299
  required: true,
@@ -2234,8 +2311,8 @@ var MODEL_PROVIDER_TYPES = {
2234
2311
  defaultAuthMethod: "api-key",
2235
2312
  environmentMapping: {
2236
2313
  CLAUDE_CODE_USE_FOUNDRY: "1",
2237
- ANTHROPIC_FOUNDRY_API_KEY: "$credentials.ANTHROPIC_FOUNDRY_API_KEY",
2238
- ANTHROPIC_FOUNDRY_RESOURCE: "$credentials.ANTHROPIC_FOUNDRY_RESOURCE",
2314
+ ANTHROPIC_FOUNDRY_API_KEY: "$secrets.ANTHROPIC_FOUNDRY_API_KEY",
2315
+ ANTHROPIC_FOUNDRY_RESOURCE: "$secrets.ANTHROPIC_FOUNDRY_RESOURCE",
2239
2316
  ANTHROPIC_MODEL: "$model"
2240
2317
  },
2241
2318
  models: [],
@@ -2251,7 +2328,7 @@ var MODEL_PROVIDER_TYPES = {
2251
2328
  "api-key": {
2252
2329
  label: "Bedrock API Key",
2253
2330
  helpText: "Use a Bedrock API key for authentication",
2254
- credentials: {
2331
+ secrets: {
2255
2332
  AWS_BEARER_TOKEN_BEDROCK: {
2256
2333
  label: "AWS_BEARER_TOKEN_BEDROCK",
2257
2334
  required: true,
@@ -2267,8 +2344,8 @@ var MODEL_PROVIDER_TYPES = {
2267
2344
  },
2268
2345
  "access-keys": {
2269
2346
  label: "IAM Access Keys",
2270
- helpText: "Use IAM access key credentials",
2271
- credentials: {
2347
+ helpText: "Use IAM access key secrets",
2348
+ secrets: {
2272
2349
  AWS_ACCESS_KEY_ID: {
2273
2350
  label: "AWS_ACCESS_KEY_ID",
2274
2351
  required: true,
@@ -2282,7 +2359,7 @@ var MODEL_PROVIDER_TYPES = {
2282
2359
  AWS_SESSION_TOKEN: {
2283
2360
  label: "AWS_SESSION_TOKEN",
2284
2361
  required: false,
2285
- helpText: "Optional, for temporary credentials"
2362
+ helpText: "Optional, for temporary secrets"
2286
2363
  },
2287
2364
  AWS_REGION: {
2288
2365
  label: "AWS_REGION",
@@ -2296,11 +2373,11 @@ var MODEL_PROVIDER_TYPES = {
2296
2373
  defaultAuthMethod: "api-key",
2297
2374
  environmentMapping: {
2298
2375
  CLAUDE_CODE_USE_BEDROCK: "1",
2299
- AWS_REGION: "$credentials.AWS_REGION",
2300
- AWS_BEARER_TOKEN_BEDROCK: "$credentials.AWS_BEARER_TOKEN_BEDROCK",
2301
- AWS_ACCESS_KEY_ID: "$credentials.AWS_ACCESS_KEY_ID",
2302
- AWS_SECRET_ACCESS_KEY: "$credentials.AWS_SECRET_ACCESS_KEY",
2303
- AWS_SESSION_TOKEN: "$credentials.AWS_SESSION_TOKEN",
2376
+ AWS_REGION: "$secrets.AWS_REGION",
2377
+ AWS_BEARER_TOKEN_BEDROCK: "$secrets.AWS_BEARER_TOKEN_BEDROCK",
2378
+ AWS_ACCESS_KEY_ID: "$secrets.AWS_ACCESS_KEY_ID",
2379
+ AWS_SECRET_ACCESS_KEY: "$secrets.AWS_SECRET_ACCESS_KEY",
2380
+ AWS_SESSION_TOKEN: "$secrets.AWS_SESSION_TOKEN",
2304
2381
  ANTHROPIC_MODEL: "$model"
2305
2382
  },
2306
2383
  models: [],
@@ -2333,13 +2410,13 @@ function getDefaultAuthMethod(type) {
2333
2410
  const config = MODEL_PROVIDER_TYPES[type];
2334
2411
  return "defaultAuthMethod" in config ? config.defaultAuthMethod : void 0;
2335
2412
  }
2336
- function getCredentialsForAuthMethod(type, authMethod) {
2413
+ function getSecretsForAuthMethod(type, authMethod) {
2337
2414
  const authMethods = getAuthMethodsForType(type);
2338
2415
  if (!authMethods || !(authMethod in authMethods)) {
2339
2416
  return void 0;
2340
2417
  }
2341
2418
  const method = authMethods[authMethod];
2342
- return method?.credentials;
2419
+ return method?.secrets;
2343
2420
  }
2344
2421
  function getModels(type) {
2345
2422
  const config = MODEL_PROVIDER_TYPES[type];
@@ -2365,11 +2442,11 @@ var modelProviderResponseSchema = z16.object({
2365
2442
  id: z16.string().uuid(),
2366
2443
  type: modelProviderTypeSchema,
2367
2444
  framework: modelProviderFrameworkSchema,
2368
- credentialName: z16.string().nullable(),
2369
- // Legacy single-credential (deprecated for multi-auth)
2445
+ secretName: z16.string().nullable(),
2446
+ // Legacy single-secret (deprecated for multi-auth)
2370
2447
  authMethod: z16.string().nullable(),
2371
2448
  // For multi-auth providers
2372
- credentialNames: z16.array(z16.string()).nullable(),
2449
+ secretNames: z16.array(z16.string()).nullable(),
2373
2450
  // For multi-auth providers
2374
2451
  isDefault: z16.boolean(),
2375
2452
  selectedModel: z16.string().nullable(),
@@ -2381,23 +2458,21 @@ var modelProviderListResponseSchema = z16.object({
2381
2458
  });
2382
2459
  var upsertModelProviderRequestSchema = z16.object({
2383
2460
  type: modelProviderTypeSchema,
2384
- credential: z16.string().min(1).optional(),
2385
- // Legacy single credential
2461
+ secret: z16.string().min(1).optional(),
2462
+ // Legacy single secret
2386
2463
  authMethod: z16.string().optional(),
2387
2464
  // For multi-auth providers
2388
- credentials: z16.record(z16.string(), z16.string()).optional(),
2465
+ secrets: z16.record(z16.string(), z16.string()).optional(),
2389
2466
  // For multi-auth providers
2390
- convert: z16.boolean().optional(),
2391
2467
  selectedModel: z16.string().optional()
2392
2468
  });
2393
2469
  var upsertModelProviderResponseSchema = z16.object({
2394
2470
  provider: modelProviderResponseSchema,
2395
2471
  created: z16.boolean()
2396
2472
  });
2397
- var checkCredentialResponseSchema = z16.object({
2473
+ var checkSecretResponseSchema = z16.object({
2398
2474
  exists: z16.boolean(),
2399
- credentialName: z16.string(),
2400
- currentType: z16.enum(["user", "model-provider"]).optional()
2475
+ secretName: z16.string()
2401
2476
  });
2402
2477
  var modelProvidersMainContract = c13.router({
2403
2478
  list: {
@@ -2436,11 +2511,11 @@ var modelProvidersCheckContract = c13.router({
2436
2511
  type: modelProviderTypeSchema
2437
2512
  }),
2438
2513
  responses: {
2439
- 200: checkCredentialResponseSchema,
2514
+ 200: checkSecretResponseSchema,
2440
2515
  401: apiErrorSchema,
2441
2516
  500: apiErrorSchema
2442
2517
  },
2443
- summary: "Check if credential exists for a model provider type"
2518
+ summary: "Check if secret exists for a model provider type"
2444
2519
  }
2445
2520
  });
2446
2521
  var modelProvidersByTypeContract = c13.router({
@@ -2476,7 +2551,7 @@ var modelProvidersConvertContract = c13.router({
2476
2551
  404: apiErrorSchema,
2477
2552
  500: apiErrorSchema
2478
2553
  },
2479
- summary: "Convert existing user credential to model provider"
2554
+ summary: "Convert existing user secret to model provider"
2480
2555
  }
2481
2556
  });
2482
2557
  var modelProvidersSetDefaultContract = c13.router({
@@ -3627,13 +3702,14 @@ function getSkillStorageName(fullPath) {
3627
3702
 
3628
3703
  // ../../packages/core/src/github-url.ts
3629
3704
  function parseGitHubTreeUrl(url) {
3630
- const fullPathMatch = url.match(/^https:\/\/github\.com\/(.+)$/);
3705
+ const normalizedUrl = url.replace(/\/+$/, "");
3706
+ const fullPathMatch = normalizedUrl.match(/^https:\/\/github\.com\/(.+)$/);
3631
3707
  if (!fullPathMatch) {
3632
3708
  return null;
3633
3709
  }
3634
3710
  const fullPath = fullPathMatch[1];
3635
3711
  const regex = /^https:\/\/github\.com\/([^/]+)\/([^/]+)\/tree\/([^/]+)\/(.+)$/;
3636
- const match = url.match(regex);
3712
+ const match = normalizedUrl.match(regex);
3637
3713
  if (!match) {
3638
3714
  return null;
3639
3715
  }
@@ -3649,6 +3725,39 @@ function parseGitHubTreeUrl(url) {
3649
3725
  fullPath
3650
3726
  };
3651
3727
  }
3728
+ function parseGitHubUrl(url) {
3729
+ const normalizedUrl = url.replace(/\/+$/, "");
3730
+ const fullPathMatch = normalizedUrl.match(/^https:\/\/github\.com\/(.+)$/);
3731
+ if (!fullPathMatch) {
3732
+ return null;
3733
+ }
3734
+ const fullPath = fullPathMatch[1];
3735
+ const plainMatch = normalizedUrl.match(
3736
+ /^https:\/\/github\.com\/([^/]+)\/([^/]+)$/
3737
+ );
3738
+ if (plainMatch) {
3739
+ return {
3740
+ owner: plainMatch[1],
3741
+ repo: plainMatch[2],
3742
+ branch: null,
3743
+ path: null,
3744
+ fullPath
3745
+ };
3746
+ }
3747
+ const treeMatch = normalizedUrl.match(
3748
+ /^https:\/\/github\.com\/([^/]+)\/([^/]+)\/tree\/([^/]+)(?:\/(.+))?$/
3749
+ );
3750
+ if (treeMatch) {
3751
+ return {
3752
+ owner: treeMatch[1],
3753
+ repo: treeMatch[2],
3754
+ branch: treeMatch[3],
3755
+ path: treeMatch[4] ?? null,
3756
+ fullPath
3757
+ };
3758
+ }
3759
+ return null;
3760
+ }
3652
3761
 
3653
3762
  // ../../packages/core/src/frameworks.ts
3654
3763
  var SUPPORTED_FRAMEWORKS = ["claude-code", "codex"];
@@ -3710,9 +3819,10 @@ var FEATURE_SWITCHES = {
3710
3819
 
3711
3820
  // src/lib/api/core/client-factory.ts
3712
3821
  var ApiRequestError = class extends Error {
3713
- constructor(message, code) {
3822
+ constructor(message, code, status) {
3714
3823
  super(message);
3715
3824
  this.code = code;
3825
+ this.status = status;
3716
3826
  this.name = "ApiRequestError";
3717
3827
  }
3718
3828
  };
@@ -3742,11 +3852,27 @@ async function getClientConfig() {
3742
3852
  const baseHeaders = await getHeaders();
3743
3853
  return { baseUrl, baseHeaders, jsonQuery: true };
3744
3854
  }
3745
- function handleError(result, defaultMessage) {
3855
+ function handleError(result, defaultMessage, options) {
3856
+ if (!options?.useServerMessage) {
3857
+ if (result.status === 401) {
3858
+ throw new ApiRequestError(
3859
+ "Not authenticated. Run: vm0 auth login",
3860
+ "UNAUTHORIZED",
3861
+ 401
3862
+ );
3863
+ }
3864
+ if (result.status === 403) {
3865
+ throw new ApiRequestError(
3866
+ "An unexpected network issue occurred",
3867
+ "FORBIDDEN",
3868
+ 403
3869
+ );
3870
+ }
3871
+ }
3746
3872
  const errorBody = result.body;
3747
3873
  const message = errorBody.error?.message || defaultMessage;
3748
3874
  const code = errorBody.error?.code || "UNKNOWN";
3749
- throw new ApiRequestError(message, code);
3875
+ throw new ApiRequestError(message, code, result.status);
3750
3876
  }
3751
3877
 
3752
3878
  // src/lib/api/core/http.ts
@@ -3931,7 +4057,7 @@ async function getScope() {
3931
4057
  if (result.status === 200) {
3932
4058
  return result.body;
3933
4059
  }
3934
- handleError(result, "Failed to get scope");
4060
+ handleError(result, "Failed to get scope", { useServerMessage: true });
3935
4061
  }
3936
4062
  async function createScope(body) {
3937
4063
  const config = await getClientConfig();
@@ -3940,7 +4066,7 @@ async function createScope(body) {
3940
4066
  if (result.status === 201) {
3941
4067
  return result.body;
3942
4068
  }
3943
- handleError(result, "Failed to create scope");
4069
+ handleError(result, "Failed to create scope", { useServerMessage: true });
3944
4070
  }
3945
4071
  async function updateScope(body) {
3946
4072
  const config = await getClientConfig();
@@ -3949,7 +4075,7 @@ async function updateScope(body) {
3949
4075
  if (result.status === 200) {
3950
4076
  return result.body;
3951
4077
  }
3952
- handleError(result, "Failed to update scope");
4078
+ handleError(result, "Failed to update scope", { useServerMessage: true });
3953
4079
  }
3954
4080
 
3955
4081
  // src/lib/api/domains/storages.ts
@@ -4187,7 +4313,7 @@ async function upsertModelProvider(body) {
4187
4313
  }
4188
4314
  handleError(result, "Failed to set model provider");
4189
4315
  }
4190
- async function checkModelProviderCredential(type) {
4316
+ async function checkModelProviderSecret(type) {
4191
4317
  const config = await getClientConfig();
4192
4318
  const client = initClient9(modelProvidersCheckContract, config);
4193
4319
  const result = await client.check({
@@ -4196,7 +4322,7 @@ async function checkModelProviderCredential(type) {
4196
4322
  if (result.status === 200) {
4197
4323
  return result.body;
4198
4324
  }
4199
- handleError(result, "Failed to check credential");
4325
+ handleError(result, "Failed to check secret");
4200
4326
  }
4201
4327
  async function deleteModelProvider(type) {
4202
4328
  const config = await getClientConfig();
@@ -4209,17 +4335,6 @@ async function deleteModelProvider(type) {
4209
4335
  }
4210
4336
  handleError(result, `Model provider "${type}" not found`);
4211
4337
  }
4212
- async function convertModelProviderCredential(type) {
4213
- const config = await getClientConfig();
4214
- const client = initClient9(modelProvidersConvertContract, config);
4215
- const result = await client.convert({
4216
- params: { type }
4217
- });
4218
- if (result.status === 200) {
4219
- return result.body;
4220
- }
4221
- handleError(result, "Failed to convert credential");
4222
- }
4223
4338
  async function setModelProviderDefault(type) {
4224
4339
  const config = await getClientConfig();
4225
4340
  const client = initClient9(modelProvidersSetDefaultContract, config);
@@ -4450,7 +4565,7 @@ function validateAgentCompose(config) {
4450
4565
  // src/lib/domain/github-skills.ts
4451
4566
  import * as fs from "fs/promises";
4452
4567
  import * as path from "path";
4453
- import * as os from "os";
4568
+ import * as os2 from "os";
4454
4569
  import { exec } from "child_process";
4455
4570
  import { promisify } from "util";
4456
4571
  import { parse as parseYaml } from "yaml";
@@ -4470,7 +4585,7 @@ function getSkillStorageName2(parsed) {
4470
4585
  async function downloadGitHubSkill(parsed, destDir) {
4471
4586
  const repoUrl = `https://github.com/${parsed.owner}/${parsed.repo}.git`;
4472
4587
  const skillDir = path.join(destDir, parsed.skillName);
4473
- const tempDir = await fs.mkdtemp(path.join(os.tmpdir(), "vm0-skill-"));
4588
+ const tempDir = await fs.mkdtemp(path.join(os2.tmpdir(), "vm0-skill-"));
4474
4589
  try {
4475
4590
  await execAsync(`git init`, { cwd: tempDir });
4476
4591
  await execAsync(`git remote add origin "${repoUrl}"`, { cwd: tempDir });
@@ -4489,10 +4604,41 @@ async function downloadGitHubSkill(parsed, destDir) {
4489
4604
  await fs.rm(tempDir, { recursive: true, force: true });
4490
4605
  }
4491
4606
  }
4607
+ async function getDefaultBranch(owner, repo) {
4608
+ const repoUrl = `https://github.com/${owner}/${repo}.git`;
4609
+ try {
4610
+ const { stdout } = await execAsync(
4611
+ `git ls-remote --symref "${repoUrl}" HEAD`
4612
+ );
4613
+ const match = stdout.match(/ref: refs\/heads\/([^\s]+)/);
4614
+ if (!match) {
4615
+ throw new Error(
4616
+ `Could not determine default branch for ${owner}/${repo}`
4617
+ );
4618
+ }
4619
+ return match[1];
4620
+ } catch (error) {
4621
+ const message = error instanceof Error ? error.message : String(error);
4622
+ if (message.includes("not found") || message.includes("Repository not found")) {
4623
+ throw new Error(`Repository not found: ${owner}/${repo}`);
4624
+ }
4625
+ if (message.includes("Authentication failed") || message.includes("could not read Username")) {
4626
+ throw new Error(
4627
+ `Cannot access repository ${owner}/${repo}. Is it private?`
4628
+ );
4629
+ }
4630
+ throw error;
4631
+ }
4632
+ }
4492
4633
  async function downloadGitHubDirectory(url) {
4493
- const parsed = parseGitHubTreeUrl2(url);
4634
+ const parsed = parseGitHubUrl(url);
4635
+ if (!parsed) {
4636
+ throw new Error(
4637
+ `Invalid GitHub URL: ${url}. Expected format: https://github.com/{owner}/{repo}[/tree/{branch}[/path]]`
4638
+ );
4639
+ }
4494
4640
  const repoUrl = `https://github.com/${parsed.owner}/${parsed.repo}.git`;
4495
- const tempDir = await fs.mkdtemp(path.join(os.tmpdir(), "vm0-github-"));
4641
+ const tempDir = await fs.mkdtemp(path.join(os2.tmpdir(), "vm0-github-"));
4496
4642
  try {
4497
4643
  try {
4498
4644
  await execAsync("git --version");
@@ -4501,13 +4647,15 @@ async function downloadGitHubDirectory(url) {
4501
4647
  "git command not found. Please install git to use GitHub URLs."
4502
4648
  );
4503
4649
  }
4650
+ const branch = parsed.branch ?? await getDefaultBranch(parsed.owner, parsed.repo);
4504
4651
  await execAsync(`git init`, { cwd: tempDir });
4505
4652
  await execAsync(`git remote add origin "${repoUrl}"`, { cwd: tempDir });
4506
4653
  await execAsync(`git config core.sparseCheckout true`, { cwd: tempDir });
4654
+ const sparsePattern = parsed.path ?? "/*";
4507
4655
  const sparseFile = path.join(tempDir, ".git", "info", "sparse-checkout");
4508
- await fs.writeFile(sparseFile, parsed.path + "\n");
4656
+ await fs.writeFile(sparseFile, sparsePattern + "\n");
4509
4657
  try {
4510
- await execAsync(`git fetch --depth 1 origin "${parsed.branch}"`, {
4658
+ await execAsync(`git fetch --depth 1 origin "${branch}"`, {
4511
4659
  cwd: tempDir
4512
4660
  });
4513
4661
  } catch (error) {
@@ -4516,15 +4664,14 @@ async function downloadGitHubDirectory(url) {
4516
4664
  throw new Error(`Cannot access repository. Is it private? URL: ${url}`);
4517
4665
  }
4518
4666
  if (message.includes("couldn't find remote ref")) {
4519
- throw new Error(
4520
- `Branch "${parsed.branch}" not found in repository: ${url}`
4521
- );
4667
+ throw new Error(`Branch "${branch}" not found in repository: ${url}`);
4522
4668
  }
4523
4669
  throw error;
4524
4670
  }
4525
- await execAsync(`git checkout "${parsed.branch}"`, { cwd: tempDir });
4671
+ await execAsync(`git checkout "${branch}"`, { cwd: tempDir });
4672
+ const downloadedDir = parsed.path ? path.join(tempDir, parsed.path) : tempDir;
4526
4673
  return {
4527
- dir: path.join(tempDir, parsed.path),
4674
+ dir: downloadedDir,
4528
4675
  tempRoot: tempDir
4529
4676
  };
4530
4677
  } catch (error) {
@@ -4577,13 +4724,13 @@ async function readSkillFrontmatter(skillDir) {
4577
4724
  // src/lib/storage/system-storage.ts
4578
4725
  import * as fs4 from "fs/promises";
4579
4726
  import * as path4 from "path";
4580
- import * as os3 from "os";
4727
+ import * as os4 from "os";
4581
4728
 
4582
4729
  // src/lib/storage/direct-upload.ts
4583
4730
  import { createHash } from "crypto";
4584
4731
  import * as fs3 from "fs";
4585
4732
  import * as path3 from "path";
4586
- import * as os2 from "os";
4733
+ import * as os3 from "os";
4587
4734
  import * as tar2 from "tar";
4588
4735
 
4589
4736
  // src/lib/utils/file-utils.ts
@@ -4746,7 +4893,7 @@ async function collectFileMetadata(cwd, files, onProgress) {
4746
4893
  return fileEntries;
4747
4894
  }
4748
4895
  async function createArchive(cwd, files) {
4749
- const tmpDir = fs3.mkdtempSync(path3.join(os2.tmpdir(), "vm0-"));
4896
+ const tmpDir = fs3.mkdtempSync(path3.join(os3.tmpdir(), "vm0-"));
4750
4897
  const tarPath = path3.join(tmpDir, "archive.tar.gz");
4751
4898
  try {
4752
4899
  const relativePaths = files.map((file) => path3.relative(cwd, file));
@@ -4903,7 +5050,7 @@ async function uploadInstructions(agentName, instructionsFilePath, basePath, fra
4903
5050
  const storageName = getInstructionsStorageName(agentName.toLowerCase());
4904
5051
  const absolutePath = path4.isAbsolute(instructionsFilePath) ? instructionsFilePath : path4.join(basePath, instructionsFilePath);
4905
5052
  const content = await fs4.readFile(absolutePath, "utf8");
4906
- const tmpDir = await fs4.mkdtemp(path4.join(os3.tmpdir(), "vm0-instructions-"));
5053
+ const tmpDir = await fs4.mkdtemp(path4.join(os4.tmpdir(), "vm0-instructions-"));
4907
5054
  const instructionsDir = path4.join(tmpDir, "instructions");
4908
5055
  await fs4.mkdir(instructionsDir);
4909
5056
  const filename = getInstructionsFilename(framework);
@@ -4922,7 +5069,7 @@ async function uploadInstructions(agentName, instructionsFilePath, basePath, fra
4922
5069
  async function uploadSkill(skillUrl) {
4923
5070
  const parsed = parseGitHubTreeUrl2(skillUrl);
4924
5071
  const storageName = getSkillStorageName2(parsed);
4925
- const tmpDir = await fs4.mkdtemp(path4.join(os3.tmpdir(), "vm0-skill-"));
5072
+ const tmpDir = await fs4.mkdtemp(path4.join(os4.tmpdir(), "vm0-skill-"));
4926
5073
  try {
4927
5074
  const skillDir = await downloadGitHubSkill(parsed, tmpDir);
4928
5075
  await validateSkillDirectory(skillDir);
@@ -5207,8 +5354,8 @@ async function silentUpgradeAfterCommand(currentVersion) {
5207
5354
 
5208
5355
  // src/commands/compose/index.ts
5209
5356
  var DEFAULT_CONFIG_FILE = "vm0.yaml";
5210
- function isGitHubTreeUrl(input) {
5211
- return input.startsWith("https://github.com/") && input.includes("/tree/");
5357
+ function isGitHubUrl(input) {
5358
+ return /^https:\/\/github\.com\/[^/]+\/[^/]+/.test(input);
5212
5359
  }
5213
5360
  function getSecretsFromComposeContent(content) {
5214
5361
  const refs = extractVariableReferences(content);
@@ -5425,7 +5572,7 @@ async function finalizeCompose(config, agent, variables, options) {
5425
5572
  )
5426
5573
  );
5427
5574
  if (options.autoUpdate !== false) {
5428
- await silentUpgradeAfterCommand("9.20.2");
5575
+ await silentUpgradeAfterCommand("9.21.0");
5429
5576
  }
5430
5577
  }
5431
5578
  async function handleGitHubCompose(url, options) {
@@ -5504,7 +5651,7 @@ var composeCommand = new Command7().name("compose").description("Create or updat
5504
5651
  async (configFile, options) => {
5505
5652
  const resolvedConfigFile = configFile ?? DEFAULT_CONFIG_FILE;
5506
5653
  try {
5507
- if (isGitHubTreeUrl(resolvedConfigFile)) {
5654
+ if (isGitHubUrl(resolvedConfigFile)) {
5508
5655
  if (!options.experimentalSharedCompose) {
5509
5656
  console.error(
5510
5657
  chalk4.red(
@@ -7793,7 +7940,7 @@ var mainRunCommand = new Command8().name("run").description("Run an agent").argu
7793
7940
  }
7794
7941
  showNextSteps(result);
7795
7942
  if (options.autoUpdate !== false) {
7796
- await silentUpgradeAfterCommand("9.20.2");
7943
+ await silentUpgradeAfterCommand("9.21.0");
7797
7944
  }
7798
7945
  } catch (error) {
7799
7946
  handleRunError(error, identifier);
@@ -8238,7 +8385,7 @@ import { Command as Command15 } from "commander";
8238
8385
  import chalk17 from "chalk";
8239
8386
  import path7 from "path";
8240
8387
  import * as fs6 from "fs";
8241
- import * as os4 from "os";
8388
+ import * as os5 from "os";
8242
8389
  import * as tar3 from "tar";
8243
8390
 
8244
8391
  // src/lib/storage/pull-utils.ts
@@ -8290,7 +8437,7 @@ var pullCommand = new Command15().name("pull").description("Pull cloud files to
8290
8437
  const arrayBuffer = await s3Response.arrayBuffer();
8291
8438
  const tarBuffer = Buffer.from(arrayBuffer);
8292
8439
  console.log(chalk17.green(`\u2713 Downloaded ${formatBytes(tarBuffer.length)}`));
8293
- const tmpDir = fs6.mkdtempSync(path7.join(os4.tmpdir(), "vm0-"));
8440
+ const tmpDir = fs6.mkdtempSync(path7.join(os5.tmpdir(), "vm0-"));
8294
8441
  const tarPath = path7.join(tmpDir, "volume.tar.gz");
8295
8442
  await fs6.promises.writeFile(tarPath, tarBuffer);
8296
8443
  console.log(chalk17.dim("Syncing local files..."));
@@ -8439,7 +8586,7 @@ import chalk21 from "chalk";
8439
8586
  import chalk20 from "chalk";
8440
8587
  import path8 from "path";
8441
8588
  import * as fs7 from "fs";
8442
- import * as os5 from "os";
8589
+ import * as os6 from "os";
8443
8590
  import * as tar4 from "tar";
8444
8591
  async function cloneStorage(name, type, destination, options = {}) {
8445
8592
  const typeLabel = type === "artifact" ? "artifact" : "volume";
@@ -8479,7 +8626,7 @@ async function cloneStorage(name, type, destination, options = {}) {
8479
8626
  const arrayBuffer = await s3Response.arrayBuffer();
8480
8627
  const tarBuffer = Buffer.from(arrayBuffer);
8481
8628
  console.log(chalk20.green(`\u2713 Downloaded ${formatBytes(tarBuffer.length)}`));
8482
- const tmpDir = fs7.mkdtempSync(path8.join(os5.tmpdir(), "vm0-clone-"));
8629
+ const tmpDir = fs7.mkdtempSync(path8.join(os6.tmpdir(), "vm0-clone-"));
8483
8630
  const tarPath = path8.join(tmpDir, "archive.tar.gz");
8484
8631
  await fs7.promises.writeFile(tarPath, tarBuffer);
8485
8632
  const files = await listTarFiles(tarPath);
@@ -8680,7 +8827,7 @@ import { Command as Command22 } from "commander";
8680
8827
  import chalk24 from "chalk";
8681
8828
  import path10 from "path";
8682
8829
  import * as fs8 from "fs";
8683
- import * as os6 from "os";
8830
+ import * as os7 from "os";
8684
8831
  import * as tar5 from "tar";
8685
8832
  var pullCommand2 = new Command22().name("pull").description("Pull cloud artifact to local directory").argument("[versionId]", "Version ID to pull (default: latest)").action(async (versionId) => {
8686
8833
  try {
@@ -8727,7 +8874,7 @@ var pullCommand2 = new Command22().name("pull").description("Pull cloud artifact
8727
8874
  const arrayBuffer = await s3Response.arrayBuffer();
8728
8875
  const tarBuffer = Buffer.from(arrayBuffer);
8729
8876
  console.log(chalk24.green(`\u2713 Downloaded ${formatBytes(tarBuffer.length)}`));
8730
- const tmpDir = fs8.mkdtempSync(path10.join(os6.tmpdir(), "vm0-"));
8877
+ const tmpDir = fs8.mkdtempSync(path10.join(os7.tmpdir(), "vm0-"));
8731
8878
  const tarPath = path10.join(tmpDir, "artifact.tar.gz");
8732
8879
  await fs8.promises.writeFile(tarPath, tarBuffer);
8733
8880
  console.log(chalk24.dim("Syncing local files..."));
@@ -9300,7 +9447,7 @@ var cookAction = new Command27().name("cook").description("Quick start: prepare,
9300
9447
  ).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(
9301
9448
  async (prompt, options) => {
9302
9449
  if (options.autoUpdate !== false) {
9303
- const shouldExit = await checkAndUpgrade("9.20.2", prompt);
9450
+ const shouldExit = await checkAndUpgrade("9.21.0", prompt);
9304
9451
  if (shouldExit) {
9305
9452
  process.exit(0);
9306
9453
  }
@@ -10049,7 +10196,7 @@ import chalk38 from "chalk";
10049
10196
  // src/lib/domain/source-derivation.ts
10050
10197
  import * as fs9 from "fs/promises";
10051
10198
  import * as path14 from "path";
10052
- import * as os7 from "os";
10199
+ import * as os8 from "os";
10053
10200
  async function fetchSkillFrontmatter(skillUrl, tempDir) {
10054
10201
  try {
10055
10202
  const parsed = parseGitHubTreeUrl2(skillUrl);
@@ -10089,7 +10236,7 @@ async function deriveAgentVariableSources(agent, options) {
10089
10236
  };
10090
10237
  }
10091
10238
  const tempDir = await fs9.mkdtemp(
10092
- path14.join(os7.tmpdir(), "vm0-source-derivation-")
10239
+ path14.join(os8.tmpdir(), "vm0-source-derivation-")
10093
10240
  );
10094
10241
  try {
10095
10242
  const skillResults = await Promise.all(
@@ -11840,7 +11987,7 @@ var listCommand6 = new Command53().name("list").alias("ls").description("List al
11840
11987
  console.log(chalk53.dim("No secrets found"));
11841
11988
  console.log();
11842
11989
  console.log("To add a secret:");
11843
- console.log(chalk53.cyan(" vm0 secret set MY_API_KEY <value>"));
11990
+ console.log(chalk53.cyan(" vm0 secret set MY_API_KEY --body <value>"));
11844
11991
  return;
11845
11992
  }
11846
11993
  console.log(chalk53.bold("Secrets:"));
@@ -11874,9 +12021,32 @@ var listCommand6 = new Command53().name("list").alias("ls").description("List al
11874
12021
  // src/commands/secret/set.ts
11875
12022
  import { Command as Command54 } from "commander";
11876
12023
  import chalk54 from "chalk";
11877
- var setCommand2 = new Command54().name("set").description("Create or update a secret").argument("<name>", "Secret name (uppercase, e.g., MY_API_KEY)").argument("<value>", "Secret value").option("-d, --description <description>", "Optional description").action(
11878
- async (name, value, options) => {
12024
+ var setCommand2 = new Command54().name("set").description("Create or update a secret").argument("<name>", "Secret name (uppercase, e.g., MY_API_KEY)").option(
12025
+ "-b, --body <value>",
12026
+ "Secret value (required in non-interactive mode)"
12027
+ ).option("-d, --description <description>", "Optional description").action(
12028
+ async (name, options) => {
11879
12029
  try {
12030
+ let value;
12031
+ if (options.body !== void 0) {
12032
+ value = options.body;
12033
+ } else if (isInteractive()) {
12034
+ const prompted = await promptPassword("Enter secret value:");
12035
+ if (prompted === void 0) {
12036
+ process.exit(0);
12037
+ }
12038
+ value = prompted;
12039
+ } else {
12040
+ console.error(
12041
+ chalk54.red("\u2717 --body is required in non-interactive mode")
12042
+ );
12043
+ console.log();
12044
+ console.log("Usage:");
12045
+ console.log(
12046
+ chalk54.cyan(` vm0 secret set ${name} --body "your-secret-value"`)
12047
+ );
12048
+ process.exit(1);
12049
+ }
11880
12050
  const secret = await setSecret({
11881
12051
  name,
11882
12052
  value,
@@ -12203,63 +12373,61 @@ function validateAuthMethod(type, authMethodStr) {
12203
12373
  }
12204
12374
  return authMethodStr;
12205
12375
  }
12206
- function parseCredentials(type, authMethod, credentialArgs) {
12207
- const credentialsConfig = getCredentialsForAuthMethod(type, authMethod);
12208
- if (!credentialsConfig) {
12376
+ function parseSecrets(type, authMethod, secretArgs) {
12377
+ const secretsConfig = getSecretsForAuthMethod(type, authMethod);
12378
+ if (!secretsConfig) {
12209
12379
  console.error(chalk60.red(`\u2717 Invalid auth method "${authMethod}"`));
12210
12380
  process.exit(1);
12211
12381
  }
12212
- const credentialNames = Object.keys(credentialsConfig);
12213
- const firstArg = credentialArgs[0];
12214
- if (credentialArgs.length === 1 && firstArg && !firstArg.includes("=")) {
12215
- if (credentialNames.length !== 1) {
12382
+ const secretNames = Object.keys(secretsConfig);
12383
+ const firstArg = secretArgs[0];
12384
+ if (secretArgs.length === 1 && firstArg && !firstArg.includes("=")) {
12385
+ if (secretNames.length !== 1) {
12216
12386
  console.error(
12217
- chalk60.red(
12218
- "\u2717 Must use KEY=VALUE format for multi-credential auth methods"
12219
- )
12387
+ chalk60.red("\u2717 Must use KEY=VALUE format for multi-secret auth methods")
12220
12388
  );
12221
12389
  console.log();
12222
- console.log("Required credentials:");
12223
- for (const [name, fieldConfig] of Object.entries(credentialsConfig)) {
12390
+ console.log("Required secrets:");
12391
+ for (const [name, fieldConfig] of Object.entries(secretsConfig)) {
12224
12392
  const requiredNote = fieldConfig.required ? " (required)" : "";
12225
12393
  console.log(` ${chalk60.cyan(name)}${requiredNote}`);
12226
12394
  }
12227
12395
  process.exit(1);
12228
12396
  }
12229
- const firstCredentialName = credentialNames[0];
12230
- if (!firstCredentialName) {
12231
- console.error(chalk60.red("\u2717 No credentials defined for this auth method"));
12397
+ const firstSecretName = secretNames[0];
12398
+ if (!firstSecretName) {
12399
+ console.error(chalk60.red("\u2717 No secrets defined for this auth method"));
12232
12400
  process.exit(1);
12233
12401
  }
12234
- return { [firstCredentialName]: firstArg };
12402
+ return { [firstSecretName]: firstArg };
12235
12403
  }
12236
- const credentials = {};
12237
- for (const arg of credentialArgs) {
12404
+ const secrets = {};
12405
+ for (const arg of secretArgs) {
12238
12406
  const eqIndex = arg.indexOf("=");
12239
12407
  if (eqIndex === -1) {
12240
- console.error(chalk60.red(`\u2717 Invalid credential format "${arg}"`));
12408
+ console.error(chalk60.red(`\u2717 Invalid secret format "${arg}"`));
12241
12409
  console.log();
12242
12410
  console.log("Use KEY=VALUE format (e.g., AWS_REGION=us-east-1)");
12243
12411
  process.exit(1);
12244
12412
  }
12245
12413
  const key = arg.slice(0, eqIndex);
12246
12414
  const value = arg.slice(eqIndex + 1);
12247
- credentials[key] = value;
12415
+ secrets[key] = value;
12248
12416
  }
12249
- return credentials;
12417
+ return secrets;
12250
12418
  }
12251
- function validateCredentials(type, authMethod, credentials) {
12252
- const credentialsConfig = getCredentialsForAuthMethod(type, authMethod);
12253
- if (!credentialsConfig) {
12419
+ function validateSecrets(type, authMethod, secrets) {
12420
+ const secretsConfig = getSecretsForAuthMethod(type, authMethod);
12421
+ if (!secretsConfig) {
12254
12422
  console.error(chalk60.red(`\u2717 Invalid auth method "${authMethod}"`));
12255
12423
  process.exit(1);
12256
12424
  }
12257
- for (const [name, fieldConfig] of Object.entries(credentialsConfig)) {
12258
- if (fieldConfig.required && !credentials[name]) {
12259
- console.error(chalk60.red(`\u2717 Missing required credential: ${name}`));
12425
+ for (const [name, fieldConfig] of Object.entries(secretsConfig)) {
12426
+ if (fieldConfig.required && !secrets[name]) {
12427
+ console.error(chalk60.red(`\u2717 Missing required secret: ${name}`));
12260
12428
  console.log();
12261
- console.log("Required credentials:");
12262
- for (const [n, fc] of Object.entries(credentialsConfig)) {
12429
+ console.log("Required secrets:");
12430
+ for (const [n, fc] of Object.entries(secretsConfig)) {
12263
12431
  if (fc.required) {
12264
12432
  console.log(` ${chalk60.cyan(n)} - ${fc.label}`);
12265
12433
  }
@@ -12267,12 +12435,12 @@ function validateCredentials(type, authMethod, credentials) {
12267
12435
  process.exit(1);
12268
12436
  }
12269
12437
  }
12270
- for (const name of Object.keys(credentials)) {
12271
- if (!(name in credentialsConfig)) {
12272
- console.error(chalk60.red(`\u2717 Unknown credential: ${name}`));
12438
+ for (const name of Object.keys(secrets)) {
12439
+ if (!(name in secretsConfig)) {
12440
+ console.error(chalk60.red(`\u2717 Unknown secret: ${name}`));
12273
12441
  console.log();
12274
- console.log("Valid credentials:");
12275
- for (const [n, fc] of Object.entries(credentialsConfig)) {
12442
+ console.log("Valid secrets:");
12443
+ for (const [n, fc] of Object.entries(secretsConfig)) {
12276
12444
  const requiredNote = fc.required ? " (required)" : " (optional)";
12277
12445
  console.log(` ${chalk60.cyan(n)}${requiredNote}`);
12278
12446
  }
@@ -12321,37 +12489,37 @@ function handleNonInteractiveMode(options) {
12321
12489
  console.log("Example:");
12322
12490
  console.log(
12323
12491
  chalk60.cyan(
12324
- ` vm0 model-provider setup --type ${type} --auth-method ${authMethodNames[0]} --credential KEY=VALUE`
12492
+ ` vm0 model-provider setup --type ${type} --auth-method ${authMethodNames[0]} --secret KEY=VALUE`
12325
12493
  )
12326
12494
  );
12327
12495
  process.exit(1);
12328
12496
  }
12329
12497
  }
12330
- const credentials = parseCredentials(type, authMethod, options.credential);
12331
- validateCredentials(type, authMethod, credentials);
12498
+ const secrets = parseSecrets(type, authMethod, options.secret);
12499
+ validateSecrets(type, authMethod, secrets);
12332
12500
  return {
12333
12501
  type,
12334
12502
  authMethod,
12335
- credentials,
12503
+ secrets,
12336
12504
  selectedModel,
12337
12505
  isInteractiveMode: false
12338
12506
  };
12339
12507
  }
12340
- const credentialArgs = options.credential;
12341
- const firstArg = credentialArgs[0];
12508
+ const secretArgs = options.secret;
12509
+ const firstArg = secretArgs[0];
12342
12510
  if (!firstArg) {
12343
- console.error(chalk60.red("\u2717 Credential is required"));
12511
+ console.error(chalk60.red("\u2717 Secret is required"));
12344
12512
  process.exit(1);
12345
12513
  }
12346
- let credential;
12514
+ let secret;
12347
12515
  if (firstArg.includes("=")) {
12348
- credential = firstArg.slice(firstArg.indexOf("=") + 1);
12516
+ secret = firstArg.slice(firstArg.indexOf("=") + 1);
12349
12517
  } else {
12350
- credential = firstArg;
12518
+ secret = firstArg;
12351
12519
  }
12352
12520
  return {
12353
12521
  type,
12354
- credential,
12522
+ secret,
12355
12523
  selectedModel,
12356
12524
  isInteractiveMode: false
12357
12525
  };
@@ -12425,29 +12593,29 @@ async function promptForAuthMethod(type) {
12425
12593
  );
12426
12594
  return response.authMethod;
12427
12595
  }
12428
- function isSecretCredential(name) {
12596
+ function isSensitiveSecret(name) {
12429
12597
  const nonSecretPatterns = ["REGION", "ENDPOINT", "URL"];
12430
12598
  return !nonSecretPatterns.some(
12431
12599
  (pattern) => name.toUpperCase().includes(pattern)
12432
12600
  );
12433
12601
  }
12434
- async function promptForCredentials(type, authMethod) {
12435
- const credentialsConfig = getCredentialsForAuthMethod(type, authMethod);
12436
- if (!credentialsConfig) {
12602
+ async function promptForSecrets(type, authMethod) {
12603
+ const secretsConfig = getSecretsForAuthMethod(type, authMethod);
12604
+ if (!secretsConfig) {
12437
12605
  console.error(chalk60.red(`\u2717 Invalid auth method "${authMethod}"`));
12438
12606
  process.exit(1);
12439
12607
  }
12440
- const credentials = {};
12441
- for (const [name, fieldConfig] of Object.entries(credentialsConfig)) {
12608
+ const secrets = {};
12609
+ for (const [name, fieldConfig] of Object.entries(secretsConfig)) {
12442
12610
  if (fieldConfig.helpText) {
12443
12611
  console.log(chalk60.dim(fieldConfig.helpText));
12444
12612
  }
12445
- const isSecret = isSecretCredential(name);
12613
+ const isSensitive = isSensitiveSecret(name);
12446
12614
  const placeholder = "placeholder" in fieldConfig ? fieldConfig.placeholder : "";
12447
12615
  if (fieldConfig.required) {
12448
12616
  const response = await prompts2(
12449
12617
  {
12450
- type: isSecret ? "password" : "text",
12618
+ type: isSensitive ? "password" : "text",
12451
12619
  name: "value",
12452
12620
  message: `${fieldConfig.label}:`,
12453
12621
  initial: placeholder ? "" : void 0,
@@ -12455,11 +12623,11 @@ async function promptForCredentials(type, authMethod) {
12455
12623
  },
12456
12624
  { onCancel: () => process.exit(0) }
12457
12625
  );
12458
- credentials[name] = response.value;
12626
+ secrets[name] = response.value;
12459
12627
  } else {
12460
12628
  const response = await prompts2(
12461
12629
  {
12462
- type: isSecret ? "password" : "text",
12630
+ type: isSensitive ? "password" : "text",
12463
12631
  name: "value",
12464
12632
  message: `${fieldConfig.label} (optional):`
12465
12633
  },
@@ -12467,11 +12635,11 @@ async function promptForCredentials(type, authMethod) {
12467
12635
  );
12468
12636
  const value = response.value;
12469
12637
  if (value && value.trim()) {
12470
- credentials[name] = value.trim();
12638
+ secrets[name] = value.trim();
12471
12639
  }
12472
12640
  }
12473
12641
  }
12474
- return credentials;
12642
+ return secrets;
12475
12643
  }
12476
12644
  async function handleInteractiveMode() {
12477
12645
  if (!isInteractive()) {
@@ -12479,9 +12647,7 @@ async function handleInteractiveMode() {
12479
12647
  console.log();
12480
12648
  console.log("Use non-interactive mode:");
12481
12649
  console.log(
12482
- chalk60.cyan(
12483
- ' vm0 model-provider setup --type <type> --credential "<value>"'
12484
- )
12650
+ chalk60.cyan(' vm0 model-provider setup --type <type> --secret "<value>"')
12485
12651
  );
12486
12652
  process.exit(1);
12487
12653
  }
@@ -12514,32 +12680,8 @@ async function handleInteractiveMode() {
12514
12680
  { onCancel: () => process.exit(0) }
12515
12681
  );
12516
12682
  const type = typeResponse.type;
12517
- const checkResult = await checkModelProviderCredential(type);
12518
- if (checkResult.exists && checkResult.currentType === "user") {
12519
- const convertResponse = await prompts2(
12520
- {
12521
- type: "confirm",
12522
- name: "convert",
12523
- message: `Credential "${checkResult.credentialName}" already exists. Convert to model provider?`,
12524
- initial: true
12525
- },
12526
- { onCancel: () => process.exit(0) }
12527
- );
12528
- if (convertResponse.convert) {
12529
- const provider = await convertModelProviderCredential(type);
12530
- const defaultNote = provider.isDefault ? ` (default for ${provider.framework})` : "";
12531
- console.log(
12532
- chalk60.green(
12533
- `\u2713 Converted "${checkResult.credentialName}" to model provider${defaultNote}`
12534
- )
12535
- );
12536
- await promptSetAsDefault(type, provider.framework, provider.isDefault);
12537
- return null;
12538
- }
12539
- console.log(chalk60.dim("Aborted"));
12540
- process.exit(0);
12541
- }
12542
- if (checkResult.exists && checkResult.currentType === "model-provider") {
12683
+ const checkResult = await checkModelProviderSecret(type);
12684
+ if (checkResult.exists) {
12543
12685
  console.log();
12544
12686
  console.log(`"${type}" is already configured.`);
12545
12687
  console.log();
@@ -12549,8 +12691,8 @@ async function handleInteractiveMode() {
12549
12691
  name: "action",
12550
12692
  message: "",
12551
12693
  choices: [
12552
- { title: "Keep existing credential", value: "keep" },
12553
- { title: "Update credential", value: "update" }
12694
+ { title: "Keep existing secret", value: "keep" },
12695
+ { title: "Update secret", value: "update" }
12554
12696
  ]
12555
12697
  },
12556
12698
  { onCancel: () => process.exit(0) }
@@ -12559,7 +12701,7 @@ async function handleInteractiveMode() {
12559
12701
  const selectedModel2 = await promptForModelSelection(type);
12560
12702
  return {
12561
12703
  type,
12562
- keepExistingCredential: true,
12704
+ keepExistingSecret: true,
12563
12705
  selectedModel: selectedModel2,
12564
12706
  isInteractiveMode: true
12565
12707
  };
@@ -12571,38 +12713,33 @@ async function handleInteractiveMode() {
12571
12713
  console.log();
12572
12714
  if (hasAuthMethods(type)) {
12573
12715
  const authMethod = await promptForAuthMethod(type);
12574
- const credentials = await promptForCredentials(type, authMethod);
12716
+ const secrets = await promptForSecrets(type, authMethod);
12575
12717
  const selectedModel2 = await promptForModelSelection(type);
12576
12718
  return {
12577
12719
  type,
12578
12720
  authMethod,
12579
- credentials,
12721
+ secrets,
12580
12722
  selectedModel: selectedModel2,
12581
12723
  isInteractiveMode: true
12582
12724
  };
12583
12725
  }
12584
- const credentialLabel = "credentialLabel" in config ? config.credentialLabel : "credential";
12585
- const credentialResponse = await prompts2(
12726
+ const secretLabel = "secretLabel" in config ? config.secretLabel : "secret";
12727
+ const secretResponse = await prompts2(
12586
12728
  {
12587
12729
  type: "password",
12588
- name: "credential",
12589
- message: `Enter your ${credentialLabel}:`,
12590
- validate: (value) => value.length > 0 || `${credentialLabel} is required`
12730
+ name: "secret",
12731
+ message: `Enter your ${secretLabel}:`,
12732
+ validate: (value) => value.length > 0 || `${secretLabel} is required`
12591
12733
  },
12592
12734
  { onCancel: () => process.exit(0) }
12593
12735
  );
12594
- const credential = credentialResponse.credential;
12736
+ const secret = secretResponse.secret;
12595
12737
  const selectedModel = await promptForModelSelection(type);
12596
- return { type, credential, selectedModel, isInteractiveMode: true };
12738
+ return { type, secret, selectedModel, isInteractiveMode: true };
12597
12739
  }
12598
12740
  function handleSetupError2(error) {
12599
12741
  if (error instanceof Error) {
12600
- if (error.message.includes("already exists")) {
12601
- console.error(chalk60.red(`\u2717 ${error.message}`));
12602
- console.log();
12603
- console.log("To convert the existing credential, run:");
12604
- console.log(chalk60.cyan(" vm0 model-provider setup --convert"));
12605
- } else if (error.message.includes("Not authenticated")) {
12742
+ if (error.message.includes("Not authenticated")) {
12606
12743
  console.error(chalk60.red("\u2717 Not authenticated. Run: vm0 auth login"));
12607
12744
  } else {
12608
12745
  console.error(chalk60.red(`\u2717 ${error.message}`));
@@ -12628,34 +12765,31 @@ async function promptSetAsDefault(type, framework, isDefault) {
12628
12765
  console.log(chalk60.green(`\u2713 Default for ${framework} set to "${type}"`));
12629
12766
  }
12630
12767
  }
12631
- function collectCredentials(value, previous) {
12768
+ function collectSecrets(value, previous) {
12632
12769
  return previous.concat([value]);
12633
12770
  }
12634
12771
  var setupCommand2 = new Command62().name("setup").description("Configure a model provider").option("-t, --type <type>", "Provider type (for non-interactive mode)").option(
12635
- "-c, --credential <value>",
12636
- "Credential value (can be used multiple times, supports VALUE or KEY=VALUE format)",
12637
- collectCredentials,
12772
+ "-s, --secret <value>",
12773
+ "Secret value (can be used multiple times, supports VALUE or KEY=VALUE format)",
12774
+ collectSecrets,
12638
12775
  []
12639
12776
  ).option(
12640
12777
  "-a, --auth-method <method>",
12641
12778
  "Auth method (required for multi-auth providers like aws-bedrock)"
12642
- ).option("-m, --model <model>", "Model selection (for non-interactive mode)").option("--convert", "Convert existing user credential to model provider").action(
12779
+ ).option("-m, --model <model>", "Model selection (for non-interactive mode)").action(
12643
12780
  async (options) => {
12644
12781
  try {
12645
12782
  let input;
12646
- const shouldConvert = options.convert ?? false;
12647
- const credentialArgs = options.credential ?? [];
12648
- if (options.type && credentialArgs.length > 0) {
12783
+ const secretArgs = options.secret ?? [];
12784
+ if (options.type && secretArgs.length > 0) {
12649
12785
  input = handleNonInteractiveMode({
12650
12786
  type: options.type,
12651
- credential: credentialArgs,
12787
+ secret: secretArgs,
12652
12788
  authMethod: options.authMethod,
12653
12789
  model: options.model
12654
12790
  });
12655
- } else if (options.type || credentialArgs.length > 0) {
12656
- console.error(
12657
- chalk60.red("\u2717 Both --type and --credential are required")
12658
- );
12791
+ } else if (options.type || secretArgs.length > 0) {
12792
+ console.error(chalk60.red("\u2717 Both --type and --secret are required"));
12659
12793
  process.exit(1);
12660
12794
  } else {
12661
12795
  const result = await handleInteractiveMode();
@@ -12664,7 +12798,7 @@ var setupCommand2 = new Command62().name("setup").description("Configure a model
12664
12798
  }
12665
12799
  input = result;
12666
12800
  }
12667
- if (input.keepExistingCredential) {
12801
+ if (input.keepExistingSecret) {
12668
12802
  const provider2 = await updateModelProviderModel(
12669
12803
  input.type,
12670
12804
  input.selectedModel
@@ -12693,10 +12827,9 @@ var setupCommand2 = new Command62().name("setup").description("Configure a model
12693
12827
  }
12694
12828
  const { provider, created } = await upsertModelProvider({
12695
12829
  type: input.type,
12696
- credential: input.credential,
12830
+ secret: input.secret,
12697
12831
  authMethod: input.authMethod,
12698
- credentials: input.credentials,
12699
- convert: shouldConvert,
12832
+ secrets: input.secrets,
12700
12833
  selectedModel: input.selectedModel
12701
12834
  });
12702
12835
  const action = created ? "created" : "updated";
@@ -13030,17 +13163,16 @@ function getProviderChoices() {
13030
13163
  type,
13031
13164
  label: config.label,
13032
13165
  helpText: config.helpText,
13033
- credentialLabel: "credentialLabel" in config ? config.credentialLabel : "",
13166
+ secretLabel: "secretLabel" in config ? config.secretLabel : "",
13034
13167
  models: getModels(type),
13035
13168
  defaultModel: getDefaultModel(type)
13036
13169
  };
13037
13170
  });
13038
13171
  }
13039
- async function setupModelProvider(type, credential, options) {
13172
+ async function setupModelProvider(type, secret, options) {
13040
13173
  const response = await upsertModelProvider({
13041
13174
  type,
13042
- credential,
13043
- convert: options?.convert,
13175
+ secret,
13044
13176
  selectedModel: options?.selectedModel
13045
13177
  });
13046
13178
  return {
@@ -13231,12 +13363,10 @@ async function handleModelProvider(ctx) {
13231
13363
  step.detail(chalk66.dim(line));
13232
13364
  }
13233
13365
  }
13234
- const credential = await step.prompt(
13235
- () => promptPassword(
13236
- `Enter your ${selectedChoice?.credentialLabel ?? "credential"}:`
13237
- )
13366
+ const secret = await step.prompt(
13367
+ () => promptPassword(`Enter your ${selectedChoice?.secretLabel ?? "secret"}:`)
13238
13368
  );
13239
- if (!credential) {
13369
+ if (!secret) {
13240
13370
  console.log(chalk66.dim("Cancelled"));
13241
13371
  process.exit(0);
13242
13372
  }
@@ -13261,7 +13391,7 @@ async function handleModelProvider(ctx) {
13261
13391
  }
13262
13392
  selectedModel = modelSelection === "" ? void 0 : modelSelection;
13263
13393
  }
13264
- const result = await setupModelProvider(providerType, credential, {
13394
+ const result = await setupModelProvider(providerType, secret, {
13265
13395
  selectedModel
13266
13396
  });
13267
13397
  const modelNote = result.provider.selectedModel ? ` with model: ${result.provider.selectedModel}` : "";
@@ -13415,7 +13545,7 @@ var setupClaudeCommand = new Command67().name("setup-claude").description("Insta
13415
13545
 
13416
13546
  // src/index.ts
13417
13547
  var program = new Command68();
13418
- program.name("vm0").description("VM0 CLI - Build and run agents with natural language").version("9.20.2");
13548
+ program.name("vm0").description("VM0 CLI - Build and run agents with natural language").version("9.21.0");
13419
13549
  program.addCommand(authCommand);
13420
13550
  program.addCommand(infoCommand);
13421
13551
  program.addCommand(composeCommand);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@vm0/cli",
3
- "version": "9.20.2",
3
+ "version": "9.21.0",
4
4
  "description": "CLI application",
5
5
  "repository": {
6
6
  "type": "git",
@@ -15,6 +15,7 @@
15
15
  "."
16
16
  ],
17
17
  "dependencies": {
18
+ "@sentry/node": "^10.38.0",
18
19
  "@ts-rest/core": "3.53.0-rc.1",
19
20
  "ably": "^2.17.0",
20
21
  "chalk": "^5.6.0",