omnirush 0.8.4 → 0.8.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/src/bin.js CHANGED
@@ -60,10 +60,11 @@ import {
60
60
  openBrowser,
61
61
  pollForToken,
62
62
  redactForDisplay,
63
- refreshTokens,
64
63
  saveAuth,
65
64
  savePendingFlow,
66
65
  clearPendingFlow,
66
+ createRefresher,
67
+ sessionEndedMessage,
67
68
  } from "../assets/extensions/omnirush/auth.js";
68
69
 
69
70
  const require = createRequire(import.meta.url);
@@ -162,10 +163,21 @@ async function launchModels(gatewayUrl, accessToken) {
162
163
  const base = String(gatewayUrl).replace(/\/+$/, "");
163
164
  if (process.env.OMNIRUSH_STATIC_MODELS !== "1" && accessToken) {
164
165
  try {
165
- const response = await fetch(`${base}/models`, {
166
- headers: { Authorization: `Bearer ${accessToken}`, Accept: "application/json" },
166
+ const get = (token) => fetch(`${base}/models`, {
167
+ headers: { Authorization: `Bearer ${token}`, Accept: "application/json" },
167
168
  signal: AbortSignal.timeout(2500),
168
169
  });
170
+ let response = await get(accessToken);
171
+ if (response.status === 401) {
172
+ // The stored access token expired (or another process rotated):
173
+ // refresh now, under the shared lock, so the agent starts with a
174
+ // working pair on disk.
175
+ await response.body?.cancel().catch(() => undefined);
176
+ const outcome = await createRefresher({ dir: OMNI_DIR, origin: managerOrigin() })
177
+ .recover(accessToken)
178
+ .catch(() => null);
179
+ if (outcome?.status === "ok") response = await get(outcome.accessToken);
180
+ }
169
181
  if (response.ok) {
170
182
  const payload = await response.json();
171
183
  const models = catalogFromGateway(payload);
@@ -444,15 +456,24 @@ async function cmdLogout() {
444
456
  console.log(`Signed out. Credentials removed from ${OMNI_DIR}`);
445
457
  }
446
458
 
447
- async function fetchMeWithRefresh(auth) {
459
+ /**
460
+ * GET /device/me with the current on-disk token; a 401 adopts a pair
461
+ * another process already rotated, or refreshes under the shared refresh
462
+ * lock (never a bare refresh that could race a running agent). Resolves
463
+ * {me} or {me: null, outcome} with the recover() verdict.
464
+ */
465
+ async function fetchMeWithRefresh() {
448
466
  const origin = managerOrigin();
449
- let me = await deviceMe(origin, { accessToken: auth.accessToken, fetchImpl: globalThis.fetch });
450
- if (me !== null) return { me, auth };
451
- // 401: single-flight refresh (rotate both), retry once.
452
- const next = await refreshTokens(origin, { refreshToken: auth.refreshToken, fetchImpl: globalThis.fetch });
453
- saveAuth(OMNI_DIR, next);
454
- me = await deviceMe(origin, { accessToken: next.accessToken, fetchImpl: globalThis.fetch });
455
- return { me, auth: next };
467
+ const refresher = createRefresher({ dir: OMNI_DIR, origin });
468
+ let token = refresher.accessToken();
469
+ for (let round = 0; round < 3; round++) {
470
+ const me = await deviceMe(origin, { accessToken: token, fetchImpl: globalThis.fetch });
471
+ if (me !== null) return { me };
472
+ const outcome = await refresher.recover(token);
473
+ if (outcome.status !== "ok") return { me: null, outcome };
474
+ token = outcome.accessToken;
475
+ }
476
+ return { me: null, outcome: { status: "dead", reason: "session", detail: "access token refused after refresh" } };
456
477
  }
457
478
 
458
479
  async function cmdWhoami() {
@@ -461,9 +482,13 @@ async function cmdWhoami() {
461
482
  console.error("Omnirush: not signed in. Run `omnirush login` first.");
462
483
  process.exit(1);
463
484
  }
464
- const { me } = await fetchMeWithRefresh(auth);
485
+ const { me, outcome } = await fetchMeWithRefresh();
465
486
  if (!me) {
466
- console.error("Omnirush: credentials rejected — run `omnirush login` again.");
487
+ console.error(
488
+ outcome?.status === "transient"
489
+ ? `Omnirush: cannot reach the manager to verify the session (${outcome.error}) — try again shortly.`
490
+ : sessionEndedMessage(outcome),
491
+ );
467
492
  process.exit(1);
468
493
  }
469
494
  console.log(JSON.stringify(redactForDisplay(me), null, 2));
@@ -491,21 +516,19 @@ async function cmdDoctor() {
491
516
  const auth = loadAuth(OMNI_DIR);
492
517
  if (auth) {
493
518
  try {
494
- const { me } = await fetchMeWithRefresh(auth);
519
+ const { me, outcome } = await fetchMeWithRefresh();
495
520
  if (me) {
496
521
  const label =
497
522
  (me && typeof me === "object" && (me.device_name || me.email || me.user_id || me.id)) ||
498
523
  "device recognized";
499
524
  ok("auth", true, `signed in (${label})`);
525
+ } else if (outcome?.status === "transient") {
526
+ ok("auth", false, `cannot verify session (${outcome.error})`);
500
527
  } else {
501
- ok("auth", false, "credentials rejected — run `omnirush login` again");
528
+ ok("auth", false, sessionEndedMessage(outcome).replace(/^Omnirush: /, ""));
502
529
  }
503
530
  } catch (e) {
504
- if (e?.name === "RefreshRejectedError") {
505
- ok("auth", false, "session expired — run `omnirush login` again");
506
- } else {
507
- ok("auth", false, `cannot verify session (${e.message})`);
508
- }
531
+ ok("auth", false, `cannot verify session (${e.message})`);
509
532
  }
510
533
  } else {
511
534
  const pending = loadPendingFlow(OMNI_DIR);
@@ -706,6 +729,9 @@ function childEnv(auth) {
706
729
  const origin = (process.env.OMNIRUSH_ORIGIN || "").trim().replace(/\/+$/, "") ||
707
730
  gateway.replace(/\/+$/, "").replace(/\/v1$/, ""); // provider base -> manager origin
708
731
  return {
732
+ // Bootstrap values only: the agent (and every sub-agent it spawns)
733
+ // re-reads the shared auth file in OMNIRUSH_DIR for each request, so
734
+ // these never go stale in a way that matters.
709
735
  OMNIRUSH_TOKEN: auth.accessToken,
710
736
  OMNIRUSH_ACCESS_TOKEN: auth.accessToken,
711
737
  OMNIRUSH_ORIGIN: origin,
@@ -790,7 +816,8 @@ async function cmdRun() {
790
816
  const piArgs = withModelDefaults([], resolveModelDefaults(process.env));
791
817
  spawnAgent(cmd, [...args, ...piArgs], {
792
818
  stdio: "inherit",
793
- env: { ...process.env, ...childEnv(auth) },
819
+ // The pair may have rotated during launch (model catalog refresh).
820
+ env: { ...process.env, ...childEnv(loadAuth(OMNI_DIR) ?? auth) },
794
821
  });
795
822
  }
796
823