@agent-team-foundation/first-tree-hub 0.10.13 → 0.10.15

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.
@@ -3,7 +3,7 @@ import { o as logFormatSchema, s as logLevelSchema } from "./logger-core-BTmvdfl
3
3
  import { z } from "zod";
4
4
  import { dirname, join } from "node:path";
5
5
  import { homedir } from "node:os";
6
- import { chmodSync, cpSync, existsSync, mkdirSync, readFileSync, readdirSync, statSync, writeFileSync } from "node:fs";
6
+ import { chmodSync, cpSync, existsSync, mkdirSync, readFileSync, readdirSync, renameSync, statSync, unlinkSync, writeFileSync } from "node:fs";
7
7
  import { randomBytes } from "node:crypto";
8
8
  import { parse, stringify } from "yaml";
9
9
  //#region ../shared/dist/config/index.mjs
@@ -563,6 +563,11 @@ const serverConfigSchema = defineConfig({
563
563
  secret: true
564
564
  })
565
565
  },
566
+ auth: {
567
+ accessTokenExpiry: field(z.string().default("30m"), { env: "FIRST_TREE_HUB_AUTH_ACCESS_TOKEN_EXPIRY" }),
568
+ refreshTokenExpiry: field(z.string().default("30d"), { env: "FIRST_TREE_HUB_AUTH_REFRESH_TOKEN_EXPIRY" }),
569
+ connectTokenExpiry: field(z.string().default("10m"), { env: "FIRST_TREE_HUB_AUTH_CONNECT_TOKEN_EXPIRY" })
570
+ },
566
571
  contextTree: optional({
567
572
  repo: field(z.string(), {
568
573
  env: "FIRST_TREE_HUB_CONTEXT_TREE_REPO",
@@ -644,6 +649,8 @@ const serverConfigSchema = defineConfig({
644
649
  //#endregion
645
650
  //#region src/core/bootstrap.ts
646
651
  var bootstrap_exports = /* @__PURE__ */ __exportAll({
652
+ AuthRefreshFailedError: () => AuthRefreshFailedError,
653
+ AuthRefreshRateLimitedError: () => AuthRefreshRateLimitedError,
647
654
  ensureFreshAccessToken: () => ensureFreshAccessToken,
648
655
  ensureFreshAdminToken: () => ensureFreshAdminToken,
649
656
  loadCredentials: () => loadCredentials,
@@ -686,6 +693,53 @@ function resolveAccessToken() {
686
693
  return creds.accessToken;
687
694
  }
688
695
  /**
696
+ * Thrown when `/auth/refresh` returns 401 — i.e. the persisted refresh
697
+ * token has expired or been revoked, so no amount of retrying will get
698
+ * us back online without operator action. Callers (the WS reconnect
699
+ * loop in particular) catch this distinctly from generic network/HTTP
700
+ * errors so they can stop the 1Hz reconnect-and-fail thrash and ask
701
+ * systemd/launchd to back off.
702
+ */
703
+ var AuthRefreshFailedError = class extends Error {
704
+ constructor(message) {
705
+ super(message);
706
+ this.name = "AuthRefreshFailedError";
707
+ }
708
+ };
709
+ /**
710
+ * Thrown when `/auth/refresh` returns 429. Carries the server-suggested
711
+ * retry-after (or a sane default) so the WS reconnect loop can wait at
712
+ * least that long instead of pounding the limiter inside the same window
713
+ * with its default 1/2/4/8s exponential backoff — which would just keep
714
+ * the rate-limit bucket full and stretch the outage. Defaults to 30s when
715
+ * the server omits the header.
716
+ */
717
+ var AuthRefreshRateLimitedError = class extends Error {
718
+ retryAfterMs;
719
+ constructor(retryAfterMs, message) {
720
+ super(message ?? `Refresh request rate-limited; retry after ${Math.round(retryAfterMs / 1e3)}s.`);
721
+ this.name = "AuthRefreshRateLimitedError";
722
+ this.retryAfterMs = retryAfterMs;
723
+ }
724
+ };
725
+ /**
726
+ * Parse an HTTP `Retry-After` header. Accepts either an integer seconds
727
+ * value (the form fastify-rate-limit emits) or an RFC 7231 HTTP-date.
728
+ * Returns ms, or `null` when the header is absent / malformed.
729
+ */
730
+ function parseRetryAfterMs(header) {
731
+ if (!header) return null;
732
+ const trimmed = header.trim();
733
+ const seconds = Number(trimmed);
734
+ if (Number.isFinite(seconds) && seconds >= 0) return seconds * 1e3;
735
+ const date = Date.parse(trimmed);
736
+ if (Number.isFinite(date)) {
737
+ const delta = date - Date.now();
738
+ return delta > 0 ? delta : 0;
739
+ }
740
+ return null;
741
+ }
742
+ /**
689
743
  * In-flight refresh promise. Multiple callers (WS handshake, proactive
690
744
  * refresh timer, every SDK request) can see an expired token within the same
691
745
  * millisecond — without dedupe each would fire an independent `/auth/refresh`
@@ -704,6 +758,14 @@ const DEFAULT_MIN_VALIDITY_MS = 3e4;
704
758
  * token has less than that much life left. The WS proactive-refresh path
705
759
  * passes a value that overlaps its lead window so it never receives a
706
760
  * token already inside the "about to expire" zone.
761
+ *
762
+ * Sliding-window note: the server now rotates the refresh token on every
763
+ * successful `/auth/refresh`. We persist the rotated token alongside the
764
+ * new access token so an actively-used client never hits the absolute
765
+ * `refreshTokenExpiry` ceiling. If the response omits `refreshToken`
766
+ * (i.e. an older server) we keep the existing one — the cost is just
767
+ * losing the sliding behaviour against that backend, not a correctness
768
+ * regression.
707
769
  */
708
770
  async function ensureFreshAccessToken(opts) {
709
771
  const minValidityMs = opts?.minValidityMs ?? DEFAULT_MIN_VALIDITY_MS;
@@ -718,11 +780,14 @@ async function ensureFreshAccessToken(opts) {
718
780
  body: JSON.stringify({ refreshToken: creds.refreshToken }),
719
781
  signal: AbortSignal.timeout(1e4)
720
782
  });
721
- if (!res.ok) throw new Error("Access token expired and refresh failed. Run `first-tree-hub client connect <server-url>`.");
783
+ if (res.status === 401) throw new AuthRefreshFailedError("Refresh token rejected by server. Re-run `first-tree-hub connect <token>` (get a fresh token from the Web Computers page → New Connection).");
784
+ if (res.status === 429) throw new AuthRefreshRateLimitedError(parseRetryAfterMs(res.headers.get("retry-after")) ?? 3e4);
785
+ if (!res.ok) throw new Error(`Refresh request failed with status ${res.status}.`);
722
786
  const data = await res.json();
723
787
  saveCredentials({
724
788
  ...creds,
725
- accessToken: data.accessToken
789
+ accessToken: data.accessToken,
790
+ refreshToken: data.refreshToken ?? creds.refreshToken
726
791
  });
727
792
  return data.accessToken;
728
793
  })();
@@ -745,13 +810,34 @@ function isTokenStale(token, minValidityMs) {
745
810
  return true;
746
811
  }
747
812
  }
748
- /** Persist credentials to disk. */
813
+ /**
814
+ * Persist credentials to disk atomically.
815
+ *
816
+ * Plain `writeFileSync` opens with `O_TRUNC` then writes — between those
817
+ * calls the file is empty, and a concurrent `loadCredentials()` (e.g. a
818
+ * background daemon refreshing while the user runs a foreground CLI command)
819
+ * reads "" → `JSON.parse` throws → we fall back to "no credentials" and
820
+ * surface a misleading "run `client connect` again" error. write-to-temp +
821
+ * rename gives readers an all-or-nothing view: they see the old file or the
822
+ * new file, never a half-written one. Server-side the sliding-window design
823
+ * already accepts last-writer-wins semantics for the refresh token itself
824
+ * (see auth service comment), so atomicity at the file level is enough.
825
+ */
749
826
  function saveCredentials(creds) {
750
827
  mkdirSync(dirname(CREDENTIALS_PATH), {
751
828
  recursive: true,
752
829
  mode: 448
753
830
  });
754
- writeFileSync(CREDENTIALS_PATH, JSON.stringify(creds, null, 2), { mode: 384 });
831
+ const tmp = `${CREDENTIALS_PATH}.tmp.${process.pid}`;
832
+ try {
833
+ writeFileSync(tmp, JSON.stringify(creds, null, 2), { mode: 384 });
834
+ renameSync(tmp, CREDENTIALS_PATH);
835
+ } catch (err) {
836
+ try {
837
+ unlinkSync(tmp);
838
+ } catch {}
839
+ throw err;
840
+ }
755
841
  }
756
842
  /**
757
843
  * Load persisted credentials saved by the `connect` command.
@@ -778,4 +864,4 @@ function saveAgentConfig(agentName, agentId, runtime) {
778
864
  return agentDir;
779
865
  }
780
866
  //#endregion
781
- export { serverConfigSchema as C, resolveConfigReadonly as S, loadAgents as _, resolveAccessToken as a, resetConfig as b, saveCredentials as c, DEFAULT_HOME_DIR as d, agentConfigSchema as f, initConfig as g, getConfigValue as h, loadCredentials as i, DEFAULT_CONFIG_DIR as l, collectMissingPrompts as m, ensureFreshAccessToken as n, resolveServerUrl as o, clientConfigSchema as p, ensureFreshAdminToken as r, saveAgentConfig as s, bootstrap_exports as t, DEFAULT_DATA_DIR as u, migrateLegacyHome as v, setConfigValue as w, resetConfigMeta as x, readConfigFile as y };
867
+ export { resetConfigMeta as C, setConfigValue as E, resetConfig as S, serverConfigSchema as T, getConfigValue as _, ensureFreshAdminToken as a, migrateLegacyHome as b, resolveServerUrl as c, DEFAULT_CONFIG_DIR as d, DEFAULT_DATA_DIR as f, collectMissingPrompts as g, clientConfigSchema as h, ensureFreshAccessToken as i, saveAgentConfig as l, agentConfigSchema as m, AuthRefreshRateLimitedError as n, loadCredentials as o, DEFAULT_HOME_DIR as p, bootstrap_exports as r, resolveAccessToken as s, AuthRefreshFailedError as t, saveCredentials as u, initConfig as v, resolveConfigReadonly as w, readConfigFile as x, loadAgents as y };
@@ -1,10 +1,10 @@
1
1
  #!/usr/bin/env node
2
2
  import "../observability-DPyf745N-BSc8QNcR.mjs";
3
- import { $ as findStaleAliases, A as checkDatabase, B as installClientService, C as runHomeMigration, D as checkAgentConfigs, E as runMigrations, F as checkServerReachable, G as stopClientService, I as checkWebSocket, L as printResults, M as checkNodeVersion, N as checkServerConfig, O as checkBackgroundService, P as checkServerHealth, R as reconcileAgentConfigs, S as saveOnboardState, T as migrateLocalAgentDirs, U as restartClientService, V as isServiceSupported, W as startClientService, X as ClientRuntime, Y as stopPostgres, Z as handleClientOrgMismatch, _ as promptMissingFields, _t as probeCapabilities, a as declineUpdate, at as fail, b as onboardCheck, c as detectInstallMode, ct as print, d as startServer, dt as ClientOrgMismatchError, et as formatStaleReason, f as COMMAND_VERSION, ft as ClientUserMismatchError, g as promptAddAgent, gt as cleanWorkspaces, h as isInteractive, ht as SessionRegistry, i as createExecuteUpdate, it as resolveReplyToFromEnv, j as checkDocker, k as checkClientConfig, l as fetchLatestVersion, lt as setJsonMode, m as uploadClientCapabilities, mt as SdkError, nt as createOwner, o as promptUpdate, ot as success, p as reconcileLocalRuntimeProviders, pt as FirstTreeHubSDK, r as registerSaaSConnectCommand, s as PACKAGE_NAME, tt as removeLocalAgent, u as installGlobalLatest, v as formatCheckReport, vt as applyClientLoggerConfig, w as createApiNameResolver, x as onboardCreate, y as loadOnboardState, yt as configureClientLoggerForService, z as getClientServiceStatus } from "../saas-connect-DLVGb8OH.mjs";
3
+ import { $ as findStaleAliases, A as checkDatabase, B as installClientService, C as runHomeMigration, D as checkAgentConfigs, E as runMigrations, F as checkServerReachable, G as stopClientService, I as checkWebSocket, L as printResults, M as checkNodeVersion, N as checkServerConfig, O as checkBackgroundService, P as checkServerHealth, R as reconcileAgentConfigs, S as saveOnboardState, T as migrateLocalAgentDirs, U as restartClientService, V as isServiceSupported, W as startClientService, X as ClientRuntime, Y as stopPostgres, Z as handleClientOrgMismatch, _ as promptMissingFields, _t as probeCapabilities, a as declineUpdate, at as fail, b as onboardCheck, c as detectInstallMode, ct as print, d as startServer, dt as ClientOrgMismatchError, et as formatStaleReason, f as COMMAND_VERSION, ft as ClientUserMismatchError, g as promptAddAgent, gt as cleanWorkspaces, h as isInteractive, ht as SessionRegistry, i as createExecuteUpdate, it as resolveReplyToFromEnv, j as checkDocker, k as checkClientConfig, l as fetchLatestVersion, lt as setJsonMode, m as uploadClientCapabilities, mt as SdkError, nt as createOwner, o as promptUpdate, ot as success, p as reconcileLocalRuntimeProviders, pt as FirstTreeHubSDK, r as registerSaaSConnectCommand, s as PACKAGE_NAME, tt as removeLocalAgent, u as installGlobalLatest, v as formatCheckReport, vt as applyClientLoggerConfig, w as createApiNameResolver, x as onboardCreate, y as loadOnboardState, yt as configureClientLoggerForService, z as getClientServiceStatus } from "../saas-connect-CebXWFF-.mjs";
4
4
  import "../logger-core-BTmvdflj-DjW8FM4T.mjs";
5
- import { C as serverConfigSchema, S as resolveConfigReadonly, _ as loadAgents, b as resetConfig, c as saveCredentials, d as DEFAULT_HOME_DIR, f as agentConfigSchema, g as initConfig, h as getConfigValue, i as loadCredentials, l as DEFAULT_CONFIG_DIR, n as ensureFreshAccessToken, o as resolveServerUrl, p as clientConfigSchema, r as ensureFreshAdminToken, s as saveAgentConfig, u as DEFAULT_DATA_DIR, w as setConfigValue, x as resetConfigMeta, y as readConfigFile } from "../bootstrap-CDeXqhkQ.mjs";
6
- import "../dist-DwbhZyGi.mjs";
7
- import { n as bindFeishuUser, t as bindFeishuBot } from "../feishu-viiZmwcn.mjs";
5
+ import { C as resetConfigMeta, E as setConfigValue, S as resetConfig, T as serverConfigSchema, _ as getConfigValue, a as ensureFreshAdminToken, c as resolveServerUrl, d as DEFAULT_CONFIG_DIR, f as DEFAULT_DATA_DIR, h as clientConfigSchema, i as ensureFreshAccessToken, l as saveAgentConfig, m as agentConfigSchema, o as loadCredentials, p as DEFAULT_HOME_DIR, u as saveCredentials, v as initConfig, w as resolveConfigReadonly, x as readConfigFile, y as loadAgents } from "../bootstrap-DUeYbwm-.mjs";
6
+ import "../dist-D6AOiyNg.mjs";
7
+ import { n as bindFeishuUser, t as bindFeishuBot } from "../feishu-DQ1l18Ah.mjs";
8
8
  import "../invitation-B1pjAyOz-BaCA9PII.mjs";
9
9
  import { join } from "node:path";
10
10
  import { existsSync, mkdirSync, readFileSync, readdirSync } from "node:fs";
@@ -1308,6 +1308,24 @@ function registerClientCommands(program) {
1308
1308
  print.line(` Hub: (could not read ${clientYaml}: ${msg.slice(0, 60)})\n`);
1309
1309
  }
1310
1310
  else print.line(" Hub: (not configured — run `first-tree-hub client connect <url>`)\n");
1311
+ const creds = loadCredentials();
1312
+ if (creds) {
1313
+ const exp = decodeJwtExpSeconds(creds.refreshToken);
1314
+ if (exp == null) print.line(" Auth: ⚠ could not parse refresh token (corrupt credentials)\n");
1315
+ else {
1316
+ const remainingSec = exp - Math.floor(Date.now() / 1e3);
1317
+ if (remainingSec <= 0) {
1318
+ print.line(" Auth: ✗ refresh token EXPIRED — re-run `first-tree-hub connect <token>`\n");
1319
+ print.line(" (get a fresh token from your Hub's Web admin → Computers → New Connection)\n");
1320
+ } else if (remainingSec < 2 * 86400) {
1321
+ const hours = Math.floor(remainingSec / 3600);
1322
+ print.line(` Auth: ⚠ refresh token expires in ~${hours}h — reclaim soon to stay online\n`);
1323
+ } else {
1324
+ const days = Math.floor(remainingSec / 86400);
1325
+ print.line(` Auth: ✓ refresh token valid for ~${days}d\n`);
1326
+ }
1327
+ }
1328
+ } else print.line(" Auth: (no credentials — run `first-tree-hub client connect <url>`)\n");
1311
1329
  const agentsDir = join(DEFAULT_CONFIG_DIR, "agents");
1312
1330
  try {
1313
1331
  const agents = loadAgents({
@@ -1474,6 +1492,25 @@ function getNested(obj, path) {
1474
1492
  }
1475
1493
  return typeof cur === "string" ? cur : null;
1476
1494
  }
1495
+ /**
1496
+ * Pull the `exp` claim (in seconds since epoch) out of a JWT without
1497
+ * verifying the signature — the `client status` auth-health line just
1498
+ * needs the wall-clock countdown, not a trust decision. Returns null
1499
+ * for malformed tokens so the caller can render a friendly fallback
1500
+ * instead of crashing.
1501
+ */
1502
+ function decodeJwtExpSeconds(token) {
1503
+ const parts = token.split(".");
1504
+ if (parts.length < 2 || !parts[1]) return null;
1505
+ try {
1506
+ const b64 = parts[1].replace(/-/g, "+").replace(/_/g, "/");
1507
+ const pad = b64.length % 4 === 0 ? "" : "=".repeat(4 - b64.length % 4);
1508
+ const payload = JSON.parse(Buffer.from(b64 + pad, "base64").toString("utf-8"));
1509
+ return typeof payload.exp === "number" ? payload.exp : null;
1510
+ } catch {
1511
+ return null;
1512
+ }
1513
+ }
1477
1514
  //#endregion
1478
1515
  //#region src/commands/config.ts
1479
1516
  function resolveConfigPath(flags) {
@@ -1571,13 +1608,13 @@ function isSecretField(schema, dotPath) {
1571
1608
  //#region src/commands/onboard.ts
1572
1609
  async function promptMissing(args) {
1573
1610
  if (!args.server) try {
1574
- const { resolveServerUrl } = await import("../bootstrap-CDeXqhkQ.mjs").then((n) => n.t);
1611
+ const { resolveServerUrl } = await import("../bootstrap-DUeYbwm-.mjs").then((n) => n.r);
1575
1612
  resolveServerUrl();
1576
1613
  } catch {
1577
1614
  args.server = await input({ message: "Hub server URL:" });
1578
1615
  saveOnboardState(args);
1579
1616
  }
1580
- const { loadCredentials } = await import("../bootstrap-CDeXqhkQ.mjs").then((n) => n.t);
1617
+ const { loadCredentials } = await import("../bootstrap-DUeYbwm-.mjs").then((n) => n.r);
1581
1618
  if (!loadCredentials()) throw new Error("No saved credentials. Run `first-tree-hub client connect <server-url>` before onboarding.");
1582
1619
  if (!args.id) {
1583
1620
  args.id = await input({ message: "Agent ID:" });
@@ -585,10 +585,25 @@ const addParticipantSchema = z.object({
585
585
  });
586
586
  z.object({ agentId: z.string().min(1) });
587
587
  const clientStatusSchema = z.enum(["connected", "disconnected"]);
588
+ /**
589
+ * Auth health channel surfaced to the Web admin dashboard. Computed
590
+ * server-side per request from the row's offline duration vs the
591
+ * configured refresh-token TTL — there is no DB column. See
592
+ * `deriveAuthState` server-side.
593
+ *
594
+ * - `ok` — online, or recently offline (cached refresh token can
595
+ * plausibly still mint access tokens).
596
+ * - `expired` — offline longer than the refresh-token TTL; the client
597
+ * cannot recover on its own. The operator mints a fresh
598
+ * connect token via the Web "+ New Connection" button
599
+ * (or the inline Reconnect button on the row).
600
+ */
601
+ const clientAuthStateSchema = z.enum(["ok", "expired"]);
588
602
  z.object({
589
603
  id: z.string(),
590
604
  userId: z.string().nullable(),
591
605
  status: clientStatusSchema,
606
+ authState: clientAuthStateSchema,
592
607
  sdkVersion: z.string().max(50).nullable(),
593
608
  hostname: z.string().max(100).nullable(),
594
609
  os: z.string().max(50).nullable(),
@@ -1,5 +1,5 @@
1
1
  import { d as __exportAll } from "./esm-CYu4tXXn.mjs";
2
- import { r as AGENT_SELECTOR_HEADER } from "./dist-DwbhZyGi.mjs";
2
+ import { r as AGENT_SELECTOR_HEADER } from "./dist-D6AOiyNg.mjs";
3
3
  //#region src/core/feishu.ts
4
4
  var feishu_exports = /* @__PURE__ */ __exportAll({
5
5
  bindFeishuBot: () => bindFeishuBot,
package/dist/index.mjs CHANGED
@@ -1,8 +1,8 @@
1
1
  import "./observability-DPyf745N-BSc8QNcR.mjs";
2
- import { A as checkDatabase, B as installClientService, C as runHomeMigration, D as checkAgentConfigs, E as runMigrations, F as checkServerReachable, G as stopClientService, H as resolveCliInvocation, I as checkWebSocket, J as isDockerAvailable, K as uninstallClientService, L as printResults, M as checkNodeVersion, N as checkServerConfig, P as checkServerHealth, Q as rotateClientIdWithBackup, U as restartClientService, V as isServiceSupported, W as startClientService, X as ClientRuntime, Y as stopPostgres, Z as handleClientOrgMismatch, _ as promptMissingFields, b as onboardCheck, d as startServer, g as promptAddAgent, h as isInteractive, j as checkDocker, k as checkClientConfig, mt as SdkError, n as deriveHubUrlFromToken, nt as createOwner, pt as FirstTreeHubSDK, q as ensurePostgres, rt as hasUser, st as blank, t as HubUrlDerivationError, ut as status, v as formatCheckReport, x as onboardCreate, z as getClientServiceStatus } from "./saas-connect-DLVGb8OH.mjs";
2
+ import { A as checkDatabase, B as installClientService, C as runHomeMigration, D as checkAgentConfigs, E as runMigrations, F as checkServerReachable, G as stopClientService, H as resolveCliInvocation, I as checkWebSocket, J as isDockerAvailable, K as uninstallClientService, L as printResults, M as checkNodeVersion, N as checkServerConfig, P as checkServerHealth, Q as rotateClientIdWithBackup, U as restartClientService, V as isServiceSupported, W as startClientService, X as ClientRuntime, Y as stopPostgres, Z as handleClientOrgMismatch, _ as promptMissingFields, b as onboardCheck, d as startServer, g as promptAddAgent, h as isInteractive, j as checkDocker, k as checkClientConfig, mt as SdkError, n as deriveHubUrlFromToken, nt as createOwner, pt as FirstTreeHubSDK, q as ensurePostgres, rt as hasUser, st as blank, t as HubUrlDerivationError, ut as status, v as formatCheckReport, x as onboardCreate, z as getClientServiceStatus } from "./saas-connect-CebXWFF-.mjs";
3
3
  import "./logger-core-BTmvdflj-DjW8FM4T.mjs";
4
- import { a as resolveAccessToken, n as ensureFreshAccessToken, o as resolveServerUrl, r as ensureFreshAdminToken } from "./bootstrap-CDeXqhkQ.mjs";
5
- import "./dist-DwbhZyGi.mjs";
6
- import { n as bindFeishuUser, t as bindFeishuBot } from "./feishu-viiZmwcn.mjs";
4
+ import { a as ensureFreshAdminToken, c as resolveServerUrl, i as ensureFreshAccessToken, n as AuthRefreshRateLimitedError, s as resolveAccessToken, t as AuthRefreshFailedError } from "./bootstrap-DUeYbwm-.mjs";
5
+ import "./dist-D6AOiyNg.mjs";
6
+ import { n as bindFeishuUser, t as bindFeishuBot } from "./feishu-DQ1l18Ah.mjs";
7
7
  import "./invitation-B1pjAyOz-BaCA9PII.mjs";
8
- export { ClientRuntime, FirstTreeHubSDK, HubUrlDerivationError, SdkError, bindFeishuBot, bindFeishuUser, blank, checkAgentConfigs, checkClientConfig, checkDatabase, checkDocker, checkNodeVersion, checkServerConfig, checkServerHealth, checkServerReachable, checkWebSocket, createOwner, deriveHubUrlFromToken, ensureFreshAccessToken, ensureFreshAdminToken, ensurePostgres, formatCheckReport, getClientServiceStatus, handleClientOrgMismatch, hasUser, installClientService, isDockerAvailable, isInteractive, isServiceSupported, onboardCheck, onboardCreate, printResults, promptAddAgent, promptMissingFields, resolveAccessToken, resolveCliInvocation, resolveServerUrl, restartClientService, rotateClientIdWithBackup, runHomeMigration, runMigrations, startClientService, startServer, status, stopClientService, stopPostgres, uninstallClientService };
8
+ export { AuthRefreshFailedError, AuthRefreshRateLimitedError, ClientRuntime, FirstTreeHubSDK, HubUrlDerivationError, SdkError, bindFeishuBot, bindFeishuUser, blank, checkAgentConfigs, checkClientConfig, checkDatabase, checkDocker, checkNodeVersion, checkServerConfig, checkServerHealth, checkServerReachable, checkWebSocket, createOwner, deriveHubUrlFromToken, ensureFreshAccessToken, ensureFreshAdminToken, ensurePostgres, formatCheckReport, getClientServiceStatus, handleClientOrgMismatch, hasUser, installClientService, isDockerAvailable, isInteractive, isServiceSupported, onboardCheck, onboardCreate, printResults, promptAddAgent, promptMissingFields, resolveAccessToken, resolveCliInvocation, resolveServerUrl, restartClientService, rotateClientIdWithBackup, runHomeMigration, runMigrations, startClientService, startServer, status, stopClientService, stopPostgres, uninstallClientService };
@@ -1,3 +1,3 @@
1
- import "./dist-DwbhZyGi.mjs";
1
+ import "./dist-D6AOiyNg.mjs";
2
2
  import { g as previewInvitation, v as rotateInvitation } from "./invitation-B1pjAyOz-BaCA9PII.mjs";
3
3
  export { previewInvitation, rotateInvitation };