@agent-team-foundation/first-tree-hub 0.10.11 → 0.10.12

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.
@@ -693,15 +693,23 @@ function resolveAccessToken() {
693
693
  * promise so N concurrent callers resolve from a single HTTP call.
694
694
  */
695
695
  let inflightRefresh = null;
696
+ /** Default freshness window for HTTP callers: refresh if token expires within 30s. */
697
+ const DEFAULT_MIN_VALIDITY_MS = 3e4;
696
698
  /**
697
699
  * Ensure the persisted access token is fresh. Call before any API request
698
700
  * when using persisted credentials. Returns the (possibly refreshed) access
699
701
  * token. Service-user API keys are out of scope for this milestone.
702
+ *
703
+ * `opts.minValidityMs` raises the freshness bar — refresh when the cached
704
+ * token has less than that much life left. The WS proactive-refresh path
705
+ * passes a value that overlaps its lead window so it never receives a
706
+ * token already inside the "about to expire" zone.
700
707
  */
701
- async function ensureFreshAccessToken() {
708
+ async function ensureFreshAccessToken(opts) {
709
+ const minValidityMs = opts?.minValidityMs ?? DEFAULT_MIN_VALIDITY_MS;
702
710
  const creds = loadCredentials();
703
711
  if (!creds) throw new Error("No credentials found. Run `first-tree-hub client connect <server-url>` to sign in.");
704
- if (!isTokenExpired(creds.accessToken)) return creds.accessToken;
712
+ if (!isTokenStale(creds.accessToken, minValidityMs)) return creds.accessToken;
705
713
  if (inflightRefresh) return inflightRefresh;
706
714
  inflightRefresh = (async () => {
707
715
  const res = await fetch(`${creds.serverUrl}/api/v1/auth/refresh`, {
@@ -726,13 +734,13 @@ async function ensureFreshAccessToken() {
726
734
  }
727
735
  /** Back-compat alias retained so existing call sites keep compiling. */
728
736
  const ensureFreshAdminToken = ensureFreshAccessToken;
729
- function isTokenExpired(token) {
737
+ function isTokenStale(token, minValidityMs) {
730
738
  try {
731
739
  const parts = token.split(".");
732
740
  if (parts.length !== 3 || !parts[1]) return true;
733
741
  const payload = JSON.parse(Buffer.from(parts[1], "base64url").toString());
734
742
  if (!payload.exp) return false;
735
- return payload.exp * 1e3 < Date.now() + 3e4;
743
+ return payload.exp * 1e3 < Date.now() + minValidityMs;
736
744
  } catch {
737
745
  return true;
738
746
  }
@@ -1,8 +1,8 @@
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-D-7x9KRd.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";
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-BTKiVIYk.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
6
  import "../dist-DwbhZyGi.mjs";
7
7
  import { n as bindFeishuUser, t as bindFeishuBot } from "../feishu-viiZmwcn.mjs";
8
8
  import "../invitation-B1pjAyOz-BaCA9PII.mjs";
@@ -236,7 +236,7 @@ function createSdk(agentName) {
236
236
  const { serverUrl, agentId } = resolveLocalAgent(agentName);
237
237
  return new FirstTreeHubSDK({
238
238
  serverUrl,
239
- getAccessToken: () => ensureFreshAccessToken(),
239
+ getAccessToken: (opts) => ensureFreshAccessToken(opts),
240
240
  agentId
241
241
  });
242
242
  }
@@ -336,7 +336,7 @@ function registerAgentCommands(program) {
336
336
  const clientId = readClientId();
337
337
  const sdk = new FirstTreeHubSDK({
338
338
  serverUrl,
339
- getAccessToken: () => ensureFreshAccessToken()
339
+ getAccessToken: (opts) => ensureFreshAccessToken(opts)
340
340
  });
341
341
  const stale = await findStaleAliases({
342
342
  clientId,
@@ -1221,7 +1221,7 @@ function registerClientCommands(program) {
1221
1221
  });
1222
1222
  const sdk = new FirstTreeHubSDK({
1223
1223
  serverUrl,
1224
- getAccessToken: () => ensureFreshAccessToken()
1224
+ getAccessToken: (opts) => ensureFreshAccessToken(opts)
1225
1225
  });
1226
1226
  agentCheck = await reconcileAgentConfigs({
1227
1227
  clientId: cfg.client.id,
@@ -1394,7 +1394,7 @@ function registerClientCommands(program) {
1394
1394
  try {
1395
1395
  const sdk = new FirstTreeHubSDK({
1396
1396
  serverUrl,
1397
- getAccessToken: () => ensureFreshAccessToken()
1397
+ getAccessToken: (opts) => ensureFreshAccessToken(opts)
1398
1398
  });
1399
1399
  const stale = await findStaleAliases({
1400
1400
  clientId,
@@ -1571,13 +1571,13 @@ function isSecretField(schema, dotPath) {
1571
1571
  //#region src/commands/onboard.ts
1572
1572
  async function promptMissing(args) {
1573
1573
  if (!args.server) try {
1574
- const { resolveServerUrl } = await import("../bootstrap-BTKiVIYk.mjs").then((n) => n.t);
1574
+ const { resolveServerUrl } = await import("../bootstrap-CDeXqhkQ.mjs").then((n) => n.t);
1575
1575
  resolveServerUrl();
1576
1576
  } catch {
1577
1577
  args.server = await input({ message: "Hub server URL:" });
1578
1578
  saveOnboardState(args);
1579
1579
  }
1580
- const { loadCredentials } = await import("../bootstrap-BTKiVIYk.mjs").then((n) => n.t);
1580
+ const { loadCredentials } = await import("../bootstrap-CDeXqhkQ.mjs").then((n) => n.t);
1581
1581
  if (!loadCredentials()) throw new Error("No saved credentials. Run `first-tree-hub client connect <server-url>` before onboarding.");
1582
1582
  if (!args.id) {
1583
1583
  args.id = await input({ message: "Agent ID:" });
package/dist/index.mjs CHANGED
@@ -1,7 +1,7 @@
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-D-7x9KRd.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";
3
3
  import "./logger-core-BTmvdflj-DjW8FM4T.mjs";
4
- import { a as resolveAccessToken, n as ensureFreshAccessToken, o as resolveServerUrl, r as ensureFreshAdminToken } from "./bootstrap-BTKiVIYk.mjs";
4
+ import { a as resolveAccessToken, n as ensureFreshAccessToken, o as resolveServerUrl, r as ensureFreshAdminToken } from "./bootstrap-CDeXqhkQ.mjs";
5
5
  import "./dist-DwbhZyGi.mjs";
6
6
  import { n as bindFeishuUser, t as bindFeishuBot } from "./feishu-viiZmwcn.mjs";
7
7
  import "./invitation-B1pjAyOz-BaCA9PII.mjs";
@@ -1,6 +1,6 @@
1
1
  import { m as __toESM } from "./esm-CYu4tXXn.mjs";
2
2
  import { _ as withSpan, a as endWsConnectionSpan, b as require_pino, c as messageAttrs, d as rootLogger$1, g as startWsConnectionSpan, i as currentTraceId, n as applyLoggerConfig, o as getFastifyOtelPlugin, p as setWsConnectionAttrs, r as createLogger$1, t as adapterAttrs, u as observabilityPlugin, v as withWsMessageSpan, y as FIRST_TREE_HUB_ATTR } from "./observability-DPyf745N-BSc8QNcR.mjs";
3
- import { C as serverConfigSchema, S as resolveConfigReadonly, _ as loadAgents, b as resetConfig, c as saveCredentials, d as DEFAULT_HOME_DIR$1, f as agentConfigSchema, g as initConfig, i as loadCredentials, l as DEFAULT_CONFIG_DIR, m as collectMissingPrompts, n as ensureFreshAccessToken, o as resolveServerUrl, p as clientConfigSchema, s as saveAgentConfig, u as DEFAULT_DATA_DIR$1, v as migrateLegacyHome, w as setConfigValue, x as resetConfigMeta } from "./bootstrap-BTKiVIYk.mjs";
3
+ import { C as serverConfigSchema, S as resolveConfigReadonly, _ as loadAgents, b as resetConfig, c as saveCredentials, d as DEFAULT_HOME_DIR$1, f as agentConfigSchema, g as initConfig, i as loadCredentials, l as DEFAULT_CONFIG_DIR, m as collectMissingPrompts, n as ensureFreshAccessToken, o as resolveServerUrl, p as clientConfigSchema, s as saveAgentConfig, u as DEFAULT_DATA_DIR$1, v as migrateLegacyHome, w as setConfigValue, x as resetConfigMeta } from "./bootstrap-CDeXqhkQ.mjs";
4
4
  import { $ as refreshTokenSchema, A as createOrgFromMeSchema, B as imageInlineContentSchema, C as clientRegisterSchema, D as createAgentSchema, E as createAdapterMappingSchema, F as dryRunAgentRuntimeConfigSchema, G as isReservedAgentName$1, H as inboxDeliverFrameSchema$1, I as extractMentions, J as loginSchema, K as joinByInvitationSchema, L as githubCallbackQuerySchema, M as createTaskSchema, N as defaultRuntimeConfigPayload, O as createChatSchema, P as delegateFeishuUserSchema, Q as rebindAgentSchema, R as githubDevCallbackQuerySchema, S as clientCapabilitiesSchema$1, St as wsAuthFrameSchema, T as createAdapterConfigSchema, U as inboxPollQuerySchema, V as inboxAckFrameSchema, W as isRedactedEnvValue, X as notificationQuerySchema, Y as messageSourceSchema$1, Z as paginationQuerySchema, _ as adminUpdateTaskSchema, _t as updateClientCapabilitiesSchema, a as AGENT_STATUSES, at as sendToAgentSchema, b as agentRuntimeConfigPayloadSchema$1, bt as updateSystemConfigSchema, ct as sessionEventSchema$1, d as TASK_HEALTH_SIGNALS, dt as switchOrgSchema, et as runtimeStateMessageSchema, f as TASK_STATUSES, ft as taskListQuerySchema, g as adminCreateTaskSchema, gt as updateChatSchema, h as addParticipantSchema, ht as updateAgentSchema, i as AGENT_SOURCES, it as sendMessageSchema, j as createOrganizationSchema, k as createMemberSchema, l as SYSTEM_CONFIG_DEFAULTS, lt as sessionReconcileRequestSchema, m as WS_AUTH_FRAME_TIMEOUT_MS, mt as updateAgentRuntimeConfigSchema, n as AGENT_NAME_REGEX$1, nt as scanMentionTokens, o as AGENT_TYPES, ot as sessionCompletionMessageSchema, p as TASK_TERMINAL_STATUSES, pt as updateAdapterConfigSchema, q as linkTaskChatSchema, r as AGENT_SELECTOR_HEADER$1, rt as selfServiceFeishuBotSchema, s as AGENT_VISIBILITY, st as sessionEventMessageSchema, t as AGENT_BIND_REJECT_REASONS, tt as safeRedirectPath, u as TASK_CREATOR_TYPES, ut as sessionStateMessageSchema, v as agentBindRequestSchema, vt as updateMemberSchema, w as connectTokenExchangeSchema, x as agentTypeSchema$1, xt as updateTaskStatusSchema, y as agentPinnedMessageSchema$1, yt as updateOrganizationSchema, z as githubStartQuerySchema } from "./dist-DwbhZyGi.mjs";
5
5
  import { _ as recordRedemption, a as ConflictError, b as uuidv7, c as UnauthorizedError, d as findActiveByToken, f as getActiveInvitation, h as organizations, i as ClientUserMismatchError$1, l as buildInviteUrl, m as invitations, n as BadRequestError, o as ForbiddenError, p as invitationRedemptions, r as ClientOrgMismatchError$1, s as NotFoundError, t as AppError, u as ensureActiveInvitation, y as users } from "./invitation-B1pjAyOz-BaCA9PII.mjs";
6
6
  import { createRequire } from "node:module";
@@ -2064,7 +2064,7 @@ var ClientConnection = class extends EventEmitter {
2064
2064
  this.reconnectAttempt = 0;
2065
2065
  this.wsLogger.debug("socket opened, sending auth");
2066
2066
  try {
2067
- const token = await this.getAccessToken();
2067
+ const token = await this.getAccessToken({ minValidityMs: AUTH_REFRESH_LEAD_MS + 5e3 });
2068
2068
  ws.send(JSON.stringify({
2069
2069
  type: "auth",
2070
2070
  token
@@ -2096,7 +2096,11 @@ var ClientConnection = class extends EventEmitter {
2096
2096
  settle(reject, typedErr ?? /* @__PURE__ */ new Error(`WebSocket closed before ready (code ${code})`));
2097
2097
  return;
2098
2098
  }
2099
- this.wsLogger.warn({
2099
+ if (code === 1e3) this.wsLogger.info({
2100
+ code,
2101
+ wasRegistered
2102
+ }, "disconnected");
2103
+ else this.wsLogger.warn({
2100
2104
  code,
2101
2105
  wasRegistered
2102
2106
  }, "disconnected");
@@ -6257,7 +6261,7 @@ var ClientRuntime = class {
6257
6261
  serverUrl,
6258
6262
  clientId,
6259
6263
  sdkVersion: options.currentVersion,
6260
- getAccessToken: () => ensureFreshAccessToken()
6264
+ getAccessToken: (opts) => ensureFreshAccessToken(opts)
6261
6265
  });
6262
6266
  registerBuiltinHandlers();
6263
6267
  this.connection.on("auth:expired", () => {
@@ -18752,7 +18756,13 @@ function resolveNpmCommand() {
18752
18756
  */
18753
18757
  function detectInstallMode(argv1 = process.argv[1] ?? "") {
18754
18758
  if (!argv1) return "npx";
18755
- const start = dirname(resolve(argv1));
18759
+ let resolvedArgv1;
18760
+ try {
18761
+ resolvedArgv1 = realpathSync(argv1);
18762
+ } catch {
18763
+ resolvedArgv1 = argv1;
18764
+ }
18765
+ const start = dirname(resolve(resolvedArgv1));
18756
18766
  {
18757
18767
  let dir = start;
18758
18768
  for (let i = 0; i < 10; i++) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@agent-team-foundation/first-tree-hub",
3
- "version": "0.10.11",
3
+ "version": "0.10.12",
4
4
  "type": "module",
5
5
  "description": "First Tree Hub — unified CLI for server, client, and agent management",
6
6
  "exports": {