@vm0/cli 4.35.2 → 4.36.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 +266 -674
- package/package.json +1 -1
package/index.js
CHANGED
|
@@ -6,8 +6,8 @@ var __export = (target, all) => {
|
|
|
6
6
|
};
|
|
7
7
|
|
|
8
8
|
// src/index.ts
|
|
9
|
-
import { Command as
|
|
10
|
-
import
|
|
9
|
+
import { Command as Command24 } from "commander";
|
|
10
|
+
import chalk27 from "chalk";
|
|
11
11
|
|
|
12
12
|
// src/lib/auth.ts
|
|
13
13
|
import chalk from "chalk";
|
|
@@ -2760,7 +2760,7 @@ var $ZodBase64 = /* @__PURE__ */ $constructor("$ZodBase64", (inst, def) => {
|
|
|
2760
2760
|
function isValidBase64URL(data) {
|
|
2761
2761
|
if (!base64url.test(data))
|
|
2762
2762
|
return false;
|
|
2763
|
-
const base643 = data.replace(/[-_]/g, (
|
|
2763
|
+
const base643 = data.replace(/[-_]/g, (c11) => c11 === "-" ? "+" : "/");
|
|
2764
2764
|
const padded = base643.padEnd(Math.ceil(base643.length / 4) * 4, "=");
|
|
2765
2765
|
return isValidBase64(padded);
|
|
2766
2766
|
}
|
|
@@ -11672,9 +11672,9 @@ var ZodDate = /* @__PURE__ */ $constructor("ZodDate", (inst, def) => {
|
|
|
11672
11672
|
ZodType.init(inst, def);
|
|
11673
11673
|
inst.min = (value, params) => inst.check(_gte(value, params));
|
|
11674
11674
|
inst.max = (value, params) => inst.check(_lte(value, params));
|
|
11675
|
-
const
|
|
11676
|
-
inst.minDate =
|
|
11677
|
-
inst.maxDate =
|
|
11675
|
+
const c11 = inst._zod.bag;
|
|
11676
|
+
inst.minDate = c11.minimum ? new Date(c11.minimum) : null;
|
|
11677
|
+
inst.maxDate = c11.maximum ? new Date(c11.maximum) : null;
|
|
11678
11678
|
});
|
|
11679
11679
|
function date3(params) {
|
|
11680
11680
|
return _date(ZodDate, params);
|
|
@@ -12269,6 +12269,13 @@ var apiErrorSchema = external_exports.object({
|
|
|
12269
12269
|
|
|
12270
12270
|
// ../../packages/core/src/contracts/composes.ts
|
|
12271
12271
|
var c = initContract();
|
|
12272
|
+
var composeVersionQuerySchema = external_exports.preprocess(
|
|
12273
|
+
(val) => val === void 0 || val === null ? void 0 : String(val),
|
|
12274
|
+
external_exports.string().min(1, "Missing version query parameter").regex(
|
|
12275
|
+
/^[a-f0-9]{8,64}$|^latest$/i,
|
|
12276
|
+
"Version must be 8-64 hex characters or 'latest'"
|
|
12277
|
+
)
|
|
12278
|
+
);
|
|
12272
12279
|
var agentNameSchema = external_exports.string().min(3, "Agent name must be at least 3 characters").max(64, "Agent name must be 64 characters or less").regex(
|
|
12273
12280
|
/^[a-zA-Z0-9][a-zA-Z0-9-]{1,62}[a-zA-Z0-9]$/,
|
|
12274
12281
|
"Agent name must start and end with letter or number, and contain only letters, numbers, and hyphens"
|
|
@@ -12277,11 +12284,33 @@ var volumeConfigSchema = external_exports.object({
|
|
|
12277
12284
|
name: external_exports.string().min(1, "Volume name is required"),
|
|
12278
12285
|
version: external_exports.string().min(1, "Volume version is required")
|
|
12279
12286
|
});
|
|
12287
|
+
var SUPPORTED_APPS = ["github"];
|
|
12288
|
+
var SUPPORTED_APP_TAGS = ["latest", "dev"];
|
|
12289
|
+
var appStringSchema = external_exports.string().regex(
|
|
12290
|
+
/^[a-z]+(:(?:latest|dev))?$/,
|
|
12291
|
+
"App must be in format 'app' or 'app:tag' (e.g., 'github', 'github:dev')"
|
|
12292
|
+
).refine(
|
|
12293
|
+
(val) => {
|
|
12294
|
+
const [app] = val.split(":");
|
|
12295
|
+
return SUPPORTED_APPS.includes(app);
|
|
12296
|
+
},
|
|
12297
|
+
`Unsupported app. Supported apps: ${SUPPORTED_APPS.join(", ")}`
|
|
12298
|
+
);
|
|
12280
12299
|
var agentDefinitionSchema = external_exports.object({
|
|
12281
12300
|
description: external_exports.string().optional(),
|
|
12301
|
+
/**
|
|
12302
|
+
* @deprecated Use `apps` field instead for pre-installed tools.
|
|
12303
|
+
* This field will be removed in a future version.
|
|
12304
|
+
*/
|
|
12282
12305
|
image: external_exports.string().optional(),
|
|
12283
|
-
// Optional when provider supports auto-config
|
|
12284
12306
|
provider: external_exports.string().min(1, "Provider is required"),
|
|
12307
|
+
/**
|
|
12308
|
+
* Array of pre-installed apps/tools for the agent environment.
|
|
12309
|
+
* Format: "app" or "app:tag" (e.g., "github", "github:dev", "github:latest")
|
|
12310
|
+
* Default tag is "latest" if not specified.
|
|
12311
|
+
* Currently supported apps: "github" (includes GitHub CLI)
|
|
12312
|
+
*/
|
|
12313
|
+
apps: external_exports.array(appStringSchema).optional(),
|
|
12285
12314
|
volumes: external_exports.array(external_exports.string()).optional(),
|
|
12286
12315
|
working_dir: external_exports.string().optional(),
|
|
12287
12316
|
// Optional when provider supports auto-config
|
|
@@ -12405,7 +12434,7 @@ var composesVersionsContract = c.router({
|
|
|
12405
12434
|
path: "/api/agent/composes/versions",
|
|
12406
12435
|
query: external_exports.object({
|
|
12407
12436
|
composeId: external_exports.string().min(1, "Missing composeId query parameter"),
|
|
12408
|
-
version:
|
|
12437
|
+
version: composeVersionQuerySchema
|
|
12409
12438
|
}),
|
|
12410
12439
|
responses: {
|
|
12411
12440
|
200: external_exports.object({
|
|
@@ -12714,6 +12743,10 @@ var runNetworkLogsContract = c2.router({
|
|
|
12714
12743
|
// ../../packages/core/src/contracts/storages.ts
|
|
12715
12744
|
var c3 = initContract();
|
|
12716
12745
|
var storageTypeSchema = external_exports.enum(["volume", "artifact"]);
|
|
12746
|
+
var versionQuerySchema = external_exports.preprocess(
|
|
12747
|
+
(val) => val === void 0 || val === null ? void 0 : String(val),
|
|
12748
|
+
external_exports.string().regex(/^[a-f0-9]{8,64}$/i, "Version must be 8-64 hex characters").optional()
|
|
12749
|
+
);
|
|
12717
12750
|
var uploadStorageResponseSchema = external_exports.object({
|
|
12718
12751
|
name: external_exports.string(),
|
|
12719
12752
|
versionId: external_exports.string(),
|
|
@@ -12762,7 +12795,7 @@ var storagesContract = c3.router({
|
|
|
12762
12795
|
path: "/api/storages",
|
|
12763
12796
|
query: external_exports.object({
|
|
12764
12797
|
name: external_exports.string().min(1, "Storage name is required"),
|
|
12765
|
-
version:
|
|
12798
|
+
version: versionQuerySchema
|
|
12766
12799
|
}),
|
|
12767
12800
|
responses: {
|
|
12768
12801
|
// Binary response - actual handling done at route level
|
|
@@ -12862,7 +12895,7 @@ var storagesDownloadContract = c3.router({
|
|
|
12862
12895
|
query: external_exports.object({
|
|
12863
12896
|
name: external_exports.string().min(1, "Storage name is required"),
|
|
12864
12897
|
type: storageTypeSchema,
|
|
12865
|
-
version:
|
|
12898
|
+
version: versionQuerySchema
|
|
12866
12899
|
}),
|
|
12867
12900
|
responses: {
|
|
12868
12901
|
// Normal response with presigned URL
|
|
@@ -13291,129 +13324,8 @@ var authContract = c6.router({
|
|
|
13291
13324
|
}
|
|
13292
13325
|
});
|
|
13293
13326
|
|
|
13294
|
-
// ../../packages/core/src/contracts/images.ts
|
|
13295
|
-
var c7 = initContract();
|
|
13296
|
-
var buildStatusSchema = external_exports.enum(["building", "ready", "error"]);
|
|
13297
|
-
var imageInfoSchema = external_exports.object({
|
|
13298
|
-
id: external_exports.string(),
|
|
13299
|
-
alias: external_exports.string(),
|
|
13300
|
-
versionId: external_exports.string().nullable(),
|
|
13301
|
-
// null for legacy images without versioning
|
|
13302
|
-
status: external_exports.string(),
|
|
13303
|
-
errorMessage: external_exports.string().nullable(),
|
|
13304
|
-
createdAt: external_exports.coerce.date(),
|
|
13305
|
-
updatedAt: external_exports.coerce.date()
|
|
13306
|
-
});
|
|
13307
|
-
var createImageRequestSchema = external_exports.object({
|
|
13308
|
-
dockerfile: external_exports.string().min(1, "dockerfile is required"),
|
|
13309
|
-
alias: external_exports.string().min(3, "alias must be at least 3 characters").max(64, "alias must be at most 64 characters").regex(
|
|
13310
|
-
/^[a-zA-Z0-9][a-zA-Z0-9-]{1,62}[a-zA-Z0-9]$/,
|
|
13311
|
-
"alias must be 3-64 characters, alphanumeric and hyphens, start/end with alphanumeric"
|
|
13312
|
-
).refine(
|
|
13313
|
-
(val) => !val.toLowerCase().startsWith("vm0-"),
|
|
13314
|
-
'alias cannot start with "vm0-" (reserved for system templates)'
|
|
13315
|
-
).transform((s) => s.toLowerCase()),
|
|
13316
|
-
deleteExisting: external_exports.boolean().optional()
|
|
13317
|
-
});
|
|
13318
|
-
var createImageResponseSchema = external_exports.object({
|
|
13319
|
-
buildId: external_exports.string(),
|
|
13320
|
-
imageId: external_exports.string(),
|
|
13321
|
-
alias: external_exports.string(),
|
|
13322
|
-
versionId: external_exports.string()
|
|
13323
|
-
// nanoid(8), unique per build
|
|
13324
|
-
});
|
|
13325
|
-
var buildStatusResponseSchema = external_exports.object({
|
|
13326
|
-
status: buildStatusSchema,
|
|
13327
|
-
logs: external_exports.array(external_exports.string()),
|
|
13328
|
-
logsOffset: external_exports.number(),
|
|
13329
|
-
error: external_exports.string().optional()
|
|
13330
|
-
});
|
|
13331
|
-
var imagesMainContract = c7.router({
|
|
13332
|
-
/**
|
|
13333
|
-
* GET /api/images
|
|
13334
|
-
* List all images for authenticated user
|
|
13335
|
-
*/
|
|
13336
|
-
list: {
|
|
13337
|
-
method: "GET",
|
|
13338
|
-
path: "/api/images",
|
|
13339
|
-
responses: {
|
|
13340
|
-
200: external_exports.object({
|
|
13341
|
-
images: external_exports.array(imageInfoSchema)
|
|
13342
|
-
}),
|
|
13343
|
-
401: apiErrorSchema,
|
|
13344
|
-
500: apiErrorSchema
|
|
13345
|
-
},
|
|
13346
|
-
summary: "List user images"
|
|
13347
|
-
},
|
|
13348
|
-
/**
|
|
13349
|
-
* POST /api/images
|
|
13350
|
-
* Create an image build task from a Dockerfile
|
|
13351
|
-
*/
|
|
13352
|
-
create: {
|
|
13353
|
-
method: "POST",
|
|
13354
|
-
path: "/api/images",
|
|
13355
|
-
body: createImageRequestSchema,
|
|
13356
|
-
responses: {
|
|
13357
|
-
202: createImageResponseSchema,
|
|
13358
|
-
400: apiErrorSchema,
|
|
13359
|
-
401: apiErrorSchema,
|
|
13360
|
-
500: apiErrorSchema
|
|
13361
|
-
},
|
|
13362
|
-
summary: "Create image build"
|
|
13363
|
-
}
|
|
13364
|
-
});
|
|
13365
|
-
var imagesByIdContract = c7.router({
|
|
13366
|
-
/**
|
|
13367
|
-
* DELETE /api/images/:imageId
|
|
13368
|
-
* Delete an image by ID
|
|
13369
|
-
*/
|
|
13370
|
-
delete: {
|
|
13371
|
-
method: "DELETE",
|
|
13372
|
-
path: "/api/images/:imageId",
|
|
13373
|
-
pathParams: external_exports.object({
|
|
13374
|
-
imageId: external_exports.string().min(1, "imageId is required")
|
|
13375
|
-
}),
|
|
13376
|
-
responses: {
|
|
13377
|
-
200: external_exports.object({
|
|
13378
|
-
deleted: external_exports.boolean()
|
|
13379
|
-
}),
|
|
13380
|
-
400: apiErrorSchema,
|
|
13381
|
-
401: apiErrorSchema,
|
|
13382
|
-
403: apiErrorSchema,
|
|
13383
|
-
404: apiErrorSchema,
|
|
13384
|
-
500: apiErrorSchema
|
|
13385
|
-
},
|
|
13386
|
-
summary: "Delete image"
|
|
13387
|
-
}
|
|
13388
|
-
});
|
|
13389
|
-
var imageBuildsContract = c7.router({
|
|
13390
|
-
/**
|
|
13391
|
-
* GET /api/images/:imageId/builds/:buildId
|
|
13392
|
-
* Query build status with incremental logs
|
|
13393
|
-
*/
|
|
13394
|
-
getStatus: {
|
|
13395
|
-
method: "GET",
|
|
13396
|
-
path: "/api/images/:imageId/builds/:buildId",
|
|
13397
|
-
pathParams: external_exports.object({
|
|
13398
|
-
imageId: external_exports.string().min(1, "imageId is required"),
|
|
13399
|
-
buildId: external_exports.string().min(1, "buildId is required")
|
|
13400
|
-
}),
|
|
13401
|
-
query: external_exports.object({
|
|
13402
|
-
logsOffset: external_exports.coerce.number().int().min(0).optional().default(0)
|
|
13403
|
-
}),
|
|
13404
|
-
responses: {
|
|
13405
|
-
200: buildStatusResponseSchema,
|
|
13406
|
-
400: apiErrorSchema,
|
|
13407
|
-
401: apiErrorSchema,
|
|
13408
|
-
404: apiErrorSchema,
|
|
13409
|
-
500: apiErrorSchema
|
|
13410
|
-
},
|
|
13411
|
-
summary: "Get build status"
|
|
13412
|
-
}
|
|
13413
|
-
});
|
|
13414
|
-
|
|
13415
13327
|
// ../../packages/core/src/contracts/cron.ts
|
|
13416
|
-
var
|
|
13328
|
+
var c7 = initContract();
|
|
13417
13329
|
var cleanupResultSchema = external_exports.object({
|
|
13418
13330
|
runId: external_exports.string(),
|
|
13419
13331
|
sandboxId: external_exports.string().nullable(),
|
|
@@ -13425,7 +13337,7 @@ var cleanupResponseSchema = external_exports.object({
|
|
|
13425
13337
|
errors: external_exports.number(),
|
|
13426
13338
|
results: external_exports.array(cleanupResultSchema)
|
|
13427
13339
|
});
|
|
13428
|
-
var cronCleanupSandboxesContract =
|
|
13340
|
+
var cronCleanupSandboxesContract = c7.router({
|
|
13429
13341
|
/**
|
|
13430
13342
|
* GET /api/cron/cleanup-sandboxes
|
|
13431
13343
|
* Cron job to cleanup sandboxes that have stopped sending heartbeats
|
|
@@ -13457,7 +13369,7 @@ var proxyErrorSchema = external_exports.object({
|
|
|
13457
13369
|
});
|
|
13458
13370
|
|
|
13459
13371
|
// ../../packages/core/src/contracts/scopes.ts
|
|
13460
|
-
var
|
|
13372
|
+
var c8 = initContract();
|
|
13461
13373
|
var scopeTypeSchema = external_exports.enum(["personal", "organization", "system"]);
|
|
13462
13374
|
var scopeSlugSchema = external_exports.string().min(3, "Scope slug must be at least 3 characters").max(64, "Scope slug must be at most 64 characters").regex(
|
|
13463
13375
|
/^[a-z0-9][a-z0-9-]*[a-z0-9]$|^[a-z0-9]{1,2}$/,
|
|
@@ -13482,7 +13394,7 @@ var updateScopeRequestSchema = external_exports.object({
|
|
|
13482
13394
|
slug: scopeSlugSchema,
|
|
13483
13395
|
force: external_exports.boolean().optional().default(false)
|
|
13484
13396
|
});
|
|
13485
|
-
var scopeContract =
|
|
13397
|
+
var scopeContract = c8.router({
|
|
13486
13398
|
/**
|
|
13487
13399
|
* GET /api/scope
|
|
13488
13400
|
* Get current user's scope
|
|
@@ -13537,7 +13449,7 @@ var scopeContract = c9.router({
|
|
|
13537
13449
|
});
|
|
13538
13450
|
|
|
13539
13451
|
// ../../packages/core/src/contracts/sessions.ts
|
|
13540
|
-
var
|
|
13452
|
+
var c9 = initContract();
|
|
13541
13453
|
var sessionResponseSchema = external_exports.object({
|
|
13542
13454
|
id: external_exports.string(),
|
|
13543
13455
|
agentComposeId: external_exports.string(),
|
|
@@ -13571,7 +13483,7 @@ var checkpointResponseSchema = external_exports.object({
|
|
|
13571
13483
|
volumeVersionsSnapshot: volumeVersionsSnapshotSchema2.nullable(),
|
|
13572
13484
|
createdAt: external_exports.string()
|
|
13573
13485
|
});
|
|
13574
|
-
var sessionsByIdContract =
|
|
13486
|
+
var sessionsByIdContract = c9.router({
|
|
13575
13487
|
/**
|
|
13576
13488
|
* GET /api/agent/sessions/:id
|
|
13577
13489
|
* Get session by ID
|
|
@@ -13591,7 +13503,7 @@ var sessionsByIdContract = c10.router({
|
|
|
13591
13503
|
summary: "Get session by ID"
|
|
13592
13504
|
}
|
|
13593
13505
|
});
|
|
13594
|
-
var checkpointsByIdContract =
|
|
13506
|
+
var checkpointsByIdContract = c9.router({
|
|
13595
13507
|
/**
|
|
13596
13508
|
* GET /api/agent/checkpoints/:id
|
|
13597
13509
|
* Get checkpoint by ID
|
|
@@ -13613,7 +13525,7 @@ var checkpointsByIdContract = c10.router({
|
|
|
13613
13525
|
});
|
|
13614
13526
|
|
|
13615
13527
|
// ../../packages/core/src/contracts/runners.ts
|
|
13616
|
-
var
|
|
13528
|
+
var c10 = initContract();
|
|
13617
13529
|
var runnerGroupSchema = external_exports.string().regex(
|
|
13618
13530
|
/^[a-z0-9-]+\/[a-z0-9-]+$/,
|
|
13619
13531
|
"Runner group must be in scope/name format (e.g., acme/production)"
|
|
@@ -13626,7 +13538,7 @@ var jobSchema = external_exports.object({
|
|
|
13626
13538
|
secretNames: external_exports.array(external_exports.string()).nullable(),
|
|
13627
13539
|
checkpointId: external_exports.string().uuid().nullable()
|
|
13628
13540
|
});
|
|
13629
|
-
var runnersPollContract =
|
|
13541
|
+
var runnersPollContract = c10.router({
|
|
13630
13542
|
poll: {
|
|
13631
13543
|
method: "POST",
|
|
13632
13544
|
path: "/api/runners/poll",
|
|
@@ -13688,7 +13600,7 @@ var executionContextSchema = external_exports.object({
|
|
|
13688
13600
|
secretValues: external_exports.array(external_exports.string()).nullable(),
|
|
13689
13601
|
cliAgentType: external_exports.string()
|
|
13690
13602
|
});
|
|
13691
|
-
var runnersJobClaimContract =
|
|
13603
|
+
var runnersJobClaimContract = c10.router({
|
|
13692
13604
|
claim: {
|
|
13693
13605
|
method: "POST",
|
|
13694
13606
|
path: "/api/runners/jobs/:id/claim",
|
|
@@ -13729,7 +13641,7 @@ function getLegacySystemTemplateWarning(legacyFormat) {
|
|
|
13729
13641
|
return `Warning: "${legacyFormat}" format is deprecated. Use "vm0/codex:dev" instead.`;
|
|
13730
13642
|
}
|
|
13731
13643
|
if (legacyFormat.startsWith("vm0-github-cli")) {
|
|
13732
|
-
return `Warning: "${legacyFormat}" is deprecated
|
|
13644
|
+
return `Warning: "${legacyFormat}" is deprecated. Use "apps: [github]" in vm0.yaml instead.`;
|
|
13733
13645
|
}
|
|
13734
13646
|
return `Warning: "${legacyFormat}" format is deprecated.`;
|
|
13735
13647
|
}
|
|
@@ -13737,12 +13649,6 @@ function isLegacySystemTemplate(reference) {
|
|
|
13737
13649
|
return reference.startsWith("vm0-");
|
|
13738
13650
|
}
|
|
13739
13651
|
|
|
13740
|
-
// ../../packages/core/src/version-id.ts
|
|
13741
|
-
var VERSION_ID_DISPLAY_LENGTH = 8;
|
|
13742
|
-
function formatVersionIdForDisplay(versionId) {
|
|
13743
|
-
return versionId.slice(0, VERSION_ID_DISPLAY_LENGTH);
|
|
13744
|
-
}
|
|
13745
|
-
|
|
13746
13652
|
// ../../packages/core/src/storage-names.ts
|
|
13747
13653
|
function getInstructionsStorageName(agentName) {
|
|
13748
13654
|
return `agent-instructions@${agentName}`;
|
|
@@ -14249,9 +14155,43 @@ function getProviderDefaults(provider) {
|
|
|
14249
14155
|
function isProviderSupported(provider) {
|
|
14250
14156
|
return provider in PROVIDER_DEFAULTS;
|
|
14251
14157
|
}
|
|
14252
|
-
|
|
14158
|
+
var PROVIDER_APPS_IMAGES = {
|
|
14159
|
+
"claude-code": {
|
|
14160
|
+
github: {
|
|
14161
|
+
production: "vm0/claude-code-github:latest",
|
|
14162
|
+
development: "vm0/claude-code-github:dev"
|
|
14163
|
+
}
|
|
14164
|
+
},
|
|
14165
|
+
codex: {
|
|
14166
|
+
github: {
|
|
14167
|
+
production: "vm0/codex-github:latest",
|
|
14168
|
+
development: "vm0/codex-github:dev"
|
|
14169
|
+
}
|
|
14170
|
+
}
|
|
14171
|
+
};
|
|
14172
|
+
function parseAppString(appString) {
|
|
14173
|
+
const [app, tag] = appString.split(":");
|
|
14174
|
+
return {
|
|
14175
|
+
app: app ?? appString,
|
|
14176
|
+
tag: tag === "dev" ? "dev" : "latest"
|
|
14177
|
+
};
|
|
14178
|
+
}
|
|
14179
|
+
function getDefaultImageWithApps(provider, apps) {
|
|
14253
14180
|
const defaults = PROVIDER_DEFAULTS[provider];
|
|
14254
14181
|
if (!defaults) return void 0;
|
|
14182
|
+
if (apps && apps.length > 0) {
|
|
14183
|
+
const providerApps = PROVIDER_APPS_IMAGES[provider];
|
|
14184
|
+
if (providerApps) {
|
|
14185
|
+
const firstApp = apps[0];
|
|
14186
|
+
if (firstApp) {
|
|
14187
|
+
const { app, tag } = parseAppString(firstApp);
|
|
14188
|
+
const appImage = providerApps[app];
|
|
14189
|
+
if (appImage) {
|
|
14190
|
+
return tag === "dev" ? appImage.development : appImage.production;
|
|
14191
|
+
}
|
|
14192
|
+
}
|
|
14193
|
+
}
|
|
14194
|
+
}
|
|
14255
14195
|
const isDevelopment = process.env.NODE_ENV === "development" || process.env.NODE_ENV === "test";
|
|
14256
14196
|
return isDevelopment ? defaults.image.development : defaults.image.production;
|
|
14257
14197
|
}
|
|
@@ -14448,6 +14388,41 @@ function validateAgentCompose(config2) {
|
|
|
14448
14388
|
}
|
|
14449
14389
|
}
|
|
14450
14390
|
}
|
|
14391
|
+
if (agent.apps !== void 0) {
|
|
14392
|
+
if (!Array.isArray(agent.apps)) {
|
|
14393
|
+
return {
|
|
14394
|
+
valid: false,
|
|
14395
|
+
error: "agent.apps must be an array of strings"
|
|
14396
|
+
};
|
|
14397
|
+
}
|
|
14398
|
+
for (const appEntry of agent.apps) {
|
|
14399
|
+
if (typeof appEntry !== "string") {
|
|
14400
|
+
return {
|
|
14401
|
+
valid: false,
|
|
14402
|
+
error: "Each entry in apps must be a string"
|
|
14403
|
+
};
|
|
14404
|
+
}
|
|
14405
|
+
const [appName, tag] = appEntry.split(":");
|
|
14406
|
+
if (!appName) {
|
|
14407
|
+
return {
|
|
14408
|
+
valid: false,
|
|
14409
|
+
error: `Invalid app format: "${appEntry}". Expected "app" or "app:tag"`
|
|
14410
|
+
};
|
|
14411
|
+
}
|
|
14412
|
+
if (!SUPPORTED_APPS.includes(appName)) {
|
|
14413
|
+
return {
|
|
14414
|
+
valid: false,
|
|
14415
|
+
error: `Invalid app: "${appName}". Supported apps: ${SUPPORTED_APPS.join(", ")}`
|
|
14416
|
+
};
|
|
14417
|
+
}
|
|
14418
|
+
if (tag !== void 0 && !SUPPORTED_APP_TAGS.includes(tag)) {
|
|
14419
|
+
return {
|
|
14420
|
+
valid: false,
|
|
14421
|
+
error: `Invalid app tag: "${tag}". Supported tags: ${SUPPORTED_APP_TAGS.join(", ")}`
|
|
14422
|
+
};
|
|
14423
|
+
}
|
|
14424
|
+
}
|
|
14425
|
+
}
|
|
14451
14426
|
const agentVolumes = agent.volumes;
|
|
14452
14427
|
if (agentVolumes && Array.isArray(agentVolumes) && agentVolumes.length > 0) {
|
|
14453
14428
|
const volumesSection = cfg.volumes;
|
|
@@ -15011,9 +14986,14 @@ var composeCommand = new Command().name("compose").description("Create or update
|
|
|
15011
14986
|
for (const [name, agentConfig] of Object.entries(agentsConfig)) {
|
|
15012
14987
|
const image = agentConfig.image;
|
|
15013
14988
|
if (image) {
|
|
14989
|
+
console.log(
|
|
14990
|
+
chalk2.yellow(
|
|
14991
|
+
`\u26A0 Agent "${name}": 'image' field is deprecated. Use 'apps' field for pre-installed tools.`
|
|
14992
|
+
)
|
|
14993
|
+
);
|
|
15014
14994
|
const warning = getLegacySystemTemplateWarning(image);
|
|
15015
14995
|
if (warning) {
|
|
15016
|
-
console.log(chalk2.yellow(
|
|
14996
|
+
console.log(chalk2.yellow(` ${warning}`));
|
|
15017
14997
|
}
|
|
15018
14998
|
}
|
|
15019
14999
|
}
|
|
@@ -15025,7 +15005,11 @@ var composeCommand = new Command().name("compose").description("Create or update
|
|
|
15025
15005
|
const defaults = getProviderDefaults(agent.provider);
|
|
15026
15006
|
if (defaults) {
|
|
15027
15007
|
if (!agent.image) {
|
|
15028
|
-
const
|
|
15008
|
+
const apps = agent.apps;
|
|
15009
|
+
const defaultImage = getDefaultImageWithApps(
|
|
15010
|
+
agent.provider,
|
|
15011
|
+
apps
|
|
15012
|
+
);
|
|
15029
15013
|
if (defaultImage) {
|
|
15030
15014
|
agent.image = defaultImage;
|
|
15031
15015
|
console.log(
|
|
@@ -15474,9 +15458,9 @@ var CodexEventParser = class {
|
|
|
15474
15458
|
}
|
|
15475
15459
|
}
|
|
15476
15460
|
if (itemType === "file_change" && item.changes && item.changes.length > 0) {
|
|
15477
|
-
const changes = item.changes.map((
|
|
15478
|
-
const action =
|
|
15479
|
-
return `${action}: ${
|
|
15461
|
+
const changes = item.changes.map((c11) => {
|
|
15462
|
+
const action = c11.kind === "add" ? "Created" : c11.kind === "modify" ? "Modified" : "Deleted";
|
|
15463
|
+
return `${action}: ${c11.path}`;
|
|
15480
15464
|
}).join("\n");
|
|
15481
15465
|
return {
|
|
15482
15466
|
type: "text",
|
|
@@ -15817,9 +15801,9 @@ var CodexEventRenderer = class {
|
|
|
15817
15801
|
return;
|
|
15818
15802
|
}
|
|
15819
15803
|
if (itemType === "file_change" && item.changes && item.changes.length > 0) {
|
|
15820
|
-
const summary = item.changes.map((
|
|
15821
|
-
const icon =
|
|
15822
|
-
return `${icon}${
|
|
15804
|
+
const summary = item.changes.map((c11) => {
|
|
15805
|
+
const icon = c11.kind === "add" ? "+" : c11.kind === "delete" ? "-" : "~";
|
|
15806
|
+
return `${icon}${c11.path}`;
|
|
15823
15807
|
}).join(", ");
|
|
15824
15808
|
console.log(chalk4.green("[files]") + ` ${summary}`);
|
|
15825
15809
|
return;
|
|
@@ -17708,7 +17692,7 @@ async function autoPullArtifact(runOutput, artifactDir) {
|
|
|
17708
17692
|
}
|
|
17709
17693
|
var cookCmd = new Command17().name("cook").description("One-click agent preparation and execution from vm0.yaml");
|
|
17710
17694
|
cookCmd.argument("[prompt]", "Prompt for the agent").option("-y, --yes", "Skip confirmation prompts").action(async (prompt, options) => {
|
|
17711
|
-
const shouldExit = await checkAndUpgrade("4.
|
|
17695
|
+
const shouldExit = await checkAndUpgrade("4.36.0", prompt);
|
|
17712
17696
|
if (shouldExit) {
|
|
17713
17697
|
process.exit(0);
|
|
17714
17698
|
}
|
|
@@ -17992,400 +17976,9 @@ cookCmd.command("resume").description(
|
|
|
17992
17976
|
});
|
|
17993
17977
|
var cookCommand = cookCmd;
|
|
17994
17978
|
|
|
17995
|
-
// src/commands/
|
|
17996
|
-
import { Command as Command22 } from "commander";
|
|
17997
|
-
|
|
17998
|
-
// src/commands/image/build.ts
|
|
17979
|
+
// src/commands/logs/index.ts
|
|
17999
17980
|
import { Command as Command18 } from "commander";
|
|
18000
17981
|
import chalk22 from "chalk";
|
|
18001
|
-
import { readFile as readFile8 } from "fs/promises";
|
|
18002
|
-
import { existsSync as existsSync9 } from "fs";
|
|
18003
|
-
|
|
18004
|
-
// src/lib/dockerfile-validator.ts
|
|
18005
|
-
var ALLOWED_INSTRUCTIONS = /* @__PURE__ */ new Set(["FROM", "RUN"]);
|
|
18006
|
-
function validateDockerfile(content) {
|
|
18007
|
-
const errors = [];
|
|
18008
|
-
const lines = content.split("\n");
|
|
18009
|
-
let inContinuation = false;
|
|
18010
|
-
for (let i = 0; i < lines.length; i++) {
|
|
18011
|
-
const line = lines[i];
|
|
18012
|
-
const trimmed = line.trim();
|
|
18013
|
-
if (!inContinuation && !trimmed) continue;
|
|
18014
|
-
if (!inContinuation && trimmed.startsWith("#")) continue;
|
|
18015
|
-
if (inContinuation) {
|
|
18016
|
-
inContinuation = trimmed.endsWith("\\");
|
|
18017
|
-
continue;
|
|
18018
|
-
}
|
|
18019
|
-
const match = trimmed.match(/^([A-Za-z]+)\s/);
|
|
18020
|
-
if (match) {
|
|
18021
|
-
const instruction = match[1].toUpperCase();
|
|
18022
|
-
if (!ALLOWED_INSTRUCTIONS.has(instruction)) {
|
|
18023
|
-
errors.push(`Unsupported instruction: ${instruction} (line ${i + 1})`);
|
|
18024
|
-
}
|
|
18025
|
-
}
|
|
18026
|
-
inContinuation = trimmed.endsWith("\\");
|
|
18027
|
-
}
|
|
18028
|
-
return {
|
|
18029
|
-
valid: errors.length === 0,
|
|
18030
|
-
errors
|
|
18031
|
-
};
|
|
18032
|
-
}
|
|
18033
|
-
|
|
18034
|
-
// src/commands/image/build.ts
|
|
18035
|
-
var sleep2 = (ms) => new Promise((resolve2) => setTimeout(resolve2, ms));
|
|
18036
|
-
var buildCommand = new Command18().name("build").description("Build a custom image from a Dockerfile").requiredOption("-f, --file <path>", "Path to Dockerfile").requiredOption("-n, --name <name>", "Name for the image").option("--delete-existing", "Delete existing image before building").action(
|
|
18037
|
-
async (options) => {
|
|
18038
|
-
const { file: file2, name, deleteExisting } = options;
|
|
18039
|
-
if (!existsSync9(file2)) {
|
|
18040
|
-
console.error(chalk22.red(`\u2717 Dockerfile not found: ${file2}`));
|
|
18041
|
-
process.exit(1);
|
|
18042
|
-
}
|
|
18043
|
-
const nameRegex = /^[a-zA-Z0-9][a-zA-Z0-9-]{1,62}[a-zA-Z0-9]$/;
|
|
18044
|
-
if (!nameRegex.test(name)) {
|
|
18045
|
-
console.error(
|
|
18046
|
-
chalk22.red(
|
|
18047
|
-
"\u2717 Invalid name format. Must be 3-64 characters, letters, numbers, and hyphens only."
|
|
18048
|
-
)
|
|
18049
|
-
);
|
|
18050
|
-
process.exit(1);
|
|
18051
|
-
}
|
|
18052
|
-
if (name.startsWith("vm0-")) {
|
|
18053
|
-
console.error(
|
|
18054
|
-
chalk22.red(
|
|
18055
|
-
'\u2717 Invalid name. Cannot start with "vm0-" (reserved prefix).'
|
|
18056
|
-
)
|
|
18057
|
-
);
|
|
18058
|
-
process.exit(1);
|
|
18059
|
-
}
|
|
18060
|
-
try {
|
|
18061
|
-
const scope = await apiClient.getScope();
|
|
18062
|
-
const dockerfile = await readFile8(file2, "utf8");
|
|
18063
|
-
const validation = validateDockerfile(dockerfile);
|
|
18064
|
-
if (!validation.valid) {
|
|
18065
|
-
console.error(chalk22.red("\u2717 Dockerfile validation failed\n"));
|
|
18066
|
-
for (const error43 of validation.errors) {
|
|
18067
|
-
console.error(chalk22.red(` ${error43}`));
|
|
18068
|
-
}
|
|
18069
|
-
console.error();
|
|
18070
|
-
console.error(
|
|
18071
|
-
chalk22.yellow(
|
|
18072
|
-
" vm0 image build only supports FROM and RUN instructions."
|
|
18073
|
-
)
|
|
18074
|
-
);
|
|
18075
|
-
console.error(
|
|
18076
|
-
chalk22.yellow(
|
|
18077
|
-
" The purpose is to pre-install environment dependencies."
|
|
18078
|
-
)
|
|
18079
|
-
);
|
|
18080
|
-
process.exit(1);
|
|
18081
|
-
}
|
|
18082
|
-
console.log(chalk22.bold(`Building image: ${scope.slug}/${name}`));
|
|
18083
|
-
console.log();
|
|
18084
|
-
const buildInfo = await apiClient.createImage({
|
|
18085
|
-
dockerfile,
|
|
18086
|
-
alias: name,
|
|
18087
|
-
deleteExisting
|
|
18088
|
-
});
|
|
18089
|
-
const { imageId, buildId, versionId } = buildInfo;
|
|
18090
|
-
console.log(chalk22.dim(` Build ID: ${buildId}`));
|
|
18091
|
-
console.log();
|
|
18092
|
-
let logsOffset = 0;
|
|
18093
|
-
let status = "building";
|
|
18094
|
-
while (status === "building") {
|
|
18095
|
-
const statusResponse = await apiClient.get(
|
|
18096
|
-
`/api/images/${imageId}/builds/${buildId}?logsOffset=${logsOffset}`
|
|
18097
|
-
);
|
|
18098
|
-
if (!statusResponse.ok) {
|
|
18099
|
-
const error43 = await statusResponse.json();
|
|
18100
|
-
throw new Error(
|
|
18101
|
-
error43.error?.message || "Failed to get build status"
|
|
18102
|
-
);
|
|
18103
|
-
}
|
|
18104
|
-
const statusData = await statusResponse.json();
|
|
18105
|
-
for (const log of statusData.logs) {
|
|
18106
|
-
console.log(chalk22.dim(` ${log}`));
|
|
18107
|
-
}
|
|
18108
|
-
logsOffset = statusData.logsOffset;
|
|
18109
|
-
status = statusData.status;
|
|
18110
|
-
if (status === "building") {
|
|
18111
|
-
await sleep2(2e3);
|
|
18112
|
-
}
|
|
18113
|
-
}
|
|
18114
|
-
console.log();
|
|
18115
|
-
if (status === "ready") {
|
|
18116
|
-
const shortVersion = formatVersionIdForDisplay(versionId);
|
|
18117
|
-
console.log(
|
|
18118
|
-
chalk22.green(`\u2713 Image built: ${scope.slug}/${name}:${shortVersion}`)
|
|
18119
|
-
);
|
|
18120
|
-
} else {
|
|
18121
|
-
console.error(chalk22.red(`\u2717 Build failed`));
|
|
18122
|
-
process.exit(1);
|
|
18123
|
-
}
|
|
18124
|
-
} catch (error43) {
|
|
18125
|
-
if (error43 instanceof Error) {
|
|
18126
|
-
if (error43.message.includes("Not authenticated")) {
|
|
18127
|
-
console.error(
|
|
18128
|
-
chalk22.red("\u2717 Not authenticated. Run: vm0 auth login")
|
|
18129
|
-
);
|
|
18130
|
-
} else {
|
|
18131
|
-
console.error(chalk22.red(`\u2717 ${error43.message}`));
|
|
18132
|
-
}
|
|
18133
|
-
} else {
|
|
18134
|
-
console.error(chalk22.red("\u2717 An unexpected error occurred"));
|
|
18135
|
-
}
|
|
18136
|
-
process.exit(1);
|
|
18137
|
-
}
|
|
18138
|
-
}
|
|
18139
|
-
);
|
|
18140
|
-
|
|
18141
|
-
// src/commands/image/list.ts
|
|
18142
|
-
import { Command as Command19 } from "commander";
|
|
18143
|
-
import chalk23 from "chalk";
|
|
18144
|
-
var listCommand3 = new Command19().name("list").alias("ls").description("List your custom images").action(async () => {
|
|
18145
|
-
try {
|
|
18146
|
-
const response = await apiClient.get("/api/images");
|
|
18147
|
-
if (!response.ok) {
|
|
18148
|
-
const error43 = await response.json();
|
|
18149
|
-
throw new Error(
|
|
18150
|
-
error43.error?.message || "Failed to list images"
|
|
18151
|
-
);
|
|
18152
|
-
}
|
|
18153
|
-
const data = await response.json();
|
|
18154
|
-
const { images } = data;
|
|
18155
|
-
if (images.length === 0) {
|
|
18156
|
-
console.log(chalk23.dim("No images found."));
|
|
18157
|
-
console.log();
|
|
18158
|
-
console.log("Build your first image:");
|
|
18159
|
-
console.log(
|
|
18160
|
-
chalk23.cyan(" vm0 image build --file Dockerfile --name my-image")
|
|
18161
|
-
);
|
|
18162
|
-
return;
|
|
18163
|
-
}
|
|
18164
|
-
console.log(chalk23.bold("Your images:"));
|
|
18165
|
-
console.log();
|
|
18166
|
-
const imagesByAlias = /* @__PURE__ */ new Map();
|
|
18167
|
-
for (const image of images) {
|
|
18168
|
-
const list2 = imagesByAlias.get(image.alias) || [];
|
|
18169
|
-
list2.push(image);
|
|
18170
|
-
imagesByAlias.set(image.alias, list2);
|
|
18171
|
-
}
|
|
18172
|
-
const latestVersions = /* @__PURE__ */ new Map();
|
|
18173
|
-
for (const [alias, versions] of imagesByAlias) {
|
|
18174
|
-
const latestReady = versions.find((v) => v.status === "ready");
|
|
18175
|
-
latestVersions.set(alias, latestReady?.versionId || null);
|
|
18176
|
-
}
|
|
18177
|
-
console.log(
|
|
18178
|
-
chalk23.dim(
|
|
18179
|
-
`${"NAME".padEnd(40)} ${"STATUS".padEnd(12)} ${"CREATED".padEnd(20)}`
|
|
18180
|
-
)
|
|
18181
|
-
);
|
|
18182
|
-
console.log(chalk23.dim("-".repeat(72)));
|
|
18183
|
-
for (const image of images) {
|
|
18184
|
-
const statusColor = image.status === "ready" ? chalk23.green : image.status === "building" ? chalk23.yellow : chalk23.red;
|
|
18185
|
-
const createdAt = new Date(image.createdAt).toLocaleString();
|
|
18186
|
-
let displayName = image.alias;
|
|
18187
|
-
if (image.versionId) {
|
|
18188
|
-
const shortVersion = formatVersionIdForDisplay(image.versionId);
|
|
18189
|
-
displayName = `${image.alias}:${shortVersion}`;
|
|
18190
|
-
if (image.status === "ready" && latestVersions.get(image.alias) === image.versionId) {
|
|
18191
|
-
displayName = `${displayName} ${chalk23.cyan("latest")}`;
|
|
18192
|
-
}
|
|
18193
|
-
}
|
|
18194
|
-
console.log(
|
|
18195
|
-
`${displayName.padEnd(40)} ${statusColor(image.status.padEnd(12))} ${createdAt.padEnd(20)}`
|
|
18196
|
-
);
|
|
18197
|
-
if (image.status === "error" && image.errorMessage) {
|
|
18198
|
-
console.log(chalk23.red(` Error: ${image.errorMessage}`));
|
|
18199
|
-
}
|
|
18200
|
-
}
|
|
18201
|
-
console.log();
|
|
18202
|
-
console.log(chalk23.dim(`Total: ${images.length} version(s)`));
|
|
18203
|
-
} catch (error43) {
|
|
18204
|
-
if (error43 instanceof Error) {
|
|
18205
|
-
if (error43.message.includes("Not authenticated")) {
|
|
18206
|
-
console.error(chalk23.red("Not authenticated. Run: vm0 auth login"));
|
|
18207
|
-
} else {
|
|
18208
|
-
console.error(chalk23.red(`Error: ${error43.message}`));
|
|
18209
|
-
}
|
|
18210
|
-
} else {
|
|
18211
|
-
console.error(chalk23.red("An unexpected error occurred"));
|
|
18212
|
-
}
|
|
18213
|
-
process.exit(1);
|
|
18214
|
-
}
|
|
18215
|
-
});
|
|
18216
|
-
|
|
18217
|
-
// src/commands/image/delete.ts
|
|
18218
|
-
import { Command as Command20 } from "commander";
|
|
18219
|
-
import chalk24 from "chalk";
|
|
18220
|
-
var deleteCommand = new Command20().name("delete").alias("rm").description("Delete a custom image or specific version").argument("<name>", "Image name or name:version to delete").option("-f, --force", "Skip confirmation prompt").option("--all", "Delete all versions of the image").action(
|
|
18221
|
-
async (nameArg, options) => {
|
|
18222
|
-
try {
|
|
18223
|
-
const colonIndex = nameArg.lastIndexOf(":");
|
|
18224
|
-
const hasVersion = colonIndex > 0;
|
|
18225
|
-
const name = hasVersion ? nameArg.slice(0, colonIndex) : nameArg;
|
|
18226
|
-
const versionId = hasVersion ? nameArg.slice(colonIndex + 1) : null;
|
|
18227
|
-
const listResponse = await apiClient.get("/api/images");
|
|
18228
|
-
if (!listResponse.ok) {
|
|
18229
|
-
const error43 = await listResponse.json();
|
|
18230
|
-
throw new Error(
|
|
18231
|
-
error43.error?.message || "Failed to list images"
|
|
18232
|
-
);
|
|
18233
|
-
}
|
|
18234
|
-
const data = await listResponse.json();
|
|
18235
|
-
let imagesToDelete;
|
|
18236
|
-
if (versionId) {
|
|
18237
|
-
const matchingVersions = data.images.filter(
|
|
18238
|
-
(img) => img.alias === name && img.versionId && img.versionId.startsWith(versionId.toLowerCase())
|
|
18239
|
-
);
|
|
18240
|
-
if (matchingVersions.length === 0) {
|
|
18241
|
-
console.error(chalk24.red(`Image version not found: ${nameArg}`));
|
|
18242
|
-
process.exit(1);
|
|
18243
|
-
}
|
|
18244
|
-
if (matchingVersions.length > 1) {
|
|
18245
|
-
console.error(
|
|
18246
|
-
chalk24.red(
|
|
18247
|
-
`Ambiguous version prefix "${versionId}". Please use more characters.`
|
|
18248
|
-
)
|
|
18249
|
-
);
|
|
18250
|
-
process.exit(1);
|
|
18251
|
-
}
|
|
18252
|
-
imagesToDelete = [matchingVersions[0]];
|
|
18253
|
-
} else if (options.all) {
|
|
18254
|
-
imagesToDelete = data.images.filter((img) => img.alias === name);
|
|
18255
|
-
if (imagesToDelete.length === 0) {
|
|
18256
|
-
console.error(chalk24.red(`Image not found: ${name}`));
|
|
18257
|
-
process.exit(1);
|
|
18258
|
-
}
|
|
18259
|
-
} else {
|
|
18260
|
-
const matchingImages = data.images.filter(
|
|
18261
|
-
(img) => img.alias === name
|
|
18262
|
-
);
|
|
18263
|
-
if (matchingImages.length === 0) {
|
|
18264
|
-
console.error(chalk24.red(`Image not found: ${name}`));
|
|
18265
|
-
process.exit(1);
|
|
18266
|
-
}
|
|
18267
|
-
const latestReady = matchingImages.find(
|
|
18268
|
-
(img) => img.status === "ready"
|
|
18269
|
-
);
|
|
18270
|
-
if (latestReady) {
|
|
18271
|
-
imagesToDelete = [latestReady];
|
|
18272
|
-
} else {
|
|
18273
|
-
imagesToDelete = [matchingImages[0]];
|
|
18274
|
-
}
|
|
18275
|
-
}
|
|
18276
|
-
const firstImage = imagesToDelete[0];
|
|
18277
|
-
const firstVersionDisplay = firstImage.versionId ? `:${formatVersionIdForDisplay(firstImage.versionId)}` : "";
|
|
18278
|
-
const confirmMsg = imagesToDelete.length === 1 ? `Delete image "${firstImage.alias}${firstVersionDisplay}"?` : `Delete ${imagesToDelete.length} versions of "${name}"?`;
|
|
18279
|
-
if (!options.force) {
|
|
18280
|
-
const confirmed = await promptConfirm(confirmMsg, false);
|
|
18281
|
-
if (!confirmed) {
|
|
18282
|
-
console.log(chalk24.dim("Cancelled."));
|
|
18283
|
-
return;
|
|
18284
|
-
}
|
|
18285
|
-
}
|
|
18286
|
-
for (const image of imagesToDelete) {
|
|
18287
|
-
const deleteResponse = await apiClient.delete(
|
|
18288
|
-
`/api/images/${image.id}`
|
|
18289
|
-
);
|
|
18290
|
-
if (!deleteResponse.ok) {
|
|
18291
|
-
const error43 = await deleteResponse.json();
|
|
18292
|
-
throw new Error(
|
|
18293
|
-
error43.error?.message || "Failed to delete image"
|
|
18294
|
-
);
|
|
18295
|
-
}
|
|
18296
|
-
const displayName = image.versionId ? `${image.alias}:${formatVersionIdForDisplay(image.versionId)}` : image.alias;
|
|
18297
|
-
console.log(chalk24.green(`Deleted image: ${displayName}`));
|
|
18298
|
-
}
|
|
18299
|
-
} catch (error43) {
|
|
18300
|
-
if (error43 instanceof Error) {
|
|
18301
|
-
if (error43.message.includes("Not authenticated")) {
|
|
18302
|
-
console.error(chalk24.red("Not authenticated. Run: vm0 auth login"));
|
|
18303
|
-
} else {
|
|
18304
|
-
console.error(chalk24.red(`Error: ${error43.message}`));
|
|
18305
|
-
}
|
|
18306
|
-
} else {
|
|
18307
|
-
console.error(chalk24.red("An unexpected error occurred"));
|
|
18308
|
-
}
|
|
18309
|
-
process.exit(1);
|
|
18310
|
-
}
|
|
18311
|
-
}
|
|
18312
|
-
);
|
|
18313
|
-
|
|
18314
|
-
// src/commands/image/versions.ts
|
|
18315
|
-
import { Command as Command21 } from "commander";
|
|
18316
|
-
import chalk25 from "chalk";
|
|
18317
|
-
var versionsCommand = new Command21().name("versions").description("List all versions of an image").argument("<name>", "Name of the image").action(async (name) => {
|
|
18318
|
-
try {
|
|
18319
|
-
const response = await apiClient.get("/api/images");
|
|
18320
|
-
if (!response.ok) {
|
|
18321
|
-
const error43 = await response.json();
|
|
18322
|
-
throw new Error(
|
|
18323
|
-
error43.error?.message || "Failed to list images"
|
|
18324
|
-
);
|
|
18325
|
-
}
|
|
18326
|
-
const data = await response.json();
|
|
18327
|
-
const versions = data.images.filter((img) => img.alias === name);
|
|
18328
|
-
if (versions.length === 0) {
|
|
18329
|
-
console.error(chalk25.red(`Image not found: ${name}`));
|
|
18330
|
-
process.exit(1);
|
|
18331
|
-
}
|
|
18332
|
-
const latestReady = versions.find((v) => v.status === "ready");
|
|
18333
|
-
const latestVersionId = latestReady?.versionId || null;
|
|
18334
|
-
console.log(chalk25.bold(`Versions of ${name}:`));
|
|
18335
|
-
console.log();
|
|
18336
|
-
console.log(
|
|
18337
|
-
chalk25.dim(
|
|
18338
|
-
`${"VERSION".padEnd(20)} ${"STATUS".padEnd(12)} ${"CREATED".padEnd(24)}`
|
|
18339
|
-
)
|
|
18340
|
-
);
|
|
18341
|
-
console.log(chalk25.dim("-".repeat(56)));
|
|
18342
|
-
for (const version2 of versions) {
|
|
18343
|
-
const statusColor = version2.status === "ready" ? chalk25.green : version2.status === "building" ? chalk25.yellow : chalk25.red;
|
|
18344
|
-
const createdAt = new Date(version2.createdAt).toLocaleString();
|
|
18345
|
-
let versionDisplay = version2.versionId ? formatVersionIdForDisplay(version2.versionId) : "(legacy)";
|
|
18346
|
-
if (version2.status === "ready" && version2.versionId === latestVersionId) {
|
|
18347
|
-
versionDisplay = `${versionDisplay} ${chalk25.cyan("latest")}`;
|
|
18348
|
-
}
|
|
18349
|
-
console.log(
|
|
18350
|
-
`${versionDisplay.padEnd(20)} ${statusColor(version2.status.padEnd(12))} ${createdAt.padEnd(24)}`
|
|
18351
|
-
);
|
|
18352
|
-
if (version2.status === "error" && version2.errorMessage) {
|
|
18353
|
-
console.log(chalk25.red(` Error: ${version2.errorMessage}`));
|
|
18354
|
-
}
|
|
18355
|
-
}
|
|
18356
|
-
console.log();
|
|
18357
|
-
console.log(chalk25.dim(`Total: ${versions.length} version(s)`));
|
|
18358
|
-
console.log();
|
|
18359
|
-
console.log(chalk25.dim("Usage:"));
|
|
18360
|
-
console.log(chalk25.dim(` image: "${name}" # uses latest`));
|
|
18361
|
-
if (latestVersionId) {
|
|
18362
|
-
const shortVersion = formatVersionIdForDisplay(latestVersionId);
|
|
18363
|
-
console.log(
|
|
18364
|
-
chalk25.dim(
|
|
18365
|
-
` image: "${name}:${shortVersion}" # pin to specific version`
|
|
18366
|
-
)
|
|
18367
|
-
);
|
|
18368
|
-
}
|
|
18369
|
-
} catch (error43) {
|
|
18370
|
-
if (error43 instanceof Error) {
|
|
18371
|
-
if (error43.message.includes("Not authenticated")) {
|
|
18372
|
-
console.error(chalk25.red("Not authenticated. Run: vm0 auth login"));
|
|
18373
|
-
} else {
|
|
18374
|
-
console.error(chalk25.red(`Error: ${error43.message}`));
|
|
18375
|
-
}
|
|
18376
|
-
} else {
|
|
18377
|
-
console.error(chalk25.red("An unexpected error occurred"));
|
|
18378
|
-
}
|
|
18379
|
-
process.exit(1);
|
|
18380
|
-
}
|
|
18381
|
-
});
|
|
18382
|
-
|
|
18383
|
-
// src/commands/image/index.ts
|
|
18384
|
-
var imageCommand = new Command22().name("image").description("Manage custom images").addCommand(buildCommand).addCommand(listCommand3).addCommand(deleteCommand).addCommand(versionsCommand);
|
|
18385
|
-
|
|
18386
|
-
// src/commands/logs/index.ts
|
|
18387
|
-
import { Command as Command23 } from "commander";
|
|
18388
|
-
import chalk26 from "chalk";
|
|
18389
17982
|
|
|
18390
17983
|
// src/lib/time-parser.ts
|
|
18391
17984
|
function parseTime(timeStr) {
|
|
@@ -18447,23 +18040,23 @@ function formatMetric(metric) {
|
|
|
18447
18040
|
function formatNetworkLog(entry) {
|
|
18448
18041
|
let statusColor;
|
|
18449
18042
|
if (entry.status >= 200 && entry.status < 300) {
|
|
18450
|
-
statusColor =
|
|
18043
|
+
statusColor = chalk22.green;
|
|
18451
18044
|
} else if (entry.status >= 300 && entry.status < 400) {
|
|
18452
|
-
statusColor =
|
|
18045
|
+
statusColor = chalk22.yellow;
|
|
18453
18046
|
} else if (entry.status >= 400) {
|
|
18454
|
-
statusColor =
|
|
18047
|
+
statusColor = chalk22.red;
|
|
18455
18048
|
} else {
|
|
18456
|
-
statusColor =
|
|
18049
|
+
statusColor = chalk22.gray;
|
|
18457
18050
|
}
|
|
18458
18051
|
let latencyColor;
|
|
18459
18052
|
if (entry.latency_ms < 500) {
|
|
18460
|
-
latencyColor =
|
|
18053
|
+
latencyColor = chalk22.green;
|
|
18461
18054
|
} else if (entry.latency_ms < 2e3) {
|
|
18462
|
-
latencyColor =
|
|
18055
|
+
latencyColor = chalk22.yellow;
|
|
18463
18056
|
} else {
|
|
18464
|
-
latencyColor =
|
|
18057
|
+
latencyColor = chalk22.red;
|
|
18465
18058
|
}
|
|
18466
|
-
return `[${entry.timestamp}] ${entry.method.padEnd(6)} ${statusColor(entry.status)} ${latencyColor(entry.latency_ms + "ms")} ${formatBytes8(entry.request_size)}/${formatBytes8(entry.response_size)} ${
|
|
18059
|
+
return `[${entry.timestamp}] ${entry.method.padEnd(6)} ${statusColor(entry.status)} ${latencyColor(entry.latency_ms + "ms")} ${formatBytes8(entry.request_size)}/${formatBytes8(entry.response_size)} ${chalk22.dim(entry.url)}`;
|
|
18467
18060
|
}
|
|
18468
18061
|
function renderAgentEvent(event, provider) {
|
|
18469
18062
|
const eventData = event.eventData;
|
|
@@ -18486,7 +18079,7 @@ function getLogType(options) {
|
|
|
18486
18079
|
].filter(Boolean).length;
|
|
18487
18080
|
if (selected > 1) {
|
|
18488
18081
|
console.error(
|
|
18489
|
-
|
|
18082
|
+
chalk22.red(
|
|
18490
18083
|
"Options --agent, --system, --metrics, and --network are mutually exclusive"
|
|
18491
18084
|
)
|
|
18492
18085
|
);
|
|
@@ -18497,7 +18090,7 @@ function getLogType(options) {
|
|
|
18497
18090
|
if (options.network) return "network";
|
|
18498
18091
|
return "agent";
|
|
18499
18092
|
}
|
|
18500
|
-
var logsCommand = new
|
|
18093
|
+
var logsCommand = new Command18().name("logs").description("View logs for an agent run").argument("<runId>", "Run ID to fetch logs for").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(
|
|
18501
18094
|
"--since <time>",
|
|
18502
18095
|
"Show logs since timestamp (e.g., 5m, 2h, 1d, 2024-01-15T10:30:00Z, 1705312200)"
|
|
18503
18096
|
).option("--tail <n>", "Show last N entries (default: 5, max: 100)").option("--head <n>", "Show first N entries (max: 100)").action(
|
|
@@ -18506,7 +18099,7 @@ var logsCommand = new Command23().name("logs").description("View logs for an age
|
|
|
18506
18099
|
const logType = getLogType(options);
|
|
18507
18100
|
if (options.tail !== void 0 && options.head !== void 0) {
|
|
18508
18101
|
console.error(
|
|
18509
|
-
|
|
18102
|
+
chalk22.red("Options --tail and --head are mutually exclusive")
|
|
18510
18103
|
);
|
|
18511
18104
|
process.exit(1);
|
|
18512
18105
|
}
|
|
@@ -18543,7 +18136,7 @@ var logsCommand = new Command23().name("logs").description("View logs for an age
|
|
|
18543
18136
|
async function showAgentEvents(runId, options) {
|
|
18544
18137
|
const response = await apiClient.getAgentEvents(runId, options);
|
|
18545
18138
|
if (response.events.length === 0) {
|
|
18546
|
-
console.log(
|
|
18139
|
+
console.log(chalk22.yellow("No agent events found for this run."));
|
|
18547
18140
|
return;
|
|
18548
18141
|
}
|
|
18549
18142
|
const events = options.order === "desc" ? [...response.events].reverse() : response.events;
|
|
@@ -18553,7 +18146,7 @@ async function showAgentEvents(runId, options) {
|
|
|
18553
18146
|
if (response.hasMore) {
|
|
18554
18147
|
console.log();
|
|
18555
18148
|
console.log(
|
|
18556
|
-
|
|
18149
|
+
chalk22.dim(
|
|
18557
18150
|
`Showing ${response.events.length} events. Use --tail to see more.`
|
|
18558
18151
|
)
|
|
18559
18152
|
);
|
|
@@ -18562,21 +18155,21 @@ async function showAgentEvents(runId, options) {
|
|
|
18562
18155
|
async function showSystemLog(runId, options) {
|
|
18563
18156
|
const response = await apiClient.getSystemLog(runId, options);
|
|
18564
18157
|
if (!response.systemLog) {
|
|
18565
|
-
console.log(
|
|
18158
|
+
console.log(chalk22.yellow("No system log found for this run."));
|
|
18566
18159
|
return;
|
|
18567
18160
|
}
|
|
18568
18161
|
console.log(response.systemLog);
|
|
18569
18162
|
if (response.hasMore) {
|
|
18570
18163
|
console.log();
|
|
18571
18164
|
console.log(
|
|
18572
|
-
|
|
18165
|
+
chalk22.dim("More log entries available. Use --tail to see more.")
|
|
18573
18166
|
);
|
|
18574
18167
|
}
|
|
18575
18168
|
}
|
|
18576
18169
|
async function showMetrics(runId, options) {
|
|
18577
18170
|
const response = await apiClient.getMetrics(runId, options);
|
|
18578
18171
|
if (response.metrics.length === 0) {
|
|
18579
|
-
console.log(
|
|
18172
|
+
console.log(chalk22.yellow("No metrics found for this run."));
|
|
18580
18173
|
return;
|
|
18581
18174
|
}
|
|
18582
18175
|
const metrics = options.order === "desc" ? [...response.metrics].reverse() : response.metrics;
|
|
@@ -18586,7 +18179,7 @@ async function showMetrics(runId, options) {
|
|
|
18586
18179
|
if (response.hasMore) {
|
|
18587
18180
|
console.log();
|
|
18588
18181
|
console.log(
|
|
18589
|
-
|
|
18182
|
+
chalk22.dim(
|
|
18590
18183
|
`Showing ${response.metrics.length} metrics. Use --tail to see more.`
|
|
18591
18184
|
)
|
|
18592
18185
|
);
|
|
@@ -18596,7 +18189,7 @@ async function showNetworkLogs(runId, options) {
|
|
|
18596
18189
|
const response = await apiClient.getNetworkLogs(runId, options);
|
|
18597
18190
|
if (response.networkLogs.length === 0) {
|
|
18598
18191
|
console.log(
|
|
18599
|
-
|
|
18192
|
+
chalk22.yellow(
|
|
18600
18193
|
"No network logs found for this run. Network logs are only captured when beta_network_security is enabled."
|
|
18601
18194
|
)
|
|
18602
18195
|
);
|
|
@@ -18609,7 +18202,7 @@ async function showNetworkLogs(runId, options) {
|
|
|
18609
18202
|
if (response.hasMore) {
|
|
18610
18203
|
console.log();
|
|
18611
18204
|
console.log(
|
|
18612
|
-
|
|
18205
|
+
chalk22.dim(
|
|
18613
18206
|
`Showing ${response.networkLogs.length} network logs. Use --tail to see more.`
|
|
18614
18207
|
)
|
|
18615
18208
|
);
|
|
@@ -18618,31 +18211,31 @@ async function showNetworkLogs(runId, options) {
|
|
|
18618
18211
|
function handleError(error43, runId) {
|
|
18619
18212
|
if (error43 instanceof Error) {
|
|
18620
18213
|
if (error43.message.includes("Not authenticated")) {
|
|
18621
|
-
console.error(
|
|
18214
|
+
console.error(chalk22.red("Not authenticated. Run: vm0 auth login"));
|
|
18622
18215
|
} else if (error43.message.includes("not found")) {
|
|
18623
|
-
console.error(
|
|
18216
|
+
console.error(chalk22.red(`Run not found: ${runId}`));
|
|
18624
18217
|
} else if (error43.message.includes("Invalid time format")) {
|
|
18625
|
-
console.error(
|
|
18218
|
+
console.error(chalk22.red(error43.message));
|
|
18626
18219
|
} else {
|
|
18627
|
-
console.error(
|
|
18628
|
-
console.error(
|
|
18220
|
+
console.error(chalk22.red("Failed to fetch logs"));
|
|
18221
|
+
console.error(chalk22.dim(` ${error43.message}`));
|
|
18629
18222
|
}
|
|
18630
18223
|
} else {
|
|
18631
|
-
console.error(
|
|
18224
|
+
console.error(chalk22.red("An unexpected error occurred"));
|
|
18632
18225
|
}
|
|
18633
18226
|
}
|
|
18634
18227
|
|
|
18635
18228
|
// src/commands/scope/index.ts
|
|
18636
|
-
import { Command as
|
|
18229
|
+
import { Command as Command21 } from "commander";
|
|
18637
18230
|
|
|
18638
18231
|
// src/commands/scope/status.ts
|
|
18639
|
-
import { Command as
|
|
18640
|
-
import
|
|
18641
|
-
var statusCommand3 = new
|
|
18232
|
+
import { Command as Command19 } from "commander";
|
|
18233
|
+
import chalk23 from "chalk";
|
|
18234
|
+
var statusCommand3 = new Command19().name("status").description("View current scope status").action(async () => {
|
|
18642
18235
|
try {
|
|
18643
18236
|
const scope = await apiClient.getScope();
|
|
18644
|
-
console.log(
|
|
18645
|
-
console.log(` Slug: ${
|
|
18237
|
+
console.log(chalk23.bold("Scope Information:"));
|
|
18238
|
+
console.log(` Slug: ${chalk23.green(scope.slug)}`);
|
|
18646
18239
|
console.log(` Type: ${scope.type}`);
|
|
18647
18240
|
if (scope.displayName) {
|
|
18648
18241
|
console.log(` Display Name: ${scope.displayName}`);
|
|
@@ -18653,29 +18246,29 @@ var statusCommand3 = new Command24().name("status").description("View current sc
|
|
|
18653
18246
|
} catch (error43) {
|
|
18654
18247
|
if (error43 instanceof Error) {
|
|
18655
18248
|
if (error43.message.includes("Not authenticated")) {
|
|
18656
|
-
console.error(
|
|
18249
|
+
console.error(chalk23.red("\u2717 Not authenticated. Run: vm0 auth login"));
|
|
18657
18250
|
} else if (error43.message.includes("No scope configured")) {
|
|
18658
|
-
console.log(
|
|
18251
|
+
console.log(chalk23.yellow("No scope configured."));
|
|
18659
18252
|
console.log();
|
|
18660
18253
|
console.log("Set your scope with:");
|
|
18661
|
-
console.log(
|
|
18254
|
+
console.log(chalk23.cyan(" vm0 scope set <slug>"));
|
|
18662
18255
|
console.log();
|
|
18663
18256
|
console.log("Example:");
|
|
18664
|
-
console.log(
|
|
18257
|
+
console.log(chalk23.dim(" vm0 scope set myusername"));
|
|
18665
18258
|
} else {
|
|
18666
|
-
console.error(
|
|
18259
|
+
console.error(chalk23.red(`\u2717 ${error43.message}`));
|
|
18667
18260
|
}
|
|
18668
18261
|
} else {
|
|
18669
|
-
console.error(
|
|
18262
|
+
console.error(chalk23.red("\u2717 An unexpected error occurred"));
|
|
18670
18263
|
}
|
|
18671
18264
|
process.exit(1);
|
|
18672
18265
|
}
|
|
18673
18266
|
});
|
|
18674
18267
|
|
|
18675
18268
|
// src/commands/scope/set.ts
|
|
18676
|
-
import { Command as
|
|
18677
|
-
import
|
|
18678
|
-
var setCommand = new
|
|
18269
|
+
import { Command as Command20 } from "commander";
|
|
18270
|
+
import chalk24 from "chalk";
|
|
18271
|
+
var setCommand = new Command20().name("set").description("Set your scope slug").argument("<slug>", "The scope slug (e.g., your username)").option("--force", "Force change existing scope (may break references)").option("--display-name <name>", "Display name for the scope").action(
|
|
18679
18272
|
async (slug, options) => {
|
|
18680
18273
|
try {
|
|
18681
18274
|
let existingScope;
|
|
@@ -18690,56 +18283,56 @@ var setCommand = new Command25().name("set").description("Set your scope slug").
|
|
|
18690
18283
|
if (existingScope) {
|
|
18691
18284
|
if (!options.force) {
|
|
18692
18285
|
console.error(
|
|
18693
|
-
|
|
18286
|
+
chalk24.yellow(`You already have a scope: ${existingScope.slug}`)
|
|
18694
18287
|
);
|
|
18695
18288
|
console.error();
|
|
18696
18289
|
console.error("To change your scope, use --force:");
|
|
18697
|
-
console.error(
|
|
18290
|
+
console.error(chalk24.cyan(` vm0 scope set ${slug} --force`));
|
|
18698
18291
|
console.error();
|
|
18699
18292
|
console.error(
|
|
18700
|
-
|
|
18293
|
+
chalk24.yellow(
|
|
18701
18294
|
"Warning: Changing your scope may break existing image references."
|
|
18702
18295
|
)
|
|
18703
18296
|
);
|
|
18704
18297
|
process.exit(1);
|
|
18705
18298
|
}
|
|
18706
18299
|
scope = await apiClient.updateScope({ slug, force: true });
|
|
18707
|
-
console.log(
|
|
18300
|
+
console.log(chalk24.green(`\u2713 Scope updated to ${scope.slug}`));
|
|
18708
18301
|
} else {
|
|
18709
18302
|
scope = await apiClient.createScope({
|
|
18710
18303
|
slug,
|
|
18711
18304
|
displayName: options.displayName
|
|
18712
18305
|
});
|
|
18713
|
-
console.log(
|
|
18306
|
+
console.log(chalk24.green(`\u2713 Scope created: ${scope.slug}`));
|
|
18714
18307
|
}
|
|
18715
18308
|
console.log();
|
|
18716
18309
|
console.log("Your images will now be namespaced as:");
|
|
18717
|
-
console.log(
|
|
18310
|
+
console.log(chalk24.cyan(` ${scope.slug}/<image-name>`));
|
|
18718
18311
|
} catch (error43) {
|
|
18719
18312
|
if (error43 instanceof Error) {
|
|
18720
18313
|
if (error43.message.includes("Not authenticated")) {
|
|
18721
18314
|
console.error(
|
|
18722
|
-
|
|
18315
|
+
chalk24.red("\u2717 Not authenticated. Run: vm0 auth login")
|
|
18723
18316
|
);
|
|
18724
18317
|
} else if (error43.message.includes("already exists")) {
|
|
18725
18318
|
console.error(
|
|
18726
|
-
|
|
18319
|
+
chalk24.red(
|
|
18727
18320
|
`\u2717 Scope "${slug}" is already taken. Please choose a different slug.`
|
|
18728
18321
|
)
|
|
18729
18322
|
);
|
|
18730
18323
|
} else if (error43.message.includes("reserved")) {
|
|
18731
|
-
console.error(
|
|
18324
|
+
console.error(chalk24.red(`\u2717 ${error43.message}`));
|
|
18732
18325
|
} else if (error43.message.includes("vm0")) {
|
|
18733
18326
|
console.error(
|
|
18734
|
-
|
|
18327
|
+
chalk24.red(
|
|
18735
18328
|
"\u2717 Scope slugs cannot start with 'vm0' (reserved for system use)"
|
|
18736
18329
|
)
|
|
18737
18330
|
);
|
|
18738
18331
|
} else {
|
|
18739
|
-
console.error(
|
|
18332
|
+
console.error(chalk24.red(`\u2717 ${error43.message}`));
|
|
18740
18333
|
}
|
|
18741
18334
|
} else {
|
|
18742
|
-
console.error(
|
|
18335
|
+
console.error(chalk24.red("\u2717 An unexpected error occurred"));
|
|
18743
18336
|
}
|
|
18744
18337
|
process.exit(1);
|
|
18745
18338
|
}
|
|
@@ -18747,13 +18340,13 @@ var setCommand = new Command25().name("set").description("Set your scope slug").
|
|
|
18747
18340
|
);
|
|
18748
18341
|
|
|
18749
18342
|
// src/commands/scope/index.ts
|
|
18750
|
-
var scopeCommand = new
|
|
18343
|
+
var scopeCommand = new Command21().name("scope").description("Manage your scope (namespace for images)").addCommand(statusCommand3).addCommand(setCommand);
|
|
18751
18344
|
|
|
18752
18345
|
// src/commands/init.ts
|
|
18753
|
-
import { Command as
|
|
18754
|
-
import
|
|
18346
|
+
import { Command as Command22 } from "commander";
|
|
18347
|
+
import chalk25 from "chalk";
|
|
18755
18348
|
import path13 from "path";
|
|
18756
|
-
import { existsSync as
|
|
18349
|
+
import { existsSync as existsSync9 } from "fs";
|
|
18757
18350
|
import { writeFile as writeFile7 } from "fs/promises";
|
|
18758
18351
|
var VM0_YAML_FILE = "vm0.yaml";
|
|
18759
18352
|
var AGENTS_MD_FILE = "AGENTS.md";
|
|
@@ -18788,18 +18381,18 @@ You are a HackerNews AI content curator.
|
|
|
18788
18381
|
}
|
|
18789
18382
|
function checkExistingFiles() {
|
|
18790
18383
|
const existingFiles = [];
|
|
18791
|
-
if (
|
|
18792
|
-
if (
|
|
18384
|
+
if (existsSync9(VM0_YAML_FILE)) existingFiles.push(VM0_YAML_FILE);
|
|
18385
|
+
if (existsSync9(AGENTS_MD_FILE)) existingFiles.push(AGENTS_MD_FILE);
|
|
18793
18386
|
return existingFiles;
|
|
18794
18387
|
}
|
|
18795
|
-
var initCommand3 = new
|
|
18388
|
+
var initCommand3 = new Command22().name("init").description("Initialize a new VM0 project in the current directory").option("-f, --force", "Overwrite existing files").option("-n, --name <name>", "Agent name (required in non-interactive mode)").action(async (options) => {
|
|
18796
18389
|
const existingFiles = checkExistingFiles();
|
|
18797
18390
|
if (existingFiles.length > 0 && !options.force) {
|
|
18798
18391
|
for (const file2 of existingFiles) {
|
|
18799
|
-
console.log(
|
|
18392
|
+
console.log(chalk25.red(`\u2717 ${file2} already exists`));
|
|
18800
18393
|
}
|
|
18801
18394
|
console.log();
|
|
18802
|
-
console.log(`To overwrite: ${
|
|
18395
|
+
console.log(`To overwrite: ${chalk25.cyan("vm0 init --force")}`);
|
|
18803
18396
|
process.exit(1);
|
|
18804
18397
|
}
|
|
18805
18398
|
let agentName;
|
|
@@ -18807,9 +18400,9 @@ var initCommand3 = new Command27().name("init").description("Initialize a new VM
|
|
|
18807
18400
|
agentName = options.name.trim();
|
|
18808
18401
|
} else if (!isInteractive()) {
|
|
18809
18402
|
console.error(
|
|
18810
|
-
|
|
18403
|
+
chalk25.red("\u2717 --name flag is required in non-interactive mode")
|
|
18811
18404
|
);
|
|
18812
|
-
console.error(
|
|
18405
|
+
console.error(chalk25.dim(" Usage: vm0 init --name <agent-name>"));
|
|
18813
18406
|
process.exit(1);
|
|
18814
18407
|
} else {
|
|
18815
18408
|
const dirName = path13.basename(process.cwd());
|
|
@@ -18825,40 +18418,40 @@ var initCommand3 = new Command27().name("init").description("Initialize a new VM
|
|
|
18825
18418
|
}
|
|
18826
18419
|
);
|
|
18827
18420
|
if (name === void 0) {
|
|
18828
|
-
console.log(
|
|
18421
|
+
console.log(chalk25.dim("Cancelled"));
|
|
18829
18422
|
return;
|
|
18830
18423
|
}
|
|
18831
18424
|
agentName = name;
|
|
18832
18425
|
}
|
|
18833
18426
|
if (!agentName || !validateAgentName(agentName)) {
|
|
18834
|
-
console.log(
|
|
18427
|
+
console.log(chalk25.red("\u2717 Invalid agent name"));
|
|
18835
18428
|
console.log(
|
|
18836
|
-
|
|
18429
|
+
chalk25.dim(" Must be 3-64 characters, alphanumeric and hyphens only")
|
|
18837
18430
|
);
|
|
18838
|
-
console.log(
|
|
18431
|
+
console.log(chalk25.dim(" Must start and end with letter or number"));
|
|
18839
18432
|
process.exit(1);
|
|
18840
18433
|
}
|
|
18841
18434
|
await writeFile7(VM0_YAML_FILE, generateVm0Yaml(agentName));
|
|
18842
18435
|
const vm0Status = existingFiles.includes(VM0_YAML_FILE) ? " (overwritten)" : "";
|
|
18843
|
-
console.log(
|
|
18436
|
+
console.log(chalk25.green(`\u2713 Created ${VM0_YAML_FILE}${vm0Status}`));
|
|
18844
18437
|
await writeFile7(AGENTS_MD_FILE, generateAgentsMd());
|
|
18845
18438
|
const agentsStatus = existingFiles.includes(AGENTS_MD_FILE) ? " (overwritten)" : "";
|
|
18846
|
-
console.log(
|
|
18439
|
+
console.log(chalk25.green(`\u2713 Created ${AGENTS_MD_FILE}${agentsStatus}`));
|
|
18847
18440
|
console.log();
|
|
18848
18441
|
console.log("Next steps:");
|
|
18849
18442
|
console.log(
|
|
18850
|
-
` 1. Get your Claude Code token: ${
|
|
18443
|
+
` 1. Get your Claude Code token: ${chalk25.cyan("claude setup-token")}`
|
|
18851
18444
|
);
|
|
18852
18445
|
console.log(` 2. Set the environment variable (or add to .env file):`);
|
|
18853
|
-
console.log(
|
|
18854
|
-
console.log(` 3. Run your agent: ${
|
|
18446
|
+
console.log(chalk25.dim(` export CLAUDE_CODE_OAUTH_TOKEN=<your-token>`));
|
|
18447
|
+
console.log(` 3. Run your agent: ${chalk25.cyan('vm0 cook "your prompt"')}`);
|
|
18855
18448
|
});
|
|
18856
18449
|
|
|
18857
18450
|
// src/commands/setup-github.ts
|
|
18858
|
-
import { Command as
|
|
18859
|
-
import
|
|
18860
|
-
import { existsSync as
|
|
18861
|
-
import { mkdir as mkdir7, readFile as
|
|
18451
|
+
import { Command as Command23 } from "commander";
|
|
18452
|
+
import chalk26 from "chalk";
|
|
18453
|
+
import { existsSync as existsSync10 } from "fs";
|
|
18454
|
+
import { mkdir as mkdir7, readFile as readFile8, writeFile as writeFile8 } from "fs/promises";
|
|
18862
18455
|
import { execSync, spawnSync } from "child_process";
|
|
18863
18456
|
import path14 from "path";
|
|
18864
18457
|
import { parse as parseYaml5 } from "yaml";
|
|
@@ -18899,67 +18492,67 @@ async function checkPrerequisites() {
|
|
|
18899
18492
|
console.log("Checking prerequisites...");
|
|
18900
18493
|
const gitRoot = getGitRoot();
|
|
18901
18494
|
if (!gitRoot) {
|
|
18902
|
-
console.log(
|
|
18495
|
+
console.log(chalk26.red("\u2717 Not in a git repository"));
|
|
18903
18496
|
console.log();
|
|
18904
18497
|
console.log("This command must be run from within a git repository.");
|
|
18905
18498
|
console.log();
|
|
18906
18499
|
console.log("To initialize a git repository, run:");
|
|
18907
|
-
console.log(` ${
|
|
18500
|
+
console.log(` ${chalk26.cyan("git init")}`);
|
|
18908
18501
|
process.exit(1);
|
|
18909
18502
|
}
|
|
18910
|
-
console.log(
|
|
18503
|
+
console.log(chalk26.green("\u2713 Git repository detected"));
|
|
18911
18504
|
if (!isGhInstalled()) {
|
|
18912
|
-
console.log(
|
|
18505
|
+
console.log(chalk26.red("\u2717 GitHub CLI (gh) is not installed"));
|
|
18913
18506
|
console.log();
|
|
18914
18507
|
console.log("GitHub CLI is required for this command.");
|
|
18915
18508
|
console.log();
|
|
18916
|
-
console.log(` macOS: ${
|
|
18917
|
-
console.log(` Other: ${
|
|
18509
|
+
console.log(` macOS: ${chalk26.cyan("brew install gh")}`);
|
|
18510
|
+
console.log(` Other: ${chalk26.cyan("https://cli.github.com/")}`);
|
|
18918
18511
|
console.log();
|
|
18919
18512
|
console.log("After installation, run:");
|
|
18920
|
-
console.log(` ${
|
|
18513
|
+
console.log(` ${chalk26.cyan("gh auth login")}`);
|
|
18921
18514
|
console.log();
|
|
18922
18515
|
console.log("Then try again:");
|
|
18923
|
-
console.log(` ${
|
|
18516
|
+
console.log(` ${chalk26.cyan("vm0 setup-github")}`);
|
|
18924
18517
|
process.exit(1);
|
|
18925
18518
|
}
|
|
18926
|
-
console.log(
|
|
18519
|
+
console.log(chalk26.green("\u2713 GitHub CLI (gh) is installed"));
|
|
18927
18520
|
if (!isGhAuthenticated()) {
|
|
18928
|
-
console.log(
|
|
18521
|
+
console.log(chalk26.red("\u2717 GitHub CLI is not authenticated"));
|
|
18929
18522
|
console.log();
|
|
18930
18523
|
console.log("Please authenticate GitHub CLI first:");
|
|
18931
|
-
console.log(` ${
|
|
18524
|
+
console.log(` ${chalk26.cyan("gh auth login")}`);
|
|
18932
18525
|
console.log();
|
|
18933
18526
|
console.log("Then try again:");
|
|
18934
|
-
console.log(` ${
|
|
18527
|
+
console.log(` ${chalk26.cyan("vm0 setup-github")}`);
|
|
18935
18528
|
process.exit(1);
|
|
18936
18529
|
}
|
|
18937
|
-
console.log(
|
|
18530
|
+
console.log(chalk26.green("\u2713 GitHub CLI is authenticated"));
|
|
18938
18531
|
const token = await getToken();
|
|
18939
18532
|
if (!token) {
|
|
18940
|
-
console.log(
|
|
18533
|
+
console.log(chalk26.red("\u2717 VM0 not authenticated"));
|
|
18941
18534
|
console.log();
|
|
18942
18535
|
console.log("Please authenticate with VM0 first:");
|
|
18943
|
-
console.log(` ${
|
|
18536
|
+
console.log(` ${chalk26.cyan("vm0 auth login")}`);
|
|
18944
18537
|
console.log();
|
|
18945
18538
|
console.log("Then try again:");
|
|
18946
|
-
console.log(` ${
|
|
18539
|
+
console.log(` ${chalk26.cyan("vm0 setup-github")}`);
|
|
18947
18540
|
process.exit(1);
|
|
18948
18541
|
}
|
|
18949
|
-
console.log(
|
|
18950
|
-
if (!
|
|
18951
|
-
console.log(
|
|
18542
|
+
console.log(chalk26.green("\u2713 VM0 authenticated"));
|
|
18543
|
+
if (!existsSync10("vm0.yaml")) {
|
|
18544
|
+
console.log(chalk26.red("\u2717 vm0.yaml not found"));
|
|
18952
18545
|
console.log();
|
|
18953
18546
|
console.log("This command requires a vm0.yaml configuration file.");
|
|
18954
18547
|
console.log();
|
|
18955
18548
|
console.log("To create one, run:");
|
|
18956
|
-
console.log(` ${
|
|
18549
|
+
console.log(` ${chalk26.cyan("vm0 init")}`);
|
|
18957
18550
|
console.log();
|
|
18958
18551
|
console.log("Then try again:");
|
|
18959
|
-
console.log(` ${
|
|
18552
|
+
console.log(` ${chalk26.cyan("vm0 setup-github")}`);
|
|
18960
18553
|
process.exit(1);
|
|
18961
18554
|
}
|
|
18962
|
-
console.log(
|
|
18555
|
+
console.log(chalk26.green("\u2713 vm0.yaml found"));
|
|
18963
18556
|
return { token, gitRoot };
|
|
18964
18557
|
}
|
|
18965
18558
|
function generatePublishYaml(workingDir) {
|
|
@@ -19116,7 +18709,7 @@ function displaySecretsTable(secretStatuses, varStatuses) {
|
|
|
19116
18709
|
if (secretStatuses.length > 0) {
|
|
19117
18710
|
console.log("\u2502 Secrets: \u2502");
|
|
19118
18711
|
for (const s of secretStatuses) {
|
|
19119
|
-
const status = s.found ?
|
|
18712
|
+
const status = s.found ? chalk26.green("\u2713") : chalk26.red("\u2717");
|
|
19120
18713
|
const source = s.found ? `(from ${s.source})` : "not found";
|
|
19121
18714
|
const paddedName = (s.name + " ").padEnd(23, ".");
|
|
19122
18715
|
console.log(`\u2502 ${status} ${paddedName} ${source.padEnd(19)}\u2502`);
|
|
@@ -19125,7 +18718,7 @@ function displaySecretsTable(secretStatuses, varStatuses) {
|
|
|
19125
18718
|
if (varStatuses.length > 0) {
|
|
19126
18719
|
console.log("\u2502 Variables: \u2502");
|
|
19127
18720
|
for (const v of varStatuses) {
|
|
19128
|
-
const status = v.found ?
|
|
18721
|
+
const status = v.found ? chalk26.green("\u2713") : chalk26.red("\u2717");
|
|
19129
18722
|
const source = v.found ? `(from ${v.source})` : "not found";
|
|
19130
18723
|
const paddedName = (v.name + " ").padEnd(23, ".");
|
|
19131
18724
|
console.log(`\u2502 ${status} ${paddedName} ${source.padEnd(19)}\u2502`);
|
|
@@ -19137,17 +18730,17 @@ function showManualSetupInstructions(secrets, vars) {
|
|
|
19137
18730
|
console.log("Skipped automatic setup. Configure secrets manually:");
|
|
19138
18731
|
console.log();
|
|
19139
18732
|
console.log(" Step 1: Get your VM0 token");
|
|
19140
|
-
console.log(` ${
|
|
18733
|
+
console.log(` ${chalk26.cyan("vm0 auth setup-token")}`);
|
|
19141
18734
|
console.log();
|
|
19142
18735
|
console.log(" Step 2: Set GitHub secrets");
|
|
19143
18736
|
for (const s of secrets) {
|
|
19144
|
-
console.log(` ${
|
|
18737
|
+
console.log(` ${chalk26.cyan(`gh secret set ${s}`)}`);
|
|
19145
18738
|
}
|
|
19146
18739
|
if (vars.length > 0) {
|
|
19147
18740
|
console.log();
|
|
19148
18741
|
console.log(" Step 3: Set GitHub variables");
|
|
19149
18742
|
for (const v of vars) {
|
|
19150
|
-
console.log(` ${
|
|
18743
|
+
console.log(` ${chalk26.cyan(`gh variable set ${v}`)}`);
|
|
19151
18744
|
}
|
|
19152
18745
|
}
|
|
19153
18746
|
}
|
|
@@ -19190,7 +18783,7 @@ function showWorkflowsCreatedMessage() {
|
|
|
19190
18783
|
console.log("\u2502 3. Push to main branch to trigger publish \u2502");
|
|
19191
18784
|
console.log("\u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518");
|
|
19192
18785
|
}
|
|
19193
|
-
var setupGithubCommand = new
|
|
18786
|
+
var setupGithubCommand = new Command23().name("setup-github").description("Initialize GitHub Actions workflows for agent deployment").option("-f, --force", "Overwrite existing workflow files").option("-y, --yes", "Auto-confirm all prompts").option("--skip-secrets", "Skip automatic secrets/variables setup").action(
|
|
19194
18787
|
async (options) => {
|
|
19195
18788
|
const prereqs = await checkPrerequisites();
|
|
19196
18789
|
if (!prereqs) {
|
|
@@ -19200,14 +18793,14 @@ var setupGithubCommand = new Command28().name("setup-github").description("Initi
|
|
|
19200
18793
|
const workingDir = getRelativeWorkingDir(gitRoot);
|
|
19201
18794
|
console.log();
|
|
19202
18795
|
console.log("Analyzing vm0.yaml...");
|
|
19203
|
-
const content = await
|
|
18796
|
+
const content = await readFile8("vm0.yaml", "utf8");
|
|
19204
18797
|
const config2 = parseYaml5(content);
|
|
19205
18798
|
const agents = config2.agents;
|
|
19206
18799
|
const agentName = Object.keys(agents)[0];
|
|
19207
|
-
console.log(
|
|
18800
|
+
console.log(chalk26.green(`\u2713 Agent: ${agentName}`));
|
|
19208
18801
|
const { secrets, vars } = extractSecretsAndVars(config2);
|
|
19209
18802
|
console.log(
|
|
19210
|
-
|
|
18803
|
+
chalk26.green(
|
|
19211
18804
|
`\u2713 Found ${secrets.length} secrets, ${vars.length} variables`
|
|
19212
18805
|
)
|
|
19213
18806
|
);
|
|
@@ -19217,10 +18810,10 @@ var setupGithubCommand = new Command28().name("setup-github").description("Initi
|
|
|
19217
18810
|
const displayPublishPath = ".github/workflows/publish.yml";
|
|
19218
18811
|
const displayRunPath = ".github/workflows/run.yml";
|
|
19219
18812
|
const existingFiles = [];
|
|
19220
|
-
if (
|
|
19221
|
-
if (
|
|
18813
|
+
if (existsSync10(publishPath)) existingFiles.push(displayPublishPath);
|
|
18814
|
+
if (existsSync10(runPath)) existingFiles.push(displayRunPath);
|
|
19222
18815
|
if (existingFiles.length > 0 && !options.force) {
|
|
19223
|
-
console.log(
|
|
18816
|
+
console.log(chalk26.yellow("\u26A0 Existing workflow files detected:"));
|
|
19224
18817
|
for (const file2 of existingFiles) {
|
|
19225
18818
|
console.log(` \u2022 ${file2}`);
|
|
19226
18819
|
}
|
|
@@ -19233,7 +18826,7 @@ var setupGithubCommand = new Command28().name("setup-github").description("Initi
|
|
|
19233
18826
|
if (!overwrite) {
|
|
19234
18827
|
console.log();
|
|
19235
18828
|
console.log("Aborted. To force overwrite, run:");
|
|
19236
|
-
console.log(` ${
|
|
18829
|
+
console.log(` ${chalk26.cyan("vm0 setup-github --force")}`);
|
|
19237
18830
|
process.exit(0);
|
|
19238
18831
|
}
|
|
19239
18832
|
}
|
|
@@ -19243,13 +18836,13 @@ var setupGithubCommand = new Command28().name("setup-github").description("Initi
|
|
|
19243
18836
|
await mkdir7(path14.join(gitRoot, ".github/workflows"), { recursive: true });
|
|
19244
18837
|
await writeFile8(publishPath, generatePublishYaml(workingDir));
|
|
19245
18838
|
const publishStatus = existingFiles.includes(displayPublishPath) ? "Overwrote" : "Created";
|
|
19246
|
-
console.log(
|
|
18839
|
+
console.log(chalk26.green(`\u2713 ${publishStatus} ${displayPublishPath}`));
|
|
19247
18840
|
await writeFile8(runPath, generateRunYaml(agentName, secrets, vars));
|
|
19248
18841
|
const runStatus = existingFiles.includes(displayRunPath) ? "Overwrote" : "Created";
|
|
19249
|
-
console.log(
|
|
18842
|
+
console.log(chalk26.green(`\u2713 ${runStatus} ${displayRunPath}`));
|
|
19250
18843
|
console.log();
|
|
19251
18844
|
if (options.skipSecrets) {
|
|
19252
|
-
console.log(
|
|
18845
|
+
console.log(chalk26.green("\u2713 Done (secrets setup skipped)"));
|
|
19253
18846
|
return;
|
|
19254
18847
|
}
|
|
19255
18848
|
const { secretStatuses, varStatuses } = await detectSecretValues(
|
|
@@ -19289,14 +18882,14 @@ var setupGithubCommand = new Command28().name("setup-github").description("Initi
|
|
|
19289
18882
|
if (s.found && s.value) {
|
|
19290
18883
|
const success2 = setGitHubSecret(s.name, s.value);
|
|
19291
18884
|
if (success2) {
|
|
19292
|
-
console.log(` ${
|
|
18885
|
+
console.log(` ${chalk26.green("\u2713")} ${s.name}`);
|
|
19293
18886
|
} else {
|
|
19294
|
-
console.log(` ${
|
|
18887
|
+
console.log(` ${chalk26.red("\u2717")} ${s.name} (failed)`);
|
|
19295
18888
|
failedSecrets.push(s.name);
|
|
19296
18889
|
}
|
|
19297
18890
|
} else {
|
|
19298
18891
|
console.log(
|
|
19299
|
-
` ${
|
|
18892
|
+
` ${chalk26.yellow("\u26A0")} ${s.name} (skipped - not found)`
|
|
19300
18893
|
);
|
|
19301
18894
|
}
|
|
19302
18895
|
}
|
|
@@ -19308,14 +18901,14 @@ var setupGithubCommand = new Command28().name("setup-github").description("Initi
|
|
|
19308
18901
|
if (v.found && v.value) {
|
|
19309
18902
|
const success2 = setGitHubVariable(v.name, v.value);
|
|
19310
18903
|
if (success2) {
|
|
19311
|
-
console.log(` ${
|
|
18904
|
+
console.log(` ${chalk26.green("\u2713")} ${v.name}`);
|
|
19312
18905
|
} else {
|
|
19313
|
-
console.log(` ${
|
|
18906
|
+
console.log(` ${chalk26.red("\u2717")} ${v.name} (failed)`);
|
|
19314
18907
|
failedVars.push(v.name);
|
|
19315
18908
|
}
|
|
19316
18909
|
} else {
|
|
19317
18910
|
console.log(
|
|
19318
|
-
` ${
|
|
18911
|
+
` ${chalk26.yellow("\u26A0")} ${v.name} (skipped - not found)`
|
|
19319
18912
|
);
|
|
19320
18913
|
}
|
|
19321
18914
|
}
|
|
@@ -19338,10 +18931,10 @@ var setupGithubCommand = new Command28().name("setup-github").description("Initi
|
|
|
19338
18931
|
);
|
|
19339
18932
|
|
|
19340
18933
|
// src/index.ts
|
|
19341
|
-
var program = new
|
|
19342
|
-
program.name("vm0").description("VM0 CLI - A modern build tool").version("4.
|
|
18934
|
+
var program = new Command24();
|
|
18935
|
+
program.name("vm0").description("VM0 CLI - A modern build tool").version("4.36.0");
|
|
19343
18936
|
program.command("info").description("Display environment information").action(async () => {
|
|
19344
|
-
console.log(
|
|
18937
|
+
console.log(chalk27.bold("System Information:"));
|
|
19345
18938
|
console.log(`Node Version: ${process.version}`);
|
|
19346
18939
|
console.log(`Platform: ${process.platform}`);
|
|
19347
18940
|
console.log(`Architecture: ${process.arch}`);
|
|
@@ -19366,7 +18959,6 @@ program.addCommand(runCommand);
|
|
|
19366
18959
|
program.addCommand(volumeCommand);
|
|
19367
18960
|
program.addCommand(artifactCommand);
|
|
19368
18961
|
program.addCommand(cookCommand);
|
|
19369
|
-
program.addCommand(imageCommand);
|
|
19370
18962
|
program.addCommand(logsCommand);
|
|
19371
18963
|
program.addCommand(scopeCommand);
|
|
19372
18964
|
program.addCommand(initCommand3);
|