diff --git a/src/negative_test/claude-code-settings/invalid-enum-values.json b/src/negative_test/claude-code-settings/invalid-enum-values.json index 250d2b2b679..974395f2785 100644 --- a/src/negative_test/claude-code-settings/invalid-enum-values.json +++ b/src/negative_test/claude-code-settings/invalid-enum-values.json @@ -2,5 +2,9 @@ "forceLoginMethod": "github", "permissions": { "defaultMode": "invalid-mode" + }, + "spinnerVerbs": { + "mode": "merge", + "verbs": ["Analyzing"] } } 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 new file mode 100644 index 00000000000..feb9ce9d9f5 --- /dev/null +++ b/src/negative_test/claude-code-settings/invalid-marketplace-host-pattern.json @@ -0,0 +1,15 @@ +{ + "extraKnownMarketplaces": { + "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 d199f2a58a4..3a8f687c9da 100644 --- a/src/negative_test/claude-code-settings/wrong-property-types.json +++ b/src/negative_test/claude-code-settings/wrong-property-types.json @@ -1,10 +1,29 @@ { "cleanupPeriodDays": "thirty", "enableAllProjectMcpServers": 1, + "hooks": { + "PreToolUse": [ + { + "hooks": [ + { + "async": "true", + "command": "echo test", + "type": "command" + } + ] + } + ] + }, "includeCoAuthoredBy": "yes", "permissions": { "additionalDirectories": "should be array", "allow": "should be array", "ask": "should be array" + }, + "sandbox": { + "network": { + "allowAllUnixSockets": "yes", + "allowedDomains": "api.anthropic.com" + } } } diff --git a/src/schemas/json/claude-code-settings.json b/src/schemas/json/claude-code-settings.json index 9957f96e8a8..7bbec15a43e 100644 --- a/src/schemas/json/claude-code-settings.json +++ b/src/schemas/json/claude-code-settings.json @@ -5,7 +5,7 @@ "permissionRule": { "type": "string", "description": "Tool permission rule. See https://code.claude.com/docs/en/settings#permission-rule-syntax", - "pattern": "^((Bash|Edit|ExitPlanMode|Glob|Grep|KillShell|NotebookEdit|Read|Skill|Task|TodoWrite|WebFetch|WebSearch|Write)(\\((?=.*[^)*?])[^)]+\\))?|mcp__.*)$", + "pattern": "^((Bash|Edit|ExitPlanMode|Glob|Grep|KillShell|LS|MultiEdit|NotebookEdit|NotebookRead|Read|Skill|SlashCommand|Task|TodoWrite|WebFetch|WebSearch|Write)(\\((?=.*[^)*?])[^)]+\\))?|mcp__.*)$", "examples": [ "Bash", "Bash(npm run build)", @@ -14,11 +14,13 @@ "Bash(ls*)", "Bash(git * main)", "Edit", + "MultiEdit", "Edit(/src/**/*.ts)", "Read(./.env)", "Read(./secrets/**)", "Read(/Users/alice/secrets/**)", "Read(~/Documents/*.pdf)", + "SlashCommand(/clear)", "WebFetch", "WebFetch(domain:example.com)", "mcp__github__search_repositories" @@ -46,6 +48,10 @@ "type": "number", "description": "Optional timeout in seconds", "exclusiveMinimum": 0 + }, + "async": { + "type": "boolean", + "description": "Run this hook asynchronously without blocking Claude Code" } } }, @@ -69,6 +75,10 @@ "type": "number", "description": "Optional timeout in seconds", "exclusiveMinimum": 0 + }, + "async": { + "type": "boolean", + "description": "Run this hook asynchronously without blocking Claude Code" } } } @@ -517,6 +527,21 @@ "required": ["source", "url"], "additionalProperties": false }, + { + "type": "object", + "properties": { + "source": { + "type": "string", + "const": "hostPattern" + }, + "hostPattern": { + "type": "string", + "description": "Git host pattern to trust for repositories in source specifications" + } + }, + "required": ["source", "hostPattern"], + "additionalProperties": false + }, { "type": "object", "properties": { @@ -627,6 +652,21 @@ "description": "(Managed settings only) Allowlist of plugin marketplaces users can add. Undefined = no restrictions, empty array = lockdown. Uses exact matching for source specifications. See https://code.claude.com/docs/en/settings#strictknownmarketplaces", "items": { "anyOf": [ + { + "type": "object", + "properties": { + "source": { + "type": "string", + "const": "hostPattern" + }, + "hostPattern": { + "type": "string", + "description": "Git host pattern to trust for repositories in source specifications" + } + }, + "required": ["source", "hostPattern"], + "additionalProperties": false + }, { "type": "object", "properties": { @@ -822,6 +862,26 @@ "minimum": 1, "maximum": 65535, "description": "SOCKS proxy port to use for network filtering. If not specified, a proxy server will be started automatically" + }, + "allowAllUnixSockets": { + "type": "boolean", + "description": "Allow all Unix domain socket connections. If true, this overrides allowUnixSockets" + }, + "allowedDomains": { + "type": "array", + "items": { + "type": "string", + "minLength": 1 + }, + "description": "Allowlist of network domains for sandboxed commands. Supports wildcard patterns like *.example.com" + }, + "deniedDomains": { + "type": "array", + "items": { + "type": "string", + "minLength": 1 + }, + "description": "Denylist of network domains for sandboxed commands. Supports wildcard patterns like *.example.com" } }, "additionalProperties": false @@ -863,6 +923,28 @@ }, "additionalProperties": false }, + "spinnerVerbs": { + "type": "object", + "description": "Customize the verbs shown in spinner progress messages", + "properties": { + "mode": { + "type": "string", + "enum": ["append", "replace"], + "description": "How custom verbs should be combined with the default spinner verbs" + }, + "verbs": { + "type": "array", + "items": { + "type": "string", + "minLength": 1 + }, + "minItems": 1, + "description": "Custom verbs used in spinner progress text" + } + }, + "required": ["verbs"], + "additionalProperties": false + }, "spinnerTipsEnabled": { "type": "boolean", "description": "Show tips in the spinner while Claude is working. Set to false to disable tips (default: true)", diff --git a/src/test/claude-code-settings/hooks-complete.json b/src/test/claude-code-settings/hooks-complete.json index 922b8a4fba7..b1ea64991d9 100644 --- a/src/test/claude-code-settings/hooks-complete.json +++ b/src/test/claude-code-settings/hooks-complete.json @@ -44,6 +44,7 @@ { "hooks": [ { + "async": true, "command": "echo 'Running bash command' >> /tmp/claude-log.txt", "timeout": 5, "type": "command" diff --git a/src/test/claude-code-settings/marketplace-host-pattern.json b/src/test/claude-code-settings/marketplace-host-pattern.json new file mode 100644 index 00000000000..2ceda674c17 --- /dev/null +++ b/src/test/claude-code-settings/marketplace-host-pattern.json @@ -0,0 +1,16 @@ +{ + "extraKnownMarketplaces": { + "internal-git": { + "source": { + "hostPattern": "git.internal.example.com", + "source": "hostPattern" + } + } + }, + "strictKnownMarketplaces": [ + { + "hostPattern": "*.corp.example", + "source": "hostPattern" + } + ] +} diff --git a/src/test/claude-code-settings/modern-complete-config.json b/src/test/claude-code-settings/modern-complete-config.json index 4caee0a228e..da57e3e4044 100644 --- a/src/test/claude-code-settings/modern-complete-config.json +++ b/src/test/claude-code-settings/modern-complete-config.json @@ -15,6 +15,14 @@ "CLAUDE_LOG_LEVEL": "debug", "PROJECT_ROOT": "/home/user/projects" }, + "extraKnownMarketplaces": { + "corp-git-host": { + "source": { + "hostPattern": "git.corp.example", + "source": "hostPattern" + } + } + }, "fileSuggestion": { "command": "~/.claude/file-suggestion.sh", "type": "command" @@ -74,6 +82,19 @@ }, "plansDirectory": "./plans", "respectGitignore": true, + "sandbox": { + "network": { + "allowAllUnixSockets": false, + "allowLocalBinding": true, + "allowedDomains": ["api.anthropic.com", "*.example.com"], + "deniedDomains": ["malware.example"], + "socksProxyPort": 11080 + } + }, "showTurnDuration": true, + "spinnerVerbs": { + "mode": "append", + "verbs": ["Analyzing", "Building"] + }, "terminalProgressBarEnabled": true }