@vellumai/cli 0.6.0 → 0.6.1
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/package.json +1 -1
- package/src/__tests__/teleport.test.ts +4 -21
- package/src/__tests__/version-compat.test.ts +206 -0
- package/src/commands/backup.ts +1 -15
- package/src/commands/events.ts +146 -0
- package/src/commands/hatch.ts +1 -14
- package/src/commands/message.ts +105 -0
- package/src/commands/restore.ts +1 -21
- package/src/commands/retire.ts +2 -7
- package/src/commands/rollback.ts +8 -37
- package/src/commands/teleport.ts +18 -109
- package/src/commands/upgrade.ts +43 -43
- package/src/index.ts +6 -0
- package/src/lib/arg-utils.ts +13 -0
- package/src/lib/assistant-client.ts +228 -0
- package/src/lib/docker.ts +141 -49
- package/src/lib/hatch-local.ts +5 -2
- package/src/lib/health-check.ts +3 -8
- package/src/lib/ngrok.ts +11 -1
- package/src/lib/platform-client.ts +77 -56
- package/src/lib/upgrade-lifecycle.ts +5 -15
- package/src/lib/version-compat.ts +67 -5
package/src/commands/retire.ts
CHANGED
|
@@ -4,7 +4,7 @@ import {
|
|
|
4
4
|
} from "../lib/assistant-config";
|
|
5
5
|
import type { AssistantEntry } from "../lib/assistant-config";
|
|
6
6
|
import {
|
|
7
|
-
|
|
7
|
+
authHeaders,
|
|
8
8
|
getPlatformUrl,
|
|
9
9
|
readPlatformToken,
|
|
10
10
|
} from "../lib/platform-client";
|
|
@@ -93,16 +93,11 @@ async function retireVellum(
|
|
|
93
93
|
process.exit(1);
|
|
94
94
|
}
|
|
95
95
|
|
|
96
|
-
const orgId = await fetchOrganizationId(token, runtimeUrl);
|
|
97
|
-
|
|
98
96
|
const platformUrl = runtimeUrl || getPlatformUrl();
|
|
99
97
|
const url = `${platformUrl}/v1/assistants/${encodeURIComponent(assistantId)}/retire/`;
|
|
100
98
|
const response = await fetch(url, {
|
|
101
99
|
method: "DELETE",
|
|
102
|
-
headers:
|
|
103
|
-
"X-Session-Token": token,
|
|
104
|
-
"Vellum-Organization-Id": orgId,
|
|
105
|
-
},
|
|
100
|
+
headers: await authHeaders(token, runtimeUrl),
|
|
106
101
|
});
|
|
107
102
|
|
|
108
103
|
if (!response.ok) {
|
package/src/commands/rollback.ts
CHANGED
|
@@ -17,7 +17,6 @@ import {
|
|
|
17
17
|
import type { ServiceName } from "../lib/docker";
|
|
18
18
|
import { emitCliError, categorizeUpgradeError } from "../lib/cli-error.js";
|
|
19
19
|
import {
|
|
20
|
-
fetchOrganizationId,
|
|
21
20
|
readPlatformToken,
|
|
22
21
|
rollbackPlatformAssistant,
|
|
23
22
|
} from "../lib/platform-client.js";
|
|
@@ -35,7 +34,7 @@ import {
|
|
|
35
34
|
UPGRADE_PROGRESS,
|
|
36
35
|
waitForReady,
|
|
37
36
|
} from "../lib/upgrade-lifecycle.js";
|
|
38
|
-
import {
|
|
37
|
+
import { compareVersions } from "../lib/version-compat.js";
|
|
39
38
|
|
|
40
39
|
function parseArgs(): { name: string | null; version: string | null } {
|
|
41
40
|
const args = process.argv.slice(3);
|
|
@@ -153,21 +152,12 @@ async function rollbackPlatformViaEndpoint(
|
|
|
153
152
|
|
|
154
153
|
// Step 1 — Version validation (only if version provided)
|
|
155
154
|
if (version && currentVersion) {
|
|
156
|
-
const
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
(target.major === current.major &&
|
|
163
|
-
target.minor === current.minor &&
|
|
164
|
-
target.patch < current.patch);
|
|
165
|
-
if (!isOlder) {
|
|
166
|
-
const msg = `Target version ${version} is not older than the current version ${currentVersion}. Use \`vellum upgrade --version ${version}\` to upgrade.`;
|
|
167
|
-
console.error(msg);
|
|
168
|
-
emitCliError("VERSION_DIRECTION", msg);
|
|
169
|
-
process.exit(1);
|
|
170
|
-
}
|
|
155
|
+
const cmp = compareVersions(version, currentVersion);
|
|
156
|
+
if (cmp !== null && cmp >= 0) {
|
|
157
|
+
const msg = `Target version ${version} is not older than the current version ${currentVersion}. Use \`vellum upgrade --version ${version}\` to upgrade.`;
|
|
158
|
+
console.error(msg);
|
|
159
|
+
emitCliError("VERSION_DIRECTION", msg);
|
|
160
|
+
process.exit(1);
|
|
171
161
|
}
|
|
172
162
|
}
|
|
173
163
|
|
|
@@ -181,20 +171,6 @@ async function rollbackPlatformViaEndpoint(
|
|
|
181
171
|
process.exit(1);
|
|
182
172
|
}
|
|
183
173
|
|
|
184
|
-
let orgId: string;
|
|
185
|
-
try {
|
|
186
|
-
orgId = await fetchOrganizationId(token, entry.runtimeUrl);
|
|
187
|
-
} catch (err) {
|
|
188
|
-
const msg = err instanceof Error ? err.message : String(err);
|
|
189
|
-
if (msg.includes("401") || msg.includes("403")) {
|
|
190
|
-
console.error("Authentication failed. Run 'vellum login' to refresh.");
|
|
191
|
-
} else {
|
|
192
|
-
console.error(`Error: ${msg}`);
|
|
193
|
-
}
|
|
194
|
-
emitCliError("AUTH_FAILED", "Failed to authenticate with platform", msg);
|
|
195
|
-
process.exit(1);
|
|
196
|
-
}
|
|
197
|
-
|
|
198
174
|
// Step 3 — Call rollback endpoint
|
|
199
175
|
if (version) {
|
|
200
176
|
console.log(`Rolling back to ${version}...`);
|
|
@@ -204,12 +180,7 @@ async function rollbackPlatformViaEndpoint(
|
|
|
204
180
|
|
|
205
181
|
let result: { detail: string; version: string | null };
|
|
206
182
|
try {
|
|
207
|
-
result = await rollbackPlatformAssistant(
|
|
208
|
-
token,
|
|
209
|
-
orgId,
|
|
210
|
-
version,
|
|
211
|
-
entry.runtimeUrl,
|
|
212
|
-
);
|
|
183
|
+
result = await rollbackPlatformAssistant(token, version, entry.runtimeUrl);
|
|
213
184
|
} catch (err) {
|
|
214
185
|
const detail = err instanceof Error ? err.message : String(err);
|
|
215
186
|
|
package/src/commands/teleport.ts
CHANGED
|
@@ -12,7 +12,6 @@ import {
|
|
|
12
12
|
} from "../lib/guardian-token.js";
|
|
13
13
|
import {
|
|
14
14
|
readPlatformToken,
|
|
15
|
-
fetchOrganizationId,
|
|
16
15
|
getPlatformUrl,
|
|
17
16
|
hatchAssistant,
|
|
18
17
|
platformInitiateExport,
|
|
@@ -423,7 +422,7 @@ async function importViaHttp(
|
|
|
423
422
|
"Content-Type": "application/octet-stream",
|
|
424
423
|
},
|
|
425
424
|
body: new Blob([bundleData]),
|
|
426
|
-
signal: AbortSignal.timeout(
|
|
425
|
+
signal: AbortSignal.timeout(300_000),
|
|
427
426
|
});
|
|
428
427
|
|
|
429
428
|
// Retry once with a fresh token on 401
|
|
@@ -447,13 +446,13 @@ async function importViaHttp(
|
|
|
447
446
|
"Content-Type": "application/octet-stream",
|
|
448
447
|
},
|
|
449
448
|
body: new Blob([bundleData]),
|
|
450
|
-
signal: AbortSignal.timeout(
|
|
449
|
+
signal: AbortSignal.timeout(300_000),
|
|
451
450
|
});
|
|
452
451
|
}
|
|
453
452
|
}
|
|
454
453
|
} catch (err) {
|
|
455
454
|
if (err instanceof Error && err.name === "TimeoutError") {
|
|
456
|
-
console.error("Error: Import request timed out after
|
|
455
|
+
console.error("Error: Import request timed out after 5 minutes.");
|
|
457
456
|
process.exit(1);
|
|
458
457
|
}
|
|
459
458
|
const msg = err instanceof Error ? err.message : String(err);
|
|
@@ -489,36 +488,12 @@ async function exportFromAssistant(
|
|
|
489
488
|
process.exit(1);
|
|
490
489
|
}
|
|
491
490
|
|
|
492
|
-
let orgId: string;
|
|
493
|
-
try {
|
|
494
|
-
orgId = await fetchOrganizationId(token, entry.runtimeUrl);
|
|
495
|
-
} catch (err) {
|
|
496
|
-
const msg = err instanceof Error ? err.message : String(err);
|
|
497
|
-
if (msg.includes("401") || msg.includes("403")) {
|
|
498
|
-
console.error("Authentication failed. Run 'vellum login' to refresh.");
|
|
499
|
-
process.exit(1);
|
|
500
|
-
}
|
|
501
|
-
throw err;
|
|
502
|
-
}
|
|
503
|
-
|
|
504
491
|
// Initiate export job
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
"teleport export",
|
|
511
|
-
entry.runtimeUrl,
|
|
512
|
-
);
|
|
513
|
-
jobId = result.jobId;
|
|
514
|
-
} catch (err) {
|
|
515
|
-
const msg = err instanceof Error ? err.message : String(err);
|
|
516
|
-
if (msg.includes("401") || msg.includes("403")) {
|
|
517
|
-
console.error("Authentication failed. Run 'vellum login' to refresh.");
|
|
518
|
-
process.exit(1);
|
|
519
|
-
}
|
|
520
|
-
throw err;
|
|
521
|
-
}
|
|
492
|
+
const { jobId } = await platformInitiateExport(
|
|
493
|
+
token,
|
|
494
|
+
"teleport export",
|
|
495
|
+
entry.runtimeUrl,
|
|
496
|
+
);
|
|
522
497
|
|
|
523
498
|
console.log(`Export started (job ${jobId})...`);
|
|
524
499
|
|
|
@@ -531,12 +506,7 @@ async function exportFromAssistant(
|
|
|
531
506
|
while (Date.now() < deadline) {
|
|
532
507
|
let status: { status: string; downloadUrl?: string; error?: string };
|
|
533
508
|
try {
|
|
534
|
-
status = await platformPollExportStatus(
|
|
535
|
-
jobId,
|
|
536
|
-
token,
|
|
537
|
-
orgId,
|
|
538
|
-
entry.runtimeUrl,
|
|
539
|
-
);
|
|
509
|
+
status = await platformPollExportStatus(jobId, token, entry.runtimeUrl);
|
|
540
510
|
} catch (err) {
|
|
541
511
|
const msg = err instanceof Error ? err.message : String(err);
|
|
542
512
|
if (msg.includes("not found")) {
|
|
@@ -642,18 +612,6 @@ async function importToAssistant(
|
|
|
642
612
|
process.exit(1);
|
|
643
613
|
}
|
|
644
614
|
|
|
645
|
-
let orgId: string;
|
|
646
|
-
try {
|
|
647
|
-
orgId = await fetchOrganizationId(token, entry.runtimeUrl);
|
|
648
|
-
} catch (err) {
|
|
649
|
-
const msg = err instanceof Error ? err.message : String(err);
|
|
650
|
-
if (msg.includes("401") || msg.includes("403")) {
|
|
651
|
-
console.error("Authentication failed. Run 'vellum login' to refresh.");
|
|
652
|
-
process.exit(1);
|
|
653
|
-
}
|
|
654
|
-
throw err;
|
|
655
|
-
}
|
|
656
|
-
|
|
657
615
|
// Use pre-uploaded bundle key if provided (string), skip upload if null
|
|
658
616
|
// (signals signed URLs were already tried and unavailable), or try
|
|
659
617
|
// signed-URL upload if undefined (never attempted).
|
|
@@ -663,7 +621,6 @@ async function importToAssistant(
|
|
|
663
621
|
try {
|
|
664
622
|
const { uploadUrl, bundleKey: key } = await platformRequestUploadUrl(
|
|
665
623
|
token,
|
|
666
|
-
orgId,
|
|
667
624
|
entry.runtimeUrl,
|
|
668
625
|
);
|
|
669
626
|
bundleKey = key;
|
|
@@ -692,15 +649,9 @@ async function importToAssistant(
|
|
|
692
649
|
? await platformImportPreflightFromGcs(
|
|
693
650
|
bundleKey,
|
|
694
651
|
token,
|
|
695
|
-
orgId,
|
|
696
652
|
entry.runtimeUrl,
|
|
697
653
|
)
|
|
698
|
-
: await platformImportPreflight(
|
|
699
|
-
bundleData,
|
|
700
|
-
token,
|
|
701
|
-
orgId,
|
|
702
|
-
entry.runtimeUrl,
|
|
703
|
-
);
|
|
654
|
+
: await platformImportPreflight(bundleData, token, entry.runtimeUrl);
|
|
704
655
|
} catch (err) {
|
|
705
656
|
if (err instanceof Error && err.name === "TimeoutError") {
|
|
706
657
|
console.error("Error: Preflight request timed out after 2 minutes.");
|
|
@@ -751,21 +702,11 @@ async function importToAssistant(
|
|
|
751
702
|
let importResult: { statusCode: number; body: Record<string, unknown> };
|
|
752
703
|
try {
|
|
753
704
|
importResult = bundleKey
|
|
754
|
-
? await platformImportBundleFromGcs(
|
|
755
|
-
|
|
756
|
-
token,
|
|
757
|
-
orgId,
|
|
758
|
-
entry.runtimeUrl,
|
|
759
|
-
)
|
|
760
|
-
: await platformImportBundle(
|
|
761
|
-
bundleData,
|
|
762
|
-
token,
|
|
763
|
-
orgId,
|
|
764
|
-
entry.runtimeUrl,
|
|
765
|
-
);
|
|
705
|
+
? await platformImportBundleFromGcs(bundleKey, token, entry.runtimeUrl)
|
|
706
|
+
: await platformImportBundle(bundleData, token, entry.runtimeUrl);
|
|
766
707
|
} catch (err) {
|
|
767
708
|
if (err instanceof Error && err.name === "TimeoutError") {
|
|
768
|
-
console.error("Error: Import request timed out after
|
|
709
|
+
console.error("Error: Import request timed out after 5 minutes.");
|
|
769
710
|
process.exit(1);
|
|
770
711
|
}
|
|
771
712
|
throw err;
|
|
@@ -796,7 +737,6 @@ async function importToAssistant(
|
|
|
796
737
|
export async function resolveOrHatchTarget(
|
|
797
738
|
targetEnv: "local" | "docker" | "platform",
|
|
798
739
|
targetName?: string,
|
|
799
|
-
orgId?: string,
|
|
800
740
|
): Promise<AssistantEntry> {
|
|
801
741
|
// If a name is provided, try to find an existing assistant
|
|
802
742
|
if (targetName) {
|
|
@@ -876,25 +816,7 @@ export async function resolveOrHatchTarget(
|
|
|
876
816
|
process.exit(1);
|
|
877
817
|
}
|
|
878
818
|
|
|
879
|
-
|
|
880
|
-
if (orgId) {
|
|
881
|
-
resolvedOrgId = orgId;
|
|
882
|
-
} else {
|
|
883
|
-
try {
|
|
884
|
-
resolvedOrgId = await fetchOrganizationId(token);
|
|
885
|
-
} catch (err) {
|
|
886
|
-
const msg = err instanceof Error ? err.message : String(err);
|
|
887
|
-
if (msg.includes("401") || msg.includes("403")) {
|
|
888
|
-
console.error(
|
|
889
|
-
"Authentication failed. Run 'vellum login' to refresh.",
|
|
890
|
-
);
|
|
891
|
-
process.exit(1);
|
|
892
|
-
}
|
|
893
|
-
throw err;
|
|
894
|
-
}
|
|
895
|
-
}
|
|
896
|
-
|
|
897
|
-
const result = await hatchAssistant(token, resolvedOrgId);
|
|
819
|
+
const result = await hatchAssistant(token);
|
|
898
820
|
const entry: AssistantEntry = {
|
|
899
821
|
assistantId: result.id,
|
|
900
822
|
runtimeUrl: getPlatformUrl(),
|
|
@@ -1170,7 +1092,7 @@ export async function teleport(): Promise<void> {
|
|
|
1170
1092
|
// Platform target: reordered flow — upload to GCS before hatching so that
|
|
1171
1093
|
// if upload fails, no empty assistant is left dangling on the platform.
|
|
1172
1094
|
if (targetEnv === "platform") {
|
|
1173
|
-
// Step B — Auth
|
|
1095
|
+
// Step B — Auth
|
|
1174
1096
|
const token = readPlatformToken();
|
|
1175
1097
|
if (!token) {
|
|
1176
1098
|
console.error("Not logged in. Run 'vellum login' first.");
|
|
@@ -1191,22 +1113,10 @@ export async function teleport(): Promise<void> {
|
|
|
1191
1113
|
}
|
|
1192
1114
|
}
|
|
1193
1115
|
|
|
1194
|
-
// Use the existing target's runtimeUrl for all platform calls so upload
|
|
1195
|
-
//
|
|
1116
|
+
// Use the existing target's runtimeUrl for all platform calls so upload
|
|
1117
|
+
// and import hit the same instance.
|
|
1196
1118
|
const targetPlatformUrl = existingTarget?.runtimeUrl;
|
|
1197
1119
|
|
|
1198
|
-
let orgId: string;
|
|
1199
|
-
try {
|
|
1200
|
-
orgId = await fetchOrganizationId(token, targetPlatformUrl);
|
|
1201
|
-
} catch (err) {
|
|
1202
|
-
const msg = err instanceof Error ? err.message : String(err);
|
|
1203
|
-
if (msg.includes("401") || msg.includes("403")) {
|
|
1204
|
-
console.error("Authentication failed. Run 'vellum login' to refresh.");
|
|
1205
|
-
process.exit(1);
|
|
1206
|
-
}
|
|
1207
|
-
throw err;
|
|
1208
|
-
}
|
|
1209
|
-
|
|
1210
1120
|
// Step C — Upload to GCS
|
|
1211
1121
|
// bundleKey: string = uploaded successfully, null = tried but unavailable,
|
|
1212
1122
|
// undefined would mean "never tried" (not used here).
|
|
@@ -1214,7 +1124,6 @@ export async function teleport(): Promise<void> {
|
|
|
1214
1124
|
try {
|
|
1215
1125
|
const { uploadUrl, bundleKey: key } = await platformRequestUploadUrl(
|
|
1216
1126
|
token,
|
|
1217
|
-
orgId,
|
|
1218
1127
|
targetPlatformUrl,
|
|
1219
1128
|
);
|
|
1220
1129
|
bundleKey = key;
|
|
@@ -1231,7 +1140,7 @@ export async function teleport(): Promise<void> {
|
|
|
1231
1140
|
}
|
|
1232
1141
|
|
|
1233
1142
|
// Step D — Hatch (upload succeeded or fallback to inline — safe to hatch)
|
|
1234
|
-
const toEntry = await resolveOrHatchTarget(targetEnv, targetName
|
|
1143
|
+
const toEntry = await resolveOrHatchTarget(targetEnv, targetName);
|
|
1235
1144
|
const toCloud = resolveCloud(toEntry);
|
|
1236
1145
|
|
|
1237
1146
|
// Step E — Import from GCS (or inline fallback)
|
package/src/commands/upgrade.ts
CHANGED
|
@@ -18,7 +18,7 @@ import {
|
|
|
18
18
|
} from "../lib/docker";
|
|
19
19
|
import { resolveImageRefs } from "../lib/platform-releases";
|
|
20
20
|
import {
|
|
21
|
-
|
|
21
|
+
authHeaders,
|
|
22
22
|
getPlatformUrl,
|
|
23
23
|
readPlatformToken,
|
|
24
24
|
} from "../lib/platform-client";
|
|
@@ -42,7 +42,7 @@ import {
|
|
|
42
42
|
UPGRADE_PROGRESS,
|
|
43
43
|
waitForReady,
|
|
44
44
|
} from "../lib/upgrade-lifecycle.js";
|
|
45
|
-
import {
|
|
45
|
+
import { compareVersions } from "../lib/version-compat.js";
|
|
46
46
|
|
|
47
47
|
interface UpgradeArgs {
|
|
48
48
|
name: string | null;
|
|
@@ -193,21 +193,12 @@ async function upgradeDocker(
|
|
|
193
193
|
// Users should use `vellum rollback --version <version>` for downgrades.
|
|
194
194
|
const currentVersion = entry.serviceGroupVersion;
|
|
195
195
|
if (currentVersion && versionTag) {
|
|
196
|
-
const
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
(target.major === current.major &&
|
|
203
|
-
target.minor === current.minor &&
|
|
204
|
-
target.patch < current.patch);
|
|
205
|
-
if (isOlder) {
|
|
206
|
-
const msg = `Cannot upgrade to an older version (${versionTag} < ${currentVersion}). Use \`vellum rollback --version ${versionTag}\` instead.`;
|
|
207
|
-
console.error(msg);
|
|
208
|
-
emitCliError("VERSION_DIRECTION", msg);
|
|
209
|
-
process.exit(1);
|
|
210
|
-
}
|
|
196
|
+
const cmp = compareVersions(versionTag, currentVersion);
|
|
197
|
+
if (cmp !== null && cmp < 0) {
|
|
198
|
+
const msg = `Cannot upgrade to an older version (${versionTag} < ${currentVersion}). Use \`vellum rollback --version ${versionTag}\` instead.`;
|
|
199
|
+
console.error(msg);
|
|
200
|
+
emitCliError("VERSION_DIRECTION", msg);
|
|
201
|
+
process.exit(1);
|
|
211
202
|
}
|
|
212
203
|
}
|
|
213
204
|
|
|
@@ -694,21 +685,12 @@ async function upgradePlatform(
|
|
|
694
685
|
// we must not block the request based on the local CLI version.
|
|
695
686
|
const currentVersion = entry.serviceGroupVersion;
|
|
696
687
|
if (version && currentVersion) {
|
|
697
|
-
const
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
(target.major === current.major &&
|
|
704
|
-
target.minor === current.minor &&
|
|
705
|
-
target.patch < current.patch);
|
|
706
|
-
if (isOlder) {
|
|
707
|
-
const msg = `Cannot upgrade to an older version (${version} < ${currentVersion}). Use \`vellum rollback --version ${version}\` instead.`;
|
|
708
|
-
console.error(msg);
|
|
709
|
-
emitCliError("VERSION_DIRECTION", msg);
|
|
710
|
-
process.exit(1);
|
|
711
|
-
}
|
|
688
|
+
const cmp = compareVersions(version, currentVersion);
|
|
689
|
+
if (cmp !== null && cmp < 0) {
|
|
690
|
+
const msg = `Cannot upgrade to an older version (${version} < ${currentVersion}). Use \`vellum rollback --version ${version}\` instead.`;
|
|
691
|
+
console.error(msg);
|
|
692
|
+
emitCliError("VERSION_DIRECTION", msg);
|
|
693
|
+
process.exit(1);
|
|
712
694
|
}
|
|
713
695
|
}
|
|
714
696
|
|
|
@@ -725,7 +707,7 @@ async function upgradePlatform(
|
|
|
725
707
|
process.exit(1);
|
|
726
708
|
}
|
|
727
709
|
|
|
728
|
-
const
|
|
710
|
+
const headers = await authHeaders(token, entry.runtimeUrl);
|
|
729
711
|
|
|
730
712
|
const url = `${entry.runtimeUrl || getPlatformUrl()}/v1/assistants/upgrade/`;
|
|
731
713
|
const body: { assistant_id?: string; version?: string } = {
|
|
@@ -737,14 +719,28 @@ async function upgradePlatform(
|
|
|
737
719
|
|
|
738
720
|
const response = await fetch(url, {
|
|
739
721
|
method: "POST",
|
|
740
|
-
headers
|
|
741
|
-
"Content-Type": "application/json",
|
|
742
|
-
"X-Session-Token": token,
|
|
743
|
-
"Vellum-Organization-Id": orgId,
|
|
744
|
-
},
|
|
722
|
+
headers,
|
|
745
723
|
body: JSON.stringify(body),
|
|
746
724
|
});
|
|
747
725
|
|
|
726
|
+
if (response.status === 401 || response.status === 403) {
|
|
727
|
+
const text = await response.text();
|
|
728
|
+
console.error(
|
|
729
|
+
`Authentication failed (${response.status}). Run 'vellum login' to refresh.`,
|
|
730
|
+
);
|
|
731
|
+
emitCliError("AUTH_FAILED", "Authentication failed", text);
|
|
732
|
+
try {
|
|
733
|
+
await broadcastUpgradeEvent(
|
|
734
|
+
entry.runtimeUrl,
|
|
735
|
+
entry.assistantId,
|
|
736
|
+
buildCompleteEvent(entry.serviceGroupVersion ?? "unknown", false),
|
|
737
|
+
);
|
|
738
|
+
} catch {
|
|
739
|
+
// Best-effort — broadcast may fail if the assistant is unreachable
|
|
740
|
+
}
|
|
741
|
+
process.exit(1);
|
|
742
|
+
}
|
|
743
|
+
|
|
748
744
|
if (!response.ok) {
|
|
749
745
|
const text = await response.text();
|
|
750
746
|
console.error(
|
|
@@ -755,11 +751,15 @@ async function upgradePlatform(
|
|
|
755
751
|
`Platform upgrade failed (${response.status})`,
|
|
756
752
|
text,
|
|
757
753
|
);
|
|
758
|
-
|
|
759
|
-
|
|
760
|
-
|
|
761
|
-
|
|
762
|
-
|
|
754
|
+
try {
|
|
755
|
+
await broadcastUpgradeEvent(
|
|
756
|
+
entry.runtimeUrl,
|
|
757
|
+
entry.assistantId,
|
|
758
|
+
buildCompleteEvent(entry.serviceGroupVersion ?? "unknown", false),
|
|
759
|
+
);
|
|
760
|
+
} catch {
|
|
761
|
+
// Best-effort — broadcast may fail if the assistant is unreachable
|
|
762
|
+
}
|
|
763
763
|
process.exit(1);
|
|
764
764
|
}
|
|
765
765
|
|
package/src/index.ts
CHANGED
|
@@ -4,8 +4,10 @@ import cliPkg from "../package.json";
|
|
|
4
4
|
import { backup } from "./commands/backup";
|
|
5
5
|
import { clean } from "./commands/clean";
|
|
6
6
|
import { client } from "./commands/client";
|
|
7
|
+
import { events } from "./commands/events";
|
|
7
8
|
import { hatch } from "./commands/hatch";
|
|
8
9
|
import { login, logout, whoami } from "./commands/login";
|
|
10
|
+
import { message } from "./commands/message";
|
|
9
11
|
import { pair } from "./commands/pair";
|
|
10
12
|
import { ps } from "./commands/ps";
|
|
11
13
|
import { recover } from "./commands/recover";
|
|
@@ -33,9 +35,11 @@ const commands = {
|
|
|
33
35
|
backup,
|
|
34
36
|
clean,
|
|
35
37
|
client,
|
|
38
|
+
events,
|
|
36
39
|
hatch,
|
|
37
40
|
login,
|
|
38
41
|
logout,
|
|
42
|
+
message,
|
|
39
43
|
pair,
|
|
40
44
|
ps,
|
|
41
45
|
recover,
|
|
@@ -62,9 +66,11 @@ function printHelp(): void {
|
|
|
62
66
|
console.log(" backup Export a backup of a running assistant");
|
|
63
67
|
console.log(" clean Kill orphaned vellum processes");
|
|
64
68
|
console.log(" client Connect to a hatched assistant");
|
|
69
|
+
console.log(" events Stream events from a running assistant");
|
|
65
70
|
console.log(" hatch Create a new assistant instance");
|
|
66
71
|
console.log(" login Log in to the Vellum platform");
|
|
67
72
|
console.log(" logout Log out of the Vellum platform");
|
|
73
|
+
console.log(" message Send a message to a running assistant");
|
|
68
74
|
console.log(" pair Pair with a remote assistant via QR code");
|
|
69
75
|
console.log(
|
|
70
76
|
" ps List assistants (or processes for a specific assistant)",
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/** Extract a named flag's value from an arg list, returning [value, remaining]. */
|
|
2
|
+
export function extractFlag(
|
|
3
|
+
args: string[],
|
|
4
|
+
flag: string,
|
|
5
|
+
): [string | undefined, string[]] {
|
|
6
|
+
const idx = args.indexOf(flag);
|
|
7
|
+
if (idx === -1 || idx + 1 >= args.length) {
|
|
8
|
+
return [undefined, args.filter((a) => a !== flag)];
|
|
9
|
+
}
|
|
10
|
+
const value = args[idx + 1]!;
|
|
11
|
+
const remaining = [...args.slice(0, idx), ...args.slice(idx + 2)];
|
|
12
|
+
return [value, remaining];
|
|
13
|
+
}
|