@vellumai/cli 0.6.4 → 0.6.6

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/bun.lock CHANGED
@@ -5,25 +5,25 @@
5
5
  "": {
6
6
  "name": "@vellumai/cli",
7
7
  "dependencies": {
8
- "chalk": "^5.6.0",
9
- "ink": "^6.7.0",
10
- "jsqr": "^1.4.0",
11
- "nanoid": "^5.1.7",
12
- "pngjs": "^7.0.0",
13
- "qrcode-terminal": "^0.12.0",
14
- "react": "^19.2.4",
15
- "react-devtools-core": "^6.1.2",
8
+ "chalk": "5.6.2",
9
+ "ink": "6.8.0",
10
+ "jsqr": "1.4.0",
11
+ "nanoid": "5.1.7",
12
+ "pngjs": "7.0.0",
13
+ "qrcode-terminal": "0.12.0",
14
+ "react": "19.2.4",
15
+ "react-devtools-core": "6.1.5",
16
16
  },
17
17
  "devDependencies": {
18
- "@types/bun": "^1.2.4",
19
- "@types/pngjs": "^6.0.5",
20
- "@types/qrcode-terminal": "^0.12.2",
21
- "@types/react": "^19.2.14",
22
- "eslint": "^10.0.0",
23
- "knip": "^5.86.0",
24
- "prettier": "^3.8.1",
25
- "typescript": "^5.9.3",
26
- "typescript-eslint": "^8.55.0",
18
+ "@types/bun": "1.3.11",
19
+ "@types/pngjs": "6.0.5",
20
+ "@types/qrcode-terminal": "0.12.2",
21
+ "@types/react": "19.2.14",
22
+ "eslint": "10.1.0",
23
+ "knip": "5.88.1",
24
+ "prettier": "3.8.1",
25
+ "typescript": "5.9.3",
26
+ "typescript-eslint": "8.58.0",
27
27
  },
28
28
  },
29
29
  },
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@vellumai/cli",
3
- "version": "0.6.4",
3
+ "version": "0.6.6",
4
4
  "description": "CLI tools for vellum-assistant",
5
5
  "type": "module",
6
6
  "exports": {
@@ -24,24 +24,24 @@
24
24
  "author": "Vellum AI",
25
25
  "license": "MIT",
26
26
  "dependencies": {
27
- "chalk": "^5.6.0",
28
- "ink": "^6.7.0",
29
- "jsqr": "^1.4.0",
30
- "nanoid": "^5.1.7",
31
- "pngjs": "^7.0.0",
32
- "qrcode-terminal": "^0.12.0",
33
- "react": "^19.2.4",
34
- "react-devtools-core": "^6.1.2"
27
+ "chalk": "5.6.2",
28
+ "ink": "6.8.0",
29
+ "jsqr": "1.4.0",
30
+ "nanoid": "5.1.7",
31
+ "pngjs": "7.0.0",
32
+ "qrcode-terminal": "0.12.0",
33
+ "react": "19.2.4",
34
+ "react-devtools-core": "6.1.5"
35
35
  },
36
36
  "devDependencies": {
37
- "@types/bun": "^1.2.4",
38
- "@types/pngjs": "^6.0.5",
39
- "@types/qrcode-terminal": "^0.12.2",
40
- "@types/react": "^19.2.14",
41
- "eslint": "^10.0.0",
42
- "knip": "^5.86.0",
43
- "prettier": "^3.8.1",
44
- "typescript": "^5.9.3",
45
- "typescript-eslint": "^8.55.0"
37
+ "@types/bun": "1.3.11",
38
+ "@types/pngjs": "6.0.5",
39
+ "@types/qrcode-terminal": "0.12.2",
40
+ "@types/react": "19.2.14",
41
+ "eslint": "10.1.0",
42
+ "knip": "5.88.1",
43
+ "prettier": "3.8.1",
44
+ "typescript": "5.9.3",
45
+ "typescript-eslint": "8.58.0"
46
46
  }
47
47
  }
@@ -7,18 +7,20 @@ import {
7
7
  getOrCreatePersistedDeviceId,
8
8
  loadGuardianToken,
9
9
  saveGuardianToken,
10
+ seedGuardianTokenFromSiblingEnv,
10
11
  type GuardianTokenData,
11
12
  } from "../lib/guardian-token.js";
12
13
 
13
14
  function makeTokenData(suffix: string): GuardianTokenData {
14
15
  const now = new Date().toISOString();
16
+ const oneHourFromNow = new Date(Date.now() + 60 * 60 * 1000).toISOString();
15
17
  return {
16
18
  guardianPrincipalId: `principal-${suffix}`,
17
19
  accessToken: `access-${suffix}`,
18
- accessTokenExpiresAt: now,
20
+ accessTokenExpiresAt: oneHourFromNow,
19
21
  refreshToken: `refresh-${suffix}`,
20
- refreshTokenExpiresAt: now,
21
- refreshAfter: now,
22
+ refreshTokenExpiresAt: oneHourFromNow,
23
+ refreshAfter: oneHourFromNow,
22
24
  isNew: true,
23
25
  deviceId: `device-${suffix}`,
24
26
  leasedAt: now,
@@ -169,4 +171,55 @@ describe("guardian-token paths are env-scoped", () => {
169
171
  const second = getOrCreatePersistedDeviceId();
170
172
  expect(first).toBe(second);
171
173
  });
174
+
175
+ test("seedGuardianTokenFromSiblingEnv copies a dev token into the current local env", () => {
176
+ // Write a token under the dev env.
177
+ process.env.VELLUM_ENVIRONMENT = "dev";
178
+ saveGuardianToken("alpha", makeTokenData("dev"));
179
+
180
+ // Switch to local env — no token present yet.
181
+ process.env.VELLUM_ENVIRONMENT = "local";
182
+ expect(loadGuardianToken("alpha")).toBeNull();
183
+
184
+ const seeded = seedGuardianTokenFromSiblingEnv("alpha");
185
+ expect(seeded).toBe(true);
186
+
187
+ const localPath = join(
188
+ tempHome,
189
+ "vellum-local",
190
+ "assistants",
191
+ "alpha",
192
+ "guardian-token.json",
193
+ );
194
+ expect(existsSync(localPath)).toBe(true);
195
+ const loaded = loadGuardianToken("alpha");
196
+ expect(loaded).not.toBeNull();
197
+ expect(loaded!.guardianPrincipalId).toBe("principal-dev");
198
+
199
+ // Idempotent — second call is a no-op.
200
+ expect(seedGuardianTokenFromSiblingEnv("alpha")).toBe(false);
201
+ });
202
+
203
+ test("seedGuardianTokenFromSiblingEnv returns false when no sibling token exists", () => {
204
+ process.env.VELLUM_ENVIRONMENT = "local";
205
+ expect(seedGuardianTokenFromSiblingEnv("nonexistent")).toBe(false);
206
+ expect(loadGuardianToken("nonexistent")).toBeNull();
207
+ });
208
+
209
+ test("seedGuardianTokenFromSiblingEnv does not overwrite an existing token", () => {
210
+ // Token already present in the current env.
211
+ process.env.VELLUM_ENVIRONMENT = "local";
212
+ saveGuardianToken("alpha", makeTokenData("local"));
213
+
214
+ // And a different sibling token in dev.
215
+ process.env.VELLUM_ENVIRONMENT = "dev";
216
+ saveGuardianToken("alpha", makeTokenData("dev"));
217
+
218
+ // Back to local — seed should no-op because a token is already present.
219
+ process.env.VELLUM_ENVIRONMENT = "local";
220
+ expect(seedGuardianTokenFromSiblingEnv("alpha")).toBe(false);
221
+ expect(loadGuardianToken("alpha")!.guardianPrincipalId).toBe(
222
+ "principal-local",
223
+ );
224
+ });
172
225
  });
@@ -0,0 +1,64 @@
1
+ import { readFileSync } from "node:fs";
2
+ import { join } from "node:path";
3
+ import { describe, expect, test } from "bun:test";
4
+
5
+ import {
6
+ LLM_PROVIDER_ENV_VAR_NAMES,
7
+ SEARCH_PROVIDER_ENV_VAR_NAMES,
8
+ } from "../shared/provider-env-vars.js";
9
+
10
+ /**
11
+ * Drift guard for the CLI-side LLM provider env-var mirror.
12
+ *
13
+ * `cli/src/shared/provider-env-vars.ts` hardcodes the LLM env-var names so the
14
+ * CLI doesn't need to import the assistant's `PROVIDER_CATALOG` (no CLI →
15
+ * assistant cross-package imports exist). This test pulls the catalog JSON at
16
+ * `meta/llm-provider-catalog.json` — which is kept in sync with
17
+ * `PROVIDER_CATALOG` by `assistant/src/__tests__/llm-catalog-parity.test.ts` —
18
+ * and asserts the CLI's mirror matches the catalog's `envVar` entries.
19
+ *
20
+ * It also asserts the search-provider mirror matches `meta/provider-env-vars.json`.
21
+ */
22
+
23
+ const REPO_ROOT = join(import.meta.dir, "..", "..", "..");
24
+
25
+ interface LlmCatalogEntry {
26
+ id: string;
27
+ envVar?: string;
28
+ }
29
+
30
+ interface LlmCatalog {
31
+ version: number;
32
+ providers: LlmCatalogEntry[];
33
+ }
34
+
35
+ interface SearchProviderRegistry {
36
+ version: number;
37
+ providers: Record<string, string>;
38
+ }
39
+
40
+ function loadLlmCatalog(): LlmCatalog {
41
+ const path = join(REPO_ROOT, "meta", "llm-provider-catalog.json");
42
+ return JSON.parse(readFileSync(path, "utf-8"));
43
+ }
44
+
45
+ function loadSearchProviderRegistry(): SearchProviderRegistry {
46
+ const path = join(REPO_ROOT, "meta", "provider-env-vars.json");
47
+ return JSON.parse(readFileSync(path, "utf-8"));
48
+ }
49
+
50
+ describe("CLI provider env-var parity", () => {
51
+ test("LLM_PROVIDER_ENV_VAR_NAMES matches meta/llm-provider-catalog.json entries with envVar", () => {
52
+ const catalog = loadLlmCatalog();
53
+ const expected: Record<string, string> = {};
54
+ for (const provider of catalog.providers) {
55
+ if (provider.envVar) expected[provider.id] = provider.envVar;
56
+ }
57
+ expect(LLM_PROVIDER_ENV_VAR_NAMES).toEqual(expected);
58
+ });
59
+
60
+ test("SEARCH_PROVIDER_ENV_VAR_NAMES matches meta/provider-env-vars.json", () => {
61
+ const registry = loadSearchProviderRegistry();
62
+ expect(SEARCH_PROVIDER_ENV_VAR_NAMES).toEqual(registry.providers);
63
+ });
64
+ });
@@ -159,6 +159,36 @@ describe("multi-local", () => {
159
159
  }
160
160
  });
161
161
 
162
+ test("allocation picks env-specific port bases for non-prod envs", async () => {
163
+ // Each non-prod env sits in its own 1000-port window (see
164
+ // environments/seeds.ts). Hatching under VELLUM_ENVIRONMENT=dev should
165
+ // produce ports in the dev block (18000+), not the production defaults.
166
+ const prevEnv = process.env.VELLUM_ENVIRONMENT;
167
+ const prevXdg = process.env.XDG_DATA_HOME;
168
+ const xdgDataHome = mkdtempSync(join(tmpdir(), "cli-multi-xdg-ports-"));
169
+ process.env.VELLUM_ENVIRONMENT = "dev";
170
+ process.env.XDG_DATA_HOME = xdgDataHome;
171
+ try {
172
+ const res = await allocateLocalResources("dev-a");
173
+ expect(res.daemonPort).toBe(18000);
174
+ expect(res.gatewayPort).toBe(18100);
175
+ expect(res.qdrantPort).toBe(18200);
176
+ expect(res.cesPort).toBe(18300);
177
+ } finally {
178
+ if (prevEnv !== undefined) {
179
+ process.env.VELLUM_ENVIRONMENT = prevEnv;
180
+ } else {
181
+ delete process.env.VELLUM_ENVIRONMENT;
182
+ }
183
+ if (prevXdg !== undefined) {
184
+ process.env.XDG_DATA_HOME = prevXdg;
185
+ } else {
186
+ delete process.env.XDG_DATA_HOME;
187
+ }
188
+ rmSync(xdgDataHome, { recursive: true, force: true });
189
+ }
190
+ });
191
+
162
192
  test("second instance gets distinct ports and dir when first instance is saved", async () => {
163
193
  // GIVEN a first local assistant already exists in the lockfile
164
194
  saveAssistantEntry(makeEntry("instance-a"));
@@ -0,0 +1,186 @@
1
+ import { spawn } from "child_process";
2
+
3
+ import {
4
+ findAssistantByName,
5
+ loadLatestAssistant,
6
+ resolveCloud,
7
+ } from "../lib/assistant-config";
8
+ import { dockerResourceNames } from "../lib/docker";
9
+ import type { ServiceName } from "../lib/docker";
10
+ import { execAppleContainer } from "../lib/exec-apple-container";
11
+ import { sshAppleContainer } from "../lib/ssh-apple-container";
12
+
13
+ const SERVICE_ALIASES: Record<string, ServiceName> = {
14
+ assistant: "assistant",
15
+ "vellum-assistant": "assistant",
16
+ gateway: "gateway",
17
+ "vellum-gateway": "gateway",
18
+ "credential-executor": "credential-executor",
19
+ "vellum-credential-executor": "credential-executor",
20
+ };
21
+
22
+ function normalizeService(raw: string): ServiceName {
23
+ const normalized = SERVICE_ALIASES[raw];
24
+ if (!normalized) {
25
+ console.error(
26
+ `Unknown service '${raw}'. Valid services: assistant, gateway, credential-executor`,
27
+ );
28
+ process.exit(1);
29
+ }
30
+ return normalized;
31
+ }
32
+
33
+ function resolveDockerContainer(
34
+ instanceName: string,
35
+ service: ServiceName,
36
+ ): string {
37
+ const res = dockerResourceNames(instanceName);
38
+ switch (service) {
39
+ case "assistant":
40
+ return res.assistantContainer;
41
+ case "gateway":
42
+ return res.gatewayContainer;
43
+ case "credential-executor":
44
+ return res.cesContainer;
45
+ }
46
+ }
47
+
48
+ export async function exec(): Promise<void> {
49
+ const rawArgs = process.argv.slice(3);
50
+
51
+ // Only check for help flags before the -- separator so that
52
+ // `vellum exec -- curl --help` passes through correctly.
53
+ const dashDashIndex = rawArgs.indexOf("--");
54
+ const preArgs =
55
+ dashDashIndex === -1 ? rawArgs : rawArgs.slice(0, dashDashIndex);
56
+
57
+ if (
58
+ preArgs.includes("--help") ||
59
+ preArgs.includes("-h") ||
60
+ rawArgs.length === 0
61
+ ) {
62
+ console.log(
63
+ "Usage: vellum exec [<name>] [--service <svc>] [-it] -- <command...>",
64
+ );
65
+ console.log("");
66
+ console.log("Execute a command inside an assistant's container.");
67
+ console.log("");
68
+ console.log("Arguments:");
69
+ console.log(
70
+ " <name> Name of the assistant (defaults to active)",
71
+ );
72
+ console.log(
73
+ " <command...> Command and arguments to run (after --)",
74
+ );
75
+ console.log("");
76
+ console.log("Options:");
77
+ console.log(
78
+ " --service <svc> Target service (default: assistant)",
79
+ );
80
+ console.log(
81
+ " -it Interactive mode with TTY (like docker exec -it)",
82
+ );
83
+ console.log("");
84
+ console.log("Services:");
85
+ console.log(" assistant (or vellum-assistant)");
86
+ console.log(" gateway (or vellum-gateway)");
87
+ console.log(" credential-executor (or vellum-credential-executor)");
88
+ console.log("");
89
+ console.log("Examples:");
90
+ console.log(" vellum exec -- ls -la /workspace");
91
+ console.log(" vellum exec -- cat /workspace/NOW.md");
92
+ console.log(" vellum exec -it -- /bin/bash");
93
+ console.log(
94
+ " vellum exec --service gateway -- cat /tmp/gateway.log",
95
+ );
96
+ process.exit(0);
97
+ }
98
+
99
+ if (dashDashIndex === -1) {
100
+ console.error(
101
+ "Error: missing '--' separator before command.\n" +
102
+ "Usage: vellum exec [<name>] -- <command...>",
103
+ );
104
+ process.exit(1);
105
+ }
106
+
107
+ const command = rawArgs.slice(dashDashIndex + 1);
108
+
109
+ if (command.length === 0) {
110
+ console.error("Error: no command specified after '--'.");
111
+ process.exit(1);
112
+ }
113
+
114
+ let nameArg: string | undefined;
115
+ let serviceRaw = "assistant";
116
+ let interactive = false;
117
+
118
+ for (let i = 0; i < preArgs.length; i++) {
119
+ if (preArgs[i] === "--service" && preArgs[i + 1]) {
120
+ serviceRaw = preArgs[++i];
121
+ } else if (preArgs[i] === "-it" || preArgs[i] === "-ti") {
122
+ interactive = true;
123
+ } else if (!preArgs[i].startsWith("-")) {
124
+ nameArg = preArgs[i];
125
+ }
126
+ }
127
+
128
+ const service = normalizeService(serviceRaw);
129
+
130
+ const entry = nameArg
131
+ ? findAssistantByName(nameArg)
132
+ : loadLatestAssistant();
133
+
134
+ if (!entry) {
135
+ if (nameArg) {
136
+ console.error(`No assistant instance found with name '${nameArg}'.`);
137
+ } else {
138
+ console.error("No assistant instance found. Run `vellum hatch` first.");
139
+ }
140
+ process.exit(1);
141
+ }
142
+
143
+ const cloud = resolveCloud(entry);
144
+
145
+ if (cloud === "local") {
146
+ console.error(
147
+ "Cannot exec into a local assistant — it runs directly on this machine.",
148
+ );
149
+ process.exit(1);
150
+ }
151
+
152
+ if (cloud === "apple-container") {
153
+ const fullServiceName = `vellum-${service}`;
154
+ if (interactive) {
155
+ await sshAppleContainer(entry, command, fullServiceName);
156
+ } else {
157
+ await execAppleContainer(entry, command, fullServiceName);
158
+ }
159
+ return;
160
+ }
161
+
162
+ if (cloud === "docker") {
163
+ const container = resolveDockerContainer(entry.assistantId, service);
164
+ const dockerArgs = interactive
165
+ ? ["exec", "-it", container, ...command]
166
+ : ["exec", container, ...command];
167
+
168
+ const child = spawn("docker", dockerArgs, { stdio: "inherit" });
169
+ await new Promise<void>((resolve, reject) => {
170
+ child.on("close", (code) => {
171
+ if (code === 0) resolve();
172
+ else {
173
+ process.exitCode = code ?? 1;
174
+ resolve();
175
+ }
176
+ });
177
+ child.on("error", reject);
178
+ });
179
+ return;
180
+ }
181
+
182
+ console.error(
183
+ `Error: 'vellum exec' is not supported for ${cloud} instances.`,
184
+ );
185
+ process.exit(1);
186
+ }
@@ -15,7 +15,9 @@ import {
15
15
  fetchOrganizationId,
16
16
  getPlatformUrl,
17
17
  injectCredentialsIntoAssistant,
18
+ readGatewayCredential,
18
19
  readPlatformToken,
20
+ reprovisionAssistantApiKey,
19
21
  savePlatformToken,
20
22
  } from "../lib/platform-client";
21
23
 
@@ -193,12 +195,41 @@ export async function login(): Promise<void> {
193
195
  `Registered assistant: ${registration.assistant.name} (${registration.assistant.id})`,
194
196
  );
195
197
 
198
+ // Resolve the API key to inject, mirroring the macOS app's
199
+ // LocalAssistantBootstrapService 3-step flow:
200
+ // 1. Use fresh key from registration (first-time only)
201
+ // 2. Use existing key from the daemon's credential store
202
+ // 3. Reprovision (rotate) as a last resort — this revokes the
203
+ // old key server-side, so we only do it when the gateway
204
+ // confirms no key exists (not when it's merely unreachable).
205
+ let assistantApiKey = registration.assistant_api_key;
206
+ if (!assistantApiKey) {
207
+ const cached = await readGatewayCredential(
208
+ entry.runtimeUrl,
209
+ "vellum:assistant_api_key",
210
+ entry.bearerToken,
211
+ );
212
+ if (cached.value) {
213
+ assistantApiKey = cached.value;
214
+ } else if (!cached.unreachable) {
215
+ console.log("No API key available locally — reprovisioning...");
216
+ const reprovision = await reprovisionAssistantApiKey(
217
+ token,
218
+ orgId,
219
+ clientInstallationId,
220
+ entry.assistantId,
221
+ "cli",
222
+ );
223
+ assistantApiKey = reprovision.provisioning.assistant_api_key;
224
+ }
225
+ }
226
+
196
227
  // Inject credentials into the running assistant via the gateway,
197
228
  // mirroring the desktop app's LocalAssistantBootstrapService flow.
198
229
  const allInjected = await injectCredentialsIntoAssistant({
199
230
  gatewayUrl: entry.runtimeUrl,
200
231
  bearerToken: entry.bearerToken,
201
- assistantApiKey: registration.assistant_api_key,
232
+ assistantApiKey,
202
233
  platformAssistantId: registration.assistant.id,
203
234
  platformBaseUrl: getPlatformUrl(),
204
235
  organizationId: orgId,
@@ -1,8 +1,14 @@
1
+ import { existsSync, unlinkSync } from "fs";
2
+ import { join } from "path";
3
+
1
4
  import {
2
5
  findAssistantByName,
6
+ loadAllAssistants,
3
7
  removeAssistantEntry,
4
8
  } from "../lib/assistant-config";
5
9
  import type { AssistantEntry } from "../lib/assistant-config";
10
+ import { getConfigDir } from "../lib/environments/paths";
11
+ import { getCurrentEnvironment } from "../lib/environments/resolve";
6
12
  import {
7
13
  authHeaders,
8
14
  getPlatformUrl,
@@ -246,4 +252,21 @@ async function retireInner(): Promise<void> {
246
252
 
247
253
  removeAssistantEntry(name);
248
254
  console.log(`Removed ${name} from config.`);
255
+
256
+ // When no assistants remain, remove the dock-display-name sentinel so
257
+ // the next build.sh run falls back to "Vellum" instead of using the
258
+ // retired assistant's name.
259
+ if (loadAllAssistants().length === 0) {
260
+ const dockLabelFile = join(
261
+ getConfigDir(getCurrentEnvironment()),
262
+ "dock-display-name",
263
+ );
264
+ if (existsSync(dockLabelFile)) {
265
+ try {
266
+ unlinkSync(dockLabelFile);
267
+ } catch {
268
+ // Best-effort — the macOS app will also reset this on next launch.
269
+ }
270
+ }
271
+ }
249
272
  }
@@ -6,7 +6,7 @@ import {
6
6
  } from "../lib/assistant-config";
7
7
  import type { AssistantEntry } from "../lib/assistant-config";
8
8
  import { dockerResourceNames } from "../lib/docker";
9
- import { sshAppleContainer } from "./ssh-apple-container";
9
+ import { sshAppleContainer } from "../lib/ssh-apple-container";
10
10
 
11
11
  const SSH_OPTS = [
12
12
  "-o",
@@ -27,6 +27,8 @@ import {
27
27
  platformImportBundleFromGcs,
28
28
  platformPollImportStatus,
29
29
  ensureSelfHostedLocalRegistration,
30
+ readGatewayCredential,
31
+ reprovisionAssistantApiKey,
30
32
  injectCredentialsIntoAssistant,
31
33
  fetchCurrentUser,
32
34
  fetchOrganizationId,
@@ -1135,10 +1137,35 @@ async function tryInjectPlatformCredentials(
1135
1137
  "cli",
1136
1138
  );
1137
1139
 
1140
+ // Resolve the API key: 1) fresh from registration, 2) existing from
1141
+ // daemon credential store, 3) reprovision as last resort (revokes old key).
1142
+ // Only reprovision when the gateway confirms no key exists — not when
1143
+ // the gateway is merely unreachable (would revoke without injecting).
1144
+ let assistantApiKey = registration.assistant_api_key;
1145
+ if (!assistantApiKey) {
1146
+ const cached = await readGatewayCredential(
1147
+ entry.runtimeUrl,
1148
+ "vellum:assistant_api_key",
1149
+ entry.bearerToken,
1150
+ );
1151
+ if (cached.value) {
1152
+ assistantApiKey = cached.value;
1153
+ } else if (!cached.unreachable) {
1154
+ const reprovision = await reprovisionAssistantApiKey(
1155
+ token,
1156
+ orgId,
1157
+ clientInstallationId,
1158
+ entry.assistantId,
1159
+ "cli",
1160
+ );
1161
+ assistantApiKey = reprovision.provisioning.assistant_api_key;
1162
+ }
1163
+ }
1164
+
1138
1165
  const allInjected = await injectCredentialsIntoAssistant({
1139
1166
  gatewayUrl: entry.runtimeUrl,
1140
1167
  bearerToken: entry.bearerToken,
1141
- assistantApiKey: registration.assistant_api_key,
1168
+ assistantApiKey,
1142
1169
  platformAssistantId: registration.assistant.id,
1143
1170
  platformBaseUrl: getPlatformUrl(),
1144
1171
  organizationId: orgId,