@schoolai/shipyard 3.7.0 → 3.8.0-rc.20260529.0

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.
Files changed (104) hide show
  1. package/dist/{auth-SS7LV5XK.js → auth-EXHO3AG5.js} +4 -4
  2. package/dist/capability-detector-worker.js +142 -0
  3. package/dist/capability-detector-worker.js.map +1 -0
  4. package/dist/{chunk-DKMDBOFU.js → chunk-2CNIEBKO.js} +21 -11
  5. package/dist/chunk-2CNIEBKO.js.map +1 -0
  6. package/dist/chunk-4T2OQAVL.js +51 -0
  7. package/dist/chunk-4T2OQAVL.js.map +1 -0
  8. package/dist/chunk-5ER6ZHA2.js +46 -0
  9. package/dist/chunk-5ER6ZHA2.js.map +1 -0
  10. package/dist/chunk-7LSEE26O.js +24227 -0
  11. package/dist/chunk-7LSEE26O.js.map +1 -0
  12. package/dist/{chunk-7AHRFPAL.js → chunk-7YOU7MBN.js} +183 -17
  13. package/dist/chunk-7YOU7MBN.js.map +1 -0
  14. package/dist/chunk-CMGJGK6R.js +382 -0
  15. package/dist/chunk-CMGJGK6R.js.map +1 -0
  16. package/dist/{chunk-VPMN47TL.js → chunk-CNR7O5YH.js} +1 -2
  17. package/dist/{chunk-2J3WSIAF.js → chunk-EF2DAODF.js} +18 -3
  18. package/dist/chunk-EF2DAODF.js.map +1 -0
  19. package/dist/chunk-HQ43PHOH.js +1203 -0
  20. package/dist/chunk-HQ43PHOH.js.map +1 -0
  21. package/dist/chunk-KITSAHTX.js +134 -0
  22. package/dist/chunk-KITSAHTX.js.map +1 -0
  23. package/dist/chunk-LESHN5J5.js +6898 -0
  24. package/dist/chunk-LESHN5J5.js.map +1 -0
  25. package/dist/{chunk-LW2MS4T5.js → chunk-LMJFHKRD.js} +15 -12
  26. package/dist/chunk-LMJFHKRD.js.map +1 -0
  27. package/dist/{chunk-SNYEQHUK.js → chunk-NACJENDW.js} +14 -21
  28. package/dist/chunk-NACJENDW.js.map +1 -0
  29. package/dist/{chunk-IISLTKYY.js → chunk-TU63KZFW.js} +2 -2
  30. package/dist/chunk-TX6DK4PK.js +186 -0
  31. package/dist/chunk-TX6DK4PK.js.map +1 -0
  32. package/dist/chunk-UQVXWOPT.js +48 -0
  33. package/dist/chunk-UQVXWOPT.js.map +1 -0
  34. package/dist/{chunk-3MNPDCO5.js → chunk-WBB4XHLH.js} +139 -140
  35. package/dist/chunk-WBB4XHLH.js.map +1 -0
  36. package/dist/chunk-X3MULCV5.js +11 -0
  37. package/dist/chunk-X3MULCV5.js.map +1 -0
  38. package/dist/chunk-YZ3Z3ZYI.js +787 -0
  39. package/dist/chunk-YZ3Z3ZYI.js.map +1 -0
  40. package/dist/{chunk-2UN5AR7V.js → chunk-ZAOPND5G.js} +2 -2
  41. package/dist/chunk-ZFKJAYAN.js +542 -0
  42. package/dist/chunk-ZFKJAYAN.js.map +1 -0
  43. package/dist/cursor-hook-shim.js +316 -0
  44. package/dist/cursor-hook-shim.js.map +1 -0
  45. package/dist/cursor-runner.js +358 -0
  46. package/dist/cursor-runner.js.map +1 -0
  47. package/dist/electron-utility.js +111 -0
  48. package/dist/electron-utility.js.map +1 -0
  49. package/dist/git-pool-V73Q53NX.js +18 -0
  50. package/dist/{git-repo-VRT57DGC.js → git-repo-TN3VZXQV.js} +9 -6
  51. package/dist/index.js +12 -12
  52. package/dist/index.js.map +1 -1
  53. package/dist/{logger-GQCSLSZH.js → logger-QHPTO22N.js} +4 -4
  54. package/dist/login-Q7SZI7JJ.js +20 -0
  55. package/dist/{logout-VUNCW5B2.js → logout-O4AVMO5S.js} +6 -6
  56. package/dist/mcp-servers-F64M5T4I.js +24 -0
  57. package/dist/{roi-Y3MX5UW4.js → roi-EYDLPOCS.js} +5 -5
  58. package/dist/rss-worker.js +159 -0
  59. package/dist/rss-worker.js.map +1 -0
  60. package/dist/{serve-O53FNK64.js → serve-6A7RJWEF.js} +89862 -102999
  61. package/dist/{serve-O53FNK64.js.map → serve-6A7RJWEF.js.map} +1 -1
  62. package/dist/skills-ZHEPSBHW.js +11 -0
  63. package/dist/{start-IDFDHRD6.js → start-YGYYIK53.js} +229 -27
  64. package/dist/start-YGYYIK53.js.map +1 -0
  65. package/dist/vault-crypto-BKDOA65F.js +13 -0
  66. package/dist/vault-crypto-BKDOA65F.js.map +1 -0
  67. package/dist/worker.js +6 -3
  68. package/dist/worker.js.map +1 -1
  69. package/package.json +17 -10
  70. package/dist/chunk-2J3WSIAF.js.map +0 -1
  71. package/dist/chunk-3MNPDCO5.js.map +0 -1
  72. package/dist/chunk-66OBOZ3X.js +0 -79
  73. package/dist/chunk-66OBOZ3X.js.map +0 -1
  74. package/dist/chunk-7AHRFPAL.js.map +0 -1
  75. package/dist/chunk-DKMDBOFU.js.map +0 -1
  76. package/dist/chunk-L2WQMPWS.js +0 -666
  77. package/dist/chunk-L2WQMPWS.js.map +0 -1
  78. package/dist/chunk-LW2MS4T5.js.map +0 -1
  79. package/dist/chunk-PI77CUEP.js +0 -49
  80. package/dist/chunk-PI77CUEP.js.map +0 -1
  81. package/dist/chunk-RXI4637N.js +0 -395
  82. package/dist/chunk-RXI4637N.js.map +0 -1
  83. package/dist/chunk-SNYEQHUK.js.map +0 -1
  84. package/dist/chunk-VBPHGPBR.js +0 -126
  85. package/dist/chunk-VBPHGPBR.js.map +0 -1
  86. package/dist/index.d.ts +0 -2
  87. package/dist/login-L4BBPUYO.js +0 -20
  88. package/dist/mcp-servers-MXS5VAWI.js +0 -18
  89. package/dist/shell-V36EX2IJ.js +0 -27
  90. package/dist/skills-GPGRNV4R.js +0 -9
  91. package/dist/start-IDFDHRD6.js.map +0 -1
  92. package/dist/worker.d.ts +0 -49
  93. /package/dist/{auth-SS7LV5XK.js.map → auth-EXHO3AG5.js.map} +0 -0
  94. /package/dist/{chunk-VPMN47TL.js.map → chunk-CNR7O5YH.js.map} +0 -0
  95. /package/dist/{chunk-IISLTKYY.js.map → chunk-TU63KZFW.js.map} +0 -0
  96. /package/dist/{chunk-2UN5AR7V.js.map → chunk-ZAOPND5G.js.map} +0 -0
  97. /package/dist/{git-repo-VRT57DGC.js.map → git-pool-V73Q53NX.js.map} +0 -0
  98. /package/dist/{logger-GQCSLSZH.js.map → git-repo-TN3VZXQV.js.map} +0 -0
  99. /package/dist/{login-L4BBPUYO.js.map → logger-QHPTO22N.js.map} +0 -0
  100. /package/dist/{mcp-servers-MXS5VAWI.js.map → login-Q7SZI7JJ.js.map} +0 -0
  101. /package/dist/{logout-VUNCW5B2.js.map → logout-O4AVMO5S.js.map} +0 -0
  102. /package/dist/{shell-V36EX2IJ.js.map → mcp-servers-F64M5T4I.js.map} +0 -0
  103. /package/dist/{roi-Y3MX5UW4.js.map → roi-EYDLPOCS.js.map} +0 -0
  104. /package/dist/{skills-GPGRNV4R.js.map → skills-ZHEPSBHW.js.map} +0 -0
@@ -1,666 +0,0 @@
1
- #!/usr/bin/env node
2
- import {
3
- logger
4
- } from "./chunk-2UN5AR7V.js";
5
- import {
6
- external_exports
7
- } from "./chunk-VPMN47TL.js";
8
-
9
- // src/shared/capabilities/mcp-servers.ts
10
- import { readFile as readFile2 } from "fs/promises";
11
- import { homedir as homedir2 } from "os";
12
- import { join as join2 } from "path";
13
-
14
- // src/shared/mcp/claude-code-credentials.ts
15
- import { execFile as execFileCb } from "child_process";
16
- import { readFile } from "fs/promises";
17
- import { homedir } from "os";
18
- import { join } from "path";
19
- import { promisify } from "util";
20
-
21
- // src/shared/mcp/schemas.ts
22
- import {
23
- OAuthMetadataSchema,
24
- OAuthProtectedResourceMetadataSchema,
25
- OpenIdProviderDiscoveryMetadataSchema
26
- } from "@modelcontextprotocol/sdk/shared/auth.js";
27
- var AuthorizationServerMetadataSchema = external_exports.union([
28
- OAuthMetadataSchema,
29
- OpenIdProviderDiscoveryMetadataSchema
30
- ]);
31
- var DiscoveryStateSchema = external_exports.object({
32
- authorizationServerUrl: external_exports.string(),
33
- authorizationServerMetadata: AuthorizationServerMetadataSchema.optional(),
34
- resourceMetadata: OAuthProtectedResourceMetadataSchema.optional(),
35
- resourceMetadataUrl: external_exports.string().optional()
36
- }).passthrough();
37
-
38
- // src/shared/mcp/claude-code-credentials.ts
39
- var execFile = promisify(execFileCb);
40
- var ClaudeCodeOAuthEntrySchema = external_exports.object({
41
- serverName: external_exports.string().nullable().optional(),
42
- serverUrl: external_exports.string().nullable().optional(),
43
- clientId: external_exports.string().nullable().optional(),
44
- clientSecret: external_exports.string().nullable().optional(),
45
- accessToken: external_exports.string().nullable().optional(),
46
- refreshToken: external_exports.string().nullable().optional(),
47
- expiresAt: external_exports.number().nullable().optional(),
48
- discoveryState: DiscoveryStateSchema.nullable().optional()
49
- }).passthrough();
50
- var CredentialsFileSchema = external_exports.object({
51
- mcpOAuth: external_exports.record(external_exports.string(), external_exports.unknown()).optional()
52
- }).passthrough();
53
- var CREDENTIALS_PATH = join(homedir(), ".claude", ".credentials.json");
54
- var KEYCHAIN_SERVICE = "Claude Code-credentials";
55
- var PluginMcpJsonSchema = external_exports.record(
56
- external_exports.string(),
57
- external_exports.object({
58
- url: external_exports.string().optional(),
59
- oauth: external_exports.object({ clientId: external_exports.string(), callbackPort: external_exports.number().optional() }).optional()
60
- }).passthrough()
61
- );
62
- async function extractClientIdsFromPlugin(installPath, result) {
63
- const raw = await readFile(join(installPath, ".mcp.json"), "utf-8");
64
- const json = JSON.parse(raw);
65
- const outer = external_exports.record(external_exports.string(), external_exports.unknown()).safeParse(json);
66
- if (!outer.success) return;
67
- const servers = outer.data.mcpServers ?? outer.data;
68
- const validated = PluginMcpJsonSchema.safeParse(servers);
69
- if (!validated.success) return;
70
- for (const config of Object.values(validated.data)) {
71
- if (config.url && config.oauth?.clientId) {
72
- result.set(config.url, config.oauth.clientId);
73
- }
74
- }
75
- }
76
- async function readPluginClientIds() {
77
- const result = /* @__PURE__ */ new Map();
78
- try {
79
- const installedPath = join(homedir(), ".claude", "plugins", "installed_plugins.json");
80
- const InstalledPluginsSchema = external_exports.object({
81
- plugins: external_exports.record(external_exports.string(), external_exports.array(external_exports.object({ installPath: external_exports.string().optional() }))).optional()
82
- });
83
- const parsed = InstalledPluginsSchema.safeParse(
84
- JSON.parse(await readFile(installedPath, "utf-8"))
85
- );
86
- if (!parsed.success || !parsed.data.plugins) return result;
87
- for (const installs of Object.values(parsed.data.plugins)) {
88
- const installPath = installs?.[0]?.installPath;
89
- if (!installPath) continue;
90
- await extractClientIdsFromPlugin(installPath, result).catch(() => {
91
- });
92
- }
93
- } catch {
94
- }
95
- return result;
96
- }
97
- async function readKeychainCredentials() {
98
- if (process.platform !== "darwin") return null;
99
- try {
100
- const { stdout } = await execFile(
101
- "security",
102
- ["find-generic-password", "-s", KEYCHAIN_SERVICE, "-w"],
103
- { timeout: 5e3 }
104
- );
105
- const result = external_exports.record(external_exports.string(), external_exports.unknown()).safeParse(JSON.parse(stdout.trim()));
106
- return result.success ? result.data : null;
107
- } catch {
108
- return null;
109
- }
110
- }
111
- function scanEntries(mcpOAuth, serverUrl) {
112
- let bestWithToken = null;
113
- let clientId;
114
- let clientSecret;
115
- let discoveryState;
116
- for (const value of Object.values(mcpOAuth)) {
117
- const entryResult = ClaudeCodeOAuthEntrySchema.safeParse(value);
118
- if (!entryResult.success) continue;
119
- const entry = entryResult.data;
120
- if (entry.serverUrl !== serverUrl) continue;
121
- if (entry.clientId && !clientId) {
122
- clientId = entry.clientId;
123
- clientSecret = entry.clientSecret || void 0;
124
- }
125
- if (entry.discoveryState && !discoveryState) {
126
- discoveryState = entry.discoveryState;
127
- }
128
- if (entry.accessToken && !bestWithToken) {
129
- bestWithToken = entry;
130
- }
131
- }
132
- return { bestWithToken, clientId, clientSecret, discoveryState };
133
- }
134
- function findMatchingEntry(credentialsData, serverName, serverUrl) {
135
- const fileResult = CredentialsFileSchema.safeParse(credentialsData);
136
- if (!fileResult.success) return null;
137
- const mcpOAuth = fileResult.data.mcpOAuth;
138
- if (!mcpOAuth) return null;
139
- const { bestWithToken, clientId, clientSecret, discoveryState } = scanEntries(
140
- mcpOAuth,
141
- serverUrl
142
- );
143
- if (!bestWithToken && !clientId) return null;
144
- return {
145
- serverName: bestWithToken?.serverName ?? serverName,
146
- serverUrl,
147
- clientId: bestWithToken?.clientId || clientId,
148
- clientSecret: bestWithToken?.clientSecret || clientSecret || void 0,
149
- accessToken: bestWithToken?.accessToken || void 0,
150
- refreshToken: bestWithToken?.refreshToken || void 0,
151
- expiresAt: bestWithToken?.expiresAt ?? void 0,
152
- discoveryState: bestWithToken?.discoveryState ?? discoveryState ?? void 0
153
- };
154
- }
155
- async function readClaudeCodeCredentials(serverName, serverUrl) {
156
- if (!serverUrl) return null;
157
- try {
158
- const keychainData = await readKeychainCredentials();
159
- if (keychainData) {
160
- const entry = findMatchingEntry(keychainData, serverName, serverUrl);
161
- if (entry) {
162
- logger.debug({ serverUrl }, "Found Claude Code credentials in macOS Keychain");
163
- return entry;
164
- }
165
- }
166
- } catch (err) {
167
- logger.debug({ err }, "Failed to read Claude Code credentials from Keychain");
168
- }
169
- try {
170
- const raw = await readFile(CREDENTIALS_PATH, "utf-8");
171
- const fileResult = CredentialsFileSchema.safeParse(JSON.parse(raw));
172
- if (fileResult.success) {
173
- const entry = findMatchingEntry(fileResult.data, serverName, serverUrl);
174
- if (entry) {
175
- logger.debug({ serverUrl }, "Found Claude Code credentials in legacy file");
176
- return entry;
177
- }
178
- }
179
- return null;
180
- } catch (err) {
181
- logger.debug({ err }, "Failed to read Claude Code credentials from file");
182
- return null;
183
- }
184
- }
185
-
186
- // src/shared/mcp/resolve-servers.ts
187
- var ENV_VAR_PATTERN = /\$\{([^}]+)\}/g;
188
- var VAULT_REF_PATTERN = /^\$\{vault:([^}]+)\}$/;
189
- function interpolateEnvVars(headers) {
190
- const result = {};
191
- for (const [key, value] of Object.entries(headers)) {
192
- result[key] = value.replace(
193
- ENV_VAR_PATTERN,
194
- (_, varName) => process.env[varName] ?? ""
195
- );
196
- }
197
- return result;
198
- }
199
- function resolveHeaders(server) {
200
- if (!server.headers) return void 0;
201
- return interpolateEnvVars(server.headers);
202
- }
203
- function resolveStdioEnv(env, store, log) {
204
- if (!env) return void 0;
205
- if (!store) return env;
206
- const result = {};
207
- let changed = false;
208
- for (const [key, value] of Object.entries(env)) {
209
- const match = VAULT_REF_PATTERN.exec(value);
210
- if (match) {
211
- const vaultKey = match[1] ?? "";
212
- const token = store.getTokenSync(vaultKey);
213
- if (token && !store.isExpired(token)) {
214
- result[key] = token.accessToken;
215
- changed = true;
216
- log?.({
217
- event: "vault_ref_resolved",
218
- envKey: key,
219
- vaultKey,
220
- tokenType: token.tokenType,
221
- hasExpiry: token.expiresAt !== void 0
222
- });
223
- continue;
224
- }
225
- log?.({
226
- event: "vault_ref_unresolved",
227
- envKey: key,
228
- vaultKey,
229
- tokenFound: token !== null,
230
- tokenExpired: token ? store.isExpired(token) : false
231
- });
232
- }
233
- result[key] = value;
234
- }
235
- return changed ? result : env;
236
- }
237
- function resolveEnabledMcpServers(overrides, available, mcpTokenStore) {
238
- if (!overrides || !available) return void 0;
239
- const enabledNames = new Set(overrides.filter((o) => o.enabled).map((o) => o.name));
240
- if (enabledNames.size === 0) return {};
241
- const result = {};
242
- for (const server of available) {
243
- if (!enabledNames.has(server.name)) continue;
244
- if (server.type === "http" && server.url) {
245
- result[server.name] = {
246
- type: "http",
247
- url: server.url,
248
- headers: resolveHeaders(server)
249
- };
250
- } else if (server.type === "sse" && server.url) {
251
- result[server.name] = {
252
- type: "sse",
253
- url: server.url,
254
- headers: resolveHeaders(server)
255
- };
256
- } else if (server.command) {
257
- result[server.name] = {
258
- command: server.command,
259
- args: server.args ?? void 0,
260
- env: resolveStdioEnv(server.env, mcpTokenStore)
261
- };
262
- }
263
- }
264
- return result;
265
- }
266
-
267
- // src/shared/auth/anthropic-credentials.ts
268
- import { execFile as execFileCb2 } from "child_process";
269
- import { promisify as promisify2 } from "util";
270
- var execFile2 = promisify2(execFileCb2);
271
- var defaultLog = (entry) => logger.debug(entry, entry.event);
272
- function isRecord(value) {
273
- return typeof value === "object" && value !== null && !Array.isArray(value);
274
- }
275
- async function readKeychainEntry(service) {
276
- if (process.platform !== "darwin") return null;
277
- try {
278
- const { stdout } = await execFile2("security", ["find-generic-password", "-s", service, "-w"], {
279
- timeout: 5e3
280
- });
281
- const value = stdout.trim();
282
- return value || null;
283
- } catch {
284
- return null;
285
- }
286
- }
287
- async function readKeychainOAuthToken(log = defaultLog) {
288
- if (process.platform !== "darwin") {
289
- log({ event: "anthropic_keychain_read_skipped", reason: "non_darwin" });
290
- return null;
291
- }
292
- const raw = await readKeychainEntry("Claude Code-credentials");
293
- if (!raw) {
294
- log({ event: "anthropic_keychain_oauth_missing", reason: "no_credentials_entry" });
295
- return null;
296
- }
297
- let parsed;
298
- try {
299
- parsed = JSON.parse(raw);
300
- } catch {
301
- log({ event: "anthropic_keychain_oauth_corrupt", reason: "json_parse_error" });
302
- return null;
303
- }
304
- if (!isRecord(parsed)) {
305
- log({ event: "anthropic_keychain_oauth_corrupt", reason: "json_parse_error" });
306
- return null;
307
- }
308
- const oauth = parsed.claudeAiOauth;
309
- if (!isRecord(oauth)) {
310
- log({ event: "anthropic_keychain_oauth_missing", reason: "no_oauth_field" });
311
- return null;
312
- }
313
- const token = oauth.accessToken;
314
- if (typeof token !== "string" || token.length === 0) {
315
- log({ event: "anthropic_keychain_oauth_missing", reason: "no_oauth_field" });
316
- return null;
317
- }
318
- return token;
319
- }
320
- async function readKeychainManagedKey() {
321
- const value = await readKeychainEntry("Claude Code");
322
- if (!value || !value.startsWith("sk-")) return null;
323
- return value;
324
- }
325
-
326
- // src/shared/capabilities/account-integrations.ts
327
- function parseClaudeAiServers(data) {
328
- if (typeof data !== "object" || data === null) return [];
329
- const obj = data;
330
- if (!Array.isArray(obj.data)) return [];
331
- const results = [];
332
- for (const entry of obj.data) {
333
- if (typeof entry !== "object" || entry === null) continue;
334
- const rec = entry;
335
- if (typeof rec.name === "string" && typeof rec.url === "string") {
336
- results.push({ name: rec.name, url: rec.url });
337
- }
338
- }
339
- return results;
340
- }
341
- async function fetchClaudeAiIntegrations(log) {
342
- const debugLog = log ?? ((entry) => logger.debug(entry, entry.event));
343
- try {
344
- const token = await readKeychainOAuthToken(debugLog);
345
- if (!token) {
346
- debugLog({ event: "claudeai_integrations_skipped", reason: "no_oauth_token" });
347
- return [];
348
- }
349
- const controller = new AbortController();
350
- const timeout = setTimeout(() => controller.abort(), 1e4);
351
- try {
352
- const response = await fetch("https://api.anthropic.com/v1/mcp_servers?limit=1000", {
353
- headers: {
354
- Authorization: `Bearer ${token}`
355
- },
356
- signal: controller.signal
357
- });
358
- if (!response.ok) {
359
- debugLog({
360
- event: "claudeai_integrations_fetch_failed",
361
- status: response.status
362
- });
363
- return [];
364
- }
365
- const body = await response.json();
366
- const servers = parseClaudeAiServers(body);
367
- return servers.map((s) => ({
368
- name: s.name,
369
- type: "http",
370
- url: s.url,
371
- enabled: true,
372
- source: "claudeai",
373
- authStatus: "unknown"
374
- }));
375
- } finally {
376
- clearTimeout(timeout);
377
- }
378
- } catch (err) {
379
- debugLog({
380
- event: "claudeai_integrations_fetch_error",
381
- error: err instanceof Error ? err.message : String(err)
382
- });
383
- return [];
384
- }
385
- }
386
-
387
- // src/shared/capabilities/mcp-servers.ts
388
- var MCPStdioEntrySchema = external_exports.object({
389
- type: external_exports.literal("stdio").optional(),
390
- command: external_exports.string(),
391
- args: external_exports.array(external_exports.string()).optional(),
392
- env: external_exports.record(external_exports.string(), external_exports.string()).optional()
393
- }).passthrough();
394
- var MCPOAuthConfigSchema = external_exports.object({
395
- clientId: external_exports.string().optional(),
396
- callbackPort: external_exports.number().optional()
397
- }).passthrough();
398
- var MCPHttpEntrySchema = external_exports.object({
399
- type: external_exports.literal("http"),
400
- url: external_exports.string(),
401
- headers: external_exports.record(external_exports.string(), external_exports.string()).optional(),
402
- oauth: MCPOAuthConfigSchema.optional()
403
- }).passthrough();
404
- var MCPSSEEntrySchema = external_exports.object({
405
- type: external_exports.literal("sse"),
406
- url: external_exports.string(),
407
- headers: external_exports.record(external_exports.string(), external_exports.string()).optional()
408
- }).passthrough();
409
- var MCPServerEntrySchema = external_exports.union([MCPStdioEntrySchema, MCPHttpEntrySchema, MCPSSEEntrySchema]);
410
- function shouldFetchClaudeAiIntegrations(preferredAuth) {
411
- if (preferredAuth == null) return true;
412
- return preferredAuth === "claude-ai";
413
- }
414
- var SECRET_PATTERNS = /^(sk-|ghp_|gho_|glpat-|xoxb-|xoxp-|Bearer\s|token\s)/i;
415
- var SECRET_FLAGS = /* @__PURE__ */ new Set(["--api-key", "--token", "--secret", "--password", "--key", "-k"]);
416
- function redactArgs(args) {
417
- return args.map((arg, i) => {
418
- if (SECRET_PATTERNS.test(arg)) return "***";
419
- const prevArg = i > 0 ? args[i - 1] : void 0;
420
- if (prevArg && SECRET_FLAGS.has(prevArg)) return "***";
421
- const eqIdx = arg.indexOf("=");
422
- if (eqIdx > 0 && SECRET_FLAGS.has(arg.slice(0, eqIdx))) {
423
- return `${arg.slice(0, eqIdx + 1)}***`;
424
- }
425
- return arg;
426
- });
427
- }
428
- function redactEnv(env) {
429
- const result = {};
430
- for (const key of Object.keys(env)) {
431
- result[key] = "***";
432
- }
433
- return result;
434
- }
435
- function isHttpEntry(data) {
436
- return "type" in data && data.type === "http";
437
- }
438
- function isSSEEntry(data) {
439
- return "type" in data && data.type === "sse";
440
- }
441
- function entryToServerInfo(name, data, source) {
442
- if (isHttpEntry(data)) {
443
- return {
444
- name,
445
- type: "http",
446
- url: data.url,
447
- headers: data.headers,
448
- oauth: data.oauth,
449
- enabled: true,
450
- source,
451
- authStatus: "unknown"
452
- };
453
- }
454
- if (isSSEEntry(data)) {
455
- return {
456
- name,
457
- type: "sse",
458
- url: data.url,
459
- headers: data.headers,
460
- enabled: true,
461
- source,
462
- authStatus: "unknown"
463
- };
464
- }
465
- return {
466
- name,
467
- type: "stdio",
468
- command: data.command,
469
- args: data.args,
470
- env: data.env,
471
- enabled: true,
472
- source,
473
- authStatus: "unknown"
474
- };
475
- }
476
- async function readMCPConfig(filePath, source, log) {
477
- try {
478
- const raw = await readFile2(filePath, "utf-8");
479
- const json = JSON.parse(raw);
480
- const entries = typeof json.mcpServers === "object" && json.mcpServers !== null ? json.mcpServers : json;
481
- const servers = [];
482
- for (const [name, value] of Object.entries(entries)) {
483
- if (name === "mcpServers") continue;
484
- if (typeof value !== "object" || value === null || Array.isArray(value)) continue;
485
- const result = MCPServerEntrySchema.safeParse(value);
486
- if (!result.success) {
487
- const entry = {
488
- event: "mcp_config_entry_invalid",
489
- name,
490
- source,
491
- filePath,
492
- error: result.error.message
493
- };
494
- if (log) log(entry);
495
- else console.warn("[mcp-servers]", entry.event, entry.name, entry.error);
496
- continue;
497
- }
498
- servers.push(entryToServerInfo(name, result.data, source));
499
- }
500
- return servers;
501
- } catch {
502
- return [];
503
- }
504
- }
505
- async function readPluginMCPServers() {
506
- const servers = [];
507
- try {
508
- const settingsPath = join2(homedir2(), ".claude", "settings.json");
509
- const settingsRaw = await readFile2(settingsPath, "utf-8");
510
- const settings = JSON.parse(settingsRaw);
511
- if (!settings.enabledPlugins) return [];
512
- const installedPath = join2(homedir2(), ".claude", "plugins", "installed_plugins.json");
513
- const installedRaw = await readFile2(installedPath, "utf-8");
514
- const installed = JSON.parse(installedRaw);
515
- if (!installed.plugins) return [];
516
- for (const [pluginId, enabled] of Object.entries(settings.enabledPlugins)) {
517
- if (!enabled) continue;
518
- const installs = installed.plugins[pluginId];
519
- if (!installs || installs.length === 0) continue;
520
- const installPath = installs[0]?.installPath;
521
- if (!installPath) continue;
522
- const mcpJsonPath = join2(installPath, ".mcp.json");
523
- const pluginServers = await readMCPConfig(mcpJsonPath, "plugin");
524
- servers.push(...pluginServers);
525
- }
526
- } catch {
527
- }
528
- return servers;
529
- }
530
- var SOURCE_PRIORITY = [
531
- "claudeai",
532
- "plugin",
533
- "user",
534
- "project",
535
- "local",
536
- "mcp-json"
537
- ];
538
- async function resolveClaudeCodeAuthStatuses(servers) {
539
- for (const server of servers.values()) {
540
- if (server.authStatus !== "unknown") continue;
541
- if (server.type === "stdio") continue;
542
- const ccCreds = await readClaudeCodeCredentials(server.name, server.url ?? "");
543
- if (ccCreds?.accessToken && ccCreds.expiresAt && ccCreds.expiresAt > Date.now()) {
544
- server.authStatus = "authenticated";
545
- }
546
- }
547
- }
548
- function resolveStdioAuthStatus(server, tokens, tokenStore) {
549
- if (!server.env) return;
550
- for (const value of Object.values(server.env)) {
551
- const match = VAULT_REF_PATTERN.exec(value);
552
- if (!match) continue;
553
- const vaultKey = match[1] ?? "";
554
- const token = tokens[vaultKey];
555
- if (token) {
556
- server.authStatus = tokenStore.isExpired(token) ? "unauthenticated" : "authenticated";
557
- return;
558
- }
559
- }
560
- }
561
- async function resolveAuthStatuses(servers, tokenStore) {
562
- const tokens = await tokenStore.getAllTokens();
563
- for (const server of servers.values()) {
564
- if (server.type === "stdio") {
565
- resolveStdioAuthStatus(server, tokens, tokenStore);
566
- continue;
567
- }
568
- const token = tokens[server.name];
569
- if (token) {
570
- server.authStatus = tokenStore.isExpired(token) ? "unauthenticated" : "authenticated";
571
- }
572
- }
573
- await resolveClaudeCodeAuthStatuses(servers);
574
- }
575
- async function detectMCPServers(environments, tokenStore, log, lastKnown, preferredAuth) {
576
- try {
577
- return await detectMCPServersInner(environments, tokenStore, log, preferredAuth);
578
- } catch (err) {
579
- const { logger: logger2 } = await import("./logger-GQCSLSZH.js");
580
- if (lastKnown && lastKnown.length > 0) {
581
- logger2.warn(
582
- { err, lastKnownCount: lastKnown.length },
583
- "detectMCPServers threw \u2014 preserving lastKnown"
584
- );
585
- return lastKnown;
586
- }
587
- logger2.debug({ err }, "detectMCPServers threw with no lastKnown \u2014 returning []");
588
- return [];
589
- }
590
- }
591
- async function detectMCPServersInner(environments, tokenStore, log, preferredAuth) {
592
- const allServers = [];
593
- const userSettingsPath = join2(homedir2(), ".claude", "settings.json");
594
- const userLocalSettingsPath = join2(homedir2(), ".claude", "settings.local.json");
595
- const userMcpJsonPath = join2(homedir2(), ".mcp.json");
596
- const userClaudeJsonPath = join2(homedir2(), ".claude.json");
597
- const fetchClaudeAi = shouldFetchClaudeAiIntegrations(preferredAuth);
598
- const claudeAiPromise = fetchClaudeAi ? fetchClaudeAiIntegrations(log) : Promise.resolve([]);
599
- if (!fetchClaudeAi && log) {
600
- log({ event: "claudeai_integrations_skipped_by_method", method: preferredAuth ?? null });
601
- }
602
- const [
603
- userServers,
604
- userLocalServers,
605
- userMcpJsonServers,
606
- userClaudeJsonServers,
607
- pluginServers,
608
- claudeAiServers
609
- ] = await Promise.all([
610
- readMCPConfig(userSettingsPath, "user", log),
611
- readMCPConfig(userLocalSettingsPath, "user", log),
612
- readMCPConfig(userMcpJsonPath, "user", log),
613
- readMCPConfig(userClaudeJsonPath, "user", log),
614
- readPluginMCPServers(),
615
- claudeAiPromise
616
- ]);
617
- allServers.push(
618
- ...claudeAiServers,
619
- ...pluginServers,
620
- ...userServers,
621
- ...userLocalServers,
622
- ...userMcpJsonServers,
623
- ...userClaudeJsonServers
624
- );
625
- const envResults = await Promise.all(
626
- environments.map((env) => {
627
- const projectPath = join2(env.path, ".claude", "settings.json");
628
- const localPath = join2(env.path, ".claude", "settings.local.json");
629
- const mcpJsonPath = join2(env.path, ".mcp.json");
630
- return Promise.all([
631
- readMCPConfig(projectPath, "project", log),
632
- readMCPConfig(localPath, "local", log),
633
- readMCPConfig(mcpJsonPath, "mcp-json", log)
634
- ]);
635
- })
636
- );
637
- for (const [projectServers, localServers, mcpJsonServers] of envResults) {
638
- allServers.push(...projectServers, ...localServers, ...mcpJsonServers);
639
- }
640
- const deduped = /* @__PURE__ */ new Map();
641
- for (const server of allServers) {
642
- const existing = deduped.get(server.name);
643
- if (!existing || SOURCE_PRIORITY.indexOf(server.source) >= SOURCE_PRIORITY.indexOf(existing.source)) {
644
- deduped.set(server.name, server);
645
- }
646
- }
647
- if (tokenStore) {
648
- await resolveAuthStatuses(deduped, tokenStore);
649
- }
650
- return [...deduped.values()];
651
- }
652
-
653
- export {
654
- DiscoveryStateSchema,
655
- readPluginClientIds,
656
- readClaudeCodeCredentials,
657
- resolveStdioEnv,
658
- resolveEnabledMcpServers,
659
- readKeychainOAuthToken,
660
- readKeychainManagedKey,
661
- shouldFetchClaudeAiIntegrations,
662
- redactArgs,
663
- redactEnv,
664
- detectMCPServers
665
- };
666
- //# sourceMappingURL=chunk-L2WQMPWS.js.map