@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.
- package/index.js +362 -232
- 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
|
-
|
|
2172
|
+
secretName: "CLAUDE_CODE_OAUTH_TOKEN",
|
|
2096
2173
|
label: "Claude Code (OAuth Token)",
|
|
2097
|
-
|
|
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
|
-
|
|
2179
|
+
secretName: "ANTHROPIC_API_KEY",
|
|
2103
2180
|
label: "Anthropic API Key",
|
|
2104
|
-
|
|
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
|
-
|
|
2186
|
+
secretName: "OPENROUTER_API_KEY",
|
|
2110
2187
|
label: "OpenRouter",
|
|
2111
|
-
|
|
2188
|
+
secretLabel: "API key",
|
|
2112
2189
|
helpText: "Get your API key at: https://openrouter.ai/settings/keys",
|
|
2113
2190
|
environmentMapping: {
|
|
2114
|
-
ANTHROPIC_AUTH_TOKEN: "$
|
|
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
|
-
|
|
2209
|
+
secretName: "MOONSHOT_API_KEY",
|
|
2133
2210
|
label: "Moonshot (Kimi)",
|
|
2134
|
-
|
|
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: "$
|
|
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
|
-
|
|
2231
|
+
secretName: "MINIMAX_API_KEY",
|
|
2155
2232
|
label: "MiniMax",
|
|
2156
|
-
|
|
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: "$
|
|
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
|
-
|
|
2251
|
+
secretName: "DEEPSEEK_API_KEY",
|
|
2175
2252
|
label: "DeepSeek",
|
|
2176
|
-
|
|
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: "$
|
|
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
|
-
|
|
2271
|
+
secretName: "ZAI_API_KEY",
|
|
2195
2272
|
label: "Z.AI (GLM)",
|
|
2196
|
-
|
|
2273
|
+
secretLabel: "API key",
|
|
2197
2274
|
helpText: "Get your API key at: https://z.ai/model-api",
|
|
2198
2275
|
environmentMapping: {
|
|
2199
|
-
ANTHROPIC_AUTH_TOKEN: "$
|
|
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
|
-
|
|
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: "$
|
|
2238
|
-
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
|
-
|
|
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
|
|
2271
|
-
|
|
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
|
|
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: "$
|
|
2300
|
-
AWS_BEARER_TOKEN_BEDROCK: "$
|
|
2301
|
-
AWS_ACCESS_KEY_ID: "$
|
|
2302
|
-
AWS_SECRET_ACCESS_KEY: "$
|
|
2303
|
-
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
|
|
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?.
|
|
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
|
-
|
|
2369
|
-
// Legacy single-
|
|
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
|
-
|
|
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
|
-
|
|
2385
|
-
// Legacy single
|
|
2461
|
+
secret: z16.string().min(1).optional(),
|
|
2462
|
+
// Legacy single secret
|
|
2386
2463
|
authMethod: z16.string().optional(),
|
|
2387
2464
|
// For multi-auth providers
|
|
2388
|
-
|
|
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
|
|
2473
|
+
var checkSecretResponseSchema = z16.object({
|
|
2398
2474
|
exists: z16.boolean(),
|
|
2399
|
-
|
|
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:
|
|
2514
|
+
200: checkSecretResponseSchema,
|
|
2440
2515
|
401: apiErrorSchema,
|
|
2441
2516
|
500: apiErrorSchema
|
|
2442
2517
|
},
|
|
2443
|
-
summary: "Check if
|
|
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
|
|
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
|
|
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 =
|
|
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
|
|
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
|
|
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
|
|
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(
|
|
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 =
|
|
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(
|
|
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,
|
|
4656
|
+
await fs.writeFile(sparseFile, sparsePattern + "\n");
|
|
4509
4657
|
try {
|
|
4510
|
-
await execAsync(`git fetch --depth 1 origin "${
|
|
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 "${
|
|
4671
|
+
await execAsync(`git checkout "${branch}"`, { cwd: tempDir });
|
|
4672
|
+
const downloadedDir = parsed.path ? path.join(tempDir, parsed.path) : tempDir;
|
|
4526
4673
|
return {
|
|
4527
|
-
dir:
|
|
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
|
|
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
|
|
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(
|
|
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(
|
|
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(
|
|
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
|
|
5211
|
-
return
|
|
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.
|
|
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 (
|
|
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.
|
|
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
|
|
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(
|
|
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
|
|
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(
|
|
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
|
|
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(
|
|
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.
|
|
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
|
|
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(
|
|
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)").
|
|
11878
|
-
|
|
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
|
|
12207
|
-
const
|
|
12208
|
-
if (!
|
|
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
|
|
12213
|
-
const firstArg =
|
|
12214
|
-
if (
|
|
12215
|
-
if (
|
|
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
|
|
12223
|
-
for (const [name, fieldConfig] of Object.entries(
|
|
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
|
|
12230
|
-
if (!
|
|
12231
|
-
console.error(chalk60.red("\u2717 No
|
|
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 { [
|
|
12402
|
+
return { [firstSecretName]: firstArg };
|
|
12235
12403
|
}
|
|
12236
|
-
const
|
|
12237
|
-
for (const arg of
|
|
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
|
|
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
|
-
|
|
12415
|
+
secrets[key] = value;
|
|
12248
12416
|
}
|
|
12249
|
-
return
|
|
12417
|
+
return secrets;
|
|
12250
12418
|
}
|
|
12251
|
-
function
|
|
12252
|
-
const
|
|
12253
|
-
if (!
|
|
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(
|
|
12258
|
-
if (fieldConfig.required && !
|
|
12259
|
-
console.error(chalk60.red(`\u2717 Missing required
|
|
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
|
|
12262
|
-
for (const [n, fc] of Object.entries(
|
|
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(
|
|
12271
|
-
if (!(name in
|
|
12272
|
-
console.error(chalk60.red(`\u2717 Unknown
|
|
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
|
|
12275
|
-
for (const [n, fc] of Object.entries(
|
|
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]} --
|
|
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
|
|
12331
|
-
|
|
12498
|
+
const secrets = parseSecrets(type, authMethod, options.secret);
|
|
12499
|
+
validateSecrets(type, authMethod, secrets);
|
|
12332
12500
|
return {
|
|
12333
12501
|
type,
|
|
12334
12502
|
authMethod,
|
|
12335
|
-
|
|
12503
|
+
secrets,
|
|
12336
12504
|
selectedModel,
|
|
12337
12505
|
isInteractiveMode: false
|
|
12338
12506
|
};
|
|
12339
12507
|
}
|
|
12340
|
-
const
|
|
12341
|
-
const firstArg =
|
|
12508
|
+
const secretArgs = options.secret;
|
|
12509
|
+
const firstArg = secretArgs[0];
|
|
12342
12510
|
if (!firstArg) {
|
|
12343
|
-
console.error(chalk60.red("\u2717
|
|
12511
|
+
console.error(chalk60.red("\u2717 Secret is required"));
|
|
12344
12512
|
process.exit(1);
|
|
12345
12513
|
}
|
|
12346
|
-
let
|
|
12514
|
+
let secret;
|
|
12347
12515
|
if (firstArg.includes("=")) {
|
|
12348
|
-
|
|
12516
|
+
secret = firstArg.slice(firstArg.indexOf("=") + 1);
|
|
12349
12517
|
} else {
|
|
12350
|
-
|
|
12518
|
+
secret = firstArg;
|
|
12351
12519
|
}
|
|
12352
12520
|
return {
|
|
12353
12521
|
type,
|
|
12354
|
-
|
|
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
|
|
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
|
|
12435
|
-
const
|
|
12436
|
-
if (!
|
|
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
|
|
12441
|
-
for (const [name, fieldConfig] of Object.entries(
|
|
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
|
|
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:
|
|
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
|
-
|
|
12626
|
+
secrets[name] = response.value;
|
|
12459
12627
|
} else {
|
|
12460
12628
|
const response = await prompts2(
|
|
12461
12629
|
{
|
|
12462
|
-
type:
|
|
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
|
-
|
|
12638
|
+
secrets[name] = value.trim();
|
|
12471
12639
|
}
|
|
12472
12640
|
}
|
|
12473
12641
|
}
|
|
12474
|
-
return
|
|
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
|
|
12518
|
-
if (checkResult.exists
|
|
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
|
|
12553
|
-
{ title: "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
|
-
|
|
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
|
|
12716
|
+
const secrets = await promptForSecrets(type, authMethod);
|
|
12575
12717
|
const selectedModel2 = await promptForModelSelection(type);
|
|
12576
12718
|
return {
|
|
12577
12719
|
type,
|
|
12578
12720
|
authMethod,
|
|
12579
|
-
|
|
12721
|
+
secrets,
|
|
12580
12722
|
selectedModel: selectedModel2,
|
|
12581
12723
|
isInteractiveMode: true
|
|
12582
12724
|
};
|
|
12583
12725
|
}
|
|
12584
|
-
const
|
|
12585
|
-
const
|
|
12726
|
+
const secretLabel = "secretLabel" in config ? config.secretLabel : "secret";
|
|
12727
|
+
const secretResponse = await prompts2(
|
|
12586
12728
|
{
|
|
12587
12729
|
type: "password",
|
|
12588
|
-
name: "
|
|
12589
|
-
message: `Enter your ${
|
|
12590
|
-
validate: (value) => value.length > 0 || `${
|
|
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
|
|
12736
|
+
const secret = secretResponse.secret;
|
|
12595
12737
|
const selectedModel = await promptForModelSelection(type);
|
|
12596
|
-
return { type,
|
|
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("
|
|
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
|
|
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
|
-
"-
|
|
12636
|
-
"
|
|
12637
|
-
|
|
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)").
|
|
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
|
|
12647
|
-
|
|
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
|
-
|
|
12787
|
+
secret: secretArgs,
|
|
12652
12788
|
authMethod: options.authMethod,
|
|
12653
12789
|
model: options.model
|
|
12654
12790
|
});
|
|
12655
|
-
} else if (options.type ||
|
|
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.
|
|
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
|
-
|
|
12830
|
+
secret: input.secret,
|
|
12697
12831
|
authMethod: input.authMethod,
|
|
12698
|
-
|
|
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
|
-
|
|
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,
|
|
13172
|
+
async function setupModelProvider(type, secret, options) {
|
|
13040
13173
|
const response = await upsertModelProvider({
|
|
13041
13174
|
type,
|
|
13042
|
-
|
|
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
|
|
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 (!
|
|
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,
|
|
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.
|
|
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.
|
|
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",
|