@vellumai/cli 0.5.6 → 0.5.8
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/knip.json +3 -1
- package/package.json +1 -1
- package/src/commands/backup.ts +152 -13
- package/src/commands/hatch.ts +120 -65
- package/src/commands/restore.ts +359 -16
- package/src/commands/retire.ts +5 -5
- package/src/commands/rollback.ts +436 -142
- package/src/commands/upgrade.ts +575 -205
- package/src/index.ts +4 -4
- package/src/lib/assistant-config.ts +33 -6
- package/src/lib/aws.ts +15 -8
- package/src/lib/backup-ops.ts +213 -0
- package/src/lib/cli-error.ts +93 -0
- package/src/lib/config-utils.ts +59 -0
- package/src/lib/docker.ts +99 -50
- package/src/lib/doctor-client.ts +11 -1
- package/src/lib/gcp.ts +19 -10
- package/src/lib/guardian-token.ts +4 -42
- package/src/lib/local.ts +30 -9
- package/src/lib/platform-client.ts +205 -3
- package/src/lib/platform-releases.ts +112 -0
- package/src/lib/upgrade-lifecycle.ts +844 -0
package/src/commands/restore.ts
CHANGED
|
@@ -1,45 +1,71 @@
|
|
|
1
1
|
import { existsSync, readFileSync } from "fs";
|
|
2
2
|
|
|
3
3
|
import { findAssistantByName } from "../lib/assistant-config.js";
|
|
4
|
+
import type { AssistantEntry } from "../lib/assistant-config.js";
|
|
4
5
|
import {
|
|
5
6
|
loadGuardianToken,
|
|
6
7
|
leaseGuardianToken,
|
|
7
8
|
} from "../lib/guardian-token.js";
|
|
9
|
+
import {
|
|
10
|
+
readPlatformToken,
|
|
11
|
+
fetchOrganizationId,
|
|
12
|
+
rollbackPlatformAssistant,
|
|
13
|
+
platformImportPreflight,
|
|
14
|
+
platformImportBundle,
|
|
15
|
+
} from "../lib/platform-client.js";
|
|
16
|
+
import { performDockerRollback } from "../lib/upgrade-lifecycle.js";
|
|
8
17
|
|
|
9
18
|
function printUsage(): void {
|
|
10
|
-
console.log(
|
|
19
|
+
console.log(
|
|
20
|
+
"Usage: vellum restore <name> --from <path> [--version <version>] [--dry-run]",
|
|
21
|
+
);
|
|
11
22
|
console.log("");
|
|
12
|
-
console.log("Restore a .vbundle backup into
|
|
23
|
+
console.log("Restore data from a .vbundle backup into an assistant.");
|
|
24
|
+
console.log(
|
|
25
|
+
"With --version, also rolls back to the specified version first.",
|
|
26
|
+
);
|
|
13
27
|
console.log("");
|
|
14
28
|
console.log("Arguments:");
|
|
15
|
-
console.log(" <name>
|
|
29
|
+
console.log(" <name> Name of the assistant to restore into");
|
|
16
30
|
console.log("");
|
|
17
31
|
console.log("Options:");
|
|
32
|
+
console.log(" --from <path> Path to the .vbundle file (required)");
|
|
33
|
+
console.log(
|
|
34
|
+
" --version <version> Roll back to this version before importing data",
|
|
35
|
+
);
|
|
18
36
|
console.log(
|
|
19
|
-
" --
|
|
37
|
+
" --dry-run Show what would change without applying (data-only)",
|
|
20
38
|
);
|
|
21
|
-
console.log(" --dry-run Show what would change without applying");
|
|
22
39
|
console.log("");
|
|
23
40
|
console.log("Examples:");
|
|
24
|
-
console.log(" vellum restore my-assistant --from
|
|
41
|
+
console.log(" vellum restore my-assistant --from backup.vbundle");
|
|
25
42
|
console.log(
|
|
26
|
-
" vellum restore my-assistant --from
|
|
43
|
+
" vellum restore my-assistant --from backup.vbundle --version v1.2.3",
|
|
27
44
|
);
|
|
45
|
+
console.log(" vellum restore my-assistant --from backup.vbundle --dry-run");
|
|
28
46
|
}
|
|
29
47
|
|
|
30
48
|
function parseArgs(argv: string[]): {
|
|
31
49
|
name: string | undefined;
|
|
32
50
|
fromPath: string | undefined;
|
|
51
|
+
version: string | undefined;
|
|
33
52
|
dryRun: boolean;
|
|
34
53
|
help: boolean;
|
|
35
54
|
} {
|
|
36
55
|
const args = argv.slice(3);
|
|
37
56
|
|
|
38
57
|
if (args.includes("--help") || args.includes("-h")) {
|
|
39
|
-
return {
|
|
58
|
+
return {
|
|
59
|
+
name: undefined,
|
|
60
|
+
fromPath: undefined,
|
|
61
|
+
version: undefined,
|
|
62
|
+
dryRun: false,
|
|
63
|
+
help: true,
|
|
64
|
+
};
|
|
40
65
|
}
|
|
41
66
|
|
|
42
67
|
let fromPath: string | undefined;
|
|
68
|
+
let version: string | undefined;
|
|
43
69
|
const dryRun = args.includes("--dry-run");
|
|
44
70
|
const positionals: string[] = [];
|
|
45
71
|
|
|
@@ -47,6 +73,14 @@ function parseArgs(argv: string[]): {
|
|
|
47
73
|
if (args[i] === "--from" && args[i + 1]) {
|
|
48
74
|
fromPath = args[i + 1];
|
|
49
75
|
i++; // skip the value
|
|
76
|
+
} else if (args[i] === "--version") {
|
|
77
|
+
const next = args[i + 1];
|
|
78
|
+
if (!next || next.startsWith("-")) {
|
|
79
|
+
console.error("Error: --version requires a value");
|
|
80
|
+
process.exit(1);
|
|
81
|
+
}
|
|
82
|
+
version = next;
|
|
83
|
+
i++; // skip the value
|
|
50
84
|
} else if (args[i] === "--dry-run") {
|
|
51
85
|
// already handled above
|
|
52
86
|
} else if (!args[i].startsWith("-")) {
|
|
@@ -54,7 +88,7 @@ function parseArgs(argv: string[]): {
|
|
|
54
88
|
}
|
|
55
89
|
}
|
|
56
90
|
|
|
57
|
-
return { name: positionals[0], fromPath, dryRun, help: false };
|
|
91
|
+
return { name: positionals[0], fromPath, version, dryRun, help: false };
|
|
58
92
|
}
|
|
59
93
|
|
|
60
94
|
async function getAccessToken(
|
|
@@ -126,14 +160,289 @@ interface ImportResponse {
|
|
|
126
160
|
};
|
|
127
161
|
}
|
|
128
162
|
|
|
163
|
+
// ---------------------------------------------------------------------------
|
|
164
|
+
// Platform (Vellum-hosted) restore via Django migration import
|
|
165
|
+
// ---------------------------------------------------------------------------
|
|
166
|
+
|
|
167
|
+
async function restorePlatform(
|
|
168
|
+
entry: AssistantEntry,
|
|
169
|
+
name: string,
|
|
170
|
+
bundleData: Buffer,
|
|
171
|
+
opts: { version?: string; dryRun: boolean },
|
|
172
|
+
): Promise<void> {
|
|
173
|
+
// Step 1 — Authenticate
|
|
174
|
+
const token = readPlatformToken();
|
|
175
|
+
if (!token) {
|
|
176
|
+
console.error("Not logged in. Run 'vellum login' first.");
|
|
177
|
+
process.exit(1);
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
let orgId: string;
|
|
181
|
+
try {
|
|
182
|
+
orgId = await fetchOrganizationId(token);
|
|
183
|
+
} catch (err) {
|
|
184
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
185
|
+
if (msg.includes("401") || msg.includes("403")) {
|
|
186
|
+
console.error("Authentication failed. Run 'vellum login' to refresh.");
|
|
187
|
+
process.exit(1);
|
|
188
|
+
}
|
|
189
|
+
throw err;
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
// Step 2 — Dry-run path
|
|
193
|
+
if (opts.dryRun) {
|
|
194
|
+
if (opts.version) {
|
|
195
|
+
console.error(
|
|
196
|
+
"Dry-run is not supported with --version. Use `vellum restore --from <path> --dry-run` for data-only preflight.",
|
|
197
|
+
);
|
|
198
|
+
process.exit(1);
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
console.log("Running preflight analysis...\n");
|
|
202
|
+
|
|
203
|
+
let preflightResult: { statusCode: number; body: Record<string, unknown> };
|
|
204
|
+
try {
|
|
205
|
+
preflightResult = await platformImportPreflight(
|
|
206
|
+
new Uint8Array(bundleData),
|
|
207
|
+
token,
|
|
208
|
+
orgId,
|
|
209
|
+
);
|
|
210
|
+
} catch (err) {
|
|
211
|
+
if (err instanceof Error && err.name === "TimeoutError") {
|
|
212
|
+
console.error("Error: Preflight request timed out after 2 minutes.");
|
|
213
|
+
process.exit(1);
|
|
214
|
+
}
|
|
215
|
+
throw err;
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
if (
|
|
219
|
+
preflightResult.statusCode === 401 ||
|
|
220
|
+
preflightResult.statusCode === 403
|
|
221
|
+
) {
|
|
222
|
+
console.error("Authentication failed. Run 'vellum login' to refresh.");
|
|
223
|
+
process.exit(1);
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
if (preflightResult.statusCode === 404) {
|
|
227
|
+
console.error(
|
|
228
|
+
"No managed assistant found. Ensure your assistant is running.",
|
|
229
|
+
);
|
|
230
|
+
process.exit(1);
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
if (preflightResult.statusCode === 409) {
|
|
234
|
+
console.error(
|
|
235
|
+
"Multiple assistants found. This is a platform configuration issue.",
|
|
236
|
+
);
|
|
237
|
+
process.exit(1);
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
if (
|
|
241
|
+
preflightResult.statusCode === 502 ||
|
|
242
|
+
preflightResult.statusCode === 503 ||
|
|
243
|
+
preflightResult.statusCode === 504
|
|
244
|
+
) {
|
|
245
|
+
console.error(
|
|
246
|
+
`Assistant is unreachable. Try 'vellum wake ${name}' first.`,
|
|
247
|
+
);
|
|
248
|
+
process.exit(1);
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
if (preflightResult.statusCode !== 200) {
|
|
252
|
+
console.error(
|
|
253
|
+
`Error: Preflight check failed (${preflightResult.statusCode}): ${JSON.stringify(preflightResult.body)}`,
|
|
254
|
+
);
|
|
255
|
+
process.exit(1);
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
const result = preflightResult.body as unknown as PreflightResponse;
|
|
259
|
+
|
|
260
|
+
if (!result.can_import) {
|
|
261
|
+
if (result.validation?.errors?.length) {
|
|
262
|
+
console.error("Import blocked by validation errors:");
|
|
263
|
+
for (const err of result.validation.errors) {
|
|
264
|
+
console.error(
|
|
265
|
+
` - ${err.message}${err.path ? ` (${err.path})` : ""}`,
|
|
266
|
+
);
|
|
267
|
+
}
|
|
268
|
+
}
|
|
269
|
+
if (result.conflicts?.length) {
|
|
270
|
+
console.error("Import blocked by conflicts:");
|
|
271
|
+
for (const conflict of result.conflicts) {
|
|
272
|
+
console.error(
|
|
273
|
+
` - ${conflict.message}${conflict.path ? ` (${conflict.path})` : ""}`,
|
|
274
|
+
);
|
|
275
|
+
}
|
|
276
|
+
}
|
|
277
|
+
process.exit(1);
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
// Print summary table
|
|
281
|
+
const summary = result.summary ?? {
|
|
282
|
+
files_to_create: 0,
|
|
283
|
+
files_to_overwrite: 0,
|
|
284
|
+
files_unchanged: 0,
|
|
285
|
+
total_files: 0,
|
|
286
|
+
};
|
|
287
|
+
console.log("Preflight analysis:");
|
|
288
|
+
console.log(` Files to create: ${summary.files_to_create}`);
|
|
289
|
+
console.log(` Files to overwrite: ${summary.files_to_overwrite}`);
|
|
290
|
+
console.log(` Files unchanged: ${summary.files_unchanged}`);
|
|
291
|
+
console.log(` Total: ${summary.total_files}`);
|
|
292
|
+
console.log("");
|
|
293
|
+
|
|
294
|
+
const conflicts = result.conflicts ?? [];
|
|
295
|
+
console.log(
|
|
296
|
+
`Conflicts: ${conflicts.length > 0 ? conflicts.map((c) => c.message).join(", ") : "none"}`,
|
|
297
|
+
);
|
|
298
|
+
|
|
299
|
+
// List individual files with their action
|
|
300
|
+
if (result.files && result.files.length > 0) {
|
|
301
|
+
console.log("");
|
|
302
|
+
console.log("Files:");
|
|
303
|
+
for (const file of result.files) {
|
|
304
|
+
console.log(` [${file.action}] ${file.path}`);
|
|
305
|
+
}
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
return;
|
|
309
|
+
}
|
|
310
|
+
|
|
311
|
+
// Step 3 — Version rollback (if --version set)
|
|
312
|
+
if (opts.version) {
|
|
313
|
+
console.log(
|
|
314
|
+
`Rolling back to version ${opts.version} before restoring data...`,
|
|
315
|
+
);
|
|
316
|
+
|
|
317
|
+
try {
|
|
318
|
+
await rollbackPlatformAssistant(token, orgId, opts.version);
|
|
319
|
+
} catch (err) {
|
|
320
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
321
|
+
if (msg.includes("401") || msg.includes("403")) {
|
|
322
|
+
console.error("Authentication failed. Run 'vellum login' to refresh.");
|
|
323
|
+
process.exit(1);
|
|
324
|
+
}
|
|
325
|
+
console.error(`Error: Rollback failed — ${msg}`);
|
|
326
|
+
process.exit(1);
|
|
327
|
+
}
|
|
328
|
+
|
|
329
|
+
console.log(
|
|
330
|
+
`Rolled back to ${opts.version}. Proceeding with data restore...`,
|
|
331
|
+
);
|
|
332
|
+
}
|
|
333
|
+
|
|
334
|
+
// Step 4 — Data import
|
|
335
|
+
console.log("Importing backup data...");
|
|
336
|
+
|
|
337
|
+
let importResult: { statusCode: number; body: Record<string, unknown> };
|
|
338
|
+
try {
|
|
339
|
+
importResult = await platformImportBundle(
|
|
340
|
+
new Uint8Array(bundleData),
|
|
341
|
+
token,
|
|
342
|
+
orgId,
|
|
343
|
+
);
|
|
344
|
+
} catch (err) {
|
|
345
|
+
if (err instanceof Error && err.name === "TimeoutError") {
|
|
346
|
+
console.error("Error: Import request timed out after 2 minutes.");
|
|
347
|
+
process.exit(1);
|
|
348
|
+
}
|
|
349
|
+
throw err;
|
|
350
|
+
}
|
|
351
|
+
|
|
352
|
+
if (importResult.statusCode === 401 || importResult.statusCode === 403) {
|
|
353
|
+
console.error("Authentication failed. Run 'vellum login' to refresh.");
|
|
354
|
+
process.exit(1);
|
|
355
|
+
}
|
|
356
|
+
|
|
357
|
+
if (importResult.statusCode === 404) {
|
|
358
|
+
console.error(
|
|
359
|
+
"No managed assistant found. Ensure your assistant is running.",
|
|
360
|
+
);
|
|
361
|
+
process.exit(1);
|
|
362
|
+
}
|
|
363
|
+
|
|
364
|
+
if (importResult.statusCode === 409) {
|
|
365
|
+
console.error(
|
|
366
|
+
"Multiple assistants found. This is a platform configuration issue.",
|
|
367
|
+
);
|
|
368
|
+
process.exit(1);
|
|
369
|
+
}
|
|
370
|
+
|
|
371
|
+
if (
|
|
372
|
+
importResult.statusCode === 502 ||
|
|
373
|
+
importResult.statusCode === 503 ||
|
|
374
|
+
importResult.statusCode === 504
|
|
375
|
+
) {
|
|
376
|
+
console.error(`Assistant is unreachable. Try 'vellum wake ${name}' first.`);
|
|
377
|
+
process.exit(1);
|
|
378
|
+
}
|
|
379
|
+
|
|
380
|
+
if (importResult.statusCode < 200 || importResult.statusCode >= 300) {
|
|
381
|
+
console.error(`Error: Import failed (${importResult.statusCode})`);
|
|
382
|
+
process.exit(1);
|
|
383
|
+
}
|
|
384
|
+
|
|
385
|
+
const result = importResult.body as unknown as ImportResponse;
|
|
386
|
+
|
|
387
|
+
if (!result.success) {
|
|
388
|
+
console.error(
|
|
389
|
+
`Error: Import failed — ${result.message ?? result.reason ?? "unknown reason"}`,
|
|
390
|
+
);
|
|
391
|
+
for (const err of result.errors ?? []) {
|
|
392
|
+
console.error(` - ${err.message}${err.path ? ` (${err.path})` : ""}`);
|
|
393
|
+
}
|
|
394
|
+
process.exit(1);
|
|
395
|
+
}
|
|
396
|
+
|
|
397
|
+
// Print import report
|
|
398
|
+
const summary = result.summary ?? {
|
|
399
|
+
total_files: 0,
|
|
400
|
+
files_created: 0,
|
|
401
|
+
files_overwritten: 0,
|
|
402
|
+
files_skipped: 0,
|
|
403
|
+
backups_created: 0,
|
|
404
|
+
};
|
|
405
|
+
console.log("✅ Restore complete.");
|
|
406
|
+
console.log(` Files created: ${summary.files_created}`);
|
|
407
|
+
console.log(` Files overwritten: ${summary.files_overwritten}`);
|
|
408
|
+
console.log(` Files skipped: ${summary.files_skipped}`);
|
|
409
|
+
console.log(` Backups created: ${summary.backups_created}`);
|
|
410
|
+
|
|
411
|
+
// Print warnings if any
|
|
412
|
+
const warnings = result.warnings ?? [];
|
|
413
|
+
if (warnings.length > 0) {
|
|
414
|
+
console.log("");
|
|
415
|
+
console.log("Warnings:");
|
|
416
|
+
for (const warning of warnings) {
|
|
417
|
+
console.log(` ⚠️ ${warning}`);
|
|
418
|
+
}
|
|
419
|
+
}
|
|
420
|
+
}
|
|
421
|
+
|
|
129
422
|
export async function restore(): Promise<void> {
|
|
130
|
-
const { name, fromPath, dryRun, help } = parseArgs(process.argv);
|
|
423
|
+
const { name, fromPath, version, dryRun, help } = parseArgs(process.argv);
|
|
131
424
|
|
|
132
425
|
if (help) {
|
|
133
426
|
printUsage();
|
|
134
427
|
process.exit(0);
|
|
135
428
|
}
|
|
136
429
|
|
|
430
|
+
// --version requires --from
|
|
431
|
+
if (version && !fromPath) {
|
|
432
|
+
console.error(
|
|
433
|
+
"A backup file is required for restore. Use --from <path> to specify the .vbundle file.",
|
|
434
|
+
);
|
|
435
|
+
process.exit(1);
|
|
436
|
+
}
|
|
437
|
+
|
|
438
|
+
// --dry-run is not supported with --version
|
|
439
|
+
if (version && dryRun) {
|
|
440
|
+
console.error(
|
|
441
|
+
"Dry-run is not supported with --version. Use `vellum restore --from <path> --dry-run` for data-only preflight.",
|
|
442
|
+
);
|
|
443
|
+
process.exit(1);
|
|
444
|
+
}
|
|
445
|
+
|
|
137
446
|
if (!name || !fromPath) {
|
|
138
447
|
console.error("Error: Both <name> and --from <path> are required.");
|
|
139
448
|
console.error("");
|
|
@@ -160,8 +469,24 @@ export async function restore(): Promise<void> {
|
|
|
160
469
|
const sizeMB = (bundleData.byteLength / (1024 * 1024)).toFixed(2);
|
|
161
470
|
console.log(`Reading ${fromPath} (${sizeMB} MB)...`);
|
|
162
471
|
|
|
163
|
-
//
|
|
164
|
-
const
|
|
472
|
+
// Detect topology and route platform assistants through Django import
|
|
473
|
+
const cloud =
|
|
474
|
+
entry.cloud || (entry.project ? "gcp" : entry.sshUser ? "custom" : "local");
|
|
475
|
+
if (cloud === "vellum") {
|
|
476
|
+
await restorePlatform(entry, name, bundleData, { version, dryRun });
|
|
477
|
+
return;
|
|
478
|
+
}
|
|
479
|
+
|
|
480
|
+
if (version && cloud !== "docker") {
|
|
481
|
+
console.error(
|
|
482
|
+
"Restore with --version is only supported for Docker and managed assistants.",
|
|
483
|
+
);
|
|
484
|
+
process.exit(1);
|
|
485
|
+
}
|
|
486
|
+
|
|
487
|
+
// Obtain auth token (acquired before dry-run or before data import;
|
|
488
|
+
// re-acquired after version rollback since containers restart).
|
|
489
|
+
let accessToken = await getAccessToken(
|
|
165
490
|
entry.runtimeUrl,
|
|
166
491
|
entry.assistantId,
|
|
167
492
|
name,
|
|
@@ -215,13 +540,17 @@ export async function restore(): Promise<void> {
|
|
|
215
540
|
if (result.validation?.errors?.length) {
|
|
216
541
|
console.error("Import blocked by validation errors:");
|
|
217
542
|
for (const err of result.validation.errors) {
|
|
218
|
-
console.error(
|
|
543
|
+
console.error(
|
|
544
|
+
` - ${err.message}${err.path ? ` (${err.path})` : ""}`,
|
|
545
|
+
);
|
|
219
546
|
}
|
|
220
547
|
}
|
|
221
548
|
if (result.conflicts?.length) {
|
|
222
549
|
console.error("Import blocked by conflicts:");
|
|
223
550
|
for (const conflict of result.conflicts) {
|
|
224
|
-
console.error(
|
|
551
|
+
console.error(
|
|
552
|
+
` - ${conflict.message}${conflict.path ? ` (${conflict.path})` : ""}`,
|
|
553
|
+
);
|
|
225
554
|
}
|
|
226
555
|
}
|
|
227
556
|
process.exit(1);
|
|
@@ -255,8 +584,22 @@ export async function restore(): Promise<void> {
|
|
|
255
584
|
}
|
|
256
585
|
}
|
|
257
586
|
} else {
|
|
258
|
-
//
|
|
259
|
-
|
|
587
|
+
// Version rollback (when --version is specified)
|
|
588
|
+
if (version) {
|
|
589
|
+
console.log(`Rolling back to version ${version}...`);
|
|
590
|
+
await performDockerRollback(entry, { targetVersion: version });
|
|
591
|
+
console.log("");
|
|
592
|
+
|
|
593
|
+
// Re-acquire auth token since containers were restarted during rollback
|
|
594
|
+
accessToken = await getAccessToken(
|
|
595
|
+
entry.runtimeUrl,
|
|
596
|
+
entry.assistantId,
|
|
597
|
+
name,
|
|
598
|
+
);
|
|
599
|
+
}
|
|
600
|
+
|
|
601
|
+
// Data import
|
|
602
|
+
console.log("Importing backup data...\n");
|
|
260
603
|
|
|
261
604
|
let response: Response;
|
|
262
605
|
try {
|
package/src/commands/retire.ts
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import { spawn } from "child_process";
|
|
2
2
|
import { existsSync, mkdirSync, renameSync, writeFileSync } from "fs";
|
|
3
|
-
import { homedir } from "os";
|
|
4
3
|
import { basename, dirname, join } from "path";
|
|
5
4
|
|
|
6
5
|
import {
|
|
7
6
|
findAssistantByName,
|
|
7
|
+
getBaseDir,
|
|
8
8
|
loadAllAssistants,
|
|
9
9
|
removeAssistantEntry,
|
|
10
10
|
} from "../lib/assistant-config";
|
|
@@ -109,10 +109,10 @@ async function retireLocal(name: string, entry: AssistantEntry): Promise<void> {
|
|
|
109
109
|
await stopOrphanedDaemonProcesses();
|
|
110
110
|
}
|
|
111
111
|
|
|
112
|
-
// For named instances (instanceDir differs from
|
|
113
|
-
// remove the entire instance directory. For the default
|
|
114
|
-
//
|
|
115
|
-
const isNamedInstance = resources.instanceDir !==
|
|
112
|
+
// For named instances (instanceDir differs from the base directory),
|
|
113
|
+
// archive and remove the entire instance directory. For the default
|
|
114
|
+
// instance, archive only the .vellum subdirectory.
|
|
115
|
+
const isNamedInstance = resources.instanceDir !== getBaseDir();
|
|
116
116
|
const dirToArchive = isNamedInstance ? resources.instanceDir : vellumDir;
|
|
117
117
|
|
|
118
118
|
// Move the data directory out of the way so the path is immediately available
|