@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.
- package/dist/actions/mcp/editorConfigs.js +11 -5
- package/dist/actions/mcp/editorConfigs.js.map +1 -1
- package/oclif.manifest.json +1 -1
- package/package.json +8 -8
- package/templates/app-quickstart/.claude/skills/sanity-app-sdk/SKILL.md +56 -0
- package/templates/app-quickstart/AGENTS.md +40 -0
- package/templates/app-quickstart/README.md +22 -0
- package/templates/app-quickstart/src/ExampleComponent.css +6 -0
- package/templates/app-quickstart/src/ExampleComponent.tsx +30 -9
- package/templates/app-sanity-ui/.claude/skills/sanity-app-sdk/SKILL.md +60 -0
- package/templates/app-sanity-ui/AGENTS.md +44 -0
- package/templates/app-sanity-ui/README.md +23 -0
- package/templates/app-sanity-ui/src/ExampleComponent.tsx +8 -5
|
@@ -212,20 +212,23 @@ function buildGitHubCopilotCliServerConfig(token) {
|
|
|
212
212
|
};
|
|
213
213
|
}
|
|
214
214
|
function buildOpenCodeServerConfig(token) {
|
|
215
|
-
|
|
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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"}
|
package/oclif.manifest.json
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@sanity/cli",
|
|
3
|
-
"version": "7.
|
|
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.
|
|
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.
|
|
122
|
-
"@sanity/cli
|
|
123
|
-
"@sanity/
|
|
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.
|
|
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
|
|
160
|
-
"@sanity/
|
|
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)
|
|
@@ -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
|
|
21
|
-
|
|
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
|
-
|
|
26
|
-
|
|
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 {
|
|
28
|
+
<pre>{`import {Suspense} from 'react'
|
|
29
|
+
import {useDocuments} from '@sanity/sdk-react'
|
|
29
30
|
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
</
|
|
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
|
|
22
|
-
|
|
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
|
|
26
|
-
|
|
27
|
-
<a href="https://reference.sanity.io/_sanity/sdk-react/">
|
|
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>
|