dsh-grok-subscription 2.0.2 → 2.0.4

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/lib/index.js CHANGED
@@ -16,6 +16,8 @@ var CLIENT_VERSION_HEADER = "x-grok-client-version";
16
16
  var CLIENT_IDENTIFIER = "grok-shell";
17
17
  var CLIENT_VERSION_FALLBACK = "1.0.5";
18
18
  var API_KEY_SCOPE = "xai::api_key";
19
+ var XAI_OAUTH_ISSUER = "https://auth.x.ai";
20
+ var GROK_OIDC_CLIENT_ID = "b1a00492-073a-47ea-816f-4c329264a828";
19
21
  var SESSION_AUTH_MODES = Object.freeze(["oidc", "external", "web_login", "grok"]);
20
22
  var API_KEY_AUTH_MODES = Object.freeze(["api_key"]);
21
23
  var AUTH_FILE_MAX_BYTES = 1048576;
@@ -37,19 +39,28 @@ var IMAGE_INPUT_MODEL_IDS = Object.freeze([
37
39
  var IMPORT_TIMEOUT_MS = 2500;
38
40
  var CREDENTIALS_IO_TIMEOUT_MS = 1500;
39
41
  var RPC_HANDLER_TIMEOUT_MS = 8e3;
40
- var LOGIN_START_TIMEOUT_MS = 1e4;
41
42
  var LOGIN_HANDLER_TIMEOUT_MS = 2e4;
42
43
 
43
44
  // src/session.js
44
- import { existsSync as existsSync3 } from "node:fs";
45
45
  import { spawn } from "node:child_process";
46
- import { join as join3 } from "node:path";
47
46
 
48
47
  // src/auth-file.js
49
- import { lstatSync, openSync, readFileSync, closeSync, constants as fsConstants } from "node:fs";
48
+ import { randomBytes } from "node:crypto";
49
+ import {
50
+ chmodSync,
51
+ closeSync,
52
+ constants as fsConstants,
53
+ lstatSync,
54
+ mkdirSync,
55
+ openSync,
56
+ readFileSync,
57
+ renameSync,
58
+ unlinkSync,
59
+ writeSync
60
+ } from "node:fs";
50
61
  import { homedir } from "node:os";
51
- import { join } from "node:path";
52
- var XAI_OAUTH_ISSUER = "https://auth.x.ai";
62
+ import { dirname, join } from "node:path";
63
+ var XAI_OAUTH_ISSUER2 = "https://auth.x.ai";
53
64
  function grokHome(env = process.env) {
54
65
  const override = typeof env.GROK_HOME === "string" && env.GROK_HOME.trim() ? env.GROK_HOME.trim() : void 0;
55
66
  return override ?? join(homedir(), ".grok");
@@ -165,6 +176,9 @@ function sessionFromEntry(scope, entry) {
165
176
  return Object.freeze({
166
177
  scope,
167
178
  accessToken: token,
179
+ refreshToken: asNonEmptyString(object.refresh_token ?? object.refreshToken),
180
+ oidcIssuer: asNonEmptyString(object.oidc_issuer ?? object.oidcIssuer),
181
+ oidcClientId: asNonEmptyString(object.oidc_client_id ?? object.oidcClientId),
168
182
  authMode,
169
183
  email,
170
184
  userId,
@@ -174,8 +188,8 @@ function sessionFromEntry(scope, entry) {
174
188
  }
175
189
  function preferredScopeScore(scope, entry) {
176
190
  const issuer = entry && typeof entry === "object" ? asNonEmptyString(entry.oidc_issuer ?? entry.oidcIssuer) : void 0;
177
- if (typeof scope === "string" && scope.startsWith(`${XAI_OAUTH_ISSUER}::`)) return 3;
178
- if (issuer === XAI_OAUTH_ISSUER) return 2;
191
+ if (typeof scope === "string" && scope.startsWith(`${XAI_OAUTH_ISSUER2}::`)) return 3;
192
+ if (issuer === XAI_OAUTH_ISSUER2) return 2;
179
193
  if (SESSION_AUTH_MODES.includes(normalizeAuthMode(entry?.auth_mode ?? entry?.authMode) ?? "")) return 1;
180
194
  return 0;
181
195
  }
@@ -213,6 +227,91 @@ function readGrokAuthSession(path = authJsonPath(), options = {}) {
213
227
  const document = readSecureJsonFile(path, options);
214
228
  return parseAuthDocument(document);
215
229
  }
230
+ function fileMeta(stat) {
231
+ return {
232
+ isSymbolicLink: typeof stat.isSymbolicLink === "function" ? stat.isSymbolicLink() : Boolean(stat.isSymbolicLink),
233
+ isFile: typeof stat.isFile === "function" ? stat.isFile() : Boolean(stat.isFile),
234
+ mode: stat.mode,
235
+ uid: stat.uid,
236
+ size: stat.size
237
+ };
238
+ }
239
+ function writeOauthSession(path, fields, options = {}) {
240
+ if (!asNonEmptyString(fields?.accessToken) || !asNonEmptyString(fields?.issuer) || !asNonEmptyString(fields?.clientId)) {
241
+ throw new Error("Refusing to store an OAuth session without an access token");
242
+ }
243
+ const lstat = options.lstat ?? ((target) => lstatSync(target, { throwIfNoEntry: false }));
244
+ const existing = lstat(path);
245
+ let document = {};
246
+ if (existing) {
247
+ const meta = fileMeta(existing);
248
+ if (meta.isSymbolicLink) throw new Error("Refusing to write a symbolic-link Grok auth.json");
249
+ if (!meta.isFile) throw new Error("Grok auth.json is not a regular file");
250
+ const platform = options.platform ?? process.platform;
251
+ const currentUid = options.uid ?? process.getuid?.();
252
+ if (platform !== "win32" && typeof currentUid === "number" && typeof meta.uid === "number" && meta.uid !== currentUid) {
253
+ throw new Error("Grok auth.json is not owned by the current user");
254
+ }
255
+ if (typeof meta.size === "number" && meta.size > AUTH_FILE_MAX_BYTES) {
256
+ throw new Error("Grok auth.json is larger than the allowed size");
257
+ }
258
+ document = readSecureJsonFile(path, options);
259
+ if (!document || typeof document !== "object" || Array.isArray(document)) {
260
+ throw new Error("Grok auth document is not an object");
261
+ }
262
+ }
263
+ const scope = `${fields.issuer}::${fields.clientId}`;
264
+ const previous = document[scope] && typeof document[scope] === "object" && !Array.isArray(document[scope]) ? document[scope] : {};
265
+ const next = { ...previous, key: fields.accessToken, auth_mode: "oidc", oidc_issuer: fields.issuer, oidc_client_id: fields.clientId };
266
+ if (asNonEmptyString(fields.expiresAt)) next.expires_at = fields.expiresAt;
267
+ if (asNonEmptyString(fields.refreshToken)) next.refresh_token = fields.refreshToken;
268
+ if (asNonEmptyString(fields.email)) next.email = fields.email;
269
+ if (asNonEmptyString(fields.userId)) next.user_id = fields.userId;
270
+ document[scope] = next;
271
+ writeSecureJsonFile(path, document, options);
272
+ return parseAuthDocument(document);
273
+ }
274
+ function writeSecureJsonFile(path, document, options = {}) {
275
+ const mkdir = options.mkdir ?? ((dir) => mkdirSync(dir, { recursive: true, mode: 448 }));
276
+ const open = options.open ?? ((target) => openSync(target, fsConstants.O_WRONLY | fsConstants.O_CREAT | fsConstants.O_EXCL, 384));
277
+ const write = options.write ?? ((fd2, payload2) => writeSync(fd2, payload2));
278
+ const close = options.close ?? closeSync;
279
+ const rename = options.rename ?? renameSync;
280
+ const unlink = options.unlink ?? unlinkSync;
281
+ const chmod = options.chmod ?? chmodSync;
282
+ mkdir(dirname(path));
283
+ const tmp = `${path}.${randomBytes(6).toString("hex")}.tmp`;
284
+ const payload = `${JSON.stringify(document, null, 2)}
285
+ `;
286
+ const fd = open(tmp);
287
+ try {
288
+ write(fd, payload);
289
+ } catch (error) {
290
+ try {
291
+ close(fd);
292
+ } catch {
293
+ }
294
+ try {
295
+ unlink(tmp);
296
+ } catch {
297
+ }
298
+ throw error;
299
+ }
300
+ close(fd);
301
+ try {
302
+ rename(tmp, path);
303
+ } catch (error) {
304
+ try {
305
+ unlink(tmp);
306
+ } catch {
307
+ }
308
+ throw error;
309
+ }
310
+ try {
311
+ chmod(path, 384);
312
+ } catch {
313
+ }
314
+ }
216
315
  function publicSessionView(session) {
217
316
  if (!session) {
218
317
  return Object.freeze({
@@ -323,7 +422,21 @@ async function readResponseJson(response, options = {}) {
323
422
 
324
423
  // src/catalog.js
325
424
  var REASONING_LEVELS = Object.freeze(["low", "medium", "high", "xhigh"]);
326
- var FALLBACK_CONTEXT_WINDOW = 256e3;
425
+ var DOCUMENTED_CONTEXT_WINDOWS = Object.freeze({
426
+ "grok-4.7": 5e5,
427
+ "grok-4.7-build-fast": 5e5,
428
+ "grok-4.6": 5e5,
429
+ "grok-4.5": 5e5,
430
+ "grok-4.3": 1e6,
431
+ "grok-4.20-0309-reasoning": 1e6,
432
+ "grok-4.20-0309-non-reasoning": 1e6,
433
+ "grok-4.20-multi-agent-0309": 1e6,
434
+ "grok-build-0.1": 256e3
435
+ });
436
+ var FALLBACK_CONTEXT_WINDOW = 5e5;
437
+ function documentedContextWindow(id) {
438
+ return Object.prototype.hasOwnProperty.call(DOCUMENTED_CONTEXT_WINDOWS, id) ? DOCUMENTED_CONTEXT_WINDOWS[id] : void 0;
439
+ }
327
440
  function asId(value) {
328
441
  return typeof value === "string" && value.trim() ? value.trim() : void 0;
329
442
  }
@@ -358,11 +471,12 @@ function extractLiveModels(body) {
358
471
  if (!id || seen.has(id)) continue;
359
472
  seen.add(id);
360
473
  const object = row && typeof row === "object" ? row : { id };
474
+ const contextWindow = documentedContextWindow(id) ?? contextWindowOf(object) ?? FALLBACK_CONTEXT_WINDOW;
361
475
  models.push(Object.freeze({
362
476
  id,
363
477
  name: displayNameOf(id, object),
364
- contextWindow: contextWindowOf(object) ?? FALLBACK_CONTEXT_WINDOW,
365
- maxTokens: contextWindowOf(object) ?? FALLBACK_CONTEXT_WINDOW,
478
+ contextWindow,
479
+ maxTokens: contextWindow,
366
480
  reasoning: object.reasoning !== false,
367
481
  reasoningEfforts: reasoningEffortsOf(object)
368
482
  }));
@@ -373,8 +487,8 @@ function fallbackModels() {
373
487
  return FALLBACK_MODEL_IDS.map((id) => Object.freeze({
374
488
  id,
375
489
  name: id === "grok-4.7" ? "Grok 4.7" : id === "grok-4.6" ? "Grok 4.6" : "Grok 4.5",
376
- contextWindow: FALLBACK_CONTEXT_WINDOW,
377
- maxTokens: FALLBACK_CONTEXT_WINDOW,
490
+ contextWindow: documentedContextWindow(id) ?? FALLBACK_CONTEXT_WINDOW,
491
+ maxTokens: documentedContextWindow(id) ?? FALLBACK_CONTEXT_WINDOW,
378
492
  reasoning: true,
379
493
  reasoningEfforts: id === "grok-4.5" ? ["low", "medium", "high"] : ["low", "medium", "high", "xhigh"],
380
494
  defaultEffort: "high",
@@ -814,7 +928,7 @@ async function fetchBillingUsage(accessToken, options = {}) {
814
928
  import { existsSync as existsSync2, readFileSync as readFileSync3 } from "node:fs";
815
929
  import { createRequire } from "node:module";
816
930
  import { homedir as homedir2 } from "node:os";
817
- import { dirname, join as join2 } from "node:path";
931
+ import { dirname as dirname2, join as join2 } from "node:path";
818
932
  import { pathToFileURL } from "node:url";
819
933
  function withImportTimeout(promise, ms, message) {
820
934
  let timer;
@@ -835,16 +949,16 @@ function hostModuleRoots(env = process.env, argv1 = process.argv[1]) {
835
949
  const override = env.DSH_GROK_PEER_ROOT;
836
950
  if (typeof override === "string" && override.trim()) push(override.trim());
837
951
  if (typeof argv1 === "string" && argv1) {
838
- let dir = dirname(argv1);
839
- for (let depth = 0; depth < 6 && dir && dir !== dirname(dir); depth++) {
952
+ let dir = dirname2(argv1);
953
+ for (let depth = 0; depth < 6 && dir && dir !== dirname2(dir); depth++) {
840
954
  push(join2(dir, "node_modules"));
841
- dir = dirname(dir);
955
+ dir = dirname2(dir);
842
956
  }
843
957
  }
844
958
  const prefix = env.NPM_CONFIG_PREFIX;
845
959
  if (typeof prefix === "string" && prefix.trim()) push(join2(prefix.trim(), "lib", "node_modules"));
846
960
  if (typeof process.execPath === "string" && process.execPath) {
847
- push(join2(dirname(process.execPath), "..", "lib", "node_modules"));
961
+ push(join2(dirname2(process.execPath), "..", "lib", "node_modules"));
848
962
  }
849
963
  push(join2("/opt/homebrew", "lib", "node_modules"));
850
964
  push(join2("/usr/local", "lib", "node_modules"));
@@ -1134,40 +1248,209 @@ async function createGrokBuildAdapter(session, options = {}) {
1134
1248
  };
1135
1249
  }
1136
1250
 
1137
- // src/session.js
1138
- var WINDOWS_EXEC_EXTENSIONS = [".COM", ".EXE", ".BAT", ".CMD"];
1139
- var hasPathSeparator = (value) => value.includes("/") || value.includes("\\");
1140
- function executableNames(bin, platform, env) {
1141
- if (platform !== "win32") return [bin];
1142
- const declared = String(env.PATHEXT ?? "").split(";").map((part) => part.trim()).filter(Boolean).map((part) => part.startsWith(".") ? part : `.${part}`);
1143
- const extensions = declared.length > 0 ? declared : WINDOWS_EXEC_EXTENSIONS;
1144
- return [bin, ...extensions.map((extension) => `${bin}${extension}`)];
1145
- }
1146
- function firstExisting(names, exists) {
1147
- for (const name2 of names) if (exists(name2)) return name2;
1251
+ // src/oauth.js
1252
+ var OAUTH_SCOPES = "openid profile email offline_access api:access grok-cli:access";
1253
+ var OAUTH_BODY_LIMIT = 64 * 1024;
1254
+ var OAUTH_ERROR_LIMIT = 180;
1255
+ function collapse(value) {
1256
+ return String(value ?? "").replace(/\s+/gu, " ").trim().slice(0, OAUTH_ERROR_LIMIT);
1257
+ }
1258
+ function oauthError(body, status) {
1259
+ const code = collapse(body?.error) || "request_failed";
1260
+ const description = collapse(body?.error_description);
1261
+ if (description && description !== code) return `${code}: ${description} (HTTP ${status})`;
1262
+ return `${code} (HTTP ${status})`;
1263
+ }
1264
+ async function readOauthBody(response) {
1265
+ const status = typeof response.status === "number" ? response.status : 0;
1266
+ const declared = Number(response.headers?.get?.("content-length"));
1267
+ if (Number.isFinite(declared) && declared > OAUTH_BODY_LIMIT) {
1268
+ throw new Error(`OAuth response exceeded ${OAUTH_BODY_LIMIT} bytes (HTTP ${status})`);
1269
+ }
1270
+ let text;
1271
+ try {
1272
+ text = await readResponseText(response);
1273
+ } catch (error) {
1274
+ throw new Error(`OAuth response could not be read (HTTP ${status})`, { cause: error });
1275
+ }
1276
+ if (typeof text !== "string" || text.length > OAUTH_BODY_LIMIT) {
1277
+ throw new Error(`OAuth response exceeded ${OAUTH_BODY_LIMIT} bytes (HTTP ${status})`);
1278
+ }
1279
+ try {
1280
+ return JSON.parse(text);
1281
+ } catch {
1282
+ throw new Error(`OAuth endpoint returned HTTP ${status} with a non-JSON body`);
1283
+ }
1284
+ }
1285
+ function timeoutSignal(ms) {
1286
+ if (typeof AbortSignal !== "undefined" && typeof AbortSignal.timeout === "function") {
1287
+ return AbortSignal.timeout(ms);
1288
+ }
1148
1289
  return void 0;
1149
1290
  }
1150
- function pathEntry(dir, platform) {
1151
- return platform === "win32" && dir.length > 1 && dir.startsWith('"') && dir.endsWith('"') ? dir.slice(1, -1) : dir;
1291
+ async function postForm(url, params, fetchImpl) {
1292
+ const response = await fetchImpl(url, {
1293
+ method: "POST",
1294
+ headers: {
1295
+ accept: "application/json",
1296
+ "content-type": "application/x-www-form-urlencoded"
1297
+ },
1298
+ body: new URLSearchParams(params).toString(),
1299
+ signal: timeoutSignal(CLI_REFRESH_TIMEOUT_MS)
1300
+ });
1301
+ const body = await readOauthBody(response);
1302
+ return { status: typeof response.status === "number" ? response.status : 0, body };
1303
+ }
1304
+ function isXaiHttpsUrl(value) {
1305
+ try {
1306
+ const url = new URL(value);
1307
+ const host = url.hostname.toLowerCase();
1308
+ return url.protocol === "https:" && !url.username && !url.password && (host === "x.ai" || host.endsWith(".x.ai"));
1309
+ } catch {
1310
+ return false;
1311
+ }
1312
+ }
1313
+ function endpointOnIssuer(value, issuer, field) {
1314
+ let url;
1315
+ let issuerUrl;
1316
+ try {
1317
+ url = new URL(value);
1318
+ issuerUrl = new URL(issuer);
1319
+ } catch {
1320
+ throw new Error(`OIDC discovery returned an invalid ${field}`);
1321
+ }
1322
+ if (url.protocol !== "https:" || issuerUrl.protocol !== "https:") {
1323
+ throw new Error(`OIDC discovery returned a non-HTTPS ${field}`);
1324
+ }
1325
+ if (url.username || url.password) throw new Error(`OIDC discovery returned credentials in ${field}`);
1326
+ if (url.origin !== issuerUrl.origin) throw new Error(`OIDC discovery ${field} does not match the issuer`);
1327
+ return url.toString();
1328
+ }
1329
+ function fallbackOauthEndpoints(issuer = XAI_OAUTH_ISSUER) {
1330
+ const base = String(issuer).replace(/\/+$/u, "");
1331
+ return {
1332
+ deviceAuthorizationEndpoint: `${base}/oauth2/device/code`,
1333
+ tokenEndpoint: `${base}/oauth2/token`
1334
+ };
1335
+ }
1336
+ async function discoverOauthEndpoints(issuer = XAI_OAUTH_ISSUER, options = {}) {
1337
+ const fetchImpl = options.fetch ?? fetch;
1338
+ const base = String(issuer).replace(/\/+$/u, "");
1339
+ try {
1340
+ const response = await fetchImpl(`${base}/.well-known/openid-configuration`, {
1341
+ headers: { accept: "application/json" },
1342
+ signal: timeoutSignal(CLI_REFRESH_TIMEOUT_MS)
1343
+ });
1344
+ const body = await readOauthBody(response);
1345
+ const status = typeof response.status === "number" ? response.status : 0;
1346
+ if (status < 200 || status >= 300) throw new Error(`OIDC discovery failed (HTTP ${status})`);
1347
+ const discovered = typeof body?.issuer === "string" ? body.issuer.replace(/\/+$/u, "") : "";
1348
+ if (discovered !== base) throw new Error("OIDC discovery issuer does not match the requested issuer");
1349
+ return {
1350
+ deviceAuthorizationEndpoint: endpointOnIssuer(body.device_authorization_endpoint, base, "device_authorization_endpoint"),
1351
+ tokenEndpoint: endpointOnIssuer(body.token_endpoint, base, "token_endpoint")
1352
+ };
1353
+ } catch {
1354
+ return fallbackOauthEndpoints(base);
1355
+ }
1356
+ }
1357
+ function clockMs(now) {
1358
+ if (typeof now === "function") return now();
1359
+ if (typeof now === "number" && Number.isFinite(now)) return now;
1360
+ return Date.now();
1152
1361
  }
1153
- function resolveGrokBin(env = process.env, exists = existsSync3, platform = process.platform) {
1154
- const override = typeof env.DSH_GROK_BIN === "string" && env.DSH_GROK_BIN.trim() ? env.DSH_GROK_BIN.trim() : void 0;
1155
- if (override !== void 0) {
1156
- if (!hasPathSeparator(override)) return override;
1157
- return firstExisting(executableNames(override, platform, env), exists) ?? override;
1362
+ function expiresAtFrom(body, accessToken, nowMs) {
1363
+ if (typeof body?.expires_in === "number" && Number.isFinite(body.expires_in) && body.expires_in > 0) {
1364
+ return new Date(nowMs + body.expires_in * 1e3).toISOString();
1158
1365
  }
1159
- const local = join3(grokHome(env), "bin", "grok");
1160
- const installed = firstExisting(executableNames(local, platform, env), exists);
1161
- if (installed !== void 0) return installed;
1162
- return "grok";
1366
+ const exp = jwtExpiryMs(accessToken);
1367
+ return typeof exp === "number" ? new Date(exp).toISOString() : void 0;
1368
+ }
1369
+ function jwtExpiryMs(token) {
1370
+ const parts = typeof token === "string" ? token.split(".") : [];
1371
+ if (parts.length < 2) return void 0;
1372
+ try {
1373
+ const payload = JSON.parse(Buffer.from(parts[1], "base64url").toString("utf8"));
1374
+ if (typeof payload?.exp === "number" && Number.isFinite(payload.exp)) return payload.exp * 1e3;
1375
+ } catch {
1376
+ return void 0;
1377
+ }
1378
+ return void 0;
1379
+ }
1380
+ async function requestDeviceAuthorization(options = {}) {
1381
+ const fetchImpl = options.fetch ?? fetch;
1382
+ const clientId = options.clientId ?? GROK_OIDC_CLIENT_ID;
1383
+ const scopes = options.scopes ?? OAUTH_SCOPES;
1384
+ const endpoint = options.endpoint;
1385
+ if (!isXaiHttpsUrl(endpoint)) throw new Error("Refusing to request a device code from a non-x.ai endpoint");
1386
+ const { status, body } = await postForm(endpoint, {
1387
+ client_id: clientId,
1388
+ scope: scopes
1389
+ }, fetchImpl);
1390
+ if (body?.error || status < 200 || status >= 300) {
1391
+ throw new Error(`Could not start device sign-in: ${oauthError(body, status)}`);
1392
+ }
1393
+ const deviceCode = typeof body?.device_code === "string" ? body.device_code : "";
1394
+ const userCode = typeof body?.user_code === "string" ? body.user_code : "";
1395
+ const verificationUri = typeof body?.verification_uri === "string" ? body.verification_uri : void 0;
1396
+ const verificationUriComplete = typeof body?.verification_uri_complete === "string" ? body.verification_uri_complete : void 0;
1397
+ if (!deviceCode || !userCode) throw new Error("Device sign-in returned no user code");
1398
+ return {
1399
+ deviceCode,
1400
+ userCode,
1401
+ verificationUri,
1402
+ verificationUriComplete,
1403
+ expiresIn: typeof body?.expires_in === "number" ? body.expires_in : void 0,
1404
+ interval: typeof body?.interval === "number" ? body.interval : void 0
1405
+ };
1163
1406
  }
1164
- function grokCliAvailable(env = process.env, exists = existsSync3, platform = process.platform) {
1165
- const bin = resolveGrokBin(env, exists, platform);
1166
- if (hasPathSeparator(bin)) return exists(bin);
1167
- const delimiter = platform === "win32" ? ";" : ":";
1168
- const names = executableNames(bin, platform, env);
1169
- return String(env.PATH ?? "").split(delimiter).some((dir) => dir && names.some((name2) => exists(join3(pathEntry(dir, platform), name2))));
1407
+ async function exchangeDeviceCode(options = {}) {
1408
+ const fetchImpl = options.fetch ?? fetch;
1409
+ const clientId = options.clientId ?? GROK_OIDC_CLIENT_ID;
1410
+ const endpoint = options.endpoint;
1411
+ if (!isXaiHttpsUrl(endpoint)) return { kind: "stop", error: "refusing a non-x.ai token endpoint" };
1412
+ const { status, body } = await postForm(endpoint, {
1413
+ grant_type: "urn:ietf:params:oauth:grant-type:device_code",
1414
+ client_id: clientId,
1415
+ device_code: options.deviceCode
1416
+ }, fetchImpl);
1417
+ return classifyTokenResponse(body, status, clockMs(options.now));
1418
+ }
1419
+ async function refreshOauthToken(options = {}) {
1420
+ const fetchImpl = options.fetch ?? fetch;
1421
+ const endpoint = options.endpoint;
1422
+ if (!isXaiHttpsUrl(endpoint)) throw new Error("Refusing to refresh a token at a non-x.ai endpoint");
1423
+ const { status, body } = await postForm(endpoint, {
1424
+ grant_type: "refresh_token",
1425
+ client_id: options.clientId ?? GROK_OIDC_CLIENT_ID,
1426
+ refresh_token: options.refreshToken
1427
+ }, fetchImpl);
1428
+ const result = classifyTokenResponse(body, status, clockMs(options.now));
1429
+ if (result.kind !== "ok") throw new Error(`Could not refresh the session: ${result.error ?? "unknown"}`);
1430
+ return result;
1431
+ }
1432
+ function classifyTokenResponse(body, status, nowMs) {
1433
+ const error = typeof body?.error === "string" ? body.error : "";
1434
+ if (error === "authorization_pending") return { kind: "pending" };
1435
+ if (error === "slow_down") return { kind: "slow_down" };
1436
+ if (error) return { kind: "stop", error: oauthError(body, status) };
1437
+ const accessToken = typeof body?.access_token === "string" ? body.access_token : "";
1438
+ if (!accessToken || status < 200 || status >= 300) {
1439
+ return { kind: "stop", error: oauthError(body, status) };
1440
+ }
1441
+ const refreshToken = typeof body?.refresh_token === "string" && body.refresh_token ? body.refresh_token : void 0;
1442
+ return {
1443
+ kind: "ok",
1444
+ accessToken,
1445
+ refreshToken,
1446
+ expiresIn: typeof body?.expires_in === "number" ? body.expires_in : void 0,
1447
+ expiresAt: expiresAtFrom(body, accessToken, nowMs),
1448
+ issuer: XAI_OAUTH_ISSUER,
1449
+ clientId: GROK_OIDC_CLIENT_ID
1450
+ };
1170
1451
  }
1452
+
1453
+ // src/session.js
1171
1454
  function openExternal(url, options = {}) {
1172
1455
  const spawnFn = options.spawn ?? spawn;
1173
1456
  const platform = options.platform ?? process.platform;
@@ -1191,127 +1474,59 @@ function openExternal(url, options = {}) {
1191
1474
  child.unref?.();
1192
1475
  });
1193
1476
  }
1194
- var LOGIN_URL_PATTERN = /https?:\/\/[^\s<>"'`\\]+/u;
1195
- var DEVICE_CODE_PATTERN = /\b([A-Z0-9]{4}-[A-Z0-9]{4})\b/u;
1196
- async function spawnGrokLogin(options = {}) {
1197
- const spawnFn = options.spawn ?? spawn;
1198
- const bin = resolveGrokBin(options.env, options.exists);
1199
- const args = options.device ? ["login", "--device-auth"] : ["login"];
1200
- const startTimeoutMs = typeof options.startTimeoutMs === "number" && options.startTimeoutMs > 0 ? options.startTimeoutMs : LOGIN_START_TIMEOUT_MS;
1201
- const openUrl = options.openUrl ?? ((url) => openExternal(url, { spawn: options.openSpawn }));
1202
- return new Promise((resolve, reject) => {
1203
- let child;
1204
- try {
1205
- child = spawnFn(bin, args, {
1206
- stdio: options.stdio ?? ["ignore", "pipe", "pipe"],
1207
- env: options.env ?? process.env
1208
- });
1209
- } catch (error) {
1210
- reject(new Error(`Could not start grok CLI (${bin})`, { cause: error }));
1211
- return;
1212
- }
1213
- let settled = false;
1214
- let loginUrl;
1215
- let userCode;
1216
- let buffer = "";
1217
- let timer;
1218
- const succeed = (value) => {
1219
- if (settled) return;
1220
- settled = true;
1221
- if (timer) clearTimeout(timer);
1222
- resolve(value);
1223
- };
1224
- const scan = (text) => {
1225
- if (text) buffer = `${buffer}${text}`.slice(-8192);
1226
- if (!userCode) {
1227
- const code = DEVICE_CODE_PATTERN.exec(buffer);
1228
- if (code) userCode = code[1];
1229
- }
1230
- if (loginUrl) return;
1231
- const match = LOGIN_URL_PATTERN.exec(buffer);
1232
- if (!match) return;
1233
- loginUrl = match[0];
1234
- try {
1235
- void openUrl(loginUrl);
1236
- } catch {
1237
- }
1238
- succeed({ ok: true, pending: true, loginUrl, userCode, child });
1239
- };
1240
- const piped = Boolean(child.stdout && child.stderr);
1241
- if (piped) {
1242
- child.stdout.on("data", (chunk) => scan(String(chunk)));
1243
- child.stderr.on("data", (chunk) => scan(String(chunk)));
1244
- timer = setTimeout(() => {
1245
- succeed({
1246
- ok: true,
1247
- pending: true,
1248
- loginUrl,
1249
- userCode,
1250
- child,
1251
- warning: `grok login printed no sign-in URL within ${startTimeoutMs}ms`
1252
- });
1253
- }, startTimeoutMs);
1254
- }
1255
- child.on("error", (error) => {
1256
- if (settled) return;
1257
- settled = true;
1258
- if (timer) clearTimeout(timer);
1259
- reject(new Error(`Could not start grok CLI (${bin})`, { cause: error }));
1260
- });
1261
- child.on("exit", (code, signal) => {
1262
- if (settled) return;
1263
- settled = true;
1264
- if (timer) clearTimeout(timer);
1265
- if (code === 0) resolve({ ok: true, pending: false, loginUrl, userCode, child });
1266
- else reject(new Error(signal ? `grok login terminated by ${signal}` : `grok login exited with code ${code ?? "unknown"}`));
1267
- });
1477
+ function defaultSleep(ms) {
1478
+ return new Promise((resolve) => {
1479
+ const timer = setTimeout(resolve, ms);
1480
+ if (typeof timer.unref === "function") timer.unref();
1268
1481
  });
1269
1482
  }
1270
- async function spawnGrokRefresh(options = {}) {
1271
- const spawnFn = options.spawn ?? spawn;
1272
- const bin = resolveGrokBin(options.env, options.exists);
1273
- const timeoutMs = typeof options.timeoutMs === "number" && options.timeoutMs > 0 ? options.timeoutMs : CLI_REFRESH_TIMEOUT_MS;
1274
- return new Promise((resolve, reject) => {
1275
- let child;
1276
- try {
1277
- child = spawnFn(bin, ["models"], {
1278
- stdio: options.stdio ?? "ignore",
1279
- env: options.env ?? process.env
1280
- });
1281
- } catch (error) {
1282
- reject(new Error(`Could not start grok CLI (${bin})`, { cause: error }));
1283
- return;
1284
- }
1285
- let settled = false;
1286
- const timer = setTimeout(() => {
1287
- if (settled) return;
1288
- settled = true;
1289
- try {
1290
- child.kill("SIGKILL");
1291
- } catch {
1292
- }
1293
- resolve({ ok: false, reason: "timeout" });
1294
- }, timeoutMs);
1295
- child.on("error", (error) => {
1296
- if (settled) return;
1297
- settled = true;
1298
- clearTimeout(timer);
1299
- reject(new Error(`Could not run grok CLI (${bin})`, { cause: error }));
1300
- });
1301
- child.on("exit", (code) => {
1302
- if (settled) return;
1303
- settled = true;
1304
- clearTimeout(timer);
1305
- resolve({ ok: true, code });
1306
- });
1307
- });
1483
+ function issuerOf(session) {
1484
+ if (typeof session?.oidcIssuer === "string" && session.oidcIssuer.startsWith("https://")) return session.oidcIssuer;
1485
+ const scope = typeof session?.scope === "string" ? session.scope : "";
1486
+ const issuer = scope.split("::")[0];
1487
+ if (issuer?.startsWith("https://")) return issuer;
1488
+ return XAI_OAUTH_ISSUER;
1489
+ }
1490
+ function clientIdOf(session) {
1491
+ if (typeof session?.oidcClientId === "string" && session.oidcClientId) return session.oidcClientId;
1492
+ const scope = typeof session?.scope === "string" ? session.scope : "";
1493
+ const clientId = scope.split("::")[1];
1494
+ return clientId || GROK_OIDC_CLIENT_ID;
1308
1495
  }
1309
1496
  async function defaultRenewSession(options = {}) {
1310
1497
  const env = options.env ?? process.env;
1311
- if (!grokCliAvailable(env)) return void 0;
1312
- await spawnGrokRefresh({ env });
1313
- const parsed = (options.readAuth ?? readGrokAuthSession)();
1314
- return parsed?.session;
1498
+ const path = options.authPath ?? authJsonPath(env);
1499
+ const read = options.readAuth ?? (() => readGrokAuthSession(path));
1500
+ let parsed;
1501
+ try {
1502
+ parsed = read();
1503
+ } catch {
1504
+ return void 0;
1505
+ }
1506
+ const current = parsed?.session;
1507
+ if (!current?.refreshToken) return void 0;
1508
+ const issuer = issuerOf(current);
1509
+ const clientId = clientIdOf(current);
1510
+ const fetchImpl = options.fetch ?? fetch;
1511
+ const endpoints = options.endpoints ?? await discoverOauthEndpoints(issuer, { fetch: fetchImpl });
1512
+ const nowMs = typeof options.now === "function" ? options.now() : Date.now();
1513
+ const tokens = await refreshOauthToken({
1514
+ endpoint: endpoints.tokenEndpoint,
1515
+ clientId,
1516
+ refreshToken: current.refreshToken,
1517
+ fetch: fetchImpl,
1518
+ now: () => nowMs
1519
+ });
1520
+ const written = writeOauthSession(path, {
1521
+ issuer,
1522
+ clientId,
1523
+ accessToken: tokens.accessToken,
1524
+ refreshToken: tokens.refreshToken || current.refreshToken,
1525
+ expiresAt: tokens.expiresAt ?? current.expiresAt,
1526
+ email: current.email,
1527
+ userId: current.userId
1528
+ });
1529
+ return written.session;
1315
1530
  }
1316
1531
  async function defaultCredentialRefOf() {
1317
1532
  try {
@@ -1348,9 +1563,21 @@ function createSessionService({
1348
1563
  storeTokenTimeoutMs = STORE_TOKEN_TIMEOUT_MS,
1349
1564
  credentialsIoTimeoutMs = CREDENTIALS_IO_TIMEOUT_MS,
1350
1565
  credentialRefOf = defaultCredentialRefOf,
1351
- renewSession = defaultRenewSession,
1566
+ renewSession,
1567
+ fetch: fetchImpl,
1568
+ authPath,
1569
+ env,
1570
+ oauthEndpoints,
1352
1571
  now = () => Date.now()
1353
1572
  } = {}) {
1573
+ const renew = renewSession ?? (() => defaultRenewSession({
1574
+ readAuth,
1575
+ fetch: fetchImpl,
1576
+ authPath,
1577
+ env,
1578
+ endpoints: oauthEndpoints,
1579
+ now
1580
+ }));
1354
1581
  let catalog = { models: [], source: "signed-out", error: void 0 };
1355
1582
  let lastPublic = publicSessionView(void 0);
1356
1583
  let lastUsage = unavailable("Not fetched yet");
@@ -1389,7 +1616,7 @@ function createSessionService({
1389
1616
  if (renewalInFlight) return renewalInFlight;
1390
1617
  renewalInFlight = (async () => {
1391
1618
  try {
1392
- const session = await renewSession();
1619
+ const session = await renew();
1393
1620
  const token = adoptSession(session);
1394
1621
  if (token) notifyCatalogChange();
1395
1622
  return token;
@@ -1529,7 +1756,7 @@ function createSessionService({
1529
1756
  );
1530
1757
  });
1531
1758
  });
1532
- const message = parsed.reason === "api-key-only" ? "Found an API-key entry only. Sign in with SuperGrok / X Premium via grok login." : "No Grok Build subscription session in auth.json. Run grok login first.";
1759
+ const message = parsed.reason === "api-key-only" ? "Found an API-key entry only. Sign in with a SuperGrok / X Premium account." : "No Grok Build subscription session in auth.json. Sign in from Settings first.";
1533
1760
  notifyCatalogChange();
1534
1761
  return { ok: false, error: message, account: lastPublic, catalog, usage: lastUsage };
1535
1762
  }
@@ -1551,15 +1778,16 @@ function createSessionService({
1551
1778
  kickBackgroundUsageRefresh();
1552
1779
  return { ok: true, account: lastPublic, catalog, usage: lastUsage };
1553
1780
  };
1781
+ const snapshot = () => ({ account: lastPublic, catalog, usage: lastUsage, authPath: authPath ?? authJsonPath(env) });
1554
1782
  const status = async () => {
1555
1783
  if (typeof memoryAccessToken === "string" && memoryAccessToken.length > 0 || lastPublic.signedIn === true) {
1556
- return { account: lastPublic, catalog, usage: lastUsage, cliAvailable: grokCliAvailable(), authPath: authJsonPath() };
1784
+ return snapshot();
1557
1785
  }
1558
1786
  try {
1559
1787
  const parsed = readAuth();
1560
1788
  if (parsed.session) {
1561
1789
  adoptSession(parsed.session);
1562
- return { account: lastPublic, catalog, usage: lastUsage, cliAvailable: grokCliAvailable(), authPath: authJsonPath() };
1790
+ return snapshot();
1563
1791
  }
1564
1792
  } catch (error) {
1565
1793
  logger?.warn?.(
@@ -1578,36 +1806,95 @@ function createSessionService({
1578
1806
  lastPublic = publicSessionView(void 0);
1579
1807
  catalog = { models: [], source: "signed-out", error: void 0 };
1580
1808
  lastUsage = unavailable("Not signed in");
1581
- return { account: lastPublic, catalog, usage: lastUsage, cliAvailable: grokCliAvailable(), authPath: authJsonPath() };
1809
+ return snapshot();
1582
1810
  }
1583
1811
  memoryAccessToken = token;
1584
1812
  lastPublic = Object.freeze({ signedIn: true, maskedAccount: "\u2022\u2022\u2022\u2022", authMode: "oidc", source: "dsh-credentials" });
1585
- return { account: lastPublic, catalog, usage: lastUsage, cliAvailable: grokCliAvailable(), authPath: authJsonPath() };
1813
+ return snapshot();
1586
1814
  };
1587
- const login = async (options) => {
1588
- const started = await spawnGrokLogin(options);
1589
- const extra = {
1590
- ...started.loginUrl === void 0 ? {} : { loginUrl: started.loginUrl },
1591
- ...started.userCode === void 0 ? {} : { userCode: started.userCode },
1592
- ...started.warning === void 0 ? {} : { warning: started.warning }
1593
- };
1594
- if (started.pending) {
1595
- started.child?.once?.("exit", (code) => {
1596
- if (code !== 0) return;
1597
- scheduleDeferred(() => {
1598
- void pull().catch((error) => {
1599
- logger?.warn?.(
1600
- "Grok subscription login sync failed: %s",
1601
- error instanceof Error ? error.message : "unknown"
1602
- );
1603
- });
1604
- });
1815
+ let loginEpoch = 0;
1816
+ const login = async (loginOptions) => {
1817
+ const epoch = ++loginEpoch;
1818
+ const fetchLogin = loginOptions?.fetch ?? fetchImpl ?? fetch;
1819
+ const path = loginOptions?.authPath ?? authPath ?? authJsonPath(env);
1820
+ const sleep = loginOptions?.sleep ?? defaultSleep;
1821
+ const openUrl = loginOptions?.openUrl ?? ((url) => openExternal(url, { spawn: loginOptions?.openSpawn }));
1822
+ const clock = () => typeof loginOptions?.now === "function" ? loginOptions.now() : now();
1823
+ let endpoints;
1824
+ let device;
1825
+ try {
1826
+ endpoints = loginOptions?.endpoints ?? oauthEndpoints ?? await discoverOauthEndpoints(XAI_OAUTH_ISSUER, { fetch: fetchLogin });
1827
+ device = await requestDeviceAuthorization({
1828
+ endpoint: endpoints.deviceAuthorizationEndpoint,
1829
+ fetch: fetchLogin
1605
1830
  });
1606
- return { ok: true, pending: true, ...extra, ...await status() };
1831
+ } catch (error) {
1832
+ const message = error instanceof Error ? error.message : "Could not start sign-in";
1833
+ return { ok: false, error: message, ...await status() };
1607
1834
  }
1608
- return { ...await pull(), pending: false, ...extra };
1835
+ const loginUrl = device.verificationUriComplete || device.verificationUri;
1836
+ if (!isXaiHttpsUrl(loginUrl) || !device.userCode || !device.deviceCode) {
1837
+ return { ok: false, error: "Sign-in did not return a verification link.", ...await status() };
1838
+ }
1839
+ try {
1840
+ void openUrl(loginUrl);
1841
+ } catch {
1842
+ }
1843
+ const deadline = clock() + (typeof device.expiresIn === "number" && device.expiresIn > 0 ? device.expiresIn : 900) * 1e3;
1844
+ let interval = Number.isFinite(device.interval) && device.interval >= 0 ? device.interval : 5;
1845
+ const poll = async () => {
1846
+ try {
1847
+ while (epoch === loginEpoch) {
1848
+ if (clock() >= deadline) {
1849
+ logger?.warn?.("Grok subscription sign-in timed out before authorization");
1850
+ return;
1851
+ }
1852
+ await sleep(interval * 1e3);
1853
+ if (epoch !== loginEpoch) return;
1854
+ const result = await exchangeDeviceCode({
1855
+ endpoint: endpoints.tokenEndpoint,
1856
+ deviceCode: device.deviceCode,
1857
+ fetch: fetchLogin,
1858
+ now: clock
1859
+ });
1860
+ if (epoch !== loginEpoch) return;
1861
+ if (result.kind === "pending") continue;
1862
+ if (result.kind === "slow_down") {
1863
+ interval += 5;
1864
+ continue;
1865
+ }
1866
+ if (result.kind !== "ok") {
1867
+ logger?.warn?.("Grok subscription sign-in stopped: %s", result.error ?? "unknown");
1868
+ return;
1869
+ }
1870
+ writeOauthSession(path, {
1871
+ issuer: result.issuer,
1872
+ clientId: result.clientId,
1873
+ accessToken: result.accessToken,
1874
+ refreshToken: result.refreshToken,
1875
+ expiresAt: result.expiresAt
1876
+ });
1877
+ if (epoch !== loginEpoch) return;
1878
+ await pull();
1879
+ return;
1880
+ }
1881
+ } catch (error) {
1882
+ logger?.warn?.(
1883
+ "Grok subscription sign-in failed: %s",
1884
+ error instanceof Error ? error.message : "unknown"
1885
+ );
1886
+ } finally {
1887
+ try {
1888
+ loginOptions?.onSettled?.();
1889
+ } catch {
1890
+ }
1891
+ }
1892
+ };
1893
+ void poll();
1894
+ return { ok: true, pending: true, loginUrl, userCode: device.userCode, ...await status() };
1609
1895
  };
1610
1896
  const logout = async () => {
1897
+ loginEpoch += 1;
1611
1898
  memoryAccessToken = void 0;
1612
1899
  memorySessionTouched = true;
1613
1900
  await clearToken().catch((error) => {
@@ -1630,7 +1917,7 @@ function createSessionService({
1630
1917
  login,
1631
1918
  logout,
1632
1919
  currentToken: readStoredToken,
1633
- /** Force a CLI-backed renewal; used when the provider answers 401. */
1920
+ /** Force a refresh-token renewal; used when the provider answers 401. */
1634
1921
  refreshToken: () => renewAccessToken(),
1635
1922
  models: () => catalog.models,
1636
1923
  catalog: () => catalog,
@@ -1641,10 +1928,10 @@ function createSessionService({
1641
1928
 
1642
1929
  // src/plugin-version.js
1643
1930
  import { spawn as spawn2 } from "node:child_process";
1644
- import { existsSync as existsSync4 } from "node:fs";
1931
+ import { existsSync as existsSync3 } from "node:fs";
1645
1932
  import { readdir, readFile, realpath } from "node:fs/promises";
1646
1933
  import { homedir as homedir3 } from "node:os";
1647
- import { join as join4 } from "node:path";
1934
+ import { join as join3 } from "node:path";
1648
1935
  import { fileURLToPath } from "node:url";
1649
1936
  var PACKAGE_NAME = PLUGIN_ID;
1650
1937
  var NPM_REGISTRY_LATEST_URL = `https://registry.npmjs.org/${PACKAGE_NAME}/latest`;
@@ -1688,7 +1975,7 @@ var readManifest = async (path) => {
1688
1975
  };
1689
1976
  async function confirmInstalled({ profileDir, expected, settleDelayMs, attempts = 3 }) {
1690
1977
  for (let attempt = 1; attempt <= attempts; attempt += 1) {
1691
- const installed = (await readManifest(join4(profileDir, "node_modules", PACKAGE_NAME, "package.json")))?.version;
1978
+ const installed = (await readManifest(join3(profileDir, "node_modules", PACKAGE_NAME, "package.json")))?.version;
1692
1979
  if (installed === expected) return;
1693
1980
  if (attempt < attempts) await new Promise((resolve) => {
1694
1981
  setTimeout(resolve, settleDelayMs);
@@ -1705,20 +1992,20 @@ async function findInstall({ dshHome, ownPackageJsonUrl }) {
1705
1992
  }
1706
1993
  let entries = [];
1707
1994
  try {
1708
- entries = await readdir(join4(dshHome, "profiles"), { withFileTypes: true });
1995
+ entries = await readdir(join3(dshHome, "profiles"), { withFileTypes: true });
1709
1996
  } catch {
1710
1997
  entries = [];
1711
1998
  }
1712
1999
  const declared = [];
1713
2000
  for (const entry of entries) {
1714
2001
  if (!entry.isDirectory()) continue;
1715
- const profileDir = join4(dshHome, "profiles", entry.name);
1716
- const spec = (await readManifest(join4(profileDir, "package.json")))?.dependencies?.[PACKAGE_NAME];
2002
+ const profileDir = join3(dshHome, "profiles", entry.name);
2003
+ const spec = (await readManifest(join3(profileDir, "package.json")))?.dependencies?.[PACKAGE_NAME];
1717
2004
  if (typeof spec !== "string") continue;
1718
2005
  declared.push({ profile: entry.name, spec });
1719
2006
  if (ownReal === void 0) continue;
1720
2007
  try {
1721
- const installed = await realpath(join4(profileDir, "node_modules", PACKAGE_NAME, "package.json"));
2008
+ const installed = await realpath(join3(profileDir, "node_modules", PACKAGE_NAME, "package.json"));
1722
2009
  if (installed === ownReal) return { kind: classifySpec(spec), profile: entry.name };
1723
2010
  } catch {
1724
2011
  }
@@ -1726,9 +2013,9 @@ async function findInstall({ dshHome, ownPackageJsonUrl }) {
1726
2013
  if (declared.length === 1) return { kind: classifySpec(declared[0].spec), profile: declared[0].profile };
1727
2014
  return { kind: "unknown" };
1728
2015
  }
1729
- var isExistingPath = (value) => typeof value === "string" && value !== "" && existsSync4(value);
2016
+ var isExistingPath = (value) => typeof value === "string" && value !== "" && existsSync3(value);
1730
2017
  var PNPM_SCRIPT = /[\\/]pnpm\.(?:mjs|cjs|js)$/u;
1731
- var dshRuntimeRoot = (value) => isExistingPath(value) && existsSync4(join4(value, "node_modules", "@deepseek-ai", "dsh", "package.json")) ? value : void 0;
2018
+ var dshRuntimeRoot = (value) => isExistingPath(value) && existsSync3(join3(value, "node_modules", "@deepseek-ai", "dsh", "package.json")) ? value : void 0;
1732
2019
  function resolvePnpm({ argv } = {}) {
1733
2020
  const entries = Array.isArray(argv) ? argv : [];
1734
2021
  for (const entry of entries) {
@@ -1737,8 +2024,8 @@ function resolvePnpm({ argv } = {}) {
1737
2024
  for (const entry of entries) {
1738
2025
  const root = dshRuntimeRoot(entry);
1739
2026
  if (root === void 0) continue;
1740
- const script = join4(root, "..", "pnpm", "bin", "pnpm.mjs");
1741
- if (existsSync4(script)) return script;
2027
+ const script = join3(root, "..", "pnpm", "bin", "pnpm.mjs");
2028
+ if (existsSync3(script)) return script;
1742
2029
  }
1743
2030
  return void 0;
1744
2031
  }
@@ -1811,15 +2098,15 @@ function createGrokPluginManager({
1811
2098
  } = {}) {
1812
2099
  if (typeof fetchImpl !== "function") throw new Error("Grok plugin manager requires fetch");
1813
2100
  if (typeof runCommand !== "function") throw new Error("Grok plugin manager requires runCommand");
1814
- const dshHome = typeof env.DSH_HOME === "string" && env.DSH_HOME !== "" ? env.DSH_HOME : join4(homedir3(), ".dsh");
2101
+ const dshHome = typeof env.DSH_HOME === "string" && env.DSH_HOME !== "" ? env.DSH_HOME : join3(homedir3(), ".dsh");
1815
2102
  const launcher = resolveLauncher({ argv, execPath });
1816
2103
  let cached;
1817
2104
  let inFlight;
1818
2105
  let generation = 0;
1819
2106
  let updating = false;
1820
2107
  const fetchLatest = async (signal) => {
1821
- const timeoutSignal = AbortSignal.timeout(timeoutMs);
1822
- const requestSignal = signal === void 0 ? timeoutSignal : AbortSignal.any([signal, timeoutSignal]);
2108
+ const timeoutSignal2 = AbortSignal.timeout(timeoutMs);
2109
+ const requestSignal = signal === void 0 ? timeoutSignal2 : AbortSignal.any([signal, timeoutSignal2]);
1823
2110
  let response;
1824
2111
  try {
1825
2112
  response = await fetchImpl(registryUrl, {
@@ -1901,7 +2188,7 @@ function createGrokPluginManager({
1901
2188
  throw new Error("Grok plugin update could not find the owning profile");
1902
2189
  }
1903
2190
  const latest = await fetchLatest(signal);
1904
- const profileDir = join4(dshHome, "profiles", install.profile);
2191
+ const profileDir = join3(dshHome, "profiles", install.profile);
1905
2192
  let result;
1906
2193
  try {
1907
2194
  result = await runCommand({
@@ -1967,7 +2254,10 @@ function stripSecrets(value) {
1967
2254
  delete next.accessToken;
1968
2255
  delete next.token;
1969
2256
  delete next.refresh;
2257
+ delete next.refreshToken;
1970
2258
  delete next.refresh_token;
2259
+ delete next.deviceCode;
2260
+ delete next.device_code;
1971
2261
  delete next.key;
1972
2262
  if (next.catalog) {
1973
2263
  next.catalog = {