@vellumai/cli 0.5.12 → 0.5.14

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.
@@ -66,7 +66,7 @@ export async function backup(): Promise<void> {
66
66
  const cloud =
67
67
  entry.cloud || (entry.project ? "gcp" : entry.sshUser ? "custom" : "local");
68
68
  if (cloud === "vellum") {
69
- await backupPlatform(name, outputArg);
69
+ await backupPlatform(name, outputArg, entry.runtimeUrl);
70
70
  return;
71
71
  }
72
72
 
@@ -184,7 +184,11 @@ export async function backup(): Promise<void> {
184
184
  // Platform (Vellum-hosted) backup via Django async migration export
185
185
  // ---------------------------------------------------------------------------
186
186
 
187
- async function backupPlatform(name: string, outputArg?: string): Promise<void> {
187
+ async function backupPlatform(
188
+ name: string,
189
+ outputArg?: string,
190
+ runtimeUrl?: string,
191
+ ): Promise<void> {
188
192
  // Step 1 — Authenticate
189
193
  const token = readPlatformToken();
190
194
  if (!token) {
@@ -194,7 +198,7 @@ async function backupPlatform(name: string, outputArg?: string): Promise<void> {
194
198
 
195
199
  let orgId: string;
196
200
  try {
197
- orgId = await fetchOrganizationId(token);
201
+ orgId = await fetchOrganizationId(token, runtimeUrl);
198
202
  } catch (err) {
199
203
  const msg = err instanceof Error ? err.message : String(err);
200
204
  if (msg.includes("401") || msg.includes("403")) {
@@ -207,7 +211,12 @@ async function backupPlatform(name: string, outputArg?: string): Promise<void> {
207
211
  // Step 2 — Initiate export job
208
212
  let jobId: string;
209
213
  try {
210
- const result = await platformInitiateExport(token, orgId, "CLI backup");
214
+ const result = await platformInitiateExport(
215
+ token,
216
+ orgId,
217
+ "CLI backup",
218
+ runtimeUrl,
219
+ );
211
220
  jobId = result.jobId;
212
221
  } catch (err) {
213
222
  const msg = err instanceof Error ? err.message : String(err);
@@ -235,7 +244,7 @@ async function backupPlatform(name: string, outputArg?: string): Promise<void> {
235
244
  while (Date.now() < deadline) {
236
245
  let status: { status: string; downloadUrl?: string; error?: string };
237
246
  try {
238
- status = await platformPollExportStatus(jobId, token, orgId);
247
+ status = await platformPollExportStatus(jobId, token, orgId, runtimeUrl);
239
248
  } catch (err) {
240
249
  const msg = err instanceof Error ? err.message : String(err);
241
250
  // Let non-transient errors (e.g. 404 "job not found") propagate immediately
@@ -42,12 +42,17 @@ import { hatchGcp } from "../lib/gcp";
42
42
  import type { PollResult, WatchHatchingResult } from "../lib/gcp";
43
43
  import { buildNestedConfig, writeInitialConfig } from "../lib/config-utils";
44
44
  import {
45
+ generateLocalSigningKey,
45
46
  startLocalDaemon,
46
47
  startGateway,
47
48
  stopLocalProcesses,
48
49
  } from "../lib/local";
49
50
  import { maybeStartNgrokTunnel } from "../lib/ngrok";
50
- import { getPlatformUrl } from "../lib/platform-client";
51
+ import {
52
+ getPlatformUrl,
53
+ hatchAssistant,
54
+ readPlatformToken,
55
+ } from "../lib/platform-client";
51
56
  import { httpHealthCheck } from "../lib/http-client";
52
57
  import { detectOrphanedProcesses } from "../lib/orphan-detection";
53
58
  import { isProcessAlive, stopProcess } from "../lib/process";
@@ -237,7 +242,7 @@ function parseArgs(): HatchArgs {
237
242
  console.log(" -d Run in detached mode");
238
243
  console.log(" --name <name> Custom instance name");
239
244
  console.log(
240
- " --remote <host> Remote host (local, gcp, aws, docker, custom)",
245
+ " --remote <host> Remote host (local, gcp, aws, docker, custom, vellum)",
241
246
  );
242
247
  console.log(
243
248
  " --restart Restart processes without onboarding side effects",
@@ -772,12 +777,16 @@ async function hatchLocal(
772
777
  const defaultWorkspaceConfigPath = writeInitialConfig(configValues);
773
778
 
774
779
  emitProgress(4, 7, "Starting assistant...");
775
- await startLocalDaemon(watch, resources, { defaultWorkspaceConfigPath });
780
+ const signingKey = generateLocalSigningKey();
781
+ await startLocalDaemon(watch, resources, {
782
+ defaultWorkspaceConfigPath,
783
+ signingKey,
784
+ });
776
785
 
777
786
  emitProgress(5, 7, "Starting gateway...");
778
787
  let runtimeUrl = `http://127.0.0.1:${resources.gatewayPort}`;
779
788
  try {
780
- runtimeUrl = await startGateway(watch, resources);
789
+ runtimeUrl = await startGateway(watch, resources, { signingKey });
781
790
  } catch (error) {
782
791
  // Gateway failed — stop the daemon we just started so we don't leave
783
792
  // orphaned processes with no lock file entry.
@@ -820,7 +829,7 @@ async function hatchLocal(
820
829
  species,
821
830
  hatchedAt: new Date().toISOString(),
822
831
  serviceGroupVersion: cliPkg.version ? `v${cliPkg.version}` : undefined,
823
- resources,
832
+ resources: { ...resources, signingKey },
824
833
  };
825
834
  emitProgress(7, 7, "Saving configuration...");
826
835
  if (!restart) {
@@ -943,6 +952,48 @@ export async function hatch(): Promise<void> {
943
952
  return;
944
953
  }
945
954
 
955
+ if (remote === "vellum") {
956
+ await hatchVellumPlatform();
957
+ return;
958
+ }
959
+
946
960
  console.error(`Error: Remote host '${remote}' is not yet supported.`);
947
961
  process.exit(1);
948
962
  }
963
+
964
+ async function hatchVellumPlatform(): Promise<void> {
965
+ const token = readPlatformToken();
966
+ if (!token) {
967
+ console.error("Not logged in. Run `vellum login --token <token>` first.");
968
+ process.exit(1);
969
+ }
970
+
971
+ const config = SPECIES_CONFIG.vellum;
972
+ console.log("");
973
+ for (const line of config.art) {
974
+ console.log(` ${line}`);
975
+ }
976
+ console.log("");
977
+ console.log(" Hatching assistant on Vellum platform...");
978
+ console.log("");
979
+
980
+ const result = await hatchAssistant(token);
981
+
982
+ const platformUrl = getPlatformUrl();
983
+
984
+ saveAssistantEntry({
985
+ assistantId: result.id,
986
+ runtimeUrl: platformUrl,
987
+ cloud: "vellum",
988
+ species: "vellum",
989
+ hatchedAt: new Date().toISOString(),
990
+ });
991
+ setActiveAssistant(result.id);
992
+
993
+ console.log(` ${config.hatchedEmoji} Your assistant has hatched!`);
994
+ console.log("");
995
+ console.log(` ID: ${result.id}`);
996
+ console.log(` Name: ${result.name}`);
997
+ console.log(` Status: ${result.status}`);
998
+ console.log("");
999
+ }
@@ -238,7 +238,7 @@ async function getLocalProcesses(entry: AssistantEntry): Promise<TableRow[]> {
238
238
  name: "embed-worker",
239
239
  pgrepName: "embed-worker",
240
240
  port: 0,
241
- pidFile: join(vellumDir, "embed-worker.pid"),
241
+ pidFile: join(vellumDir, "workspace", "embed-worker.pid"),
242
242
  },
243
243
  ];
244
244
 
@@ -4,7 +4,11 @@ import { join } from "path";
4
4
 
5
5
  import { saveAssistantEntry } from "../lib/assistant-config";
6
6
  import type { AssistantEntry } from "../lib/assistant-config";
7
- import { startLocalDaemon, startGateway } from "../lib/local";
7
+ import {
8
+ generateLocalSigningKey,
9
+ startLocalDaemon,
10
+ startGateway,
11
+ } from "../lib/local";
8
12
  import { getArchivePath, getMetadataPath } from "../lib/retire-archive";
9
13
  import { exec } from "../lib/step-runner";
10
14
 
@@ -66,9 +70,14 @@ export async function recover(): Promise<void> {
66
70
  unlinkSync(archivePath);
67
71
  unlinkSync(metadataPath);
68
72
 
69
- // 7. Start daemon + gateway (same as wake)
70
- await startLocalDaemon(false, entry.resources);
71
- await startGateway(false, entry.resources);
73
+ // 7. Persist signing key so it survives daemon/gateway restarts (same as wake)
74
+ const signingKey = generateLocalSigningKey();
75
+ entry.resources = { ...entry.resources, signingKey };
76
+ saveAssistantEntry(entry);
77
+
78
+ // 8. Start daemon + gateway
79
+ await startLocalDaemon(false, entry.resources, { signingKey });
80
+ await startGateway(false, entry.resources, { signingKey });
72
81
 
73
82
  console.log(`✅ Recovered assistant '${name}'.`);
74
83
  }
@@ -179,7 +179,7 @@ async function restorePlatform(
179
179
 
180
180
  let orgId: string;
181
181
  try {
182
- orgId = await fetchOrganizationId(token);
182
+ orgId = await fetchOrganizationId(token, entry.runtimeUrl);
183
183
  } catch (err) {
184
184
  const msg = err instanceof Error ? err.message : String(err);
185
185
  if (msg.includes("401") || msg.includes("403")) {
@@ -206,6 +206,7 @@ async function restorePlatform(
206
206
  new Uint8Array(bundleData),
207
207
  token,
208
208
  orgId,
209
+ entry.runtimeUrl,
209
210
  );
210
211
  } catch (err) {
211
212
  if (err instanceof Error && err.name === "TimeoutError") {
@@ -315,7 +316,12 @@ async function restorePlatform(
315
316
  );
316
317
 
317
318
  try {
318
- await rollbackPlatformAssistant(token, orgId, opts.version);
319
+ await rollbackPlatformAssistant(
320
+ token,
321
+ orgId,
322
+ opts.version,
323
+ entry.runtimeUrl,
324
+ );
319
325
  } catch (err) {
320
326
  const msg = err instanceof Error ? err.message : String(err);
321
327
  if (msg.includes("401") || msg.includes("403")) {
@@ -340,6 +346,7 @@ async function restorePlatform(
340
346
  new Uint8Array(bundleData),
341
347
  token,
342
348
  orgId,
349
+ entry.runtimeUrl,
343
350
  );
344
351
  } catch (err) {
345
352
  if (err instanceof Error && err.name === "TimeoutError") {
@@ -197,7 +197,10 @@ async function retireCustom(entry: AssistantEntry): Promise<void> {
197
197
  console.log(`\u2705 Custom instance retired.`);
198
198
  }
199
199
 
200
- async function retireVellum(assistantId: string): Promise<void> {
200
+ async function retireVellum(
201
+ assistantId: string,
202
+ runtimeUrl?: string,
203
+ ): Promise<void> {
201
204
  console.log("\u{1F5D1}\ufe0f Retiring platform-hosted instance...\n");
202
205
 
203
206
  const token = readPlatformToken();
@@ -208,9 +211,10 @@ async function retireVellum(assistantId: string): Promise<void> {
208
211
  process.exit(1);
209
212
  }
210
213
 
211
- const orgId = await fetchOrganizationId(token);
214
+ const orgId = await fetchOrganizationId(token, runtimeUrl);
212
215
 
213
- const url = `${getPlatformUrl()}/v1/assistants/${encodeURIComponent(assistantId)}/retire/`;
216
+ const platformUrl = runtimeUrl || getPlatformUrl();
217
+ const url = `${platformUrl}/v1/assistants/${encodeURIComponent(assistantId)}/retire/`;
214
218
  const response = await fetch(url, {
215
219
  method: "DELETE",
216
220
  headers: {
@@ -343,7 +347,7 @@ async function retireInner(): Promise<void> {
343
347
  } else if (cloud === "custom") {
344
348
  await retireCustom(entry);
345
349
  } else if (cloud === "vellum") {
346
- await retireVellum(entry.assistantId);
350
+ await retireVellum(entry.assistantId, entry.runtimeUrl);
347
351
  } else {
348
352
  console.error(`Error: Unknown cloud type '${cloud}'.`);
349
353
  process.exit(1);
@@ -11,8 +11,6 @@ import {
11
11
  captureImageRefs,
12
12
  GATEWAY_INTERNAL_PORT,
13
13
  dockerResourceNames,
14
- migrateCesSecurityFiles,
15
- migrateGatewaySecurityFiles,
16
14
  startContainers,
17
15
  stopContainers,
18
16
  } from "../lib/docker";
@@ -185,7 +183,7 @@ async function rollbackPlatformViaEndpoint(
185
183
 
186
184
  let orgId: string;
187
185
  try {
188
- orgId = await fetchOrganizationId(token);
186
+ orgId = await fetchOrganizationId(token, entry.runtimeUrl);
189
187
  } catch (err) {
190
188
  const msg = err instanceof Error ? err.message : String(err);
191
189
  if (msg.includes("401") || msg.includes("403")) {
@@ -206,7 +204,12 @@ async function rollbackPlatformViaEndpoint(
206
204
 
207
205
  let result: { detail: string; version: string | null };
208
206
  try {
209
- result = await rollbackPlatformAssistant(token, orgId, version);
207
+ result = await rollbackPlatformAssistant(
208
+ token,
209
+ orgId,
210
+ version,
211
+ entry.runtimeUrl,
212
+ );
210
213
  } catch (err) {
211
214
  const detail = err instanceof Error ? err.message : String(err);
212
215
 
@@ -423,13 +426,6 @@ export async function rollback(): Promise<void> {
423
426
  await stopContainers(res);
424
427
  console.log("✅ Containers stopped\n");
425
428
 
426
- // Run security file migrations and signing key cleanup
427
- console.log("🔄 Migrating security files to gateway volume...");
428
- await migrateGatewaySecurityFiles(res, (msg) => console.log(msg));
429
-
430
- console.log("🔄 Migrating credential files to CES security volume...");
431
- await migrateCesSecurityFiles(res, (msg) => console.log(msg));
432
-
433
429
  console.log("🚀 Starting containers with previous version...");
434
430
  await startContainers(
435
431
  {