@sanity/cli 7.4.2 → 7.5.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.
@@ -212,20 +212,23 @@ function buildGitHubCopilotCliServerConfig(token) {
212
212
  };
213
213
  }
214
214
  function buildOpenCodeServerConfig(token) {
215
- return {
216
- headers: {
217
- Authorization: `Bearer ${token}`
218
- },
215
+ const config = {
219
216
  type: 'remote',
220
217
  url: MCP_SERVER_URL
221
218
  };
219
+ if (token) {
220
+ config.headers = {
221
+ Authorization: `Bearer ${token}`
222
+ };
223
+ }
224
+ return config;
222
225
  }
223
226
  function buildZedServerConfig(token) {
224
227
  return {
228
+ enabled: true,
225
229
  headers: {
226
230
  Authorization: `Bearer ${token}`
227
231
  },
228
- settings: {},
229
232
  url: MCP_SERVER_URL
230
233
  };
231
234
  }
@@ -317,6 +320,7 @@ function buildZedServerConfig(token) {
317
320
  buildServerConfig: buildOpenCodeServerConfig,
318
321
  configKey: 'mcp',
319
322
  detect: detectOpenCode,
323
+ oauthOnly: true,
320
324
  skillsCliAgent: 'opencode'
321
325
  },
322
326
  // Doc: https://code.visualstudio.com/docs/copilot/chat/mcp-servers
@@ -327,6 +331,7 @@ function buildZedServerConfig(token) {
327
331
  ...EDITOR_DEFAULTS,
328
332
  configKey: 'servers',
329
333
  detect: detectVSCode,
334
+ oauthOnly: true,
330
335
  skillsCliAgent: 'github-copilot'
331
336
  },
332
337
  // Doc: https://code.visualstudio.com/docs/copilot/chat/mcp-servers
@@ -335,6 +340,7 @@ function buildZedServerConfig(token) {
335
340
  ...EDITOR_DEFAULTS,
336
341
  configKey: 'servers',
337
342
  detect: detectVSCodeInsiders,
343
+ oauthOnly: true,
338
344
  skillsCliAgent: 'github-copilot'
339
345
  },
340
346
  // Doc: https://zed.dev/docs/assistant/model-context-protocol
@@ -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 * 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 * The directory to install skills to.\n */\n skillsDir?: 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\nexport const UNIVERSAL_SKILLS_DIR = '.agents/skills'\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 skillsDir: UNIVERSAL_SKILLS_DIR,\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 const config: Record<string, unknown> = {\n type: 'http',\n url: MCP_SERVER_URL,\n }\n\n if (token) {\n config.http_headers = {Authorization: `Bearer ${token}`}\n }\n\n return config\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 skillsDir: '.claude/skills',\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 oauthOnly: true,\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\nexport function isUniversalSkillsCliAgentByEditorName(editorName: EditorName): boolean {\n return EDITOR_CONFIGS[editorName]?.skillsDir === UNIVERSAL_SKILLS_DIR\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\n/** Display name for a skills-CLI agent ID (e.g. `'cursor'` → `'Cursor'`). */\nexport function getSkillsCliAgentDisplayNameById(agentId: string): string | undefined {\n return SKILLS_CLI_AGENT_DISPLAY_NAMES[agentId]\n}\n\n/**\n * The relative, home-anchored directory the `skills` CLI installs into for a\n * given agent ID (e.g. `'cursor'` → `'.agents/skills'`, `'claude-code'` →\n * `'.claude/skills'`). Derived from `EDITOR_CONFIGS` so it stays a single\n * source of truth.\n */\nexport function getSkillsCliAgentSkillsDir(agentName: string): string | undefined {\n for (const name of Object.keys(EDITOR_CONFIGS) as EditorName[]) {\n const config = EDITOR_CONFIGS[name]\n const agent = getSkillsCliAgent(name)\n if (agent === agentName) {\n return config.skillsDir\n }\n }\n return 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","UNIVERSAL_SKILLS_DIR","EDITOR_DEFAULTS","buildServerConfig","configKey","format","oauthOnly","readToken","skillsDir","buildAntigravityServerConfig","serverUrl","buildClineServerConfig","disabled","buildCodexCliServerConfig","config","buildGitHubCopilotCliServerConfig","tools","buildOpenCodeServerConfig","buildZedServerConfig","settings","EDITOR_CONFIGS","Antigravity","detect","skillsCliAgent","Cline","Cursor","MCPorter","OpenCode","Zed","getSkillsCliAgent","editorName","SKILLS_CLI_AGENT_DISPLAY_NAMES","antigravity","cline","codex","cursor","opencode","isUniversalSkillsCliAgentByEditorName","getSkillsCliAgentDisplayName","agent","getSkillsCliAgentDisplayNameById","agentId","getSkillsCliAgentSkillsDir","agentName","name","Object","keys"],"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 * The directory to install skills to.\n */\n skillsDir?: 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\nexport const UNIVERSAL_SKILLS_DIR = '.agents/skills'\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 skillsDir: UNIVERSAL_SKILLS_DIR,\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 const config: Record<string, unknown> = {\n type: 'http',\n url: MCP_SERVER_URL,\n }\n\n if (token) {\n config.http_headers = {Authorization: `Bearer ${token}`}\n }\n\n return config\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 const config: Record<string, unknown> = {\n type: 'remote',\n url: MCP_SERVER_URL,\n }\n\n if (token) {\n config.headers = {Authorization: `Bearer ${token}`}\n }\n\n return config\n}\n\nfunction buildZedServerConfig(token: string): Record<string, unknown> {\n return {\n enabled: true,\n headers: {Authorization: `Bearer ${token}`},\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 skillsDir: '.claude/skills',\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 oauthOnly: true,\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 oauthOnly: true,\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 oauthOnly: true,\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 oauthOnly: true,\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\nexport function isUniversalSkillsCliAgentByEditorName(editorName: EditorName): boolean {\n return EDITOR_CONFIGS[editorName]?.skillsDir === UNIVERSAL_SKILLS_DIR\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\n/** Display name for a skills-CLI agent ID (e.g. `'cursor'` → `'Cursor'`). */\nexport function getSkillsCliAgentDisplayNameById(agentId: string): string | undefined {\n return SKILLS_CLI_AGENT_DISPLAY_NAMES[agentId]\n}\n\n/**\n * The relative, home-anchored directory the `skills` CLI installs into for a\n * given agent ID (e.g. `'cursor'` → `'.agents/skills'`, `'claude-code'` →\n * `'.claude/skills'`). Derived from `EDITOR_CONFIGS` so it stays a single\n * source of truth.\n */\nexport function getSkillsCliAgentSkillsDir(agentName: string): string | undefined {\n for (const name of Object.keys(EDITOR_CONFIGS) as EditorName[]) {\n const config = EDITOR_CONFIGS[name]\n const agent = getSkillsCliAgent(name)\n if (agent === agentName) {\n return config.skillsDir\n }\n }\n return 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","UNIVERSAL_SKILLS_DIR","EDITOR_DEFAULTS","buildServerConfig","configKey","format","oauthOnly","readToken","skillsDir","buildAntigravityServerConfig","serverUrl","buildClineServerConfig","disabled","buildCodexCliServerConfig","config","buildGitHubCopilotCliServerConfig","tools","buildOpenCodeServerConfig","buildZedServerConfig","enabled","EDITOR_CONFIGS","Antigravity","detect","skillsCliAgent","Cline","Cursor","MCPorter","OpenCode","Zed","getSkillsCliAgent","editorName","SKILLS_CLI_AGENT_DISPLAY_NAMES","antigravity","cline","codex","cursor","opencode","isUniversalSkillsCliAgentByEditorName","getSkillsCliAgentDisplayName","agent","getSkillsCliAgentDisplayNameById","agentId","getSkillsCliAgentSkillsDir","agentName","name","Object","keys"],"mappings":"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"}
@@ -5149,5 +5149,5 @@
5149
5149
  ]
5150
5150
  }
5151
5151
  },
5152
- "version": "7.4.2"
5152
+ "version": "7.5.0"
5153
5153
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sanity/cli",
3
- "version": "7.4.2",
3
+ "version": "7.5.0",
4
4
  "description": "Sanity CLI tool for managing Sanity projects and organizations",
5
5
  "keywords": [
6
6
  "cli",
@@ -114,17 +114,17 @@
114
114
  "tinyglobby": "^0.2.17",
115
115
  "tsx": "^4.22.4",
116
116
  "typeid-js": "^1.2.0",
117
- "vite": "8.1.0",
117
+ "vite": "^8.1.2",
118
118
  "which": "^6.0.1",
119
119
  "yaml": "^2.9.0",
120
120
  "zod": "^4.4.3",
121
- "@sanity/cli-build": "^2.0.0",
122
- "@sanity/cli-core": "^2.1.2",
123
- "@sanity/workbench-cli": "^1.1.2"
121
+ "@sanity/cli-build": "^2.0.1",
122
+ "@sanity/workbench-cli": "^1.1.3",
123
+ "@sanity/cli-core": "^2.1.3"
124
124
  },
125
125
  "devDependencies": {
126
126
  "@eslint/compat": "^2.1.0",
127
- "@sanity/pkg-utils": "^10.5.8",
127
+ "@sanity/pkg-utils": "^10.8.1",
128
128
  "@sanity/ui": "^3.2.0",
129
129
  "@swc/cli": "^0.8.1",
130
130
  "@swc/core": "^1.15.41",
@@ -156,8 +156,8 @@
156
156
  "vitest": "^4.1.9",
157
157
  "@repo/package.config": "0.0.1",
158
158
  "@repo/tsconfig": "3.70.0",
159
- "@sanity/cli-test": "2.0.2",
160
- "@sanity/eslint-config-cli": "1.1.2"
159
+ "@sanity/eslint-config-cli": "1.1.2",
160
+ "@sanity/cli-test": "2.0.3"
161
161
  },
162
162
  "peerDependencies": {
163
163
  "babel-plugin-react-compiler": "*"
@@ -0,0 +1,56 @@
1
+ ---
2
+ name: sanity-app-sdk
3
+ description: Build features with the Sanity App SDK (@sanity/sdk-react). Use when adding components, fetching or editing Sanity content, or working with hooks like useDocuments, useDocument, useDocumentProjection, useEditDocument, or useQuery.
4
+ ---
5
+
6
+ # Sanity App SDK
7
+
8
+ ## Get the maintained guide first
9
+
10
+ If the Sanity MCP server is configured, call its `get_sanity_rules` tool with the `app-sdk` rule before writing SDK code. That rule is maintained by Sanity, is more detailed, and supersedes the notes below. The notes below are a fallback for when MCP is not available.
11
+
12
+ ## Picking a hook
13
+
14
+ - `useDocuments` / `usePaginatedDocuments`: lists of documents. Returns document handles, not full documents.
15
+ - `useDocumentProjection`: read specific fields from a handle, for display.
16
+ - `useDocument` plus `useEditDocument`: read and write a single document in real time.
17
+ - `useQuery`: raw GROQ. Use sparingly; prefer handles plus projections.
18
+
19
+ ## Document handles
20
+
21
+ Fetch handles first, then spread them into other hooks:
22
+
23
+ ```tsx
24
+ const {data} = useDocuments({documentType: 'article'})
25
+
26
+ // in a child component receiving one handle:
27
+ const {data: fields} = useDocumentProjection({...handle, projection: '{title}'})
28
+ ```
29
+
30
+ Use `documentId` as the React key when rendering lists, never the array index.
31
+
32
+ ## Suspense
33
+
34
+ Data hooks suspend while loading. Wrap every data-fetching component in `<Suspense>` with a fallback, keep one fetching hook per component, and always pass a `fallback` to `SanityApp`. All SDK hooks must be used inside `SanityApp`.
35
+
36
+ ## Editing
37
+
38
+ Write through `useEditDocument` on change so content stays in sync with the Content Lake:
39
+
40
+ ```tsx
41
+ const {data: title} = useDocument({...handle, path: 'title'})
42
+ const editTitle = useEditDocument({...handle, path: 'title'})
43
+ // <input value={title ?? ''} onChange={(e) => editTitle(e.currentTarget.value)} />
44
+ ```
45
+
46
+ Do not hold document field values in `useState` and save on submit. That pattern goes stale and loses concurrent edits.
47
+
48
+ ## Documentation
49
+
50
+ Fetch these for current detail rather than relying on the notes above:
51
+
52
+ - Best practices: https://www.sanity.io/docs/app-sdk/sdk-best-practices
53
+ - Editing documents: https://www.sanity.io/docs/app-sdk/editing-documents
54
+ - Configuration: https://www.sanity.io/docs/app-sdk/sdk-configuration
55
+ - Deployment: https://www.sanity.io/docs/app-sdk/sdk-deployment
56
+ - API reference with current signatures: https://reference.sanity.io/_sanity/sdk-react/
@@ -0,0 +1,40 @@
1
+ # AGENTS.md
2
+
3
+ Guidance for AI coding agents working in this repository.
4
+
5
+ ## What this is
6
+
7
+ A React application built with the Sanity App SDK (`@sanity/sdk-react`). It is not a Sanity Studio. The app reads and writes content in a Sanity project through SDK hooks, and runs inside the organization's Sanity Dashboard, in development and when deployed. The `sanity` CLI runs it with Vite under the hood.
8
+
9
+ ## Key files
10
+
11
+ - `src/App.tsx`: entry point. The `SanityApp` component takes a `config` array with `projectId` and `dataset`. All SDK hooks must be used inside `SanityApp`.
12
+ - `sanity.cli.ts`: CLI config with the organization ID and app entry path.
13
+
14
+ ## Commands
15
+
16
+ - `npm run dev`: starts the dev server on port 3333, but the app only renders inside the Sanity Dashboard. The CLI prints a Dashboard URL to open. Viewing it requires a signed-in Sanity account, so a human must complete authentication in the browser.
17
+ - `npm run build`: production build.
18
+ - `npm run deploy`: deploy to the Sanity Dashboard.
19
+
20
+ Environment variables prefixed with `SANITY_APP_` are bundled into the app.
21
+
22
+ ## Working with the App SDK
23
+
24
+ If the Sanity MCP server is available, call its `get_sanity_rules` tool with the `app-sdk` rule before writing SDK code. That rule is the maintained guide and supersedes the notes below.
25
+
26
+ Essentials:
27
+
28
+ - Data hooks suspend while loading. Wrap every data-fetching component in `<Suspense>`, keep one fetching hook per component, and always pass a `fallback` to `SanityApp`.
29
+ - Fetch lists with `useDocuments` (or `usePaginatedDocuments`). They return document handles, not full documents. Spread a handle into `useDocumentProjection` to display fields, or into `useDocument` and `useEditDocument` for real-time editing.
30
+ - Use `documentId` as the React key when rendering document lists, never the array index.
31
+ - Do not hold document field values in `useState` and save on submit. Write through `useEditDocument` on change so content stays in sync with the Content Lake.
32
+ - Prefer handles plus projections over raw GROQ. Reach for `useQuery` only when a complex query genuinely needs it.
33
+
34
+ ## Documentation
35
+
36
+ - App SDK docs: https://www.sanity.io/docs/app-sdk
37
+ - Best practices: https://www.sanity.io/docs/app-sdk/sdk-best-practices
38
+ - Editing documents: https://www.sanity.io/docs/app-sdk/editing-documents
39
+ - Configuration: https://www.sanity.io/docs/app-sdk/sdk-configuration
40
+ - API reference with current signatures: https://reference.sanity.io/_sanity/sdk-react/
@@ -0,0 +1,22 @@
1
+ # Sanity App
2
+
3
+ A custom application built with the [Sanity App SDK](https://www.sanity.io/docs/app-sdk?utm_source=readme). It is a React app that runs inside your organization's Sanity Dashboard, in development and when deployed.
4
+
5
+ ## Commands
6
+
7
+ - `npm run dev` starts the dev server and prints a Sanity Dashboard URL where your app runs. Open it and sign in with your Sanity account.
8
+ - `npm run build` builds the app for production.
9
+ - `npm run deploy` deploys the app to the Sanity Dashboard.
10
+
11
+ ## Configuration
12
+
13
+ - `src/App.tsx` is the app entry point. The `SanityApp` config sets which project and dataset the app reads content from.
14
+ - `sanity.cli.ts` holds your organization ID and the app entry path.
15
+
16
+ ## Learn more
17
+
18
+ - [App SDK Quickstart Guide](https://www.sanity.io/docs/app-sdk/sdk-quickstart?utm_source=readme)
19
+ - [App SDK documentation](https://www.sanity.io/docs/app-sdk?utm_source=readme)
20
+ - [API reference](https://reference.sanity.io/_sanity/sdk-react/)
21
+ - [Deploying your app](https://www.sanity.io/docs/app-sdk/sdk-deployment?utm_source=readme)
22
+ - [SDK Explorer with example apps](https://sdk-explorer.sanity.io)
@@ -88,3 +88,9 @@ p {
88
88
  border-left: 3px solid #e0e0e0;
89
89
  line-height: 1.5;
90
90
  }
91
+
92
+ .example-links {
93
+ margin-top: 1.5rem;
94
+ padding-inline-start: 1.25rem;
95
+ line-height: 1.8;
96
+ }
@@ -17,21 +17,42 @@ export function ExampleComponent() {
17
17
  Welcome to your Sanity App{user?.name ? `, ${user.name}` : ''}!
18
18
  </h1>
19
19
  <p className="example-text">
20
- This is an example component. You can replace this with your own content by creating a new
21
- component and importing it in App.tsx.
20
+ This is an example component, rendered with the <code>useCurrentUser</code> hook from the
21
+ App SDK. Replace it with your own components by importing them in App.tsx.
22
22
  </p>
23
23
  <div className="code-hint">
24
24
  <p>
25
- Quick tip: Create new components in separate files and import them like this in App.tsx /
26
- App.jsx:
25
+ A good next step is fetching content. Data hooks like <code>useDocuments</code> suspend
26
+ while loading, so render them inside a <code>{'<Suspense>'}</code> boundary:
27
27
  </p>
28
- <pre>{`import {YourComponent} from './YourComponent'
28
+ <pre>{`import {Suspense} from 'react'
29
+ import {useDocuments} from '@sanity/sdk-react'
29
30
 
30
- // Then use it in your JSX
31
- <SanityApp config={sanityConfigs}>
32
- <YourComponent />
33
- </SanityApp>`}</pre>
31
+ function DocumentList() {
32
+ // useDocuments returns handles you can pass to other hooks
33
+ const {data} = useDocuments({documentType: 'yourType'})
34
+ return <ul>{data.map((doc) => <li key={doc.documentId}>{doc.documentId}</li>)}</ul>
35
+ }
36
+
37
+ function App() {
38
+ return (
39
+ <Suspense fallback={<div>Loading...</div>}>
40
+ <DocumentList />
41
+ </Suspense>
42
+ )
43
+ }`}</pre>
34
44
  </div>
45
+ <ul className="example-links">
46
+ <li>
47
+ <a href="https://www.sanity.io/docs/app-sdk">App SDK documentation</a>
48
+ </li>
49
+ <li>
50
+ <a href="https://reference.sanity.io/_sanity/sdk-react/">API reference</a>
51
+ </li>
52
+ <li>
53
+ <a href="https://sdk-explorer.sanity.io">SDK Explorer with example apps</a>
54
+ </li>
55
+ </ul>
35
56
  </div>
36
57
  )
37
58
  }
@@ -0,0 +1,60 @@
1
+ ---
2
+ name: sanity-app-sdk
3
+ description: Build features with the Sanity App SDK (@sanity/sdk-react) and Sanity UI. Use when adding components, fetching or editing Sanity content, or working with hooks like useDocuments, useDocument, useDocumentProjection, useEditDocument, or useQuery.
4
+ ---
5
+
6
+ # Sanity App SDK
7
+
8
+ ## Get the maintained guide first
9
+
10
+ If the Sanity MCP server is configured, call its `get_sanity_rules` tool with the `app-sdk` rule before writing SDK code. That rule is maintained by Sanity, is more detailed, and supersedes the notes below. The notes below are a fallback for when MCP is not available.
11
+
12
+ ## Picking a hook
13
+
14
+ - `useDocuments` / `usePaginatedDocuments`: lists of documents. Returns document handles, not full documents.
15
+ - `useDocumentProjection`: read specific fields from a handle, for display.
16
+ - `useDocument` plus `useEditDocument`: read and write a single document in real time.
17
+ - `useQuery`: raw GROQ. Use sparingly; prefer handles plus projections.
18
+
19
+ ## Document handles
20
+
21
+ Fetch handles first, then spread them into other hooks:
22
+
23
+ ```tsx
24
+ const {data} = useDocuments({documentType: 'article'})
25
+
26
+ // in a child component receiving one handle:
27
+ const {data: fields} = useDocumentProjection({...handle, projection: '{title}'})
28
+ ```
29
+
30
+ Use `documentId` as the React key when rendering lists, never the array index.
31
+
32
+ ## Suspense
33
+
34
+ Data hooks suspend while loading. Wrap every data-fetching component in `<Suspense>` with a fallback, keep one fetching hook per component, and always pass a `fallback` to `SanityApp`. All SDK hooks must be used inside `SanityApp`.
35
+
36
+ ## Editing
37
+
38
+ Write through `useEditDocument` on change so content stays in sync with the Content Lake:
39
+
40
+ ```tsx
41
+ const {data: title} = useDocument({...handle, path: 'title'})
42
+ const editTitle = useEditDocument({...handle, path: 'title'})
43
+ // <input value={title ?? ''} onChange={(e) => editTitle(e.currentTarget.value)} />
44
+ ```
45
+
46
+ Do not hold document field values in `useState` and save on submit. That pattern goes stale and loses concurrent edits.
47
+
48
+ ## Sanity UI
49
+
50
+ This app wraps everything in Sanity UI's `ThemeProvider` (see `src/SanityUI.tsx`, built with `buildTheme()`). Build UI with Sanity UI primitives like `Card`, `Stack`, `Flex`, `Text`, and `Button`. See https://www.sanity.io/docs/app-sdk/sanity-ui-sdk and https://www.sanity.io/ui.
51
+
52
+ ## Documentation
53
+
54
+ Fetch these for current detail rather than relying on the notes above:
55
+
56
+ - Best practices: https://www.sanity.io/docs/app-sdk/sdk-best-practices
57
+ - Editing documents: https://www.sanity.io/docs/app-sdk/editing-documents
58
+ - Configuration: https://www.sanity.io/docs/app-sdk/sdk-configuration
59
+ - Deployment: https://www.sanity.io/docs/app-sdk/sdk-deployment
60
+ - API reference with current signatures: https://reference.sanity.io/_sanity/sdk-react/
@@ -0,0 +1,44 @@
1
+ # AGENTS.md
2
+
3
+ Guidance for AI coding agents working in this repository.
4
+
5
+ ## What this is
6
+
7
+ A React application built with the Sanity App SDK (`@sanity/sdk-react`) and Sanity UI (`@sanity/ui`). It is not a Sanity Studio. The app reads and writes content in a Sanity project through SDK hooks, and runs inside the organization's Sanity Dashboard, in development and when deployed. The `sanity` CLI runs it with Vite under the hood.
8
+
9
+ ## Key files
10
+
11
+ - `src/App.tsx`: entry point. The `SanityApp` component takes a `config` array with `projectId` and `dataset`. All SDK hooks must be used inside `SanityApp`.
12
+ - `src/SanityUI.tsx`: wraps the app in Sanity UI's `ThemeProvider` with a theme from `buildTheme()`. Sanity UI components must render inside this provider.
13
+ - `sanity.cli.ts`: CLI config with the organization ID and app entry path.
14
+
15
+ ## Commands
16
+
17
+ - `npm run dev`: starts the dev server on port 3333, but the app only renders inside the Sanity Dashboard. The CLI prints a Dashboard URL to open. Viewing it requires a signed-in Sanity account, so a human must complete authentication in the browser.
18
+ - `npm run build`: production build.
19
+ - `npm run deploy`: deploy to the Sanity Dashboard.
20
+
21
+ Environment variables prefixed with `SANITY_APP_` are bundled into the app.
22
+
23
+ ## Working with the App SDK
24
+
25
+ If the Sanity MCP server is available, call its `get_sanity_rules` tool with the `app-sdk` rule before writing SDK code. That rule is the maintained guide and supersedes the notes below.
26
+
27
+ Essentials:
28
+
29
+ - Data hooks suspend while loading. Wrap every data-fetching component in `<Suspense>`, keep one fetching hook per component, and always pass a `fallback` to `SanityApp`.
30
+ - Fetch lists with `useDocuments` (or `usePaginatedDocuments`). They return document handles, not full documents. Spread a handle into `useDocumentProjection` to display fields, or into `useDocument` and `useEditDocument` for real-time editing.
31
+ - Use `documentId` as the React key when rendering document lists, never the array index.
32
+ - Do not hold document field values in `useState` and save on submit. Write through `useEditDocument` on change so content stays in sync with the Content Lake.
33
+ - Prefer handles plus projections over raw GROQ. Reach for `useQuery` only when a complex query genuinely needs it.
34
+ - Build UI with Sanity UI primitives like `Card`, `Stack`, `Flex`, `Text`, and `Button` for a look consistent with Sanity tooling.
35
+
36
+ ## Documentation
37
+
38
+ - App SDK docs: https://www.sanity.io/docs/app-sdk
39
+ - Best practices: https://www.sanity.io/docs/app-sdk/sdk-best-practices
40
+ - Editing documents: https://www.sanity.io/docs/app-sdk/editing-documents
41
+ - Configuration: https://www.sanity.io/docs/app-sdk/sdk-configuration
42
+ - Sanity UI with the App SDK: https://www.sanity.io/docs/app-sdk/sanity-ui-sdk
43
+ - Sanity UI docs: https://www.sanity.io/ui
44
+ - API reference with current signatures: https://reference.sanity.io/_sanity/sdk-react/
@@ -0,0 +1,23 @@
1
+ # Sanity App
2
+
3
+ A custom application built with the [Sanity App SDK](https://www.sanity.io/docs/app-sdk?utm_source=readme) and [Sanity UI](https://www.sanity.io/ui?utm_source=readme). It is a React app that runs inside your organization's Sanity Dashboard, in development and when deployed.
4
+
5
+ ## Commands
6
+
7
+ - `npm run dev` starts the dev server and prints a Sanity Dashboard URL where your app runs. Open it and sign in with your Sanity account.
8
+ - `npm run build` builds the app for production.
9
+ - `npm run deploy` deploys the app to the Sanity Dashboard.
10
+
11
+ ## Configuration
12
+
13
+ - `src/App.tsx` is the app entry point. The `SanityApp` config sets which project and dataset the app reads content from.
14
+ - `sanity.cli.ts` holds your organization ID and the app entry path.
15
+
16
+ ## Learn more
17
+
18
+ - [App SDK Quickstart Guide](https://www.sanity.io/docs/app-sdk/sdk-quickstart?utm_source=readme)
19
+ - [App SDK documentation](https://www.sanity.io/docs/app-sdk?utm_source=readme)
20
+ - [Using Sanity UI with the App SDK](https://www.sanity.io/docs/app-sdk/sanity-ui-sdk?utm_source=readme)
21
+ - [API reference](https://reference.sanity.io/_sanity/sdk-react/)
22
+ - [Deploying your app](https://www.sanity.io/docs/app-sdk/sdk-deployment?utm_source=readme)
23
+ - [SDK Explorer with example apps](https://sdk-explorer.sanity.io)
@@ -18,13 +18,16 @@ export function ExampleComponent() {
18
18
  </Text>
19
19
  <Text muted>
20
20
  You can also replace this component with components of your own. Render them in your
21
- app by importing and using them in your application’s <code>src/App.tsx|jsx</code>{' '}
22
- file.
21
+ app by importing and using them in your application’s <code>src/App.tsx</code> file. A
22
+ good next step is fetching content with the <code>useDocuments</code> hook. Data hooks
23
+ suspend while loading, so render them inside a <code>{'<Suspense>'}</code> boundary.
23
24
  </Text>
24
25
  <Text muted>
25
- Looking for more guidance? See the <a href="https://sanity.io/ui">Sanity UI docs</a>{' '}
26
- and the{' '}
27
- <a href="https://reference.sanity.io/_sanity/sdk-react/">Sanity App SDK docs</a>!
26
+ Looking for more guidance? See the{' '}
27
+ <a href="https://www.sanity.io/docs/app-sdk">App SDK documentation</a>, the{' '}
28
+ <a href="https://reference.sanity.io/_sanity/sdk-react/">API reference</a>, the{' '}
29
+ <a href="https://sanity.io/ui">Sanity UI docs</a>, and example apps in the{' '}
30
+ <a href="https://sdk-explorer.sanity.io">SDK Explorer</a>.
28
31
  </Text>
29
32
  </Stack>
30
33
  </Flex>