@vellumai/cli 0.7.0 ā 0.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.
- package/AGENTS.md +3 -11
- package/README.md +49 -0
- package/bun.lock +0 -15
- package/package.json +1 -6
- package/src/__tests__/backup.test.ts +591 -0
- package/src/__tests__/config-utils.test.ts +35 -48
- package/src/__tests__/teleport.test.ts +597 -37
- package/src/commands/backup.ts +149 -70
- package/src/commands/client.ts +56 -14
- package/src/commands/events.ts +3 -0
- package/src/commands/exec.ts +34 -12
- package/src/commands/hatch.ts +3 -7
- package/src/commands/login.ts +15 -33
- package/src/commands/logs.ts +2 -7
- package/src/commands/ps.ts +41 -6
- package/src/commands/restore.ts +32 -47
- package/src/commands/setup.ts +38 -73
- package/src/commands/ssh.ts +2 -5
- package/src/commands/teleport.ts +148 -34
- package/src/commands/tunnel.ts +2 -7
- package/src/commands/upgrade.ts +114 -7
- package/src/commands/wake.ts +5 -16
- package/src/components/DefaultMainScreen.tsx +65 -129
- package/src/index.ts +2 -13
- package/src/lib/__tests__/docker.test.ts +50 -32
- package/src/lib/__tests__/local-runtime-client.test.ts +308 -25
- package/src/lib/__tests__/platform-client-signed-url.test.ts +237 -2
- package/src/lib/__tests__/runtime-url.test.ts +125 -0
- package/src/lib/__tests__/terminal-session.test.ts +202 -0
- package/src/lib/assistant-client.ts +18 -26
- package/src/lib/assistant-config.ts +34 -41
- package/src/lib/backup-ops.ts +43 -17
- package/src/lib/cli-error.ts +1 -0
- package/src/lib/client-identity.ts +1 -1
- package/src/lib/config-utils.ts +1 -97
- package/src/lib/docker-statefulset.ts +381 -0
- package/src/lib/docker.ts +8 -247
- package/src/lib/guardian-token.ts +56 -6
- package/src/lib/hatch-local.ts +3 -26
- package/src/lib/job-polling.ts +1 -1
- package/src/lib/local-runtime-client.ts +162 -28
- package/src/lib/local.ts +35 -64
- package/src/lib/ngrok.ts +36 -26
- package/src/lib/platform-client.ts +97 -221
- package/src/lib/platform-releases.ts +23 -0
- package/src/lib/retire-local.ts +2 -2
- package/src/lib/runtime-url.ts +52 -0
- package/src/lib/sync-cloud-assistants.ts +126 -0
- package/src/lib/terminal-client.ts +6 -1
- package/src/lib/terminal-session.ts +127 -48
- package/src/lib/tui-log.ts +60 -0
- package/src/lib/upgrade-lifecycle.ts +65 -0
- package/src/lib/xdg-log.ts +10 -4
- package/src/commands/pair.ts +0 -212
package/src/commands/tunnel.ts
CHANGED
|
@@ -1,7 +1,4 @@
|
|
|
1
|
-
import {
|
|
2
|
-
findAssistantByName,
|
|
3
|
-
loadLatestAssistant,
|
|
4
|
-
} from "../lib/assistant-config";
|
|
1
|
+
import { resolveAssistant } from "../lib/assistant-config";
|
|
5
2
|
import { runNgrokTunnel } from "../lib/ngrok";
|
|
6
3
|
|
|
7
4
|
const VALID_PROVIDERS = ["vellum", "ngrok", "cloudflare", "tailscale"] as const;
|
|
@@ -63,9 +60,7 @@ function parseArgs(): TunnelArgs {
|
|
|
63
60
|
export async function tunnel(): Promise<void> {
|
|
64
61
|
const { assistantName, provider } = parseArgs();
|
|
65
62
|
|
|
66
|
-
const entry = assistantName
|
|
67
|
-
? findAssistantByName(assistantName)
|
|
68
|
-
: loadLatestAssistant();
|
|
63
|
+
const entry = resolveAssistant(assistantName ?? undefined);
|
|
69
64
|
|
|
70
65
|
if (!entry) {
|
|
71
66
|
if (assistantName) {
|
package/src/commands/upgrade.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { randomBytes } from "crypto";
|
|
2
|
+
import { spawnSync } from "child_process";
|
|
2
3
|
|
|
3
4
|
import cliPkg from "../../package.json";
|
|
4
5
|
|
|
@@ -16,7 +17,10 @@ import {
|
|
|
16
17
|
startContainers,
|
|
17
18
|
stopContainers,
|
|
18
19
|
} from "../lib/docker";
|
|
19
|
-
import {
|
|
20
|
+
import {
|
|
21
|
+
fetchLatestStableVersion,
|
|
22
|
+
resolveImageRefs,
|
|
23
|
+
} from "../lib/platform-releases";
|
|
20
24
|
import {
|
|
21
25
|
authHeaders,
|
|
22
26
|
getPlatformUrl,
|
|
@@ -36,6 +40,7 @@ import {
|
|
|
36
40
|
buildStartingEvent,
|
|
37
41
|
buildUpgradeCommitMessage,
|
|
38
42
|
captureContainerEnv,
|
|
43
|
+
captureUpgradeFailureLogs,
|
|
39
44
|
commitWorkspaceViaGateway,
|
|
40
45
|
CONTAINER_ENV_EXCLUDE_KEYS,
|
|
41
46
|
rollbackMigrations,
|
|
@@ -47,6 +52,7 @@ import { compareVersions } from "../lib/version-compat.js";
|
|
|
47
52
|
interface UpgradeArgs {
|
|
48
53
|
name: string | null;
|
|
49
54
|
version: string | null;
|
|
55
|
+
latest: boolean;
|
|
50
56
|
prepare: boolean;
|
|
51
57
|
finalize: boolean;
|
|
52
58
|
}
|
|
@@ -55,6 +61,7 @@ function parseArgs(): UpgradeArgs {
|
|
|
55
61
|
const args = process.argv.slice(3);
|
|
56
62
|
let name: string | null = null;
|
|
57
63
|
let version: string | null = null;
|
|
64
|
+
let latest = false;
|
|
58
65
|
let prepare = false;
|
|
59
66
|
let finalize = false;
|
|
60
67
|
|
|
@@ -73,7 +80,10 @@ function parseArgs(): UpgradeArgs {
|
|
|
73
80
|
console.log("");
|
|
74
81
|
console.log("Options:");
|
|
75
82
|
console.log(
|
|
76
|
-
" --version <version> Target version to upgrade to (default:
|
|
83
|
+
" --version <version> Target version to upgrade to (default: CLI version)",
|
|
84
|
+
);
|
|
85
|
+
console.log(
|
|
86
|
+
" --latest Upgrade to the latest stable release, updating the CLI first if needed",
|
|
77
87
|
);
|
|
78
88
|
console.log(
|
|
79
89
|
" --prepare Run pre-upgrade steps only (backup, notify) without swapping versions",
|
|
@@ -84,7 +94,10 @@ function parseArgs(): UpgradeArgs {
|
|
|
84
94
|
console.log("");
|
|
85
95
|
console.log("Examples:");
|
|
86
96
|
console.log(
|
|
87
|
-
" vellum upgrade # Upgrade the active assistant to the
|
|
97
|
+
" vellum upgrade # Upgrade the active assistant to the CLI's version",
|
|
98
|
+
);
|
|
99
|
+
console.log(
|
|
100
|
+
" vellum upgrade --latest # Upgrade CLI + assistant to the latest stable release",
|
|
88
101
|
);
|
|
89
102
|
console.log(
|
|
90
103
|
" vellum upgrade my-assistant # Upgrade a specific assistant by name",
|
|
@@ -102,6 +115,8 @@ function parseArgs(): UpgradeArgs {
|
|
|
102
115
|
}
|
|
103
116
|
version = next;
|
|
104
117
|
i++;
|
|
118
|
+
} else if (arg === "--latest") {
|
|
119
|
+
latest = true;
|
|
105
120
|
} else if (arg === "--prepare") {
|
|
106
121
|
prepare = true;
|
|
107
122
|
} else if (arg === "--finalize") {
|
|
@@ -121,7 +136,13 @@ function parseArgs(): UpgradeArgs {
|
|
|
121
136
|
process.exit(1);
|
|
122
137
|
}
|
|
123
138
|
|
|
124
|
-
|
|
139
|
+
if (latest && version) {
|
|
140
|
+
console.error("Error: --latest and --version are mutually exclusive.");
|
|
141
|
+
emitCliError("UNKNOWN", "--latest and --version are mutually exclusive");
|
|
142
|
+
process.exit(1);
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
return { name, version, latest, prepare, finalize };
|
|
125
146
|
}
|
|
126
147
|
|
|
127
148
|
function resolveCloud(entry: AssistantEntry): string {
|
|
@@ -491,6 +512,11 @@ async function upgradeDocker(
|
|
|
491
512
|
} else {
|
|
492
513
|
console.error(`\nā Containers failed to become ready within the timeout.`);
|
|
493
514
|
|
|
515
|
+
const logDir = await captureUpgradeFailureLogs(res, `${instanceName}-upgrade-failure`);
|
|
516
|
+
if (logDir) {
|
|
517
|
+
console.log(`š Container logs saved to: ${logDir}`);
|
|
518
|
+
}
|
|
519
|
+
|
|
494
520
|
if (previousImageRefs) {
|
|
495
521
|
await broadcastUpgradeEvent(
|
|
496
522
|
entry.runtimeUrl,
|
|
@@ -867,8 +893,80 @@ async function upgradeFinalize(
|
|
|
867
893
|
);
|
|
868
894
|
}
|
|
869
895
|
|
|
896
|
+
/**
|
|
897
|
+
* When `--latest` is passed, resolve the latest stable version from the
|
|
898
|
+
* platform API. If the running CLI is older than that version, self-update
|
|
899
|
+
* the CLI via `bun install -g` and re-exec so the new CLI's upgrade logic
|
|
900
|
+
* (and its cliPkg.version) drives the rest of the upgrade.
|
|
901
|
+
*
|
|
902
|
+
* Returns the resolved latest version string (e.g. "v0.7.0") for callers
|
|
903
|
+
* that need it. If the CLI was updated and re-exec'd, this function never
|
|
904
|
+
* returns ā the process is replaced.
|
|
905
|
+
*/
|
|
906
|
+
async function resolveLatestAndMaybeSelfUpdate(
|
|
907
|
+
name: string | null,
|
|
908
|
+
): Promise<string> {
|
|
909
|
+
console.log("š Fetching latest stable release...");
|
|
910
|
+
const latestVersion = await fetchLatestStableVersion();
|
|
911
|
+
if (!latestVersion) {
|
|
912
|
+
console.error(
|
|
913
|
+
"Error: Could not determine the latest stable release from the platform API.",
|
|
914
|
+
);
|
|
915
|
+
emitCliError(
|
|
916
|
+
"UNKNOWN",
|
|
917
|
+
"Could not determine the latest stable release from the platform API",
|
|
918
|
+
);
|
|
919
|
+
process.exit(1);
|
|
920
|
+
}
|
|
921
|
+
|
|
922
|
+
const latestTag = latestVersion.startsWith("v")
|
|
923
|
+
? latestVersion
|
|
924
|
+
: `v${latestVersion}`;
|
|
925
|
+
const currentTag = cliPkg.version ? `v${cliPkg.version}` : null;
|
|
926
|
+
|
|
927
|
+
console.log(` Latest stable: ${latestTag}`);
|
|
928
|
+
console.log(` CLI version: ${currentTag ?? "unknown"}\n`);
|
|
929
|
+
|
|
930
|
+
// Check if the CLI needs updating
|
|
931
|
+
const cmp = currentTag ? compareVersions(latestTag, currentTag) : null;
|
|
932
|
+
if (cmp !== null && cmp > 0) {
|
|
933
|
+
console.log(`š Updating CLI to ${latestTag}...`);
|
|
934
|
+
const installResult = spawnSync(
|
|
935
|
+
"bun",
|
|
936
|
+
["install", "-g", `vellum@${latestVersion}`],
|
|
937
|
+
{ stdio: "inherit" },
|
|
938
|
+
);
|
|
939
|
+
if (installResult.error || installResult.status !== 0) {
|
|
940
|
+
const detail =
|
|
941
|
+
installResult.error?.message ?? `exited with code ${installResult.status}`;
|
|
942
|
+
console.error(`\nā CLI self-update failed: ${detail}`);
|
|
943
|
+
emitCliError("CLI_UPDATE_FAILED", "CLI self-update failed", detail);
|
|
944
|
+
process.exit(1);
|
|
945
|
+
}
|
|
946
|
+
console.log(`ā
CLI updated to ${latestTag}\n`);
|
|
947
|
+
|
|
948
|
+
// Re-exec with the updated CLI. Pass --version instead of --latest
|
|
949
|
+
// to avoid re-fetching and to prevent infinite re-exec loops.
|
|
950
|
+
const reexecArgs = ["upgrade"];
|
|
951
|
+
if (name) reexecArgs.push(name);
|
|
952
|
+
reexecArgs.push("--version", latestTag);
|
|
953
|
+
|
|
954
|
+
console.log(`š Re-running upgrade with updated CLI...\n`);
|
|
955
|
+
const reexecResult = spawnSync("vellum", reexecArgs, {
|
|
956
|
+
stdio: "inherit",
|
|
957
|
+
});
|
|
958
|
+
process.exit(reexecResult.status ?? 1);
|
|
959
|
+
}
|
|
960
|
+
|
|
961
|
+
if (cmp !== null && cmp === 0) {
|
|
962
|
+
console.log(`ā
CLI is already on the latest version (${latestTag})\n`);
|
|
963
|
+
}
|
|
964
|
+
|
|
965
|
+
return latestTag;
|
|
966
|
+
}
|
|
967
|
+
|
|
870
968
|
export async function upgrade(): Promise<void> {
|
|
871
|
-
const { name, version, prepare, finalize } = parseArgs();
|
|
969
|
+
const { name, version, latest, prepare, finalize } = parseArgs();
|
|
872
970
|
const entry = resolveTargetAssistant(name);
|
|
873
971
|
|
|
874
972
|
if (prepare) {
|
|
@@ -881,16 +979,25 @@ export async function upgrade(): Promise<void> {
|
|
|
881
979
|
return;
|
|
882
980
|
}
|
|
883
981
|
|
|
982
|
+
// When --latest is passed, resolve the target from the platform API and
|
|
983
|
+
// self-update the CLI if it's behind. The resolved version is then used
|
|
984
|
+
// as the explicit target for the rest of the upgrade flow.
|
|
985
|
+
let effectiveVersion = version;
|
|
986
|
+
if (latest) {
|
|
987
|
+
const latestTag = await resolveLatestAndMaybeSelfUpdate(name);
|
|
988
|
+
effectiveVersion = latestTag;
|
|
989
|
+
}
|
|
990
|
+
|
|
884
991
|
const cloud = resolveCloud(entry);
|
|
885
992
|
|
|
886
993
|
try {
|
|
887
994
|
if (cloud === "docker") {
|
|
888
|
-
await upgradeDocker(entry,
|
|
995
|
+
await upgradeDocker(entry, effectiveVersion);
|
|
889
996
|
return;
|
|
890
997
|
}
|
|
891
998
|
|
|
892
999
|
if (cloud === "vellum") {
|
|
893
|
-
await upgradePlatform(entry,
|
|
1000
|
+
await upgradePlatform(entry, effectiveVersion);
|
|
894
1001
|
return;
|
|
895
1002
|
}
|
|
896
1003
|
} catch (err) {
|
package/src/commands/wake.ts
CHANGED
|
@@ -195,22 +195,11 @@ export async function wake(): Promise<void> {
|
|
|
195
195
|
}
|
|
196
196
|
|
|
197
197
|
// Auto-start ngrok if webhook integrations (e.g. Telegram) are configured.
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
const ngrokChild = await maybeStartNgrokTunnel(resources.gatewayPort);
|
|
204
|
-
if (ngrokChild?.pid) {
|
|
205
|
-
const ngrokPidFile = join(resources.instanceDir, ".vellum", "ngrok.pid");
|
|
206
|
-
writeFileSync(ngrokPidFile, String(ngrokChild.pid));
|
|
207
|
-
}
|
|
208
|
-
} finally {
|
|
209
|
-
if (prevBaseDataDir !== undefined) {
|
|
210
|
-
process.env.BASE_DATA_DIR = prevBaseDataDir;
|
|
211
|
-
} else {
|
|
212
|
-
delete process.env.BASE_DATA_DIR;
|
|
213
|
-
}
|
|
198
|
+
const workspaceDir = join(resources.instanceDir, ".vellum", "workspace");
|
|
199
|
+
const ngrokChild = await maybeStartNgrokTunnel(resources.gatewayPort, workspaceDir);
|
|
200
|
+
if (ngrokChild?.pid) {
|
|
201
|
+
const ngrokPidFile = join(resources.instanceDir, ".vellum", "ngrok.pid");
|
|
202
|
+
writeFileSync(ngrokPidFile, String(ngrokChild.pid));
|
|
214
203
|
}
|
|
215
204
|
|
|
216
205
|
console.log("Wake complete.");
|