@sideboard-ai/core 0.1.219 → 0.1.221

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.
@@ -0,0 +1,178 @@
1
+ import {
2
+ formatFetchError
3
+ } from "./chunk-N7WZ6NIN.js";
4
+
5
+ // src/brightsy/config.ts
6
+ import { existsSync, readFileSync, writeFileSync } from "fs";
7
+ import { homedir } from "os";
8
+ import { join } from "path";
9
+ function brightsyConfigPath() {
10
+ const override = process.env.BRIGHTSY_CONFIG?.trim();
11
+ if (override) return override;
12
+ return join(homedir(), ".brightsy", "config.json");
13
+ }
14
+ function loadBrightsyConfig() {
15
+ const path = brightsyConfigPath();
16
+ if (!existsSync(path)) {
17
+ throw new Error("Brightsy not logged in \u2014 run `brightsy login` first");
18
+ }
19
+ const raw = JSON.parse(readFileSync(path, "utf8"));
20
+ if (!raw.access_token || !raw.account_id) {
21
+ throw new Error("Brightsy config incomplete \u2014 run `brightsy login`");
22
+ }
23
+ return raw;
24
+ }
25
+ function saveBrightsyConfig(cfg) {
26
+ writeFileSync(brightsyConfigPath(), `${JSON.stringify(cfg, null, 2)}
27
+ `, {
28
+ mode: 384
29
+ });
30
+ }
31
+
32
+ // src/brightsy/oauth.ts
33
+ var REFRESH_SKEW_MS = 6e4;
34
+ var BRIGHTSY_OAUTH_CLIENT_ID = "sideboard";
35
+ var BRIGHTSY_OAUTH_REDIRECT = "http://127.0.0.1:19850/callback";
36
+ function defaultFetch(fetchImpl) {
37
+ return fetchImpl ?? globalThis.fetch.bind(globalThis);
38
+ }
39
+ function normalizeBrightsyEndpoint(endpoint) {
40
+ return (endpoint || "https://brightsy.ai").replace(/\/$/, "");
41
+ }
42
+ function brightsyAccessTokenNeedsRefresh(expiresAt, now = Date.now()) {
43
+ if (typeof expiresAt !== "number" || !Number.isFinite(expiresAt) || expiresAt <= 0) {
44
+ return true;
45
+ }
46
+ return now >= expiresAt - REFRESH_SKEW_MS;
47
+ }
48
+ function applyGrant(current, grant) {
49
+ return {
50
+ access_token: grant.access_token,
51
+ refresh_token: grant.refresh_token || current.refresh_token,
52
+ expires_at: grant.expires_at ?? current.expires_at
53
+ };
54
+ }
55
+ async function registerBrightsyOAuthClient(opts) {
56
+ const endpoint = normalizeBrightsyEndpoint(opts.endpoint);
57
+ const url = `${endpoint}/oauth/register`;
58
+ const clientId = (opts.clientId || BRIGHTSY_OAUTH_CLIENT_ID).trim();
59
+ const redirectUri = opts.redirectUri || BRIGHTSY_OAUTH_REDIRECT;
60
+ const fetchImpl = defaultFetch(opts.fetchImpl);
61
+ let res;
62
+ try {
63
+ res = await fetchImpl(url, {
64
+ method: "POST",
65
+ headers: { "Content-Type": "application/json" },
66
+ body: JSON.stringify({
67
+ client_id: clientId,
68
+ client_name: "Sideboard",
69
+ description: "Sideboard desktop Brightsy MCP client",
70
+ redirect_uris: [redirectUri],
71
+ scope: "brightsy:api",
72
+ grant_types: ["authorization_code", "refresh_token"],
73
+ response_types: ["code"],
74
+ token_endpoint_auth_method: "none"
75
+ })
76
+ });
77
+ } catch (err) {
78
+ throw new Error(formatFetchError(err, url));
79
+ }
80
+ if (!res.ok) return null;
81
+ const data = await res.json();
82
+ if (!data.client_id?.trim()) return null;
83
+ return {
84
+ client_id: data.client_id.trim(),
85
+ client_secret: data.client_secret?.trim() || void 0
86
+ };
87
+ }
88
+ async function ensureBrightsyOAuthClientId(opts) {
89
+ const existing = opts.clientId?.trim();
90
+ if (existing) return existing;
91
+ const registered = await registerBrightsyOAuthClient({
92
+ endpoint: opts.endpoint,
93
+ fetchImpl: opts.fetchImpl
94
+ });
95
+ return registered?.client_id || BRIGHTSY_OAUTH_CLIENT_ID;
96
+ }
97
+ async function refreshBrightsyAccessToken(opts) {
98
+ const endpoint = normalizeBrightsyEndpoint(opts.endpoint);
99
+ const url = `${endpoint}/oauth/token`;
100
+ const fetchImpl = defaultFetch(opts.fetchImpl);
101
+ const clientId = opts.clientId?.trim() || BRIGHTSY_OAUTH_CLIENT_ID;
102
+ let res;
103
+ try {
104
+ res = await fetchImpl(url, {
105
+ method: "POST",
106
+ headers: { "Content-Type": "application/x-www-form-urlencoded" },
107
+ body: new URLSearchParams({
108
+ grant_type: "refresh_token",
109
+ refresh_token: opts.refreshToken,
110
+ client_id: clientId
111
+ })
112
+ });
113
+ } catch (err) {
114
+ throw new Error(formatFetchError(err, url));
115
+ }
116
+ if (!res.ok) return null;
117
+ const data = await res.json();
118
+ if (!data.access_token) return null;
119
+ return {
120
+ access_token: data.access_token,
121
+ refresh_token: data.refresh_token,
122
+ expires_at: data.expires_in ? Date.now() + data.expires_in * 1e3 : void 0
123
+ };
124
+ }
125
+ var refreshInFlight = null;
126
+ async function ensureBrightsyLocalConfigFreshOnce(opts) {
127
+ let cfg;
128
+ try {
129
+ cfg = loadBrightsyConfig();
130
+ } catch {
131
+ return null;
132
+ }
133
+ const refreshToken = cfg.refresh_token;
134
+ if (!refreshToken || !brightsyAccessTokenNeedsRefresh(cfg.expires_at)) {
135
+ return cfg;
136
+ }
137
+ const endpoint = normalizeBrightsyEndpoint(cfg.endpoint);
138
+ const clientId = await ensureBrightsyOAuthClientId({
139
+ endpoint,
140
+ clientId: cfg.oauth_client_id,
141
+ fetchImpl: opts?.fetchImpl
142
+ });
143
+ if (clientId !== cfg.oauth_client_id) {
144
+ cfg = { ...cfg, oauth_client_id: clientId };
145
+ saveBrightsyConfig(cfg);
146
+ }
147
+ const grant = await refreshBrightsyAccessToken({
148
+ endpoint,
149
+ refreshToken,
150
+ clientId,
151
+ fetchImpl: opts?.fetchImpl
152
+ });
153
+ if (!grant) return cfg;
154
+ const next = { ...cfg, ...applyGrant(cfg, grant), oauth_client_id: clientId };
155
+ saveBrightsyConfig(next);
156
+ return next;
157
+ }
158
+ async function ensureBrightsyLocalConfigFresh(opts) {
159
+ if (refreshInFlight) return refreshInFlight;
160
+ refreshInFlight = ensureBrightsyLocalConfigFreshOnce(opts).finally(() => {
161
+ refreshInFlight = null;
162
+ });
163
+ return refreshInFlight;
164
+ }
165
+
166
+ export {
167
+ brightsyConfigPath,
168
+ loadBrightsyConfig,
169
+ saveBrightsyConfig,
170
+ BRIGHTSY_OAUTH_CLIENT_ID,
171
+ BRIGHTSY_OAUTH_REDIRECT,
172
+ normalizeBrightsyEndpoint,
173
+ brightsyAccessTokenNeedsRefresh,
174
+ registerBrightsyOAuthClient,
175
+ ensureBrightsyOAuthClientId,
176
+ refreshBrightsyAccessToken,
177
+ ensureBrightsyLocalConfigFresh
178
+ };
@@ -3,10 +3,11 @@
3
3
  import {
4
4
  brightsyAccessTokenNeedsRefresh,
5
5
  ensureBrightsyLocalConfigFresh,
6
+ ensureBrightsyOAuthClientId,
6
7
  loadBrightsyConfig,
7
8
  refreshBrightsyAccessToken,
8
9
  saveBrightsyConfig
9
- } from "./chunk-Y4MIXGPA.js";
10
+ } from "./chunk-P2BSMNHB.js";
10
11
  import {
11
12
  run
12
13
  } from "./chunk-ABOBTSO6.js";
@@ -106,10 +107,10 @@ function applyConnectedTeamToCli(team) {
106
107
  account_id: team.id,
107
108
  account_slug: team.slug,
108
109
  endpoint: team.endpoint ?? base.endpoint ?? "https://brightsy.ai",
109
- oauth_client_id: base.oauth_client_id
110
+ oauth_client_id: team.oauth_client_id ?? base.oauth_client_id
110
111
  });
111
112
  }
112
- async function refreshTeamToken(team) {
113
+ async function refreshTeamToken(team, opts) {
113
114
  if (!team.refresh_token) return team;
114
115
  const cfg = (() => {
115
116
  try {
@@ -118,21 +119,31 @@ async function refreshTeamToken(team) {
118
119
  return null;
119
120
  }
120
121
  })();
122
+ const endpoint = team.endpoint || "https://brightsy.ai";
123
+ const clientId = await ensureBrightsyOAuthClientId({
124
+ endpoint,
125
+ clientId: team.oauth_client_id || cfg?.oauth_client_id,
126
+ fetchImpl: opts?.fetchImpl
127
+ });
121
128
  const grant = await refreshBrightsyAccessToken({
122
- endpoint: team.endpoint || "https://brightsy.ai",
129
+ endpoint,
123
130
  refreshToken: team.refresh_token,
124
- clientId: cfg?.oauth_client_id
131
+ clientId,
132
+ fetchImpl: opts?.fetchImpl
125
133
  });
126
- if (!grant) return team;
134
+ if (!grant) return { ...team, oauth_client_id: clientId || team.oauth_client_id };
127
135
  return {
128
136
  ...team,
129
137
  access_token: grant.access_token,
130
138
  refresh_token: grant.refresh_token || team.refresh_token,
131
- expires_at: grant.expires_at ?? team.expires_at
139
+ expires_at: grant.expires_at ?? team.expires_at,
140
+ oauth_client_id: clientId
132
141
  };
133
142
  }
134
- async function ensureConnectedBrightsyTeamTokens() {
135
- await ensureBrightsyLocalConfigFresh().catch(() => null);
143
+ async function ensureConnectedBrightsyTeamTokens(opts) {
144
+ await ensureBrightsyLocalConfigFresh({ fetchImpl: opts?.fetchImpl }).catch(
145
+ () => null
146
+ );
136
147
  const teams = readStore();
137
148
  if (teams.length === 0) return [];
138
149
  const next = [];
@@ -142,8 +153,8 @@ async function ensureConnectedBrightsyTeamTokens() {
142
153
  next.push(team);
143
154
  continue;
144
155
  }
145
- const refreshed = await refreshTeamToken(team);
146
- if (refreshed.access_token !== team.access_token || refreshed.refresh_token !== team.refresh_token || refreshed.expires_at !== team.expires_at) {
156
+ const refreshed = await refreshTeamToken(team, opts);
157
+ if (refreshed.access_token !== team.access_token || refreshed.refresh_token !== team.refresh_token || refreshed.expires_at !== team.expires_at || refreshed.oauth_client_id !== team.oauth_client_id) {
147
158
  changed = true;
148
159
  }
149
160
  next.push(refreshed);
@@ -173,7 +184,8 @@ function ensureCliTeamTracked(meta) {
173
184
  access_token: cfg.access_token,
174
185
  refresh_token: cfg.refresh_token,
175
186
  expires_at: cfg.expires_at,
176
- endpoint: cfg.endpoint
187
+ endpoint: cfg.endpoint,
188
+ oauth_client_id: cfg.oauth_client_id
177
189
  };
178
190
  writeStore([...existing, team]);
179
191
  } catch {
@@ -200,7 +212,8 @@ async function connectBrightsyTeam(accountIdOrSlug) {
200
212
  access_token: minted.access_token,
201
213
  refresh_token: minted.refresh_token,
202
214
  expires_at: minted.expires_at,
203
- endpoint: minted.endpoint
215
+ endpoint: minted.endpoint,
216
+ oauth_client_id: minted.oauth_client_id
204
217
  };
205
218
  writeStore([...existing, team]);
206
219
  return listConnectedBrightsyTeams();
@@ -12,10 +12,10 @@ import {
12
12
  brightsyMcpServerName,
13
13
  ensureCliTeamTracked,
14
14
  ensureConnectedBrightsyTeamTokens
15
- } from "./chunk-IILG7DPX.js";
15
+ } from "./chunk-QILV2BRW.js";
16
16
  import {
17
17
  loadBrightsyConfig
18
- } from "./chunk-AN3THU7F.js";
18
+ } from "./chunk-ROPGQRPU.js";
19
19
  import {
20
20
  httpFetch
21
21
  } from "./chunk-N7WZ6NIN.js";
@@ -693,6 +693,7 @@ function teamEnv(team) {
693
693
  return {
694
694
  BRIGHTSY_API_TOKEN: team.access_token,
695
695
  ...team.refresh_token ? { BRIGHTSY_REFRESH_TOKEN: team.refresh_token } : {},
696
+ ...team.oauth_client_id ? { BRIGHTSY_OAUTH_CLIENT_ID: team.oauth_client_id } : {},
696
697
  BRIGHTSY_ACCOUNT_ID: team.id,
697
698
  BRIGHTSY_API_URL: endpoint
698
699
  };
@@ -7,8 +7,8 @@ import {
7
7
  ensureConnectedBrightsyTeamTokens,
8
8
  getConnectedBrightsyTeamsRaw,
9
9
  listConnectedBrightsyTeams
10
- } from "./chunk-IILG7DPX.js";
11
- import "./chunk-AN3THU7F.js";
10
+ } from "./chunk-QILV2BRW.js";
11
+ import "./chunk-ROPGQRPU.js";
12
12
  import "./chunk-N7WZ6NIN.js";
13
13
  import "./chunk-WFUDY6PC.js";
14
14
  import "./chunk-HVUVQXZ2.js";
@@ -9,8 +9,8 @@ import {
9
9
  ensureConnectedBrightsyTeamTokens,
10
10
  getConnectedBrightsyTeamsRaw,
11
11
  listConnectedBrightsyTeams
12
- } from "./chunk-SVXIJ2IC.js";
13
- import "./chunk-Y4MIXGPA.js";
12
+ } from "./chunk-UNMMKZ4Q.js";
13
+ import "./chunk-P2BSMNHB.js";
14
14
  import "./chunk-VKQGAWHY.js";
15
15
  import "./chunk-ABOBTSO6.js";
16
16
  import "./chunk-EQNRWDLN.js";
package/dist/index.cjs CHANGED
@@ -10828,10 +10828,21 @@ var init_fetch = __esm({
10828
10828
  // src/brightsy/oauth.ts
10829
10829
  var oauth_exports = {};
10830
10830
  __export(oauth_exports, {
10831
+ BRIGHTSY_OAUTH_CLIENT_ID: () => BRIGHTSY_OAUTH_CLIENT_ID,
10832
+ BRIGHTSY_OAUTH_REDIRECT: () => BRIGHTSY_OAUTH_REDIRECT,
10831
10833
  brightsyAccessTokenNeedsRefresh: () => brightsyAccessTokenNeedsRefresh,
10832
10834
  ensureBrightsyLocalConfigFresh: () => ensureBrightsyLocalConfigFresh,
10833
- refreshBrightsyAccessToken: () => refreshBrightsyAccessToken
10835
+ ensureBrightsyOAuthClientId: () => ensureBrightsyOAuthClientId,
10836
+ normalizeBrightsyEndpoint: () => normalizeBrightsyEndpoint,
10837
+ refreshBrightsyAccessToken: () => refreshBrightsyAccessToken,
10838
+ registerBrightsyOAuthClient: () => registerBrightsyOAuthClient
10834
10839
  });
10840
+ function defaultFetch(fetchImpl) {
10841
+ return fetchImpl ?? globalThis.fetch.bind(globalThis);
10842
+ }
10843
+ function normalizeBrightsyEndpoint(endpoint) {
10844
+ return (endpoint || "https://brightsy.ai").replace(/\/$/, "");
10845
+ }
10835
10846
  function brightsyAccessTokenNeedsRefresh(expiresAt, now = Date.now()) {
10836
10847
  if (typeof expiresAt !== "number" || !Number.isFinite(expiresAt) || expiresAt <= 0) {
10837
10848
  return true;
@@ -10845,10 +10856,53 @@ function applyGrant(current, grant) {
10845
10856
  expires_at: grant.expires_at ?? current.expires_at
10846
10857
  };
10847
10858
  }
10859
+ async function registerBrightsyOAuthClient(opts) {
10860
+ const endpoint = normalizeBrightsyEndpoint(opts.endpoint);
10861
+ const url = `${endpoint}/oauth/register`;
10862
+ const clientId = (opts.clientId || BRIGHTSY_OAUTH_CLIENT_ID).trim();
10863
+ const redirectUri = opts.redirectUri || BRIGHTSY_OAUTH_REDIRECT;
10864
+ const fetchImpl = defaultFetch(opts.fetchImpl);
10865
+ let res;
10866
+ try {
10867
+ res = await fetchImpl(url, {
10868
+ method: "POST",
10869
+ headers: { "Content-Type": "application/json" },
10870
+ body: JSON.stringify({
10871
+ client_id: clientId,
10872
+ client_name: "Sideboard",
10873
+ description: "Sideboard desktop Brightsy MCP client",
10874
+ redirect_uris: [redirectUri],
10875
+ scope: "brightsy:api",
10876
+ grant_types: ["authorization_code", "refresh_token"],
10877
+ response_types: ["code"],
10878
+ token_endpoint_auth_method: "none"
10879
+ })
10880
+ });
10881
+ } catch (err) {
10882
+ throw new Error(formatFetchError(err, url));
10883
+ }
10884
+ if (!res.ok) return null;
10885
+ const data = await res.json();
10886
+ if (!data.client_id?.trim()) return null;
10887
+ return {
10888
+ client_id: data.client_id.trim(),
10889
+ client_secret: data.client_secret?.trim() || void 0
10890
+ };
10891
+ }
10892
+ async function ensureBrightsyOAuthClientId(opts) {
10893
+ const existing = opts.clientId?.trim();
10894
+ if (existing) return existing;
10895
+ const registered = await registerBrightsyOAuthClient({
10896
+ endpoint: opts.endpoint,
10897
+ fetchImpl: opts.fetchImpl
10898
+ });
10899
+ return registered?.client_id || BRIGHTSY_OAUTH_CLIENT_ID;
10900
+ }
10848
10901
  async function refreshBrightsyAccessToken(opts) {
10849
- const endpoint = (opts.endpoint || "https://brightsy.ai").replace(/\/$/, "");
10902
+ const endpoint = normalizeBrightsyEndpoint(opts.endpoint);
10850
10903
  const url = `${endpoint}/oauth/token`;
10851
- const fetchImpl = opts.fetchImpl ?? globalThis.fetch.bind(globalThis);
10904
+ const fetchImpl = defaultFetch(opts.fetchImpl);
10905
+ const clientId = opts.clientId?.trim() || BRIGHTSY_OAUTH_CLIENT_ID;
10852
10906
  let res;
10853
10907
  try {
10854
10908
  res = await fetchImpl(url, {
@@ -10857,7 +10911,7 @@ async function refreshBrightsyAccessToken(opts) {
10857
10911
  body: new URLSearchParams({
10858
10912
  grant_type: "refresh_token",
10859
10913
  refresh_token: opts.refreshToken,
10860
- client_id: opts.clientId || "brightsy-cli"
10914
+ client_id: clientId
10861
10915
  })
10862
10916
  });
10863
10917
  } catch (err) {
@@ -10872,34 +10926,55 @@ async function refreshBrightsyAccessToken(opts) {
10872
10926
  expires_at: data.expires_in ? Date.now() + data.expires_in * 1e3 : void 0
10873
10927
  };
10874
10928
  }
10875
- async function ensureBrightsyLocalConfigFresh(opts) {
10929
+ async function ensureBrightsyLocalConfigFreshOnce(opts) {
10876
10930
  let cfg;
10877
10931
  try {
10878
10932
  cfg = loadBrightsyConfig();
10879
10933
  } catch {
10880
10934
  return null;
10881
10935
  }
10882
- if (!cfg.refresh_token || !brightsyAccessTokenNeedsRefresh(cfg.expires_at)) {
10936
+ const refreshToken = cfg.refresh_token;
10937
+ if (!refreshToken || !brightsyAccessTokenNeedsRefresh(cfg.expires_at)) {
10883
10938
  return cfg;
10884
10939
  }
10885
- const grant = await refreshBrightsyAccessToken({
10886
- endpoint: cfg.endpoint || "https://brightsy.ai",
10887
- refreshToken: cfg.refresh_token,
10940
+ const endpoint = normalizeBrightsyEndpoint(cfg.endpoint);
10941
+ const clientId = await ensureBrightsyOAuthClientId({
10942
+ endpoint,
10888
10943
  clientId: cfg.oauth_client_id,
10889
10944
  fetchImpl: opts?.fetchImpl
10890
10945
  });
10946
+ if (clientId !== cfg.oauth_client_id) {
10947
+ cfg = { ...cfg, oauth_client_id: clientId };
10948
+ saveBrightsyConfig(cfg);
10949
+ }
10950
+ const grant = await refreshBrightsyAccessToken({
10951
+ endpoint,
10952
+ refreshToken,
10953
+ clientId,
10954
+ fetchImpl: opts?.fetchImpl
10955
+ });
10891
10956
  if (!grant) return cfg;
10892
- const next = { ...cfg, ...applyGrant(cfg, grant) };
10957
+ const next = { ...cfg, ...applyGrant(cfg, grant), oauth_client_id: clientId };
10893
10958
  saveBrightsyConfig(next);
10894
10959
  return next;
10895
10960
  }
10896
- var REFRESH_SKEW_MS;
10961
+ async function ensureBrightsyLocalConfigFresh(opts) {
10962
+ if (refreshInFlight) return refreshInFlight;
10963
+ refreshInFlight = ensureBrightsyLocalConfigFreshOnce(opts).finally(() => {
10964
+ refreshInFlight = null;
10965
+ });
10966
+ return refreshInFlight;
10967
+ }
10968
+ var REFRESH_SKEW_MS, BRIGHTSY_OAUTH_CLIENT_ID, BRIGHTSY_OAUTH_REDIRECT, refreshInFlight;
10897
10969
  var init_oauth = __esm({
10898
10970
  "src/brightsy/oauth.ts"() {
10899
10971
  "use strict";
10900
10972
  init_fetch();
10901
10973
  init_config();
10902
10974
  REFRESH_SKEW_MS = 6e4;
10975
+ BRIGHTSY_OAUTH_CLIENT_ID = "sideboard";
10976
+ BRIGHTSY_OAUTH_REDIRECT = "http://127.0.0.1:19850/callback";
10977
+ refreshInFlight = null;
10903
10978
  }
10904
10979
  });
10905
10980
 
@@ -11052,10 +11127,10 @@ function applyConnectedTeamToCli(team) {
11052
11127
  account_id: team.id,
11053
11128
  account_slug: team.slug,
11054
11129
  endpoint: team.endpoint ?? base.endpoint ?? "https://brightsy.ai",
11055
- oauth_client_id: base.oauth_client_id
11130
+ oauth_client_id: team.oauth_client_id ?? base.oauth_client_id
11056
11131
  });
11057
11132
  }
11058
- async function refreshTeamToken(team) {
11133
+ async function refreshTeamToken(team, opts) {
11059
11134
  if (!team.refresh_token) return team;
11060
11135
  const cfg = (() => {
11061
11136
  try {
@@ -11064,21 +11139,31 @@ async function refreshTeamToken(team) {
11064
11139
  return null;
11065
11140
  }
11066
11141
  })();
11142
+ const endpoint = team.endpoint || "https://brightsy.ai";
11143
+ const clientId = await ensureBrightsyOAuthClientId({
11144
+ endpoint,
11145
+ clientId: team.oauth_client_id || cfg?.oauth_client_id,
11146
+ fetchImpl: opts?.fetchImpl
11147
+ });
11067
11148
  const grant = await refreshBrightsyAccessToken({
11068
- endpoint: team.endpoint || "https://brightsy.ai",
11149
+ endpoint,
11069
11150
  refreshToken: team.refresh_token,
11070
- clientId: cfg?.oauth_client_id
11151
+ clientId,
11152
+ fetchImpl: opts?.fetchImpl
11071
11153
  });
11072
- if (!grant) return team;
11154
+ if (!grant) return { ...team, oauth_client_id: clientId || team.oauth_client_id };
11073
11155
  return {
11074
11156
  ...team,
11075
11157
  access_token: grant.access_token,
11076
11158
  refresh_token: grant.refresh_token || team.refresh_token,
11077
- expires_at: grant.expires_at ?? team.expires_at
11159
+ expires_at: grant.expires_at ?? team.expires_at,
11160
+ oauth_client_id: clientId
11078
11161
  };
11079
11162
  }
11080
- async function ensureConnectedBrightsyTeamTokens() {
11081
- await ensureBrightsyLocalConfigFresh().catch(() => null);
11163
+ async function ensureConnectedBrightsyTeamTokens(opts) {
11164
+ await ensureBrightsyLocalConfigFresh({ fetchImpl: opts?.fetchImpl }).catch(
11165
+ () => null
11166
+ );
11082
11167
  const teams = readStore4();
11083
11168
  if (teams.length === 0) return [];
11084
11169
  const next = [];
@@ -11088,8 +11173,8 @@ async function ensureConnectedBrightsyTeamTokens() {
11088
11173
  next.push(team);
11089
11174
  continue;
11090
11175
  }
11091
- const refreshed = await refreshTeamToken(team);
11092
- if (refreshed.access_token !== team.access_token || refreshed.refresh_token !== team.refresh_token || refreshed.expires_at !== team.expires_at) {
11176
+ const refreshed = await refreshTeamToken(team, opts);
11177
+ if (refreshed.access_token !== team.access_token || refreshed.refresh_token !== team.refresh_token || refreshed.expires_at !== team.expires_at || refreshed.oauth_client_id !== team.oauth_client_id) {
11093
11178
  changed = true;
11094
11179
  }
11095
11180
  next.push(refreshed);
@@ -11119,7 +11204,8 @@ function ensureCliTeamTracked(meta) {
11119
11204
  access_token: cfg.access_token,
11120
11205
  refresh_token: cfg.refresh_token,
11121
11206
  expires_at: cfg.expires_at,
11122
- endpoint: cfg.endpoint
11207
+ endpoint: cfg.endpoint,
11208
+ oauth_client_id: cfg.oauth_client_id
11123
11209
  };
11124
11210
  writeStore3([...existing, team]);
11125
11211
  } catch {
@@ -11146,7 +11232,8 @@ async function connectBrightsyTeam(accountIdOrSlug) {
11146
11232
  access_token: minted.access_token,
11147
11233
  refresh_token: minted.refresh_token,
11148
11234
  expires_at: minted.expires_at,
11149
- endpoint: minted.endpoint
11235
+ endpoint: minted.endpoint,
11236
+ oauth_client_id: minted.oauth_client_id
11150
11237
  };
11151
11238
  writeStore3([...existing, team]);
11152
11239
  return listConnectedBrightsyTeams();
@@ -12206,6 +12293,7 @@ function teamEnv(team) {
12206
12293
  return {
12207
12294
  BRIGHTSY_API_TOKEN: team.access_token,
12208
12295
  ...team.refresh_token ? { BRIGHTSY_REFRESH_TOKEN: team.refresh_token } : {},
12296
+ ...team.oauth_client_id ? { BRIGHTSY_OAUTH_CLIENT_ID: team.oauth_client_id } : {},
12209
12297
  BRIGHTSY_ACCOUNT_ID: team.id,
12210
12298
  BRIGHTSY_API_URL: endpoint
12211
12299
  };
@@ -18323,12 +18411,12 @@ async function ensureAbleTimeAccessToken() {
18323
18411
  return access;
18324
18412
  }
18325
18413
  if (refresh) {
18326
- if (!refreshInFlight) {
18327
- refreshInFlight = refreshAbleTimeAccessToken(refresh).finally(() => {
18328
- refreshInFlight = null;
18414
+ if (!refreshInFlight2) {
18415
+ refreshInFlight2 = refreshAbleTimeAccessToken(refresh).finally(() => {
18416
+ refreshInFlight2 = null;
18329
18417
  });
18330
18418
  }
18331
- return refreshInFlight;
18419
+ return refreshInFlight2;
18332
18420
  }
18333
18421
  return access || null;
18334
18422
  }
@@ -18451,7 +18539,7 @@ async function startAbleTimeOAuth(opts) {
18451
18539
  return loadAppSettings();
18452
18540
  }
18453
18541
  }
18454
- var import_node_crypto10, import_node_http, ABLETIME_OAUTH_CALLBACK_PATH, ABLETIME_OAUTH_PORT, ABLETIME_OAUTH_LOCAL_CALLBACK, ABLETIME_OAUTH_REDIRECT, BOUNCE_QUERY_KEYS, BAKED_ABLETIME_OAUTH_CLIENT_ID, ABLETIME_OAUTH_RESOURCE, REFRESH_SKEW_MS2, refreshInFlight, ABLETIME_OAUTH_CANCELLED, AbleTimeOAuthCancelledError;
18542
+ var import_node_crypto10, import_node_http, ABLETIME_OAUTH_CALLBACK_PATH, ABLETIME_OAUTH_PORT, ABLETIME_OAUTH_LOCAL_CALLBACK, ABLETIME_OAUTH_REDIRECT, BOUNCE_QUERY_KEYS, BAKED_ABLETIME_OAUTH_CLIENT_ID, ABLETIME_OAUTH_RESOURCE, REFRESH_SKEW_MS2, refreshInFlight2, ABLETIME_OAUTH_CANCELLED, AbleTimeOAuthCancelledError;
18455
18543
  var init_abletime_oauth = __esm({
18456
18544
  "src/integrations/abletime-oauth.ts"() {
18457
18545
  "use strict";
@@ -18468,7 +18556,7 @@ var init_abletime_oauth = __esm({
18468
18556
  BAKED_ABLETIME_OAUTH_CLIENT_ID = "https://www.sideboard.cloud/oauth/abletime-client.json";
18469
18557
  ABLETIME_OAUTH_RESOURCE = `${DEFAULT_ABLETIME_HOST}/api/public/v2/mcp`;
18470
18558
  REFRESH_SKEW_MS2 = 5 * 6e4;
18471
- refreshInFlight = null;
18559
+ refreshInFlight2 = null;
18472
18560
  ABLETIME_OAUTH_CANCELLED = "AbleTime sign-in cancelled";
18473
18561
  AbleTimeOAuthCancelledError = class extends Error {
18474
18562
  constructor(message = ABLETIME_OAUTH_CANCELLED) {
@@ -25684,6 +25772,8 @@ __export(index_exports, {
25684
25772
  BAKED_ABLETIME_OAUTH_CLIENT_ID: () => BAKED_ABLETIME_OAUTH_CLIENT_ID,
25685
25773
  BAKED_SLACK_RELAY_URL: () => BAKED_SLACK_RELAY_URL,
25686
25774
  BRIGHTSY_MCP_ALLOWED_TOOLS: () => BRIGHTSY_MCP_ALLOWED_TOOLS,
25775
+ BRIGHTSY_OAUTH_CLIENT_ID: () => BRIGHTSY_OAUTH_CLIENT_ID,
25776
+ BRIGHTSY_OAUTH_REDIRECT: () => BRIGHTSY_OAUTH_REDIRECT,
25687
25777
  BRIGHTSY_SUMMARIZE_CONTEXT_TOOL: () => BRIGHTSY_SUMMARIZE_CONTEXT_TOOL,
25688
25778
  BUNDLED_LONG_RUNNING_PATH: () => BUNDLED_LONG_RUNNING_PATH,
25689
25779
  BUNDLED_SKILL_PREFIX: () => BUNDLED_SKILL_PREFIX,
@@ -25952,6 +26042,7 @@ __export(index_exports, {
25952
26042
  ensureAbleTimeTask: () => ensureAbleTimeTask,
25953
26043
  ensureAgentPath: () => ensureAgentPath,
25954
26044
  ensureBrightsyLocalConfigFresh: () => ensureBrightsyLocalConfigFresh,
26045
+ ensureBrightsyOAuthClientId: () => ensureBrightsyOAuthClientId,
25955
26046
  ensureCloudCoordinator: () => ensureCloudCoordinator,
25956
26047
  ensureConnectedBrightsyTeamTokens: () => ensureConnectedBrightsyTeamTokens,
25957
26048
  ensureGhPreferOrigin: () => ensureGhPreferOrigin,
@@ -26260,6 +26351,7 @@ __export(index_exports, {
26260
26351
  nonInteractiveGitProcessEnv: () => nonInteractiveGitProcessEnv,
26261
26352
  normalizeAbleTimeCredential: () => normalizeAbleTimeCredential,
26262
26353
  normalizeAbleTimeHost: () => normalizeAbleTimeHost,
26354
+ normalizeBrightsyEndpoint: () => normalizeBrightsyEndpoint,
26263
26355
  normalizeCodeSelection: () => normalizeCodeSelection,
26264
26356
  normalizeLinearRelationType: () => normalizeLinearRelationType,
26265
26357
  normalizeParseResult: () => normalizeParseResult,
@@ -26328,6 +26420,7 @@ __export(index_exports, {
26328
26420
  recordSlackOutboundWatch: () => recordSlackOutboundWatch,
26329
26421
  refreshBrightsyAccessToken: () => refreshBrightsyAccessToken,
26330
26422
  refreshGitHubAuth: () => refreshGitHubAuth,
26423
+ registerBrightsyOAuthClient: () => registerBrightsyOAuthClient,
26331
26424
  registerPackagedUserMcpClients: () => registerPackagedUserMcpClients,
26332
26425
  releaseCaffeinateHoldForThread: () => releaseCaffeinateHoldForThread,
26333
26426
  releaseDesktopHost: () => releaseDesktopHost,
@@ -26859,7 +26952,7 @@ async function fetchLinearViewer(accessToken) {
26859
26952
  organizationName: viewer?.organization?.name?.trim() || void 0
26860
26953
  };
26861
26954
  }
26862
- var refreshInFlight2 = null;
26955
+ var refreshInFlight3 = null;
26863
26956
  async function refreshLinearAccessToken(refreshToken) {
26864
26957
  const { clientId, clientSecret } = linearOAuthCredentials();
26865
26958
  const body = new URLSearchParams({
@@ -26890,12 +26983,12 @@ async function getLinearAuthToken(settings = loadAppSettings()) {
26890
26983
  return access;
26891
26984
  }
26892
26985
  if (refresh) {
26893
- if (!refreshInFlight2) {
26894
- refreshInFlight2 = refreshLinearAccessToken(refresh).finally(() => {
26895
- refreshInFlight2 = null;
26986
+ if (!refreshInFlight3) {
26987
+ refreshInFlight3 = refreshLinearAccessToken(refresh).finally(() => {
26988
+ refreshInFlight3 = null;
26896
26989
  });
26897
26990
  }
26898
- return refreshInFlight2.catch((err) => {
26991
+ return refreshInFlight3.catch((err) => {
26899
26992
  if (apiKey) return apiKey;
26900
26993
  throw err;
26901
26994
  });
@@ -34476,6 +34569,8 @@ init_outbound_watch();
34476
34569
  BAKED_ABLETIME_OAUTH_CLIENT_ID,
34477
34570
  BAKED_SLACK_RELAY_URL,
34478
34571
  BRIGHTSY_MCP_ALLOWED_TOOLS,
34572
+ BRIGHTSY_OAUTH_CLIENT_ID,
34573
+ BRIGHTSY_OAUTH_REDIRECT,
34479
34574
  BRIGHTSY_SUMMARIZE_CONTEXT_TOOL,
34480
34575
  BUNDLED_LONG_RUNNING_PATH,
34481
34576
  BUNDLED_SKILL_PREFIX,
@@ -34744,6 +34839,7 @@ init_outbound_watch();
34744
34839
  ensureAbleTimeTask,
34745
34840
  ensureAgentPath,
34746
34841
  ensureBrightsyLocalConfigFresh,
34842
+ ensureBrightsyOAuthClientId,
34747
34843
  ensureCloudCoordinator,
34748
34844
  ensureConnectedBrightsyTeamTokens,
34749
34845
  ensureGhPreferOrigin,
@@ -35052,6 +35148,7 @@ init_outbound_watch();
35052
35148
  nonInteractiveGitProcessEnv,
35053
35149
  normalizeAbleTimeCredential,
35054
35150
  normalizeAbleTimeHost,
35151
+ normalizeBrightsyEndpoint,
35055
35152
  normalizeCodeSelection,
35056
35153
  normalizeLinearRelationType,
35057
35154
  normalizeParseResult,
@@ -35120,6 +35217,7 @@ init_outbound_watch();
35120
35217
  recordSlackOutboundWatch,
35121
35218
  refreshBrightsyAccessToken,
35122
35219
  refreshGitHubAuth,
35220
+ registerBrightsyOAuthClient,
35123
35221
  registerPackagedUserMcpClients,
35124
35222
  releaseCaffeinateHoldForThread,
35125
35223
  releaseDesktopHost,