@vellumai/cli 0.5.7 → 0.5.9

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.
@@ -1,5 +1,4 @@
1
1
  import { randomBytes } from "crypto";
2
- import { join } from "node:path";
3
2
 
4
3
  import cliPkg from "../../package.json";
5
4
 
@@ -25,10 +24,6 @@ import {
25
24
  getPlatformUrl,
26
25
  readPlatformToken,
27
26
  } from "../lib/platform-client";
28
- import {
29
- loadBootstrapSecret,
30
- saveBootstrapSecret,
31
- } from "../lib/guardian-token";
32
27
  import {
33
28
  createBackup,
34
29
  pruneOldBackups,
@@ -43,30 +38,35 @@ import {
43
38
  buildStartingEvent,
44
39
  buildUpgradeCommitMessage,
45
40
  captureContainerEnv,
41
+ commitWorkspaceViaGateway,
46
42
  CONTAINER_ENV_EXCLUDE_KEYS,
47
43
  rollbackMigrations,
48
44
  UPGRADE_PROGRESS,
49
45
  waitForReady,
50
46
  } from "../lib/upgrade-lifecycle.js";
51
47
  import { parseVersion } from "../lib/version-compat.js";
52
- import { commitWorkspaceState } from "../lib/workspace-git.js";
53
48
 
54
49
  interface UpgradeArgs {
55
50
  name: string | null;
56
51
  version: string | null;
52
+ prepare: boolean;
53
+ finalize: boolean;
57
54
  }
58
55
 
59
56
  function parseArgs(): UpgradeArgs {
60
57
  const args = process.argv.slice(3);
61
58
  let name: string | null = null;
62
59
  let version: string | null = null;
60
+ let prepare = false;
61
+ let finalize = false;
63
62
 
64
63
  for (let i = 0; i < args.length; i++) {
65
64
  const arg = args[i];
66
65
  if (arg === "--help" || arg === "-h") {
67
66
  console.log("Usage: vellum upgrade [<name>] [options]");
68
67
  console.log("");
69
- console.log("Upgrade an assistant to the latest version.");
68
+ console.log("Upgrade an assistant to a newer version.");
69
+ console.log("To roll back to a previous version, use `vellum rollback`.");
70
70
  console.log("");
71
71
  console.log("Arguments:");
72
72
  console.log(
@@ -77,6 +77,12 @@ function parseArgs(): UpgradeArgs {
77
77
  console.log(
78
78
  " --version <version> Target version to upgrade to (default: latest)",
79
79
  );
80
+ console.log(
81
+ " --prepare Run pre-upgrade steps only (backup, notify) without swapping versions",
82
+ );
83
+ console.log(
84
+ " --finalize Run post-upgrade steps only (broadcast complete, workspace commit)",
85
+ );
80
86
  console.log("");
81
87
  console.log("Examples:");
82
88
  console.log(
@@ -98,6 +104,10 @@ function parseArgs(): UpgradeArgs {
98
104
  }
99
105
  version = next;
100
106
  i++;
107
+ } else if (arg === "--prepare") {
108
+ prepare = true;
109
+ } else if (arg === "--finalize") {
110
+ finalize = true;
101
111
  } else if (!arg.startsWith("-")) {
102
112
  name = arg;
103
113
  } else {
@@ -107,7 +117,13 @@ function parseArgs(): UpgradeArgs {
107
117
  }
108
118
  }
109
119
 
110
- return { name, version };
120
+ if (prepare && finalize) {
121
+ console.error("Error: --prepare and --finalize are mutually exclusive.");
122
+ emitCliError("UNKNOWN", "--prepare and --finalize are mutually exclusive");
123
+ process.exit(1);
124
+ }
125
+
126
+ return { name, version, prepare, finalize };
111
127
  }
112
128
 
113
129
  function resolveCloud(entry: AssistantEntry): string {
@@ -171,12 +187,32 @@ async function upgradeDocker(
171
187
  ): Promise<void> {
172
188
  const instanceName = entry.assistantId;
173
189
  const res = dockerResourceNames(instanceName);
174
- const workspaceDir = entry.resources
175
- ? join(entry.resources.instanceDir, ".vellum", "workspace")
176
- : null;
177
190
 
178
191
  const versionTag =
179
192
  version ?? (cliPkg.version ? `v${cliPkg.version}` : "latest");
193
+
194
+ // Reject downgrades — `vellum upgrade` only handles forward version changes.
195
+ // Users should use `vellum rollback --version <version>` for downgrades.
196
+ const currentVersion = entry.serviceGroupVersion;
197
+ if (currentVersion && versionTag) {
198
+ const current = parseVersion(currentVersion);
199
+ const target = parseVersion(versionTag);
200
+ if (current && target) {
201
+ const isOlder =
202
+ target.major < current.major ||
203
+ (target.major === current.major && target.minor < current.minor) ||
204
+ (target.major === current.major &&
205
+ target.minor === current.minor &&
206
+ target.patch < current.patch);
207
+ if (isOlder) {
208
+ const msg = `Cannot upgrade to an older version (${versionTag} < ${currentVersion}). Use \`vellum rollback --version ${versionTag}\` instead.`;
209
+ console.error(msg);
210
+ emitCliError("VERSION_DIRECTION", msg);
211
+ process.exit(1);
212
+ }
213
+ }
214
+ }
215
+
180
216
  console.log("🔍 Resolving image references...");
181
217
  const { imageTags } = await resolveImageRefs(versionTag);
182
218
 
@@ -223,63 +259,6 @@ async function upgradeDocker(
223
259
  // Best-effort — if we can't get migration state, rollback will skip migration reversal
224
260
  }
225
261
 
226
- // Detect if this upgrade is actually a downgrade (user picked an older
227
- // version via the version picker). Used after readiness succeeds to align
228
- // the DB schema with the now-running old daemon.
229
- const currentVersion = entry.serviceGroupVersion;
230
- const isDowngrade =
231
- currentVersion &&
232
- versionTag &&
233
- (() => {
234
- const current = parseVersion(currentVersion);
235
- const target = parseVersion(versionTag);
236
- if (!current || !target) return false;
237
- if (target.major !== current.major) return target.major < current.major;
238
- if (target.minor !== current.minor) return target.minor < current.minor;
239
- return target.patch < current.patch;
240
- })();
241
-
242
- // For downgrades, fetch the target version's migration ceiling from the
243
- // releases API. This tells us exactly which DB migration version and
244
- // workspace migration the target version expects, enabling a precise
245
- // rollback on the CURRENT (newer) daemon before swapping containers.
246
- let targetMigrationCeiling: {
247
- dbVersion?: number;
248
- workspaceMigrationId?: string;
249
- } = {};
250
- if (isDowngrade) {
251
- try {
252
- const platformUrl = getPlatformUrl();
253
- const releasesResp = await fetch(
254
- `${platformUrl}/v1/releases/?stable=true`,
255
- { signal: AbortSignal.timeout(10000) },
256
- );
257
- if (releasesResp.ok) {
258
- const releases = (await releasesResp.json()) as Array<{
259
- version: string;
260
- db_migration_version?: number | null;
261
- last_workspace_migration_id?: string;
262
- }>;
263
- const normalizedTag = versionTag.replace(/^v/, "");
264
- const targetRelease = releases.find(
265
- (r) => r.version?.replace(/^v/, "") === normalizedTag,
266
- );
267
- if (
268
- targetRelease?.db_migration_version != null ||
269
- targetRelease?.last_workspace_migration_id
270
- ) {
271
- targetMigrationCeiling = {
272
- dbVersion: targetRelease.db_migration_version ?? undefined,
273
- workspaceMigrationId:
274
- targetRelease.last_workspace_migration_id || undefined,
275
- };
276
- }
277
- }
278
- } catch {
279
- // Best-effort — fall back to rollbackToRegistryCeiling post-swap
280
- }
281
- }
282
-
283
262
  // Persist rollback state to lockfile BEFORE any destructive changes.
284
263
  // This enables the `vellum rollback` command to restore the previous version.
285
264
  if (entry.serviceGroupVersion && entry.containerInfo) {
@@ -295,25 +274,18 @@ async function upgradeDocker(
295
274
  }
296
275
 
297
276
  // Record version transition start in workspace git history
298
- if (workspaceDir) {
299
- try {
300
- await commitWorkspaceState(
301
- workspaceDir,
302
- buildUpgradeCommitMessage({
303
- action: "upgrade",
304
- phase: "starting",
305
- from: entry.serviceGroupVersion ?? "unknown",
306
- to: versionTag,
307
- topology: "docker",
308
- assistantId: entry.assistantId,
309
- }),
310
- );
311
- } catch (err) {
312
- console.warn(
313
- `⚠️ Failed to create pre-upgrade workspace commit: ${err instanceof Error ? err.message : String(err)}`,
314
- );
315
- }
316
- }
277
+ await commitWorkspaceViaGateway(
278
+ entry.runtimeUrl,
279
+ entry.assistantId,
280
+ buildUpgradeCommitMessage({
281
+ action: "upgrade",
282
+ phase: "starting",
283
+ from: entry.serviceGroupVersion ?? "unknown",
284
+ to: versionTag,
285
+ topology: "docker",
286
+ assistantId: entry.assistantId,
287
+ }),
288
+ );
317
289
 
318
290
  console.log("💾 Capturing existing container environment...");
319
291
  const capturedEnv = await captureContainerEnv(res.assistantContainer);
@@ -381,16 +353,6 @@ async function upgradeDocker(
381
353
  const cesServiceToken =
382
354
  capturedEnv["CES_SERVICE_TOKEN"] || randomBytes(32).toString("hex");
383
355
 
384
- // Retrieve or generate a bootstrap secret for the gateway. The secret was
385
- // persisted to disk during hatch; older instances won't have one yet.
386
- // This runs BEFORE stopping containers so a write failure (disk full,
387
- // permissions) doesn't leave the assistant offline.
388
- const loadedSecret = loadBootstrapSecret(instanceName);
389
- const bootstrapSecret = loadedSecret || randomBytes(32).toString("hex");
390
- if (!loadedSecret) {
391
- saveBootstrapSecret(instanceName, bootstrapSecret);
392
- }
393
-
394
356
  // Extract or generate the shared JWT signing key. Pre-env-var instances
395
357
  // won't have it in capturedEnv, so generate fresh in that case.
396
358
  const signingKey =
@@ -434,32 +396,6 @@ async function upgradeDocker(
434
396
  buildProgressEvent(UPGRADE_PROGRESS.INSTALLING),
435
397
  );
436
398
 
437
- // If we have the target version's migration ceiling, run a PRECISE
438
- // rollback on the CURRENT (newer) daemon before stopping it. The current
439
- // daemon has the `down()` code for all migrations it applied, so it can
440
- // cleanly revert to the target version's ceiling. This is critical for
441
- // multi-version downgrades where the old daemon wouldn't know about
442
- // migrations introduced after its release.
443
- let preSwapRollbackOk = true;
444
- if (
445
- isDowngrade &&
446
- (targetMigrationCeiling.dbVersion !== undefined ||
447
- targetMigrationCeiling.workspaceMigrationId !== undefined)
448
- ) {
449
- console.log("🔄 Reverting database changes for downgrade...");
450
- await broadcastUpgradeEvent(
451
- entry.runtimeUrl,
452
- entry.assistantId,
453
- buildProgressEvent(UPGRADE_PROGRESS.REVERTING_MIGRATIONS),
454
- );
455
- preSwapRollbackOk = await rollbackMigrations(
456
- entry.runtimeUrl,
457
- entry.assistantId,
458
- targetMigrationCeiling.dbVersion,
459
- targetMigrationCeiling.workspaceMigrationId,
460
- );
461
- }
462
-
463
399
  console.log("🛑 Stopping existing containers...");
464
400
  await stopContainers(res);
465
401
  console.log("✅ Containers stopped\n");
@@ -491,7 +427,6 @@ async function upgradeDocker(
491
427
  await startContainers(
492
428
  {
493
429
  signingKey,
494
- bootstrapSecret,
495
430
  cesServiceToken,
496
431
  extraAssistantEnv,
497
432
  gatewayPort,
@@ -529,27 +464,6 @@ async function upgradeDocker(
529
464
  };
530
465
  saveAssistantEntry(updatedEntry);
531
466
 
532
- // After a downgrade, fall back to asking the now-running old daemon
533
- // to roll back migrations above its own registry ceiling when either:
534
- // (a) no release metadata was available for a precise pre-swap rollback, or
535
- // (b) the precise pre-swap rollback failed (timeout, daemon crash, etc.).
536
- // This is a no-op for multi-version jumps where the old daemon doesn't
537
- // know about the newer migrations, but correct for single-step rollbacks.
538
- if (
539
- isDowngrade &&
540
- (!preSwapRollbackOk ||
541
- (targetMigrationCeiling.dbVersion === undefined &&
542
- targetMigrationCeiling.workspaceMigrationId === undefined))
543
- ) {
544
- await rollbackMigrations(
545
- entry.runtimeUrl,
546
- entry.assistantId,
547
- undefined,
548
- undefined,
549
- true,
550
- );
551
- }
552
-
553
467
  // Notify clients on the new service group that the upgrade succeeded.
554
468
  await broadcastUpgradeEvent(
555
469
  entry.runtimeUrl,
@@ -558,26 +472,19 @@ async function upgradeDocker(
558
472
  );
559
473
 
560
474
  // Record successful upgrade in workspace git history
561
- if (workspaceDir) {
562
- try {
563
- await commitWorkspaceState(
564
- workspaceDir,
565
- buildUpgradeCommitMessage({
566
- action: "upgrade",
567
- phase: "complete",
568
- from: entry.serviceGroupVersion ?? "unknown",
569
- to: versionTag,
570
- topology: "docker",
571
- assistantId: entry.assistantId,
572
- result: "success",
573
- }),
574
- );
575
- } catch (err) {
576
- console.warn(
577
- `⚠️ Failed to create post-upgrade workspace commit: ${err instanceof Error ? err.message : String(err)}`,
578
- );
579
- }
580
- }
475
+ await commitWorkspaceViaGateway(
476
+ entry.runtimeUrl,
477
+ entry.assistantId,
478
+ buildUpgradeCommitMessage({
479
+ action: "upgrade",
480
+ phase: "complete",
481
+ from: entry.serviceGroupVersion ?? "unknown",
482
+ to: versionTag,
483
+ topology: "docker",
484
+ assistantId: entry.assistantId,
485
+ result: "success",
486
+ }),
487
+ );
581
488
 
582
489
  console.log(
583
490
  `\n✅ Docker assistant '${instanceName}' upgraded to ${versionTag}.`,
@@ -621,7 +528,6 @@ async function upgradeDocker(
621
528
  await startContainers(
622
529
  {
623
530
  signingKey,
624
- bootstrapSecret,
625
531
  cesServiceToken,
626
532
  extraAssistantEnv,
627
533
  gatewayPort,
@@ -785,28 +691,28 @@ async function upgradePlatform(
785
691
  entry: AssistantEntry,
786
692
  version: string | null,
787
693
  ): Promise<void> {
788
- const workspaceDir = entry.resources
789
- ? join(entry.resources.instanceDir, ".vellum", "workspace")
790
- : null;
791
-
792
- // Record version transition start in workspace git history
793
- if (workspaceDir) {
794
- try {
795
- await commitWorkspaceState(
796
- workspaceDir,
797
- buildUpgradeCommitMessage({
798
- action: "upgrade",
799
- phase: "starting",
800
- from: entry.serviceGroupVersion ?? "unknown",
801
- to: version ?? "latest",
802
- topology: "managed",
803
- assistantId: entry.assistantId,
804
- }),
805
- );
806
- } catch (err) {
807
- console.warn(
808
- `⚠️ Failed to create pre-upgrade workspace commit: ${err instanceof Error ? err.message : String(err)}`,
809
- );
694
+ // Reject downgrades — `vellum upgrade` only handles forward version changes.
695
+ // Users should use `vellum rollback --version <version>` for downgrades.
696
+ // Only enforce this guard when the user explicitly passed `--version`.
697
+ // When version is null the platform API decides the actual target, so
698
+ // we must not block the request based on the local CLI version.
699
+ const currentVersion = entry.serviceGroupVersion;
700
+ if (version && currentVersion) {
701
+ const current = parseVersion(currentVersion);
702
+ const target = parseVersion(version);
703
+ if (current && target) {
704
+ const isOlder =
705
+ target.major < current.major ||
706
+ (target.major === current.major && target.minor < current.minor) ||
707
+ (target.major === current.major &&
708
+ target.minor === current.minor &&
709
+ target.patch < current.patch);
710
+ if (isOlder) {
711
+ const msg = `Cannot upgrade to an older version (${version} < ${currentVersion}). Use \`vellum rollback --version ${version}\` instead.`;
712
+ console.error(msg);
713
+ emitCliError("VERSION_DIRECTION", msg);
714
+ process.exit(1);
715
+ }
810
716
  }
811
717
  }
812
718
 
@@ -833,15 +739,6 @@ async function upgradePlatform(
833
739
  body.version = version;
834
740
  }
835
741
 
836
- // Notify connected clients that an upgrade is about to begin.
837
- const targetVersion = version ?? `v${cliPkg.version}`;
838
- console.log("📢 Notifying connected clients...");
839
- await broadcastUpgradeEvent(
840
- entry.runtimeUrl,
841
- entry.assistantId,
842
- buildStartingEvent(targetVersion, 90),
843
- );
844
-
845
742
  const response = await fetch(url, {
846
743
  method: "POST",
847
744
  headers: {
@@ -879,37 +776,124 @@ async function upgradePlatform(
879
776
  // version-change detection (DaemonConnection.swift) once the new
880
777
  // version actually appears after the platform restarts the service group.
881
778
 
882
- // Record successful upgrade in workspace git history
883
- if (workspaceDir) {
884
- try {
885
- await commitWorkspaceState(
886
- workspaceDir,
887
- buildUpgradeCommitMessage({
888
- action: "upgrade",
889
- phase: "complete",
890
- from: entry.serviceGroupVersion ?? "unknown",
891
- to: version ?? "latest",
892
- topology: "managed",
893
- assistantId: entry.assistantId,
894
- result: "success",
895
- }),
896
- );
897
- } catch (err) {
898
- console.warn(
899
- `⚠️ Failed to create post-upgrade workspace commit: ${err instanceof Error ? err.message : String(err)}`,
900
- );
901
- }
902
- }
903
-
904
779
  console.log(`✅ ${result.detail}`);
905
780
  if (result.version) {
906
781
  console.log(` Version: ${result.version}`);
907
782
  }
908
783
  }
909
784
 
785
+ /**
786
+ * Pre-upgrade steps for Sparkle (macOS app) lifecycle.
787
+ * Runs the pre-update orchestration without actually swapping containers:
788
+ * broadcasts SSE events, creates a workspace commit, creates a backup,
789
+ * prunes old backups, and outputs the backup path.
790
+ */
791
+ async function upgradePrepare(
792
+ entry: AssistantEntry,
793
+ version: string | null,
794
+ ): Promise<void> {
795
+ const targetVersion = version ?? entry.serviceGroupVersion ?? "unknown";
796
+ const currentVersion = entry.serviceGroupVersion ?? "unknown";
797
+
798
+ // 1. Broadcast "starting" so the UI shows the progress spinner
799
+ await broadcastUpgradeEvent(
800
+ entry.runtimeUrl,
801
+ entry.assistantId,
802
+ buildStartingEvent(targetVersion, 30),
803
+ );
804
+
805
+ // 2. Workspace commit: record pre-update state
806
+ await commitWorkspaceViaGateway(
807
+ entry.runtimeUrl,
808
+ entry.assistantId,
809
+ `[sparkle-update] Starting: ${currentVersion} → ${targetVersion}`,
810
+ );
811
+
812
+ // 3. Progress: saving backup
813
+ await broadcastUpgradeEvent(
814
+ entry.runtimeUrl,
815
+ entry.assistantId,
816
+ buildProgressEvent("Saving a backup of your data…"),
817
+ );
818
+
819
+ // 4. Create backup
820
+ const backupPath = await createBackup(entry.runtimeUrl, entry.assistantId, {
821
+ prefix: `${entry.assistantId}-pre-upgrade`,
822
+ description: `Pre-upgrade snapshot before ${currentVersion} → ${targetVersion}`,
823
+ });
824
+
825
+ // 5. Prune old backups (keep 3)
826
+ if (backupPath) {
827
+ pruneOldBackups(entry.assistantId, 3);
828
+ }
829
+
830
+ // 6. Progress: installing update
831
+ await broadcastUpgradeEvent(
832
+ entry.runtimeUrl,
833
+ entry.assistantId,
834
+ buildProgressEvent(UPGRADE_PROGRESS.INSTALLING),
835
+ );
836
+
837
+ // 7. Output backup path to stdout for the macOS app to parse
838
+ if (backupPath) {
839
+ console.log(`BACKUP_PATH:${backupPath}`);
840
+ }
841
+ }
842
+
843
+ /**
844
+ * Post-upgrade steps for Sparkle (macOS app) lifecycle.
845
+ * Called after the app has been replaced and the daemon is back up.
846
+ * Broadcasts a "complete" SSE event and creates a workspace commit.
847
+ */
848
+ async function upgradeFinalize(
849
+ entry: AssistantEntry,
850
+ version: string | null,
851
+ ): Promise<void> {
852
+ if (!version) {
853
+ console.error(
854
+ "Error: --finalize requires --version <from-version> to record the transition.",
855
+ );
856
+ emitCliError(
857
+ "UNKNOWN",
858
+ "--finalize requires --version <from-version> to record the transition",
859
+ );
860
+ process.exit(1);
861
+ }
862
+
863
+ const fromVersion = version;
864
+ const currentVersion = cliPkg.version
865
+ ? `v${cliPkg.version}`
866
+ : (entry.serviceGroupVersion ?? "unknown");
867
+
868
+ // 1. Broadcast "complete" so the UI clears the progress spinner
869
+ await broadcastUpgradeEvent(
870
+ entry.runtimeUrl,
871
+ entry.assistantId,
872
+ buildCompleteEvent(currentVersion, true),
873
+ );
874
+
875
+ // 2. Workspace commit: record successful update
876
+ await commitWorkspaceViaGateway(
877
+ entry.runtimeUrl,
878
+ entry.assistantId,
879
+ `[sparkle-update] Complete: ${fromVersion} → ${currentVersion}\n\nresult: success`,
880
+ );
881
+ }
882
+
910
883
  export async function upgrade(): Promise<void> {
911
- const { name, version } = parseArgs();
884
+ const { name, version, prepare, finalize } = parseArgs();
912
885
  const entry = resolveTargetAssistant(name);
886
+
887
+ if (prepare) {
888
+ await upgradePrepare(entry, version);
889
+ return;
890
+ }
891
+
892
+ if (finalize) {
893
+ await upgradeFinalize(entry, version);
894
+ return;
895
+ }
896
+
913
897
  const cloud = resolveCloud(entry);
914
898
 
915
899
  try {
package/src/index.ts CHANGED
@@ -68,16 +68,16 @@ function printHelp(): void {
68
68
  " ps List assistants (or processes for a specific assistant)",
69
69
  );
70
70
  console.log(" recover Restore a previously retired local assistant");
71
- console.log(" restore Restore a .vbundle backup into a running assistant");
72
- console.log(" retire Delete an assistant instance");
73
71
  console.log(
74
- " rollback Roll back a Docker assistant to the previous version",
72
+ " restore Restore data (and optionally version) from a .vbundle backup",
75
73
  );
74
+ console.log(" retire Delete an assistant instance");
75
+ console.log(" rollback Roll back an assistant to a previous version");
76
76
  console.log(" setup Configure API keys interactively");
77
77
  console.log(" sleep Stop the assistant process");
78
78
  console.log(" ssh SSH into a remote assistant instance");
79
79
  console.log(" tunnel Create a tunnel for a locally hosted assistant");
80
- console.log(" upgrade Upgrade an assistant to the latest version");
80
+ console.log(" upgrade Upgrade an assistant to a newer version");
81
81
  console.log(" use Set the active assistant for commands");
82
82
  console.log(" wake Start the assistant and gateway");
83
83
  console.log(" whoami Show current logged-in user");
package/src/lib/aws.ts CHANGED
@@ -443,14 +443,15 @@ export async function hatchAws(
443
443
  console.log("\u{1F50D} Finding latest Debian AMI...");
444
444
  const amiId = await getLatestDebianAmi(region);
445
445
 
446
- const startupScript = await buildStartupScript(
447
- species,
448
- sshUser,
449
- providerApiKeys,
450
- instanceName,
451
- "aws",
452
- configValues,
453
- );
446
+ const { script: startupScript, laptopBootstrapSecret } =
447
+ await buildStartupScript(
448
+ species,
449
+ sshUser,
450
+ providerApiKeys,
451
+ instanceName,
452
+ "aws",
453
+ configValues,
454
+ );
454
455
  const startupScriptPath = join(tmpdir(), `${instanceName}-startup.sh`);
455
456
  writeFileSync(startupScriptPath, startupScript);
456
457
 
@@ -539,7 +540,11 @@ export async function hatchAws(
539
540
  }
540
541
 
541
542
  try {
542
- await leaseGuardianToken(runtimeUrl, instanceName);
543
+ await leaseGuardianToken(
544
+ runtimeUrl,
545
+ instanceName,
546
+ laptopBootstrapSecret,
547
+ );
543
548
  } catch (err) {
544
549
  console.warn(
545
550
  `\u26a0\ufe0f Could not lease guardian token: ${err instanceof Error ? err.message : err}`,
@@ -11,9 +11,11 @@
11
11
  export type CliErrorCategory =
12
12
  | "DOCKER_NOT_RUNNING"
13
13
  | "IMAGE_PULL_FAILED"
14
+ | "MISSING_VERSION"
14
15
  | "READINESS_TIMEOUT"
15
16
  | "ROLLBACK_FAILED"
16
17
  | "ROLLBACK_NO_STATE"
18
+ | "VERSION_DIRECTION"
17
19
  | "AUTH_FAILED"
18
20
  | "NETWORK_ERROR"
19
21
  | "UNSUPPORTED_TOPOLOGY"