@sanity/cli 6.5.3 → 6.7.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 (188) hide show
  1. package/README.md +18 -5
  2. package/bin/run.js +3 -1
  3. package/dist/actions/auth/login/login.js +39 -13
  4. package/dist/actions/auth/login/login.js.map +1 -1
  5. package/dist/actions/auth/login/validateToken.js +39 -0
  6. package/dist/actions/auth/login/validateToken.js.map +1 -0
  7. package/dist/actions/build/buildApp.js +4 -5
  8. package/dist/actions/build/buildApp.js.map +1 -1
  9. package/dist/actions/build/buildStaticFiles.js +12 -4
  10. package/dist/actions/build/buildStaticFiles.js.map +1 -1
  11. package/dist/actions/build/buildStudio.js +6 -14
  12. package/dist/actions/build/buildStudio.js.map +1 -1
  13. package/dist/actions/build/{getStudioEnvironmentVariables.js → getEnvironmentVariables.js} +15 -19
  14. package/dist/actions/build/getEnvironmentVariables.js.map +1 -0
  15. package/dist/actions/deploy/deployStudio.js +1 -2
  16. package/dist/actions/deploy/deployStudio.js.map +1 -1
  17. package/dist/actions/deploy/deployStudioSchemasAndManifests.js +1 -2
  18. package/dist/actions/deploy/deployStudioSchemasAndManifests.js.map +1 -1
  19. package/dist/actions/deploy/deployStudioSchemasAndManifests.worker.js +1 -1
  20. package/dist/actions/deploy/deployStudioSchemasAndManifests.worker.js.map +1 -1
  21. package/dist/actions/dev/startStudioDevServer.js +1 -1
  22. package/dist/actions/dev/startStudioDevServer.js.map +1 -1
  23. package/dist/actions/documents/validateDocuments.worker.js +1 -2
  24. package/dist/actions/documents/validateDocuments.worker.js.map +1 -1
  25. package/dist/actions/graphql/SchemaError.js +1 -1
  26. package/dist/actions/graphql/SchemaError.js.map +1 -1
  27. package/dist/actions/init/initAction.js +32 -1
  28. package/dist/actions/init/initAction.js.map +1 -1
  29. package/dist/actions/init/scaffoldTemplate.js +32 -18
  30. package/dist/actions/init/scaffoldTemplate.js.map +1 -1
  31. package/dist/actions/init/templates/index.js +2 -0
  32. package/dist/actions/init/templates/index.js.map +1 -1
  33. package/dist/actions/init/templates/pageBuilder.js +32 -0
  34. package/dist/actions/init/templates/pageBuilder.js.map +1 -0
  35. package/dist/actions/init/types.js +2 -1
  36. package/dist/actions/init/types.js.map +1 -1
  37. package/dist/actions/manifest/extractManifest.js +1 -1
  38. package/dist/actions/manifest/extractManifest.js.map +1 -1
  39. package/dist/actions/manifest/extractManifest.worker.js +1 -1
  40. package/dist/actions/manifest/extractManifest.worker.js.map +1 -1
  41. package/dist/actions/mcp/editorConfigs.js +51 -11
  42. package/dist/actions/mcp/editorConfigs.js.map +1 -1
  43. package/dist/actions/mcp/promptForMCPSetup.js +16 -11
  44. package/dist/actions/mcp/promptForMCPSetup.js.map +1 -1
  45. package/dist/actions/mcp/setupMCP.js +180 -61
  46. package/dist/actions/mcp/setupMCP.js.map +1 -1
  47. package/dist/actions/mcp/types.js.map +1 -1
  48. package/dist/actions/schema/deploySchemas.js +1 -1
  49. package/dist/actions/schema/deploySchemas.js.map +1 -1
  50. package/dist/actions/schema/extractSanityWorkspace.worker.js +1 -1
  51. package/dist/actions/schema/extractSanityWorkspace.worker.js.map +1 -1
  52. package/dist/actions/schema/extractSchema.js +1 -4
  53. package/dist/actions/schema/extractSchema.js.map +1 -1
  54. package/dist/actions/schema/extractSchemaWatcher.js +1 -4
  55. package/dist/actions/schema/extractSchemaWatcher.js.map +1 -1
  56. package/dist/actions/schema/getExtractOptions.js +8 -18
  57. package/dist/actions/schema/getExtractOptions.js.map +1 -1
  58. package/dist/actions/schema/types.js +0 -6
  59. package/dist/actions/schema/types.js.map +1 -1
  60. package/dist/actions/schema/validateAction.js +1 -1
  61. package/dist/actions/schema/validateAction.js.map +1 -1
  62. package/dist/actions/schema/validateSchema.worker.js +1 -2
  63. package/dist/actions/schema/validateSchema.worker.js.map +1 -1
  64. package/dist/actions/schema/watchExtractSchema.js +1 -1
  65. package/dist/actions/schema/watchExtractSchema.js.map +1 -1
  66. package/dist/actions/skills/readSkillState.js +54 -0
  67. package/dist/actions/skills/readSkillState.js.map +1 -0
  68. package/dist/actions/skills/setupSkills.js +73 -0
  69. package/dist/actions/skills/setupSkills.js.map +1 -0
  70. package/dist/commands/build.js +9 -22
  71. package/dist/commands/build.js.map +1 -1
  72. package/dist/commands/cors/add.js +5 -5
  73. package/dist/commands/cors/add.js.map +1 -1
  74. package/dist/commands/datasets/export.js +9 -0
  75. package/dist/commands/datasets/export.js.map +1 -1
  76. package/dist/commands/docs/read.js +33 -12
  77. package/dist/commands/docs/read.js.map +1 -1
  78. package/dist/commands/init.js +12 -1
  79. package/dist/commands/init.js.map +1 -1
  80. package/dist/commands/login.js +28 -5
  81. package/dist/commands/login.js.map +1 -1
  82. package/dist/commands/manifest/extract.js +1 -2
  83. package/dist/commands/manifest/extract.js.map +1 -1
  84. package/dist/commands/mcp/configure.js +2 -1
  85. package/dist/commands/mcp/configure.js.map +1 -1
  86. package/dist/commands/schemas/deploy.js +1 -2
  87. package/dist/commands/schemas/deploy.js.map +1 -1
  88. package/dist/exports/_internal.d.ts +2 -1
  89. package/dist/exports/_internal.js +1 -1
  90. package/dist/exports/_internal.js.map +1 -1
  91. package/dist/server/devServer.js +25 -4
  92. package/dist/server/devServer.js.map +1 -1
  93. package/dist/server/previewServer.js +1 -1
  94. package/dist/server/previewServer.js.map +1 -1
  95. package/dist/services/mcp.js +1 -1
  96. package/dist/services/mcp.js.map +1 -1
  97. package/dist/telemetry/init.telemetry.js.map +1 -1
  98. package/oclif.manifest.json +237 -205
  99. package/package.json +15 -16
  100. package/templates/page-builder/README.md +9 -0
  101. package/templates/page-builder/schemaTypes/hero.js +31 -0
  102. package/templates/page-builder/schemaTypes/index.js +19 -0
  103. package/templates/page-builder/static/.gitkeep +0 -0
  104. package/dist/actions/build/buildDebug.js +0 -4
  105. package/dist/actions/build/buildDebug.js.map +0 -1
  106. package/dist/actions/build/buildVendorDependencies.js +0 -149
  107. package/dist/actions/build/buildVendorDependencies.js.map +0 -1
  108. package/dist/actions/build/checkStudioDependencyVersions.js +0 -155
  109. package/dist/actions/build/checkStudioDependencyVersions.js.map +0 -1
  110. package/dist/actions/build/createExternalFromImportMap.js +0 -11
  111. package/dist/actions/build/createExternalFromImportMap.js.map +0 -1
  112. package/dist/actions/build/decorateIndexWithAutoGeneratedWarning.js +0 -13
  113. package/dist/actions/build/decorateIndexWithAutoGeneratedWarning.js.map +0 -1
  114. package/dist/actions/build/decorateIndexWithBridgeScript.js +0 -17
  115. package/dist/actions/build/decorateIndexWithBridgeScript.js.map +0 -1
  116. package/dist/actions/build/decorateIndexWithStagingScript.js +0 -16
  117. package/dist/actions/build/decorateIndexWithStagingScript.js.map +0 -1
  118. package/dist/actions/build/getAppEnvVars.js +0 -9
  119. package/dist/actions/build/getAppEnvVars.js.map +0 -1
  120. package/dist/actions/build/getEntryModule.js +0 -46
  121. package/dist/actions/build/getEntryModule.js.map +0 -1
  122. package/dist/actions/build/getPossibleDocumentComponentLocations.js +0 -11
  123. package/dist/actions/build/getPossibleDocumentComponentLocations.js.map +0 -1
  124. package/dist/actions/build/getStudioEnvVars.js +0 -9
  125. package/dist/actions/build/getStudioEnvVars.js.map +0 -1
  126. package/dist/actions/build/getStudioEnvironmentVariables.js.map +0 -1
  127. package/dist/actions/build/getViteConfig.js +0 -219
  128. package/dist/actions/build/getViteConfig.js.map +0 -1
  129. package/dist/actions/build/normalizeBasePath.js +0 -9
  130. package/dist/actions/build/normalizeBasePath.js.map +0 -1
  131. package/dist/actions/build/renderDocument.js +0 -50
  132. package/dist/actions/build/renderDocument.js.map +0 -1
  133. package/dist/actions/build/renderDocument.worker.js +0 -9
  134. package/dist/actions/build/renderDocument.worker.js.map +0 -1
  135. package/dist/actions/build/renderDocumentWorker/addTimestampImportMapScriptToHtml.js +0 -79
  136. package/dist/actions/build/renderDocumentWorker/addTimestampImportMapScriptToHtml.js.map +0 -1
  137. package/dist/actions/build/renderDocumentWorker/components/BasicDocument.js +0 -61
  138. package/dist/actions/build/renderDocumentWorker/components/BasicDocument.js.map +0 -1
  139. package/dist/actions/build/renderDocumentWorker/components/DefaultDocument.js +0 -165
  140. package/dist/actions/build/renderDocumentWorker/components/DefaultDocument.js.map +0 -1
  141. package/dist/actions/build/renderDocumentWorker/components/Favicons.js +0 -28
  142. package/dist/actions/build/renderDocumentWorker/components/Favicons.js.map +0 -1
  143. package/dist/actions/build/renderDocumentWorker/components/GlobalErrorHandler.js +0 -178
  144. package/dist/actions/build/renderDocumentWorker/components/GlobalErrorHandler.js.map +0 -1
  145. package/dist/actions/build/renderDocumentWorker/components/NoJavascript.js +0 -51
  146. package/dist/actions/build/renderDocumentWorker/components/NoJavascript.js.map +0 -1
  147. package/dist/actions/build/renderDocumentWorker/getDocumentComponent.js +0 -41
  148. package/dist/actions/build/renderDocumentWorker/getDocumentComponent.js.map +0 -1
  149. package/dist/actions/build/renderDocumentWorker/getDocumentHtml.js +0 -55
  150. package/dist/actions/build/renderDocumentWorker/getDocumentHtml.js.map +0 -1
  151. package/dist/actions/build/renderDocumentWorker/renderDocumentWorker.js +0 -31
  152. package/dist/actions/build/renderDocumentWorker/renderDocumentWorker.js.map +0 -1
  153. package/dist/actions/build/renderDocumentWorker/tryLoadDocumentComponent.js +0 -30
  154. package/dist/actions/build/renderDocumentWorker/tryLoadDocumentComponent.js.map +0 -1
  155. package/dist/actions/build/renderDocumentWorker/types.js +0 -5
  156. package/dist/actions/build/renderDocumentWorker/types.js.map +0 -1
  157. package/dist/actions/build/writeSanityRuntime.js +0 -64
  158. package/dist/actions/build/writeSanityRuntime.js.map +0 -1
  159. package/dist/actions/docs/normalizeDocsPath.js +0 -15
  160. package/dist/actions/docs/normalizeDocsPath.js.map +0 -1
  161. package/dist/actions/schema/extractSanitySchema.worker.js +0 -33
  162. package/dist/actions/schema/extractSanitySchema.worker.js.map +0 -1
  163. package/dist/actions/schema/formatSchemaValidation.js +0 -78
  164. package/dist/actions/schema/formatSchemaValidation.js.map +0 -1
  165. package/dist/actions/schema/matchSchemaPattern.js +0 -22
  166. package/dist/actions/schema/matchSchemaPattern.js.map +0 -1
  167. package/dist/actions/schema/runSchemaExtraction.js +0 -39
  168. package/dist/actions/schema/runSchemaExtraction.js.map +0 -1
  169. package/dist/actions/schema/utils/SchemaExtractionError.js +0 -10
  170. package/dist/actions/schema/utils/SchemaExtractionError.js.map +0 -1
  171. package/dist/actions/schema/utils/extractValidationFromSchemaError.js +0 -12
  172. package/dist/actions/schema/utils/extractValidationFromSchemaError.js.map +0 -1
  173. package/dist/constants.js +0 -8
  174. package/dist/constants.js.map +0 -1
  175. package/dist/server/vite/plugin-sanity-build-entries.js +0 -67
  176. package/dist/server/vite/plugin-sanity-build-entries.js.map +0 -1
  177. package/dist/server/vite/plugin-sanity-favicons.js +0 -72
  178. package/dist/server/vite/plugin-sanity-favicons.js.map +0 -1
  179. package/dist/server/vite/plugin-sanity-runtime-rewrite.js +0 -18
  180. package/dist/server/vite/plugin-sanity-runtime-rewrite.js.map +0 -1
  181. package/dist/server/vite/plugin-schema-extraction.js +0 -201
  182. package/dist/server/vite/plugin-schema-extraction.js.map +0 -1
  183. package/dist/telemetry/build.telemetry.js +0 -13
  184. package/dist/telemetry/build.telemetry.js.map +0 -1
  185. package/dist/telemetry/extractSchema.telemetry.js +0 -18
  186. package/dist/telemetry/extractSchema.telemetry.js.map +0 -1
  187. package/dist/util/getWorkspace.js +0 -18
  188. package/dist/util/getWorkspace.js.map +0 -1
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/actions/mcp/editorConfigs.ts"],"sourcesContent":["import {existsSync} from 'node:fs'\nimport os from 'node:os'\nimport path from 'node:path'\n\nimport {execa} from 'execa'\n\nimport {MCP_SERVER_URL} from '../../services/mcp.js'\n\n/**\n * Environment abstraction for editor detection.\n *\n * Detect functions receive this instead of using module-level imports, making\n * each function independently testable without global mocks.\n */\nexport interface DetectionEnv {\n env: Record<string, string | undefined>\n /** Run a CLI command to check if a tool is installed. Rejects on failure. */\n execCommand: (cmd: string, args: string[]) => Promise<void>\n existsSync: (p: string) => boolean\n homedir: string\n platform: NodeJS.Platform\n}\n\n/** Create the real detection environment backed by process/OS globals. */\nexport function createDetectionEnv(): DetectionEnv {\n return {\n env: process.env,\n execCommand: (cmd, args) => execa(cmd, args, {stdio: 'pipe', timeout: 5000}).then(() => {}),\n existsSync,\n homedir: os.homedir(),\n platform: process.platform,\n }\n}\n\ninterface EditorConfig {\n /** Builds the server config with API token. If oauthOnly is true, the token is not used */\n buildServerConfig: (token: string) => Record<string, unknown>\n configKey: string\n /** Returns the config file path if editor is detected, null otherwise */\n detect: (env: DetectionEnv) => Promise<string | null>\n format: 'jsonc' | 'toml'\n /** Extracts the auth token from a parsed Sanity server config block */\n readToken: (serverConfig: Record<string, unknown>) => string | undefined\n\n /** If true, this editor uses OAuth natively and does not need an embedded API token */\n oauthOnly?: boolean\n}\n\n/**\n * The Sanity MCP server uses OAuth by default\n * If a token is provided, the server will not use OAuth instead tool calls will use the API token\n */\nconst defaultHttpConfig = (token?: string) => {\n const defaultConfig: Record<string, unknown> = {\n type: 'http',\n url: MCP_SERVER_URL,\n }\n\n if (token) {\n defaultConfig.headers = {Authorization: `Bearer ${token}`}\n }\n\n return defaultConfig\n}\n\n// -- Detect functions --\n\nasync function detectClaudeCode(ctx: DetectionEnv): Promise<string | null> {\n try {\n await ctx.execCommand('claude', ['--version'])\n return path.join(ctx.homedir, '.claude.json')\n } catch {\n return null\n }\n}\n\nasync function detectAntigravity(ctx: DetectionEnv): Promise<string | null> {\n const antigravityDir = path.join(ctx.homedir, '.gemini/antigravity')\n return ctx.existsSync(antigravityDir) ? path.join(antigravityDir, 'mcp_config.json') : null\n}\n\nexport function getVSCodeUserDir(\n ctx: DetectionEnv,\n variant: 'insiders' | 'stable' = 'stable',\n): string | null {\n switch (ctx.platform) {\n case 'darwin': {\n return path.join(\n ctx.homedir,\n variant === 'insiders'\n ? 'Library/Application Support/Code - Insiders/User'\n : 'Library/Application Support/Code/User',\n )\n }\n case 'win32': {\n if (!ctx.env.APPDATA) return null\n return path.join(\n ctx.env.APPDATA,\n variant === 'insiders' ? 'Code - Insiders/User' : 'Code/User',\n )\n }\n default: {\n return path.join(\n ctx.homedir,\n variant === 'insiders' ? '.config/Code - Insiders/User' : '.config/Code/User',\n )\n }\n }\n}\n\nasync function detectCline(ctx: DetectionEnv): Promise<string | null> {\n const vscodeUserDir = getVSCodeUserDir(ctx)\n if (!vscodeUserDir) return null\n const clineConfigDir = path.join(vscodeUserDir, 'globalStorage/saoudrizwan.claude-dev/settings')\n return ctx.existsSync(clineConfigDir)\n ? path.join(clineConfigDir, 'cline_mcp_settings.json')\n : null\n}\n\nasync function detectClineCli(ctx: DetectionEnv): Promise<string | null> {\n const clineHome = ctx.env.CLINE_DIR || path.join(ctx.homedir, '.cline')\n if (!ctx.existsSync(clineHome)) return null\n return path.join(clineHome, 'data/settings/cline_mcp_settings.json')\n}\n\nasync function detectCodexCli(ctx: DetectionEnv): Promise<string | null> {\n try {\n await ctx.execCommand('codex', ['--version'])\n const codexHome = ctx.env.CODEX_HOME || path.join(ctx.homedir, '.codex')\n return path.join(codexHome, 'config.toml')\n } catch {\n return null\n }\n}\n\nasync function detectCursor(ctx: DetectionEnv): Promise<string | null> {\n const cursorDir = path.join(ctx.homedir, '.cursor')\n return ctx.existsSync(cursorDir) ? path.join(cursorDir, 'mcp.json') : null\n}\n\nasync function detectGeminiCli(ctx: DetectionEnv): Promise<string | null> {\n // Antigravity stores its config under ~/.gemini/antigravity, so checking\n // only the parent ~/.gemini directory causes false Gemini CLI detection.\n const settingsPath = path.join(ctx.homedir, '.gemini/settings.json')\n return ctx.existsSync(settingsPath) ? settingsPath : null\n}\n\nasync function detectGitHubCopilotCli(ctx: DetectionEnv): Promise<string | null> {\n const copilotDir =\n ctx.platform === 'linux' && ctx.env.XDG_CONFIG_HOME\n ? path.join(ctx.env.XDG_CONFIG_HOME, 'copilot')\n : path.join(ctx.homedir, '.copilot')\n return ctx.existsSync(copilotDir) ? path.join(copilotDir, 'mcp-config.json') : null\n}\n\nasync function detectOpenCode(ctx: DetectionEnv): Promise<string | null> {\n try {\n await ctx.execCommand('opencode', ['--version'])\n return path.join(ctx.homedir, '.config/opencode/opencode.json')\n } catch {\n return null\n }\n}\n\nasync function detectVSCode(ctx: DetectionEnv): Promise<string | null> {\n const configDir = getVSCodeUserDir(ctx)\n return configDir && ctx.existsSync(configDir) ? path.join(configDir, 'mcp.json') : null\n}\n\nasync function detectVSCodeInsiders(ctx: DetectionEnv): Promise<string | null> {\n const configDir = getVSCodeUserDir(ctx, 'insiders')\n return configDir && ctx.existsSync(configDir) ? path.join(configDir, 'mcp.json') : null\n}\n\nasync function detectZed(ctx: DetectionEnv): Promise<string | null> {\n let configDir: string | null = null\n switch (ctx.platform) {\n case 'win32': {\n if (ctx.env.APPDATA) {\n configDir = path.join(ctx.env.APPDATA, 'Zed')\n }\n break\n }\n default: {\n configDir = path.join(ctx.homedir, '.config/zed')\n }\n }\n return configDir && ctx.existsSync(configDir) ? path.join(configDir, 'settings.json') : null\n}\n\nasync function detectMCPorter(ctx: DetectionEnv): Promise<string | null> {\n const mcporterDir = path.join(ctx.homedir, '.mcporter')\n if (!ctx.existsSync(mcporterDir)) return null\n\n const jsonPath = path.join(mcporterDir, 'mcporter.json')\n const jsoncPath = path.join(mcporterDir, 'mcporter.jsonc')\n if (ctx.existsSync(jsonPath)) return jsonPath\n if (ctx.existsSync(jsoncPath)) return jsoncPath\n return jsonPath\n}\n\n// -- Read token helpers --\n\n/**\n * Extract a Bearer token from a headers-like object.\n * Looks for `Authorization: \"Bearer <token>\"` and returns the token portion.\n */\nfunction extractBearerToken(headers: unknown): string | undefined {\n if (typeof headers !== 'object' || headers === null) return undefined\n const auth = (headers as Record<string, unknown>).Authorization\n if (typeof auth !== 'string') return undefined\n const match = auth.match(/^Bearer\\s+(.+)$/)\n return match?.[1]\n}\n\nfunction readTokenFromHeaders(serverConfig: Record<string, unknown>): string | undefined {\n return extractBearerToken(serverConfig.headers)\n}\n\nfunction readTokenFromHttpHeaders(serverConfig: Record<string, unknown>): string | undefined {\n return extractBearerToken(serverConfig.http_headers)\n}\n\n// -- Defaults & build server config functions --\n\n/** Most editors share these values — entries only need to declare `detect` + any overrides. */\nconst EDITOR_DEFAULTS = {\n buildServerConfig: defaultHttpConfig,\n configKey: 'mcpServers',\n format: 'jsonc' as const,\n oauthOnly: false,\n readToken: readTokenFromHeaders,\n}\n\nfunction buildAntigravityServerConfig(token: string): Record<string, unknown> {\n return {\n headers: {Authorization: `Bearer ${token}`},\n serverUrl: MCP_SERVER_URL,\n }\n}\n\nfunction buildClineServerConfig(token: string): Record<string, unknown> {\n return {\n disabled: false,\n headers: {Authorization: `Bearer ${token}`},\n type: 'streamableHttp',\n url: MCP_SERVER_URL,\n }\n}\n\nfunction buildCodexCliServerConfig(token: string): Record<string, unknown> {\n return {\n http_headers: {Authorization: `Bearer ${token}`},\n type: 'http',\n url: MCP_SERVER_URL,\n }\n}\n\nfunction buildGitHubCopilotCliServerConfig(token: string): Record<string, unknown> {\n return {\n headers: {Authorization: `Bearer ${token}`},\n tools: ['*'],\n type: 'http',\n url: MCP_SERVER_URL,\n }\n}\n\nfunction buildOpenCodeServerConfig(token: string): Record<string, unknown> {\n return {\n headers: {Authorization: `Bearer ${token}`},\n type: 'remote',\n url: MCP_SERVER_URL,\n }\n}\n\nfunction buildZedServerConfig(token: string): Record<string, unknown> {\n return {\n headers: {Authorization: `Bearer ${token}`},\n settings: {},\n url: MCP_SERVER_URL,\n }\n}\n\n/**\n * Centralized editor configuration including detection logic.\n * To add a new editor: add an entry here — EditorName type is derived automatically.\n *\n * Each entry includes a doc URL pointing to the source of truth for its\n * config path and format. When updating a path, verify against the linked\n * documentation first.\n */\nexport const EDITOR_CONFIGS = {\n // Doc: https://support.google.com/gemini/answer/16255176 (Antigravity / Project Mariner)\n Antigravity: {\n ...EDITOR_DEFAULTS,\n buildServerConfig: buildAntigravityServerConfig,\n detect: detectAntigravity,\n },\n // Doc: https://docs.anthropic.com/en/docs/claude-code/mcp\n // Path: ~/.claude.json Key: mcpServers\n 'Claude Code': {...EDITOR_DEFAULTS, detect: detectClaudeCode},\n // Doc: https://github.com/cline/cline — VS Code extension (saoudrizwan.claude-dev)\n // Path: <VS Code User>/globalStorage/saoudrizwan.claude-dev/settings/cline_mcp_settings.json\n Cline: {...EDITOR_DEFAULTS, buildServerConfig: buildClineServerConfig, detect: detectCline},\n // Doc: https://github.com/cline/cline — standalone CLI mode\n // Path: $CLINE_DIR || ~/.cline/data/settings/cline_mcp_settings.json\n 'Cline CLI': {\n ...EDITOR_DEFAULTS,\n buildServerConfig: buildClineServerConfig,\n detect: detectClineCli,\n },\n // Doc: https://platform.openai.com/docs/guides/tools-remote-mcp#codex-cli\n // Path: $CODEX_HOME || ~/.codex/config.toml Key: mcp_servers Format: TOML\n 'Codex CLI': {\n ...EDITOR_DEFAULTS,\n buildServerConfig: buildCodexCliServerConfig,\n configKey: 'mcp_servers',\n detect: detectCodexCli,\n format: 'toml' as const,\n readToken: readTokenFromHttpHeaders,\n },\n // Doc: https://docs.cursor.com/context/model-context-protocol\n // Path: ~/.cursor/mcp.json Key: mcpServers\n Cursor: {\n ...EDITOR_DEFAULTS,\n detect: detectCursor,\n oauthOnly: true,\n },\n // Doc: https://googlegemini.wiki/gemini-cli/mcp-servers\n // Path: ~/.gemini/settings.json Key: mcpServers\n 'Gemini CLI': {...EDITOR_DEFAULTS, detect: detectGeminiCli},\n // Doc: https://docs.github.com/en/copilot/customizing-copilot/extending-copilot-coding-agent-with-mcp\n // Path: ~/.copilot/mcp-config.json (or $XDG_CONFIG_HOME/copilot on Linux) Key: mcpServers\n 'GitHub Copilot CLI': {\n ...EDITOR_DEFAULTS,\n buildServerConfig: buildGitHubCopilotCliServerConfig,\n detect: detectGitHubCopilotCli,\n },\n // Doc: https://github.com/nicobailon/mcporter\n // Path: ~/.mcporter/mcporter.{json,jsonc} Key: mcpServers\n MCPorter: {...EDITOR_DEFAULTS, detect: detectMCPorter},\n // Doc: https://opencode.ai/docs/config\n // Path: ~/.config/opencode/opencode.json Key: mcp\n OpenCode: {\n ...EDITOR_DEFAULTS,\n buildServerConfig: buildOpenCodeServerConfig,\n configKey: 'mcp',\n detect: detectOpenCode,\n },\n // Doc: https://code.visualstudio.com/docs/copilot/chat/mcp-servers\n // Path: <VS Code User dir>/mcp.json Key: servers\n 'VS Code': {...EDITOR_DEFAULTS, configKey: 'servers', detect: detectVSCode},\n // Doc: https://code.visualstudio.com/docs/copilot/chat/mcp-servers\n // Path: <VS Code Insiders User dir>/mcp.json Key: servers\n 'VS Code Insiders': {...EDITOR_DEFAULTS, configKey: 'servers', detect: detectVSCodeInsiders},\n // Doc: https://zed.dev/docs/assistant/model-context-protocol\n // Path: ~/.config/zed/settings.json (or $APPDATA/Zed on Windows) Key: context_servers\n Zed: {\n ...EDITOR_DEFAULTS,\n buildServerConfig: buildZedServerConfig,\n configKey: 'context_servers',\n detect: detectZed,\n },\n} satisfies Record<string, EditorConfig>\n\n/** Derived from EDITOR_CONFIGS keys - add a new editor there and this updates automatically */\nexport type EditorName = keyof typeof EDITOR_CONFIGS\n"],"names":["existsSync","os","path","execa","MCP_SERVER_URL","createDetectionEnv","env","process","execCommand","cmd","args","stdio","timeout","then","homedir","platform","defaultHttpConfig","token","defaultConfig","type","url","headers","Authorization","detectClaudeCode","ctx","join","detectAntigravity","antigravityDir","getVSCodeUserDir","variant","APPDATA","detectCline","vscodeUserDir","clineConfigDir","detectClineCli","clineHome","CLINE_DIR","detectCodexCli","codexHome","CODEX_HOME","detectCursor","cursorDir","detectGeminiCli","settingsPath","detectGitHubCopilotCli","copilotDir","XDG_CONFIG_HOME","detectOpenCode","detectVSCode","configDir","detectVSCodeInsiders","detectZed","detectMCPorter","mcporterDir","jsonPath","jsoncPath","extractBearerToken","undefined","auth","match","readTokenFromHeaders","serverConfig","readTokenFromHttpHeaders","http_headers","EDITOR_DEFAULTS","buildServerConfig","configKey","format","oauthOnly","readToken","buildAntigravityServerConfig","serverUrl","buildClineServerConfig","disabled","buildCodexCliServerConfig","buildGitHubCopilotCliServerConfig","tools","buildOpenCodeServerConfig","buildZedServerConfig","settings","EDITOR_CONFIGS","Antigravity","detect","Cline","Cursor","MCPorter","OpenCode","Zed"],"mappings":"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"}
1
+ {"version":3,"sources":["../../../src/actions/mcp/editorConfigs.ts"],"sourcesContent":["import {existsSync} from 'node:fs'\nimport os from 'node:os'\nimport path from 'node:path'\n\nimport {execa} from 'execa'\n\nimport {MCP_SERVER_URL} from '../../services/mcp.js'\n\n/**\n * Environment abstraction for editor detection.\n *\n * Detect functions receive this instead of using module-level imports, making\n * each function independently testable without global mocks.\n */\nexport interface DetectionEnv {\n env: Record<string, string | undefined>\n /** Run a CLI command to check if a tool is installed. Rejects on failure. */\n execCommand: (cmd: string, args: string[]) => Promise<void>\n existsSync: (p: string) => boolean\n homedir: string\n platform: NodeJS.Platform\n}\n\n/** Create the real detection environment backed by process/OS globals. */\nexport function createDetectionEnv(): DetectionEnv {\n return {\n env: process.env,\n execCommand: (cmd, args) => execa(cmd, args, {stdio: 'pipe', timeout: 5000}).then(() => {}),\n existsSync,\n homedir: os.homedir(),\n platform: process.platform,\n }\n}\n\ninterface EditorConfig {\n /** Builds the server config with API token. If oauthOnly is true, the token is not used */\n buildServerConfig: (token: string) => Record<string, unknown>\n configKey: string\n /** Returns the config file path if editor is detected, null otherwise */\n detect: (env: DetectionEnv) => Promise<string | null>\n format: 'jsonc' | 'toml'\n /** Extracts the auth token from a parsed Sanity server config block */\n readToken: (serverConfig: Record<string, unknown>) => string | undefined\n\n /** If true, this editor uses OAuth natively and does not need an embedded API token */\n oauthOnly?: boolean\n /**\n * Corresponding `--agent` value for the `skills` CLI (https://github.com/vercel-labs/skills).\n * Omit when the editor has no skills CLI equivalent.\n */\n skillsCliAgent?: string\n}\n\n/**\n * The Sanity MCP server uses OAuth by default\n * If a token is provided, the server will not use OAuth instead tool calls will use the API token\n */\nconst defaultHttpConfig = (token?: string) => {\n const defaultConfig: Record<string, unknown> = {\n type: 'http',\n url: MCP_SERVER_URL,\n }\n\n if (token) {\n defaultConfig.headers = {Authorization: `Bearer ${token}`}\n }\n\n return defaultConfig\n}\n\n// -- Detect functions --\n\nasync function detectClaudeCode(ctx: DetectionEnv): Promise<string | null> {\n try {\n await ctx.execCommand('claude', ['--version'])\n return path.join(ctx.homedir, '.claude.json')\n } catch {\n return null\n }\n}\n\nasync function detectAntigravity(ctx: DetectionEnv): Promise<string | null> {\n const antigravityDir = path.join(ctx.homedir, '.gemini/antigravity')\n return ctx.existsSync(antigravityDir) ? path.join(antigravityDir, 'mcp_config.json') : null\n}\n\nexport function getVSCodeUserDir(\n ctx: DetectionEnv,\n variant: 'insiders' | 'stable' = 'stable',\n): string | null {\n switch (ctx.platform) {\n case 'darwin': {\n return path.join(\n ctx.homedir,\n variant === 'insiders'\n ? 'Library/Application Support/Code - Insiders/User'\n : 'Library/Application Support/Code/User',\n )\n }\n case 'win32': {\n if (!ctx.env.APPDATA) return null\n return path.join(\n ctx.env.APPDATA,\n variant === 'insiders' ? 'Code - Insiders/User' : 'Code/User',\n )\n }\n default: {\n return path.join(\n ctx.homedir,\n variant === 'insiders' ? '.config/Code - Insiders/User' : '.config/Code/User',\n )\n }\n }\n}\n\nasync function detectCline(ctx: DetectionEnv): Promise<string | null> {\n const vscodeUserDir = getVSCodeUserDir(ctx)\n if (!vscodeUserDir) return null\n const clineConfigDir = path.join(vscodeUserDir, 'globalStorage/saoudrizwan.claude-dev/settings')\n return ctx.existsSync(clineConfigDir)\n ? path.join(clineConfigDir, 'cline_mcp_settings.json')\n : null\n}\n\nasync function detectClineCli(ctx: DetectionEnv): Promise<string | null> {\n const clineHome = ctx.env.CLINE_DIR || path.join(ctx.homedir, '.cline')\n if (!ctx.existsSync(clineHome)) return null\n return path.join(clineHome, 'data/settings/cline_mcp_settings.json')\n}\n\nasync function detectCodexCli(ctx: DetectionEnv): Promise<string | null> {\n try {\n await ctx.execCommand('codex', ['--version'])\n const codexHome = ctx.env.CODEX_HOME || path.join(ctx.homedir, '.codex')\n return path.join(codexHome, 'config.toml')\n } catch {\n return null\n }\n}\n\nasync function detectCursor(ctx: DetectionEnv): Promise<string | null> {\n const cursorDir = path.join(ctx.homedir, '.cursor')\n return ctx.existsSync(cursorDir) ? path.join(cursorDir, 'mcp.json') : null\n}\n\nasync function detectGeminiCli(ctx: DetectionEnv): Promise<string | null> {\n // Antigravity stores its config under ~/.gemini/antigravity, so checking\n // only the parent ~/.gemini directory causes false Gemini CLI detection.\n const settingsPath = path.join(ctx.homedir, '.gemini/settings.json')\n return ctx.existsSync(settingsPath) ? settingsPath : null\n}\n\nasync function detectGitHubCopilotCli(ctx: DetectionEnv): Promise<string | null> {\n const copilotDir =\n ctx.platform === 'linux' && ctx.env.XDG_CONFIG_HOME\n ? path.join(ctx.env.XDG_CONFIG_HOME, 'copilot')\n : path.join(ctx.homedir, '.copilot')\n return ctx.existsSync(copilotDir) ? path.join(copilotDir, 'mcp-config.json') : null\n}\n\nasync function detectOpenCode(ctx: DetectionEnv): Promise<string | null> {\n try {\n await ctx.execCommand('opencode', ['--version'])\n return path.join(ctx.homedir, '.config/opencode/opencode.json')\n } catch {\n return null\n }\n}\n\nasync function detectVSCode(ctx: DetectionEnv): Promise<string | null> {\n const configDir = getVSCodeUserDir(ctx)\n return configDir && ctx.existsSync(configDir) ? path.join(configDir, 'mcp.json') : null\n}\n\nasync function detectVSCodeInsiders(ctx: DetectionEnv): Promise<string | null> {\n const configDir = getVSCodeUserDir(ctx, 'insiders')\n return configDir && ctx.existsSync(configDir) ? path.join(configDir, 'mcp.json') : null\n}\n\nasync function detectZed(ctx: DetectionEnv): Promise<string | null> {\n let configDir: string | null = null\n switch (ctx.platform) {\n case 'win32': {\n if (ctx.env.APPDATA) {\n configDir = path.join(ctx.env.APPDATA, 'Zed')\n }\n break\n }\n default: {\n configDir = path.join(ctx.homedir, '.config/zed')\n }\n }\n return configDir && ctx.existsSync(configDir) ? path.join(configDir, 'settings.json') : null\n}\n\nasync function detectMCPorter(ctx: DetectionEnv): Promise<string | null> {\n const mcporterDir = path.join(ctx.homedir, '.mcporter')\n if (!ctx.existsSync(mcporterDir)) return null\n\n const jsonPath = path.join(mcporterDir, 'mcporter.json')\n const jsoncPath = path.join(mcporterDir, 'mcporter.jsonc')\n if (ctx.existsSync(jsonPath)) return jsonPath\n if (ctx.existsSync(jsoncPath)) return jsoncPath\n return jsonPath\n}\n\n// -- Read token helpers --\n\n/**\n * Extract a Bearer token from a headers-like object.\n * Looks for `Authorization: \"Bearer <token>\"` and returns the token portion.\n */\nfunction extractBearerToken(headers: unknown): string | undefined {\n if (typeof headers !== 'object' || headers === null) return undefined\n const auth = (headers as Record<string, unknown>).Authorization\n if (typeof auth !== 'string') return undefined\n const match = auth.match(/^Bearer\\s+(.+)$/)\n return match?.[1]\n}\n\nfunction readTokenFromHeaders(serverConfig: Record<string, unknown>): string | undefined {\n return extractBearerToken(serverConfig.headers)\n}\n\nfunction readTokenFromHttpHeaders(serverConfig: Record<string, unknown>): string | undefined {\n return extractBearerToken(serverConfig.http_headers)\n}\n\n// -- Defaults & build server config functions --\n\n/** Most editors share these values — entries only need to declare `detect` + any overrides. */\nconst EDITOR_DEFAULTS = {\n buildServerConfig: defaultHttpConfig,\n configKey: 'mcpServers',\n format: 'jsonc' as const,\n oauthOnly: false,\n readToken: readTokenFromHeaders,\n}\n\nfunction buildAntigravityServerConfig(token: string): Record<string, unknown> {\n return {\n headers: {Authorization: `Bearer ${token}`},\n serverUrl: MCP_SERVER_URL,\n }\n}\n\nfunction buildClineServerConfig(token: string): Record<string, unknown> {\n return {\n disabled: false,\n headers: {Authorization: `Bearer ${token}`},\n type: 'streamableHttp',\n url: MCP_SERVER_URL,\n }\n}\n\nfunction buildCodexCliServerConfig(token: string): Record<string, unknown> {\n return {\n http_headers: {Authorization: `Bearer ${token}`},\n type: 'http',\n url: MCP_SERVER_URL,\n }\n}\n\nfunction buildGitHubCopilotCliServerConfig(token: string): Record<string, unknown> {\n return {\n headers: {Authorization: `Bearer ${token}`},\n tools: ['*'],\n type: 'http',\n url: MCP_SERVER_URL,\n }\n}\n\nfunction buildOpenCodeServerConfig(token: string): Record<string, unknown> {\n return {\n headers: {Authorization: `Bearer ${token}`},\n type: 'remote',\n url: MCP_SERVER_URL,\n }\n}\n\nfunction buildZedServerConfig(token: string): Record<string, unknown> {\n return {\n headers: {Authorization: `Bearer ${token}`},\n settings: {},\n url: MCP_SERVER_URL,\n }\n}\n\n/**\n * Centralized editor configuration including detection logic.\n * To add a new editor: add an entry here — EditorName type is derived automatically.\n *\n * Each entry includes a doc URL pointing to the source of truth for its\n * config path and format. When updating a path, verify against the linked\n * documentation first.\n */\nexport const EDITOR_CONFIGS = {\n // Doc: https://support.google.com/gemini/answer/16255176 (Antigravity / Project Mariner)\n Antigravity: {\n ...EDITOR_DEFAULTS,\n buildServerConfig: buildAntigravityServerConfig,\n detect: detectAntigravity,\n skillsCliAgent: 'antigravity',\n },\n // Doc: https://docs.anthropic.com/en/docs/claude-code/mcp\n // Path: ~/.claude.json Key: mcpServers\n 'Claude Code': {\n ...EDITOR_DEFAULTS,\n detect: detectClaudeCode,\n oauthOnly: true,\n skillsCliAgent: 'claude-code',\n },\n // Doc: https://github.com/cline/cline — VS Code extension (saoudrizwan.claude-dev)\n // Path: <VS Code User>/globalStorage/saoudrizwan.claude-dev/settings/cline_mcp_settings.json\n Cline: {\n ...EDITOR_DEFAULTS,\n buildServerConfig: buildClineServerConfig,\n detect: detectCline,\n skillsCliAgent: 'cline',\n },\n // Doc: https://github.com/cline/cline — standalone CLI mode\n // Path: $CLINE_DIR || ~/.cline/data/settings/cline_mcp_settings.json\n 'Cline CLI': {\n ...EDITOR_DEFAULTS,\n buildServerConfig: buildClineServerConfig,\n detect: detectClineCli,\n skillsCliAgent: 'cline',\n },\n // Doc: https://platform.openai.com/docs/guides/tools-remote-mcp#codex-cli\n // Path: $CODEX_HOME || ~/.codex/config.toml Key: mcp_servers Format: TOML\n 'Codex CLI': {\n ...EDITOR_DEFAULTS,\n buildServerConfig: buildCodexCliServerConfig,\n configKey: 'mcp_servers',\n detect: detectCodexCli,\n format: 'toml' as const,\n readToken: readTokenFromHttpHeaders,\n skillsCliAgent: 'codex',\n },\n // Doc: https://docs.cursor.com/context/model-context-protocol\n // Path: ~/.cursor/mcp.json Key: mcpServers\n Cursor: {\n ...EDITOR_DEFAULTS,\n detect: detectCursor,\n oauthOnly: true,\n skillsCliAgent: 'cursor',\n },\n // Doc: https://googlegemini.wiki/gemini-cli/mcp-servers\n // Path: ~/.gemini/settings.json Key: mcpServers\n 'Gemini CLI': {...EDITOR_DEFAULTS, detect: detectGeminiCli, skillsCliAgent: 'gemini-cli'},\n // Doc: https://docs.github.com/en/copilot/customizing-copilot/extending-copilot-coding-agent-with-mcp\n // Path: ~/.copilot/mcp-config.json (or $XDG_CONFIG_HOME/copilot on Linux) Key: mcpServers\n 'GitHub Copilot CLI': {\n ...EDITOR_DEFAULTS,\n buildServerConfig: buildGitHubCopilotCliServerConfig,\n detect: detectGitHubCopilotCli,\n skillsCliAgent: 'github-copilot',\n },\n // Doc: https://github.com/nicobailon/mcporter\n // Path: ~/.mcporter/mcporter.{json,jsonc} Key: mcpServers\n MCPorter: {...EDITOR_DEFAULTS, detect: detectMCPorter},\n // Doc: https://opencode.ai/docs/config\n // Path: ~/.config/opencode/opencode.json Key: mcp\n OpenCode: {\n ...EDITOR_DEFAULTS,\n buildServerConfig: buildOpenCodeServerConfig,\n configKey: 'mcp',\n detect: detectOpenCode,\n skillsCliAgent: 'opencode',\n },\n // Doc: https://code.visualstudio.com/docs/copilot/chat/mcp-servers\n // Path: <VS Code User dir>/mcp.json Key: servers\n // VS Code uses GitHub Copilot for AI features; skills are installed via the\n // `github-copilot` agent (see https://code.visualstudio.com/docs/copilot/customization/agent-skills).\n 'VS Code': {\n ...EDITOR_DEFAULTS,\n configKey: 'servers',\n detect: detectVSCode,\n skillsCliAgent: 'github-copilot',\n },\n // Doc: https://code.visualstudio.com/docs/copilot/chat/mcp-servers\n // Path: <VS Code Insiders User dir>/mcp.json Key: servers\n 'VS Code Insiders': {\n ...EDITOR_DEFAULTS,\n configKey: 'servers',\n detect: detectVSCodeInsiders,\n skillsCliAgent: 'github-copilot',\n },\n // Doc: https://zed.dev/docs/assistant/model-context-protocol\n // Path: ~/.config/zed/settings.json (or $APPDATA/Zed on Windows) Key: context_servers\n // Zed doesn't support agent skills - https://github.com/zed-industries/zed/issues/49057\n Zed: {\n ...EDITOR_DEFAULTS,\n buildServerConfig: buildZedServerConfig,\n configKey: 'context_servers',\n detect: detectZed,\n },\n} satisfies Record<string, EditorConfig>\n\n/** Derived from EDITOR_CONFIGS keys - add a new editor there and this updates automatically */\nexport type EditorName = keyof typeof EDITOR_CONFIGS\n\nexport function getSkillsCliAgent(editorName: EditorName): string | undefined {\n if (editorName in EDITOR_CONFIGS) {\n const config = EDITOR_CONFIGS[editorName]\n return 'skillsCliAgent' in config ? config.skillsCliAgent : undefined\n }\n}\n\n/**\n * Skills-CLI agent ID → display name. Mirrors `displayName` from\n * `~/git/skills/src/agents.ts` for the subset of agents we install for. Used\n * to match `skills list --json` output (which keys by display name) against\n * our editors.\n */\nconst SKILLS_CLI_AGENT_DISPLAY_NAMES: Record<string, string> = {\n antigravity: 'Antigravity',\n 'claude-code': 'Claude Code',\n cline: 'Cline',\n codex: 'Codex',\n cursor: 'Cursor',\n 'gemini-cli': 'Gemini CLI',\n 'github-copilot': 'GitHub Copilot',\n opencode: 'OpenCode',\n}\n\n/** Display name used by the skills CLI for the given editor, if it has a mapping. */\nexport function getSkillsCliAgentDisplayName(editorName: EditorName): string | undefined {\n const agent = getSkillsCliAgent(editorName)\n return agent ? SKILLS_CLI_AGENT_DISPLAY_NAMES[agent] : undefined\n}\n"],"names":["existsSync","os","path","execa","MCP_SERVER_URL","createDetectionEnv","env","process","execCommand","cmd","args","stdio","timeout","then","homedir","platform","defaultHttpConfig","token","defaultConfig","type","url","headers","Authorization","detectClaudeCode","ctx","join","detectAntigravity","antigravityDir","getVSCodeUserDir","variant","APPDATA","detectCline","vscodeUserDir","clineConfigDir","detectClineCli","clineHome","CLINE_DIR","detectCodexCli","codexHome","CODEX_HOME","detectCursor","cursorDir","detectGeminiCli","settingsPath","detectGitHubCopilotCli","copilotDir","XDG_CONFIG_HOME","detectOpenCode","detectVSCode","configDir","detectVSCodeInsiders","detectZed","detectMCPorter","mcporterDir","jsonPath","jsoncPath","extractBearerToken","undefined","auth","match","readTokenFromHeaders","serverConfig","readTokenFromHttpHeaders","http_headers","EDITOR_DEFAULTS","buildServerConfig","configKey","format","oauthOnly","readToken","buildAntigravityServerConfig","serverUrl","buildClineServerConfig","disabled","buildCodexCliServerConfig","buildGitHubCopilotCliServerConfig","tools","buildOpenCodeServerConfig","buildZedServerConfig","settings","EDITOR_CONFIGS","Antigravity","detect","skillsCliAgent","Cline","Cursor","MCPorter","OpenCode","Zed","getSkillsCliAgent","editorName","config","SKILLS_CLI_AGENT_DISPLAY_NAMES","antigravity","cline","codex","cursor","opencode","getSkillsCliAgentDisplayName","agent"],"mappings":"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"}
@@ -1,5 +1,9 @@
1
1
  import { checkbox } from '@sanity/cli-core/ux';
2
- function getEditorLabel(editor) {
2
+ function getEditorLabel(choice) {
3
+ const { action, editor } = choice;
4
+ if (action === 'skill-only') {
5
+ return `${editor.name} (skill only — MCP already configured)`;
6
+ }
3
7
  if (editor.configured && editor.authStatus === 'unauthorized') {
4
8
  return `${editor.name} (auth expired)`;
5
9
  }
@@ -9,25 +13,26 @@ function getEditorLabel(editor) {
9
13
  return editor.name;
10
14
  }
11
15
  /**
12
- * Prompt user to select which editors to configure.
16
+ * Prompt the user to select editors for MCP / skills setup. The caller is
17
+ * responsible for classifying editors into actions (see `EditorAction`) and
18
+ * for choosing an appropriate prompt message.
13
19
  *
14
- * Expects only actionable editors (unconfigured, or configured with
15
- * invalid/missing credentials). Annotates entries with auth status.
16
- */ export async function promptForMCPSetup(editors) {
17
- const editorChoices = editors.map((e)=>({
20
+ * Returns the subset of `choices` the user kept, or `null` when the user
21
+ * deselected everything.
22
+ */ export async function promptForMCPSetup({ choices, message }) {
23
+ const editorChoices = choices.map((choice)=>({
18
24
  checked: true,
19
- name: getEditorLabel(e),
20
- value: e.name
25
+ name: getEditorLabel(choice),
26
+ value: choice.editor.name
21
27
  }));
22
28
  const selectedNames = await checkbox({
23
29
  choices: editorChoices,
24
- message: 'Configure Sanity MCP server?'
30
+ message
25
31
  });
26
- // User can deselect all to skip
27
32
  if (!selectedNames || selectedNames.length === 0) {
28
33
  return null;
29
34
  }
30
- return editors.filter((e)=>selectedNames.includes(e.name));
35
+ return choices.filter((c)=>selectedNames.includes(c.editor.name));
31
36
  }
32
37
 
33
38
  //# sourceMappingURL=promptForMCPSetup.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/actions/mcp/promptForMCPSetup.ts"],"sourcesContent":["import {checkbox} from '@sanity/cli-core/ux'\n\nimport {type Editor} from './types.js'\n\nfunction getEditorLabel(editor: Editor): string {\n if (editor.configured && editor.authStatus === 'unauthorized') {\n return `${editor.name} (auth expired)`\n }\n if (editor.configured && !editor.existingToken) {\n return `${editor.name} (missing credentials)`\n }\n return editor.name\n}\n\n/**\n * Prompt user to select which editors to configure.\n *\n * Expects only actionable editors (unconfigured, or configured with\n * invalid/missing credentials). Annotates entries with auth status.\n */\nexport async function promptForMCPSetup(editors: Editor[]): Promise<Editor[] | null> {\n const editorChoices = editors.map((e) => ({\n checked: true, // Pre-select all actionable editors\n name: getEditorLabel(e),\n value: e.name,\n }))\n\n const selectedNames = await checkbox({\n choices: editorChoices,\n message: 'Configure Sanity MCP server?',\n })\n\n // User can deselect all to skip\n if (!selectedNames || selectedNames.length === 0) {\n return null\n }\n\n return editors.filter((e) => selectedNames.includes(e.name))\n}\n"],"names":["checkbox","getEditorLabel","editor","configured","authStatus","name","existingToken","promptForMCPSetup","editors","editorChoices","map","e","checked","value","selectedNames","choices","message","length","filter","includes"],"mappings":"AAAA,SAAQA,QAAQ,QAAO,sBAAqB;AAI5C,SAASC,eAAeC,MAAc;IACpC,IAAIA,OAAOC,UAAU,IAAID,OAAOE,UAAU,KAAK,gBAAgB;QAC7D,OAAO,GAAGF,OAAOG,IAAI,CAAC,eAAe,CAAC;IACxC;IACA,IAAIH,OAAOC,UAAU,IAAI,CAACD,OAAOI,aAAa,EAAE;QAC9C,OAAO,GAAGJ,OAAOG,IAAI,CAAC,sBAAsB,CAAC;IAC/C;IACA,OAAOH,OAAOG,IAAI;AACpB;AAEA;;;;;CAKC,GACD,OAAO,eAAeE,kBAAkBC,OAAiB;IACvD,MAAMC,gBAAgBD,QAAQE,GAAG,CAAC,CAACC,IAAO,CAAA;YACxCC,SAAS;YACTP,MAAMJ,eAAeU;YACrBE,OAAOF,EAAEN,IAAI;QACf,CAAA;IAEA,MAAMS,gBAAgB,MAAMd,SAAS;QACnCe,SAASN;QACTO,SAAS;IACX;IAEA,gCAAgC;IAChC,IAAI,CAACF,iBAAiBA,cAAcG,MAAM,KAAK,GAAG;QAChD,OAAO;IACT;IAEA,OAAOT,QAAQU,MAAM,CAAC,CAACP,IAAMG,cAAcK,QAAQ,CAACR,EAAEN,IAAI;AAC5D"}
1
+ {"version":3,"sources":["../../../src/actions/mcp/promptForMCPSetup.ts"],"sourcesContent":["import {checkbox} from '@sanity/cli-core/ux'\n\nimport {type Editor} from './types.js'\n\n/** Action to take for an editor in the combined MCP + skills setup prompt. */\nexport type EditorAction = 'mcp-and-skill' | 'mcp-only' | 'skill-only'\n\nexport interface EditorChoice {\n action: EditorAction\n editor: Editor\n}\n\nfunction getEditorLabel(choice: EditorChoice): string {\n const {action, editor} = choice\n if (action === 'skill-only') {\n return `${editor.name} (skill only — MCP already configured)`\n }\n if (editor.configured && editor.authStatus === 'unauthorized') {\n return `${editor.name} (auth expired)`\n }\n if (editor.configured && !editor.existingToken) {\n return `${editor.name} (missing credentials)`\n }\n return editor.name\n}\n\ninterface PromptOptions {\n choices: EditorChoice[]\n message: string\n}\n\n/**\n * Prompt the user to select editors for MCP / skills setup. The caller is\n * responsible for classifying editors into actions (see `EditorAction`) and\n * for choosing an appropriate prompt message.\n *\n * Returns the subset of `choices` the user kept, or `null` when the user\n * deselected everything.\n */\nexport async function promptForMCPSetup({\n choices,\n message,\n}: PromptOptions): Promise<EditorChoice[] | null> {\n const editorChoices = choices.map((choice) => ({\n checked: true,\n name: getEditorLabel(choice),\n value: choice.editor.name,\n }))\n\n const selectedNames = await checkbox({\n choices: editorChoices,\n message,\n })\n\n if (!selectedNames || selectedNames.length === 0) {\n return null\n }\n\n return choices.filter((c) => selectedNames.includes(c.editor.name))\n}\n"],"names":["checkbox","getEditorLabel","choice","action","editor","name","configured","authStatus","existingToken","promptForMCPSetup","choices","message","editorChoices","map","checked","value","selectedNames","length","filter","c","includes"],"mappings":"AAAA,SAAQA,QAAQ,QAAO,sBAAqB;AAY5C,SAASC,eAAeC,MAAoB;IAC1C,MAAM,EAACC,MAAM,EAAEC,MAAM,EAAC,GAAGF;IACzB,IAAIC,WAAW,cAAc;QAC3B,OAAO,GAAGC,OAAOC,IAAI,CAAC,sCAAsC,CAAC;IAC/D;IACA,IAAID,OAAOE,UAAU,IAAIF,OAAOG,UAAU,KAAK,gBAAgB;QAC7D,OAAO,GAAGH,OAAOC,IAAI,CAAC,eAAe,CAAC;IACxC;IACA,IAAID,OAAOE,UAAU,IAAI,CAACF,OAAOI,aAAa,EAAE;QAC9C,OAAO,GAAGJ,OAAOC,IAAI,CAAC,sBAAsB,CAAC;IAC/C;IACA,OAAOD,OAAOC,IAAI;AACpB;AAOA;;;;;;;CAOC,GACD,OAAO,eAAeI,kBAAkB,EACtCC,OAAO,EACPC,OAAO,EACO;IACd,MAAMC,gBAAgBF,QAAQG,GAAG,CAAC,CAACX,SAAY,CAAA;YAC7CY,SAAS;YACTT,MAAMJ,eAAeC;YACrBa,OAAOb,OAAOE,MAAM,CAACC,IAAI;QAC3B,CAAA;IAEA,MAAMW,gBAAgB,MAAMhB,SAAS;QACnCU,SAASE;QACTD;IACF;IAEA,IAAI,CAACK,iBAAiBA,cAAcC,MAAM,KAAK,GAAG;QAChD,OAAO;IACT;IAEA,OAAOP,QAAQQ,MAAM,CAAC,CAACC,IAAMH,cAAcI,QAAQ,CAACD,EAAEf,MAAM,CAACC,IAAI;AACnE"}
@@ -2,30 +2,116 @@ import { ux } from '@oclif/core';
2
2
  import { subdebug } from '@sanity/cli-core';
3
3
  import { logSymbols } from '@sanity/cli-core/ux';
4
4
  import { createMCPToken, MCP_SERVER_URL } from '../../services/mcp.js';
5
+ import { readSkillState } from '../skills/readSkillState.js';
6
+ import { SANITY_SKILL_NAME } from '../skills/setupSkills.js';
5
7
  import { detectAvailableEditors } from './detectAvailableEditors.js';
6
- import { EDITOR_CONFIGS } from './editorConfigs.js';
8
+ import { EDITOR_CONFIGS, getSkillsCliAgent, getSkillsCliAgentDisplayName } from './editorConfigs.js';
7
9
  import { promptForMCPSetup } from './promptForMCPSetup.js';
8
10
  import { validateEditorTokens } from './validateEditorTokens.js';
9
11
  import { writeMCPConfig } from './writeMCPConfig.js';
10
12
  const mcpDebug = subdebug('mcp:setup');
11
13
  const NO_EDITORS_DETECTED_MESSAGE = `Couldn't auto-configure Sanity MCP server for your editor. Visit ${MCP_SERVER_URL} for setup instructions.`;
12
14
  /**
13
- * Main MCP setup orchestration
14
- * Opt-out by default: runs automatically unless skip option is set
15
+ * Classify each editor into one of four actions based on MCP status and
16
+ * whether a Sanity skill is already installed for its skills-CLI agent.
17
+ */ function classifyEditors(editors) {
18
+ return editors.map((editor)=>{
19
+ const needsMCP = !editor.configured || editor.authStatus !== 'valid';
20
+ const skillsCliAgent = getSkillsCliAgent(editor.name);
21
+ const hasSkillMapping = Boolean(skillsCliAgent);
22
+ const skillInstalled = editor.skillInstalled === true;
23
+ if (needsMCP) {
24
+ return {
25
+ action: hasSkillMapping ? 'mcp-and-skill' : 'mcp-only',
26
+ editor
27
+ };
28
+ }
29
+ if (hasSkillMapping && !skillInstalled) {
30
+ return {
31
+ action: 'skill-only',
32
+ editor
33
+ };
34
+ }
35
+ return {
36
+ action: 'none',
37
+ editor
38
+ };
39
+ });
40
+ }
41
+ /**
42
+ * Apply masking based on the configured modes. `skip` modes mute the
43
+ * corresponding action so we never prompt for or run work the user opted out
44
+ * of via `--no-mcp` / `--no-skills`.
45
+ */ function applyMasking(classified, mcpMode, skillsMode) {
46
+ const actionable = [];
47
+ for (const { action, editor } of classified){
48
+ if (action === 'none') continue;
49
+ if (mcpMode === 'skip' && skillsMode === 'skip') continue;
50
+ if (mcpMode === 'skip') {
51
+ // No MCP writes — keep only skill-only / mcp-and-skill (downgraded to skill-only)
52
+ if (action === 'mcp-only') continue;
53
+ if (action === 'mcp-and-skill') {
54
+ actionable.push({
55
+ action: 'skill-only',
56
+ editor
57
+ });
58
+ continue;
59
+ }
60
+ actionable.push({
61
+ action,
62
+ editor
63
+ });
64
+ continue;
65
+ }
66
+ if (skillsMode === 'skip') {
67
+ // No skill install — drop skill-only, downgrade mcp-and-skill → mcp-only
68
+ if (action === 'skill-only') continue;
69
+ if (action === 'mcp-and-skill') {
70
+ actionable.push({
71
+ action: 'mcp-only',
72
+ editor
73
+ });
74
+ continue;
75
+ }
76
+ actionable.push({
77
+ action,
78
+ editor
79
+ });
80
+ continue;
81
+ }
82
+ actionable.push({
83
+ action,
84
+ editor
85
+ });
86
+ }
87
+ return actionable;
88
+ }
89
+ function getPromptMessage(mcpMode, skillsMode) {
90
+ if (mcpMode === 'skip') return 'Install Sanity agent skills for these editors?';
91
+ if (skillsMode === 'skip') return 'Configure Sanity MCP server?';
92
+ return 'Configure Sanity MCP and install agent skills for these editors?';
93
+ }
94
+ /**
95
+ * Main MCP setup orchestration.
96
+ *
97
+ * When `skillsMode !== 'skip'`, the prompt combines MCP and skill offers,
98
+ * and the result includes `skillsToInstall` — agent IDs the caller should
99
+ * install via `setupSkills`. `setupMCP` itself never installs skills.
15
100
  */ export async function setupMCP(options) {
16
- const { explicit = false, mode = 'prompt' } = options ?? {};
17
- // 1. Check for explicit opt-out
18
- if (mode === 'skip') {
19
- mcpDebug('Skipping MCP configuration (mode: skip)');
101
+ const { explicit = false, mode: mcpMode = 'prompt', skillsMode = 'skip' } = options ?? {};
102
+ // 1. Both opted out → nothing to do.
103
+ if (mcpMode === 'skip' && skillsMode === 'skip') {
104
+ mcpDebug('Skipping setup (mcpMode: skip, skillsMode: skip)');
20
105
  return {
21
106
  alreadyConfiguredEditors: [],
22
107
  configuredEditors: [],
23
108
  detectedEditors: [],
109
+ skillsToInstall: [],
24
110
  skipped: true
25
111
  };
26
112
  }
27
113
  // 2. Detect available editors (filters out unparseable configs)
28
- const editors = await detectAvailableEditors();
114
+ const editors = options?.editors ?? await detectAvailableEditors();
29
115
  const detectedEditors = editors.map((e)=>e.name);
30
116
  mcpDebug('Detected %d editors: %s', detectedEditors.length, detectedEditors);
31
117
  if (editors.length === 0) {
@@ -36,16 +122,31 @@ const NO_EDITORS_DETECTED_MESSAGE = `Couldn't auto-configure Sanity MCP server f
36
122
  alreadyConfiguredEditors: [],
37
123
  configuredEditors: [],
38
124
  detectedEditors,
125
+ skillsToInstall: [],
39
126
  skipped: true
40
127
  };
41
128
  }
42
129
  // 3. Validate existing tokens against the Sanity API
43
130
  await validateEditorTokens(editors);
44
- // 4. Check if there's anything actionable
45
- const actionable = editors.filter((e)=>!e.configured || e.authStatus !== 'valid');
131
+ // 4. Read skill state when skills are in scope so classification can dedup
132
+ if (skillsMode !== 'skip') {
133
+ const { installedAgentDisplayNames } = await readSkillState({
134
+ skillName: SANITY_SKILL_NAME
135
+ });
136
+ for (const editor of editors){
137
+ const displayName = getSkillsCliAgentDisplayName(editor.name);
138
+ editor.skillInstalled = displayName ? installedAgentDisplayNames.has(displayName) : false;
139
+ }
140
+ }
141
+ // 5. Classify + mask
142
+ const classified = classifyEditors(editors);
143
+ const actionable = applyMasking(classified, mcpMode, skillsMode);
144
+ // "Already configured" surfaces editors whose MCP setup is valid (skill
145
+ // state doesn't matter for this signal — that's what skillsToInstall is for).
146
+ const actionableNames = new Set(actionable.map((c)=>c.editor.name));
147
+ const alreadyConfiguredEditors = editors.filter((e)=>e.configured && e.authStatus === 'valid' && !actionableNames.has(e.name)).map((e)=>e.name);
46
148
  if (actionable.length === 0) {
47
- mcpDebug('All editors configured with valid credentials');
48
- const alreadyConfiguredEditors = editors.filter((e)=>e.configured && e.authStatus === 'valid').map((e)=>e.name);
149
+ mcpDebug('Nothing actionable after classification + masking');
49
150
  if (explicit) {
50
151
  ux.stdout(`${logSymbols.success} All detected editors are already configured`);
51
152
  }
@@ -53,76 +154,94 @@ const NO_EDITORS_DETECTED_MESSAGE = `Couldn't auto-configure Sanity MCP server f
53
154
  alreadyConfiguredEditors,
54
155
  configuredEditors: [],
55
156
  detectedEditors,
157
+ skillsToInstall: [],
56
158
  skipped: true
57
159
  };
58
160
  }
59
- // Non-actionable editors are already configured with valid credentials
60
- const alreadyConfiguredEditors = editors.filter((e)=>!actionable.includes(e)).map((e)=>e.name);
61
- // 5. Select editors to configure prompt interactively or auto-select all
62
- const selected = mode === 'auto' ? actionable : await promptForMCPSetup(actionable);
161
+ // 6. Select editors to configure prompt interactively or auto-select all.
162
+ // We only auto when neither side wants a prompt: MCP auto, or (MCP skip
163
+ // + skills auto). Anything that asks `mode: 'prompt'` for MCP wins the
164
+ // prompt even when skills would have auto-installed.
165
+ const shouldAuto = mcpMode === 'auto' || mcpMode === 'skip' && skillsMode === 'auto';
166
+ const selected = shouldAuto ? actionable : await promptForMCPSetup({
167
+ choices: actionable,
168
+ message: getPromptMessage(mcpMode, skillsMode)
169
+ });
63
170
  if (!selected || selected.length === 0) {
64
- // User deselected all editors
65
171
  ux.stdout('MCP configuration skipped');
66
172
  return {
67
173
  alreadyConfiguredEditors,
68
174
  configuredEditors: [],
69
175
  detectedEditors,
176
+ skillsToInstall: [],
70
177
  skipped: true
71
178
  };
72
179
  }
73
- // 6. Get a tokenreuse a valid existing one or create a new one
180
+ // 7. MCP write phaseonly for choices that need MCP
181
+ const mcpSelected = selected.filter((c)=>c.action === 'mcp-only' || c.action === 'mcp-and-skill');
74
182
  let token;
75
- // Look for an existing valid token we can reuse
76
- const validEditor = editors.find((e)=>e.authStatus === 'valid' && e.existingToken);
77
- if (validEditor?.existingToken) {
78
- mcpDebug('Reusing valid token from %s', validEditor.name);
79
- token = validEditor.existingToken;
80
- }
81
- const allOAuth = selected.every((e)=>EDITOR_CONFIGS[e.name].oauthOnly);
82
- // Fall back to creating a new token
83
- // If all editors use OAuth, we don't need to create a token
84
- if (!token && !allOAuth) {
85
- try {
86
- token = await createMCPToken();
87
- } catch (error) {
88
- const err = error instanceof Error ? error : new Error(String(error));
89
- mcpDebug('Error creating MCP token', error);
90
- ux.warn(`Could not configure MCP: ${err.message}`);
91
- ux.warn('You can set up MCP manually later using https://mcp.sanity.io');
92
- return {
93
- alreadyConfiguredEditors,
94
- configuredEditors: [],
95
- detectedEditors,
96
- error: err,
97
- skipped: false
98
- };
183
+ const configuredEditors = [];
184
+ let mcpError;
185
+ if (mcpSelected.length > 0) {
186
+ const validEditor = editors.find((e)=>e.authStatus === 'valid' && e.existingToken);
187
+ if (validEditor?.existingToken) {
188
+ mcpDebug('Reusing valid token from %s', validEditor.name);
189
+ token = validEditor.existingToken;
190
+ }
191
+ const allOAuth = mcpSelected.every((c)=>EDITOR_CONFIGS[c.editor.name].oauthOnly);
192
+ if (!token && !allOAuth) {
193
+ try {
194
+ token = await createMCPToken();
195
+ } catch (error) {
196
+ const err = error instanceof Error ? error : new Error(String(error));
197
+ mcpDebug('Error creating MCP token', error);
198
+ ux.warn(`Could not configure MCP: ${err.message}`);
199
+ ux.warn('You can set up MCP manually later using https://mcp.sanity.io');
200
+ mcpError = err;
201
+ }
202
+ }
203
+ if (!mcpError) {
204
+ for (const choice of mcpSelected){
205
+ try {
206
+ await writeMCPConfig(choice.editor, token);
207
+ configuredEditors.push(choice.editor.name);
208
+ } catch (error) {
209
+ const err = error instanceof Error ? error : new Error(String(error));
210
+ mcpDebug('Error writing MCP config for %s: %O', choice.editor.name, error);
211
+ ux.warn(`Could not configure MCP for ${choice.editor.name}: ${err.message}`);
212
+ ux.warn('You can set up MCP manually later using https://mcp.sanity.io');
213
+ mcpError = err;
214
+ }
215
+ }
216
+ }
217
+ if (configuredEditors.length > 0) {
218
+ ux.stdout(`${logSymbols.success} MCP configured for ${configuredEditors.join(', ')}`);
99
219
  }
100
220
  }
101
- // 7. Write configs for each selected editor
102
- const configuredEditors = [];
103
- try {
104
- for (const editor of selected){
105
- await writeMCPConfig(editor, token);
106
- configuredEditors.push(editor.name);
221
+ // 8. Build skillsToInstall — only for choices the user kept, only when the
222
+ // associated MCP write succeeded (or wasn't needed).
223
+ const skillsToInstall = [];
224
+ if (skillsMode !== 'skip') {
225
+ for (const choice of selected){
226
+ if (choice.action === 'skill-only') {
227
+ const agent = getSkillsCliAgent(choice.editor.name);
228
+ if (agent) skillsToInstall.push(agent);
229
+ continue;
230
+ }
231
+ if (choice.action === 'mcp-and-skill' && configuredEditors.includes(choice.editor.name)) {
232
+ const agent = getSkillsCliAgent(choice.editor.name);
233
+ if (agent) skillsToInstall.push(agent);
234
+ }
107
235
  }
108
- } catch (error) {
109
- const err = error instanceof Error ? error : new Error(String(error));
110
- mcpDebug('Error writing MCP config', error);
111
- ux.warn(`Could not configure MCP: ${err.message}`);
112
- ux.warn('You can set up MCP manually later using https://mcp.sanity.io');
113
- return {
114
- alreadyConfiguredEditors,
115
- configuredEditors,
116
- detectedEditors,
117
- error: err,
118
- skipped: false
119
- };
120
236
  }
121
- ux.stdout(`${logSymbols.success} MCP configured for ${configuredEditors.join(', ')}`);
122
237
  return {
123
238
  alreadyConfiguredEditors,
124
239
  configuredEditors,
125
240
  detectedEditors,
241
+ error: mcpError,
242
+ skillsToInstall: [
243
+ ...new Set(skillsToInstall)
244
+ ],
126
245
  skipped: false
127
246
  };
128
247
  }
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/actions/mcp/setupMCP.ts"],"sourcesContent":["import {ux} from '@oclif/core'\nimport {subdebug} from '@sanity/cli-core'\nimport {logSymbols} from '@sanity/cli-core/ux'\n\nimport {createMCPToken, MCP_SERVER_URL} from '../../services/mcp.js'\nimport {detectAvailableEditors} from './detectAvailableEditors.js'\nimport {EDITOR_CONFIGS, type EditorName} from './editorConfigs.js'\nimport {promptForMCPSetup} from './promptForMCPSetup.js'\nimport {validateEditorTokens} from './validateEditorTokens.js'\nimport {writeMCPConfig} from './writeMCPConfig.js'\n\nconst mcpDebug = subdebug('mcp:setup')\n\nconst NO_EDITORS_DETECTED_MESSAGE = `Couldn't auto-configure Sanity MCP server for your editor. Visit ${MCP_SERVER_URL} for setup instructions.`\n\ninterface MCPSetupOptions {\n /**\n * Whether the user explicitly requested MCP configuration (e.g. `sanity mcp configure`).\n * When true, shows status messages even when there's nothing to do.\n * When false/undefined (e.g. called from `sanity init`), stays quiet.\n */\n explicit?: boolean\n\n /**\n * Controls how MCP setup behaves:\n * - 'prompt': Ask the user which editors to configure (default)\n * - 'auto': Auto-configure all detected editors without prompting\n * - 'skip': Skip MCP configuration entirely\n */\n mode?: 'auto' | 'prompt' | 'skip'\n}\n\ninterface MCPSetupResult {\n /** Editors that were already configured with valid credentials (nothing to do) */\n alreadyConfiguredEditors: EditorName[]\n configuredEditors: EditorName[]\n detectedEditors: EditorName[]\n skipped: boolean\n\n error?: Error\n}\n\n/**\n * Main MCP setup orchestration\n * Opt-out by default: runs automatically unless skip option is set\n */\nexport async function setupMCP(options?: MCPSetupOptions): Promise<MCPSetupResult> {\n const {explicit = false, mode = 'prompt'} = options ?? {}\n\n // 1. Check for explicit opt-out\n if (mode === 'skip') {\n mcpDebug('Skipping MCP configuration (mode: skip)')\n return {\n alreadyConfiguredEditors: [],\n configuredEditors: [],\n detectedEditors: [],\n skipped: true,\n }\n }\n\n // 2. Detect available editors (filters out unparseable configs)\n const editors = await detectAvailableEditors()\n const detectedEditors = editors.map((e) => e.name)\n\n mcpDebug('Detected %d editors: %s', detectedEditors.length, detectedEditors)\n\n if (editors.length === 0) {\n if (explicit) {\n ux.warn(NO_EDITORS_DETECTED_MESSAGE)\n }\n return {\n alreadyConfiguredEditors: [],\n configuredEditors: [],\n detectedEditors,\n skipped: true,\n }\n }\n\n // 3. Validate existing tokens against the Sanity API\n await validateEditorTokens(editors)\n\n // 4. Check if there's anything actionable\n const actionable = editors.filter((e) => !e.configured || e.authStatus !== 'valid')\n\n if (actionable.length === 0) {\n mcpDebug('All editors configured with valid credentials')\n const alreadyConfiguredEditors = editors\n .filter((e) => e.configured && e.authStatus === 'valid')\n .map((e) => e.name)\n if (explicit) {\n ux.stdout(`${logSymbols.success} All detected editors are already configured`)\n }\n return {\n alreadyConfiguredEditors,\n configuredEditors: [],\n detectedEditors,\n skipped: true,\n }\n }\n\n // Non-actionable editors are already configured with valid credentials\n const alreadyConfiguredEditors = editors.filter((e) => !actionable.includes(e)).map((e) => e.name)\n\n // 5. Select editors to configure — prompt interactively or auto-select all\n const selected = mode === 'auto' ? actionable : await promptForMCPSetup(actionable)\n\n if (!selected || selected.length === 0) {\n // User deselected all editors\n ux.stdout('MCP configuration skipped')\n return {\n alreadyConfiguredEditors,\n configuredEditors: [],\n detectedEditors,\n skipped: true,\n }\n }\n\n // 6. Get a token — reuse a valid existing one or create a new one\n let token: string | undefined\n\n // Look for an existing valid token we can reuse\n const validEditor = editors.find((e) => e.authStatus === 'valid' && e.existingToken)\n if (validEditor?.existingToken) {\n mcpDebug('Reusing valid token from %s', validEditor.name)\n token = validEditor.existingToken\n }\n\n const allOAuth = selected.every((e) => EDITOR_CONFIGS[e.name].oauthOnly)\n\n // Fall back to creating a new token\n // If all editors use OAuth, we don't need to create a token\n if (!token && !allOAuth) {\n try {\n token = await createMCPToken()\n } catch (error) {\n const err = error instanceof Error ? error : new Error(String(error))\n mcpDebug('Error creating MCP token', error)\n ux.warn(`Could not configure MCP: ${err.message}`)\n ux.warn('You can set up MCP manually later using https://mcp.sanity.io')\n return {\n alreadyConfiguredEditors,\n configuredEditors: [],\n detectedEditors,\n error: err,\n skipped: false,\n }\n }\n }\n\n // 7. Write configs for each selected editor\n const configuredEditors: EditorName[] = []\n try {\n for (const editor of selected) {\n await writeMCPConfig(editor, token)\n configuredEditors.push(editor.name)\n }\n } catch (error) {\n const err = error instanceof Error ? error : new Error(String(error))\n mcpDebug('Error writing MCP config', error)\n ux.warn(`Could not configure MCP: ${err.message}`)\n ux.warn('You can set up MCP manually later using https://mcp.sanity.io')\n return {\n alreadyConfiguredEditors,\n configuredEditors,\n detectedEditors,\n error: err,\n skipped: false,\n }\n }\n\n ux.stdout(`${logSymbols.success} MCP configured for ${configuredEditors.join(', ')}`)\n\n return {\n alreadyConfiguredEditors,\n configuredEditors,\n detectedEditors,\n skipped: false,\n }\n}\n"],"names":["ux","subdebug","logSymbols","createMCPToken","MCP_SERVER_URL","detectAvailableEditors","EDITOR_CONFIGS","promptForMCPSetup","validateEditorTokens","writeMCPConfig","mcpDebug","NO_EDITORS_DETECTED_MESSAGE","setupMCP","options","explicit","mode","alreadyConfiguredEditors","configuredEditors","detectedEditors","skipped","editors","map","e","name","length","warn","actionable","filter","configured","authStatus","stdout","success","includes","selected","token","validEditor","find","existingToken","allOAuth","every","oauthOnly","error","err","Error","String","message","editor","push","join"],"mappings":"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"}
1
+ {"version":3,"sources":["../../../src/actions/mcp/setupMCP.ts"],"sourcesContent":["import {ux} from '@oclif/core'\nimport {subdebug} from '@sanity/cli-core'\nimport {logSymbols} from '@sanity/cli-core/ux'\n\nimport {createMCPToken, MCP_SERVER_URL} from '../../services/mcp.js'\nimport {readSkillState} from '../skills/readSkillState.js'\nimport {SANITY_SKILL_NAME} from '../skills/setupSkills.js'\nimport {detectAvailableEditors} from './detectAvailableEditors.js'\nimport {\n EDITOR_CONFIGS,\n type EditorName,\n getSkillsCliAgent,\n getSkillsCliAgentDisplayName,\n} from './editorConfigs.js'\nimport {type EditorAction, type EditorChoice, promptForMCPSetup} from './promptForMCPSetup.js'\nimport {type Editor} from './types.js'\nimport {validateEditorTokens} from './validateEditorTokens.js'\nimport {writeMCPConfig} from './writeMCPConfig.js'\n\nconst mcpDebug = subdebug('mcp:setup')\n\nconst NO_EDITORS_DETECTED_MESSAGE = `Couldn't auto-configure Sanity MCP server for your editor. Visit ${MCP_SERVER_URL} for setup instructions.`\n\ntype Mode = 'auto' | 'prompt' | 'skip'\n\ninterface MCPSetupOptions {\n /**\n * Pre-detected editors. When omitted, `detectAvailableEditors()` is called.\n * Accepting this from the caller avoids re-running detection (which probes\n * the filesystem and shells out to CLI binaries) when the result is already\n * available — e.g. when `sanity init` runs both MCP and skills setup.\n */\n editors?: Editor[]\n\n /**\n * Whether the user explicitly requested MCP configuration (e.g. `sanity mcp configure`).\n * When true, shows status messages even when there's nothing to do.\n * When false/undefined (e.g. called from `sanity init`), stays quiet.\n */\n explicit?: boolean\n\n /**\n * Controls how MCP setup behaves:\n * - 'prompt': Ask the user which editors to configure (default)\n * - 'auto': Auto-configure all detected editors without prompting\n * - 'skip': Skip MCP configuration entirely\n */\n mode?: Mode\n\n /**\n * Controls whether skills install is also offered in the same prompt:\n * - 'prompt': Combine MCP + skills offers in one checkbox\n * - 'auto': Combine, but skip the prompt and select everything\n * - 'skip' (default): Skip skills entirely — today's MCP-only behavior\n */\n skillsMode?: Mode\n}\n\ninterface MCPSetupResult {\n /** Editors that were already configured with valid credentials (nothing to do) */\n alreadyConfiguredEditors: EditorName[]\n configuredEditors: EditorName[]\n detectedEditors: EditorName[]\n /** Skills-CLI agent IDs that the caller should install. Deduplicated. */\n skillsToInstall: string[]\n skipped: boolean\n\n error?: Error\n}\n\ninterface ClassifiedEditor {\n action: 'none' | EditorAction\n editor: Editor\n}\n\n/**\n * Classify each editor into one of four actions based on MCP status and\n * whether a Sanity skill is already installed for its skills-CLI agent.\n */\nfunction classifyEditors(editors: Editor[]): ClassifiedEditor[] {\n return editors.map((editor) => {\n const needsMCP = !editor.configured || editor.authStatus !== 'valid'\n const skillsCliAgent = getSkillsCliAgent(editor.name)\n const hasSkillMapping = Boolean(skillsCliAgent)\n const skillInstalled = editor.skillInstalled === true\n\n if (needsMCP) {\n return {action: hasSkillMapping ? 'mcp-and-skill' : 'mcp-only', editor}\n }\n if (hasSkillMapping && !skillInstalled) {\n return {action: 'skill-only', editor}\n }\n return {action: 'none', editor}\n })\n}\n\n/**\n * Apply masking based on the configured modes. `skip` modes mute the\n * corresponding action so we never prompt for or run work the user opted out\n * of via `--no-mcp` / `--no-skills`.\n */\nfunction applyMasking(\n classified: ClassifiedEditor[],\n mcpMode: Mode,\n skillsMode: Mode,\n): EditorChoice[] {\n const actionable: EditorChoice[] = []\n\n for (const {action, editor} of classified) {\n if (action === 'none') continue\n\n if (mcpMode === 'skip' && skillsMode === 'skip') continue\n\n if (mcpMode === 'skip') {\n // No MCP writes — keep only skill-only / mcp-and-skill (downgraded to skill-only)\n if (action === 'mcp-only') continue\n if (action === 'mcp-and-skill') {\n actionable.push({action: 'skill-only', editor})\n continue\n }\n actionable.push({action, editor})\n continue\n }\n\n if (skillsMode === 'skip') {\n // No skill install — drop skill-only, downgrade mcp-and-skill → mcp-only\n if (action === 'skill-only') continue\n if (action === 'mcp-and-skill') {\n actionable.push({action: 'mcp-only', editor})\n continue\n }\n actionable.push({action, editor})\n continue\n }\n\n actionable.push({action, editor})\n }\n\n return actionable\n}\n\nfunction getPromptMessage(mcpMode: Mode, skillsMode: Mode): string {\n if (mcpMode === 'skip') return 'Install Sanity agent skills for these editors?'\n if (skillsMode === 'skip') return 'Configure Sanity MCP server?'\n return 'Configure Sanity MCP and install agent skills for these editors?'\n}\n\n/**\n * Main MCP setup orchestration.\n *\n * When `skillsMode !== 'skip'`, the prompt combines MCP and skill offers,\n * and the result includes `skillsToInstall` — agent IDs the caller should\n * install via `setupSkills`. `setupMCP` itself never installs skills.\n */\nexport async function setupMCP(options?: MCPSetupOptions): Promise<MCPSetupResult> {\n const {explicit = false, mode: mcpMode = 'prompt', skillsMode = 'skip'} = options ?? {}\n\n // 1. Both opted out → nothing to do.\n if (mcpMode === 'skip' && skillsMode === 'skip') {\n mcpDebug('Skipping setup (mcpMode: skip, skillsMode: skip)')\n return {\n alreadyConfiguredEditors: [],\n configuredEditors: [],\n detectedEditors: [],\n skillsToInstall: [],\n skipped: true,\n }\n }\n\n // 2. Detect available editors (filters out unparseable configs)\n const editors = options?.editors ?? (await detectAvailableEditors())\n const detectedEditors = editors.map((e) => e.name)\n\n mcpDebug('Detected %d editors: %s', detectedEditors.length, detectedEditors)\n\n if (editors.length === 0) {\n if (explicit) {\n ux.warn(NO_EDITORS_DETECTED_MESSAGE)\n }\n return {\n alreadyConfiguredEditors: [],\n configuredEditors: [],\n detectedEditors,\n skillsToInstall: [],\n skipped: true,\n }\n }\n\n // 3. Validate existing tokens against the Sanity API\n await validateEditorTokens(editors)\n\n // 4. Read skill state when skills are in scope so classification can dedup\n if (skillsMode !== 'skip') {\n const {installedAgentDisplayNames} = await readSkillState({skillName: SANITY_SKILL_NAME})\n for (const editor of editors) {\n const displayName = getSkillsCliAgentDisplayName(editor.name)\n editor.skillInstalled = displayName ? installedAgentDisplayNames.has(displayName) : false\n }\n }\n\n // 5. Classify + mask\n const classified = classifyEditors(editors)\n const actionable = applyMasking(classified, mcpMode, skillsMode)\n\n // \"Already configured\" surfaces editors whose MCP setup is valid (skill\n // state doesn't matter for this signal — that's what skillsToInstall is for).\n const actionableNames = new Set(actionable.map((c) => c.editor.name))\n const alreadyConfiguredEditors = editors\n .filter((e) => e.configured && e.authStatus === 'valid' && !actionableNames.has(e.name))\n .map((e) => e.name)\n\n if (actionable.length === 0) {\n mcpDebug('Nothing actionable after classification + masking')\n if (explicit) {\n ux.stdout(`${logSymbols.success} All detected editors are already configured`)\n }\n return {\n alreadyConfiguredEditors,\n configuredEditors: [],\n detectedEditors,\n skillsToInstall: [],\n skipped: true,\n }\n }\n\n // 6. Select editors to configure — prompt interactively or auto-select all.\n // We only auto when neither side wants a prompt: MCP auto, or (MCP skip\n // + skills auto). Anything that asks `mode: 'prompt'` for MCP wins the\n // prompt even when skills would have auto-installed.\n const shouldAuto = mcpMode === 'auto' || (mcpMode === 'skip' && skillsMode === 'auto')\n const selected = shouldAuto\n ? actionable\n : await promptForMCPSetup({\n choices: actionable,\n message: getPromptMessage(mcpMode, skillsMode),\n })\n\n if (!selected || selected.length === 0) {\n ux.stdout('MCP configuration skipped')\n return {\n alreadyConfiguredEditors,\n configuredEditors: [],\n detectedEditors,\n skillsToInstall: [],\n skipped: true,\n }\n }\n\n // 7. MCP write phase — only for choices that need MCP\n const mcpSelected = selected.filter(\n (c) => c.action === 'mcp-only' || c.action === 'mcp-and-skill',\n )\n\n let token: string | undefined\n const configuredEditors: EditorName[] = []\n let mcpError: Error | undefined\n\n if (mcpSelected.length > 0) {\n const validEditor = editors.find((e) => e.authStatus === 'valid' && e.existingToken)\n if (validEditor?.existingToken) {\n mcpDebug('Reusing valid token from %s', validEditor.name)\n token = validEditor.existingToken\n }\n\n const allOAuth = mcpSelected.every((c) => EDITOR_CONFIGS[c.editor.name].oauthOnly)\n\n if (!token && !allOAuth) {\n try {\n token = await createMCPToken()\n } catch (error) {\n const err = error instanceof Error ? error : new Error(String(error))\n mcpDebug('Error creating MCP token', error)\n ux.warn(`Could not configure MCP: ${err.message}`)\n ux.warn('You can set up MCP manually later using https://mcp.sanity.io')\n mcpError = err\n }\n }\n\n if (!mcpError) {\n for (const choice of mcpSelected) {\n try {\n await writeMCPConfig(choice.editor, token)\n configuredEditors.push(choice.editor.name)\n } catch (error) {\n const err = error instanceof Error ? error : new Error(String(error))\n mcpDebug('Error writing MCP config for %s: %O', choice.editor.name, error)\n ux.warn(`Could not configure MCP for ${choice.editor.name}: ${err.message}`)\n ux.warn('You can set up MCP manually later using https://mcp.sanity.io')\n mcpError = err\n }\n }\n }\n\n if (configuredEditors.length > 0) {\n ux.stdout(`${logSymbols.success} MCP configured for ${configuredEditors.join(', ')}`)\n }\n }\n\n // 8. Build skillsToInstall — only for choices the user kept, only when the\n // associated MCP write succeeded (or wasn't needed).\n const skillsToInstall: string[] = []\n if (skillsMode !== 'skip') {\n for (const choice of selected) {\n if (choice.action === 'skill-only') {\n const agent = getSkillsCliAgent(choice.editor.name)\n if (agent) skillsToInstall.push(agent)\n continue\n }\n if (choice.action === 'mcp-and-skill' && configuredEditors.includes(choice.editor.name)) {\n const agent = getSkillsCliAgent(choice.editor.name)\n if (agent) skillsToInstall.push(agent)\n }\n }\n }\n\n return {\n alreadyConfiguredEditors,\n configuredEditors,\n detectedEditors,\n error: mcpError,\n skillsToInstall: [...new Set(skillsToInstall)],\n skipped: false,\n }\n}\n"],"names":["ux","subdebug","logSymbols","createMCPToken","MCP_SERVER_URL","readSkillState","SANITY_SKILL_NAME","detectAvailableEditors","EDITOR_CONFIGS","getSkillsCliAgent","getSkillsCliAgentDisplayName","promptForMCPSetup","validateEditorTokens","writeMCPConfig","mcpDebug","NO_EDITORS_DETECTED_MESSAGE","classifyEditors","editors","map","editor","needsMCP","configured","authStatus","skillsCliAgent","name","hasSkillMapping","Boolean","skillInstalled","action","applyMasking","classified","mcpMode","skillsMode","actionable","push","getPromptMessage","setupMCP","options","explicit","mode","alreadyConfiguredEditors","configuredEditors","detectedEditors","skillsToInstall","skipped","e","length","warn","installedAgentDisplayNames","skillName","displayName","has","actionableNames","Set","c","filter","stdout","success","shouldAuto","selected","choices","message","mcpSelected","token","mcpError","validEditor","find","existingToken","allOAuth","every","oauthOnly","error","err","Error","String","choice","join","agent","includes"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/actions/mcp/types.ts"],"sourcesContent":["import {type EditorName} from './editorConfigs.js'\n\n/** Auth credential status for a configured editor */\nexport type AuthStatus = 'unauthorized' | 'valid'\n\nexport interface Editor {\n configPath: string\n /** Whether Sanity MCP is already configured for this editor */\n configured: boolean\n name: EditorName\n\n /**\n * Auth status of the existing token. Only set for editors that have\n * a Sanity MCP config with a token that has been validated against the API.\n */\n authStatus?: AuthStatus\n /** The existing auth token found in the editor config, if any */\n existingToken?: string\n}\n"],"names":[],"mappings":"AAKA,WAaC"}
1
+ {"version":3,"sources":["../../../src/actions/mcp/types.ts"],"sourcesContent":["import {type EditorName} from './editorConfigs.js'\n\n/** Auth credential status for a configured editor */\nexport type AuthStatus = 'unauthorized' | 'valid'\n\nexport interface Editor {\n configPath: string\n /** Whether Sanity MCP is already configured for this editor */\n configured: boolean\n name: EditorName\n\n /**\n * Auth status of the existing token. Only set for editors that have\n * a Sanity MCP config with a token that has been validated against the API.\n */\n authStatus?: AuthStatus\n /** The existing auth token found in the editor config, if any */\n existingToken?: string\n /**\n * Whether the Sanity agent skill is already installed globally for this\n * editor's skills-CLI agent. Populated during setup classification when\n * skill state has been probed; absent when skill installation isn't being\n * considered (e.g. `mcp configure`).\n */\n skillInstalled?: boolean\n}\n"],"names":[],"mappings":"AAKA,WAoBC"}
@@ -1,6 +1,6 @@
1
+ import { SchemaExtractionError } from '@sanity/cli-build/_internal/extract';
1
2
  import { studioWorkerTask } from '@sanity/cli-core';
2
3
  import { updateWorkspacesSchemas } from './updateWorkspaceSchema.js';
3
- import { SchemaExtractionError } from './utils/SchemaExtractionError.js';
4
4
  export async function deploySchemas(options) {
5
5
  const { tag, verbose, workDir, workspaceName } = options;
6
6
  const result = await studioWorkerTask(new URL('extractSanityWorkspace.worker.js', import.meta.url), {
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/actions/schema/deploySchemas.ts"],"sourcesContent":["import {studioWorkerTask} from '@sanity/cli-core'\nimport {type SchemaValidationProblemGroup} from '@sanity/types'\nimport {type Workspace} from 'sanity'\n\nimport {type ManifestSchemaType} from '../manifest/types.js'\nimport {type ExtractWorkspaceWorkerData} from './types.js'\nimport {updateWorkspacesSchemas, type WorkspaceSchemaInput} from './updateWorkspaceSchema.js'\nimport {SchemaExtractionError} from './utils/SchemaExtractionError.js'\n\ninterface DeploySchemasOptions {\n verbose: boolean\n workDir: string\n\n tag?: string\n workspaceName?: string\n}\n\ntype WorkspaceWithManifest = Workspace & {manifestSchema: ManifestSchemaType[]}\n\ntype ExtractWorkspaceWorkerMessage =\n | {\n error: string\n type: 'error'\n validation?: SchemaValidationProblemGroup[]\n }\n | {\n type: 'success'\n workspaces: WorkspaceWithManifest[]\n }\n\nexport async function deploySchemas(options: DeploySchemasOptions): Promise<void> {\n const {tag, verbose, workDir, workspaceName} = options\n\n const result = await studioWorkerTask<ExtractWorkspaceWorkerMessage>(\n new URL('extractSanityWorkspace.worker.js', import.meta.url),\n {\n name: 'extractSanityWorkspace',\n studioRootPath: workDir,\n workerData: {\n configPath: workDir,\n workDir,\n } satisfies ExtractWorkspaceWorkerData,\n },\n )\n\n if (result.type === 'error') {\n throw new SchemaExtractionError(result.error, result.validation)\n }\n\n const workspaces: WorkspaceSchemaInput[] = result.workspaces\n .filter((workspace) => !workspaceName || workspace.name === workspaceName)\n .map((workspace) => ({\n dataset: workspace.dataset,\n manifestSchema: workspace.manifestSchema,\n name: workspace.name,\n projectId: workspace.projectId,\n title: workspace.title,\n }))\n\n if (workspaces.length === 0) {\n const error = workspaceName\n ? new Error(`Found no workspaces named \"${workspaceName}\"`)\n : new Error('No workspaces found')\n throw error\n }\n\n await updateWorkspacesSchemas({\n tag,\n verbose,\n workspaces,\n })\n}\n"],"names":["studioWorkerTask","updateWorkspacesSchemas","SchemaExtractionError","deploySchemas","options","tag","verbose","workDir","workspaceName","result","URL","url","name","studioRootPath","workerData","configPath","type","error","validation","workspaces","filter","workspace","map","dataset","manifestSchema","projectId","title","length","Error"],"mappings":"AAAA,SAAQA,gBAAgB,QAAO,mBAAkB;AAMjD,SAAQC,uBAAuB,QAAkC,6BAA4B;AAC7F,SAAQC,qBAAqB,QAAO,mCAAkC;AAuBtE,OAAO,eAAeC,cAAcC,OAA6B;IAC/D,MAAM,EAACC,GAAG,EAAEC,OAAO,EAAEC,OAAO,EAAEC,aAAa,EAAC,GAAGJ;IAE/C,MAAMK,SAAS,MAAMT,iBACnB,IAAIU,IAAI,oCAAoC,YAAYC,GAAG,GAC3D;QACEC,MAAM;QACNC,gBAAgBN;QAChBO,YAAY;YACVC,YAAYR;YACZA;QACF;IACF;IAGF,IAAIE,OAAOO,IAAI,KAAK,SAAS;QAC3B,MAAM,IAAId,sBAAsBO,OAAOQ,KAAK,EAAER,OAAOS,UAAU;IACjE;IAEA,MAAMC,aAAqCV,OAAOU,UAAU,CACzDC,MAAM,CAAC,CAACC,YAAc,CAACb,iBAAiBa,UAAUT,IAAI,KAAKJ,eAC3Dc,GAAG,CAAC,CAACD,YAAe,CAAA;YACnBE,SAASF,UAAUE,OAAO;YAC1BC,gBAAgBH,UAAUG,cAAc;YACxCZ,MAAMS,UAAUT,IAAI;YACpBa,WAAWJ,UAAUI,SAAS;YAC9BC,OAAOL,UAAUK,KAAK;QACxB,CAAA;IAEF,IAAIP,WAAWQ,MAAM,KAAK,GAAG;QAC3B,MAAMV,QAAQT,gBACV,IAAIoB,MAAM,CAAC,2BAA2B,EAAEpB,cAAc,CAAC,CAAC,IACxD,IAAIoB,MAAM;QACd,MAAMX;IACR;IAEA,MAAMhB,wBAAwB;QAC5BI;QACAC;QACAa;IACF;AACF"}
1
+ {"version":3,"sources":["../../../src/actions/schema/deploySchemas.ts"],"sourcesContent":["import {SchemaExtractionError} from '@sanity/cli-build/_internal/extract'\nimport {studioWorkerTask} from '@sanity/cli-core'\nimport {type SchemaValidationProblemGroup} from '@sanity/types'\nimport {type Workspace} from 'sanity'\n\nimport {type ManifestSchemaType} from '../manifest/types.js'\nimport {type ExtractWorkspaceWorkerData} from './types.js'\nimport {updateWorkspacesSchemas, type WorkspaceSchemaInput} from './updateWorkspaceSchema.js'\n\ninterface DeploySchemasOptions {\n verbose: boolean\n workDir: string\n\n tag?: string\n workspaceName?: string\n}\n\ntype WorkspaceWithManifest = Workspace & {manifestSchema: ManifestSchemaType[]}\n\ntype ExtractWorkspaceWorkerMessage =\n | {\n error: string\n type: 'error'\n validation?: SchemaValidationProblemGroup[]\n }\n | {\n type: 'success'\n workspaces: WorkspaceWithManifest[]\n }\n\nexport async function deploySchemas(options: DeploySchemasOptions): Promise<void> {\n const {tag, verbose, workDir, workspaceName} = options\n\n const result = await studioWorkerTask<ExtractWorkspaceWorkerMessage>(\n new URL('extractSanityWorkspace.worker.js', import.meta.url),\n {\n name: 'extractSanityWorkspace',\n studioRootPath: workDir,\n workerData: {\n configPath: workDir,\n workDir,\n } satisfies ExtractWorkspaceWorkerData,\n },\n )\n\n if (result.type === 'error') {\n throw new SchemaExtractionError(result.error, result.validation)\n }\n\n const workspaces: WorkspaceSchemaInput[] = result.workspaces\n .filter((workspace) => !workspaceName || workspace.name === workspaceName)\n .map((workspace) => ({\n dataset: workspace.dataset,\n manifestSchema: workspace.manifestSchema,\n name: workspace.name,\n projectId: workspace.projectId,\n title: workspace.title,\n }))\n\n if (workspaces.length === 0) {\n const error = workspaceName\n ? new Error(`Found no workspaces named \"${workspaceName}\"`)\n : new Error('No workspaces found')\n throw error\n }\n\n await updateWorkspacesSchemas({\n tag,\n verbose,\n workspaces,\n })\n}\n"],"names":["SchemaExtractionError","studioWorkerTask","updateWorkspacesSchemas","deploySchemas","options","tag","verbose","workDir","workspaceName","result","URL","url","name","studioRootPath","workerData","configPath","type","error","validation","workspaces","filter","workspace","map","dataset","manifestSchema","projectId","title","length","Error"],"mappings":"AAAA,SAAQA,qBAAqB,QAAO,sCAAqC;AACzE,SAAQC,gBAAgB,QAAO,mBAAkB;AAMjD,SAAQC,uBAAuB,QAAkC,6BAA4B;AAuB7F,OAAO,eAAeC,cAAcC,OAA6B;IAC/D,MAAM,EAACC,GAAG,EAAEC,OAAO,EAAEC,OAAO,EAAEC,aAAa,EAAC,GAAGJ;IAE/C,MAAMK,SAAS,MAAMR,iBACnB,IAAIS,IAAI,oCAAoC,YAAYC,GAAG,GAC3D;QACEC,MAAM;QACNC,gBAAgBN;QAChBO,YAAY;YACVC,YAAYR;YACZA;QACF;IACF;IAGF,IAAIE,OAAOO,IAAI,KAAK,SAAS;QAC3B,MAAM,IAAIhB,sBAAsBS,OAAOQ,KAAK,EAAER,OAAOS,UAAU;IACjE;IAEA,MAAMC,aAAqCV,OAAOU,UAAU,CACzDC,MAAM,CAAC,CAACC,YAAc,CAACb,iBAAiBa,UAAUT,IAAI,KAAKJ,eAC3Dc,GAAG,CAAC,CAACD,YAAe,CAAA;YACnBE,SAASF,UAAUE,OAAO;YAC1BC,gBAAgBH,UAAUG,cAAc;YACxCZ,MAAMS,UAAUT,IAAI;YACpBa,WAAWJ,UAAUI,SAAS;YAC9BC,OAAOL,UAAUK,KAAK;QACxB,CAAA;IAEF,IAAIP,WAAWQ,MAAM,KAAK,GAAG;QAC3B,MAAMV,QAAQT,gBACV,IAAIoB,MAAM,CAAC,2BAA2B,EAAEpB,cAAc,CAAC,CAAC,IACxD,IAAIoB,MAAM;QACd,MAAMX;IACR;IAEA,MAAMf,wBAAwB;QAC5BG;QACAC;QACAa;IACF;AACF"}
@@ -1,8 +1,8 @@
1
1
  import { isMainThread, parentPort, workerData } from 'node:worker_threads';
2
+ import { extractValidationFromSchemaError } from '@sanity/cli-build/_internal/extract';
2
3
  import { getStudioWorkspaces, safeStructuredClone } from '@sanity/cli-core';
3
4
  import { extractManifestSchemaTypes } from '../manifest/extractWorkspaceManifest.js';
4
5
  import { extractWorkspaceWorkerData } from './types.js';
5
- import { extractValidationFromSchemaError } from './utils/extractValidationFromSchemaError.js';
6
6
  if (isMainThread || !parentPort) {
7
7
  throw new Error('Should only be run in a worker!');
8
8
  }