@mastra/code-sdk 1.0.3-alpha.0 → 1.1.0-alpha.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +49 -0
- package/dist/acp/agent.js +155 -167
- package/dist/acp/agent.js.map +1 -1
- package/dist/acp/event-mapper.js +193 -168
- package/dist/acp/event-mapper.js.map +1 -1
- package/dist/acp/index.js +60 -49
- package/dist/acp/index.js.map +1 -1
- package/dist/acp/server.js +31 -30
- package/dist/acp/server.js.map +1 -1
- package/dist/acp.js +1 -4
- package/dist/agents/credential-resolver.js +40 -29
- package/dist/agents/credential-resolver.js.map +1 -1
- package/dist/agents/custom-provider-source.js +16 -9
- package/dist/agents/custom-provider-source.js.map +1 -1
- package/dist/agents/instructions.js +27 -36
- package/dist/agents/instructions.js.map +1 -1
- package/dist/agents/mastracode-gateway.js +355 -428
- package/dist/agents/mastracode-gateway.js.map +1 -1
- package/dist/agents/memory.js +87 -78
- package/dist/agents/memory.js.map +1 -1
- package/dist/agents/model.js +114 -119
- package/dist/agents/model.js.map +1 -1
- package/dist/agents/modes/build.js +12 -13
- package/dist/agents/modes/build.js.map +1 -1
- package/dist/agents/modes/explore.js +14 -13
- package/dist/agents/modes/explore.js.map +1 -1
- package/dist/agents/modes/plan.js +14 -15
- package/dist/agents/modes/plan.js.map +1 -1
- package/dist/agents/prompts/agent-instructions.js +78 -69
- package/dist/agents/prompts/agent-instructions.js.map +1 -1
- package/dist/agents/prompts/build.js +19 -16
- package/dist/agents/prompts/build.js.map +1 -1
- package/dist/agents/prompts/fast.js +8 -4
- package/dist/agents/prompts/fast.js.map +1 -1
- package/dist/agents/prompts/index.js +48 -47
- package/dist/agents/prompts/index.js.map +1 -1
- package/dist/agents/prompts/model.js +6 -5
- package/dist/agents/prompts/model.js.map +1 -1
- package/dist/agents/prompts/plan.js +20 -16
- package/dist/agents/prompts/plan.js.map +1 -1
- package/dist/agents/prompts/tool-guidance.js +77 -109
- package/dist/agents/prompts/tool-guidance.js.map +1 -1
- package/dist/agents/sandbox-filesystem.js +245 -259
- package/dist/agents/sandbox-filesystem.js.map +1 -1
- package/dist/agents/sandbox-reattach.js +9 -11
- package/dist/agents/sandbox-reattach.js.map +1 -1
- package/dist/agents/thread-caveman-state.js +92 -81
- package/dist/agents/thread-caveman-state.js.map +1 -1
- package/dist/agents/tool-availability.js +62 -80
- package/dist/agents/tool-availability.js.map +1 -1
- package/dist/agents/tools.js +99 -139
- package/dist/agents/tools.js.map +1 -1
- package/dist/agents/workspace.js +232 -225
- package/dist/agents/workspace.js.map +1 -1
- package/dist/analytics.js +139 -128
- package/dist/analytics.js.map +1 -1
- package/dist/auth/authorization-input.js +39 -25
- package/dist/auth/authorization-input.js.map +1 -1
- package/dist/auth/device-code.js +112 -80
- package/dist/auth/device-code.js.map +1 -1
- package/dist/auth/index.js +2 -9
- package/dist/auth/pkce.js +27 -16
- package/dist/auth/pkce.js.map +1 -1
- package/dist/auth/providers/anthropic.js +107 -93
- package/dist/auth/providers/anthropic.js.map +1 -1
- package/dist/auth/providers/github-copilot.js +304 -293
- package/dist/auth/providers/github-copilot.js.map +1 -1
- package/dist/auth/providers/openai-codex.js +442 -460
- package/dist/auth/providers/openai-codex.js.map +1 -1
- package/dist/auth/providers/xai.js +179 -145
- package/dist/auth/providers/xai.js.map +1 -1
- package/dist/auth/storage.js +182 -175
- package/dist/auth/storage.js.map +1 -1
- package/dist/auth/types.js +1 -1
- package/dist/clipboard/index.js +206 -172
- package/dist/clipboard/index.js.map +1 -1
- package/dist/constants.js +11 -16
- package/dist/constants.js.map +1 -1
- package/dist/error-classification.js +19 -11
- package/dist/error-classification.js.map +1 -1
- package/dist/evals/context-builder.js +145 -104
- package/dist/evals/context-builder.js.map +1 -1
- package/dist/evals/index.js +4 -7
- package/dist/evals/scorers/classify-command.js +62 -41
- package/dist/evals/scorers/classify-command.js.map +1 -1
- package/dist/evals/scorers/efficiency.js +239 -181
- package/dist/evals/scorers/efficiency.js.map +1 -1
- package/dist/evals/scorers/extract-tools.js +51 -47
- package/dist/evals/scorers/extract-tools.js.map +1 -1
- package/dist/evals/scorers/index.js +1 -5
- package/dist/evals/scorers/outcome.js +321 -212
- package/dist/evals/scorers/outcome.js.map +1 -1
- package/dist/goal-manager.js +266 -261
- package/dist/goal-manager.js.map +1 -1
- package/dist/goal-signal.js +14 -13
- package/dist/goal-signal.js.map +1 -1
- package/dist/headless/cli.js +153 -154
- package/dist/headless/cli.js.map +1 -1
- package/dist/headless/flags.js +180 -178
- package/dist/headless/flags.js.map +1 -1
- package/dist/headless/format.js +72 -71
- package/dist/headless/format.js.map +1 -1
- package/dist/headless/index.js +5 -31
- package/dist/headless/policy.js +35 -31
- package/dist/headless/policy.js.map +1 -1
- package/dist/headless/run-mc.js +332 -334
- package/dist/headless/run-mc.js.map +1 -1
- package/dist/headless/types.js +16 -7
- package/dist/headless/types.js.map +1 -1
- package/dist/hooks/config.js +56 -61
- package/dist/hooks/config.js.map +1 -1
- package/dist/hooks/executor.js +118 -116
- package/dist/hooks/executor.js.map +1 -1
- package/dist/hooks/index.js +4 -15
- package/dist/hooks/manager.js +221 -280
- package/dist/hooks/manager.js.map +1 -1
- package/dist/hooks/types.js +5 -4
- package/dist/hooks/types.js.map +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +632 -712
- package/dist/index.js.map +1 -1
- package/dist/ipc/ipc-reporter.js +19 -22
- package/dist/ipc/ipc-reporter.js.map +1 -1
- package/dist/lsp/client.js +248 -306
- package/dist/lsp/client.js.map +1 -1
- package/dist/lsp/index.js +1 -6
- package/dist/lsp/language.js +39 -43
- package/dist/lsp/language.js.map +1 -1
- package/dist/lsp/manager.js +78 -93
- package/dist/lsp/manager.js.map +1 -1
- package/dist/lsp/server.js +151 -120
- package/dist/lsp/server.js.map +1 -1
- package/dist/lsp/workspace.js +50 -47
- package/dist/lsp/workspace.js.map +1 -1
- package/dist/mcp/config.js +210 -199
- package/dist/mcp/config.js.map +1 -1
- package/dist/mcp/index.js +2 -9
- package/dist/mcp/manager.js +482 -475
- package/dist/mcp/manager.js.map +1 -1
- package/dist/mcp/types.js +1 -1
- package/dist/onboarding/custom-packs.js +14 -17
- package/dist/onboarding/custom-packs.js.map +1 -1
- package/dist/onboarding/custom-providers.js +22 -20
- package/dist/onboarding/custom-providers.js.map +1 -1
- package/dist/onboarding/index.d.ts +1 -1
- package/dist/onboarding/index.d.ts.map +1 -1
- package/dist/onboarding/index.js +3 -21
- package/dist/onboarding/om-settings.d.ts +5 -0
- package/dist/onboarding/om-settings.d.ts.map +1 -1
- package/dist/onboarding/om-settings.js +41 -20
- package/dist/onboarding/om-settings.js.map +1 -1
- package/dist/onboarding/packs.d.ts +4 -6
- package/dist/onboarding/packs.d.ts.map +1 -1
- package/dist/onboarding/packs.js +154 -105
- package/dist/onboarding/packs.js.map +1 -1
- package/dist/onboarding/settings.js +575 -517
- package/dist/onboarding/settings.js.map +1 -1
- package/dist/permissions.js +112 -99
- package/dist/permissions.js.map +1 -1
- package/dist/plugin.js +21 -23
- package/dist/plugin.js.map +1 -1
- package/dist/plugins/dependencies.js +64 -87
- package/dist/plugins/dependencies.js.map +1 -1
- package/dist/plugins/install.js +159 -169
- package/dist/plugins/install.js.map +1 -1
- package/dist/plugins/loader.js +170 -185
- package/dist/plugins/loader.js.map +1 -1
- package/dist/plugins/manager.js +374 -380
- package/dist/plugins/manager.js.map +1 -1
- package/dist/plugins/manifest.js +38 -63
- package/dist/plugins/manifest.js.map +1 -1
- package/dist/plugins/package-link.js +48 -64
- package/dist/plugins/package-link.js.map +1 -1
- package/dist/plugins/paths.js +18 -19
- package/dist/plugins/paths.js.map +1 -1
- package/dist/plugins/registry.js +97 -81
- package/dist/plugins/registry.js.map +1 -1
- package/dist/plugins/scaffold.js +62 -98
- package/dist/plugins/scaffold.js.map +1 -1
- package/dist/plugins/types.js +1 -1
- package/dist/processors/plan-rejection-abort.js +45 -44
- package/dist/processors/plan-rejection-abort.js.map +1 -1
- package/dist/providers/amazon-bedrock-gateway.js +134 -125
- package/dist/providers/amazon-bedrock-gateway.js.map +1 -1
- package/dist/providers/amazon-bedrock.js +68 -47
- package/dist/providers/amazon-bedrock.js.map +1 -1
- package/dist/providers/claude-max.js +153 -133
- package/dist/providers/claude-max.js.map +1 -1
- package/dist/providers/github-copilot.js +232 -230
- package/dist/providers/github-copilot.js.map +1 -1
- package/dist/providers/openai-codex.js +271 -260
- package/dist/providers/openai-codex.js.map +1 -1
- package/dist/providers/xai.js +57 -50
- package/dist/providers/xai.js.map +1 -1
- package/dist/schema.js +91 -89
- package/dist/schema.js.map +1 -1
- package/dist/theme-palette.js +18 -14
- package/dist/theme-palette.js.map +1 -1
- package/dist/tool-names.js +46 -37
- package/dist/tool-names.js.map +1 -1
- package/dist/tools/index.js +2 -8
- package/dist/tools/request-sandbox-access.js +71 -80
- package/dist/tools/request-sandbox-access.js.map +1 -1
- package/dist/tools/utils.js +26 -16
- package/dist/tools/utils.js.map +1 -1
- package/dist/tools/web-search.js +51 -55
- package/dist/tools/web-search.js.map +1 -1
- package/dist/utils/binaries.js +65 -61
- package/dist/utils/binaries.js.map +1 -1
- package/dist/utils/debug-log.js +51 -47
- package/dist/utils/debug-log.js.map +1 -1
- package/dist/utils/errors.js +157 -192
- package/dist/utils/errors.js.map +1 -1
- package/dist/utils/gateway-sync.js +49 -37
- package/dist/utils/gateway-sync.js.map +1 -1
- package/dist/utils/path-security.js +7 -6
- package/dist/utils/path-security.js.map +1 -1
- package/dist/utils/plan-diff.js +58 -39
- package/dist/utils/plan-diff.js.map +1 -1
- package/dist/utils/plans.js +92 -74
- package/dist/utils/plans.js.map +1 -1
- package/dist/utils/project.js +318 -256
- package/dist/utils/project.js.map +1 -1
- package/dist/utils/signals-pubsub.js +117 -99
- package/dist/utils/signals-pubsub.js.map +1 -1
- package/dist/utils/slash-command-loader.js +118 -154
- package/dist/utils/slash-command-loader.js.map +1 -1
- package/dist/utils/slash-command-processor.js +92 -83
- package/dist/utils/slash-command-processor.js.map +1 -1
- package/dist/utils/stdin-pipe.js +87 -63
- package/dist/utils/stdin-pipe.js.map +1 -1
- package/dist/utils/storage-factory.js +104 -84
- package/dist/utils/storage-factory.js.map +1 -1
- package/dist/utils/storage-maintenance.js +249 -211
- package/dist/utils/storage-maintenance.js.map +1 -1
- package/dist/utils/thread-lock.js +96 -92
- package/dist/utils/thread-lock.js.map +1 -1
- package/dist/utils/token-estimator.js +12 -12
- package/dist/utils/token-estimator.js.map +1 -1
- package/dist/utils/update-check.d.ts +1 -1
- package/dist/utils/update-check.js +341 -259
- package/dist/utils/update-check.js.map +1 -1
- package/dist/voice/stt-registry.js +131 -113
- package/dist/voice/stt-registry.js.map +1 -1
- package/package.json +11 -11
- package/dist/acp.js.map +0 -1
- package/dist/auth/index.js.map +0 -1
- package/dist/auth/types.js.map +0 -1
- package/dist/evals/index.js.map +0 -1
- package/dist/evals/scorers/index.js.map +0 -1
- package/dist/headless/index.js.map +0 -1
- package/dist/hooks/index.js.map +0 -1
- package/dist/lsp/index.js.map +0 -1
- package/dist/mcp/index.js.map +0 -1
- package/dist/mcp/types.js.map +0 -1
- package/dist/onboarding/index.js.map +0 -1
- package/dist/plugins/types.js.map +0 -1
- package/dist/tools/index.js.map +0 -1
package/dist/lsp/server.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/lsp/server.ts"],"sourcesContent":["import type { ChildProcess } from 'node:child_process';\nimport { spawn } from 'node:child_process';\nimport { existsSync } from 'node:fs';\nimport { createRequire } from 'node:module';\nimport path, { join } from 'node:path';\nimport { pathToFileURL } from 'node:url';\nimport { getLanguageId } from './language.js';\n\n/**\n * LSP Server definition and spawning logic\n */\nexport interface LSPServerInfo {\n id: string;\n name: string;\n languageIds: string[];\n root: (cwd: string) => string | null;\n spawn: (root: string) => ChildProcess | Promise<{ process: ChildProcess; initialization?: any } | undefined>;\n}\n\n/**\n * Find the nearest project root directory\n */\nexport function findNearestRoot(cwd: string, markers: string[]): string | null {\n let current = cwd;\n\n while (current !== '/') {\n for (const marker of markers) {\n if (existsSync(join(current, marker))) {\n return current;\n }\n }\n\n const parent = join(current, '..');\n if (parent === current) break;\n current = parent;\n }\n\n return null;\n}\n\n/**\n * Built-in LSP server definitions\n */\nexport const BUILTIN_SERVERS: Record<string, LSPServerInfo> = {\n typescript: {\n id: 'typescript',\n name: 'TypeScript Language Server',\n languageIds: ['typescript', 'typescriptreact', 'javascript', 'javascriptreact'],\n root: (cwd: string) => findNearestRoot(cwd, ['tsconfig.json', 'package.json']),\n spawn: async (root: string) => {\n // Try to resolve TypeScript from the project directory\n const requireFromRoot = createRequire(pathToFileURL(path.join(root, 'package.json')));\n let tsserver: string | undefined;\n try {\n tsserver = requireFromRoot.resolve('typescript/lib/tsserver.js');\n } catch {\n tsserver = undefined;\n }\n if (!tsserver) {\n return undefined;\n }\n\n // Resolve typescript-language-server binary directly to avoid npx hangs\n // (npx can hang indefinitely in projects with pnpm links)\n const localBin = join(root, 'node_modules', '.bin', 'typescript-language-server');\n const cwdBin = join(process.cwd(), 'node_modules', '.bin', 'typescript-language-server');\n let tslsBinary: string;\n if (existsSync(localBin)) {\n tslsBinary = localBin;\n } else if (existsSync(cwdBin)) {\n tslsBinary = cwdBin;\n } else {\n // Fall back to npx as last resort, but this may hang with pnpm links\n tslsBinary = 'npx';\n }\n\n const args = tslsBinary === 'npx' ? ['typescript-language-server', '--stdio'] : ['--stdio'];\n\n const proc = spawn(tslsBinary, args, {\n cwd: root,\n stdio: ['pipe', 'pipe', 'pipe'],\n });\n\n return {\n process: proc,\n initialization: {\n tsserver: {\n path: tsserver,\n logVerbosity: 'off',\n },\n },\n };\n },\n },\n\n eslint: {\n id: 'eslint',\n name: 'ESLint Language Server',\n languageIds: ['typescript', 'typescriptreact', 'javascript', 'javascriptreact'],\n root: (cwd: string) =>\n findNearestRoot(cwd, ['package.json', '.eslintrc.js', '.eslintrc.json', '.eslintrc.yml', '.eslintrc.yaml']),\n spawn: (root: string) => {\n const binaryPath = join(process.cwd(), 'node_modules', '.bin', 'eslint-lsp');\n return spawn(binaryPath, ['--stdio'], {\n cwd: root,\n stdio: ['pipe', 'pipe', 'pipe'],\n });\n },\n },\n\n python: {\n id: 'python',\n name: 'Python Language Server (Pyright)',\n languageIds: ['python'],\n root: (cwd: string) => findNearestRoot(cwd, ['pyproject.toml', 'setup.py', 'requirements.txt', '.git']),\n spawn: (root: string) => {\n // Try node_modules first, then fall back to system PATH\n const localPath = join(process.cwd(), 'node_modules', '.bin', 'pyright-langserver');\n const binaryPath = existsSync(localPath) ? localPath : 'pyright-langserver';\n return spawn(binaryPath, ['--stdio'], {\n cwd: root,\n stdio: ['pipe', 'pipe', 'pipe'],\n });\n },\n },\n\n go: {\n id: 'go',\n name: 'Go Language Server (gopls)',\n languageIds: ['go'],\n root: (cwd: string) => findNearestRoot(cwd, ['go.mod', '.git']),\n spawn: (root: string) => {\n return spawn('gopls', ['serve'], {\n cwd: root,\n stdio: ['pipe', 'pipe', 'pipe'],\n });\n },\n },\n\n rust: {\n id: 'rust',\n name: 'Rust Language Server (rust-analyzer)',\n languageIds: ['rust'],\n root: (cwd: string) => findNearestRoot(cwd, ['Cargo.toml', '.git']),\n spawn: (root: string) => {\n return spawn('rust-analyzer', ['--stdio'], {\n cwd: root,\n stdio: ['pipe', 'pipe', 'pipe'],\n });\n },\n },\n};\n\n/**\n * Get all servers that can handle a file\n */\nexport function getServersForFile(filePath: string, cwd: string): LSPServerInfo[] {\n const languageId = getLanguageId(filePath);\n if (!languageId) return [];\n\n return Object.values(BUILTIN_SERVERS).filter(\n server => server.languageIds.includes(languageId) && server.root(cwd) !== null,\n );\n}\n"],"mappings":"
|
|
1
|
+
{"version":3,"file":"server.js","names":[],"sources":["../../src/lsp/server.ts"],"sourcesContent":["import type { ChildProcess } from 'node:child_process';\nimport { spawn } from 'node:child_process';\nimport { existsSync } from 'node:fs';\nimport { createRequire } from 'node:module';\nimport path, { join } from 'node:path';\nimport { pathToFileURL } from 'node:url';\nimport { getLanguageId } from './language.js';\n\n/**\n * LSP Server definition and spawning logic\n */\nexport interface LSPServerInfo {\n id: string;\n name: string;\n languageIds: string[];\n root: (cwd: string) => string | null;\n spawn: (root: string) => ChildProcess | Promise<{ process: ChildProcess; initialization?: any } | undefined>;\n}\n\n/**\n * Find the nearest project root directory\n */\nexport function findNearestRoot(cwd: string, markers: string[]): string | null {\n let current = cwd;\n\n while (current !== '/') {\n for (const marker of markers) {\n if (existsSync(join(current, marker))) {\n return current;\n }\n }\n\n const parent = join(current, '..');\n if (parent === current) break;\n current = parent;\n }\n\n return null;\n}\n\n/**\n * Built-in LSP server definitions\n */\nexport const BUILTIN_SERVERS: Record<string, LSPServerInfo> = {\n typescript: {\n id: 'typescript',\n name: 'TypeScript Language Server',\n languageIds: ['typescript', 'typescriptreact', 'javascript', 'javascriptreact'],\n root: (cwd: string) => findNearestRoot(cwd, ['tsconfig.json', 'package.json']),\n spawn: async (root: string) => {\n // Try to resolve TypeScript from the project directory\n const requireFromRoot = createRequire(pathToFileURL(path.join(root, 'package.json')));\n let tsserver: string | undefined;\n try {\n tsserver = requireFromRoot.resolve('typescript/lib/tsserver.js');\n } catch {\n tsserver = undefined;\n }\n if (!tsserver) {\n return undefined;\n }\n\n // Resolve typescript-language-server binary directly to avoid npx hangs\n // (npx can hang indefinitely in projects with pnpm links)\n const localBin = join(root, 'node_modules', '.bin', 'typescript-language-server');\n const cwdBin = join(process.cwd(), 'node_modules', '.bin', 'typescript-language-server');\n let tslsBinary: string;\n if (existsSync(localBin)) {\n tslsBinary = localBin;\n } else if (existsSync(cwdBin)) {\n tslsBinary = cwdBin;\n } else {\n // Fall back to npx as last resort, but this may hang with pnpm links\n tslsBinary = 'npx';\n }\n\n const args = tslsBinary === 'npx' ? ['typescript-language-server', '--stdio'] : ['--stdio'];\n\n const proc = spawn(tslsBinary, args, {\n cwd: root,\n stdio: ['pipe', 'pipe', 'pipe'],\n });\n\n return {\n process: proc,\n initialization: {\n tsserver: {\n path: tsserver,\n logVerbosity: 'off',\n },\n },\n };\n },\n },\n\n eslint: {\n id: 'eslint',\n name: 'ESLint Language Server',\n languageIds: ['typescript', 'typescriptreact', 'javascript', 'javascriptreact'],\n root: (cwd: string) =>\n findNearestRoot(cwd, ['package.json', '.eslintrc.js', '.eslintrc.json', '.eslintrc.yml', '.eslintrc.yaml']),\n spawn: (root: string) => {\n const binaryPath = join(process.cwd(), 'node_modules', '.bin', 'eslint-lsp');\n return spawn(binaryPath, ['--stdio'], {\n cwd: root,\n stdio: ['pipe', 'pipe', 'pipe'],\n });\n },\n },\n\n python: {\n id: 'python',\n name: 'Python Language Server (Pyright)',\n languageIds: ['python'],\n root: (cwd: string) => findNearestRoot(cwd, ['pyproject.toml', 'setup.py', 'requirements.txt', '.git']),\n spawn: (root: string) => {\n // Try node_modules first, then fall back to system PATH\n const localPath = join(process.cwd(), 'node_modules', '.bin', 'pyright-langserver');\n const binaryPath = existsSync(localPath) ? localPath : 'pyright-langserver';\n return spawn(binaryPath, ['--stdio'], {\n cwd: root,\n stdio: ['pipe', 'pipe', 'pipe'],\n });\n },\n },\n\n go: {\n id: 'go',\n name: 'Go Language Server (gopls)',\n languageIds: ['go'],\n root: (cwd: string) => findNearestRoot(cwd, ['go.mod', '.git']),\n spawn: (root: string) => {\n return spawn('gopls', ['serve'], {\n cwd: root,\n stdio: ['pipe', 'pipe', 'pipe'],\n });\n },\n },\n\n rust: {\n id: 'rust',\n name: 'Rust Language Server (rust-analyzer)',\n languageIds: ['rust'],\n root: (cwd: string) => findNearestRoot(cwd, ['Cargo.toml', '.git']),\n spawn: (root: string) => {\n return spawn('rust-analyzer', ['--stdio'], {\n cwd: root,\n stdio: ['pipe', 'pipe', 'pipe'],\n });\n },\n },\n};\n\n/**\n * Get all servers that can handle a file\n */\nexport function getServersForFile(filePath: string, cwd: string): LSPServerInfo[] {\n const languageId = getLanguageId(filePath);\n if (!languageId) return [];\n\n return Object.values(BUILTIN_SERVERS).filter(\n server => server.languageIds.includes(languageId) && server.root(cwd) !== null,\n );\n}\n"],"mappings":"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"}
|
package/dist/lsp/workspace.js
CHANGED
|
@@ -1,52 +1,55 @@
|
|
|
1
|
-
import * as fs from "
|
|
2
|
-
import * as path from "
|
|
1
|
+
import * as fs$1 from "fs";
|
|
2
|
+
import * as path$1 from "path";
|
|
3
|
+
//#region src/lsp/workspace.ts
|
|
4
|
+
/**
|
|
5
|
+
* Workspace markers that indicate the root of a project
|
|
6
|
+
*/
|
|
3
7
|
const WORKSPACE_MARKERS = [
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
8
|
+
"package.json",
|
|
9
|
+
"tsconfig.json",
|
|
10
|
+
"pyproject.toml",
|
|
11
|
+
"go.mod",
|
|
12
|
+
".git",
|
|
13
|
+
"Cargo.toml",
|
|
14
|
+
"composer.json"
|
|
11
15
|
];
|
|
16
|
+
/**
|
|
17
|
+
* Find the workspace root by walking up from the file path
|
|
18
|
+
* looking for common workspace markers.
|
|
19
|
+
*
|
|
20
|
+
* For monorepos, this prioritizes the closest package/project root
|
|
21
|
+
* (e.g., packages/core) over the monorepo root.
|
|
22
|
+
*/
|
|
12
23
|
function findWorkspaceRoot(filePath) {
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
}
|
|
41
|
-
const parentDir = path.dirname(currentDir);
|
|
42
|
-
if (parentDir === currentDir) {
|
|
43
|
-
break;
|
|
44
|
-
}
|
|
45
|
-
currentDir = parentDir;
|
|
46
|
-
}
|
|
47
|
-
return path.dirname(path.resolve(filePath));
|
|
24
|
+
let currentDir = path$1.dirname(path$1.resolve(filePath));
|
|
25
|
+
const root = path$1.parse(currentDir).root;
|
|
26
|
+
let closestProjectRoot = null;
|
|
27
|
+
let searchDir = currentDir;
|
|
28
|
+
while (searchDir !== root) {
|
|
29
|
+
const hasTsConfig = fs$1.existsSync(path$1.join(searchDir, "tsconfig.json"));
|
|
30
|
+
const hasPackageJson = fs$1.existsSync(path$1.join(searchDir, "package.json"));
|
|
31
|
+
if (hasTsConfig || hasPackageJson) {
|
|
32
|
+
closestProjectRoot = searchDir;
|
|
33
|
+
break;
|
|
34
|
+
}
|
|
35
|
+
const parentDir = path$1.dirname(searchDir);
|
|
36
|
+
if (parentDir === searchDir) break;
|
|
37
|
+
searchDir = parentDir;
|
|
38
|
+
}
|
|
39
|
+
if (closestProjectRoot) return closestProjectRoot;
|
|
40
|
+
currentDir = path$1.dirname(path$1.resolve(filePath));
|
|
41
|
+
while (currentDir !== root) {
|
|
42
|
+
for (const marker of WORKSPACE_MARKERS) {
|
|
43
|
+
const markerPath = path$1.join(currentDir, marker);
|
|
44
|
+
if (fs$1.existsSync(markerPath)) return currentDir;
|
|
45
|
+
}
|
|
46
|
+
const parentDir = path$1.dirname(currentDir);
|
|
47
|
+
if (parentDir === currentDir) break;
|
|
48
|
+
currentDir = parentDir;
|
|
49
|
+
}
|
|
50
|
+
return path$1.dirname(path$1.resolve(filePath));
|
|
48
51
|
}
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
+
//#endregion
|
|
53
|
+
export { findWorkspaceRoot };
|
|
54
|
+
|
|
52
55
|
//# sourceMappingURL=workspace.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/lsp/workspace.ts"],"sourcesContent":["import * as fs from 'node:fs';\nimport * as path from 'node:path';\n\n/**\n * Workspace markers that indicate the root of a project\n */\nconst WORKSPACE_MARKERS = [\n 'package.json',\n 'tsconfig.json',\n 'pyproject.toml',\n 'go.mod',\n '.git',\n 'Cargo.toml',\n 'composer.json',\n];\n\n/**\n * Find the workspace root by walking up from the file path\n * looking for common workspace markers.\n *\n * For monorepos, this prioritizes the closest package/project root\n * (e.g., packages/core) over the monorepo root.\n */\nexport function findWorkspaceRoot(filePath: string): string {\n let currentDir = path.dirname(path.resolve(filePath));\n const root = path.parse(currentDir).root;\n\n // First, find the closest tsconfig.json or package.json\n // This handles monorepos where the actual project is in a subdirectory\n let closestProjectRoot: string | null = null;\n let searchDir = currentDir;\n\n while (searchDir !== root) {\n const hasTsConfig = fs.existsSync(path.join(searchDir, 'tsconfig.json'));\n const hasPackageJson = fs.existsSync(path.join(searchDir, 'package.json'));\n\n if (hasTsConfig || hasPackageJson) {\n closestProjectRoot = searchDir;\n break;\n }\n\n const parentDir = path.dirname(searchDir);\n if (parentDir === searchDir) {\n break;\n }\n searchDir = parentDir;\n }\n\n // If we found a project root, return it\n if (closestProjectRoot) {\n return closestProjectRoot;\n }\n\n // Otherwise, fall back to looking for any workspace marker\n currentDir = path.dirname(path.resolve(filePath));\n while (currentDir !== root) {\n for (const marker of WORKSPACE_MARKERS) {\n const markerPath = path.join(currentDir, marker);\n if (fs.existsSync(markerPath)) {\n return currentDir;\n }\n }\n\n const parentDir = path.dirname(currentDir);\n if (parentDir === currentDir) {\n break;\n }\n currentDir = parentDir;\n }\n\n // Fallback to the directory containing the file\n return path.dirname(path.resolve(filePath));\n}\n"],"mappings":"
|
|
1
|
+
{"version":3,"file":"workspace.js","names":["path","fs"],"sources":["../../src/lsp/workspace.ts"],"sourcesContent":["import * as fs from 'node:fs';\nimport * as path from 'node:path';\n\n/**\n * Workspace markers that indicate the root of a project\n */\nconst WORKSPACE_MARKERS = [\n 'package.json',\n 'tsconfig.json',\n 'pyproject.toml',\n 'go.mod',\n '.git',\n 'Cargo.toml',\n 'composer.json',\n];\n\n/**\n * Find the workspace root by walking up from the file path\n * looking for common workspace markers.\n *\n * For monorepos, this prioritizes the closest package/project root\n * (e.g., packages/core) over the monorepo root.\n */\nexport function findWorkspaceRoot(filePath: string): string {\n let currentDir = path.dirname(path.resolve(filePath));\n const root = path.parse(currentDir).root;\n\n // First, find the closest tsconfig.json or package.json\n // This handles monorepos where the actual project is in a subdirectory\n let closestProjectRoot: string | null = null;\n let searchDir = currentDir;\n\n while (searchDir !== root) {\n const hasTsConfig = fs.existsSync(path.join(searchDir, 'tsconfig.json'));\n const hasPackageJson = fs.existsSync(path.join(searchDir, 'package.json'));\n\n if (hasTsConfig || hasPackageJson) {\n closestProjectRoot = searchDir;\n break;\n }\n\n const parentDir = path.dirname(searchDir);\n if (parentDir === searchDir) {\n break;\n }\n searchDir = parentDir;\n }\n\n // If we found a project root, return it\n if (closestProjectRoot) {\n return closestProjectRoot;\n }\n\n // Otherwise, fall back to looking for any workspace marker\n currentDir = path.dirname(path.resolve(filePath));\n while (currentDir !== root) {\n for (const marker of WORKSPACE_MARKERS) {\n const markerPath = path.join(currentDir, marker);\n if (fs.existsSync(markerPath)) {\n return currentDir;\n }\n }\n\n const parentDir = path.dirname(currentDir);\n if (parentDir === currentDir) {\n break;\n }\n currentDir = parentDir;\n }\n\n // Fallback to the directory containing the file\n return path.dirname(path.resolve(filePath));\n}\n"],"mappings":";;;;;;AAMA,MAAM,oBAAoB;CACxB;CACA;CACA;CACA;CACA;CACA;CACA;AACF;;;;;;;;AASA,SAAgB,kBAAkB,UAA0B;CAC1D,IAAI,aAAaA,OAAK,QAAQA,OAAK,QAAQ,QAAQ,CAAC;CACpD,MAAM,OAAOA,OAAK,MAAM,UAAU,CAAC,CAAC;CAIpC,IAAI,qBAAoC;CACxC,IAAI,YAAY;CAEhB,OAAO,cAAc,MAAM;EACzB,MAAM,cAAcC,KAAG,WAAWD,OAAK,KAAK,WAAW,eAAe,CAAC;EACvE,MAAM,iBAAiBC,KAAG,WAAWD,OAAK,KAAK,WAAW,cAAc,CAAC;EAEzE,IAAI,eAAe,gBAAgB;GACjC,qBAAqB;GACrB;EACF;EAEA,MAAM,YAAYA,OAAK,QAAQ,SAAS;EACxC,IAAI,cAAc,WAChB;EAEF,YAAY;CACd;CAGA,IAAI,oBACF,OAAO;CAIT,aAAaA,OAAK,QAAQA,OAAK,QAAQ,QAAQ,CAAC;CAChD,OAAO,eAAe,MAAM;EAC1B,KAAK,MAAM,UAAU,mBAAmB;GACtC,MAAM,aAAaA,OAAK,KAAK,YAAY,MAAM;GAC/C,IAAIC,KAAG,WAAW,UAAU,GAC1B,OAAO;EAEX;EAEA,MAAM,YAAYD,OAAK,QAAQ,UAAU;EACzC,IAAI,cAAc,YAChB;EAEF,aAAa;CACf;CAGA,OAAOA,OAAK,QAAQA,OAAK,QAAQ,QAAQ,CAAC;AAC5C"}
|
package/dist/mcp/config.js
CHANGED
|
@@ -1,229 +1,240 @@
|
|
|
1
|
-
import * as fs from "node:fs";
|
|
2
|
-
import * as os from "node:os";
|
|
3
|
-
import * as path from "node:path";
|
|
4
1
|
import { DEFAULT_CONFIG_DIR } from "../constants.js";
|
|
2
|
+
import * as fs$1 from "fs";
|
|
3
|
+
import * as os$1 from "os";
|
|
4
|
+
import * as path$1 from "path";
|
|
5
|
+
//#region src/mcp/config.ts
|
|
6
|
+
/**
|
|
7
|
+
* MCP server configuration loading from filesystem.
|
|
8
|
+
* Loads from:
|
|
9
|
+
* 1. .claude/settings.local.json (Claude Code compat — lowest priority)
|
|
10
|
+
* 2. ~/.mastracode/mcp.json (global)
|
|
11
|
+
* 3. .mcp.json (project root — Claude Code compatible)
|
|
12
|
+
* 4. .mastracode/mcp.json (project — highest priority)
|
|
13
|
+
*
|
|
14
|
+
* Higher-priority configs override lower ones by server name. The project root
|
|
15
|
+
* `.mcp.json` is read so a project that already keeps MCP servers there for
|
|
16
|
+
* Claude Code does not need to duplicate them under `.mastracode/`.
|
|
17
|
+
*/
|
|
18
|
+
/**
|
|
19
|
+
* Default OAuth redirect URL for servers that do not configure one.
|
|
20
|
+
* Port 1458 is stable across sessions so persisted tokens keep the same
|
|
21
|
+
* storage fingerprint; it sits clear of the ports the Codex login flow
|
|
22
|
+
* reserves (1455/1457). When 1458 is busy the callback server falls back
|
|
23
|
+
* to the next sequential port, which stays covered by the client
|
|
24
|
+
* registration (see `@mastra/mcp`'s `getCallbackUrlCandidates`).
|
|
25
|
+
*/
|
|
5
26
|
const DEFAULT_OAUTH_REDIRECT_URL = "http://127.0.0.1:1458/oauth/callback";
|
|
6
27
|
const LOOPBACK_IPV4 = /^127\.(?:\d{1,3})\.(?:\d{1,3})\.(?:\d{1,3})$/;
|
|
7
28
|
function isLoopbackHostname(hostname) {
|
|
8
|
-
|
|
9
|
-
}
|
|
29
|
+
return hostname === "localhost" || hostname === "[::1]" || hostname === "::1" || LOOPBACK_IPV4.test(hostname);
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* Resolve the effective OAuth redirect URL for a server config.
|
|
33
|
+
*
|
|
34
|
+
* `callbackPort` (the Claude Code / Codex convention) takes precedence and
|
|
35
|
+
* synthesizes `http://localhost:<port>/callback`. Config-file entries are
|
|
36
|
+
* normalized by `parseOAuthConfig` (which also enforces that `callbackPort`
|
|
37
|
+
* and `redirectUrl` are mutually exclusive), but programmatically registered
|
|
38
|
+
* servers bypass the parser, so every consumer of the redirect URL must
|
|
39
|
+
* resolve it through this helper rather than reading `redirectUrl` directly.
|
|
40
|
+
*/
|
|
10
41
|
function resolveOAuthRedirectUrl(oauth) {
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
}
|
|
14
|
-
return oauth?.redirectUrl ?? DEFAULT_OAUTH_REDIRECT_URL;
|
|
42
|
+
if (oauth?.callbackPort !== void 0) return `http://localhost:${oauth.callbackPort}/callback`;
|
|
43
|
+
return oauth?.redirectUrl ?? "http://127.0.0.1:1458/oauth/callback";
|
|
15
44
|
}
|
|
16
45
|
function loadMcpConfig(projectDir, configDirName = DEFAULT_CONFIG_DIR) {
|
|
17
|
-
|
|
18
|
-
const globalConfig = loadSingleConfig(getGlobalMcpPath(configDirName));
|
|
19
|
-
const rootConfig = loadSingleConfig(getRootMcpPath(projectDir));
|
|
20
|
-
const projectConfig = loadSingleConfig(getProjectMcpPath(projectDir, configDirName));
|
|
21
|
-
return mergeConfigs(claudeConfig, globalConfig, rootConfig, projectConfig);
|
|
46
|
+
return mergeConfigs(loadClaudeSettings(projectDir), loadSingleConfig(getGlobalMcpPath(configDirName)), loadSingleConfig(getRootMcpPath(projectDir)), loadSingleConfig(getProjectMcpPath(projectDir, configDirName)));
|
|
22
47
|
}
|
|
23
48
|
function getProjectMcpPath(projectDir, configDirName = DEFAULT_CONFIG_DIR) {
|
|
24
|
-
|
|
49
|
+
return path$1.join(projectDir, configDirName, "mcp.json");
|
|
25
50
|
}
|
|
26
51
|
function getRootMcpPath(projectDir) {
|
|
27
|
-
|
|
52
|
+
return path$1.join(projectDir, ".mcp.json");
|
|
28
53
|
}
|
|
29
54
|
function getGlobalMcpPath(configDirName = DEFAULT_CONFIG_DIR) {
|
|
30
|
-
|
|
55
|
+
return path$1.join(os$1.homedir(), configDirName, "mcp.json");
|
|
31
56
|
}
|
|
32
57
|
function getClaudeSettingsPath(projectDir) {
|
|
33
|
-
|
|
58
|
+
return path$1.join(projectDir, ".claude", "settings.local.json");
|
|
34
59
|
}
|
|
35
60
|
function loadSingleConfig(filePath) {
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
61
|
+
try {
|
|
62
|
+
if (!fs$1.existsSync(filePath)) return {};
|
|
63
|
+
const raw = fs$1.readFileSync(filePath, "utf-8");
|
|
64
|
+
return validateConfig(JSON.parse(raw));
|
|
65
|
+
} catch {
|
|
66
|
+
return {};
|
|
67
|
+
}
|
|
43
68
|
}
|
|
44
69
|
function loadClaudeSettings(projectDir) {
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
}
|
|
70
|
+
try {
|
|
71
|
+
const filePath = getClaudeSettingsPath(projectDir);
|
|
72
|
+
if (!fs$1.existsSync(filePath)) return {};
|
|
73
|
+
const raw = fs$1.readFileSync(filePath, "utf-8");
|
|
74
|
+
const parsed = JSON.parse(raw);
|
|
75
|
+
if (parsed?.mcpServers && typeof parsed.mcpServers === "object") return validateConfig({ mcpServers: parsed.mcpServers });
|
|
76
|
+
return {};
|
|
77
|
+
} catch {
|
|
78
|
+
return {};
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
/**
|
|
82
|
+
* Expand `${VAR}` and `${VAR:-default}` references in a string from the
|
|
83
|
+
* environment, matching how Claude Code resolves values in `.mcp.json`.
|
|
84
|
+
* A referenced variable that is unset or empty falls back to its default,
|
|
85
|
+
* or to an empty string when no default is given.
|
|
86
|
+
*/
|
|
58
87
|
function expandEnvVars(value, env = process.env) {
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
88
|
+
return value.replace(/\$\{([A-Za-z_][A-Za-z0-9_]*)(?::-([^}]*))?\}|\$([A-Za-z_][A-Za-z0-9_]*)/g, (_match, bracedName, fallback, bareName) => {
|
|
89
|
+
const resolved = env[bracedName ?? bareName];
|
|
90
|
+
if (resolved !== void 0 && resolved !== "") return resolved;
|
|
91
|
+
return fallback ?? "";
|
|
92
|
+
});
|
|
93
|
+
}
|
|
94
|
+
/**
|
|
95
|
+
* Expand `${VAR}` and `$VAR` references in every string-valued HTTP header so that
|
|
96
|
+
* secrets like API keys can be referenced from the environment instead of
|
|
97
|
+
* being hardcoded in `mcp.json`.
|
|
98
|
+
*/
|
|
69
99
|
function expandHeaderEnvVars(headers) {
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
}
|
|
100
|
+
const expanded = {};
|
|
101
|
+
for (const [key, value] of Object.entries(headers)) if (typeof value === "string") expanded[key] = expandEnvVars(value);
|
|
102
|
+
return expanded;
|
|
103
|
+
}
|
|
104
|
+
/**
|
|
105
|
+
* Expand `${VAR}` and `$VAR` references in every string-valued environment
|
|
106
|
+
* variable passed to a stdio server, so that secrets can be referenced from the
|
|
107
|
+
* host environment instead of being hardcoded in `mcp.json`.
|
|
108
|
+
*/
|
|
76
109
|
function expandEnvValues(env) {
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
}
|
|
81
|
-
return expanded;
|
|
110
|
+
const expanded = {};
|
|
111
|
+
for (const [key, value] of Object.entries(env)) if (typeof value === "string") expanded[key] = expandEnvVars(value);
|
|
112
|
+
return expanded;
|
|
82
113
|
}
|
|
114
|
+
/**
|
|
115
|
+
* Classify a raw server entry as stdio, http, or skip (with reason).
|
|
116
|
+
*/
|
|
83
117
|
function classifyServerEntry(raw) {
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
118
|
+
if (!raw || typeof raw !== "object") return {
|
|
119
|
+
kind: "skip",
|
|
120
|
+
reason: "Invalid entry: expected an object"
|
|
121
|
+
};
|
|
122
|
+
const obj = raw;
|
|
123
|
+
const hasCommand = typeof obj.command === "string";
|
|
124
|
+
const hasUrl = typeof obj.url === "string";
|
|
125
|
+
if (hasCommand && hasUrl) return {
|
|
126
|
+
kind: "skip",
|
|
127
|
+
reason: "Cannot specify both \"command\" and \"url\""
|
|
128
|
+
};
|
|
129
|
+
if (hasCommand) return { kind: "stdio" };
|
|
130
|
+
if (hasUrl) {
|
|
131
|
+
try {
|
|
132
|
+
new URL(expandEnvVars(obj.url));
|
|
133
|
+
} catch {
|
|
134
|
+
return {
|
|
135
|
+
kind: "skip",
|
|
136
|
+
reason: `Invalid URL: "${obj.url}"`
|
|
137
|
+
};
|
|
138
|
+
}
|
|
139
|
+
return { kind: "http" };
|
|
140
|
+
}
|
|
141
|
+
return {
|
|
142
|
+
kind: "skip",
|
|
143
|
+
reason: "Missing required field: \"command\" (stdio) or \"url\" (http)"
|
|
144
|
+
};
|
|
105
145
|
}
|
|
106
146
|
function validateConfig(raw) {
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
147
|
+
if (!raw || typeof raw !== "object") return {};
|
|
148
|
+
const obj = raw;
|
|
149
|
+
if (!obj.mcpServers || typeof obj.mcpServers !== "object") return {};
|
|
150
|
+
const servers = {};
|
|
151
|
+
const skippedServers = [];
|
|
152
|
+
const rawServers = obj.mcpServers;
|
|
153
|
+
for (const [name, entry] of Object.entries(rawServers)) {
|
|
154
|
+
const classification = classifyServerEntry(entry);
|
|
155
|
+
if (classification.kind === "stdio") {
|
|
156
|
+
const e = entry;
|
|
157
|
+
servers[name] = {
|
|
158
|
+
command: e.command,
|
|
159
|
+
args: Array.isArray(e.args) ? e.args : void 0,
|
|
160
|
+
env: typeof e.env === "object" && e.env !== null ? expandEnvValues(e.env) : void 0
|
|
161
|
+
};
|
|
162
|
+
} else if (classification.kind === "http") {
|
|
163
|
+
const e = entry;
|
|
164
|
+
const oauthResult = parseOAuthConfig(e.oauth);
|
|
165
|
+
if (oauthResult.reason) {
|
|
166
|
+
skippedServers.push({
|
|
167
|
+
name,
|
|
168
|
+
reason: oauthResult.reason
|
|
169
|
+
});
|
|
170
|
+
continue;
|
|
171
|
+
}
|
|
172
|
+
servers[name] = {
|
|
173
|
+
url: expandEnvVars(e.url),
|
|
174
|
+
headers: typeof e.headers === "object" && e.headers !== null ? expandHeaderEnvVars(e.headers) : void 0,
|
|
175
|
+
oauth: oauthResult.config
|
|
176
|
+
};
|
|
177
|
+
} else skippedServers.push({
|
|
178
|
+
name,
|
|
179
|
+
reason: classification.reason
|
|
180
|
+
});
|
|
181
|
+
}
|
|
182
|
+
const result = {};
|
|
183
|
+
if (Object.keys(servers).length > 0) result.mcpServers = servers;
|
|
184
|
+
if (skippedServers.length > 0) result.skippedServers = skippedServers;
|
|
185
|
+
return result;
|
|
146
186
|
}
|
|
147
187
|
function parseOAuthConfig(raw) {
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
redirectUrl: rawRedirectUrl,
|
|
182
|
-
clientName: typeof obj.clientName === "string" ? obj.clientName : void 0,
|
|
183
|
-
scopes: obj.scopes,
|
|
184
|
-
clientId: typeof obj.clientId === "string" ? obj.clientId : void 0,
|
|
185
|
-
clientSecret: typeof obj.clientSecret === "string" ? obj.clientSecret : void 0
|
|
186
|
-
}
|
|
187
|
-
};
|
|
188
|
-
}
|
|
188
|
+
if (raw === void 0) return {};
|
|
189
|
+
if (!raw || typeof raw !== "object") return { reason: "Invalid OAuth config: expected an object" };
|
|
190
|
+
const obj = raw;
|
|
191
|
+
if (obj.redirectUrl !== void 0 && typeof obj.redirectUrl !== "string") return { reason: "Invalid OAuth config: \"redirectUrl\" must be a string" };
|
|
192
|
+
let callbackPortRedirectUrl;
|
|
193
|
+
if (obj.callbackPort !== void 0) {
|
|
194
|
+
if (obj.redirectUrl !== void 0) return { reason: "Invalid OAuth config: set either \"redirectUrl\" or \"callbackPort\", not both" };
|
|
195
|
+
if (typeof obj.callbackPort !== "number" || !Number.isInteger(obj.callbackPort) || obj.callbackPort < 1 || obj.callbackPort > 65535) return { reason: "Invalid OAuth config: \"callbackPort\" must be an integer between 1 and 65535" };
|
|
196
|
+
callbackPortRedirectUrl = resolveOAuthRedirectUrl({ callbackPort: obj.callbackPort });
|
|
197
|
+
}
|
|
198
|
+
const rawRedirectUrl = callbackPortRedirectUrl ?? obj.redirectUrl ?? "http://127.0.0.1:1458/oauth/callback";
|
|
199
|
+
try {
|
|
200
|
+
const redirectUrl = new URL(rawRedirectUrl);
|
|
201
|
+
const isLoopback = isLoopbackHostname(redirectUrl.hostname);
|
|
202
|
+
if (redirectUrl.protocol !== "https:" && !(redirectUrl.protocol === "http:" && isLoopback)) return { reason: "Invalid OAuth redirectUrl: must use HTTPS unless it is a loopback HTTP URL" };
|
|
203
|
+
} catch {
|
|
204
|
+
return { reason: `Invalid OAuth redirectUrl: "${rawRedirectUrl}"` };
|
|
205
|
+
}
|
|
206
|
+
if (obj.scopes !== void 0 && (!Array.isArray(obj.scopes) || obj.scopes.some((scope) => typeof scope !== "string"))) return { reason: "Invalid OAuth config: \"scopes\" must be an array of strings" };
|
|
207
|
+
return { config: {
|
|
208
|
+
redirectUrl: rawRedirectUrl,
|
|
209
|
+
clientName: typeof obj.clientName === "string" ? obj.clientName : void 0,
|
|
210
|
+
scopes: obj.scopes,
|
|
211
|
+
clientId: typeof obj.clientId === "string" ? obj.clientId : void 0,
|
|
212
|
+
clientSecret: typeof obj.clientSecret === "string" ? obj.clientSecret : void 0
|
|
213
|
+
} };
|
|
214
|
+
}
|
|
215
|
+
/**
|
|
216
|
+
* Merge configs: claude (lowest priority) < global < project (highest).
|
|
217
|
+
* Later configs override earlier by server name.
|
|
218
|
+
* Skipped entries are accumulated, but if a higher-priority config provides
|
|
219
|
+
* a valid entry for a skipped name, the skip is removed.
|
|
220
|
+
*/
|
|
189
221
|
function mergeConfigs(...configs) {
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
const result = {};
|
|
209
|
-
if (Object.keys(merged).length > 0) {
|
|
210
|
-
result.mcpServers = merged;
|
|
211
|
-
}
|
|
212
|
-
if (skippedMap.size > 0) {
|
|
213
|
-
result.skippedServers = Array.from(skippedMap.values());
|
|
214
|
-
}
|
|
215
|
-
return result;
|
|
216
|
-
}
|
|
217
|
-
export {
|
|
218
|
-
DEFAULT_OAUTH_REDIRECT_URL,
|
|
219
|
-
classifyServerEntry,
|
|
220
|
-
expandEnvVars,
|
|
221
|
-
getClaudeSettingsPath,
|
|
222
|
-
getGlobalMcpPath,
|
|
223
|
-
getProjectMcpPath,
|
|
224
|
-
getRootMcpPath,
|
|
225
|
-
loadMcpConfig,
|
|
226
|
-
resolveOAuthRedirectUrl,
|
|
227
|
-
validateConfig
|
|
228
|
-
};
|
|
222
|
+
const merged = {};
|
|
223
|
+
const allSkipped = [];
|
|
224
|
+
for (const config of configs) {
|
|
225
|
+
if (config.mcpServers) for (const [name, server] of Object.entries(config.mcpServers)) merged[name] = server;
|
|
226
|
+
if (config.skippedServers) allSkipped.push(...config.skippedServers);
|
|
227
|
+
}
|
|
228
|
+
const validNames = new Set(Object.keys(merged));
|
|
229
|
+
const filteredSkipped = allSkipped.filter((s) => !validNames.has(s.name));
|
|
230
|
+
const skippedMap = /* @__PURE__ */ new Map();
|
|
231
|
+
for (const s of filteredSkipped) skippedMap.set(s.name, s);
|
|
232
|
+
const result = {};
|
|
233
|
+
if (Object.keys(merged).length > 0) result.mcpServers = merged;
|
|
234
|
+
if (skippedMap.size > 0) result.skippedServers = Array.from(skippedMap.values());
|
|
235
|
+
return result;
|
|
236
|
+
}
|
|
237
|
+
//#endregion
|
|
238
|
+
export { DEFAULT_OAUTH_REDIRECT_URL, classifyServerEntry, expandEnvVars, getClaudeSettingsPath, getGlobalMcpPath, getProjectMcpPath, getRootMcpPath, loadMcpConfig, resolveOAuthRedirectUrl, validateConfig };
|
|
239
|
+
|
|
229
240
|
//# sourceMappingURL=config.js.map
|