diff --git a/adapters/claude/config/settings.json b/adapters/claude/config/settings.json index 4b5d4cb..a7b37d1 100644 --- a/adapters/claude/config/settings.json +++ b/adapters/claude/config/settings.json @@ -12,7 +12,7 @@ ] }, "env": { - "CLAUDE_CODE_MAX_TOOL_USE_CONCURRENCY": "5" + "CLAUDE_CODE_MAX_TOOL_USE_CONCURRENCY": "__CLAUDE_CODE_MAX_TOOL_USE_CONCURRENCY__" }, "statusLine": { "type": "command", diff --git a/adapters/codex/config/config.toml b/adapters/codex/config/config.toml index cea7612..0e4300d 100644 --- a/adapters/codex/config/config.toml +++ b/adapters/codex/config/config.toml @@ -8,7 +8,6 @@ status_line = ["model", "reasoning", "approval-mode", "project-name", "git-branc [agents] enabled = true max_concurrent_threads_per_session = 5 -max_depth = 1 [features] hooks = true diff --git a/scripts/build.ps1 b/scripts/build.ps1 index 857130a..0a608b7 100644 --- a/scripts/build.ps1 +++ b/scripts/build.ps1 @@ -210,7 +210,7 @@ $leftoverPlaceholders = @(Get-ChildItem $output -File -Recurse | ForEach-Object # expected to remain in generated output. -cmatch keeps this case-sensitive so Python # dunder names (__main__, __name__) in flashbang.sh are not mistaken for placeholders. $content = (Get-Content -LiteralPath $_.FullName -Raw) -replace '__AI_CONFIG_ROOT__|__POWERSHELL_COMMAND__', '' - if ($content -cmatch '__[A-Z0-9_]+__') { $_.FullName } + if ($content -cmatch '__[A-Z0-9_]+__' -and $content -notmatch '__CLAUDE_CODE_MAX_TOOL_USE_CONCURRENCY__') { $_.FullName } }) if ($leftoverPlaceholders.Count) { throw "Unresolved template placeholders in: $($leftoverPlaceholders -join ', ')" } diff --git a/scripts/build.sh b/scripts/build.sh index b50e6b0..51f2f6b 100755 --- a/scripts/build.sh +++ b/scripts/build.sh @@ -227,7 +227,7 @@ done # __AI_CONFIG_ROOT__ is resolved at install time, once the destination is known; it is # expected to remain in generated output, so it is excluded from the leftover check. A # single tree-wide grep (rather than one process per file) keeps this fast. -leftover_tokens=$(grep -RohE '__[A-Z0-9_]+__' "$output" 2>/dev/null | sort -u | grep -Ev '^(__AI_CONFIG_ROOT__|__POWERSHELL_COMMAND__)$' || true) +leftover_tokens=$(grep -RohE '__[A-Z0-9_]+__' "$output" 2>/dev/null | sort -u | grep -Ev '^(__AI_CONFIG_ROOT__|__POWERSHELL_COMMAND__|__CLAUDE_CODE_MAX_TOOL_USE_CONCURRENCY__)$' || true) if [ -n "$leftover_tokens" ]; then offending_files=$(grep -RlE '__[A-Z0-9_]+__' "$output" 2>/dev/null | tr '\n' ' ') printf 'Unresolved template placeholders (%s) in: %s\n' "$(printf '%s' "$leftover_tokens" | tr '\n' ' ')" "$offending_files" >&2 diff --git a/scripts/install.ps1 b/scripts/install.ps1 index 27ac222..56dfb01 100644 --- a/scripts/install.ps1 +++ b/scripts/install.ps1 @@ -34,13 +34,15 @@ if (-not (Test-Path $generated)) { throw 'Generated output is missing after a su $stamp = Get-Date -Format 'yyyyMMdd-HHmmss' $powerShellCommand = if (Get-Command powershell -ErrorAction SilentlyContinue) { 'powershell -NoProfile -ExecutionPolicy Bypass -File' } else { 'pwsh -NoProfile -ExecutionPolicy Bypass -File' } $shellCommand = if ($Shell -eq 'PowerShell') { $powerShellCommand } else { 'bash' } +$claudeConcurrency = if ($env:CLAUDE_CODE_MAX_TOOL_USE_CONCURRENCY) { $env:CLAUDE_CODE_MAX_TOOL_USE_CONCURRENCY } else { '5' } +if ($claudeConcurrency -notmatch '^[1-9][0-9]?$' -or [int]$claudeConcurrency -gt 10) { throw 'CLAUDE_CODE_MAX_TOOL_USE_CONCURRENCY must be an integer from 1 to 10.' } $plugins = Select-ConfiguredPlugins -RepositoryRoot $root -HomePath $homePath -Client $Client -Mode 'Install' -DryRun:$DryRun if ($options.update_agents) { Update-SelectedAgentClis -Client $Client -DryRun:$DryRun -Summary:$Summary } foreach ($item in (Get-InstallTargets -Generated $generated -HomePath $homePath -Shell $shell -Client $Client)) { Sync-ManagedDestination -Source $item.Source -Destination $item.Destination -Stamp $stamp ` - -AiConfigRoot $item.Destination.Replace('\','/') -ShellCommand $shellCommand -PowerShellCommand $powerShellCommand -FlashbangEnabled $options.flashbang -DryRun:$DryRun -Summary:$Summary + -AiConfigRoot $item.Destination.Replace('\','/') -ShellCommand $shellCommand -PowerShellCommand $powerShellCommand -ClaudeConcurrency $claudeConcurrency -FlashbangEnabled $options.flashbang -DryRun:$DryRun -Summary:$Summary } Sync-ConfiguredPlugins -RepositoryRoot $root -HomePath $homePath -Client $Client -DryRun:$DryRun -Summary:$Summary -Entries $plugins.Selected diff --git a/scripts/install.sh b/scripts/install.sh index 0ca2752..028e7d0 100755 --- a/scripts/install.sh +++ b/scripts/install.sh @@ -48,6 +48,8 @@ powershell_command='pwsh -NoProfile -ExecutionPolicy Bypass -File' if command -v powershell >/dev/null; then powershell_command='powershell -NoProfile -ExecutionPolicy Bypass -File'; fi shell_command=bash [ "$shell" != powershell ] || shell_command=$powershell_command +claude_concurrency=${CLAUDE_CODE_MAX_TOOL_USE_CONCURRENCY:-5} +[[ "$claude_concurrency" =~ ^[1-9][0-9]?$ ]] && [ "$claude_concurrency" -le 10 ] || { printf 'CLAUDE_CODE_MAX_TOOL_USE_CONCURRENCY must be an integer from 1 to 10.\n' >&2; exit 1; } selected_plugins=() deselected_plugins=() @@ -57,7 +59,7 @@ select_configured_plugins "$root" "$client" Install "$dry_run" selected_plugins while IFS='|' read -r source destination; do ai_config_root=$destination command -v cygpath >/dev/null && ai_config_root=$(cygpath -m "$destination") - sync_managed_destination "$source" "$destination" "$stamp" "$ai_config_root" "$shell_command" "$powershell_command" "$dry_run" "$summary" "$flashbang" + sync_managed_destination "$source" "$destination" "$stamp" "$ai_config_root" "$shell_command" "$powershell_command" "$dry_run" "$summary" "$flashbang" "$claude_concurrency" done < <(get_install_targets "$generated" "$home_path" "$shell" "$client") sync_configured_plugins "$root" "$client" "$home_path" "$dry_run" false selected_plugins "$summary" diff --git a/scripts/lib/manifest.ps1 b/scripts/lib/manifest.ps1 index 2590b33..1a3a154 100644 --- a/scripts/lib/manifest.ps1 +++ b/scripts/lib/manifest.ps1 @@ -56,6 +56,7 @@ function Sync-ManagedDestination { [string]$AiConfigRoot, [string]$ShellCommand, [string]$PowerShellCommand, + [string]$ClaudeConcurrency = '5', [bool]$FlashbangEnabled = $true, [switch]$DryRun, [switch]$Summary @@ -78,7 +79,7 @@ function Sync-ManagedDestination { } $needsSubstitution = $filterFlashbang -or $rawContent.Contains('__AI_CONFIG_ROOT__') -or $rawContent.Contains('__HOOK_COMMAND__') -or $rawContent.Contains('__POWERSHELL_HOOK_COMMAND__') -or $rawContent.Contains('__POWERSHELL_COMMAND__') if ($needsSubstitution) { - $finalContent = $rawContent.Replace('__AI_CONFIG_ROOT__', $AiConfigRoot).Replace('__HOOK_COMMAND__', $ShellCommand).Replace('__POWERSHELL_HOOK_COMMAND__', $PowerShellCommand).Replace('__POWERSHELL_COMMAND__', $PowerShellCommand).Replace('__HOOK_SCRIPT__', 'flashbang.ps1').Replace('__POWERSHELL_HOOK_SCRIPT__', 'flashbang.ps1') + $finalContent = $rawContent.Replace('__AI_CONFIG_ROOT__', $AiConfigRoot).Replace('__HOOK_COMMAND__', $ShellCommand).Replace('__POWERSHELL_HOOK_COMMAND__', $PowerShellCommand).Replace('__POWERSHELL_COMMAND__', $PowerShellCommand).Replace('__CLAUDE_CODE_MAX_TOOL_USE_CONCURRENCY__', $ClaudeConcurrency).Replace('__HOOK_SCRIPT__', 'flashbang.ps1').Replace('__POWERSHELL_HOOK_SCRIPT__', 'flashbang.ps1') $newBytes = [System.Text.Encoding]::UTF8.GetBytes($finalContent) } else { $newBytes = [System.IO.File]::ReadAllBytes($_.FullName) diff --git a/scripts/lib/manifest.sh b/scripts/lib/manifest.sh index 48a87ce..2d25039 100755 --- a/scripts/lib/manifest.sh +++ b/scripts/lib/manifest.sh @@ -49,9 +49,9 @@ write_managed_manifest() { } > "$path" } -# sync_managed_destination [summary: true|false] +# sync_managed_destination [summary: true|false] [flashbang] [claude-concurrency] sync_managed_destination() { - local source=$1 destination=$2 stamp=$3 ai_config_root=$4 shell_command=$5 powershell_command=$6 dry_run=$7 summary=${8:-false} flashbang_enabled=${9:-true} + local source=$1 destination=$2 stamp=$3 ai_config_root=$4 shell_command=$5 powershell_command=$6 dry_run=$7 summary=${8:-false} flashbang_enabled=${9:-true} claude_concurrency=${10:-5} [ "$summary" = true ] || printf 'SOURCE %s -> %s\n' "$source" "$destination" local manifest manifest=$(manifest_path "$destination") @@ -77,6 +77,7 @@ sync_managed_destination() { content=${content//__HOOK_COMMAND__/$shell_command} content=${content//__POWERSHELL_HOOK_COMMAND__/$powershell_command} content=${content//__POWERSHELL_COMMAND__/$powershell_command} + content=${content//__CLAUDE_CODE_MAX_TOOL_USE_CONCURRENCY__/$claude_concurrency} content=${content//__HOOK_SCRIPT__/flashbang.sh} content=${content//__POWERSHELL_HOOK_SCRIPT__/flashbang.sh} new_hash=$(sha256_of_string "$content")