@vm0/cli 5.1.3 → 5.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (2) hide show
  1. package/index.js +1184 -93
  2. package/package.json +1 -1
package/index.js CHANGED
@@ -6,13 +6,13 @@ var __export = (target, all) => {
6
6
  };
7
7
 
8
8
  // src/index.ts
9
- import { Command as Command27 } from "commander";
10
- import chalk29 from "chalk";
9
+ import { Command as Command35 } from "commander";
10
+ import chalk36 from "chalk";
11
11
 
12
- // src/lib/auth.ts
12
+ // src/lib/api/auth.ts
13
13
  import chalk from "chalk";
14
14
 
15
- // src/lib/config.ts
15
+ // src/lib/api/config.ts
16
16
  import { homedir } from "os";
17
17
  import { join } from "path";
18
18
  import { readFile, writeFile, mkdir, unlink } from "fs/promises";
@@ -53,7 +53,7 @@ async function clearConfig() {
53
53
  }
54
54
  }
55
55
 
56
- // src/lib/auth.ts
56
+ // src/lib/api/auth.ts
57
57
  function buildHeaders() {
58
58
  const headers = {
59
59
  "Content-Type": "application/json"
@@ -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, (c15) => c15 === "-" ? "+" : "/");
2763
+ const base643 = data.replace(/[-_]/g, (c16) => c16 === "-" ? "+" : "/");
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 c15 = inst._zod.bag;
11676
- inst.minDate = c15.minimum ? new Date(c15.minimum) : null;
11677
- inst.maxDate = c15.maximum ? new Date(c15.maximum) : null;
11675
+ const c16 = inst._zod.bag;
11676
+ inst.minDate = c16.minimum ? new Date(c16.minimum) : null;
11677
+ inst.maxDate = c16.maximum ? new Date(c16.maximum) : null;
11678
11678
  });
11679
11679
  function date3(params) {
11680
11680
  return _date(ZodDate, params);
@@ -13679,6 +13679,203 @@ var checkpointsByIdContract = c10.router({
13679
13679
  }
13680
13680
  });
13681
13681
 
13682
+ // ../../packages/core/src/contracts/schedules.ts
13683
+ var c11 = initContract();
13684
+ var scheduleTriggerSchema = external_exports.object({
13685
+ cron: external_exports.string().optional(),
13686
+ at: external_exports.string().optional(),
13687
+ timezone: external_exports.string().default("UTC")
13688
+ }).refine((data) => data.cron && !data.at || !data.cron && data.at, {
13689
+ message: "Exactly one of 'cron' or 'at' must be specified"
13690
+ });
13691
+ var scheduleRunConfigSchema = external_exports.object({
13692
+ agent: external_exports.string().min(1, "Agent reference required"),
13693
+ prompt: external_exports.string().min(1, "Prompt required"),
13694
+ vars: external_exports.record(external_exports.string(), external_exports.string()).optional(),
13695
+ secrets: external_exports.record(external_exports.string(), external_exports.string()).optional(),
13696
+ artifactName: external_exports.string().optional(),
13697
+ artifactVersion: external_exports.string().optional(),
13698
+ volumeVersions: external_exports.record(external_exports.string(), external_exports.string()).optional()
13699
+ });
13700
+ var scheduleDefinitionSchema = external_exports.object({
13701
+ on: scheduleTriggerSchema,
13702
+ run: scheduleRunConfigSchema
13703
+ });
13704
+ var scheduleYamlSchema = external_exports.object({
13705
+ version: external_exports.literal("1.0"),
13706
+ schedules: external_exports.record(external_exports.string(), scheduleDefinitionSchema)
13707
+ });
13708
+ var deployScheduleRequestSchema = external_exports.object({
13709
+ name: external_exports.string().min(1).max(64, "Schedule name max 64 chars"),
13710
+ cronExpression: external_exports.string().optional(),
13711
+ atTime: external_exports.string().optional(),
13712
+ timezone: external_exports.string().default("UTC"),
13713
+ prompt: external_exports.string().min(1, "Prompt required"),
13714
+ vars: external_exports.record(external_exports.string(), external_exports.string()).optional(),
13715
+ secrets: external_exports.record(external_exports.string(), external_exports.string()).optional(),
13716
+ artifactName: external_exports.string().optional(),
13717
+ artifactVersion: external_exports.string().optional(),
13718
+ volumeVersions: external_exports.record(external_exports.string(), external_exports.string()).optional(),
13719
+ // Resolved agent compose ID (CLI resolves scope/name:version → composeId)
13720
+ composeId: external_exports.string().uuid("Invalid compose ID")
13721
+ }).refine(
13722
+ (data) => data.cronExpression && !data.atTime || !data.cronExpression && data.atTime,
13723
+ {
13724
+ message: "Exactly one of 'cronExpression' or 'atTime' must be specified"
13725
+ }
13726
+ );
13727
+ var scheduleResponseSchema = external_exports.object({
13728
+ id: external_exports.string().uuid(),
13729
+ composeId: external_exports.string().uuid(),
13730
+ composeName: external_exports.string(),
13731
+ scopeSlug: external_exports.string(),
13732
+ name: external_exports.string(),
13733
+ cronExpression: external_exports.string().nullable(),
13734
+ atTime: external_exports.string().nullable(),
13735
+ timezone: external_exports.string(),
13736
+ prompt: external_exports.string(),
13737
+ vars: external_exports.record(external_exports.string(), external_exports.string()).nullable(),
13738
+ // Secret names only (values are never returned)
13739
+ secretNames: external_exports.array(external_exports.string()).nullable(),
13740
+ artifactName: external_exports.string().nullable(),
13741
+ artifactVersion: external_exports.string().nullable(),
13742
+ volumeVersions: external_exports.record(external_exports.string(), external_exports.string()).nullable(),
13743
+ enabled: external_exports.boolean(),
13744
+ nextRunAt: external_exports.string().nullable(),
13745
+ lastRunAt: external_exports.string().nullable(),
13746
+ lastRunId: external_exports.string().nullable(),
13747
+ createdAt: external_exports.string(),
13748
+ updatedAt: external_exports.string()
13749
+ });
13750
+ var scheduleListResponseSchema = external_exports.object({
13751
+ schedules: external_exports.array(scheduleResponseSchema)
13752
+ });
13753
+ var deployScheduleResponseSchema = external_exports.object({
13754
+ schedule: scheduleResponseSchema,
13755
+ created: external_exports.boolean()
13756
+ // true if created, false if updated
13757
+ });
13758
+ var schedulesMainContract = c11.router({
13759
+ /**
13760
+ * POST /api/agent/schedules
13761
+ * Deploy (create or update) a schedule
13762
+ */
13763
+ deploy: {
13764
+ method: "POST",
13765
+ path: "/api/agent/schedules",
13766
+ body: deployScheduleRequestSchema,
13767
+ responses: {
13768
+ 200: deployScheduleResponseSchema,
13769
+ // Updated
13770
+ 201: deployScheduleResponseSchema,
13771
+ // Created
13772
+ 400: apiErrorSchema,
13773
+ 401: apiErrorSchema,
13774
+ 404: apiErrorSchema,
13775
+ 409: apiErrorSchema
13776
+ // Schedule limit reached
13777
+ },
13778
+ summary: "Deploy schedule (create or update)"
13779
+ },
13780
+ /**
13781
+ * GET /api/agent/schedules
13782
+ * List all schedules for the user
13783
+ */
13784
+ list: {
13785
+ method: "GET",
13786
+ path: "/api/agent/schedules",
13787
+ responses: {
13788
+ 200: scheduleListResponseSchema,
13789
+ 401: apiErrorSchema
13790
+ },
13791
+ summary: "List all schedules"
13792
+ }
13793
+ });
13794
+ var schedulesByNameContract = c11.router({
13795
+ /**
13796
+ * GET /api/agent/schedules/:name
13797
+ * Get schedule by name
13798
+ */
13799
+ getByName: {
13800
+ method: "GET",
13801
+ path: "/api/agent/schedules/:name",
13802
+ pathParams: external_exports.object({
13803
+ name: external_exports.string().min(1, "Schedule name required")
13804
+ }),
13805
+ query: external_exports.object({
13806
+ composeId: external_exports.string().uuid("Compose ID required")
13807
+ }),
13808
+ responses: {
13809
+ 200: scheduleResponseSchema,
13810
+ 401: apiErrorSchema,
13811
+ 404: apiErrorSchema
13812
+ },
13813
+ summary: "Get schedule by name"
13814
+ },
13815
+ /**
13816
+ * DELETE /api/agent/schedules/:name
13817
+ * Delete schedule by name
13818
+ */
13819
+ delete: {
13820
+ method: "DELETE",
13821
+ path: "/api/agent/schedules/:name",
13822
+ pathParams: external_exports.object({
13823
+ name: external_exports.string().min(1, "Schedule name required")
13824
+ }),
13825
+ query: external_exports.object({
13826
+ composeId: external_exports.string().uuid("Compose ID required")
13827
+ }),
13828
+ responses: {
13829
+ 204: external_exports.undefined(),
13830
+ 401: apiErrorSchema,
13831
+ 404: apiErrorSchema
13832
+ },
13833
+ summary: "Delete schedule"
13834
+ }
13835
+ });
13836
+ var schedulesEnableContract = c11.router({
13837
+ /**
13838
+ * POST /api/agent/schedules/:name/enable
13839
+ * Enable a disabled schedule
13840
+ */
13841
+ enable: {
13842
+ method: "POST",
13843
+ path: "/api/agent/schedules/:name/enable",
13844
+ pathParams: external_exports.object({
13845
+ name: external_exports.string().min(1, "Schedule name required")
13846
+ }),
13847
+ body: external_exports.object({
13848
+ composeId: external_exports.string().uuid("Compose ID required")
13849
+ }),
13850
+ responses: {
13851
+ 200: scheduleResponseSchema,
13852
+ 401: apiErrorSchema,
13853
+ 404: apiErrorSchema
13854
+ },
13855
+ summary: "Enable schedule"
13856
+ },
13857
+ /**
13858
+ * POST /api/agent/schedules/:name/disable
13859
+ * Disable an enabled schedule
13860
+ */
13861
+ disable: {
13862
+ method: "POST",
13863
+ path: "/api/agent/schedules/:name/disable",
13864
+ pathParams: external_exports.object({
13865
+ name: external_exports.string().min(1, "Schedule name required")
13866
+ }),
13867
+ body: external_exports.object({
13868
+ composeId: external_exports.string().uuid("Compose ID required")
13869
+ }),
13870
+ responses: {
13871
+ 200: scheduleResponseSchema,
13872
+ 401: apiErrorSchema,
13873
+ 404: apiErrorSchema
13874
+ },
13875
+ summary: "Disable schedule"
13876
+ }
13877
+ });
13878
+
13682
13879
  // ../../packages/core/src/contracts/public/common.ts
13683
13880
  var publicApiErrorTypeSchema = external_exports.enum([
13684
13881
  "api_error",
@@ -13719,7 +13916,7 @@ var requestIdSchema = external_exports.string().uuid();
13719
13916
  var timestampSchema = external_exports.string().datetime();
13720
13917
 
13721
13918
  // ../../packages/core/src/contracts/public/agents.ts
13722
- var c11 = initContract();
13919
+ var c12 = initContract();
13723
13920
  var publicAgentSchema = external_exports.object({
13724
13921
  id: external_exports.string(),
13725
13922
  name: external_exports.string(),
@@ -13739,7 +13936,7 @@ var paginatedAgentVersionsSchema = createPaginatedResponseSchema(agentVersionSch
13739
13936
  var agentListQuerySchema = listQuerySchema.extend({
13740
13937
  name: external_exports.string().optional()
13741
13938
  });
13742
- var publicAgentsListContract = c11.router({
13939
+ var publicAgentsListContract = c12.router({
13743
13940
  list: {
13744
13941
  method: "GET",
13745
13942
  path: "/v1/agents",
@@ -13753,7 +13950,7 @@ var publicAgentsListContract = c11.router({
13753
13950
  description: "List all agents in the current scope with pagination. Use the `name` query parameter to filter by agent name."
13754
13951
  }
13755
13952
  });
13756
- var publicAgentByIdContract = c11.router({
13953
+ var publicAgentByIdContract = c12.router({
13757
13954
  get: {
13758
13955
  method: "GET",
13759
13956
  path: "/v1/agents/:id",
@@ -13770,7 +13967,7 @@ var publicAgentByIdContract = c11.router({
13770
13967
  description: "Get agent details by ID"
13771
13968
  }
13772
13969
  });
13773
- var publicAgentVersionsContract = c11.router({
13970
+ var publicAgentVersionsContract = c12.router({
13774
13971
  list: {
13775
13972
  method: "GET",
13776
13973
  path: "/v1/agents/:id/versions",
@@ -13790,7 +13987,7 @@ var publicAgentVersionsContract = c11.router({
13790
13987
  });
13791
13988
 
13792
13989
  // ../../packages/core/src/contracts/public/runs.ts
13793
- var c12 = initContract();
13990
+ var c13 = initContract();
13794
13991
  var publicRunStatusSchema = external_exports.enum([
13795
13992
  "pending",
13796
13993
  "running",
@@ -13848,7 +14045,7 @@ var runListQuerySchema = listQuerySchema.extend({
13848
14045
  status: publicRunStatusSchema.optional(),
13849
14046
  since: timestampSchema.optional()
13850
14047
  });
13851
- var publicRunsListContract = c12.router({
14048
+ var publicRunsListContract = c13.router({
13852
14049
  list: {
13853
14050
  method: "GET",
13854
14051
  path: "/v1/runs",
@@ -13877,7 +14074,7 @@ var publicRunsListContract = c12.router({
13877
14074
  description: "Create and execute a new agent run. Returns 202 Accepted as runs execute asynchronously."
13878
14075
  }
13879
14076
  });
13880
- var publicRunByIdContract = c12.router({
14077
+ var publicRunByIdContract = c13.router({
13881
14078
  get: {
13882
14079
  method: "GET",
13883
14080
  path: "/v1/runs/:id",
@@ -13894,7 +14091,7 @@ var publicRunByIdContract = c12.router({
13894
14091
  description: "Get run details by ID"
13895
14092
  }
13896
14093
  });
13897
- var publicRunCancelContract = c12.router({
14094
+ var publicRunCancelContract = c13.router({
13898
14095
  cancel: {
13899
14096
  method: "POST",
13900
14097
  path: "/v1/runs/:id/cancel",
@@ -13928,7 +14125,7 @@ var logsQuerySchema = listQuerySchema.extend({
13928
14125
  until: timestampSchema.optional(),
13929
14126
  order: external_exports.enum(["asc", "desc"]).default("asc")
13930
14127
  });
13931
- var publicRunLogsContract = c12.router({
14128
+ var publicRunLogsContract = c13.router({
13932
14129
  getLogs: {
13933
14130
  method: "GET",
13934
14131
  path: "/v1/runs/:id/logs",
@@ -13963,7 +14160,7 @@ var metricsResponseSchema2 = external_exports.object({
13963
14160
  data: external_exports.array(metricPointSchema),
13964
14161
  summary: metricsSummarySchema
13965
14162
  });
13966
- var publicRunMetricsContract = c12.router({
14163
+ var publicRunMetricsContract = c13.router({
13967
14164
  getMetrics: {
13968
14165
  method: "GET",
13969
14166
  path: "/v1/runs/:id/metrics",
@@ -13998,7 +14195,7 @@ var sseEventSchema = external_exports.object({
13998
14195
  id: external_exports.string().optional()
13999
14196
  // For Last-Event-ID reconnection
14000
14197
  });
14001
- var publicRunEventsContract = c12.router({
14198
+ var publicRunEventsContract = c13.router({
14002
14199
  streamEvents: {
14003
14200
  method: "GET",
14004
14201
  path: "/v1/runs/:id/events",
@@ -14022,7 +14219,7 @@ var publicRunEventsContract = c12.router({
14022
14219
  });
14023
14220
 
14024
14221
  // ../../packages/core/src/contracts/public/artifacts.ts
14025
- var c13 = initContract();
14222
+ var c14 = initContract();
14026
14223
  var publicArtifactSchema = external_exports.object({
14027
14224
  id: external_exports.string(),
14028
14225
  name: external_exports.string(),
@@ -14052,7 +14249,7 @@ var paginatedArtifactsSchema = createPaginatedResponseSchema(publicArtifactSchem
14052
14249
  var paginatedArtifactVersionsSchema = createPaginatedResponseSchema(
14053
14250
  artifactVersionSchema
14054
14251
  );
14055
- var publicArtifactsListContract = c13.router({
14252
+ var publicArtifactsListContract = c14.router({
14056
14253
  list: {
14057
14254
  method: "GET",
14058
14255
  path: "/v1/artifacts",
@@ -14066,7 +14263,7 @@ var publicArtifactsListContract = c13.router({
14066
14263
  description: "List all artifacts in the current scope with pagination"
14067
14264
  }
14068
14265
  });
14069
- var publicArtifactByIdContract = c13.router({
14266
+ var publicArtifactByIdContract = c14.router({
14070
14267
  get: {
14071
14268
  method: "GET",
14072
14269
  path: "/v1/artifacts/:id",
@@ -14083,7 +14280,7 @@ var publicArtifactByIdContract = c13.router({
14083
14280
  description: "Get artifact details by ID"
14084
14281
  }
14085
14282
  });
14086
- var publicArtifactVersionsContract = c13.router({
14283
+ var publicArtifactVersionsContract = c14.router({
14087
14284
  list: {
14088
14285
  method: "GET",
14089
14286
  path: "/v1/artifacts/:id/versions",
@@ -14101,7 +14298,7 @@ var publicArtifactVersionsContract = c13.router({
14101
14298
  description: "List all versions of an artifact with pagination"
14102
14299
  }
14103
14300
  });
14104
- var publicArtifactDownloadContract = c13.router({
14301
+ var publicArtifactDownloadContract = c14.router({
14105
14302
  download: {
14106
14303
  method: "GET",
14107
14304
  path: "/v1/artifacts/:id/download",
@@ -14125,7 +14322,7 @@ var publicArtifactDownloadContract = c13.router({
14125
14322
  });
14126
14323
 
14127
14324
  // ../../packages/core/src/contracts/public/volumes.ts
14128
- var c14 = initContract();
14325
+ var c15 = initContract();
14129
14326
  var publicVolumeSchema = external_exports.object({
14130
14327
  id: external_exports.string(),
14131
14328
  name: external_exports.string(),
@@ -14153,7 +14350,7 @@ var publicVolumeDetailSchema = publicVolumeSchema.extend({
14153
14350
  });
14154
14351
  var paginatedVolumesSchema = createPaginatedResponseSchema(publicVolumeSchema);
14155
14352
  var paginatedVolumeVersionsSchema = createPaginatedResponseSchema(volumeVersionSchema);
14156
- var publicVolumesListContract = c14.router({
14353
+ var publicVolumesListContract = c15.router({
14157
14354
  list: {
14158
14355
  method: "GET",
14159
14356
  path: "/v1/volumes",
@@ -14167,7 +14364,7 @@ var publicVolumesListContract = c14.router({
14167
14364
  description: "List all volumes in the current scope with pagination"
14168
14365
  }
14169
14366
  });
14170
- var publicVolumeByIdContract = c14.router({
14367
+ var publicVolumeByIdContract = c15.router({
14171
14368
  get: {
14172
14369
  method: "GET",
14173
14370
  path: "/v1/volumes/:id",
@@ -14184,7 +14381,7 @@ var publicVolumeByIdContract = c14.router({
14184
14381
  description: "Get volume details by ID"
14185
14382
  }
14186
14383
  });
14187
- var publicVolumeVersionsContract = c14.router({
14384
+ var publicVolumeVersionsContract = c15.router({
14188
14385
  list: {
14189
14386
  method: "GET",
14190
14387
  path: "/v1/volumes/:id/versions",
@@ -14202,7 +14399,7 @@ var publicVolumeVersionsContract = c14.router({
14202
14399
  description: "List all versions of a volume with pagination"
14203
14400
  }
14204
14401
  });
14205
- var publicVolumeDownloadContract = c14.router({
14402
+ var publicVolumeDownloadContract = c15.router({
14206
14403
  download: {
14207
14404
  method: "GET",
14208
14405
  path: "/v1/volumes/:id/download",
@@ -14314,7 +14511,7 @@ function getProviderDisplayName(provider) {
14314
14511
  return PROVIDER_DISPLAY_NAMES[provider];
14315
14512
  }
14316
14513
 
14317
- // src/lib/api-client.ts
14514
+ // src/lib/api/api-client.ts
14318
14515
  var ApiClient = class {
14319
14516
  async getHeaders() {
14320
14517
  const token = await getToken();
@@ -14444,22 +14641,6 @@ var ApiClient = class {
14444
14641
  }
14445
14642
  return await response.json();
14446
14643
  }
14447
- async getTelemetry(runId) {
14448
- const baseUrl = await this.getBaseUrl();
14449
- const headers = await this.getHeaders();
14450
- const response = await fetch(
14451
- `${baseUrl}/api/agent/runs/${runId}/telemetry`,
14452
- {
14453
- method: "GET",
14454
- headers
14455
- }
14456
- );
14457
- if (!response.ok) {
14458
- const error43 = await response.json();
14459
- throw new Error(error43.error?.message || "Failed to fetch telemetry");
14460
- }
14461
- return await response.json();
14462
- }
14463
14644
  async getSystemLog(runId, options) {
14464
14645
  const baseUrl = await this.getBaseUrl();
14465
14646
  const headers = await this.getHeaders();
@@ -14560,20 +14741,6 @@ var ApiClient = class {
14560
14741
  }
14561
14742
  return await response.json();
14562
14743
  }
14563
- async createImage(body) {
14564
- const baseUrl = await this.getBaseUrl();
14565
- const headers = await this.getHeaders();
14566
- const response = await fetch(`${baseUrl}/api/images`, {
14567
- method: "POST",
14568
- headers,
14569
- body: JSON.stringify(body)
14570
- });
14571
- if (!response.ok) {
14572
- const error43 = await response.json();
14573
- throw new Error(error43.error?.message || "Failed to create image");
14574
- }
14575
- return await response.json();
14576
- }
14577
14744
  /**
14578
14745
  * Get current user's scope
14579
14746
  */
@@ -14735,7 +14902,7 @@ var ApiClient = class {
14735
14902
  };
14736
14903
  var apiClient = new ApiClient();
14737
14904
 
14738
- // src/lib/provider-config.ts
14905
+ // src/lib/domain/provider-config.ts
14739
14906
  var PROVIDER_DEFAULTS = {
14740
14907
  "claude-code": {
14741
14908
  workingDir: "/home/user/workspace",
@@ -14799,7 +14966,7 @@ function getDefaultImageWithApps(provider, apps) {
14799
14966
  return isDevelopment ? defaults.image.development : defaults.image.production;
14800
14967
  }
14801
14968
 
14802
- // src/lib/yaml-validator.ts
14969
+ // src/lib/domain/yaml-validator.ts
14803
14970
  function validateAgentName(name) {
14804
14971
  const nameRegex = /^[a-zA-Z0-9]([a-zA-Z0-9-]{1,62}[a-zA-Z0-9])?$/;
14805
14972
  return nameRegex.test(name);
@@ -15066,12 +15233,12 @@ function validateAgentCompose(config2) {
15066
15233
  return { valid: true };
15067
15234
  }
15068
15235
 
15069
- // src/lib/system-storage.ts
15236
+ // src/lib/storage/system-storage.ts
15070
15237
  import * as fs4 from "fs/promises";
15071
15238
  import * as path4 from "path";
15072
15239
  import * as os3 from "os";
15073
15240
 
15074
- // src/lib/github-skills.ts
15241
+ // src/lib/domain/github-skills.ts
15075
15242
  import * as fs from "fs/promises";
15076
15243
  import * as path from "path";
15077
15244
  import * as os from "os";
@@ -15155,14 +15322,14 @@ async function readSkillFrontmatter(skillDir) {
15155
15322
  return parseSkillFrontmatter(content);
15156
15323
  }
15157
15324
 
15158
- // src/lib/direct-upload.ts
15325
+ // src/lib/storage/direct-upload.ts
15159
15326
  import { createHash } from "crypto";
15160
15327
  import * as fs3 from "fs";
15161
15328
  import * as path3 from "path";
15162
15329
  import * as os2 from "os";
15163
15330
  import * as tar2 from "tar";
15164
15331
 
15165
- // src/lib/file-utils.ts
15332
+ // src/lib/utils/file-utils.ts
15166
15333
  import * as fs2 from "fs";
15167
15334
  import * as path2 from "path";
15168
15335
  import * as tar from "tar";
@@ -15262,7 +15429,7 @@ async function removeEmptyDirs(dir, excludeDirs = [".vm0"]) {
15262
15429
  return isEmpty;
15263
15430
  }
15264
15431
 
15265
- // src/lib/direct-upload.ts
15432
+ // src/lib/storage/direct-upload.ts
15266
15433
  async function hashFileStream(filePath) {
15267
15434
  return new Promise((resolve2, reject) => {
15268
15435
  const hash2 = createHash("sha256");
@@ -15477,7 +15644,7 @@ async function directUpload(storageName, storageType, cwd, options) {
15477
15644
  };
15478
15645
  }
15479
15646
 
15480
- // src/lib/system-storage.ts
15647
+ // src/lib/storage/system-storage.ts
15481
15648
  function getInstructionsFilename(provider) {
15482
15649
  const validatedProvider = getValidatedProvider(provider);
15483
15650
  if (validatedProvider === "codex") {
@@ -15803,7 +15970,7 @@ import * as fs5 from "fs";
15803
15970
  import * as path5 from "path";
15804
15971
  import { config as dotenvConfig } from "dotenv";
15805
15972
 
15806
- // src/lib/claude-event-parser.ts
15973
+ // src/lib/events/claude-event-parser.ts
15807
15974
  var ClaudeEventParser = class {
15808
15975
  /**
15809
15976
  * Parse a raw Claude Code JSONL event into a simplified format
@@ -15907,7 +16074,7 @@ var ClaudeEventParser = class {
15907
16074
  }
15908
16075
  };
15909
16076
 
15910
- // src/lib/codex-event-parser.ts
16077
+ // src/lib/events/codex-event-parser.ts
15911
16078
  var CodexEventParser = class {
15912
16079
  /**
15913
16080
  * Parse a raw Codex CLI JSONL event into a simplified format
@@ -16061,9 +16228,9 @@ var CodexEventParser = class {
16061
16228
  }
16062
16229
  }
16063
16230
  if (itemType === "file_change" && item.changes && item.changes.length > 0) {
16064
- const changes = item.changes.map((c15) => {
16065
- const action = c15.kind === "add" ? "Created" : c15.kind === "modify" ? "Modified" : "Deleted";
16066
- return `${action}: ${c15.path}`;
16231
+ const changes = item.changes.map((c16) => {
16232
+ const action = c16.kind === "add" ? "Created" : c16.kind === "modify" ? "Modified" : "Deleted";
16233
+ return `${action}: ${c16.path}`;
16067
16234
  }).join("\n");
16068
16235
  return {
16069
16236
  type: "text",
@@ -16097,7 +16264,7 @@ ${changes}` }
16097
16264
  }
16098
16265
  };
16099
16266
 
16100
- // src/lib/event-parser-factory.ts
16267
+ // src/lib/events/event-parser-factory.ts
16101
16268
  function detectProviderFromEvent(rawEvent) {
16102
16269
  if (!rawEvent || typeof rawEvent !== "object") {
16103
16270
  return null;
@@ -16123,7 +16290,7 @@ function parseEvent(rawEvent, provider) {
16123
16290
  return Parser.parse(rawEvent);
16124
16291
  }
16125
16292
 
16126
- // src/lib/event-renderer.ts
16293
+ // src/lib/events/event-renderer.ts
16127
16294
  import chalk3 from "chalk";
16128
16295
  var EventRenderer = class {
16129
16296
  /**
@@ -16311,7 +16478,7 @@ var EventRenderer = class {
16311
16478
  }
16312
16479
  };
16313
16480
 
16314
- // src/lib/codex-event-renderer.ts
16481
+ // src/lib/events/codex-event-renderer.ts
16315
16482
  import chalk4 from "chalk";
16316
16483
  var CodexEventRenderer = class {
16317
16484
  /**
@@ -16404,9 +16571,9 @@ var CodexEventRenderer = class {
16404
16571
  return;
16405
16572
  }
16406
16573
  if (itemType === "file_change" && item.changes && item.changes.length > 0) {
16407
- const summary = item.changes.map((c15) => {
16408
- const icon = c15.kind === "add" ? "+" : c15.kind === "delete" ? "-" : "~";
16409
- return `${icon}${c15.path}`;
16574
+ const summary = item.changes.map((c16) => {
16575
+ const icon = c16.kind === "add" ? "+" : c16.kind === "delete" ? "-" : "~";
16576
+ return `${icon}${c16.path}`;
16410
16577
  }).join(", ");
16411
16578
  console.log(chalk4.green("[files]") + ` ${summary}`);
16412
16579
  return;
@@ -16981,7 +17148,7 @@ import { Command as Command3 } from "commander";
16981
17148
  import chalk6 from "chalk";
16982
17149
  import path7 from "path";
16983
17150
 
16984
- // src/lib/storage-utils.ts
17151
+ // src/lib/storage/storage-utils.ts
16985
17152
  import { readFile as readFile5, writeFile as writeFile4, mkdir as mkdir4 } from "fs/promises";
16986
17153
  import { existsSync as existsSync5 } from "fs";
16987
17154
  import { parse as parseYaml3, stringify as stringifyYaml } from "yaml";
@@ -17028,7 +17195,7 @@ async function writeStorageConfig(storageName, basePath = process.cwd(), type =
17028
17195
  await writeFile4(configPath, yamlContent, "utf8");
17029
17196
  }
17030
17197
 
17031
- // src/lib/prompt-utils.ts
17198
+ // src/lib/utils/prompt-utils.ts
17032
17199
  import prompts2 from "prompts";
17033
17200
  function isInteractive() {
17034
17201
  return process.stdout.isTTY === true;
@@ -17072,6 +17239,26 @@ async function promptConfirm(message, initial = true) {
17072
17239
  );
17073
17240
  return response.value;
17074
17241
  }
17242
+ async function promptSelect(message, choices, initial) {
17243
+ if (!isInteractive()) {
17244
+ return void 0;
17245
+ }
17246
+ const response = await prompts2(
17247
+ {
17248
+ type: "select",
17249
+ name: "value",
17250
+ message,
17251
+ choices,
17252
+ initial
17253
+ },
17254
+ {
17255
+ onCancel: () => {
17256
+ return false;
17257
+ }
17258
+ }
17259
+ );
17260
+ return response.value;
17261
+ }
17075
17262
 
17076
17263
  // src/commands/volume/init.ts
17077
17264
  var initCommand = new Command3().name("init").description("Initialize a volume in the current directory").option("-n, --name <name>", "Volume name (required in non-interactive mode)").action(async (options) => {
@@ -17206,7 +17393,7 @@ import * as fs6 from "fs";
17206
17393
  import * as os4 from "os";
17207
17394
  import * as tar3 from "tar";
17208
17395
 
17209
- // src/lib/pull-utils.ts
17396
+ // src/lib/storage/pull-utils.ts
17210
17397
  import chalk8 from "chalk";
17211
17398
  async function handleEmptyStorageResponse(cwd) {
17212
17399
  console.log(chalk8.dim("Syncing local files..."));
@@ -17442,7 +17629,7 @@ var listCommand = new Command7().name("list").alias("ls").description("List all
17442
17629
  import { Command as Command8 } from "commander";
17443
17630
  import chalk13 from "chalk";
17444
17631
 
17445
- // src/lib/clone-utils.ts
17632
+ // src/lib/storage/clone-utils.ts
17446
17633
  import chalk12 from "chalk";
17447
17634
  import path9 from "path";
17448
17635
  import * as fs7 from "fs";
@@ -17965,7 +18152,7 @@ import { spawn as spawn2 } from "child_process";
17965
18152
  import { parse as parseYaml4 } from "yaml";
17966
18153
  import { config as dotenvConfig2 } from "dotenv";
17967
18154
 
17968
- // src/lib/update-checker.ts
18155
+ // src/lib/utils/update-checker.ts
17969
18156
  import https from "https";
17970
18157
  import { spawn } from "child_process";
17971
18158
  import chalk20 from "chalk";
@@ -18073,7 +18260,7 @@ async function checkAndUpgrade(currentVersion, prompt) {
18073
18260
  return true;
18074
18261
  }
18075
18262
 
18076
- // src/lib/cook-state.ts
18263
+ // src/lib/domain/cook-state.ts
18077
18264
  import { homedir as homedir2 } from "os";
18078
18265
  import { join as join6 } from "path";
18079
18266
  import { readFile as readFile6, writeFile as writeFile5, mkdir as mkdir5 } from "fs/promises";
@@ -18298,7 +18485,7 @@ async function autoPullArtifact(runOutput, artifactDir) {
18298
18485
  }
18299
18486
  var cookCmd = new Command17().name("cook").description("One-click agent preparation and execution from vm0.yaml");
18300
18487
  cookCmd.argument("[prompt]", "Prompt for the agent").option("-y, --yes", "Skip confirmation prompts").action(async (prompt, options) => {
18301
- const shouldExit = await checkAndUpgrade("5.1.3", prompt);
18488
+ const shouldExit = await checkAndUpgrade("5.3.0", prompt);
18302
18489
  if (shouldExit) {
18303
18490
  process.exit(0);
18304
18491
  }
@@ -18586,7 +18773,7 @@ var cookCommand = cookCmd;
18586
18773
  import { Command as Command18 } from "commander";
18587
18774
  import chalk22 from "chalk";
18588
18775
 
18589
- // src/lib/time-parser.ts
18776
+ // src/lib/utils/time-parser.ts
18590
18777
  function parseTime(timeStr) {
18591
18778
  const relativeMatch = timeStr.match(/^(\d+)([smhdw])$/);
18592
18779
  if (relativeMatch) {
@@ -18982,7 +19169,7 @@ var listCommand3 = new Command22().name("list").alias("ls").description("List al
18982
19169
  );
18983
19170
  return;
18984
19171
  }
18985
- const nameWidth = Math.max(4, ...data.composes.map((c15) => c15.name.length));
19172
+ const nameWidth = Math.max(4, ...data.composes.map((c16) => c16.name.length));
18986
19173
  const header = ["NAME".padEnd(nameWidth), "VERSION", "UPDATED"].join(
18987
19174
  " "
18988
19175
  );
@@ -19013,7 +19200,7 @@ var listCommand3 = new Command22().name("list").alias("ls").description("List al
19013
19200
  import { Command as Command23 } from "commander";
19014
19201
  import chalk26 from "chalk";
19015
19202
 
19016
- // src/lib/source-derivation.ts
19203
+ // src/lib/domain/source-derivation.ts
19017
19204
  import * as fs9 from "fs/promises";
19018
19205
  import * as path13 from "path";
19019
19206
  import * as os7 from "os";
@@ -19861,11 +20048,914 @@ var setupGithubCommand = new Command26().name("setup-github").description("Initi
19861
20048
  }
19862
20049
  );
19863
20050
 
20051
+ // src/commands/schedule/index.ts
20052
+ import { Command as Command34 } from "commander";
20053
+
20054
+ // src/commands/schedule/init.ts
20055
+ import { Command as Command27 } from "commander";
20056
+ import chalk29 from "chalk";
20057
+ import { existsSync as existsSync12, writeFileSync } from "fs";
20058
+ import { stringify as stringifyYaml2 } from "yaml";
20059
+
20060
+ // src/lib/domain/schedule-utils.ts
20061
+ import { existsSync as existsSync11, readFileSync as readFileSync2 } from "fs";
20062
+ import { parse as parseYaml6 } from "yaml";
20063
+ var CONFIG_FILE4 = "vm0.yaml";
20064
+ function loadAgentName() {
20065
+ if (!existsSync11(CONFIG_FILE4)) {
20066
+ return { agentName: null };
20067
+ }
20068
+ try {
20069
+ const content = readFileSync2(CONFIG_FILE4, "utf8");
20070
+ const config2 = parseYaml6(content);
20071
+ const agentNames = Object.keys(config2.agents || {});
20072
+ return { agentName: agentNames[0] || null };
20073
+ } catch (err) {
20074
+ return {
20075
+ agentName: null,
20076
+ error: err instanceof Error ? err.message : "Failed to parse vm0.yaml"
20077
+ };
20078
+ }
20079
+ }
20080
+ function formatRelativeTime2(dateStr) {
20081
+ if (!dateStr) return "-";
20082
+ const date5 = new Date(dateStr);
20083
+ const now = /* @__PURE__ */ new Date();
20084
+ const diffMs = date5.getTime() - now.getTime();
20085
+ const diffAbs = Math.abs(diffMs);
20086
+ const minutes = Math.floor(diffAbs / (1e3 * 60));
20087
+ const hours = Math.floor(diffAbs / (1e3 * 60 * 60));
20088
+ const days = Math.floor(diffAbs / (1e3 * 60 * 60 * 24));
20089
+ const isPast = diffMs < 0;
20090
+ if (days > 0) {
20091
+ return isPast ? `${days}d ago` : `in ${days}d`;
20092
+ } else if (hours > 0) {
20093
+ return isPast ? `${hours}h ago` : `in ${hours}h`;
20094
+ } else if (minutes > 0) {
20095
+ return isPast ? `${minutes}m ago` : `in ${minutes}m`;
20096
+ } else {
20097
+ return isPast ? "just now" : "soon";
20098
+ }
20099
+ }
20100
+ function formatDateTime(dateStr) {
20101
+ if (!dateStr) return "-";
20102
+ const date5 = new Date(dateStr);
20103
+ const formatted = date5.toISOString().replace("T", " ").replace(/\.\d+Z$/, " UTC");
20104
+ const relative2 = formatRelativeTime2(dateStr);
20105
+ return `${formatted} (${relative2})`;
20106
+ }
20107
+ function generateCronExpression(frequency, time3, day) {
20108
+ const [hourStr, minuteStr] = time3.split(":");
20109
+ const hour = parseInt(hourStr ?? "0", 10);
20110
+ const minute = parseInt(minuteStr ?? "0", 10);
20111
+ switch (frequency) {
20112
+ case "daily":
20113
+ return `${minute} ${hour} * * *`;
20114
+ case "weekly":
20115
+ return `${minute} ${hour} * * ${day ?? 1}`;
20116
+ case "monthly":
20117
+ return `${minute} ${hour} ${day ?? 1} * *`;
20118
+ }
20119
+ }
20120
+ function detectTimezone() {
20121
+ return Intl.DateTimeFormat().resolvedOptions().timeZone;
20122
+ }
20123
+ function extractVarsAndSecrets() {
20124
+ const result = { vars: [], secrets: [] };
20125
+ if (!existsSync11(CONFIG_FILE4)) {
20126
+ return result;
20127
+ }
20128
+ try {
20129
+ const content = readFileSync2(CONFIG_FILE4, "utf8");
20130
+ const config2 = parseYaml6(content);
20131
+ const agents = Object.values(config2.agents || {});
20132
+ const agent = agents[0];
20133
+ if (!agent) {
20134
+ return result;
20135
+ }
20136
+ if (agent.experimental_vars) {
20137
+ result.vars.push(...agent.experimental_vars);
20138
+ }
20139
+ if (agent.experimental_secrets) {
20140
+ result.secrets.push(...agent.experimental_secrets);
20141
+ }
20142
+ if (agent.environment) {
20143
+ for (const value of Object.values(agent.environment)) {
20144
+ const varsMatches = value.matchAll(/\$\{\{\s*vars\.(\w+)\s*\}\}/g);
20145
+ for (const match of varsMatches) {
20146
+ if (match[1] && !result.vars.includes(match[1])) {
20147
+ result.vars.push(match[1]);
20148
+ }
20149
+ }
20150
+ const secretsMatches = value.matchAll(
20151
+ /\$\{\{\s*secrets\.(\w+)\s*\}\}/g
20152
+ );
20153
+ for (const match of secretsMatches) {
20154
+ if (match[1] && !result.secrets.includes(match[1])) {
20155
+ result.secrets.push(match[1]);
20156
+ }
20157
+ }
20158
+ }
20159
+ }
20160
+ return result;
20161
+ } catch {
20162
+ return result;
20163
+ }
20164
+ }
20165
+ function validateTimeFormat(time3) {
20166
+ const match = time3.match(/^(\d{1,2}):(\d{2})$/);
20167
+ if (!match) {
20168
+ return "Invalid format. Use HH:MM (e.g., 09:00)";
20169
+ }
20170
+ const hour = parseInt(match[1], 10);
20171
+ const minute = parseInt(match[2], 10);
20172
+ if (hour < 0 || hour > 23) {
20173
+ return "Hour must be 0-23";
20174
+ }
20175
+ if (minute < 0 || minute > 59) {
20176
+ return "Minute must be 0-59";
20177
+ }
20178
+ return true;
20179
+ }
20180
+
20181
+ // src/commands/schedule/init.ts
20182
+ var SCHEDULE_FILE = "schedule.yaml";
20183
+ var FREQUENCY_CHOICES = [
20184
+ { title: "Daily", value: "daily", description: "Run every day" },
20185
+ {
20186
+ title: "Weekly",
20187
+ value: "weekly",
20188
+ description: "Run once per week"
20189
+ },
20190
+ {
20191
+ title: "Monthly",
20192
+ value: "monthly",
20193
+ description: "Run once per month"
20194
+ },
20195
+ {
20196
+ title: "One-time",
20197
+ value: "once",
20198
+ description: "Run once at specific time"
20199
+ }
20200
+ ];
20201
+ var DAY_OF_WEEK_CHOICES = [
20202
+ { title: "Monday", value: 1 },
20203
+ { title: "Tuesday", value: 2 },
20204
+ { title: "Wednesday", value: 3 },
20205
+ { title: "Thursday", value: 4 },
20206
+ { title: "Friday", value: 5 },
20207
+ { title: "Saturday", value: 6 },
20208
+ { title: "Sunday", value: 0 }
20209
+ ];
20210
+ function parseDayOption(day, frequency) {
20211
+ if (frequency === "weekly") {
20212
+ const dayMap = {
20213
+ sun: 0,
20214
+ mon: 1,
20215
+ tue: 2,
20216
+ wed: 3,
20217
+ thu: 4,
20218
+ fri: 5,
20219
+ sat: 6
20220
+ };
20221
+ return dayMap[day.toLowerCase()];
20222
+ } else if (frequency === "monthly") {
20223
+ const num = parseInt(day, 10);
20224
+ if (num >= 1 && num <= 31) {
20225
+ return num;
20226
+ }
20227
+ }
20228
+ return void 0;
20229
+ }
20230
+ var initCommand4 = new Command27().name("init").description("Create a schedule.yaml interactively").option("-n, --name <name>", "Schedule name").option("-f, --frequency <type>", "Frequency: daily|weekly|monthly|once").option("-t, --time <HH:MM>", "Time to run (24-hour format)").option("-d, --day <day>", "Day of week (mon-sun) or day of month (1-31)").option("-z, --timezone <tz>", "IANA timezone").option("-p, --prompt <text>", "Prompt to run").option("--no-vars", "Don't include vars from vm0.yaml").option("--force", "Overwrite existing schedule.yaml").action(
20231
+ async (options) => {
20232
+ try {
20233
+ const { agentName, error: error43 } = loadAgentName();
20234
+ if (error43) {
20235
+ console.error(chalk29.red(`\u2717 Invalid vm0.yaml: ${error43}`));
20236
+ process.exit(1);
20237
+ }
20238
+ if (!agentName) {
20239
+ console.error(chalk29.red("\u2717 No vm0.yaml found"));
20240
+ console.error(
20241
+ chalk29.dim(" Run this command from an agent directory")
20242
+ );
20243
+ process.exit(1);
20244
+ }
20245
+ if (existsSync12(SCHEDULE_FILE) && !options.force) {
20246
+ if (!isInteractive()) {
20247
+ console.error(chalk29.red("\u2717 schedule.yaml already exists"));
20248
+ console.error(chalk29.dim(" Use --force to overwrite"));
20249
+ process.exit(1);
20250
+ }
20251
+ const overwrite = await promptConfirm(
20252
+ "schedule.yaml exists. Overwrite?",
20253
+ false
20254
+ );
20255
+ if (!overwrite) {
20256
+ console.log(chalk29.dim("Cancelled"));
20257
+ return;
20258
+ }
20259
+ }
20260
+ let scheduleName = options.name;
20261
+ if (!scheduleName) {
20262
+ if (!isInteractive()) {
20263
+ console.error(
20264
+ chalk29.red("\u2717 --name is required in non-interactive mode")
20265
+ );
20266
+ process.exit(1);
20267
+ }
20268
+ scheduleName = await promptText(
20269
+ "Schedule name",
20270
+ `${agentName}-schedule`
20271
+ );
20272
+ if (!scheduleName) {
20273
+ console.log(chalk29.dim("Cancelled"));
20274
+ return;
20275
+ }
20276
+ }
20277
+ let frequency = options.frequency;
20278
+ if (!frequency || !["daily", "weekly", "monthly", "once"].includes(frequency)) {
20279
+ if (!isInteractive()) {
20280
+ console.error(
20281
+ chalk29.red(
20282
+ "\u2717 --frequency is required (daily|weekly|monthly|once)"
20283
+ )
20284
+ );
20285
+ process.exit(1);
20286
+ }
20287
+ frequency = await promptSelect(
20288
+ "Schedule frequency",
20289
+ FREQUENCY_CHOICES,
20290
+ 0
20291
+ );
20292
+ if (!frequency) {
20293
+ console.log(chalk29.dim("Cancelled"));
20294
+ return;
20295
+ }
20296
+ }
20297
+ let day;
20298
+ if (frequency === "weekly" || frequency === "monthly") {
20299
+ if (options.day) {
20300
+ day = parseDayOption(options.day, frequency);
20301
+ if (day === void 0) {
20302
+ console.error(
20303
+ chalk29.red(
20304
+ `\u2717 Invalid day: ${options.day}. Use mon-sun for weekly or 1-31 for monthly.`
20305
+ )
20306
+ );
20307
+ process.exit(1);
20308
+ }
20309
+ } else if (isInteractive()) {
20310
+ if (frequency === "weekly") {
20311
+ day = await promptSelect("Day of week", DAY_OF_WEEK_CHOICES, 0);
20312
+ if (day === void 0) {
20313
+ console.log(chalk29.dim("Cancelled"));
20314
+ return;
20315
+ }
20316
+ } else {
20317
+ const dayStr = await promptText("Day of month (1-31)", "1");
20318
+ if (!dayStr) {
20319
+ console.log(chalk29.dim("Cancelled"));
20320
+ return;
20321
+ }
20322
+ day = parseInt(dayStr, 10);
20323
+ if (isNaN(day) || day < 1 || day > 31) {
20324
+ console.error(chalk29.red("\u2717 Day must be between 1 and 31"));
20325
+ process.exit(1);
20326
+ }
20327
+ }
20328
+ } else {
20329
+ console.error(chalk29.red("\u2717 --day is required for weekly/monthly"));
20330
+ process.exit(1);
20331
+ }
20332
+ }
20333
+ let time3 = options.time;
20334
+ let atTime;
20335
+ if (frequency === "once") {
20336
+ if (!isInteractive()) {
20337
+ console.error(
20338
+ chalk29.red("\u2717 One-time schedules require interactive mode")
20339
+ );
20340
+ console.error(
20341
+ chalk29.dim(" Use cron frequency for non-interactive mode")
20342
+ );
20343
+ process.exit(1);
20344
+ }
20345
+ const dateStr = await promptText(
20346
+ "Date and time (YYYY-MM-DD HH:MM)",
20347
+ new Date(Date.now() + 24 * 60 * 60 * 1e3).toISOString().slice(0, 16).replace("T", " ")
20348
+ );
20349
+ if (!dateStr) {
20350
+ console.log(chalk29.dim("Cancelled"));
20351
+ return;
20352
+ }
20353
+ atTime = (/* @__PURE__ */ new Date(dateStr.replace(" ", "T") + ":00Z")).toISOString();
20354
+ } else {
20355
+ if (!time3) {
20356
+ if (!isInteractive()) {
20357
+ console.error(chalk29.red("\u2717 --time is required (HH:MM format)"));
20358
+ process.exit(1);
20359
+ }
20360
+ time3 = await promptText(
20361
+ "Time (HH:MM)",
20362
+ "09:00",
20363
+ validateTimeFormat
20364
+ );
20365
+ if (!time3) {
20366
+ console.log(chalk29.dim("Cancelled"));
20367
+ return;
20368
+ }
20369
+ } else {
20370
+ const validation = validateTimeFormat(time3);
20371
+ if (validation !== true) {
20372
+ console.error(chalk29.red(`\u2717 Invalid time: ${validation}`));
20373
+ process.exit(1);
20374
+ }
20375
+ }
20376
+ }
20377
+ const detectedTimezone = detectTimezone();
20378
+ let timezone = options.timezone;
20379
+ if (!timezone) {
20380
+ if (isInteractive()) {
20381
+ timezone = await promptText("Timezone", detectedTimezone);
20382
+ if (!timezone) {
20383
+ console.log(chalk29.dim("Cancelled"));
20384
+ return;
20385
+ }
20386
+ } else {
20387
+ timezone = detectedTimezone;
20388
+ }
20389
+ }
20390
+ let promptText_ = options.prompt;
20391
+ if (!promptText_) {
20392
+ if (!isInteractive()) {
20393
+ console.error(chalk29.red("\u2717 --prompt is required"));
20394
+ process.exit(1);
20395
+ }
20396
+ promptText_ = await promptText("Prompt to run");
20397
+ if (!promptText_) {
20398
+ console.log(chalk29.dim("Cancelled"));
20399
+ return;
20400
+ }
20401
+ }
20402
+ let vars;
20403
+ let secrets;
20404
+ if (options.vars) {
20405
+ const extracted = extractVarsAndSecrets();
20406
+ if (extracted.vars.length > 0 || extracted.secrets.length > 0) {
20407
+ let includeVars = true;
20408
+ if (isInteractive()) {
20409
+ const varList = [
20410
+ ...extracted.vars.map((v) => `vars.${v}`),
20411
+ ...extracted.secrets.map((s) => `secrets.${s}`)
20412
+ ];
20413
+ includeVars = await promptConfirm(
20414
+ `Include ${varList.length} variable(s) from vm0.yaml? (${varList.join(", ")})`,
20415
+ true
20416
+ ) ?? true;
20417
+ }
20418
+ if (includeVars) {
20419
+ if (extracted.vars.length > 0) {
20420
+ vars = {};
20421
+ for (const v of extracted.vars) {
20422
+ vars[v] = `\${${v}}`;
20423
+ }
20424
+ }
20425
+ if (extracted.secrets.length > 0) {
20426
+ secrets = {};
20427
+ for (const s of extracted.secrets) {
20428
+ secrets[s] = `\${${s}}`;
20429
+ }
20430
+ }
20431
+ }
20432
+ }
20433
+ }
20434
+ const scheduleYaml = {
20435
+ version: "1.0",
20436
+ schedules: {
20437
+ [scheduleName]: {
20438
+ on: {
20439
+ timezone
20440
+ },
20441
+ run: {
20442
+ agent: agentName,
20443
+ prompt: promptText_
20444
+ }
20445
+ }
20446
+ }
20447
+ };
20448
+ if (atTime) {
20449
+ scheduleYaml.schedules[scheduleName].on.at = atTime;
20450
+ } else if (time3 && frequency !== "once") {
20451
+ scheduleYaml.schedules[scheduleName].on.cron = generateCronExpression(frequency, time3, day);
20452
+ }
20453
+ if (vars && Object.keys(vars).length > 0) {
20454
+ scheduleYaml.schedules[scheduleName].run.vars = vars;
20455
+ }
20456
+ if (secrets && Object.keys(secrets).length > 0) {
20457
+ scheduleYaml.schedules[scheduleName].run.secrets = secrets;
20458
+ }
20459
+ writeFileSync(SCHEDULE_FILE, stringifyYaml2(scheduleYaml));
20460
+ console.log(chalk29.green(`\u2713 Created ${SCHEDULE_FILE}`));
20461
+ console.log(chalk29.dim(" Deploy with: vm0 schedule deploy"));
20462
+ } catch (error43) {
20463
+ console.error(chalk29.red("\u2717 Failed to create schedule.yaml"));
20464
+ if (error43 instanceof Error) {
20465
+ console.error(chalk29.dim(` ${error43.message}`));
20466
+ }
20467
+ process.exit(1);
20468
+ }
20469
+ }
20470
+ );
20471
+
20472
+ // src/commands/schedule/deploy.ts
20473
+ import { Command as Command28 } from "commander";
20474
+ import chalk30 from "chalk";
20475
+ import { existsSync as existsSync13, readFileSync as readFileSync3 } from "fs";
20476
+ import { parse as parseYaml7 } from "yaml";
20477
+ function expandEnvVars(value) {
20478
+ return value.replace(/\$\{([^}]+)\}/g, (match, varName) => {
20479
+ const envValue = process.env[varName];
20480
+ if (envValue === void 0) {
20481
+ console.warn(
20482
+ chalk30.yellow(` Warning: Environment variable ${varName} not set`)
20483
+ );
20484
+ return match;
20485
+ }
20486
+ return envValue;
20487
+ });
20488
+ }
20489
+ function expandEnvVarsInObject(obj) {
20490
+ if (!obj) return void 0;
20491
+ const result = {};
20492
+ for (const [key, value] of Object.entries(obj)) {
20493
+ result[key] = expandEnvVars(value);
20494
+ }
20495
+ return result;
20496
+ }
20497
+ var deployCommand = new Command28().name("deploy").description("Deploy a schedule from schedule.yaml (create or update)").argument("[file]", "Path to schedule.yaml", "schedule.yaml").action(async (file2) => {
20498
+ try {
20499
+ if (!existsSync13(file2)) {
20500
+ console.error(chalk30.red(`\u2717 File not found: ${file2}`));
20501
+ console.error(chalk30.dim(" Create a schedule.yaml file first"));
20502
+ process.exit(1);
20503
+ }
20504
+ const content = readFileSync3(file2, "utf-8");
20505
+ let parsed;
20506
+ try {
20507
+ parsed = parseYaml7(content);
20508
+ } catch (err) {
20509
+ console.error(chalk30.red("\u2717 Invalid YAML syntax"));
20510
+ if (err instanceof Error) {
20511
+ console.error(chalk30.dim(` ${err.message}`));
20512
+ }
20513
+ process.exit(1);
20514
+ }
20515
+ const result = scheduleYamlSchema.safeParse(parsed);
20516
+ if (!result.success) {
20517
+ console.error(chalk30.red("\u2717 Invalid schedule.yaml format"));
20518
+ for (const issue2 of result.error.issues) {
20519
+ console.error(
20520
+ chalk30.dim(` ${issue2.path.join(".")}: ${issue2.message}`)
20521
+ );
20522
+ }
20523
+ process.exit(1);
20524
+ }
20525
+ const scheduleYaml = result.data;
20526
+ const scheduleEntries = Object.entries(scheduleYaml.schedules);
20527
+ if (scheduleEntries.length === 0) {
20528
+ console.error(chalk30.red("\u2717 No schedules defined in file"));
20529
+ process.exit(1);
20530
+ }
20531
+ if (scheduleEntries.length > 1) {
20532
+ console.error(
20533
+ chalk30.red("\u2717 Multiple schedules per file not supported yet")
20534
+ );
20535
+ console.error(chalk30.dim(" Please use one schedule per file"));
20536
+ process.exit(1);
20537
+ }
20538
+ const [scheduleName, schedule] = scheduleEntries[0];
20539
+ console.log(`Deploying schedule ${chalk30.cyan(scheduleName)}...`);
20540
+ const agentRef = schedule.run.agent;
20541
+ let composeId;
20542
+ try {
20543
+ const namePart = agentRef.includes("/") ? agentRef.split("/").pop() : agentRef;
20544
+ const agentName = namePart.includes(":") ? namePart.split(":")[0] : namePart;
20545
+ const compose = await apiClient.getComposeByName(agentName);
20546
+ composeId = compose.id;
20547
+ } catch {
20548
+ console.error(chalk30.red(`\u2717 Agent not found: ${agentRef}`));
20549
+ console.error(chalk30.dim(" Make sure the agent is pushed first"));
20550
+ process.exit(1);
20551
+ }
20552
+ const expandedVars = expandEnvVarsInObject(schedule.run.vars);
20553
+ const expandedSecrets = expandEnvVarsInObject(schedule.run.secrets);
20554
+ const body = {
20555
+ name: scheduleName,
20556
+ composeId,
20557
+ cronExpression: schedule.on.cron,
20558
+ atTime: schedule.on.at,
20559
+ timezone: schedule.on.timezone || "UTC",
20560
+ prompt: schedule.run.prompt,
20561
+ vars: expandedVars,
20562
+ secrets: expandedSecrets,
20563
+ artifactName: schedule.run.artifactName,
20564
+ artifactVersion: schedule.run.artifactVersion,
20565
+ volumeVersions: schedule.run.volumeVersions
20566
+ };
20567
+ const response = await apiClient.post("/api/agent/schedules", {
20568
+ body: JSON.stringify(body)
20569
+ });
20570
+ if (!response.ok) {
20571
+ const error43 = await response.json();
20572
+ throw new Error(error43.error?.message || "Deploy failed");
20573
+ }
20574
+ const deployResult = await response.json();
20575
+ if (deployResult.created) {
20576
+ console.log(
20577
+ chalk30.green(`\u2713 Created schedule ${chalk30.cyan(scheduleName)}`)
20578
+ );
20579
+ } else {
20580
+ console.log(
20581
+ chalk30.green(`\u2713 Updated schedule ${chalk30.cyan(scheduleName)}`)
20582
+ );
20583
+ }
20584
+ if (deployResult.schedule.nextRunAt) {
20585
+ const nextRun = new Date(deployResult.schedule.nextRunAt);
20586
+ console.log(chalk30.dim(` Next run: ${nextRun.toLocaleString()}`));
20587
+ }
20588
+ if (deployResult.schedule.cronExpression) {
20589
+ console.log(
20590
+ chalk30.dim(
20591
+ ` Cron: ${deployResult.schedule.cronExpression} (${deployResult.schedule.timezone})`
20592
+ )
20593
+ );
20594
+ } else if (deployResult.schedule.atTime) {
20595
+ console.log(chalk30.dim(` At: ${deployResult.schedule.atTime}`));
20596
+ }
20597
+ } catch (error43) {
20598
+ console.error(chalk30.red("\u2717 Failed to deploy schedule"));
20599
+ if (error43 instanceof Error) {
20600
+ if (error43.message.includes("Not authenticated")) {
20601
+ console.error(chalk30.dim(" Run: vm0 auth login"));
20602
+ } else {
20603
+ console.error(chalk30.dim(` ${error43.message}`));
20604
+ }
20605
+ }
20606
+ process.exit(1);
20607
+ }
20608
+ });
20609
+
20610
+ // src/commands/schedule/list.ts
20611
+ import { Command as Command29 } from "commander";
20612
+ import chalk31 from "chalk";
20613
+ var listCommand4 = new Command29().name("list").alias("ls").description("List all schedules").action(async () => {
20614
+ try {
20615
+ const response = await apiClient.get("/api/agent/schedules");
20616
+ if (!response.ok) {
20617
+ const error43 = await response.json();
20618
+ throw new Error(error43.error?.message || "List failed");
20619
+ }
20620
+ const result = await response.json();
20621
+ if (result.schedules.length === 0) {
20622
+ console.log(chalk31.dim("No schedules found"));
20623
+ console.log(
20624
+ chalk31.dim(" Create one with: vm0 schedule deploy schedule.yaml")
20625
+ );
20626
+ return;
20627
+ }
20628
+ const nameWidth = Math.max(
20629
+ 4,
20630
+ ...result.schedules.map((s) => s.name.length)
20631
+ );
20632
+ const agentWidth = Math.max(
20633
+ 5,
20634
+ ...result.schedules.map((s) => s.composeName.length)
20635
+ );
20636
+ const triggerWidth = Math.max(
20637
+ 7,
20638
+ ...result.schedules.map(
20639
+ (s) => s.cronExpression ? s.cronExpression.length + s.timezone.length + 3 : s.atTime?.length || 0
20640
+ )
20641
+ );
20642
+ const header = [
20643
+ "NAME".padEnd(nameWidth),
20644
+ "AGENT".padEnd(agentWidth),
20645
+ "TRIGGER".padEnd(triggerWidth),
20646
+ "STATUS".padEnd(8),
20647
+ "NEXT RUN"
20648
+ ].join(" ");
20649
+ console.log(chalk31.dim(header));
20650
+ for (const schedule of result.schedules) {
20651
+ const trigger = schedule.cronExpression ? `${schedule.cronExpression} (${schedule.timezone})` : schedule.atTime || "-";
20652
+ const status = schedule.enabled ? chalk31.green("enabled") : chalk31.yellow("disabled");
20653
+ const nextRun = schedule.enabled ? formatRelativeTime2(schedule.nextRunAt) : "-";
20654
+ const row = [
20655
+ schedule.name.padEnd(nameWidth),
20656
+ schedule.composeName.padEnd(agentWidth),
20657
+ trigger.padEnd(triggerWidth),
20658
+ status.padEnd(8 + (schedule.enabled ? 0 : 2)),
20659
+ // Account for chalk chars
20660
+ nextRun
20661
+ ].join(" ");
20662
+ console.log(row);
20663
+ }
20664
+ } catch (error43) {
20665
+ console.error(chalk31.red("\u2717 Failed to list schedules"));
20666
+ if (error43 instanceof Error) {
20667
+ if (error43.message.includes("Not authenticated")) {
20668
+ console.error(chalk31.dim(" Run: vm0 auth login"));
20669
+ } else {
20670
+ console.error(chalk31.dim(` ${error43.message}`));
20671
+ }
20672
+ }
20673
+ process.exit(1);
20674
+ }
20675
+ });
20676
+
20677
+ // src/commands/schedule/status.ts
20678
+ import { Command as Command30 } from "commander";
20679
+ import chalk32 from "chalk";
20680
+ function formatDateTimeStyled(dateStr) {
20681
+ if (!dateStr) return chalk32.dim("-");
20682
+ const formatted = formatDateTime(dateStr);
20683
+ return formatted.replace(/\(([^)]+)\)$/, chalk32.dim("($1)"));
20684
+ }
20685
+ function formatTrigger(schedule) {
20686
+ if (schedule.cronExpression) {
20687
+ return `${schedule.cronExpression} ${chalk32.dim(`(${schedule.timezone})`)}`;
20688
+ }
20689
+ if (schedule.atTime) {
20690
+ return `${schedule.atTime} ${chalk32.dim("(one-time)")}`;
20691
+ }
20692
+ return chalk32.dim("-");
20693
+ }
20694
+ var statusCommand4 = new Command30().name("status").description("Show detailed status of a schedule").argument("<name>", "Schedule name").action(async (name) => {
20695
+ try {
20696
+ const result = loadAgentName();
20697
+ if (result.error) {
20698
+ console.error(chalk32.red(`\u2717 Invalid vm0.yaml: ${result.error}`));
20699
+ process.exit(1);
20700
+ }
20701
+ if (!result.agentName) {
20702
+ console.error(chalk32.red("\u2717 No vm0.yaml found in current directory"));
20703
+ console.error(chalk32.dim(" Run this command from the agent directory"));
20704
+ process.exit(1);
20705
+ }
20706
+ const agentName = result.agentName;
20707
+ let composeId;
20708
+ try {
20709
+ const compose = await apiClient.getComposeByName(agentName);
20710
+ composeId = compose.id;
20711
+ } catch {
20712
+ console.error(chalk32.red(`\u2717 Agent not found: ${agentName}`));
20713
+ console.error(chalk32.dim(" Make sure the agent is pushed first"));
20714
+ process.exit(1);
20715
+ }
20716
+ const response = await apiClient.get(
20717
+ `/api/agent/schedules/${encodeURIComponent(name)}?composeId=${encodeURIComponent(composeId)}`
20718
+ );
20719
+ if (!response.ok) {
20720
+ const error43 = await response.json();
20721
+ throw new Error(error43.error?.message || "Failed to get schedule");
20722
+ }
20723
+ const schedule = await response.json();
20724
+ console.log();
20725
+ console.log(`Schedule: ${chalk32.cyan(schedule.name)}`);
20726
+ console.log(chalk32.dim("\u2501".repeat(50)));
20727
+ const statusText = schedule.enabled ? chalk32.green("enabled") : chalk32.yellow("disabled");
20728
+ console.log(`${"Status:".padEnd(16)}${statusText}`);
20729
+ console.log(
20730
+ `${"Agent:".padEnd(16)}${schedule.composeName} ${chalk32.dim(`(${schedule.scopeSlug})`)}`
20731
+ );
20732
+ console.log(`${"Trigger:".padEnd(16)}${formatTrigger(schedule)}`);
20733
+ if (schedule.enabled) {
20734
+ console.log(
20735
+ `${"Next Run:".padEnd(16)}${formatDateTimeStyled(schedule.nextRunAt)}`
20736
+ );
20737
+ }
20738
+ if (schedule.lastRunAt) {
20739
+ const lastRunInfo = schedule.lastRunId ? `${formatDateTimeStyled(schedule.lastRunAt)} ${chalk32.dim(`[${schedule.lastRunId.slice(0, 8)}]`)}` : formatDateTimeStyled(schedule.lastRunAt);
20740
+ console.log(`${"Last Run:".padEnd(16)}${lastRunInfo}`);
20741
+ }
20742
+ const promptPreview = schedule.prompt.length > 60 ? schedule.prompt.slice(0, 57) + "..." : schedule.prompt;
20743
+ console.log(`${"Prompt:".padEnd(16)}${chalk32.dim(promptPreview)}`);
20744
+ if (schedule.vars && Object.keys(schedule.vars).length > 0) {
20745
+ console.log(
20746
+ `${"Variables:".padEnd(16)}${Object.keys(schedule.vars).join(", ")}`
20747
+ );
20748
+ }
20749
+ if (schedule.secretNames && schedule.secretNames.length > 0) {
20750
+ console.log(
20751
+ `${"Secrets:".padEnd(16)}${schedule.secretNames.join(", ")}`
20752
+ );
20753
+ }
20754
+ if (schedule.artifactName) {
20755
+ const artifactInfo = schedule.artifactVersion ? `${schedule.artifactName}:${schedule.artifactVersion}` : schedule.artifactName;
20756
+ console.log(`${"Artifact:".padEnd(16)}${artifactInfo}`);
20757
+ }
20758
+ if (schedule.volumeVersions && Object.keys(schedule.volumeVersions).length > 0) {
20759
+ console.log(
20760
+ `${"Volumes:".padEnd(16)}${Object.keys(schedule.volumeVersions).join(", ")}`
20761
+ );
20762
+ }
20763
+ console.log();
20764
+ console.log(
20765
+ chalk32.dim(
20766
+ `Created: ${new Date(schedule.createdAt).toISOString().replace("T", " ").replace(/\.\d+Z$/, " UTC")}`
20767
+ )
20768
+ );
20769
+ console.log(
20770
+ chalk32.dim(
20771
+ `Updated: ${new Date(schedule.updatedAt).toISOString().replace("T", " ").replace(/\.\d+Z$/, " UTC")}`
20772
+ )
20773
+ );
20774
+ console.log(chalk32.dim(`ID: ${schedule.id}`));
20775
+ console.log();
20776
+ } catch (error43) {
20777
+ console.error(chalk32.red("\u2717 Failed to get schedule status"));
20778
+ if (error43 instanceof Error) {
20779
+ if (error43.message.includes("Not authenticated")) {
20780
+ console.error(chalk32.dim(" Run: vm0 auth login"));
20781
+ } else if (error43.message.includes("not found") || error43.message.includes("Not found")) {
20782
+ console.error(chalk32.dim(` Schedule "${name}" not found`));
20783
+ } else {
20784
+ console.error(chalk32.dim(` ${error43.message}`));
20785
+ }
20786
+ }
20787
+ process.exit(1);
20788
+ }
20789
+ });
20790
+
20791
+ // src/commands/schedule/delete.ts
20792
+ import { Command as Command31 } from "commander";
20793
+ import chalk33 from "chalk";
20794
+ import * as readline from "readline";
20795
+ async function confirm(message) {
20796
+ const rl = readline.createInterface({
20797
+ input: process.stdin,
20798
+ output: process.stdout
20799
+ });
20800
+ return new Promise((resolve2) => {
20801
+ rl.question(`${message} (y/N) `, (answer) => {
20802
+ rl.close();
20803
+ resolve2(answer.toLowerCase() === "y" || answer.toLowerCase() === "yes");
20804
+ });
20805
+ });
20806
+ }
20807
+ var deleteCommand = new Command31().name("delete").alias("rm").description("Delete a schedule").argument("<name>", "Schedule name to delete").option("-f, --force", "Skip confirmation prompt").action(async (name, options) => {
20808
+ try {
20809
+ const result = loadAgentName();
20810
+ if (result.error) {
20811
+ console.error(chalk33.red(`\u2717 Invalid vm0.yaml: ${result.error}`));
20812
+ process.exit(1);
20813
+ }
20814
+ if (!result.agentName) {
20815
+ console.error(chalk33.red("\u2717 No vm0.yaml found in current directory"));
20816
+ console.error(chalk33.dim(" Run this command from the agent directory"));
20817
+ process.exit(1);
20818
+ }
20819
+ const agentName = result.agentName;
20820
+ let composeId;
20821
+ try {
20822
+ const compose = await apiClient.getComposeByName(agentName);
20823
+ composeId = compose.id;
20824
+ } catch {
20825
+ console.error(chalk33.red(`\u2717 Agent not found: ${agentName}`));
20826
+ console.error(chalk33.dim(" Make sure the agent is pushed first"));
20827
+ process.exit(1);
20828
+ }
20829
+ if (!options.force) {
20830
+ const confirmed = await confirm(`Delete schedule ${chalk33.cyan(name)}?`);
20831
+ if (!confirmed) {
20832
+ console.log(chalk33.dim("Cancelled"));
20833
+ return;
20834
+ }
20835
+ }
20836
+ const response = await apiClient.delete(
20837
+ `/api/agent/schedules/${encodeURIComponent(name)}?composeId=${encodeURIComponent(composeId)}`
20838
+ );
20839
+ if (!response.ok) {
20840
+ const error43 = await response.json();
20841
+ throw new Error(error43.error?.message || "Delete failed");
20842
+ }
20843
+ console.log(chalk33.green(`\u2713 Deleted schedule ${chalk33.cyan(name)}`));
20844
+ } catch (error43) {
20845
+ console.error(chalk33.red("\u2717 Failed to delete schedule"));
20846
+ if (error43 instanceof Error) {
20847
+ if (error43.message.includes("Not authenticated")) {
20848
+ console.error(chalk33.dim(" Run: vm0 auth login"));
20849
+ } else {
20850
+ console.error(chalk33.dim(` ${error43.message}`));
20851
+ }
20852
+ }
20853
+ process.exit(1);
20854
+ }
20855
+ });
20856
+
20857
+ // src/commands/schedule/enable.ts
20858
+ import { Command as Command32 } from "commander";
20859
+ import chalk34 from "chalk";
20860
+ var enableCommand = new Command32().name("enable").description("Enable a schedule").argument("<name>", "Schedule name to enable").action(async (name) => {
20861
+ try {
20862
+ const result = loadAgentName();
20863
+ if (result.error) {
20864
+ console.error(chalk34.red(`\u2717 Invalid vm0.yaml: ${result.error}`));
20865
+ process.exit(1);
20866
+ }
20867
+ if (!result.agentName) {
20868
+ console.error(chalk34.red("\u2717 No vm0.yaml found in current directory"));
20869
+ console.error(chalk34.dim(" Run this command from the agent directory"));
20870
+ process.exit(1);
20871
+ }
20872
+ const agentName = result.agentName;
20873
+ let composeId;
20874
+ try {
20875
+ const compose = await apiClient.getComposeByName(agentName);
20876
+ composeId = compose.id;
20877
+ } catch {
20878
+ console.error(chalk34.red(`\u2717 Agent not found: ${agentName}`));
20879
+ console.error(chalk34.dim(" Make sure the agent is pushed first"));
20880
+ process.exit(1);
20881
+ }
20882
+ const response = await apiClient.post(
20883
+ `/api/agent/schedules/${encodeURIComponent(name)}/enable`,
20884
+ { body: JSON.stringify({ composeId }) }
20885
+ );
20886
+ if (!response.ok) {
20887
+ const error43 = await response.json();
20888
+ throw new Error(error43.error?.message || "Enable failed");
20889
+ }
20890
+ console.log(chalk34.green(`\u2713 Enabled schedule ${chalk34.cyan(name)}`));
20891
+ } catch (error43) {
20892
+ console.error(chalk34.red("\u2717 Failed to enable schedule"));
20893
+ if (error43 instanceof Error) {
20894
+ if (error43.message.includes("Not authenticated")) {
20895
+ console.error(chalk34.dim(" Run: vm0 auth login"));
20896
+ } else {
20897
+ console.error(chalk34.dim(` ${error43.message}`));
20898
+ }
20899
+ }
20900
+ process.exit(1);
20901
+ }
20902
+ });
20903
+
20904
+ // src/commands/schedule/disable.ts
20905
+ import { Command as Command33 } from "commander";
20906
+ import chalk35 from "chalk";
20907
+ var disableCommand = new Command33().name("disable").description("Disable a schedule").argument("<name>", "Schedule name to disable").action(async (name) => {
20908
+ try {
20909
+ const result = loadAgentName();
20910
+ if (result.error) {
20911
+ console.error(chalk35.red(`\u2717 Invalid vm0.yaml: ${result.error}`));
20912
+ process.exit(1);
20913
+ }
20914
+ if (!result.agentName) {
20915
+ console.error(chalk35.red("\u2717 No vm0.yaml found in current directory"));
20916
+ console.error(chalk35.dim(" Run this command from the agent directory"));
20917
+ process.exit(1);
20918
+ }
20919
+ const agentName = result.agentName;
20920
+ let composeId;
20921
+ try {
20922
+ const compose = await apiClient.getComposeByName(agentName);
20923
+ composeId = compose.id;
20924
+ } catch {
20925
+ console.error(chalk35.red(`\u2717 Agent not found: ${agentName}`));
20926
+ console.error(chalk35.dim(" Make sure the agent is pushed first"));
20927
+ process.exit(1);
20928
+ }
20929
+ const response = await apiClient.post(
20930
+ `/api/agent/schedules/${encodeURIComponent(name)}/disable`,
20931
+ { body: JSON.stringify({ composeId }) }
20932
+ );
20933
+ if (!response.ok) {
20934
+ const error43 = await response.json();
20935
+ throw new Error(error43.error?.message || "Disable failed");
20936
+ }
20937
+ console.log(chalk35.green(`\u2713 Disabled schedule ${chalk35.cyan(name)}`));
20938
+ } catch (error43) {
20939
+ console.error(chalk35.red("\u2717 Failed to disable schedule"));
20940
+ if (error43 instanceof Error) {
20941
+ if (error43.message.includes("Not authenticated")) {
20942
+ console.error(chalk35.dim(" Run: vm0 auth login"));
20943
+ } else {
20944
+ console.error(chalk35.dim(` ${error43.message}`));
20945
+ }
20946
+ }
20947
+ process.exit(1);
20948
+ }
20949
+ });
20950
+
20951
+ // src/commands/schedule/index.ts
20952
+ var scheduleCommand = new Command34().name("schedule").description("Manage agent schedules").addCommand(initCommand4).addCommand(deployCommand).addCommand(listCommand4).addCommand(statusCommand4).addCommand(deleteCommand).addCommand(enableCommand).addCommand(disableCommand);
20953
+
19864
20954
  // src/index.ts
19865
- var program = new Command27();
19866
- program.name("vm0").description("VM0 CLI - A modern build tool").version("5.1.3");
20955
+ var program = new Command35();
20956
+ program.name("vm0").description("VM0 CLI - A modern build tool").version("5.3.0");
19867
20957
  program.command("info").description("Display environment information").action(async () => {
19868
- console.log(chalk29.bold("System Information:"));
20958
+ console.log(chalk36.bold("System Information:"));
19869
20959
  console.log(`Node Version: ${process.version}`);
19870
20960
  console.log(`Platform: ${process.platform}`);
19871
20961
  console.log(`Architecture: ${process.arch}`);
@@ -19895,6 +20985,7 @@ program.addCommand(scopeCommand);
19895
20985
  program.addCommand(agentsCommand);
19896
20986
  program.addCommand(initCommand3);
19897
20987
  program.addCommand(setupGithubCommand);
20988
+ program.addCommand(scheduleCommand);
19898
20989
  if (process.argv[1]?.endsWith("index.js") || process.argv[1]?.endsWith("index.ts") || process.argv[1]?.endsWith("vm0")) {
19899
20990
  program.parse();
19900
20991
  }