@vm0/cli 5.6.0 → 5.7.2

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 +740 -407
  2. package/package.json +1 -1
package/index.js CHANGED
@@ -2595,8 +2595,7 @@ var ApiClient = class {
2595
2595
  throw new Error("Not authenticated. Run: vm0 auth login");
2596
2596
  }
2597
2597
  const headers = {
2598
- Authorization: `Bearer ${token}`,
2599
- "Content-Type": "application/json"
2598
+ Authorization: `Bearer ${token}`
2600
2599
  };
2601
2600
  const bypassSecret = process.env.VERCEL_AUTOMATION_BYPASS_SECRET;
2602
2601
  if (bypassSecret) {
@@ -2614,35 +2613,41 @@ var ApiClient = class {
2614
2613
  async getComposeByName(name, scope) {
2615
2614
  const baseUrl = await this.getBaseUrl();
2616
2615
  const headers = await this.getHeaders();
2617
- const params = new URLSearchParams({ name });
2618
- if (scope) {
2619
- params.append("scope", scope);
2620
- }
2621
- const response = await fetch(
2622
- `${baseUrl}/api/agent/composes?${params.toString()}`,
2623
- {
2624
- method: "GET",
2625
- headers
2616
+ const client = initClient(composesMainContract, {
2617
+ baseUrl,
2618
+ baseHeaders: headers,
2619
+ jsonQuery: true
2620
+ });
2621
+ const result = await client.getByName({
2622
+ query: {
2623
+ name,
2624
+ scope
2626
2625
  }
2627
- );
2628
- if (!response.ok) {
2629
- const error = await response.json();
2630
- throw new Error(error.error?.message || `Compose not found: ${name}`);
2626
+ });
2627
+ if (result.status === 200) {
2628
+ return result.body;
2631
2629
  }
2632
- return await response.json();
2630
+ const errorBody = result.body;
2631
+ const message = errorBody.error?.message || `Compose not found: ${name}`;
2632
+ throw new Error(message);
2633
2633
  }
2634
2634
  async getComposeById(id) {
2635
2635
  const baseUrl = await this.getBaseUrl();
2636
2636
  const headers = await this.getHeaders();
2637
- const response = await fetch(`${baseUrl}/api/agent/composes/${id}`, {
2638
- method: "GET",
2639
- headers
2637
+ const client = initClient(composesByIdContract, {
2638
+ baseUrl,
2639
+ baseHeaders: headers,
2640
+ jsonQuery: true
2640
2641
  });
2641
- if (!response.ok) {
2642
- const error = await response.json();
2643
- throw new Error(error.error?.message || `Compose not found: ${id}`);
2642
+ const result = await client.getById({
2643
+ params: { id }
2644
+ });
2645
+ if (result.status === 200) {
2646
+ return result.body;
2644
2647
  }
2645
- return await response.json();
2648
+ const errorBody = result.body;
2649
+ const message = errorBody.error?.message || `Compose not found: ${id}`;
2650
+ throw new Error(message);
2646
2651
  }
2647
2652
  /**
2648
2653
  * Resolve a version specifier to a full version ID
@@ -2651,33 +2656,41 @@ var ApiClient = class {
2651
2656
  async getComposeVersion(composeId, version) {
2652
2657
  const baseUrl = await this.getBaseUrl();
2653
2658
  const headers = await this.getHeaders();
2654
- const quotedVersion = JSON.stringify(version);
2655
- const response = await fetch(
2656
- `${baseUrl}/api/agent/composes/versions?composeId=${encodeURIComponent(composeId)}&version=${encodeURIComponent(quotedVersion)}`,
2657
- {
2658
- method: "GET",
2659
- headers
2659
+ const client = initClient(composesVersionsContract, {
2660
+ baseUrl,
2661
+ baseHeaders: headers,
2662
+ jsonQuery: true
2663
+ });
2664
+ const result = await client.resolveVersion({
2665
+ query: {
2666
+ composeId,
2667
+ version
2660
2668
  }
2661
- );
2662
- if (!response.ok) {
2663
- const error = await response.json();
2664
- throw new Error(error.error?.message || `Version not found: ${version}`);
2669
+ });
2670
+ if (result.status === 200) {
2671
+ return result.body;
2665
2672
  }
2666
- return await response.json();
2673
+ const errorBody = result.body;
2674
+ const message = errorBody.error?.message || `Version not found: ${version}`;
2675
+ throw new Error(message);
2667
2676
  }
2668
2677
  async createOrUpdateCompose(body) {
2669
2678
  const baseUrl = await this.getBaseUrl();
2670
2679
  const headers = await this.getHeaders();
2671
- const response = await fetch(`${baseUrl}/api/agent/composes`, {
2672
- method: "POST",
2673
- headers,
2674
- body: JSON.stringify(body)
2680
+ const client = initClient(composesMainContract, {
2681
+ baseUrl,
2682
+ baseHeaders: headers,
2683
+ jsonQuery: true
2675
2684
  });
2676
- if (!response.ok) {
2677
- const error = await response.json();
2678
- throw new Error(error.error?.message || "Failed to create compose");
2685
+ const result = await client.create({
2686
+ body
2687
+ });
2688
+ if (result.status === 200 || result.status === 201) {
2689
+ return result.body;
2679
2690
  }
2680
- return await response.json();
2691
+ const errorBody = result.body;
2692
+ const message = errorBody.error?.message || "Failed to create compose";
2693
+ throw new Error(message);
2681
2694
  }
2682
2695
  /**
2683
2696
  * Create a run with unified request format
@@ -2703,211 +2716,545 @@ var ApiClient = class {
2703
2716
  async getEvents(runId, options) {
2704
2717
  const baseUrl = await this.getBaseUrl();
2705
2718
  const headers = await this.getHeaders();
2706
- const since = options?.since ?? 0;
2707
- const limit = options?.limit ?? 100;
2708
- const response = await fetch(
2709
- `${baseUrl}/api/agent/runs/${runId}/events?since=${since}&limit=${limit}`,
2710
- {
2711
- method: "GET",
2712
- headers
2719
+ const client = initClient(runEventsContract, {
2720
+ baseUrl,
2721
+ baseHeaders: headers,
2722
+ jsonQuery: true
2723
+ });
2724
+ const result = await client.getEvents({
2725
+ params: { id: runId },
2726
+ query: {
2727
+ since: options?.since ?? 0,
2728
+ limit: options?.limit ?? 100
2713
2729
  }
2714
- );
2715
- if (!response.ok) {
2716
- const error = await response.json();
2717
- throw new Error(error.error?.message || "Failed to fetch events");
2730
+ });
2731
+ if (result.status === 200) {
2732
+ return result.body;
2718
2733
  }
2719
- return await response.json();
2734
+ const errorBody = result.body;
2735
+ const message = errorBody.error?.message || "Failed to fetch events";
2736
+ throw new Error(message);
2720
2737
  }
2721
2738
  async getSystemLog(runId, options) {
2722
2739
  const baseUrl = await this.getBaseUrl();
2723
2740
  const headers = await this.getHeaders();
2724
- const params = new URLSearchParams();
2725
- if (options?.since !== void 0) {
2726
- params.set("since", String(options.since));
2741
+ const client = initClient(runSystemLogContract, {
2742
+ baseUrl,
2743
+ baseHeaders: headers,
2744
+ jsonQuery: true
2745
+ });
2746
+ const result = await client.getSystemLog({
2747
+ params: { id: runId },
2748
+ query: {
2749
+ since: options?.since,
2750
+ limit: options?.limit,
2751
+ order: options?.order
2752
+ }
2753
+ });
2754
+ if (result.status === 200) {
2755
+ return result.body;
2727
2756
  }
2728
- if (options?.limit !== void 0) {
2729
- params.set("limit", String(options.limit));
2757
+ const errorBody = result.body;
2758
+ const message = errorBody.error?.message || "Failed to fetch system log";
2759
+ throw new Error(message);
2760
+ }
2761
+ async getMetrics(runId, options) {
2762
+ const baseUrl = await this.getBaseUrl();
2763
+ const headers = await this.getHeaders();
2764
+ const client = initClient(runMetricsContract, {
2765
+ baseUrl,
2766
+ baseHeaders: headers,
2767
+ jsonQuery: true
2768
+ });
2769
+ const result = await client.getMetrics({
2770
+ params: { id: runId },
2771
+ query: {
2772
+ since: options?.since,
2773
+ limit: options?.limit,
2774
+ order: options?.order
2775
+ }
2776
+ });
2777
+ if (result.status === 200) {
2778
+ return result.body;
2730
2779
  }
2731
- if (options?.order !== void 0) {
2732
- params.set("order", options.order);
2780
+ const errorBody = result.body;
2781
+ const message = errorBody.error?.message || "Failed to fetch metrics";
2782
+ throw new Error(message);
2783
+ }
2784
+ async getAgentEvents(runId, options) {
2785
+ const baseUrl = await this.getBaseUrl();
2786
+ const headers = await this.getHeaders();
2787
+ const client = initClient(runAgentEventsContract, {
2788
+ baseUrl,
2789
+ baseHeaders: headers,
2790
+ jsonQuery: true
2791
+ });
2792
+ const result = await client.getAgentEvents({
2793
+ params: { id: runId },
2794
+ query: {
2795
+ since: options?.since,
2796
+ limit: options?.limit,
2797
+ order: options?.order
2798
+ }
2799
+ });
2800
+ if (result.status === 200) {
2801
+ return result.body;
2733
2802
  }
2734
- const queryString = params.toString();
2735
- const url = `${baseUrl}/api/agent/runs/${runId}/telemetry/system-log${queryString ? `?${queryString}` : ""}`;
2736
- const response = await fetch(url, {
2737
- method: "GET",
2738
- headers
2803
+ const errorBody = result.body;
2804
+ const message = errorBody.error?.message || "Failed to fetch agent events";
2805
+ throw new Error(message);
2806
+ }
2807
+ async getNetworkLogs(runId, options) {
2808
+ const baseUrl = await this.getBaseUrl();
2809
+ const headers = await this.getHeaders();
2810
+ const client = initClient(runNetworkLogsContract, {
2811
+ baseUrl,
2812
+ baseHeaders: headers,
2813
+ jsonQuery: true
2739
2814
  });
2740
- if (!response.ok) {
2741
- const error = await response.json();
2742
- throw new Error(error.error?.message || "Failed to fetch system log");
2815
+ const result = await client.getNetworkLogs({
2816
+ params: { id: runId },
2817
+ query: {
2818
+ since: options?.since,
2819
+ limit: options?.limit,
2820
+ order: options?.order
2821
+ }
2822
+ });
2823
+ if (result.status === 200) {
2824
+ return result.body;
2743
2825
  }
2744
- return await response.json();
2826
+ const errorBody = result.body;
2827
+ const message = errorBody.error?.message || "Failed to fetch network logs";
2828
+ throw new Error(message);
2745
2829
  }
2746
- async getMetrics(runId, options) {
2830
+ /**
2831
+ * Get current user's scope
2832
+ */
2833
+ async getScope() {
2747
2834
  const baseUrl = await this.getBaseUrl();
2748
2835
  const headers = await this.getHeaders();
2749
- const params = new URLSearchParams();
2750
- if (options?.since !== void 0) {
2751
- params.set("since", String(options.since));
2836
+ const client = initClient(scopeContract, {
2837
+ baseUrl,
2838
+ baseHeaders: headers,
2839
+ jsonQuery: true
2840
+ });
2841
+ const result = await client.get();
2842
+ if (result.status === 200) {
2843
+ return result.body;
2752
2844
  }
2753
- if (options?.limit !== void 0) {
2754
- params.set("limit", String(options.limit));
2845
+ const errorBody = result.body;
2846
+ const message = errorBody.error?.message || "Failed to get scope";
2847
+ throw new Error(message);
2848
+ }
2849
+ /**
2850
+ * Create user's scope
2851
+ */
2852
+ async createScope(body) {
2853
+ const baseUrl = await this.getBaseUrl();
2854
+ const headers = await this.getHeaders();
2855
+ const client = initClient(scopeContract, {
2856
+ baseUrl,
2857
+ baseHeaders: headers,
2858
+ jsonQuery: true
2859
+ });
2860
+ const result = await client.create({ body });
2861
+ if (result.status === 201) {
2862
+ return result.body;
2755
2863
  }
2756
- if (options?.order !== void 0) {
2757
- params.set("order", options.order);
2864
+ const errorBody = result.body;
2865
+ const message = errorBody.error?.message || "Failed to create scope";
2866
+ throw new Error(message);
2867
+ }
2868
+ /**
2869
+ * Update user's scope slug
2870
+ */
2871
+ async updateScope(body) {
2872
+ const baseUrl = await this.getBaseUrl();
2873
+ const headers = await this.getHeaders();
2874
+ const client = initClient(scopeContract, {
2875
+ baseUrl,
2876
+ baseHeaders: headers,
2877
+ jsonQuery: true
2878
+ });
2879
+ const result = await client.update({ body });
2880
+ if (result.status === 200) {
2881
+ return result.body;
2758
2882
  }
2759
- const queryString = params.toString();
2760
- const url = `${baseUrl}/api/agent/runs/${runId}/telemetry/metrics${queryString ? `?${queryString}` : ""}`;
2761
- const response = await fetch(url, {
2762
- method: "GET",
2763
- headers
2883
+ const errorBody = result.body;
2884
+ const message = errorBody.error?.message || "Failed to update scope";
2885
+ throw new Error(message);
2886
+ }
2887
+ /**
2888
+ * Get session by ID
2889
+ * Used by run continue to fetch session info including secretNames
2890
+ */
2891
+ async getSession(sessionId) {
2892
+ const baseUrl = await this.getBaseUrl();
2893
+ const headers = await this.getHeaders();
2894
+ const client = initClient(sessionsByIdContract, {
2895
+ baseUrl,
2896
+ baseHeaders: headers,
2897
+ jsonQuery: true
2764
2898
  });
2765
- if (!response.ok) {
2766
- const error = await response.json();
2767
- throw new Error(error.error?.message || "Failed to fetch metrics");
2899
+ const result = await client.getById({
2900
+ params: { id: sessionId }
2901
+ });
2902
+ if (result.status === 200) {
2903
+ return result.body;
2768
2904
  }
2769
- return await response.json();
2905
+ const errorBody = result.body;
2906
+ const message = errorBody.error?.message || `Session not found: ${sessionId}`;
2907
+ throw new Error(message);
2770
2908
  }
2771
- async getAgentEvents(runId, options) {
2909
+ /**
2910
+ * Get checkpoint by ID
2911
+ * Used by run resume to fetch checkpoint info including secretNames
2912
+ */
2913
+ async getCheckpoint(checkpointId) {
2914
+ const baseUrl = await this.getBaseUrl();
2915
+ const headers = await this.getHeaders();
2916
+ const client = initClient(checkpointsByIdContract, {
2917
+ baseUrl,
2918
+ baseHeaders: headers,
2919
+ jsonQuery: true
2920
+ });
2921
+ const result = await client.getById({
2922
+ params: { id: checkpointId }
2923
+ });
2924
+ if (result.status === 200) {
2925
+ return result.body;
2926
+ }
2927
+ const errorBody = result.body;
2928
+ const message = errorBody.error?.message || `Checkpoint not found: ${checkpointId}`;
2929
+ throw new Error(message);
2930
+ }
2931
+ /**
2932
+ * Prepare storage for direct S3 upload
2933
+ */
2934
+ async prepareStorage(body) {
2935
+ const baseUrl = await this.getBaseUrl();
2936
+ const headers = await this.getHeaders();
2937
+ const client = initClient(storagesPrepareContract, {
2938
+ baseUrl,
2939
+ baseHeaders: headers,
2940
+ jsonQuery: true
2941
+ });
2942
+ const result = await client.prepare({ body });
2943
+ if (result.status === 200) {
2944
+ return result.body;
2945
+ }
2946
+ const errorBody = result.body;
2947
+ const message = errorBody.error?.message || "Failed to prepare storage";
2948
+ throw new Error(message);
2949
+ }
2950
+ /**
2951
+ * Commit storage after S3 upload
2952
+ */
2953
+ async commitStorage(body) {
2954
+ const baseUrl = await this.getBaseUrl();
2955
+ const headers = await this.getHeaders();
2956
+ const client = initClient(storagesCommitContract, {
2957
+ baseUrl,
2958
+ baseHeaders: headers,
2959
+ jsonQuery: true
2960
+ });
2961
+ const result = await client.commit({ body });
2962
+ if (result.status === 200) {
2963
+ return result.body;
2964
+ }
2965
+ const errorBody = result.body;
2966
+ const message = errorBody.error?.message || "Failed to commit storage";
2967
+ throw new Error(message);
2968
+ }
2969
+ /**
2970
+ * Get download URL for storage (volume or artifact)
2971
+ */
2972
+ async getStorageDownload(query) {
2973
+ const baseUrl = await this.getBaseUrl();
2974
+ const headers = await this.getHeaders();
2975
+ const client = initClient(storagesDownloadContract, {
2976
+ baseUrl,
2977
+ baseHeaders: headers,
2978
+ jsonQuery: true
2979
+ });
2980
+ const result = await client.download({
2981
+ query: {
2982
+ name: query.name,
2983
+ type: query.type,
2984
+ version: query.version
2985
+ }
2986
+ });
2987
+ if (result.status === 200) {
2988
+ return result.body;
2989
+ }
2990
+ const errorBody = result.body;
2991
+ const message = errorBody.error?.message || `Storage "${query.name}" not found`;
2992
+ throw new Error(message);
2993
+ }
2994
+ /**
2995
+ * List storages (volumes or artifacts)
2996
+ */
2997
+ async listStorages(query) {
2998
+ const baseUrl = await this.getBaseUrl();
2999
+ const headers = await this.getHeaders();
3000
+ const client = initClient(storagesListContract, {
3001
+ baseUrl,
3002
+ baseHeaders: headers,
3003
+ jsonQuery: true
3004
+ });
3005
+ const result = await client.list({ query });
3006
+ if (result.status === 200) {
3007
+ return result.body;
3008
+ }
3009
+ const errorBody = result.body;
3010
+ const message = errorBody.error?.message || `Failed to list ${query.type}s`;
3011
+ throw new Error(message);
3012
+ }
3013
+ /**
3014
+ * Deploy schedule (create or update)
3015
+ */
3016
+ async deploySchedule(body) {
3017
+ const baseUrl = await this.getBaseUrl();
3018
+ const headers = await this.getHeaders();
3019
+ const client = initClient(schedulesMainContract, {
3020
+ baseUrl,
3021
+ baseHeaders: headers,
3022
+ jsonQuery: true
3023
+ });
3024
+ const result = await client.deploy({ body });
3025
+ if (result.status === 200 || result.status === 201) {
3026
+ return result.body;
3027
+ }
3028
+ const errorBody = result.body;
3029
+ const message = errorBody.error?.message || "Failed to deploy schedule";
3030
+ throw new Error(message);
3031
+ }
3032
+ /**
3033
+ * List all schedules
3034
+ */
3035
+ async listSchedules() {
3036
+ const baseUrl = await this.getBaseUrl();
3037
+ const headers = await this.getHeaders();
3038
+ const client = initClient(schedulesMainContract, {
3039
+ baseUrl,
3040
+ baseHeaders: headers,
3041
+ jsonQuery: true
3042
+ });
3043
+ const result = await client.list();
3044
+ if (result.status === 200) {
3045
+ return result.body;
3046
+ }
3047
+ const errorBody = result.body;
3048
+ const message = errorBody.error?.message || "Failed to list schedules";
3049
+ throw new Error(message);
3050
+ }
3051
+ /**
3052
+ * Get schedule by name
3053
+ */
3054
+ async getScheduleByName(params) {
3055
+ const baseUrl = await this.getBaseUrl();
3056
+ const headers = await this.getHeaders();
3057
+ const client = initClient(schedulesByNameContract, {
3058
+ baseUrl,
3059
+ baseHeaders: headers,
3060
+ jsonQuery: true
3061
+ });
3062
+ const result = await client.getByName({
3063
+ params: { name: params.name },
3064
+ query: { composeId: params.composeId }
3065
+ });
3066
+ if (result.status === 200) {
3067
+ return result.body;
3068
+ }
3069
+ const errorBody = result.body;
3070
+ const message = errorBody.error?.message || `Schedule "${params.name}" not found`;
3071
+ throw new Error(message);
3072
+ }
3073
+ /**
3074
+ * Delete schedule by name
3075
+ */
3076
+ async deleteSchedule(params) {
3077
+ const baseUrl = await this.getBaseUrl();
3078
+ const headers = await this.getHeaders();
3079
+ const client = initClient(schedulesByNameContract, {
3080
+ baseUrl,
3081
+ baseHeaders: headers,
3082
+ jsonQuery: true
3083
+ });
3084
+ const result = await client.delete({
3085
+ params: { name: params.name },
3086
+ query: { composeId: params.composeId }
3087
+ });
3088
+ if (result.status === 204) {
3089
+ return;
3090
+ }
3091
+ const errorBody = result.body;
3092
+ const message = errorBody.error?.message || `Schedule "${params.name}" not found on remote`;
3093
+ throw new Error(message);
3094
+ }
3095
+ /**
3096
+ * Enable schedule
3097
+ */
3098
+ async enableSchedule(params) {
3099
+ const baseUrl = await this.getBaseUrl();
3100
+ const headers = await this.getHeaders();
3101
+ const client = initClient(schedulesEnableContract, {
3102
+ baseUrl,
3103
+ baseHeaders: headers,
3104
+ jsonQuery: true
3105
+ });
3106
+ const result = await client.enable({
3107
+ params: { name: params.name },
3108
+ body: { composeId: params.composeId }
3109
+ });
3110
+ if (result.status === 200) {
3111
+ return result.body;
3112
+ }
3113
+ const errorBody = result.body;
3114
+ const message = errorBody.error?.message || `Failed to enable schedule "${params.name}"`;
3115
+ throw new Error(message);
3116
+ }
3117
+ /**
3118
+ * Disable schedule
3119
+ */
3120
+ async disableSchedule(params) {
2772
3121
  const baseUrl = await this.getBaseUrl();
2773
3122
  const headers = await this.getHeaders();
2774
- const params = new URLSearchParams();
2775
- if (options?.since !== void 0) {
2776
- params.set("since", String(options.since));
2777
- }
2778
- if (options?.limit !== void 0) {
2779
- params.set("limit", String(options.limit));
2780
- }
2781
- if (options?.order !== void 0) {
2782
- params.set("order", options.order);
2783
- }
2784
- const queryString = params.toString();
2785
- const url = `${baseUrl}/api/agent/runs/${runId}/telemetry/agent${queryString ? `?${queryString}` : ""}`;
2786
- const response = await fetch(url, {
2787
- method: "GET",
2788
- headers
3123
+ const client = initClient(schedulesEnableContract, {
3124
+ baseUrl,
3125
+ baseHeaders: headers,
3126
+ jsonQuery: true
2789
3127
  });
2790
- if (!response.ok) {
2791
- const error = await response.json();
2792
- throw new Error(error.error?.message || "Failed to fetch agent events");
3128
+ const result = await client.disable({
3129
+ params: { name: params.name },
3130
+ body: { composeId: params.composeId }
3131
+ });
3132
+ if (result.status === 200) {
3133
+ return result.body;
2793
3134
  }
2794
- return await response.json();
3135
+ const errorBody = result.body;
3136
+ const message = errorBody.error?.message || `Failed to disable schedule "${params.name}"`;
3137
+ throw new Error(message);
2795
3138
  }
2796
- async getNetworkLogs(runId, options) {
3139
+ /**
3140
+ * List recent runs for a schedule
3141
+ */
3142
+ async listScheduleRuns(params) {
2797
3143
  const baseUrl = await this.getBaseUrl();
2798
3144
  const headers = await this.getHeaders();
2799
- const params = new URLSearchParams();
2800
- if (options?.since !== void 0) {
2801
- params.set("since", String(options.since));
2802
- }
2803
- if (options?.limit !== void 0) {
2804
- params.set("limit", String(options.limit));
2805
- }
2806
- if (options?.order !== void 0) {
2807
- params.set("order", options.order);
2808
- }
2809
- const queryString = params.toString();
2810
- const url = `${baseUrl}/api/agent/runs/${runId}/telemetry/network${queryString ? `?${queryString}` : ""}`;
2811
- const response = await fetch(url, {
2812
- method: "GET",
2813
- headers
3145
+ const client = initClient(scheduleRunsContract, {
3146
+ baseUrl,
3147
+ baseHeaders: headers,
3148
+ jsonQuery: true
2814
3149
  });
2815
- if (!response.ok) {
2816
- const error = await response.json();
2817
- throw new Error(error.error?.message || "Failed to fetch network logs");
3150
+ const result = await client.listRuns({
3151
+ params: { name: params.name },
3152
+ query: {
3153
+ composeId: params.composeId,
3154
+ limit: params.limit ?? 5
3155
+ }
3156
+ });
3157
+ if (result.status === 200) {
3158
+ return result.body;
2818
3159
  }
2819
- return await response.json();
3160
+ const errorBody = result.body;
3161
+ const message = errorBody.error?.message || `Failed to list runs for schedule "${params.name}"`;
3162
+ throw new Error(message);
2820
3163
  }
2821
3164
  /**
2822
- * Get current user's scope
3165
+ * List public agents
2823
3166
  */
2824
- async getScope() {
3167
+ async listPublicAgents(query) {
2825
3168
  const baseUrl = await this.getBaseUrl();
2826
3169
  const headers = await this.getHeaders();
2827
- const response = await fetch(`${baseUrl}/api/scope`, {
2828
- method: "GET",
2829
- headers
3170
+ const client = initClient(publicAgentsListContract, {
3171
+ baseUrl,
3172
+ baseHeaders: headers,
3173
+ jsonQuery: true
2830
3174
  });
2831
- if (!response.ok) {
2832
- const error = await response.json();
2833
- throw new Error(error.error?.message || "Failed to get scope");
3175
+ const result = await client.list({ query: query ?? {} });
3176
+ if (result.status === 200) {
3177
+ return result.body;
2834
3178
  }
2835
- return await response.json();
3179
+ const errorBody = result.body;
3180
+ const message = errorBody.error?.message || "Failed to list agents";
3181
+ throw new Error(message);
2836
3182
  }
2837
3183
  /**
2838
- * Create user's scope
3184
+ * List public artifacts
2839
3185
  */
2840
- async createScope(body) {
3186
+ async listPublicArtifacts(query) {
2841
3187
  const baseUrl = await this.getBaseUrl();
2842
3188
  const headers = await this.getHeaders();
2843
- const response = await fetch(`${baseUrl}/api/scope`, {
2844
- method: "POST",
2845
- headers,
2846
- body: JSON.stringify(body)
3189
+ const client = initClient(publicArtifactsListContract, {
3190
+ baseUrl,
3191
+ baseHeaders: headers,
3192
+ jsonQuery: true
2847
3193
  });
2848
- if (!response.ok) {
2849
- const error = await response.json();
2850
- throw new Error(error.error?.message || "Failed to create scope");
3194
+ const result = await client.list({ query: query ?? {} });
3195
+ if (result.status === 200) {
3196
+ return result.body;
2851
3197
  }
2852
- return await response.json();
3198
+ const errorBody = result.body;
3199
+ const message = errorBody.error?.message || "Failed to list artifacts";
3200
+ throw new Error(message);
2853
3201
  }
2854
3202
  /**
2855
- * Update user's scope slug
3203
+ * Get public artifact by ID
2856
3204
  */
2857
- async updateScope(body) {
3205
+ async getPublicArtifact(id) {
2858
3206
  const baseUrl = await this.getBaseUrl();
2859
3207
  const headers = await this.getHeaders();
2860
- const response = await fetch(`${baseUrl}/api/scope`, {
2861
- method: "PUT",
2862
- headers,
2863
- body: JSON.stringify(body)
3208
+ const client = initClient(publicArtifactByIdContract, {
3209
+ baseUrl,
3210
+ baseHeaders: headers,
3211
+ jsonQuery: true
2864
3212
  });
2865
- if (!response.ok) {
2866
- const error = await response.json();
2867
- throw new Error(error.error?.message || "Failed to update scope");
3213
+ const result = await client.get({ params: { id } });
3214
+ if (result.status === 200) {
3215
+ return result.body;
2868
3216
  }
2869
- return await response.json();
3217
+ const errorBody = result.body;
3218
+ const message = errorBody.error?.message || `Artifact "${id}" not found`;
3219
+ throw new Error(message);
2870
3220
  }
2871
3221
  /**
2872
- * Get session by ID
2873
- * Used by run continue to fetch session info including secretNames
3222
+ * List public volumes
2874
3223
  */
2875
- async getSession(sessionId) {
3224
+ async listPublicVolumes(query) {
2876
3225
  const baseUrl = await this.getBaseUrl();
2877
3226
  const headers = await this.getHeaders();
2878
- const response = await fetch(`${baseUrl}/api/agent/sessions/${sessionId}`, {
2879
- method: "GET",
2880
- headers
3227
+ const client = initClient(publicVolumesListContract, {
3228
+ baseUrl,
3229
+ baseHeaders: headers,
3230
+ jsonQuery: true
2881
3231
  });
2882
- if (!response.ok) {
2883
- const error = await response.json();
2884
- throw new Error(
2885
- error.error?.message || `Session not found: ${sessionId}`
2886
- );
3232
+ const result = await client.list({ query: query ?? {} });
3233
+ if (result.status === 200) {
3234
+ return result.body;
2887
3235
  }
2888
- return await response.json();
3236
+ const errorBody = result.body;
3237
+ const message = errorBody.error?.message || "Failed to list volumes";
3238
+ throw new Error(message);
2889
3239
  }
2890
3240
  /**
2891
- * Get checkpoint by ID
2892
- * Used by run resume to fetch checkpoint info including secretNames
3241
+ * Get public volume by ID
2893
3242
  */
2894
- async getCheckpoint(checkpointId) {
3243
+ async getPublicVolume(id) {
2895
3244
  const baseUrl = await this.getBaseUrl();
2896
3245
  const headers = await this.getHeaders();
2897
- const response = await fetch(
2898
- `${baseUrl}/api/agent/checkpoints/${checkpointId}`,
2899
- {
2900
- method: "GET",
2901
- headers
2902
- }
2903
- );
2904
- if (!response.ok) {
2905
- const error = await response.json();
2906
- throw new Error(
2907
- error.error?.message || `Checkpoint not found: ${checkpointId}`
2908
- );
3246
+ const client = initClient(publicVolumeByIdContract, {
3247
+ baseUrl,
3248
+ baseHeaders: headers,
3249
+ jsonQuery: true
3250
+ });
3251
+ const result = await client.get({ params: { id } });
3252
+ if (result.status === 200) {
3253
+ return result.body;
2909
3254
  }
2910
- return await response.json();
3255
+ const errorBody = result.body;
3256
+ const message = errorBody.error?.message || `Volume "${id}" not found`;
3257
+ throw new Error(message);
2911
3258
  }
2912
3259
  /**
2913
3260
  * Generic GET request
@@ -3549,34 +3896,20 @@ async function directUpload(storageName, storageType, cwd, options) {
3549
3896
  onProgress?.("Computing file hashes...");
3550
3897
  const fileEntries = await collectFileMetadata(cwd, files, onProgress);
3551
3898
  onProgress?.("Preparing upload...");
3552
- const prepareResponse = await apiClient.post("/api/storages/prepare", {
3553
- body: JSON.stringify({
3554
- storageName,
3555
- storageType,
3556
- files: fileEntries,
3557
- force
3558
- })
3899
+ const prepareResult = await apiClient.prepareStorage({
3900
+ storageName,
3901
+ storageType,
3902
+ files: fileEntries,
3903
+ force
3559
3904
  });
3560
- if (!prepareResponse.ok) {
3561
- const error = await prepareResponse.json();
3562
- throw new Error(error.error?.message || "Prepare failed");
3563
- }
3564
- const prepareResult = await prepareResponse.json();
3565
3905
  if (prepareResult.existing) {
3566
3906
  onProgress?.("Version exists, updating HEAD...");
3567
- const commitResponse2 = await apiClient.post("/api/storages/commit", {
3568
- body: JSON.stringify({
3569
- storageName,
3570
- storageType,
3571
- versionId: prepareResult.versionId,
3572
- files: fileEntries
3573
- })
3907
+ const commitResult2 = await apiClient.commitStorage({
3908
+ storageName,
3909
+ storageType,
3910
+ versionId: prepareResult.versionId,
3911
+ files: fileEntries
3574
3912
  });
3575
- if (!commitResponse2.ok) {
3576
- const error = await commitResponse2.json();
3577
- throw new Error(error.error?.message || "Commit failed");
3578
- }
3579
- const commitResult2 = await commitResponse2.json();
3580
3913
  return {
3581
3914
  versionId: commitResult2.versionId,
3582
3915
  size: commitResult2.size,
@@ -3609,19 +3942,12 @@ async function directUpload(storageName, storageType, cwd, options) {
3609
3942
  "application/json"
3610
3943
  );
3611
3944
  onProgress?.("Committing...");
3612
- const commitResponse = await apiClient.post("/api/storages/commit", {
3613
- body: JSON.stringify({
3614
- storageName,
3615
- storageType,
3616
- versionId: prepareResult.versionId,
3617
- files: fileEntries
3618
- })
3945
+ const commitResult = await apiClient.commitStorage({
3946
+ storageName,
3947
+ storageType,
3948
+ versionId: prepareResult.versionId,
3949
+ files: fileEntries
3619
3950
  });
3620
- if (!commitResponse.ok) {
3621
- const error = await commitResponse.json();
3622
- throw new Error(error.error?.message || "Commit failed");
3623
- }
3624
- const commitResult = await commitResponse.json();
3625
3951
  return {
3626
3952
  versionId: commitResult.versionId,
3627
3953
  size: commitResult.size,
@@ -5415,39 +5741,21 @@ var pullCommand = new Command5().name("pull").description("Pull cloud files to l
5415
5741
  console.log(`Pulling volume: ${config.name}`);
5416
5742
  }
5417
5743
  console.log(chalk9.dim("Getting download URL..."));
5418
- let url = `/api/storages/download?name=${encodeURIComponent(config.name)}&type=volume`;
5419
- if (versionId) {
5420
- const quotedVersion = JSON.stringify(versionId);
5421
- url += `&version=${encodeURIComponent(quotedVersion)}`;
5422
- }
5423
- const response = await apiClient.get(url);
5424
- if (!response.ok) {
5425
- if (response.status === 404) {
5426
- console.error(chalk9.red(`\u2717 Volume "${config.name}" not found`));
5427
- console.error(
5428
- chalk9.dim(
5429
- " Make sure the volume name is correct in .vm0/storage.yaml"
5430
- )
5431
- );
5432
- console.error(
5433
- chalk9.dim(" Or push the volume first with: vm0 volume push")
5434
- );
5435
- } else {
5436
- const error = await response.json();
5437
- throw new Error(error.error?.message || "Download failed");
5438
- }
5439
- process.exit(1);
5440
- }
5441
- const downloadInfo = await response.json();
5442
- if (downloadInfo.empty) {
5744
+ const downloadInfo = await apiClient.getStorageDownload({
5745
+ name: config.name,
5746
+ type: "volume",
5747
+ version: versionId
5748
+ });
5749
+ if ("empty" in downloadInfo) {
5443
5750
  await handleEmptyStorageResponse(cwd);
5444
5751
  return;
5445
5752
  }
5446
- if (!downloadInfo.url) {
5753
+ const downloadUrl = downloadInfo.url;
5754
+ if (!downloadUrl) {
5447
5755
  throw new Error("No download URL returned");
5448
5756
  }
5449
5757
  console.log(chalk9.dim("Downloading from S3..."));
5450
- const s3Response = await fetch(downloadInfo.url);
5758
+ const s3Response = await fetch(downloadUrl);
5451
5759
  if (!s3Response.ok) {
5452
5760
  throw new Error(`S3 download failed: ${s3Response.status}`);
5453
5761
  }
@@ -5519,21 +5827,12 @@ var statusCommand = new Command6().name("status").description("Show status of cl
5519
5827
  process.exit(1);
5520
5828
  }
5521
5829
  console.log(`Checking volume: ${config.name}`);
5522
- const url = `/api/storages/download?name=${encodeURIComponent(config.name)}&type=volume`;
5523
- const response = await apiClient.get(url);
5524
- if (!response.ok) {
5525
- if (response.status === 404) {
5526
- console.error(chalk10.red("\u2717 Not found on remote"));
5527
- console.error(chalk10.dim(" Run: vm0 volume push"));
5528
- } else {
5529
- const error = await response.json();
5530
- throw new Error(error.error?.message || "Status check failed");
5531
- }
5532
- process.exit(1);
5533
- }
5534
- const info = await response.json();
5830
+ const info = await apiClient.getStorageDownload({
5831
+ name: config.name,
5832
+ type: "volume"
5833
+ });
5535
5834
  const shortVersion = info.versionId.slice(0, 8);
5536
- if (info.empty) {
5835
+ if ("empty" in info) {
5537
5836
  console.log(chalk10.green("\u2713 Found (empty)"));
5538
5837
  console.log(chalk10.dim(` Version: ${shortVersion}`));
5539
5838
  } else {
@@ -5543,12 +5842,17 @@ var statusCommand = new Command6().name("status").description("Show status of cl
5543
5842
  console.log(chalk10.dim(` Size: ${formatBytes4(info.size)}`));
5544
5843
  }
5545
5844
  } catch (error) {
5546
- console.error(chalk10.red("\u2717 Status check failed"));
5547
- if (error instanceof Error) {
5548
- if (error.message.includes("Not authenticated")) {
5549
- console.error(chalk10.dim(" Run: vm0 auth login"));
5550
- } else {
5551
- console.error(chalk10.dim(` ${error.message}`));
5845
+ if (error instanceof Error && error.message.includes("not found")) {
5846
+ console.error(chalk10.red("\u2717 Not found on remote"));
5847
+ console.error(chalk10.dim(" Run: vm0 volume push"));
5848
+ } else {
5849
+ console.error(chalk10.red("\u2717 Status check failed"));
5850
+ if (error instanceof Error) {
5851
+ if (error.message.includes("Not authenticated")) {
5852
+ console.error(chalk10.dim(" Run: vm0 auth login"));
5853
+ } else {
5854
+ console.error(chalk10.dim(` ${error.message}`));
5855
+ }
5552
5856
  }
5553
5857
  }
5554
5858
  process.exit(1);
@@ -5560,13 +5864,7 @@ import { Command as Command7 } from "commander";
5560
5864
  import chalk11 from "chalk";
5561
5865
  var listCommand = new Command7().name("list").alias("ls").description("List all remote volumes").action(async () => {
5562
5866
  try {
5563
- const url = "/api/storages/list?type=volume";
5564
- const response = await apiClient.get(url);
5565
- if (!response.ok) {
5566
- const error = await response.json();
5567
- throw new Error(error.error?.message || "List failed");
5568
- }
5569
- const items = await response.json();
5867
+ const items = await apiClient.listStorages({ type: "volume" });
5570
5868
  if (items.length === 0) {
5571
5869
  console.log(chalk11.dim("No volumes found"));
5572
5870
  console.log(
@@ -5628,25 +5926,14 @@ async function cloneStorage(name, type, destination, options = {}) {
5628
5926
  throw new Error(`Directory "${destination}" already exists`);
5629
5927
  }
5630
5928
  console.log(chalk12.dim(`Checking remote ${typeLabel}...`));
5631
- let url = `/api/storages/download?name=${encodeURIComponent(name)}&type=${type}`;
5632
- if (options.version) {
5633
- const quotedVersion = JSON.stringify(options.version);
5634
- url += `&version=${encodeURIComponent(quotedVersion)}`;
5635
- }
5636
- const response = await apiClient.get(url);
5637
- if (!response.ok) {
5638
- if (response.status === 404) {
5639
- throw new Error(
5640
- `${typeLabel.charAt(0).toUpperCase() + typeLabel.slice(1)} "${name}" not found`
5641
- );
5642
- }
5643
- const error = await response.json();
5644
- throw new Error(error.error?.message || "Clone failed");
5645
- }
5646
- const downloadInfo = await response.json();
5929
+ const downloadInfo = await apiClient.getStorageDownload({
5930
+ name,
5931
+ type,
5932
+ version: options.version
5933
+ });
5647
5934
  console.log(chalk12.dim(`Creating directory: ${destination}/`));
5648
5935
  await fs7.promises.mkdir(destination, { recursive: true });
5649
- if (downloadInfo.empty) {
5936
+ if ("empty" in downloadInfo) {
5650
5937
  await writeStorageConfig(name, destination, type);
5651
5938
  console.log(chalk12.green(`\u2713 Cloned empty ${typeLabel}: ${name}`));
5652
5939
  console.log(chalk12.dim(`\u2713 Initialized .vm0/storage.yaml`));
@@ -5657,11 +5944,12 @@ async function cloneStorage(name, type, destination, options = {}) {
5657
5944
  versionId: downloadInfo.versionId
5658
5945
  };
5659
5946
  }
5660
- if (!downloadInfo.url) {
5947
+ const downloadUrl = downloadInfo.url;
5948
+ if (!downloadUrl) {
5661
5949
  throw new Error("No download URL returned");
5662
5950
  }
5663
5951
  console.log(chalk12.dim("Downloading from S3..."));
5664
- const s3Response = await fetch(downloadInfo.url);
5952
+ const s3Response = await fetch(downloadUrl);
5665
5953
  if (!s3Response.ok) {
5666
5954
  await fs7.promises.rm(destination, { recursive: true, force: true });
5667
5955
  throw new Error(`S3 download failed: ${s3Response.status}`);
@@ -5910,39 +6198,21 @@ var pullCommand2 = new Command12().name("pull").description("Pull cloud artifact
5910
6198
  console.log(`Pulling artifact: ${config.name}`);
5911
6199
  }
5912
6200
  console.log(chalk16.dim("Getting download URL..."));
5913
- let url = `/api/storages/download?name=${encodeURIComponent(config.name)}&type=artifact`;
5914
- if (versionId) {
5915
- const quotedVersion = JSON.stringify(versionId);
5916
- url += `&version=${encodeURIComponent(quotedVersion)}`;
5917
- }
5918
- const response = await apiClient.get(url);
5919
- if (!response.ok) {
5920
- if (response.status === 404) {
5921
- console.error(chalk16.red(`\u2717 Artifact "${config.name}" not found`));
5922
- console.error(
5923
- chalk16.dim(
5924
- " Make sure the artifact name is correct in .vm0/storage.yaml"
5925
- )
5926
- );
5927
- console.error(
5928
- chalk16.dim(" Or push the artifact first with: vm0 artifact push")
5929
- );
5930
- } else {
5931
- const error = await response.json();
5932
- throw new Error(error.error?.message || "Download failed");
5933
- }
5934
- process.exit(1);
5935
- }
5936
- const downloadInfo = await response.json();
5937
- if (downloadInfo.empty) {
6201
+ const downloadInfo = await apiClient.getStorageDownload({
6202
+ name: config.name,
6203
+ type: "artifact",
6204
+ version: versionId
6205
+ });
6206
+ if ("empty" in downloadInfo) {
5938
6207
  await handleEmptyStorageResponse(cwd);
5939
6208
  return;
5940
6209
  }
5941
- if (!downloadInfo.url) {
6210
+ const downloadUrl = downloadInfo.url;
6211
+ if (!downloadUrl) {
5942
6212
  throw new Error("No download URL returned");
5943
6213
  }
5944
6214
  console.log(chalk16.dim("Downloading from S3..."));
5945
- const s3Response = await fetch(downloadInfo.url);
6215
+ const s3Response = await fetch(downloadUrl);
5946
6216
  if (!s3Response.ok) {
5947
6217
  throw new Error(`S3 download failed: ${s3Response.status}`);
5948
6218
  }
@@ -6010,21 +6280,12 @@ var statusCommand2 = new Command13().name("status").description("Show status of
6010
6280
  process.exit(1);
6011
6281
  }
6012
6282
  console.log(`Checking artifact: ${config.name}`);
6013
- const url = `/api/storages/download?name=${encodeURIComponent(config.name)}&type=artifact`;
6014
- const response = await apiClient.get(url);
6015
- if (!response.ok) {
6016
- if (response.status === 404) {
6017
- console.error(chalk17.red("\u2717 Not found on remote"));
6018
- console.error(chalk17.dim(" Run: vm0 artifact push"));
6019
- } else {
6020
- const error = await response.json();
6021
- throw new Error(error.error?.message || "Status check failed");
6022
- }
6023
- process.exit(1);
6024
- }
6025
- const info = await response.json();
6283
+ const info = await apiClient.getStorageDownload({
6284
+ name: config.name,
6285
+ type: "artifact"
6286
+ });
6026
6287
  const shortVersion = info.versionId.slice(0, 8);
6027
- if (info.empty) {
6288
+ if ("empty" in info) {
6028
6289
  console.log(chalk17.green("\u2713 Found (empty)"));
6029
6290
  console.log(chalk17.dim(` Version: ${shortVersion}`));
6030
6291
  } else {
@@ -6034,9 +6295,14 @@ var statusCommand2 = new Command13().name("status").description("Show status of
6034
6295
  console.log(chalk17.dim(` Size: ${formatBytes7(info.size)}`));
6035
6296
  }
6036
6297
  } catch (error) {
6037
- console.error(chalk17.red("\u2717 Status check failed"));
6038
- if (error instanceof Error) {
6039
- console.error(chalk17.dim(` ${error.message}`));
6298
+ if (error instanceof Error && error.message.includes("not found")) {
6299
+ console.error(chalk17.red("\u2717 Not found on remote"));
6300
+ console.error(chalk17.dim(" Run: vm0 artifact push"));
6301
+ } else {
6302
+ console.error(chalk17.red("\u2717 Status check failed"));
6303
+ if (error instanceof Error) {
6304
+ console.error(chalk17.dim(` ${error.message}`));
6305
+ }
6040
6306
  }
6041
6307
  process.exit(1);
6042
6308
  }
@@ -6047,13 +6313,7 @@ import { Command as Command14 } from "commander";
6047
6313
  import chalk18 from "chalk";
6048
6314
  var listCommand2 = new Command14().name("list").alias("ls").description("List all remote artifacts").action(async () => {
6049
6315
  try {
6050
- const url = "/api/storages/list?type=artifact";
6051
- const response = await apiClient.get(url);
6052
- if (!response.ok) {
6053
- const error = await response.json();
6054
- throw new Error(error.error?.message || "List failed");
6055
- }
6056
- const items = await response.json();
6316
+ const items = await apiClient.listStorages({ type: "artifact" });
6057
6317
  if (items.length === 0) {
6058
6318
  console.log(chalk18.dim("No artifacts found"));
6059
6319
  console.log(
@@ -6472,7 +6732,7 @@ async function autoPullArtifact(runOutput, artifactDir) {
6472
6732
  }
6473
6733
  var cookCmd = new Command17().name("cook").description("One-click agent preparation and execution from vm0.yaml");
6474
6734
  cookCmd.argument("[prompt]", "Prompt for the agent").option("-y, --yes", "Skip confirmation prompts").action(async (prompt, options) => {
6475
- const shouldExit = await checkAndUpgrade("5.6.0", prompt);
6735
+ const shouldExit = await checkAndUpgrade("5.7.2", prompt);
6476
6736
  if (shouldExit) {
6477
6737
  process.exit(0);
6478
6738
  }
@@ -8048,6 +8308,7 @@ import { stringify as stringifyYaml2 } from "yaml";
8048
8308
  import { existsSync as existsSync11, readFileSync as readFileSync2 } from "fs";
8049
8309
  import { parse as parseYaml6 } from "yaml";
8050
8310
  var CONFIG_FILE4 = "vm0.yaml";
8311
+ var SCHEDULE_FILE = "schedule.yaml";
8051
8312
  function loadAgentName() {
8052
8313
  if (!existsSync11(CONFIG_FILE4)) {
8053
8314
  return { agentName: null };
@@ -8064,6 +8325,28 @@ function loadAgentName() {
8064
8325
  };
8065
8326
  }
8066
8327
  }
8328
+ function loadScheduleName() {
8329
+ if (!existsSync11(SCHEDULE_FILE)) {
8330
+ return { scheduleName: null };
8331
+ }
8332
+ try {
8333
+ const content = readFileSync2(SCHEDULE_FILE, "utf8");
8334
+ const parsed = parseYaml6(content);
8335
+ if (!parsed?.schedules) {
8336
+ return {
8337
+ scheduleName: null,
8338
+ error: "No schedules defined in schedule.yaml"
8339
+ };
8340
+ }
8341
+ const scheduleNames = Object.keys(parsed.schedules);
8342
+ return { scheduleName: scheduleNames[0] || null };
8343
+ } catch (err) {
8344
+ return {
8345
+ scheduleName: null,
8346
+ error: err instanceof Error ? err.message : "Failed to parse schedule.yaml"
8347
+ };
8348
+ }
8349
+ }
8067
8350
  function formatRelativeTime2(dateStr) {
8068
8351
  if (!dateStr) return "-";
8069
8352
  const date = new Date(dateStr);
@@ -8216,7 +8499,7 @@ function toISODateTime(dateTimeStr) {
8216
8499
  }
8217
8500
 
8218
8501
  // src/commands/schedule/init.ts
8219
- var SCHEDULE_FILE = "schedule.yaml";
8502
+ var SCHEDULE_FILE2 = "schedule.yaml";
8220
8503
  var FREQUENCY_CHOICES = [
8221
8504
  { title: "Daily", value: "daily", description: "Run every day" },
8222
8505
  {
@@ -8279,7 +8562,7 @@ var initCommand4 = new Command27().name("init").description("Create a schedule.y
8279
8562
  );
8280
8563
  process.exit(1);
8281
8564
  }
8282
- if (existsSync12(SCHEDULE_FILE) && !options.force) {
8565
+ if (existsSync12(SCHEDULE_FILE2) && !options.force) {
8283
8566
  if (!isInteractive()) {
8284
8567
  console.error(chalk29.red("\u2717 schedule.yaml already exists"));
8285
8568
  console.error(chalk29.dim(" Use --force to overwrite"));
@@ -8514,8 +8797,8 @@ var initCommand4 = new Command27().name("init").description("Create a schedule.y
8514
8797
  if (secrets && Object.keys(secrets).length > 0) {
8515
8798
  scheduleYaml.schedules[scheduleName].run.secrets = secrets;
8516
8799
  }
8517
- writeFileSync(SCHEDULE_FILE, stringifyYaml2(scheduleYaml));
8518
- console.log(chalk29.green(`\u2713 Created ${SCHEDULE_FILE}`));
8800
+ writeFileSync(SCHEDULE_FILE2, stringifyYaml2(scheduleYaml));
8801
+ console.log(chalk29.green(`\u2713 Created ${SCHEDULE_FILE2}`));
8519
8802
  console.log(chalk29.dim(" Deploy with: vm0 schedule deploy"));
8520
8803
  } catch (error) {
8521
8804
  console.error(chalk29.red("\u2717 Failed to create schedule.yaml"));
@@ -8637,14 +8920,7 @@ var deployCommand = new Command28().name("deploy").description("Deploy a schedul
8637
8920
  artifactVersion: schedule.run.artifactVersion,
8638
8921
  volumeVersions: schedule.run.volumeVersions
8639
8922
  };
8640
- const response = await apiClient.post("/api/agent/schedules", {
8641
- body: JSON.stringify(body)
8642
- });
8643
- if (!response.ok) {
8644
- const error = await response.json();
8645
- throw new Error(error.error?.message || "Deploy failed");
8646
- }
8647
- const deployResult = await response.json();
8923
+ const deployResult = await apiClient.deploySchedule(body);
8648
8924
  if (deployResult.created) {
8649
8925
  console.log(
8650
8926
  chalk30.green(`\u2713 Created schedule ${chalk30.cyan(scheduleName)}`)
@@ -8691,12 +8967,7 @@ import { Command as Command29 } from "commander";
8691
8967
  import chalk31 from "chalk";
8692
8968
  var listCommand4 = new Command29().name("list").alias("ls").description("List all schedules").action(async () => {
8693
8969
  try {
8694
- const response = await apiClient.get("/api/agent/schedules");
8695
- if (!response.ok) {
8696
- const error = await response.json();
8697
- throw new Error(error.error?.message || "List failed");
8698
- }
8699
- const result = await response.json();
8970
+ const result = await apiClient.listSchedules();
8700
8971
  if (result.schedules.length === 0) {
8701
8972
  console.log(chalk31.dim("No schedules found"));
8702
8973
  console.log(
@@ -8785,12 +9056,33 @@ function formatRunStatus(status) {
8785
9056
  return status;
8786
9057
  }
8787
9058
  }
8788
- var statusCommand4 = new Command30().name("status").description("Show detailed status of a schedule").argument("<name>", "Schedule name").option(
9059
+ var statusCommand4 = new Command30().name("status").description("Show detailed status of a schedule").argument(
9060
+ "[name]",
9061
+ "Schedule name (auto-detected from schedule.yaml if omitted)"
9062
+ ).option(
8789
9063
  "-l, --limit <number>",
8790
9064
  "Number of recent runs to show (0 to hide)",
8791
9065
  "5"
8792
- ).action(async (name, options) => {
9066
+ ).action(async (nameArg, options) => {
8793
9067
  try {
9068
+ let name = nameArg;
9069
+ if (!name) {
9070
+ const scheduleResult = loadScheduleName();
9071
+ if (scheduleResult.error) {
9072
+ console.error(chalk32.red(`\u2717 ${scheduleResult.error}`));
9073
+ process.exit(1);
9074
+ }
9075
+ if (!scheduleResult.scheduleName) {
9076
+ console.error(chalk32.red("\u2717 Schedule name required"));
9077
+ console.error(
9078
+ chalk32.dim(
9079
+ " Provide name or run from directory with schedule.yaml"
9080
+ )
9081
+ );
9082
+ process.exit(1);
9083
+ }
9084
+ name = scheduleResult.scheduleName;
9085
+ }
8794
9086
  const result = loadAgentName();
8795
9087
  if (result.error) {
8796
9088
  console.error(chalk32.red(`\u2717 Invalid vm0.yaml: ${result.error}`));
@@ -8811,14 +9103,7 @@ var statusCommand4 = new Command30().name("status").description("Show detailed s
8811
9103
  console.error(chalk32.dim(" Make sure the agent is pushed first"));
8812
9104
  process.exit(1);
8813
9105
  }
8814
- const response = await apiClient.get(
8815
- `/api/agent/schedules/${encodeURIComponent(name)}?composeId=${encodeURIComponent(composeId)}`
8816
- );
8817
- if (!response.ok) {
8818
- const error = await response.json();
8819
- throw new Error(error.error?.message || "Failed to get schedule");
8820
- }
8821
- const schedule = await response.json();
9106
+ const schedule = await apiClient.getScheduleByName({ name, composeId });
8822
9107
  console.log();
8823
9108
  console.log(`Schedule: ${chalk32.cyan(schedule.name)}`);
8824
9109
  console.log(chalk32.dim("\u2501".repeat(50)));
@@ -8861,11 +9146,12 @@ var statusCommand4 = new Command30().name("status").description("Show detailed s
8861
9146
  100
8862
9147
  );
8863
9148
  if (limit > 0) {
8864
- const runsResponse = await apiClient.get(
8865
- `/api/agent/schedules/${encodeURIComponent(name)}/runs?composeId=${encodeURIComponent(composeId)}&limit=${limit}`
8866
- );
8867
- if (runsResponse.ok) {
8868
- const { runs } = await runsResponse.json();
9149
+ try {
9150
+ const { runs } = await apiClient.listScheduleRuns({
9151
+ name,
9152
+ composeId,
9153
+ limit
9154
+ });
8869
9155
  if (runs.length > 0) {
8870
9156
  console.log();
8871
9157
  console.log("Recent Runs:");
@@ -8881,7 +9167,7 @@ var statusCommand4 = new Command30().name("status").description("Show detailed s
8881
9167
  console.log(`${id} ${status} ${created}`);
8882
9168
  }
8883
9169
  }
8884
- } else {
9170
+ } catch {
8885
9171
  console.log();
8886
9172
  console.log(chalk32.dim("Recent Runs: (unable to fetch)"));
8887
9173
  }
@@ -8893,7 +9179,9 @@ var statusCommand4 = new Command30().name("status").description("Show detailed s
8893
9179
  if (error.message.includes("Not authenticated")) {
8894
9180
  console.error(chalk32.dim(" Run: vm0 auth login"));
8895
9181
  } else if (error.message.includes("not found") || error.message.includes("Not found")) {
8896
- console.error(chalk32.dim(` Schedule "${name}" not found`));
9182
+ console.error(
9183
+ chalk32.dim(` Schedule "${nameArg ?? "unknown"}" not found`)
9184
+ );
8897
9185
  } else {
8898
9186
  console.error(chalk32.dim(` ${error.message}`));
8899
9187
  }
@@ -8918,8 +9206,29 @@ async function confirm(message) {
8918
9206
  });
8919
9207
  });
8920
9208
  }
8921
- 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) => {
9209
+ var deleteCommand = new Command31().name("delete").alias("rm").description("Delete a schedule").argument(
9210
+ "[name]",
9211
+ "Schedule name (auto-detected from schedule.yaml if omitted)"
9212
+ ).option("-f, --force", "Skip confirmation prompt").action(async (nameArg, options) => {
9213
+ let name = nameArg;
8922
9214
  try {
9215
+ if (!name) {
9216
+ const scheduleResult = loadScheduleName();
9217
+ if (scheduleResult.error) {
9218
+ console.error(chalk33.red(`\u2717 ${scheduleResult.error}`));
9219
+ process.exit(1);
9220
+ }
9221
+ if (!scheduleResult.scheduleName) {
9222
+ console.error(chalk33.red("\u2717 Schedule name required"));
9223
+ console.error(
9224
+ chalk33.dim(
9225
+ " Provide name or run from directory with schedule.yaml"
9226
+ )
9227
+ );
9228
+ process.exit(1);
9229
+ }
9230
+ name = scheduleResult.scheduleName;
9231
+ }
8923
9232
  const result = loadAgentName();
8924
9233
  if (result.error) {
8925
9234
  console.error(chalk33.red(`\u2717 Invalid vm0.yaml: ${result.error}`));
@@ -8947,19 +9256,15 @@ var deleteCommand = new Command31().name("delete").alias("rm").description("Dele
8947
9256
  return;
8948
9257
  }
8949
9258
  }
8950
- const response = await apiClient.delete(
8951
- `/api/agent/schedules/${encodeURIComponent(name)}?composeId=${encodeURIComponent(composeId)}`
8952
- );
8953
- if (!response.ok) {
8954
- const error = await response.json();
8955
- throw new Error(error.error?.message || "Delete failed");
8956
- }
9259
+ await apiClient.deleteSchedule({ name, composeId });
8957
9260
  console.log(chalk33.green(`\u2713 Deleted schedule ${chalk33.cyan(name)}`));
8958
9261
  } catch (error) {
8959
9262
  console.error(chalk33.red("\u2717 Failed to delete schedule"));
8960
9263
  if (error instanceof Error) {
8961
9264
  if (error.message.includes("Not authenticated")) {
8962
9265
  console.error(chalk33.dim(" Run: vm0 auth login"));
9266
+ } else if (error.message.toLowerCase().includes("not found")) {
9267
+ console.error(chalk33.dim(` Schedule "${name}" not found`));
8963
9268
  } else {
8964
9269
  console.error(chalk33.dim(` ${error.message}`));
8965
9270
  }
@@ -8971,8 +9276,29 @@ var deleteCommand = new Command31().name("delete").alias("rm").description("Dele
8971
9276
  // src/commands/schedule/enable.ts
8972
9277
  import { Command as Command32 } from "commander";
8973
9278
  import chalk34 from "chalk";
8974
- var enableCommand = new Command32().name("enable").description("Enable a schedule").argument("<name>", "Schedule name to enable").action(async (name) => {
9279
+ var enableCommand = new Command32().name("enable").description("Enable a schedule").argument(
9280
+ "[name]",
9281
+ "Schedule name (auto-detected from schedule.yaml if omitted)"
9282
+ ).action(async (nameArg) => {
8975
9283
  try {
9284
+ let name = nameArg;
9285
+ if (!name) {
9286
+ const scheduleResult = loadScheduleName();
9287
+ if (scheduleResult.error) {
9288
+ console.error(chalk34.red(`\u2717 ${scheduleResult.error}`));
9289
+ process.exit(1);
9290
+ }
9291
+ if (!scheduleResult.scheduleName) {
9292
+ console.error(chalk34.red("\u2717 Schedule name required"));
9293
+ console.error(
9294
+ chalk34.dim(
9295
+ " Provide name or run from directory with schedule.yaml"
9296
+ )
9297
+ );
9298
+ process.exit(1);
9299
+ }
9300
+ name = scheduleResult.scheduleName;
9301
+ }
8976
9302
  const result = loadAgentName();
8977
9303
  if (result.error) {
8978
9304
  console.error(chalk34.red(`\u2717 Invalid vm0.yaml: ${result.error}`));
@@ -8993,14 +9319,7 @@ var enableCommand = new Command32().name("enable").description("Enable a schedul
8993
9319
  console.error(chalk34.dim(" Make sure the agent is pushed first"));
8994
9320
  process.exit(1);
8995
9321
  }
8996
- const response = await apiClient.post(
8997
- `/api/agent/schedules/${encodeURIComponent(name)}/enable`,
8998
- { body: JSON.stringify({ composeId }) }
8999
- );
9000
- if (!response.ok) {
9001
- const error = await response.json();
9002
- throw new Error(error.error?.message || "Enable failed");
9003
- }
9322
+ await apiClient.enableSchedule({ name, composeId });
9004
9323
  console.log(chalk34.green(`\u2713 Enabled schedule ${chalk34.cyan(name)}`));
9005
9324
  } catch (error) {
9006
9325
  console.error(chalk34.red("\u2717 Failed to enable schedule"));
@@ -9018,8 +9337,29 @@ var enableCommand = new Command32().name("enable").description("Enable a schedul
9018
9337
  // src/commands/schedule/disable.ts
9019
9338
  import { Command as Command33 } from "commander";
9020
9339
  import chalk35 from "chalk";
9021
- var disableCommand = new Command33().name("disable").description("Disable a schedule").argument("<name>", "Schedule name to disable").action(async (name) => {
9340
+ var disableCommand = new Command33().name("disable").description("Disable a schedule").argument(
9341
+ "[name]",
9342
+ "Schedule name (auto-detected from schedule.yaml if omitted)"
9343
+ ).action(async (nameArg) => {
9022
9344
  try {
9345
+ let name = nameArg;
9346
+ if (!name) {
9347
+ const scheduleResult = loadScheduleName();
9348
+ if (scheduleResult.error) {
9349
+ console.error(chalk35.red(`\u2717 ${scheduleResult.error}`));
9350
+ process.exit(1);
9351
+ }
9352
+ if (!scheduleResult.scheduleName) {
9353
+ console.error(chalk35.red("\u2717 Schedule name required"));
9354
+ console.error(
9355
+ chalk35.dim(
9356
+ " Provide name or run from directory with schedule.yaml"
9357
+ )
9358
+ );
9359
+ process.exit(1);
9360
+ }
9361
+ name = scheduleResult.scheduleName;
9362
+ }
9023
9363
  const result = loadAgentName();
9024
9364
  if (result.error) {
9025
9365
  console.error(chalk35.red(`\u2717 Invalid vm0.yaml: ${result.error}`));
@@ -9040,14 +9380,7 @@ var disableCommand = new Command33().name("disable").description("Disable a sche
9040
9380
  console.error(chalk35.dim(" Make sure the agent is pushed first"));
9041
9381
  process.exit(1);
9042
9382
  }
9043
- const response = await apiClient.post(
9044
- `/api/agent/schedules/${encodeURIComponent(name)}/disable`,
9045
- { body: JSON.stringify({ composeId }) }
9046
- );
9047
- if (!response.ok) {
9048
- const error = await response.json();
9049
- throw new Error(error.error?.message || "Disable failed");
9050
- }
9383
+ await apiClient.disableSchedule({ name, composeId });
9051
9384
  console.log(chalk35.green(`\u2713 Disabled schedule ${chalk35.cyan(name)}`));
9052
9385
  } catch (error) {
9053
9386
  console.error(chalk35.red("\u2717 Failed to disable schedule"));
@@ -9067,7 +9400,7 @@ var scheduleCommand = new Command34().name("schedule").description("Manage agent
9067
9400
 
9068
9401
  // src/index.ts
9069
9402
  var program = new Command35();
9070
- program.name("vm0").description("VM0 CLI - A modern build tool").version("5.6.0");
9403
+ program.name("vm0").description("VM0 CLI - A modern build tool").version("5.7.2");
9071
9404
  program.command("info").description("Display environment information").action(async () => {
9072
9405
  console.log(chalk36.bold("System Information:"));
9073
9406
  console.log(`Node Version: ${process.version}`);