@vm0/cli 9.244.5 → 9.244.7

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 (102) hide show
  1. package/{agent-NQVS6VCY.js → agent-2TIFNP32.js} +7 -7
  2. package/{banking-U5U2G6QH.js → banking-UR7XJI3L.js} +3 -3
  3. package/{chat-BGF7IB3O.js → chat-5N4C3FDV.js} +4 -4
  4. package/{chunk-UEGRDQR3.js → chunk-26BGLMA3.js} +4 -32
  5. package/chunk-26BGLMA3.js.map +1 -0
  6. package/{chunk-ZMTKJ4VW.js → chunk-5QJVQEHO.js} +69 -6
  7. package/chunk-5QJVQEHO.js.map +1 -0
  8. package/{chunk-SBH7L4UT.js → chunk-7KSTVBNN.js} +4 -4
  9. package/{chunk-624QMD56.js → chunk-BIJC6U3G.js} +2 -2
  10. package/{chunk-KS62N6VR.js → chunk-E32I3TNQ.js} +26 -129
  11. package/chunk-E32I3TNQ.js.map +1 -0
  12. package/{chunk-4V373IPM.js → chunk-JWDLLCI3.js} +2 -2
  13. package/{chunk-PBFD5MP4.js → chunk-M6GLCPCJ.js} +3 -3
  14. package/{chunk-VUUGKMER.js → chunk-NR6ANGRK.js} +41 -245
  15. package/chunk-NR6ANGRK.js.map +1 -0
  16. package/{chunk-NOUED6XP.js → chunk-QCG2H3VD.js} +2 -2
  17. package/{chunk-MKPBFN7W.js → chunk-STMJYQTH.js} +2 -2
  18. package/chunk-ZUSDQG2O.js +50 -0
  19. package/chunk-ZUSDQG2O.js.map +1 -0
  20. package/{computer-use-F4VFLO6X.js → computer-use-3WUKJYHK.js} +3 -3
  21. package/{connector-SWU3H7YL.js → connector-PDEOFNTE.js} +9 -21
  22. package/connector-PDEOFNTE.js.map +1 -0
  23. package/{credit-ZMXGA5CQ.js → credit-ET4RS32X.js} +4 -4
  24. package/{developer-support-IOTX3JWR.js → developer-support-3DJEJT2A.js} +3 -3
  25. package/{doctor-DTMFWDXL.js → doctor-F7OWYXXH.js} +3 -3
  26. package/{generate-IQUCOIYW.js → generate-4GKWSL6P.js} +4 -4
  27. package/{github-AJT3E56L.js → github-S5HFK2IC.js} +3 -3
  28. package/{goal-NCK5T57P.js → goal-ISJWIT2Q.js} +3 -3
  29. package/{host-BRKGWZLP.js → host-T52XQ2SZ.js} +4 -5
  30. package/{host-BRKGWZLP.js.map → host-T52XQ2SZ.js.map} +1 -1
  31. package/index.js +12 -2040
  32. package/index.js.map +1 -1
  33. package/{logs-WZVT4BS7.js → logs-D4IL5OLR.js} +8 -8
  34. package/{mail-QS4HABXH.js → mail-JXO3GW72.js} +5 -5
  35. package/{maps-3X6V34JQ.js → maps-T3YFBRLP.js} +3 -3
  36. package/{model-6ETRDASM.js → model-GJRTV6E5.js} +4 -4
  37. package/{model-provider-XEKOLWZY.js → model-provider-T4VN4HNU.js} +4 -4
  38. package/{org-DKGPME4L.js → org-GNNU77Y5.js} +3 -3
  39. package/package.json +1 -1
  40. package/{phone-6455TFON.js → phone-EQ4R2GBO.js} +3 -3
  41. package/{preference-2XMANS52.js → preference-3FHEQPKG.js} +3 -3
  42. package/{chunk-CK6ATTWW.js → resource-EOO2VATC.js} +133 -4
  43. package/resource-EOO2VATC.js.map +1 -0
  44. package/{scrape-CIP2FZED.js → scrape-TZCFJY6X.js} +3 -3
  45. package/{search-GCQ55FYS.js → search-RXP4DMUC.js} +7 -7
  46. package/{secret-NVLEVYXQ.js → secret-S4ZCVY2X.js} +3 -3
  47. package/{slack-EGYW76W2.js → slack-7YJFUJE6.js} +3 -3
  48. package/{teams-2D63XX2R.js → teams-45MMUROF.js} +3 -3
  49. package/{telegram-GQARG3MD.js → telegram-7ZCSI24W.js} +3 -3
  50. package/{variable-WMKLX7TF.js → variable-O33TDP4J.js} +3 -3
  51. package/{video-NAUNUYGP.js → video-D5LSABFJ.js} +2 -2
  52. package/{web-7U3YS3KP.js → web-JW7AH2UT.js} +3 -3
  53. package/{web-search-EIO3GVKH.js → web-search-MHFQFZS6.js} +3 -3
  54. package/{whoami-QZJAGTDW.js → whoami-5DJLOQUZ.js} +5 -5
  55. package/{workflow-RMJIYOUB.js → workflow-TXG3RBJR.js} +3 -3
  56. package/zero.js +35 -35
  57. package/chunk-CK6ATTWW.js.map +0 -1
  58. package/chunk-KS62N6VR.js.map +0 -1
  59. package/chunk-T6TZMDU6.js +0 -132
  60. package/chunk-T6TZMDU6.js.map +0 -1
  61. package/chunk-UEGRDQR3.js.map +0 -1
  62. package/chunk-VUUGKMER.js.map +0 -1
  63. package/chunk-ZMTKJ4VW.js.map +0 -1
  64. package/connector-SWU3H7YL.js.map +0 -1
  65. package/resource-MIFLTTK6.js +0 -143
  66. package/resource-MIFLTTK6.js.map +0 -1
  67. /package/{agent-NQVS6VCY.js.map → agent-2TIFNP32.js.map} +0 -0
  68. /package/{banking-U5U2G6QH.js.map → banking-UR7XJI3L.js.map} +0 -0
  69. /package/{chat-BGF7IB3O.js.map → chat-5N4C3FDV.js.map} +0 -0
  70. /package/{chunk-SBH7L4UT.js.map → chunk-7KSTVBNN.js.map} +0 -0
  71. /package/{chunk-624QMD56.js.map → chunk-BIJC6U3G.js.map} +0 -0
  72. /package/{chunk-4V373IPM.js.map → chunk-JWDLLCI3.js.map} +0 -0
  73. /package/{chunk-PBFD5MP4.js.map → chunk-M6GLCPCJ.js.map} +0 -0
  74. /package/{chunk-NOUED6XP.js.map → chunk-QCG2H3VD.js.map} +0 -0
  75. /package/{chunk-MKPBFN7W.js.map → chunk-STMJYQTH.js.map} +0 -0
  76. /package/{computer-use-F4VFLO6X.js.map → computer-use-3WUKJYHK.js.map} +0 -0
  77. /package/{credit-ZMXGA5CQ.js.map → credit-ET4RS32X.js.map} +0 -0
  78. /package/{developer-support-IOTX3JWR.js.map → developer-support-3DJEJT2A.js.map} +0 -0
  79. /package/{doctor-DTMFWDXL.js.map → doctor-F7OWYXXH.js.map} +0 -0
  80. /package/{generate-IQUCOIYW.js.map → generate-4GKWSL6P.js.map} +0 -0
  81. /package/{github-AJT3E56L.js.map → github-S5HFK2IC.js.map} +0 -0
  82. /package/{goal-NCK5T57P.js.map → goal-ISJWIT2Q.js.map} +0 -0
  83. /package/{logs-WZVT4BS7.js.map → logs-D4IL5OLR.js.map} +0 -0
  84. /package/{mail-QS4HABXH.js.map → mail-JXO3GW72.js.map} +0 -0
  85. /package/{maps-3X6V34JQ.js.map → maps-T3YFBRLP.js.map} +0 -0
  86. /package/{model-6ETRDASM.js.map → model-GJRTV6E5.js.map} +0 -0
  87. /package/{model-provider-XEKOLWZY.js.map → model-provider-T4VN4HNU.js.map} +0 -0
  88. /package/{org-DKGPME4L.js.map → org-GNNU77Y5.js.map} +0 -0
  89. /package/{phone-6455TFON.js.map → phone-EQ4R2GBO.js.map} +0 -0
  90. /package/{preference-2XMANS52.js.map → preference-3FHEQPKG.js.map} +0 -0
  91. /package/{scrape-CIP2FZED.js.map → scrape-TZCFJY6X.js.map} +0 -0
  92. /package/{search-GCQ55FYS.js.map → search-RXP4DMUC.js.map} +0 -0
  93. /package/{secret-NVLEVYXQ.js.map → secret-S4ZCVY2X.js.map} +0 -0
  94. /package/{slack-EGYW76W2.js.map → slack-7YJFUJE6.js.map} +0 -0
  95. /package/{teams-2D63XX2R.js.map → teams-45MMUROF.js.map} +0 -0
  96. /package/{telegram-GQARG3MD.js.map → telegram-7ZCSI24W.js.map} +0 -0
  97. /package/{variable-WMKLX7TF.js.map → variable-O33TDP4J.js.map} +0 -0
  98. /package/{video-NAUNUYGP.js.map → video-D5LSABFJ.js.map} +0 -0
  99. /package/{web-7U3YS3KP.js.map → web-JW7AH2UT.js.map} +0 -0
  100. /package/{web-search-EIO3GVKH.js.map → web-search-MHFQFZS6.js.map} +0 -0
  101. /package/{whoami-QZJAGTDW.js.map → whoami-5DJLOQUZ.js.map} +0 -0
  102. /package/{workflow-RMJIYOUB.js.map → workflow-TXG3RBJR.js.map} +0 -0
package/index.js CHANGED
@@ -2,84 +2,41 @@
2
2
  import { createRequire as __createRequire } from "node:module";
3
3
  const require = __createRequire(import.meta.url);
4
4
  import {
5
- checkDirectoryStatus,
6
- excludeVm0Filter,
7
- formatBytes,
8
- formatRelativeTime,
9
- listTarFiles,
10
- removeExtraFiles
11
- } from "./chunk-T6TZMDU6.js";
5
+ formatRelativeTime
6
+ } from "./chunk-ZUSDQG2O.js";
12
7
  import {
13
- EventRenderer,
14
- EventStreamNormalizer,
15
8
  collectArtifacts,
16
9
  collectKeyValue,
17
- collectLogItems,
18
10
  collectMounts,
19
11
  collectVolumeVersions,
20
- extractAndGroupVariables,
21
12
  extractSecretNames,
22
13
  extractVarNames,
23
- formatIsoTimestamp,
24
- getInstructionsFilename,
25
- getInstructionsStorageName,
26
- isSupportedFramework,
27
14
  isUUID,
28
15
  loadValues,
29
- parseBoundedLogCount,
30
16
  parseIdentifier,
31
17
  parsePermissionPolicies,
32
- parsePositiveLogCount,
33
- parseSearchQuery,
34
18
  parseTime,
35
19
  pollEvents,
36
20
  renderRunCreated,
37
- require_dist,
38
21
  showNextSteps
39
- } from "./chunk-KS62N6VR.js";
40
- import {
41
- Qn,
42
- So
43
- } from "./chunk-CK6ATTWW.js";
22
+ } from "./chunk-E32I3TNQ.js";
44
23
  import "./chunk-DWWE7STW.js";
45
- import {
46
- isInteractive,
47
- promptText
48
- } from "./chunk-JFY6GK7Y.js";
49
24
  import {
50
25
  ALL_RUN_STATUSES,
51
- agentDefinitionSchema,
52
26
  cancelRun,
53
- commitStorage,
54
- createOrUpdateCompose,
55
27
  createRun,
56
28
  directRunModelProviderTypeSchema,
57
- getAgentEvents,
58
29
  getCheckpoint,
59
30
  getComposeById,
60
31
  getComposeByName,
61
32
  getComposeVersion,
62
- getMetrics,
63
- getNetworkLogs,
64
33
  getRunQueue,
65
34
  getSession,
66
- getStorageDownload,
67
- getSystemLog,
68
- guaranteedConnectorProvidedBindingNames,
69
- listRuns,
70
- listStorages,
71
- listZeroConnectors,
72
- listZeroSecrets,
73
- listZeroVariables,
74
- prepareStorage,
75
- searchLogs,
76
- volumeConfigSchema
77
- } from "./chunk-VUUGKMER.js";
35
+ listRuns
36
+ } from "./chunk-NR6ANGRK.js";
78
37
  import "./chunk-LTDQISD7.js";
79
38
  import {
80
- ApiRequestError,
81
39
  clearConfig,
82
- external_exports,
83
40
  getActiveOrg,
84
41
  getApiUrl,
85
42
  getToken,
@@ -88,17 +45,16 @@ import {
88
45
  saveConfig,
89
46
  source_default,
90
47
  withErrorHandler
91
- } from "./chunk-UEGRDQR3.js";
48
+ } from "./chunk-26BGLMA3.js";
92
49
  import {
93
50
  configureGlobalProxyFromEnv
94
- } from "./chunk-PBFD5MP4.js";
51
+ } from "./chunk-M6GLCPCJ.js";
95
52
  import "./chunk-LRHXR7JT.js";
96
53
  import {
97
54
  Command,
98
55
  Option
99
56
  } from "./chunk-B3W2RUBP.js";
100
57
  import {
101
- __toESM,
102
58
  init_esm_shims
103
59
  } from "./chunk-DIRAZ3YX.js";
104
60
 
@@ -277,485 +233,11 @@ var setupTokenCommand = new Command().name("setup-token").description("Output au
277
233
  // src/commands/auth/index.ts
278
234
  var authCommand = new Command().name("auth").description("Authenticate vm0").addCommand(loginCommand).addCommand(logoutCommand).addCommand(statusCommand).addCommand(setupTokenCommand);
279
235
 
280
- // src/commands/compose/index.ts
281
- init_esm_shims();
282
- var import_yaml = __toESM(require_dist(), 1);
283
- import { readFile as readFile2 } from "fs/promises";
284
- import { existsSync as existsSync2 } from "fs";
285
- import { dirname } from "path";
286
-
287
- // src/lib/domain/yaml-validator.ts
288
- init_esm_shims();
289
- var cliAgentNameSchema = external_exports.string().min(3, "Agent name must be at least 3 characters").max(64, "Agent name must be 64 characters or less").regex(
290
- /^[a-zA-Z0-9]([a-zA-Z0-9-]{0,62}[a-zA-Z0-9])?$/,
291
- "Agent name must start and end with letter or number, and contain only letters, numbers, and hyphens"
292
- );
293
- var cliComposeSchema = external_exports.object({
294
- version: external_exports.string().min(1, "Missing config.version"),
295
- agents: external_exports.record(cliAgentNameSchema, agentDefinitionSchema),
296
- volumes: external_exports.record(external_exports.string(), volumeConfigSchema).optional()
297
- }).superRefine((config, ctx) => {
298
- const agentKeys = Object.keys(config.agents);
299
- if (agentKeys.length === 0) {
300
- ctx.addIssue({
301
- code: external_exports.ZodIssueCode.custom,
302
- message: "agents must have at least one agent defined",
303
- path: ["agents"]
304
- });
305
- return;
306
- }
307
- if (agentKeys.length > 1) {
308
- ctx.addIssue({
309
- code: external_exports.ZodIssueCode.custom,
310
- message: "Multiple agents not supported yet. Only one agent allowed.",
311
- path: ["agents"]
312
- });
313
- return;
314
- }
315
- const agentName = agentKeys[0];
316
- const agent = config.agents[agentName];
317
- const agentVolumes = agent?.volumes;
318
- if (agentVolumes && agentVolumes.length > 0) {
319
- if (!config.volumes) {
320
- ctx.addIssue({
321
- code: external_exports.ZodIssueCode.custom,
322
- message: "Agent references volumes but no volumes section defined. Each volume must have explicit name and version.",
323
- path: ["volumes"]
324
- });
325
- return;
326
- }
327
- for (const volDeclaration of agentVolumes) {
328
- const parts = volDeclaration.split(":");
329
- if (parts.length !== 2) {
330
- ctx.addIssue({
331
- code: external_exports.ZodIssueCode.custom,
332
- message: `Invalid volume declaration: ${volDeclaration}. Expected format: volume-key:/mount/path`,
333
- path: ["agents", agentName, "volumes"]
334
- });
335
- continue;
336
- }
337
- const volumeKey = parts[0].trim();
338
- if (!config.volumes[volumeKey]) {
339
- ctx.addIssue({
340
- code: external_exports.ZodIssueCode.custom,
341
- message: `Volume "${volumeKey}" is not defined in volumes section. Each volume must have explicit name and version.`,
342
- path: ["volumes", volumeKey]
343
- });
344
- }
345
- }
346
- }
347
- });
348
- function formatInvalidTypeIssue(path9, issue) {
349
- const runtimeReceived = Reflect.get(issue, "received");
350
- const received = typeof runtimeReceived === "string" ? runtimeReceived : void 0;
351
- const isMissing = received === "undefined" || issue.message.includes("received undefined") || issue.message === "Required";
352
- if (path9 === "version" && isMissing) {
353
- return "Missing config.version";
354
- }
355
- if (path9 === "agents" && isMissing) {
356
- return "Missing agents object in config";
357
- }
358
- if (path9.startsWith("volumes.") && path9.endsWith(".name")) {
359
- const volumeKey = path9.split(".")[1];
360
- return `Volume "${volumeKey}" must have a 'name' field (string)`;
361
- }
362
- if (path9.startsWith("volumes.") && path9.endsWith(".version")) {
363
- const volumeKey = path9.split(".")[1];
364
- return `Volume "${volumeKey}" must have a 'version' field (string)`;
365
- }
366
- if (issue.expected === "array") {
367
- const fieldName = path9.replace(/^agents\.[^.]+\./, "agent.");
368
- return `${fieldName} must be an array`;
369
- }
370
- if (issue.expected === "string" && received === "number") {
371
- const fieldName = path9.replace(/^agents\.[^.]+\./, "agent.");
372
- const match = fieldName.match(/^(agent\.[^.]+)\.\d+$/);
373
- if (match) {
374
- return `Each entry in ${match[1]?.replace("agent.", "")} must be a string`;
375
- }
376
- }
377
- return null;
378
- }
379
- function formatZodError(error) {
380
- const issue = error.issues[0];
381
- if (!issue) return "Validation failed";
382
- const path9 = issue.path.join(".");
383
- const message = issue.message;
384
- if (!path9) return message;
385
- if (issue.code === "invalid_type") {
386
- const formatted = formatInvalidTypeIssue(path9, issue);
387
- if (formatted) return formatted;
388
- }
389
- if (issue.code === "invalid_key" && path9.startsWith("agents.")) {
390
- return "Invalid agent name format. Must be 3-64 characters, letters, numbers, and hyphens only. Must start and end with letter or number.";
391
- }
392
- if (message === "Invalid key in record" && path9.startsWith("agents.")) {
393
- return "Invalid agent name format. Must be 3-64 characters, letters, numbers, and hyphens only. Must start and end with letter or number.";
394
- }
395
- if (issue.code === "custom") {
396
- return message;
397
- }
398
- if (path9.startsWith("agents.")) {
399
- const cleanPath = path9.replace(/^agents\.[^.]+\./, "agent.");
400
- if (message.startsWith("Invalid input:")) {
401
- const match = message.match(/expected (\w+), received (\w+)/);
402
- if (match && match[1] === "string" && match[2] === "number") {
403
- const fieldMatch = cleanPath.match(/^(agent\.[^.]+)\.\d+$/);
404
- if (fieldMatch) {
405
- return `Each entry in ${fieldMatch[1]?.replace("agent.", "")} must be a string`;
406
- }
407
- }
408
- }
409
- return `${cleanPath}: ${message}`;
410
- }
411
- return `${path9}: ${message}`;
412
- }
413
- var KNOWN_AGENT_FIELDS = Object.keys(agentDefinitionSchema.shape);
414
- function levenshteinDistance(a, b) {
415
- if (a === b) return 0;
416
- if (a.length === 0) return b.length;
417
- if (b.length === 0) return a.length;
418
- if (a.length > b.length) [a, b] = [b, a];
419
- const row = Array.from({ length: a.length + 1 }, (_, i) => {
420
- return i;
421
- });
422
- for (let j = 1; j <= b.length; j++) {
423
- let prev = j - 1;
424
- row[0] = j;
425
- for (let i = 1; i <= a.length; i++) {
426
- const cost = a[i - 1] === b[j - 1] ? 0 : 1;
427
- const current = Math.min(
428
- row[i] + 1,
429
- // deletion
430
- row[i - 1] + 1,
431
- // insertion
432
- prev + cost
433
- // substitution
434
- );
435
- prev = row[i];
436
- row[i] = current;
437
- }
438
- }
439
- return row[a.length];
440
- }
441
- function findSimilarField(unknown, knownFields) {
442
- let bestMatch = null;
443
- let bestDistance = Infinity;
444
- for (const known of knownFields) {
445
- if (unknown === known) continue;
446
- const distance = levenshteinDistance(unknown, known);
447
- if (distance <= 2 && distance < bestDistance) {
448
- bestDistance = distance;
449
- bestMatch = known;
450
- }
451
- if (unknown.length >= 3 && known.startsWith(unknown) && !bestMatch) {
452
- bestMatch = known;
453
- }
454
- }
455
- return bestMatch;
456
- }
457
- function extractAgentEntries(config) {
458
- if (!config || typeof config !== "object") return null;
459
- const cfg = config;
460
- const agents = cfg.agents;
461
- if (!agents || typeof agents !== "object" || Array.isArray(agents))
462
- return null;
463
- return agents;
464
- }
465
- function checkForFieldTypos(config) {
466
- const agents = extractAgentEntries(config);
467
- if (!agents) return null;
468
- const errors = [];
469
- for (const [agentName, agent] of Object.entries(agents)) {
470
- if (!agent || typeof agent !== "object" || Array.isArray(agent)) continue;
471
- for (const field of Object.keys(agent)) {
472
- if (KNOWN_AGENT_FIELDS.includes(field)) continue;
473
- const suggestion = findSimilarField(field, KNOWN_AGENT_FIELDS);
474
- if (suggestion) {
475
- errors.push(
476
- `Unknown field "${field}" in agent "${agentName}". Did you mean "${suggestion}"?`
477
- );
478
- }
479
- }
480
- }
481
- return errors.length > 0 ? errors.join("\n") : null;
482
- }
483
- function checkForDeprecatedProvider(config) {
484
- const agents = extractAgentEntries(config);
485
- if (!agents) return null;
486
- for (const agent of Object.values(agents)) {
487
- if (agent && typeof agent === "object" && !Array.isArray(agent)) {
488
- if ("provider" in agent && !("framework" in agent)) {
489
- const providerValue = agent.provider;
490
- return `'provider' field is deprecated. Use 'framework' instead.
491
-
492
- Change in your vm0.yaml:
493
- - provider: ${providerValue}
494
- + framework: ${providerValue}`;
495
- }
496
- }
497
- }
498
- return null;
499
- }
500
- function validateAgentCompose(config) {
501
- const deprecationError = checkForDeprecatedProvider(config);
502
- if (deprecationError) {
503
- return { valid: false, error: deprecationError };
504
- }
505
- const typoError = checkForFieldTypos(config);
506
- if (typoError) {
507
- return { valid: false, error: typoError };
508
- }
509
- if (config && typeof config === "object" && Array.isArray(config.agents)) {
510
- return {
511
- valid: false,
512
- error: "agents must be an object, not an array. Use format: agents: { agent-name: { ... } }"
513
- };
514
- }
515
- if (!config || typeof config !== "object") {
516
- return { valid: false, error: "Config must be an object" };
517
- }
518
- const result = cliComposeSchema.safeParse(config);
519
- if (!result.success) {
520
- return { valid: false, error: formatZodError(result.error) };
521
- }
522
- return { valid: true };
523
- }
524
-
525
- // src/lib/storage/system-storage.ts
236
+ // src/commands/run/index.ts
526
237
  init_esm_shims();
527
- import * as fs2 from "fs/promises";
528
- import * as path2 from "path";
529
- import * as os2 from "os";
530
238
 
531
- // src/lib/storage/direct-upload.ts
239
+ // src/commands/run/run.ts
532
240
  init_esm_shims();
533
- import { createHash } from "crypto";
534
- import * as fs from "fs";
535
- import * as path from "path";
536
- import * as os from "os";
537
- async function hashFileStream(filePath) {
538
- return new Promise((resolve, reject) => {
539
- const hash = createHash("sha256");
540
- const stream = fs.createReadStream(filePath);
541
- stream.on("data", (chunk) => {
542
- return hash.update(chunk);
543
- });
544
- stream.on("end", () => {
545
- return resolve(hash.digest("hex"));
546
- });
547
- stream.on("error", reject);
548
- });
549
- }
550
- async function getAllFiles(dirPath, baseDir = dirPath) {
551
- const files = [];
552
- const entries = await fs.promises.readdir(dirPath, { withFileTypes: true });
553
- for (const entry of entries) {
554
- const fullPath = path.join(dirPath, entry.name);
555
- const relativePath = path.relative(baseDir, fullPath);
556
- if (relativePath.startsWith(".vm0")) {
557
- continue;
558
- }
559
- if (entry.isDirectory()) {
560
- const subFiles = await getAllFiles(fullPath, baseDir);
561
- files.push(...subFiles);
562
- } else {
563
- files.push(fullPath);
564
- }
565
- }
566
- return files;
567
- }
568
- async function collectFileMetadata(cwd, files, onProgress) {
569
- const fileEntries = [];
570
- for (let i = 0; i < files.length; i++) {
571
- const file = files[i];
572
- const relativePath = path.relative(cwd, file);
573
- const [hash, stats] = await Promise.all([
574
- hashFileStream(file),
575
- fs.promises.stat(file)
576
- ]);
577
- fileEntries.push({
578
- path: relativePath,
579
- hash,
580
- size: stats.size
581
- });
582
- if (onProgress && (i + 1) % 100 === 0) {
583
- onProgress(`Hashing files... ${i + 1}/${files.length}`);
584
- }
585
- }
586
- return fileEntries;
587
- }
588
- async function createArchive(cwd, files) {
589
- const tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), "vm0-"));
590
- const tarPath = path.join(tmpDir, "archive.tar.gz");
591
- try {
592
- const relativePaths = files.map((file) => {
593
- return path.relative(cwd, file);
594
- });
595
- if (relativePaths.length > 0) {
596
- await Qn(
597
- {
598
- gzip: true,
599
- file: tarPath,
600
- cwd
601
- },
602
- relativePaths
603
- );
604
- } else {
605
- await Qn(
606
- {
607
- gzip: true,
608
- file: tarPath,
609
- cwd,
610
- filter: excludeVm0Filter
611
- },
612
- ["."]
613
- );
614
- }
615
- const tarBuffer = await fs.promises.readFile(tarPath);
616
- return tarBuffer;
617
- } finally {
618
- if (fs.existsSync(tarPath)) {
619
- await fs.promises.unlink(tarPath);
620
- }
621
- await fs.promises.rmdir(tmpDir);
622
- }
623
- }
624
- function createManifest(files) {
625
- const manifest = {
626
- version: 1,
627
- files,
628
- createdAt: (/* @__PURE__ */ new Date()).toISOString()
629
- };
630
- return Buffer.from(JSON.stringify(manifest, null, 2));
631
- }
632
- function sleep(ms) {
633
- return new Promise((resolve) => {
634
- return setTimeout(resolve, ms);
635
- });
636
- }
637
- async function uploadToPresignedUrl(presignedUrl, data, contentType, maxRetries = 3) {
638
- let lastError = null;
639
- for (let attempt = 1; attempt <= maxRetries; attempt++) {
640
- try {
641
- const response = await fetch(presignedUrl, {
642
- method: "PUT",
643
- body: data,
644
- headers: {
645
- "Content-Type": contentType
646
- }
647
- });
648
- if (response.ok) {
649
- return;
650
- }
651
- if (response.status >= 400 && response.status < 500) {
652
- const text2 = await response.text();
653
- throw new Error(`S3 upload failed: ${response.status} - ${text2}`);
654
- }
655
- const text = await response.text();
656
- lastError = new Error(`S3 upload failed: ${response.status} - ${text}`);
657
- } catch (error) {
658
- lastError = error instanceof Error ? error : new Error("Unknown upload error");
659
- if (lastError.message.includes("400") || lastError.message.includes("403")) {
660
- throw lastError;
661
- }
662
- }
663
- if (attempt < maxRetries) {
664
- const backoffMs = Math.pow(2, attempt - 1) * 1e3;
665
- await sleep(backoffMs);
666
- }
667
- }
668
- throw lastError || new Error("S3 upload failed after retries");
669
- }
670
- async function directUpload(storageName, storageType, cwd, options) {
671
- const { onProgress, force } = options || {};
672
- onProgress?.("Collecting files...");
673
- const files = await getAllFiles(cwd);
674
- onProgress?.("Computing file hashes...");
675
- const fileEntries = await collectFileMetadata(cwd, files, onProgress);
676
- onProgress?.("Preparing upload...");
677
- const prepareResult = await prepareStorage({
678
- storageName,
679
- storageType,
680
- files: fileEntries,
681
- force
682
- });
683
- if (prepareResult.existing) {
684
- onProgress?.("Version exists, updating HEAD...");
685
- const commitResult2 = await commitStorage({
686
- storageName,
687
- storageType,
688
- versionId: prepareResult.versionId,
689
- files: fileEntries
690
- });
691
- return {
692
- versionId: commitResult2.versionId,
693
- size: commitResult2.size,
694
- fileCount: commitResult2.fileCount,
695
- deduplicated: true,
696
- empty: commitResult2.fileCount === 0
697
- };
698
- }
699
- if (files.length > 0) {
700
- onProgress?.("Compressing files...");
701
- const archiveBuffer = await createArchive(cwd, files);
702
- onProgress?.("Uploading archive to S3...");
703
- if (!prepareResult.uploads) {
704
- throw new Error("No upload URLs received from prepare endpoint");
705
- }
706
- await uploadToPresignedUrl(
707
- prepareResult.uploads.archive.presignedUrl,
708
- archiveBuffer,
709
- "application/gzip"
710
- );
711
- }
712
- onProgress?.("Uploading manifest...");
713
- if (!prepareResult.uploads) {
714
- throw new Error("No upload URLs received from prepare endpoint");
715
- }
716
- const manifestBuffer = createManifest(fileEntries);
717
- await uploadToPresignedUrl(
718
- prepareResult.uploads.manifest.presignedUrl,
719
- manifestBuffer,
720
- "application/json"
721
- );
722
- onProgress?.("Committing...");
723
- const commitResult = await commitStorage({
724
- storageName,
725
- storageType,
726
- versionId: prepareResult.versionId,
727
- files: fileEntries
728
- });
729
- return {
730
- versionId: commitResult.versionId,
731
- size: commitResult.size,
732
- fileCount: commitResult.fileCount,
733
- deduplicated: commitResult.deduplicated || false,
734
- empty: commitResult.fileCount === 0
735
- };
736
- }
737
-
738
- // src/lib/storage/system-storage.ts
739
- async function uploadInstructions(agentName, instructionsFilePath, basePath, framework) {
740
- const storageName = getInstructionsStorageName(agentName.toLowerCase());
741
- const absolutePath = path2.isAbsolute(instructionsFilePath) ? instructionsFilePath : path2.join(basePath, instructionsFilePath);
742
- const content = await fs2.readFile(absolutePath, "utf8");
743
- const tmpDir = await fs2.mkdtemp(path2.join(os2.tmpdir(), "vm0-instructions-"));
744
- const instructionsDir = path2.join(tmpDir, "instructions");
745
- await fs2.mkdir(instructionsDir);
746
- const filename = getInstructionsFilename(framework);
747
- await fs2.writeFile(path2.join(instructionsDir, filename), content);
748
- try {
749
- const result = await directUpload(storageName, "volume", instructionsDir);
750
- return {
751
- name: storageName,
752
- versionId: result.versionId,
753
- action: result.deduplicated ? "deduplicated" : "created"
754
- };
755
- } finally {
756
- await fs2.rm(tmpDir, { recursive: true, force: true });
757
- }
758
- }
759
241
 
760
242
  // src/lib/utils/update-checker.ts
761
243
  init_esm_shims();
@@ -884,228 +366,7 @@ async function waitForSilentUpgrade(timeout = TIMEOUT_MS) {
884
366
  }
885
367
  }
886
368
 
887
- // src/commands/compose/index.ts
888
- var DEFAULT_CONFIG_FILE = "vm0.yaml";
889
- function getSecretsFromComposeContent(content) {
890
- const grouped = extractAndGroupVariables(content);
891
- return new Set(
892
- grouped.secrets.map((r) => {
893
- return r.name;
894
- })
895
- );
896
- }
897
- function getVarsFromComposeContent(content) {
898
- const grouped = extractAndGroupVariables(content);
899
- return new Set(
900
- grouped.vars.map((r) => {
901
- return r.name;
902
- })
903
- );
904
- }
905
- async function loadAndValidateConfig(configFile) {
906
- if (!existsSync2(configFile)) {
907
- throw new Error(`Config file not found: ${configFile}`);
908
- }
909
- const content = await readFile2(configFile, "utf8");
910
- let config;
911
- try {
912
- config = (0, import_yaml.parse)(content);
913
- } catch (error) {
914
- const message = error instanceof Error ? error.message : "Unknown error";
915
- throw new Error(`Invalid YAML format: ${message}`);
916
- }
917
- const validation = validateAgentCompose(config);
918
- if (!validation.valid) {
919
- throw new Error(validation.error);
920
- }
921
- const cfg = config;
922
- const agentsConfig = cfg.agents;
923
- const agentName = Object.keys(agentsConfig)[0];
924
- const agent = agentsConfig[agentName];
925
- const basePath = dirname(configFile);
926
- return { config, agentName, agent, basePath };
927
- }
928
- async function uploadInstructionsIfPresent(agentName, agent, basePath, jsonMode) {
929
- if (!agent.instructions) return;
930
- if (!jsonMode) {
931
- console.log(`Uploading instructions: ${agent.instructions}`);
932
- }
933
- const result = await uploadInstructions(
934
- agentName,
935
- agent.instructions,
936
- basePath,
937
- agent.framework
938
- );
939
- if (!jsonMode) {
940
- console.log(
941
- source_default.green(
942
- `\u2713 Instructions ${result.action === "deduplicated" ? "(unchanged)" : "uploaded"}: ${result.versionId.slice(0, 8)}`
943
- )
944
- );
945
- }
946
- }
947
- function stripSkillsFromAgents(config) {
948
- if (!config || typeof config !== "object") return config;
949
- const cfg = structuredClone(config);
950
- const agents = cfg.agents;
951
- if (agents && typeof agents === "object" && !Array.isArray(agents)) {
952
- for (const agent of Object.values(agents)) {
953
- if (agent && typeof agent === "object" && !Array.isArray(agent)) {
954
- delete agent.skills;
955
- }
956
- }
957
- }
958
- return cfg;
959
- }
960
- async function checkAndPromptMissingItems(config, options) {
961
- const requiredSecrets = getSecretsFromComposeContent(config);
962
- const requiredVars = getVarsFromComposeContent(config);
963
- if (requiredSecrets.size === 0 && requiredVars.size === 0) {
964
- return { missingSecrets: [], missingVars: [] };
965
- }
966
- const [secretsResponse, variablesResponse, connectorsResponse] = await Promise.all([
967
- requiredSecrets.size > 0 ? listZeroSecrets() : { secrets: [] },
968
- requiredVars.size > 0 ? listZeroVariables() : { variables: [] },
969
- listZeroConnectors()
970
- ]);
971
- const existingSecretNames = new Set(
972
- secretsResponse.secrets.map((s) => {
973
- return s.name;
974
- })
975
- );
976
- const existingVarNames = new Set(
977
- variablesResponse.variables.map((v) => {
978
- return v.name;
979
- })
980
- );
981
- const guaranteedConnectorProvidedSecretNames = guaranteedConnectorProvidedBindingNames({
982
- bindings: connectorsResponse.connectorProvidedBindings,
983
- namespace: "secrets"
984
- });
985
- const guaranteedConnectorProvidedVarNames = guaranteedConnectorProvidedBindingNames({
986
- bindings: connectorsResponse.connectorProvidedBindings,
987
- namespace: "vars"
988
- });
989
- const missingSecrets = [...requiredSecrets].filter((name) => {
990
- return !existingSecretNames.has(name) && !guaranteedConnectorProvidedSecretNames.has(name);
991
- });
992
- const missingVars = [...requiredVars].filter((name) => {
993
- return !existingVarNames.has(name) && !guaranteedConnectorProvidedVarNames.has(name);
994
- });
995
- if (missingSecrets.length === 0 && missingVars.length === 0) {
996
- return { missingSecrets: [], missingVars: [] };
997
- }
998
- if (!options.json) {
999
- console.log();
1000
- console.log(source_default.yellow("\u26A0 Missing secrets/variables detected:"));
1001
- if (missingSecrets.length > 0) {
1002
- console.log(source_default.yellow(` Secrets: ${missingSecrets.join(", ")}`));
1003
- }
1004
- if (missingVars.length > 0) {
1005
- console.log(source_default.yellow(` Variables: ${missingVars.join(", ")}`));
1006
- }
1007
- console.log();
1008
- }
1009
- return { missingSecrets, missingVars };
1010
- }
1011
- async function finalizeCompose(config, agent, options) {
1012
- if (!options.json) {
1013
- console.log("Uploading compose...");
1014
- }
1015
- const contentToPost = stripSkillsFromAgents(config);
1016
- const response = await createOrUpdateCompose({ content: contentToPost });
1017
- const shortVersionId = response.versionId.slice(0, 8);
1018
- const displayName = response.name;
1019
- const result = {
1020
- composeId: response.composeId,
1021
- composeName: response.name,
1022
- versionId: response.versionId,
1023
- action: response.action,
1024
- displayName
1025
- };
1026
- if (!options.json) {
1027
- const missingItems = await checkAndPromptMissingItems(config, options);
1028
- if (missingItems.missingSecrets.length > 0 || missingItems.missingVars.length > 0) {
1029
- result.missingSecrets = missingItems.missingSecrets;
1030
- result.missingVars = missingItems.missingVars;
1031
- }
1032
- }
1033
- if (!options.json) {
1034
- if (response.action === "created") {
1035
- console.log(source_default.green(`\u2713 Compose created: ${displayName}`));
1036
- } else {
1037
- console.log(source_default.green(`\u2713 Compose version exists: ${displayName}`));
1038
- }
1039
- console.log(source_default.dim(` Version: ${shortVersionId}`));
1040
- console.log();
1041
- console.log(" Run your agent:");
1042
- console.log(
1043
- source_default.cyan(
1044
- ` vm0 run ${displayName}:${shortVersionId} --artifact <artifact> "your prompt"`
1045
- )
1046
- );
1047
- }
1048
- if (options.autoUpdate !== false) {
1049
- await waitForSilentUpgrade();
1050
- }
1051
- return result;
1052
- }
1053
- var composeCommand = new Command().name("compose").description("Create or update agent compose (e.g., vm0.yaml)").argument(
1054
- "[agent-yaml]",
1055
- `Path to agent YAML file (default: ${DEFAULT_CONFIG_FILE})`
1056
- ).option("-y, --yes", "Skip confirmation prompts").option(
1057
- "--experimental-shared-compose",
1058
- "[deprecated] No longer required, kept for backward compatibility"
1059
- ).option("--json", "Output JSON for scripts (suppresses interactive output)").option(
1060
- "--porcelain",
1061
- "[deprecated: use --json] Output JSON for scripts",
1062
- false
1063
- ).addOption(new Option("--no-auto-update").hideHelp()).action(
1064
- withErrorHandler(
1065
- async (configFile, options) => {
1066
- const resolvedConfigFile = configFile ?? DEFAULT_CONFIG_FILE;
1067
- if (options.porcelain && !options.json) {
1068
- console.error(
1069
- source_default.yellow("\u26A0 --porcelain is deprecated, use --json instead")
1070
- );
1071
- options.json = true;
1072
- }
1073
- if (options.json) {
1074
- options.yes = true;
1075
- options.autoUpdate = false;
1076
- }
1077
- if (options.autoUpdate !== false) {
1078
- await startSilentUpgrade("9.244.5");
1079
- }
1080
- try {
1081
- const { config, agentName, agent, basePath } = await loadAndValidateConfig(resolvedConfigFile);
1082
- await uploadInstructionsIfPresent(
1083
- agentName,
1084
- agent,
1085
- basePath,
1086
- options.json
1087
- );
1088
- const result = await finalizeCompose(config, agent, options);
1089
- if (options.json) {
1090
- console.log(JSON.stringify(result));
1091
- }
1092
- } catch (error) {
1093
- if (options.json) {
1094
- const message = error instanceof Error ? error.message : "An unexpected error occurred";
1095
- console.log(JSON.stringify({ error: message }));
1096
- process.exit(1);
1097
- }
1098
- throw error;
1099
- }
1100
- }
1101
- )
1102
- );
1103
-
1104
- // src/commands/run/index.ts
1105
- init_esm_shims();
1106
-
1107
369
  // src/commands/run/run.ts
1108
- init_esm_shims();
1109
370
  function parseModelProviderType(value) {
1110
371
  if (value === void 0) {
1111
372
  return void 0;
@@ -1172,7 +433,7 @@ var mainRunCommand = new Command().name("run").description("Run an agent").argum
1172
433
  withErrorHandler(
1173
434
  async (identifier, prompt, options) => {
1174
435
  if (options.autoUpdate !== false) {
1175
- await startSilentUpgrade("9.244.5");
436
+ await startSilentUpgrade("9.244.7");
1176
437
  }
1177
438
  const { name, version } = parseIdentifier(identifier);
1178
439
  let composeId;
@@ -1184,11 +445,7 @@ var mainRunCommand = new Command().name("run").description("Run an agent").argum
1184
445
  } else {
1185
446
  const compose = await getComposeByName(name);
1186
447
  if (!compose) {
1187
- throw new Error(`Agent not found: ${identifier}`, {
1188
- cause: new Error(
1189
- "Make sure you've composed the agent with: vm0 compose"
1190
- )
1191
- });
448
+ throw new Error(`Agent not found: ${identifier}`);
1192
449
  }
1193
450
  composeId = compose.id;
1194
451
  composeContent = compose.content;
@@ -1652,1287 +909,6 @@ mainRunCommand.addCommand(killCommand);
1652
909
  mainRunCommand.addCommand(queueCommand);
1653
910
  var runCommand = mainRunCommand;
1654
911
 
1655
- // src/commands/volume/index.ts
1656
- init_esm_shims();
1657
-
1658
- // src/commands/volume/init.ts
1659
- init_esm_shims();
1660
- import path4 from "path";
1661
-
1662
- // src/lib/storage/storage-utils.ts
1663
- init_esm_shims();
1664
- var import_yaml2 = __toESM(require_dist(), 1);
1665
- import { readFile as readFile3, writeFile as writeFile2, mkdir as mkdir2 } from "fs/promises";
1666
- import { existsSync as existsSync3 } from "fs";
1667
- import path3 from "path";
1668
- var CONFIG_DIR = ".vm0";
1669
- var CONFIG_FILE = "storage.yaml";
1670
- function isValidStorageName(name) {
1671
- if (name.length < 3 || name.length > 64) {
1672
- return false;
1673
- }
1674
- const pattern = /^[a-z0-9][a-z0-9-]{1,62}[a-z0-9]$/;
1675
- return pattern.test(name) && !name.includes("--");
1676
- }
1677
- async function readStorageConfig(basePath = process.cwd()) {
1678
- const configPath = path3.join(basePath, CONFIG_DIR, CONFIG_FILE);
1679
- const legacyConfigPath = path3.join(basePath, CONFIG_DIR, "volume.yaml");
1680
- let actualPath = null;
1681
- if (existsSync3(configPath)) {
1682
- actualPath = configPath;
1683
- } else if (existsSync3(legacyConfigPath)) {
1684
- actualPath = legacyConfigPath;
1685
- }
1686
- if (!actualPath) {
1687
- return null;
1688
- }
1689
- const content = await readFile3(actualPath, "utf8");
1690
- const config = (0, import_yaml2.parse)(content);
1691
- if (!config.type) {
1692
- config.type = "volume";
1693
- }
1694
- return config;
1695
- }
1696
- async function writeStorageConfig(storageName, basePath = process.cwd(), type = "volume") {
1697
- const configDir = path3.join(basePath, CONFIG_DIR);
1698
- const configPath = path3.join(configDir, CONFIG_FILE);
1699
- if (!existsSync3(configDir)) {
1700
- await mkdir2(configDir, { recursive: true });
1701
- }
1702
- const config = {
1703
- name: storageName,
1704
- type
1705
- };
1706
- const yamlContent = (0, import_yaml2.stringify)(config);
1707
- await writeFile2(configPath, yamlContent, "utf8");
1708
- }
1709
-
1710
- // src/commands/volume/init.ts
1711
- var initCommand = new Command().name("init").description("Initialize a volume in the current directory").option("-n, --name <name>", "Volume name (required in non-interactive mode)").action(
1712
- withErrorHandler(async (options) => {
1713
- const cwd = process.cwd();
1714
- const dirName = path4.basename(cwd);
1715
- const existingConfig = await readStorageConfig(cwd);
1716
- if (existingConfig) {
1717
- console.log(
1718
- source_default.yellow(`Volume already initialized: ${existingConfig.name}`)
1719
- );
1720
- console.log(
1721
- source_default.dim(`Config file: ${path4.join(cwd, ".vm0", "storage.yaml")}`)
1722
- );
1723
- return;
1724
- }
1725
- let volumeName;
1726
- if (options.name) {
1727
- volumeName = options.name;
1728
- } else if (!isInteractive()) {
1729
- throw new Error("--name flag is required in non-interactive mode", {
1730
- cause: new Error("Usage: vm0 volume init --name <volume-name>")
1731
- });
1732
- } else {
1733
- const defaultName = isValidStorageName(dirName) ? dirName : void 0;
1734
- const name = await promptText(
1735
- "Enter volume name",
1736
- defaultName,
1737
- (value) => {
1738
- if (!isValidStorageName(value)) {
1739
- return "Must be 3-64 characters, lowercase alphanumeric with hyphens";
1740
- }
1741
- return true;
1742
- }
1743
- );
1744
- if (name === void 0) {
1745
- console.log(source_default.dim("Cancelled"));
1746
- return;
1747
- }
1748
- volumeName = name;
1749
- }
1750
- if (!isValidStorageName(volumeName)) {
1751
- throw new Error(`Invalid volume name: "${volumeName}"`, {
1752
- cause: new Error(
1753
- "Volume names must be 3-64 characters, lowercase alphanumeric with hyphens"
1754
- )
1755
- });
1756
- }
1757
- await writeStorageConfig(volumeName, cwd);
1758
- console.log(source_default.green(`\u2713 Initialized volume: ${volumeName}`));
1759
- console.log(
1760
- source_default.dim(
1761
- ` Config saved to ${path4.join(cwd, ".vm0", "storage.yaml")}`
1762
- )
1763
- );
1764
- })
1765
- );
1766
-
1767
- // src/commands/volume/push.ts
1768
- init_esm_shims();
1769
- var pushCommand = new Command().name("push").description("Push local files to cloud volume").option(
1770
- "-f, --force",
1771
- "Force upload even if content unchanged (recreate archive)"
1772
- ).action(
1773
- withErrorHandler(async (options) => {
1774
- const cwd = process.cwd();
1775
- const config = await readStorageConfig(cwd);
1776
- if (!config) {
1777
- throw new Error("No volume initialized in this directory", {
1778
- cause: new Error("Run: vm0 volume init")
1779
- });
1780
- }
1781
- console.log(`Pushing volume: ${config.name}`);
1782
- const result = await directUpload(config.name, "volume", cwd, {
1783
- onProgress: (message) => {
1784
- console.log(source_default.dim(message));
1785
- },
1786
- force: options.force
1787
- });
1788
- const shortVersion = result.versionId.slice(0, 8);
1789
- if (result.empty) {
1790
- console.log(source_default.dim("No files found (empty volume)"));
1791
- } else if (result.deduplicated) {
1792
- console.log(source_default.green("\u2713 Content unchanged (deduplicated)"));
1793
- } else {
1794
- console.log(source_default.green("\u2713 Upload complete"));
1795
- }
1796
- console.log(source_default.dim(` Version: ${shortVersion}`));
1797
- console.log(source_default.dim(` Files: ${result.fileCount.toLocaleString()}`));
1798
- console.log(source_default.dim(` Size: ${formatBytes(result.size)}`));
1799
- })
1800
- );
1801
-
1802
- // src/commands/volume/pull.ts
1803
- init_esm_shims();
1804
- import path5 from "path";
1805
- import * as fs3 from "fs";
1806
- import * as os3 from "os";
1807
-
1808
- // src/lib/storage/pull-utils.ts
1809
- init_esm_shims();
1810
- async function handleEmptyStorageResponse(cwd) {
1811
- console.log(source_default.dim("Syncing local files..."));
1812
- const removedCount = await removeExtraFiles(cwd, /* @__PURE__ */ new Set());
1813
- if (removedCount > 0) {
1814
- console.log(source_default.green(`\u2713 Removed ${removedCount} files not in remote`));
1815
- }
1816
- console.log(source_default.green("\u2713 Synced (0 files)"));
1817
- return { removedCount };
1818
- }
1819
-
1820
- // src/commands/volume/pull.ts
1821
- var pullCommand = new Command().name("pull").description("Pull cloud files to local directory").argument("[versionId]", "Version ID to pull (default: latest)").action(
1822
- withErrorHandler(async (versionId) => {
1823
- const cwd = process.cwd();
1824
- const config = await readStorageConfig(cwd);
1825
- if (!config) {
1826
- throw new Error("No volume initialized in this directory", {
1827
- cause: new Error("Run: vm0 volume init")
1828
- });
1829
- }
1830
- if (versionId) {
1831
- console.log(`Pulling volume: ${config.name} (version: ${versionId})`);
1832
- } else {
1833
- console.log(`Pulling volume: ${config.name}`);
1834
- }
1835
- console.log(source_default.dim("Getting download URL..."));
1836
- const downloadInfo = await getStorageDownload({
1837
- name: config.name,
1838
- type: "volume",
1839
- version: versionId
1840
- });
1841
- if ("empty" in downloadInfo) {
1842
- await handleEmptyStorageResponse(cwd);
1843
- return;
1844
- }
1845
- const downloadUrl = downloadInfo.url;
1846
- if (!downloadUrl) {
1847
- throw new Error("No download URL returned");
1848
- }
1849
- console.log(source_default.dim("Downloading from S3..."));
1850
- const s3Response = await fetch(downloadUrl);
1851
- if (!s3Response.ok) {
1852
- throw new Error(`S3 download failed: ${s3Response.status}`);
1853
- }
1854
- const arrayBuffer = await s3Response.arrayBuffer();
1855
- const tarBuffer = Buffer.from(arrayBuffer);
1856
- console.log(source_default.green(`\u2713 Downloaded ${formatBytes(tarBuffer.length)}`));
1857
- const tmpDir = fs3.mkdtempSync(path5.join(os3.tmpdir(), "vm0-"));
1858
- const tarPath = path5.join(tmpDir, "volume.tar.gz");
1859
- await fs3.promises.writeFile(tarPath, tarBuffer);
1860
- console.log(source_default.dim("Syncing local files..."));
1861
- const remoteFiles = await listTarFiles(tarPath);
1862
- const remoteFilesSet = new Set(
1863
- remoteFiles.map((f) => {
1864
- return f.replace(/\\/g, "/");
1865
- })
1866
- );
1867
- const removedCount = await removeExtraFiles(cwd, remoteFilesSet);
1868
- if (removedCount > 0) {
1869
- console.log(
1870
- source_default.green(`\u2713 Removed ${removedCount} files not in remote`)
1871
- );
1872
- }
1873
- console.log(source_default.dim("Extracting files..."));
1874
- await So({
1875
- file: tarPath,
1876
- cwd,
1877
- gzip: true
1878
- });
1879
- await fs3.promises.unlink(tarPath);
1880
- await fs3.promises.rmdir(tmpDir);
1881
- console.log(source_default.green(`\u2713 Extracted ${remoteFiles.length} files`));
1882
- })
1883
- );
1884
-
1885
- // src/commands/volume/status.ts
1886
- init_esm_shims();
1887
- var statusCommand2 = new Command().name("status").description("Show status of cloud volume").action(
1888
- withErrorHandler(async () => {
1889
- const cwd = process.cwd();
1890
- const config = await readStorageConfig(cwd);
1891
- if (!config) {
1892
- throw new Error("No volume initialized in this directory", {
1893
- cause: new Error("Run: vm0 volume init")
1894
- });
1895
- }
1896
- if (config.type !== "volume") {
1897
- throw new Error(
1898
- "This directory is initialized as an artifact, not a volume",
1899
- { cause: new Error("Use: vm0 artifact status") }
1900
- );
1901
- }
1902
- console.log(`Checking volume: ${config.name}`);
1903
- try {
1904
- const info = await getStorageDownload({
1905
- name: config.name,
1906
- type: "volume"
1907
- });
1908
- const shortVersion = info.versionId.slice(0, 8);
1909
- if ("empty" in info) {
1910
- console.log(source_default.green("\u2713 Found (empty)"));
1911
- console.log(source_default.dim(` Version: ${shortVersion}`));
1912
- } else {
1913
- console.log(source_default.green("\u2713 Found"));
1914
- console.log(source_default.dim(` Version: ${shortVersion}`));
1915
- console.log(source_default.dim(` Files: ${info.fileCount.toLocaleString()}`));
1916
- console.log(source_default.dim(` Size: ${formatBytes(info.size)}`));
1917
- }
1918
- } catch (error) {
1919
- if (error instanceof ApiRequestError && error.status === 404) {
1920
- throw new Error("Not found on remote", {
1921
- cause: new Error("Run: vm0 volume push")
1922
- });
1923
- }
1924
- throw error;
1925
- }
1926
- })
1927
- );
1928
-
1929
- // src/commands/volume/list.ts
1930
- init_esm_shims();
1931
- var listCommand2 = new Command().name("list").alias("ls").description("List all remote volumes").action(
1932
- withErrorHandler(async () => {
1933
- const items = await listStorages({ type: "volume" });
1934
- if (items.length === 0) {
1935
- console.log(source_default.dim("No volumes found"));
1936
- console.log(
1937
- source_default.dim(" Create one with: vm0 volume init && vm0 volume push")
1938
- );
1939
- return;
1940
- }
1941
- const nameWidth = Math.max(
1942
- 4,
1943
- ...items.map((i) => {
1944
- return i.name.length;
1945
- })
1946
- );
1947
- const sizeWidth = Math.max(
1948
- 4,
1949
- ...items.map((i) => {
1950
- return formatBytes(i.size).length;
1951
- })
1952
- );
1953
- const filesWidth = Math.max(
1954
- 5,
1955
- ...items.map((i) => {
1956
- return i.fileCount.toString().length;
1957
- })
1958
- );
1959
- const header = [
1960
- "NAME".padEnd(nameWidth),
1961
- "SIZE".padStart(sizeWidth),
1962
- "FILES".padStart(filesWidth),
1963
- "UPDATED"
1964
- ].join(" ");
1965
- console.log(source_default.dim(header));
1966
- for (const item of items) {
1967
- const row = [
1968
- item.name.padEnd(nameWidth),
1969
- formatBytes(item.size).padStart(sizeWidth),
1970
- item.fileCount.toString().padStart(filesWidth),
1971
- formatRelativeTime(item.updatedAt)
1972
- ].join(" ");
1973
- console.log(row);
1974
- }
1975
- })
1976
- );
1977
-
1978
- // src/commands/volume/clone.ts
1979
- init_esm_shims();
1980
-
1981
- // src/lib/storage/clone-utils.ts
1982
- init_esm_shims();
1983
- import path6 from "path";
1984
- import * as fs4 from "fs";
1985
- import * as os4 from "os";
1986
- async function cloneStorage(name, type, destination, options = {}) {
1987
- const typeLabel = type;
1988
- const dirStatus = checkDirectoryStatus(destination);
1989
- if (dirStatus.exists && !dirStatus.empty) {
1990
- throw new Error(`Directory "${destination}" is not empty`);
1991
- }
1992
- console.log(source_default.dim(`Checking remote ${typeLabel}...`));
1993
- const downloadInfo = await getStorageDownload({
1994
- name,
1995
- type,
1996
- version: options.version
1997
- });
1998
- console.log(source_default.dim(`Creating directory: ${destination}/`));
1999
- await fs4.promises.mkdir(destination, { recursive: true });
2000
- if ("empty" in downloadInfo) {
2001
- await writeStorageConfig(name, destination, type);
2002
- console.log(source_default.green(`\u2713 Cloned empty ${typeLabel}: ${name}`));
2003
- console.log(source_default.dim(`\u2713 Initialized .vm0/storage.yaml`));
2004
- return {
2005
- success: true,
2006
- fileCount: 0,
2007
- size: 0,
2008
- versionId: downloadInfo.versionId
2009
- };
2010
- }
2011
- const downloadUrl = downloadInfo.url;
2012
- if (!downloadUrl) {
2013
- throw new Error("No download URL returned");
2014
- }
2015
- console.log(source_default.dim("Downloading from S3..."));
2016
- const s3Response = await fetch(downloadUrl);
2017
- if (!s3Response.ok) {
2018
- await fs4.promises.rm(destination, { recursive: true, force: true });
2019
- throw new Error(`S3 download failed: ${s3Response.status}`);
2020
- }
2021
- const arrayBuffer = await s3Response.arrayBuffer();
2022
- const tarBuffer = Buffer.from(arrayBuffer);
2023
- console.log(source_default.green(`\u2713 Downloaded ${formatBytes(tarBuffer.length)}`));
2024
- const tmpDir = fs4.mkdtempSync(path6.join(os4.tmpdir(), "vm0-clone-"));
2025
- const tarPath = path6.join(tmpDir, "archive.tar.gz");
2026
- await fs4.promises.writeFile(tarPath, tarBuffer);
2027
- const files = await listTarFiles(tarPath);
2028
- console.log(source_default.dim("Extracting files..."));
2029
- await So({
2030
- file: tarPath,
2031
- cwd: destination,
2032
- gzip: true
2033
- });
2034
- await fs4.promises.unlink(tarPath);
2035
- await fs4.promises.rmdir(tmpDir);
2036
- console.log(source_default.green(`\u2713 Extracted ${files.length} files`));
2037
- await writeStorageConfig(name, destination, type);
2038
- console.log(source_default.green(`\u2713 Initialized .vm0/storage.yaml`));
2039
- return {
2040
- success: true,
2041
- fileCount: downloadInfo.fileCount,
2042
- size: downloadInfo.size,
2043
- versionId: downloadInfo.versionId
2044
- };
2045
- }
2046
-
2047
- // src/commands/volume/clone.ts
2048
- var cloneCommand = new Command().name("clone").description("Clone a remote volume to local directory (latest version)").argument("<name>", "Volume name to clone").argument("[destination]", "Destination directory (default: volume name)").action(
2049
- withErrorHandler(async (name, destination) => {
2050
- const targetDir = destination || name;
2051
- console.log(`Cloning volume: ${name}`);
2052
- const result = await cloneStorage(name, "volume", targetDir);
2053
- console.log(source_default.green(`
2054
- \u2713 Successfully cloned volume: ${name}`));
2055
- console.log(source_default.dim(` Location: ${targetDir}/`));
2056
- console.log(source_default.dim(` Version: ${result.versionId.slice(0, 8)}`));
2057
- })
2058
- );
2059
-
2060
- // src/commands/volume/index.ts
2061
- var volumeCommand = new Command().name("volume").description("Manage volumes (defined in compose, not versioned after run)").addCommand(initCommand).addCommand(pushCommand).addCommand(pullCommand).addCommand(statusCommand2).addCommand(listCommand2).addCommand(cloneCommand);
2062
-
2063
- // src/commands/artifact/index.ts
2064
- init_esm_shims();
2065
-
2066
- // src/commands/artifact/init.ts
2067
- init_esm_shims();
2068
- import path7 from "path";
2069
- var initCommand2 = new Command().name("init").description("Initialize an artifact in the current directory").option(
2070
- "-n, --name <name>",
2071
- "Artifact name (required in non-interactive mode)"
2072
- ).action(
2073
- withErrorHandler(async (options) => {
2074
- const cwd = process.cwd();
2075
- const dirName = path7.basename(cwd);
2076
- const existingConfig = await readStorageConfig(cwd);
2077
- if (existingConfig) {
2078
- if (existingConfig.type === "artifact") {
2079
- console.log(
2080
- source_default.yellow(
2081
- `Artifact already initialized: ${existingConfig.name}`
2082
- )
2083
- );
2084
- } else {
2085
- console.log(
2086
- source_default.yellow(
2087
- `Directory already initialized as volume: ${existingConfig.name}`
2088
- )
2089
- );
2090
- console.log(
2091
- source_default.dim(
2092
- " To change type, delete .vm0/storage.yaml and reinitialize"
2093
- )
2094
- );
2095
- }
2096
- console.log(
2097
- source_default.dim(`Config file: ${path7.join(cwd, ".vm0", "storage.yaml")}`)
2098
- );
2099
- return;
2100
- }
2101
- let artifactName;
2102
- if (options.name) {
2103
- artifactName = options.name;
2104
- } else if (!isInteractive()) {
2105
- throw new Error("--name flag is required in non-interactive mode", {
2106
- cause: new Error("Usage: vm0 artifact init --name <artifact-name>")
2107
- });
2108
- } else {
2109
- const defaultName = isValidStorageName(dirName) ? dirName : void 0;
2110
- const name = await promptText(
2111
- "Enter artifact name",
2112
- defaultName,
2113
- (value) => {
2114
- if (!isValidStorageName(value)) {
2115
- return "Must be 3-64 characters, lowercase alphanumeric with hyphens";
2116
- }
2117
- return true;
2118
- }
2119
- );
2120
- if (name === void 0) {
2121
- console.log(source_default.dim("Cancelled"));
2122
- return;
2123
- }
2124
- artifactName = name;
2125
- }
2126
- if (!isValidStorageName(artifactName)) {
2127
- throw new Error(`Invalid artifact name: "${artifactName}"`, {
2128
- cause: new Error(
2129
- "Artifact names must be 3-64 characters, lowercase alphanumeric with hyphens"
2130
- )
2131
- });
2132
- }
2133
- await writeStorageConfig(artifactName, cwd, "artifact");
2134
- console.log(source_default.green(`\u2713 Initialized artifact: ${artifactName}`));
2135
- console.log(
2136
- source_default.dim(
2137
- ` Config saved to ${path7.join(cwd, ".vm0", "storage.yaml")}`
2138
- )
2139
- );
2140
- })
2141
- );
2142
-
2143
- // src/commands/artifact/push.ts
2144
- init_esm_shims();
2145
- var pushCommand2 = new Command().name("push").description("Push local files to cloud artifact").option(
2146
- "-f, --force",
2147
- "Force upload even if content unchanged (recreate archive)"
2148
- ).action(
2149
- withErrorHandler(async (options) => {
2150
- const cwd = process.cwd();
2151
- const config = await readStorageConfig(cwd);
2152
- if (!config) {
2153
- throw new Error("No artifact initialized in this directory", {
2154
- cause: new Error("Run: vm0 artifact init")
2155
- });
2156
- }
2157
- if (config.type !== "artifact") {
2158
- throw new Error(
2159
- "This directory is initialized as a volume, not an artifact",
2160
- { cause: new Error("Use: vm0 volume push") }
2161
- );
2162
- }
2163
- console.log(`Pushing artifact: ${config.name}`);
2164
- const result = await directUpload(config.name, "artifact", cwd, {
2165
- onProgress: (message) => {
2166
- console.log(source_default.dim(message));
2167
- },
2168
- force: options.force
2169
- });
2170
- const shortVersion = result.versionId.slice(0, 8);
2171
- if (result.empty) {
2172
- console.log(source_default.dim("No files found (empty artifact)"));
2173
- } else if (result.deduplicated) {
2174
- console.log(source_default.green("\u2713 Content unchanged (deduplicated)"));
2175
- } else {
2176
- console.log(source_default.green("\u2713 Upload complete"));
2177
- }
2178
- console.log(source_default.dim(` Version: ${shortVersion}`));
2179
- console.log(source_default.dim(` Files: ${result.fileCount.toLocaleString()}`));
2180
- console.log(source_default.dim(` Size: ${formatBytes(result.size)}`));
2181
- })
2182
- );
2183
-
2184
- // src/commands/artifact/pull.ts
2185
- init_esm_shims();
2186
- import path8 from "path";
2187
- import * as fs5 from "fs";
2188
- import * as os5 from "os";
2189
- var pullCommand2 = new Command().name("pull").description("Pull cloud artifact to local directory").argument("[versionId]", "Version ID to pull (default: latest)").action(
2190
- withErrorHandler(async (versionId) => {
2191
- const cwd = process.cwd();
2192
- const config = await readStorageConfig(cwd);
2193
- if (!config) {
2194
- throw new Error("No artifact initialized in this directory", {
2195
- cause: new Error("Run: vm0 artifact init")
2196
- });
2197
- }
2198
- if (config.type !== "artifact") {
2199
- throw new Error(
2200
- "This directory is initialized as a volume, not an artifact",
2201
- { cause: new Error("Use: vm0 volume pull") }
2202
- );
2203
- }
2204
- if (versionId) {
2205
- console.log(`Pulling artifact: ${config.name} (version: ${versionId})`);
2206
- } else {
2207
- console.log(`Pulling artifact: ${config.name}`);
2208
- }
2209
- console.log(source_default.dim("Getting download URL..."));
2210
- const downloadInfo = await getStorageDownload({
2211
- name: config.name,
2212
- type: "artifact",
2213
- version: versionId
2214
- });
2215
- if ("empty" in downloadInfo) {
2216
- await handleEmptyStorageResponse(cwd);
2217
- return;
2218
- }
2219
- const downloadUrl = downloadInfo.url;
2220
- if (!downloadUrl) {
2221
- throw new Error("No download URL returned");
2222
- }
2223
- console.log(source_default.dim("Downloading from S3..."));
2224
- const s3Response = await fetch(downloadUrl);
2225
- if (!s3Response.ok) {
2226
- throw new Error(`S3 download failed: ${s3Response.status}`);
2227
- }
2228
- const arrayBuffer = await s3Response.arrayBuffer();
2229
- const tarBuffer = Buffer.from(arrayBuffer);
2230
- console.log(source_default.green(`\u2713 Downloaded ${formatBytes(tarBuffer.length)}`));
2231
- const tmpDir = fs5.mkdtempSync(path8.join(os5.tmpdir(), "vm0-"));
2232
- const tarPath = path8.join(tmpDir, "artifact.tar.gz");
2233
- await fs5.promises.writeFile(tarPath, tarBuffer);
2234
- console.log(source_default.dim("Syncing local files..."));
2235
- const remoteFiles = await listTarFiles(tarPath);
2236
- const remoteFilesSet = new Set(
2237
- remoteFiles.map((f) => {
2238
- return f.replace(/\\/g, "/");
2239
- })
2240
- );
2241
- const removedCount = await removeExtraFiles(cwd, remoteFilesSet);
2242
- if (removedCount > 0) {
2243
- console.log(
2244
- source_default.green(`\u2713 Removed ${removedCount} files not in remote`)
2245
- );
2246
- }
2247
- console.log(source_default.dim("Extracting files..."));
2248
- await So({
2249
- file: tarPath,
2250
- cwd,
2251
- gzip: true
2252
- });
2253
- await fs5.promises.unlink(tarPath);
2254
- await fs5.promises.rmdir(tmpDir);
2255
- console.log(source_default.green(`\u2713 Extracted ${remoteFiles.length} files`));
2256
- })
2257
- );
2258
-
2259
- // src/commands/artifact/status.ts
2260
- init_esm_shims();
2261
- var statusCommand3 = new Command().name("status").description("Show status of cloud artifact").action(
2262
- withErrorHandler(async () => {
2263
- const cwd = process.cwd();
2264
- const config = await readStorageConfig(cwd);
2265
- if (!config) {
2266
- throw new Error("No artifact initialized in this directory", {
2267
- cause: new Error("Run: vm0 artifact init")
2268
- });
2269
- }
2270
- if (config.type !== "artifact") {
2271
- throw new Error(
2272
- "This directory is initialized as a volume, not an artifact",
2273
- { cause: new Error("Use: vm0 volume status") }
2274
- );
2275
- }
2276
- console.log(`Checking artifact: ${config.name}`);
2277
- try {
2278
- const info = await getStorageDownload({
2279
- name: config.name,
2280
- type: "artifact"
2281
- });
2282
- const shortVersion = info.versionId.slice(0, 8);
2283
- if ("empty" in info) {
2284
- console.log(source_default.green("\u2713 Found (empty)"));
2285
- console.log(source_default.dim(` Version: ${shortVersion}`));
2286
- } else {
2287
- console.log(source_default.green("\u2713 Found"));
2288
- console.log(source_default.dim(` Version: ${shortVersion}`));
2289
- console.log(source_default.dim(` Files: ${info.fileCount.toLocaleString()}`));
2290
- console.log(source_default.dim(` Size: ${formatBytes(info.size)}`));
2291
- }
2292
- } catch (error) {
2293
- if (error instanceof ApiRequestError && error.status === 404) {
2294
- throw new Error("Not found on remote", {
2295
- cause: new Error("Run: vm0 artifact push")
2296
- });
2297
- }
2298
- throw error;
2299
- }
2300
- })
2301
- );
2302
-
2303
- // src/commands/artifact/list.ts
2304
- init_esm_shims();
2305
- var listCommand3 = new Command().name("list").alias("ls").description("List all remote artifacts").action(
2306
- withErrorHandler(async () => {
2307
- const items = await listStorages({ type: "artifact" });
2308
- if (items.length === 0) {
2309
- console.log(source_default.dim("No artifacts found"));
2310
- console.log(
2311
- source_default.dim(
2312
- " Create one with: vm0 artifact init && vm0 artifact push"
2313
- )
2314
- );
2315
- return;
2316
- }
2317
- const nameWidth = Math.max(
2318
- 4,
2319
- ...items.map((i) => {
2320
- return i.name.length;
2321
- })
2322
- );
2323
- const sizeWidth = Math.max(
2324
- 4,
2325
- ...items.map((i) => {
2326
- return formatBytes(i.size).length;
2327
- })
2328
- );
2329
- const filesWidth = Math.max(
2330
- 5,
2331
- ...items.map((i) => {
2332
- return i.fileCount.toString().length;
2333
- })
2334
- );
2335
- const header = [
2336
- "NAME".padEnd(nameWidth),
2337
- "SIZE".padStart(sizeWidth),
2338
- "FILES".padStart(filesWidth),
2339
- "UPDATED"
2340
- ].join(" ");
2341
- console.log(source_default.dim(header));
2342
- for (const item of items) {
2343
- const row = [
2344
- item.name.padEnd(nameWidth),
2345
- formatBytes(item.size).padStart(sizeWidth),
2346
- item.fileCount.toString().padStart(filesWidth),
2347
- formatRelativeTime(item.updatedAt)
2348
- ].join(" ");
2349
- console.log(row);
2350
- }
2351
- })
2352
- );
2353
-
2354
- // src/commands/artifact/clone.ts
2355
- init_esm_shims();
2356
- var cloneCommand2 = new Command().name("clone").description("Clone a remote artifact to local directory (latest version)").argument("<name>", "Artifact name to clone").argument("[destination]", "Destination directory (default: artifact name)").action(
2357
- withErrorHandler(async (name, destination) => {
2358
- const targetDir = destination || name;
2359
- console.log(`Cloning artifact: ${name}`);
2360
- const result = await cloneStorage(name, "artifact", targetDir);
2361
- console.log(source_default.green(`
2362
- \u2713 Successfully cloned artifact: ${name}`));
2363
- console.log(source_default.dim(` Location: ${targetDir}/`));
2364
- console.log(source_default.dim(` Version: ${result.versionId.slice(0, 8)}`));
2365
- })
2366
- );
2367
-
2368
- // src/commands/artifact/index.ts
2369
- var artifactCommand = new Command().name("artifact").description("Manage artifacts (specified at run, versioned after run)").addCommand(initCommand2).addCommand(pushCommand2).addCommand(pullCommand2).addCommand(statusCommand3).addCommand(listCommand3).addCommand(cloneCommand2);
2370
-
2371
- // src/commands/logs/index.ts
2372
- init_esm_shims();
2373
-
2374
- // src/commands/logs/search.ts
2375
- init_esm_shims();
2376
- var SEVEN_DAYS_MS = 7 * 24 * 60 * 60 * 1e3;
2377
- function supportedSearchFramework(framework) {
2378
- const normalized = framework ?? void 0;
2379
- return isSupportedFramework(normalized) ? normalized : void 0;
2380
- }
2381
- function renderSearchEvent(event, framework, renderer, normalizer) {
2382
- const parsedEvents = normalizer.process(
2383
- event.eventData,
2384
- supportedSearchFramework(framework),
2385
- new Date(event.createdAt)
2386
- );
2387
- for (const parsed of parsedEvents) {
2388
- renderer.render(parsed);
2389
- }
2390
- }
2391
- function flushSearchRenderer(renderer, normalizer) {
2392
- for (const parsed of normalizer.flush()) {
2393
- renderer.render(parsed);
2394
- }
2395
- renderer.flush();
2396
- }
2397
- function formatRunHeader(runId, agentName, timestamp) {
2398
- const shortId = runId.slice(0, 8);
2399
- const time = formatIsoTimestamp(timestamp);
2400
- return `\u2500\u2500 Run ${shortId} (${agentName}, ${time}) \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500`;
2401
- }
2402
- function parseContextOptions(options) {
2403
- const contextN = options.context !== void 0 ? parseBoundedLogCount(options.context, "--context", 0, 10) : 0;
2404
- const before = options.beforeContext !== void 0 ? parseBoundedLogCount(options.beforeContext, "--before-context", 0, 10) : contextN;
2405
- const after = options.afterContext !== void 0 ? parseBoundedLogCount(options.afterContext, "--after-context", 0, 10) : contextN;
2406
- return { before, after };
2407
- }
2408
- function parseLimit2(value) {
2409
- if (value === void 0) return void 0;
2410
- return parseBoundedLogCount(value, "--limit", 1, 50);
2411
- }
2412
- function renderResults(response) {
2413
- const grouped = /* @__PURE__ */ new Map();
2414
- for (const result of response.results) {
2415
- const existing = grouped.get(result.runId);
2416
- if (existing) {
2417
- existing.results.push(result);
2418
- } else {
2419
- grouped.set(result.runId, {
2420
- agentName: result.agentName,
2421
- results: [result]
2422
- });
2423
- }
2424
- }
2425
- let isFirstGroup = true;
2426
- for (const [runId, group] of grouped) {
2427
- if (!isFirstGroup) {
2428
- console.log();
2429
- }
2430
- isFirstGroup = false;
2431
- const firstTimestamp = group.results[0].matchedEvent.createdAt;
2432
- console.log(
2433
- source_default.bold(formatRunHeader(runId, group.agentName, firstTimestamp))
2434
- );
2435
- for (const result of group.results) {
2436
- const renderer = new EventRenderer({
2437
- showTimestamp: true,
2438
- verbose: false
2439
- });
2440
- const normalizer = new EventStreamNormalizer();
2441
- for (const event of result.contextBefore) {
2442
- renderSearchEvent(event, result.framework, renderer, normalizer);
2443
- }
2444
- renderSearchEvent(
2445
- result.matchedEvent,
2446
- result.framework,
2447
- renderer,
2448
- normalizer
2449
- );
2450
- for (const event of result.contextAfter) {
2451
- renderSearchEvent(event, result.framework, renderer, normalizer);
2452
- }
2453
- flushSearchRenderer(renderer, normalizer);
2454
- }
2455
- }
2456
- if (response.hasMore) {
2457
- console.log();
2458
- console.log(
2459
- source_default.dim(
2460
- ` Showing first ${response.results.length} matches. Use --limit to see more.`
2461
- )
2462
- );
2463
- }
2464
- }
2465
- var searchCommand = new Command().name("search").description("Search agent events across runs").argument("<keyword>", "Search keyword").option("-A, --after-context <n>", "Show n events after each match").option("-B, --before-context <n>", "Show n events before each match").option("-C, --context <n>", "Show n events before and after each match").option("--agent <id>", "Filter by agent ID").option("--run <id>", "Filter by specific run ID").option("--since <time>", "Search logs since (default: 7d)").option("--limit <n>", "Maximum number of matches (default: 20)").action(
2466
- withErrorHandler(async (keyword, options) => {
2467
- const searchKeyword = parseSearchQuery(keyword, "Keyword");
2468
- if (options.agent !== void 0 && !isUUID(options.agent)) {
2469
- console.error(
2470
- source_default.red(`\u2717 Invalid agent ID "${options.agent}" \u2014 expected a UUID`)
2471
- );
2472
- console.error(source_default.dim(" Run: vm0 run list to find agent IDs"));
2473
- process.exit(1);
2474
- }
2475
- if (options.run !== void 0 && !isUUID(options.run)) {
2476
- console.error(
2477
- source_default.red(`\u2717 Invalid run ID "${options.run}" \u2014 expected a UUID`)
2478
- );
2479
- console.error(source_default.dim(" Run: vm0 run list to find run IDs"));
2480
- process.exit(1);
2481
- }
2482
- const { before, after } = parseContextOptions(options);
2483
- const since = options.since !== void 0 ? parseTime(options.since) : Date.now() - SEVEN_DAYS_MS;
2484
- const limit = parseLimit2(options.limit);
2485
- const response = await searchLogs({
2486
- keyword: searchKeyword,
2487
- agentId: options.agent,
2488
- runId: options.run,
2489
- since,
2490
- limit,
2491
- before,
2492
- after
2493
- });
2494
- if (response.results.length === 0) {
2495
- console.log(source_default.dim("No matches found"));
2496
- console.log(
2497
- source_default.dim(
2498
- " Try a broader search with --since 30d or a different keyword"
2499
- )
2500
- );
2501
- return;
2502
- }
2503
- renderResults(response);
2504
- })
2505
- );
2506
-
2507
- // src/commands/logs/index.ts
2508
- var PAGE_LIMIT = 100;
2509
- function buildPlatformLogsUrl(apiUrl, runId) {
2510
- const url = new URL(apiUrl);
2511
- const hostname = url.hostname;
2512
- if (hostname === "localhost" || hostname === "127.0.0.1") {
2513
- return `http://${hostname}:3001/logs/${runId}`;
2514
- }
2515
- const parts = hostname.split(".");
2516
- if (parts[0] === "www" || parts[0] === "app" || parts[0] === "platform" || parts[0] === "api") {
2517
- parts[0] = "app";
2518
- } else {
2519
- parts.unshift("app");
2520
- }
2521
- const platformHost = parts.join(".");
2522
- const port = url.port ? `:${url.port}` : "";
2523
- return `https://${platformHost}${port}/logs/${runId}`;
2524
- }
2525
- function supportedLogFramework(framework) {
2526
- return isSupportedFramework(framework) ? framework : void 0;
2527
- }
2528
- function hasLogFramework(framework) {
2529
- return framework !== void 0 && framework !== null;
2530
- }
2531
- function formatMetric(metric) {
2532
- const memPercent = (metric.mem_used / metric.mem_total * 100).toFixed(1);
2533
- const diskPercent = (metric.disk_used / metric.disk_total * 100).toFixed(1);
2534
- return `[${metric.ts}] CPU: ${metric.cpu.toFixed(1)}% | Mem: ${formatBytes(metric.mem_used)}/${formatBytes(metric.mem_total)} (${memPercent}%) | Disk: ${formatBytes(metric.disk_used)}/${formatBytes(metric.disk_total)} (${diskPercent}%)`;
2535
- }
2536
- function formatFirewallTag(entry) {
2537
- if (!entry.firewall_name) return "";
2538
- const billable = entry.firewall_billable ? ` ${source_default.yellow("$")}` : "";
2539
- return ` ${source_default.cyan(`[${entry.firewall_name}${billable}]`)}`;
2540
- }
2541
- function formatBrowserUserAgentTag(entry) {
2542
- return entry.browser_user_agent ? ` ${source_default.magenta("[browser]")}` : "";
2543
- }
2544
- function formatConnectorDiagnosticInfo(entry) {
2545
- const tags = [];
2546
- if (entry.connector_diagnostic_type) {
2547
- tags.push(entry.connector_diagnostic_type);
2548
- }
2549
- if (entry.connector_diagnostic_reason) {
2550
- tags.push(entry.connector_diagnostic_reason);
2551
- }
2552
- if (entry.connector_diagnostic_env_names && entry.connector_diagnostic_env_names.length > 0) {
2553
- tags.push(`env: ${entry.connector_diagnostic_env_names.join(", ")}`);
2554
- }
2555
- if (entry.connector_diagnostic_base) {
2556
- tags.push(`base: ${entry.connector_diagnostic_base}`);
2557
- }
2558
- if (tags.length === 0) return "";
2559
- return ` ${source_default.red(`[connector diagnostic: ${tags.join("; ")}]`)}`;
2560
- }
2561
- function formatConnectorRouteInfo(entry) {
2562
- const tags = [];
2563
- if (entry.connector_route_reason) {
2564
- tags.push(entry.connector_route_reason);
2565
- }
2566
- if (entry.connector_route_candidates && entry.connector_route_candidates.length > 0) {
2567
- tags.push(`candidates: ${entry.connector_route_candidates.join(", ")}`);
2568
- }
2569
- if (tags.length === 0) return "";
2570
- return ` ${source_default.red(`[connector route: ${tags.join("; ")}]`)}`;
2571
- }
2572
- function nonEmptyLogField(value) {
2573
- const trimmed = value?.trim();
2574
- return trimmed && trimmed.length > 0 ? trimmed : void 0;
2575
- }
2576
- function formatNetworkTarget(entry) {
2577
- const url = nonEmptyLogField(entry.url);
2578
- if (url) {
2579
- return url;
2580
- }
2581
- const host = nonEmptyLogField(entry.host);
2582
- if (!host) {
2583
- return "unknown";
2584
- }
2585
- return entry.port !== void 0 ? `${host}:${entry.port}` : host;
2586
- }
2587
- function formatNetworkDeny(entry) {
2588
- const method = entry.method || "???";
2589
- const url = formatNetworkTarget(entry);
2590
- const error = entry.firewall_error ? ` ${source_default.red(entry.firewall_error)}` : "";
2591
- return `[${entry.timestamp}] ${method.padEnd(6)} ${source_default.red.bold("DENY")} ${source_default.dim(url)}${formatFirewallTag(entry)}${formatBrowserUserAgentTag(entry)}${error}${formatConnectorDiagnosticInfo(entry)}${formatConnectorRouteInfo(entry)}`;
2592
- }
2593
- function formatNetworkBlock(entry) {
2594
- const method = entry.method || "???";
2595
- const target = formatNetworkTarget(entry);
2596
- const error = entry.firewall_error ? ` ${source_default.red(entry.firewall_error)}` : "";
2597
- return `[${entry.timestamp}] ${method.padEnd(6)} ${source_default.yellow.bold("BLOCK")} ${source_default.dim(target)}${formatFirewallTag(entry)}${formatBrowserUserAgentTag(entry)}${error}${formatConnectorDiagnosticInfo(entry)}${formatConnectorRouteInfo(entry)}${formatAuthInfo(entry)}`;
2598
- }
2599
- function formatAuthInfo(entry) {
2600
- const tags = [];
2601
- if (entry.auth_url_rewrite) {
2602
- tags.push("url-rewrite");
2603
- }
2604
- if (entry.auth_resolved_secrets && entry.auth_resolved_secrets.length > 0) {
2605
- const refreshedSet = new Set(entry.auth_refreshed_secrets ?? []);
2606
- for (const name of entry.auth_resolved_secrets) {
2607
- if (refreshedSet.has(name)) {
2608
- tags.push(`${name} (refreshed)`);
2609
- } else if (entry.auth_cache_hit) {
2610
- tags.push(`${name} (cached)`);
2611
- } else {
2612
- tags.push(name);
2613
- }
2614
- }
2615
- }
2616
- if (tags.length === 0) return "";
2617
- return ` ${source_default.yellow(`\u2194 ${tags.join(", ")}`)}`;
2618
- }
2619
- function formatNetworkRequest(entry) {
2620
- let statusColor;
2621
- const status = entry.status || 0;
2622
- if (status >= 200 && status < 300) {
2623
- statusColor = source_default.green;
2624
- } else if (status >= 300 && status < 400) {
2625
- statusColor = source_default.yellow;
2626
- } else if (status >= 400) {
2627
- statusColor = source_default.red;
2628
- } else {
2629
- statusColor = source_default.gray;
2630
- }
2631
- let latencyColor;
2632
- const latencyMs = entry.latency_ms || 0;
2633
- if (latencyMs < 500) {
2634
- latencyColor = source_default.green;
2635
- } else if (latencyMs < 2e3) {
2636
- latencyColor = source_default.yellow;
2637
- } else {
2638
- latencyColor = source_default.red;
2639
- }
2640
- const method = entry.method || "???";
2641
- const requestSize = entry.request_size || 0;
2642
- const responseSize = entry.response_size || 0;
2643
- const url = formatNetworkTarget(entry);
2644
- const error = entry.firewall_error ? ` ${source_default.red(entry.firewall_error)}` : "";
2645
- let line = `[${entry.timestamp}] ${method.padEnd(6)} ${statusColor(status)} ${latencyColor(latencyMs + "ms")} ${formatBytes(requestSize)}/${formatBytes(responseSize)} ${source_default.dim(url)}${formatFirewallTag(entry)}${formatBrowserUserAgentTag(entry)}${error}${formatConnectorDiagnosticInfo(entry)}${formatConnectorRouteInfo(entry)}${formatAuthInfo(entry)}`;
2646
- line += formatCaptureFields(entry);
2647
- return line;
2648
- }
2649
- var BODY_PREVIEW_LENGTH = 200;
2650
- function formatCaptureFields(entry) {
2651
- let result = "";
2652
- if (entry.request_headers) {
2653
- const hdrs = Object.entries(entry.request_headers).map(([k, v]) => {
2654
- return `${k}: ${v}`;
2655
- }).join(", ");
2656
- result += `
2657
- ${source_default.gray("request_headers:")} ${hdrs}`;
2658
- }
2659
- if (entry.request_body) {
2660
- const truncated = entry.request_body_truncated ? " (truncated)" : "";
2661
- const preview = entry.request_body.slice(0, BODY_PREVIEW_LENGTH);
2662
- const ellipsis = entry.request_body.length > BODY_PREVIEW_LENGTH ? "..." : "";
2663
- result += `
2664
- ${source_default.gray("request_body:")} ${preview}${ellipsis}${truncated}`;
2665
- }
2666
- if (entry.response_body) {
2667
- const truncated = entry.response_body_truncated ? " (truncated)" : "";
2668
- const preview = entry.response_body.slice(0, BODY_PREVIEW_LENGTH);
2669
- const ellipsis = entry.response_body.length > BODY_PREVIEW_LENGTH ? "..." : "";
2670
- result += `
2671
- ${source_default.gray("response_body:")} ${preview}${ellipsis}${truncated}`;
2672
- }
2673
- return result;
2674
- }
2675
- function formatNetworkTcp(entry) {
2676
- const host = entry.host || "unknown";
2677
- const port = entry.port || 0;
2678
- const requestSize = entry.request_size || 0;
2679
- const responseSize = entry.response_size || 0;
2680
- const latencyMs = entry.latency_ms || 0;
2681
- const error = entry.error ? ` ${source_default.red(entry.error)}` : "";
2682
- return `[${entry.timestamp}] ${source_default.blue("TCP")} ${latencyMs}ms ${formatBytes(requestSize)}/${formatBytes(responseSize)} ${source_default.dim(`${host}:${port}`)}${error}`;
2683
- }
2684
- function formatNetworkOther(entry) {
2685
- const proto = (entry.type || "???").toUpperCase();
2686
- const host = entry.host || "unknown";
2687
- const port = entry.port || 0;
2688
- const size = entry.request_size ? ` ${formatBytes(entry.request_size)}` : "";
2689
- const dnsResult = entry.type === "dns" && entry.dns_result ? ` ${source_default.gray("->")} ${source_default.dim(entry.dns_result)}` : "";
2690
- return `[${entry.timestamp}] ${source_default.magenta(proto.padEnd(5))}${size} ${source_default.dim(`${host}:${port}`)}${dnsResult}`;
2691
- }
2692
- function formatNetworkLog(entry) {
2693
- if (entry.action === "BLOCK") return formatNetworkBlock(entry);
2694
- if (entry.type === "tcp") return formatNetworkTcp(entry);
2695
- if (entry.type && entry.type !== "http") return formatNetworkOther(entry);
2696
- if (entry.action === "DENY") return formatNetworkDeny(entry);
2697
- return formatNetworkRequest(entry);
2698
- }
2699
- function createLogRenderer(verbose) {
2700
- return new EventRenderer({
2701
- showTimestamp: true,
2702
- verbose
2703
- });
2704
- }
2705
- function renderAgentEvent(event, renderer, normalizer, framework) {
2706
- const parsedEvents = normalizer.process(
2707
- event.eventData,
2708
- framework,
2709
- new Date(event.createdAt)
2710
- );
2711
- for (const parsed of parsedEvents) {
2712
- renderer.render(parsed);
2713
- }
2714
- }
2715
- function getLogType(options) {
2716
- const selected = [
2717
- options.agent,
2718
- options.system,
2719
- options.metrics,
2720
- options.network
2721
- ].filter(Boolean).length;
2722
- if (selected > 1) {
2723
- throw new Error(
2724
- "Options --agent, --system, --metrics, and --network are mutually exclusive"
2725
- );
2726
- }
2727
- if (options.system) return "system";
2728
- if (options.metrics) return "metrics";
2729
- if (options.network) return "network";
2730
- return "agent";
2731
- }
2732
- var logsCommand = new Command().name("logs").description("View and search agent run logs").argument("[runId]", "Run ID to fetch logs for").addCommand(searchCommand).option("-a, --agent", "Show agent events (default)").option("-s, --system", "Show system log").option("-m, --metrics", "Show metrics").option("-n, --network", "Show network logs (proxy traffic)").option(
2733
- "--since <time>",
2734
- "Show logs since timestamp (e.g., 5m, 2h, 1d, 2024-01-15T10:30:00Z, 1705312200)"
2735
- ).option("--tail <n>", "Show last N entries (default: 5)").option("--head <n>", "Show first N entries").option("--all", "Fetch all log entries").action(
2736
- withErrorHandler(
2737
- async (runId, options) => {
2738
- if (!runId) {
2739
- logsCommand.help();
2740
- return;
2741
- }
2742
- if (!isUUID(runId)) {
2743
- console.error(
2744
- source_default.red(`\u2717 Invalid run ID "${runId}" \u2014 expected a UUID`)
2745
- );
2746
- console.error(source_default.dim(" Run: vm0 run list to find run IDs"));
2747
- process.exit(1);
2748
- }
2749
- const logType = getLogType(options);
2750
- const countModes = [
2751
- options.tail !== void 0,
2752
- options.head !== void 0,
2753
- options.all === true
2754
- ].filter(Boolean).length;
2755
- if (countModes > 1) {
2756
- throw new Error(
2757
- "Options --tail, --head, and --all are mutually exclusive"
2758
- );
2759
- }
2760
- let since;
2761
- if (options.since !== void 0) {
2762
- since = parseTime(options.since);
2763
- }
2764
- const isAll = options.all === true;
2765
- const isHead = options.head !== void 0;
2766
- const isTail = options.tail !== void 0;
2767
- let targetCount;
2768
- if (isAll) {
2769
- targetCount = "all";
2770
- } else if (isHead) {
2771
- targetCount = parsePositiveLogCount(options.head, "--head");
2772
- } else if (isTail) {
2773
- targetCount = parsePositiveLogCount(options.tail, "--tail");
2774
- } else {
2775
- targetCount = 5;
2776
- }
2777
- const order = isHead ? "asc" : "desc";
2778
- const apiUrl = await getApiUrl();
2779
- const platformUrl = buildPlatformLogsUrl(apiUrl, runId);
2780
- switch (logType) {
2781
- case "agent":
2782
- await showAgentEvents(
2783
- runId,
2784
- { since, targetCount, order },
2785
- platformUrl
2786
- );
2787
- break;
2788
- case "system":
2789
- await showSystemLog(runId, { since, targetCount, order });
2790
- break;
2791
- case "metrics":
2792
- await showMetrics(runId, { since, targetCount, order });
2793
- break;
2794
- case "network":
2795
- await showNetworkLogs(runId, { since, targetCount, order });
2796
- break;
2797
- }
2798
- }
2799
- )
2800
- );
2801
- async function showAgentEvents(runId, options, platformUrl) {
2802
- const events = await collectLogItems({
2803
- fetchPage: async (request) => {
2804
- const response = await getAgentEvents(runId, request);
2805
- const responseFramework = response.framework;
2806
- return {
2807
- items: response.events.map((event) => {
2808
- const framework2 = supportedLogFramework(
2809
- responseFramework ?? void 0
2810
- );
2811
- return {
2812
- event,
2813
- ...framework2 ? { framework: framework2 } : {},
2814
- useDefaultFramework: !hasLogFramework(responseFramework)
2815
- };
2816
- }),
2817
- hasMore: response.hasMore,
2818
- nextCursor: response.nextCursor
2819
- };
2820
- },
2821
- sinceTime: options.since,
2822
- targetCount: options.targetCount,
2823
- order: options.order,
2824
- pageLimit: PAGE_LIMIT
2825
- });
2826
- if (events.length === 0) {
2827
- console.log(source_default.yellow("No agent events found for this run"));
2828
- return;
2829
- }
2830
- const framework = events.find((item) => {
2831
- return item.framework !== void 0;
2832
- })?.framework;
2833
- const renderer = createLogRenderer(true);
2834
- const normalizer = new EventStreamNormalizer();
2835
- for (const item of events) {
2836
- renderAgentEvent(
2837
- item.event,
2838
- renderer,
2839
- normalizer,
2840
- item.framework ?? (item.useDefaultFramework ? framework : void 0)
2841
- );
2842
- }
2843
- for (const parsed of normalizer.flush()) {
2844
- renderer.render(parsed);
2845
- }
2846
- renderer.flush();
2847
- console.log(source_default.dim(`View on platform: ${platformUrl}`));
2848
- }
2849
- async function showSystemLog(runId, options) {
2850
- const pages = [];
2851
- const seenCursors = /* @__PURE__ */ new Set();
2852
- let cursor;
2853
- let remainingBatches = options.targetCount === "all" ? void 0 : options.targetCount;
2854
- while (true) {
2855
- const limit = remainingBatches === void 0 ? PAGE_LIMIT : Math.min(remainingBatches, PAGE_LIMIT);
2856
- const response = await getSystemLog(runId, {
2857
- sinceTime: options.since,
2858
- cursor,
2859
- limit,
2860
- order: options.order
2861
- });
2862
- const pageHasLog = response.systemLog.length > 0;
2863
- if (pageHasLog) {
2864
- pages.push(response.systemLog);
2865
- }
2866
- if (remainingBatches !== void 0 && pageHasLog) {
2867
- remainingBatches -= limit;
2868
- if (remainingBatches <= 0) {
2869
- break;
2870
- }
2871
- }
2872
- const nextCursor = response.nextCursor ?? null;
2873
- if (!response.hasMore || !nextCursor || seenCursors.has(nextCursor)) {
2874
- break;
2875
- }
2876
- seenCursors.add(nextCursor);
2877
- cursor = nextCursor;
2878
- }
2879
- if (pages.length === 0) {
2880
- console.log(source_default.yellow("No system log found for this run"));
2881
- return;
2882
- }
2883
- console.log(pages.join(""));
2884
- }
2885
- async function showMetrics(runId, options) {
2886
- const metrics = await collectLogItems({
2887
- fetchPage: async (request) => {
2888
- const response = await getMetrics(runId, request);
2889
- return {
2890
- items: response.metrics,
2891
- hasMore: response.hasMore,
2892
- nextCursor: response.nextCursor
2893
- };
2894
- },
2895
- sinceTime: options.since,
2896
- targetCount: options.targetCount,
2897
- order: options.order,
2898
- pageLimit: PAGE_LIMIT
2899
- });
2900
- if (metrics.length === 0) {
2901
- console.log(source_default.yellow("No metrics found for this run"));
2902
- return;
2903
- }
2904
- for (const metric of metrics) {
2905
- console.log(formatMetric(metric));
2906
- }
2907
- }
2908
- async function showNetworkLogs(runId, options) {
2909
- const networkLogs = await collectLogItems({
2910
- fetchPage: async (request) => {
2911
- const response = await getNetworkLogs(runId, request);
2912
- return {
2913
- items: response.networkLogs,
2914
- hasMore: response.hasMore,
2915
- nextCursor: response.nextCursor
2916
- };
2917
- },
2918
- sinceTime: options.since,
2919
- targetCount: options.targetCount,
2920
- order: options.order,
2921
- pageLimit: PAGE_LIMIT
2922
- });
2923
- if (networkLogs.length === 0) {
2924
- console.log(
2925
- source_default.yellow(
2926
- "No network logs found for this run. Network logs are only captured when using a runner with proxy enabled"
2927
- )
2928
- );
2929
- return;
2930
- }
2931
- for (const entry of networkLogs) {
2932
- console.log(formatNetworkLog(entry));
2933
- }
2934
- }
2935
-
2936
912
  // src/commands/whoami.ts
2937
913
  init_esm_shims();
2938
914
  function isInsideSandbox() {
@@ -2988,13 +964,9 @@ var whoamiCommand = new Command().name("whoami").description("Show current ident
2988
964
 
2989
965
  // src/index.ts
2990
966
  var program = new Command();
2991
- program.name("vm0").description("VM0 CLI - Build and run agents with natural language").version("9.244.5");
967
+ program.name("vm0").description("VM0 CLI - Build and run agents with natural language").version("9.244.7");
2992
968
  program.addCommand(authCommand);
2993
- program.addCommand(composeCommand);
2994
969
  program.addCommand(runCommand);
2995
- program.addCommand(volumeCommand);
2996
- program.addCommand(artifactCommand);
2997
- program.addCommand(logsCommand);
2998
970
  program.addCommand(whoamiCommand);
2999
971
  if (process.argv[1]?.endsWith("index.js") || process.argv[1]?.endsWith("index.ts") || process.argv[1]?.endsWith("vm0")) {
3000
972
  await configureGlobalProxyFromEnv();