diff --git a/src/negative_test/claude-code-settings/invalid-blocked-marketplace-git-url.json b/src/negative_test/claude-code-settings/invalid-blocked-marketplace-git-url.json new file mode 100644 index 00000000000..1835d793604 --- /dev/null +++ b/src/negative_test/claude-code-settings/invalid-blocked-marketplace-git-url.json @@ -0,0 +1,8 @@ +{ + "blockedMarketplaces": [ + { + "source": "git", + "url": "https://github.com/org/repo-without-git-suffix" + } + ] +} diff --git a/src/negative_test/claude-code-settings/invalid-marketplace-host-pattern.json b/src/negative_test/claude-code-settings/invalid-marketplace-host-pattern.json index 4b7efbe2ea5..050dcf286e3 100644 --- a/src/negative_test/claude-code-settings/invalid-marketplace-host-pattern.json +++ b/src/negative_test/claude-code-settings/invalid-marketplace-host-pattern.json @@ -5,17 +5,6 @@ "source": "git", "url": "https://example.com/no-git-suffix" } - }, - "internal-git": { - "source": { - "source": "hostPattern" - } - } - }, - "strictKnownMarketplaces": [ - { - "hostPattern": 123, - "source": "hostPattern" } - ] + } } diff --git a/src/negative_test/claude-code-settings/wrong-property-types.json b/src/negative_test/claude-code-settings/wrong-property-types.json index 82e6201b3d1..7f443fc8adc 100644 --- a/src/negative_test/claude-code-settings/wrong-property-types.json +++ b/src/negative_test/claude-code-settings/wrong-property-types.json @@ -26,5 +26,11 @@ "allowAllUnixSockets": "yes", "allowedDomains": "api.anthropic.com" } - } + }, + "strictKnownMarketplaces": [ + { + "hostPattern": 123, + "source": "hostPattern" + } + ] } diff --git a/src/schema-validation.jsonc b/src/schema-validation.jsonc index 1230b8bcb22..9111cd1d2a1 100644 --- a/src/schema-validation.jsonc +++ b/src/schema-validation.jsonc @@ -407,7 +407,12 @@ "openapi-overlay-1.X.json", // uses external references "openapi-arazzo-1.X.json" // uses external references ], - "coverage": [], + "coverage": [ + { + "schema": "claude-code-settings.json", + "strict": true + } + ], "catalogEntryNoLintNameOrDescription": [ "https://json-schema.org/draft-04/schema", "https://json-schema.org/draft-07/schema", diff --git a/src/schemas/json/claude-code-settings.json b/src/schemas/json/claude-code-settings.json index 212eccf78ee..173b9e72358 100644 --- a/src/schemas/json/claude-code-settings.json +++ b/src/schemas/json/claude-code-settings.json @@ -187,7 +187,7 @@ "env": { "type": "object", "additionalProperties": false, - "description": "Environment variables to set for Claude Code sessions", + "description": "Environment variables to set for Claude Code sessions. See https://code.claude.com/docs/en/model-config#environment-variables for notable variables like CLAUDE_CODE_DISABLE_1M_CONTEXT (disables 1M token context window variants)", "examples": [ { "ANTHROPIC_MODEL": "claude-opus-4-1", @@ -313,7 +313,7 @@ "items": { "type": "string" }, - "description": "Restrict which models users can select. When defined, users can only switch between these model options. See https://code.claude.com/docs/en/model-config#restrict-model-selection", + "description": "Restrict which models users can select. When defined at multiple settings levels (user, project, etc.), arrays are merged and deduplicated. See https://code.claude.com/docs/en/model-config#restrict-model-selection", "examples": [["sonnet", "haiku"]] }, "effortLevel": { @@ -324,7 +324,7 @@ }, "fastMode": { "type": "boolean", - "description": "Enable fast mode for Opus 4.6. Fast mode uses the same model with faster output at higher cost per token. Alternatively, toggle with /fast command. See https://code.claude.com/docs/en/fast-mode", + "description": "Enable fast mode for Opus 4.6 (research preview). Fast mode uses the same model with 2.5x faster output at higher per-token cost. Requires extra usage enabled. Alternatively, toggle with /fast command. See https://code.claude.com/docs/en/fast-mode", "default": false }, "enableAllProjectMcpServers": { @@ -552,6 +552,27 @@ "$ref": "#/$defs/hookMatcher" } }, + "ConfigChange": { + "type": "array", + "description": "Hooks that run when settings, managed settings, or skill files change during a session. Supports matchers: user_settings, project_settings, local_settings, policy_settings, skills. Command handlers only. Exit code 2 blocks the change (except policy_settings which is audit-only). See https://code.claude.com/docs/en/hooks#configchange", + "items": { + "$ref": "#/$defs/hookMatcher" + } + }, + "WorktreeCreate": { + "type": "array", + "description": "Hooks that run when a worktree is created via --worktree or isolation: \"worktree\" in subagents. Command handlers only, no matchers. Hook must print absolute path to created worktree on stdout; non-zero exit fails creation. See https://code.claude.com/docs/en/hooks#worktreecreate", + "items": { + "$ref": "#/$defs/hookMatcher" + } + }, + "WorktreeRemove": { + "type": "array", + "description": "Hooks that run when a worktree is being removed at session exit or when a subagent finishes. Command handlers only, no matchers. Used for cleanup tasks; cannot block removal. See https://code.claude.com/docs/en/hooks#worktreeremove", + "items": { + "$ref": "#/$defs/hookMatcher" + } + }, "SessionStart": { "type": "array", "description": "Hooks that run when a new session starts", @@ -570,7 +591,7 @@ }, "disableAllHooks": { "type": "boolean", - "description": "Disable all hooks and statusLine execution" + "description": "Disable all hooks and statusLine execution. When true in managed settings, user and project-level disableAllHooks cannot override it. See https://code.claude.com/docs/en/hooks#disable-or-remove-hooks" }, "allowManagedHooksOnly": { "type": "boolean", @@ -1210,8 +1231,13 @@ "anyOf": [ { "type": "object", + "additionalProperties": false, "properties": { - "source": { "type": "string", "const": "url" }, + "source": { + "type": "string", + "const": "url", + "description": "Block marketplace fetched from direct URL" + }, "url": { "type": "string", "format": "uri", @@ -1227,8 +1253,13 @@ }, { "type": "object", + "additionalProperties": false, "properties": { - "source": { "type": "string", "const": "github" }, + "source": { + "type": "string", + "const": "github", + "description": "Block marketplace from GitHub repository" + }, "repo": { "type": "string", "description": "GitHub repository in owner/repo format" @@ -1246,8 +1277,13 @@ }, { "type": "object", + "additionalProperties": false, "properties": { - "source": { "type": "string", "const": "git" }, + "source": { + "type": "string", + "const": "git", + "description": "Block marketplace from git repository URL" + }, "url": { "type": "string", "pattern": ".*\\.git$", @@ -1266,8 +1302,13 @@ }, { "type": "object", + "additionalProperties": false, "properties": { - "source": { "type": "string", "const": "npm" }, + "source": { + "type": "string", + "const": "npm", + "description": "Block marketplace from NPM package" + }, "package": { "type": "string", "description": "NPM package containing marketplace.json" @@ -1277,8 +1318,13 @@ }, { "type": "object", + "additionalProperties": false, "properties": { - "source": { "type": "string", "const": "file" }, + "source": { + "type": "string", + "const": "file", + "description": "Block marketplace from local file" + }, "path": { "type": "string", "description": "Local file path to marketplace.json" @@ -1288,8 +1334,13 @@ }, { "type": "object", + "additionalProperties": false, "properties": { - "source": { "type": "string", "const": "directory" }, + "source": { + "type": "string", + "const": "directory", + "description": "Block marketplace from local directory" + }, "path": { "type": "string", "description": "Local directory containing .claude-plugin/marketplace.json" @@ -1299,8 +1350,13 @@ }, { "type": "object", + "additionalProperties": false, "properties": { - "source": { "type": "string", "const": "hostPattern" }, + "source": { + "type": "string", + "const": "hostPattern", + "description": "Block marketplace by host pattern matching" + }, "hostPattern": { "type": "string", "description": "Regex pattern to match the host/domain extracted from any marketplace source type" diff --git a/src/test/claude-code-settings/hooks-complete.json b/src/test/claude-code-settings/hooks-complete.json index e3308b77ae7..8afd3cda77b 100644 --- a/src/test/claude-code-settings/hooks-complete.json +++ b/src/test/claude-code-settings/hooks-complete.json @@ -1,5 +1,16 @@ { "hooks": { + "ConfigChange": [ + { + "hooks": [ + { + "command": "echo 'Config changed' >> /tmp/claude-config.log", + "type": "command" + } + ], + "matcher": "user_settings" + } + ], "Notification": [ { "hooks": [ @@ -172,6 +183,26 @@ } ] } + ], + "WorktreeCreate": [ + { + "hooks": [ + { + "command": "mkdir -p /tmp/worktree && echo /tmp/worktree", + "type": "command" + } + ] + } + ], + "WorktreeRemove": [ + { + "hooks": [ + { + "command": "echo 'Removing worktree' >> /tmp/claude-cleanup.log", + "type": "command" + } + ] + } ] } } diff --git a/src/test/claude-code-settings/managed-settings.json b/src/test/claude-code-settings/managed-settings.json index 694fb45e841..51a4e74b134 100644 --- a/src/test/claude-code-settings/managed-settings.json +++ b/src/test/claude-code-settings/managed-settings.json @@ -22,6 +22,10 @@ { "hostPattern": "^untrusted\\.example\\.com$", "source": "hostPattern" + }, + { + "source": "git", + "url": "https://github.com/untrusted-org/plugins.git" } ], "deniedMcpServers": [ diff --git a/src/test/claude-code-settings/modern-complete-config.json b/src/test/claude-code-settings/modern-complete-config.json index 56ba2984bb4..3f5c83e9a03 100644 --- a/src/test/claude-code-settings/modern-complete-config.json +++ b/src/test/claude-code-settings/modern-complete-config.json @@ -43,6 +43,17 @@ "forceLoginMethod": "console", "forceLoginOrgUUID": "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx", "hooks": { + "ConfigChange": [ + { + "hooks": [ + { + "command": "echo 'Config changed' >> ~/.claude-code/config-changes.log", + "type": "command" + } + ], + "matcher": "user_settings" + } + ], "PermissionRequest": [ { "hooks": [ @@ -85,6 +96,26 @@ } ] } + ], + "WorktreeCreate": [ + { + "hooks": [ + { + "command": "mkdir -p ~/.claude/worktrees && echo ~/.claude/worktrees/feature-branch", + "type": "command" + } + ] + } + ], + "WorktreeRemove": [ + { + "hooks": [ + { + "command": "echo 'Cleaning up worktree' >> ~/.claude-code/cleanup.log", + "type": "command" + } + ] + } ] }, "includeCoAuthoredBy": true,