@@ -3031,16 +3031,57 @@ def configure_all_mcp_servers(servers: list[dict[str, Any]]) -> bool:
30313031 return True
30323032
30333033
3034+ def download_hook_files (
3035+ hooks : dict [str , Any ],
3036+ claude_user_dir : Path ,
3037+ config_source : str | None = None ,
3038+ base_url : str | None = None ,
3039+ auth_param : str | None = None ,
3040+ ) -> bool :
3041+ """Download hook files from configuration.
3042+
3043+ Args:
3044+ hooks: Hooks configuration dictionary with 'files' key
3045+ claude_user_dir: Path to Claude user directory
3046+ config_source: Optional config source for resolving resource paths
3047+ base_url: Optional base URL for resolving resources
3048+ auth_param: Optional authentication parameter
3049+
3050+ Returns:
3051+ bool: True if successful, False otherwise.
3052+ """
3053+ hook_files = hooks .get ('files' , [])
3054+
3055+ if not hook_files :
3056+ info ('No hook files to download' )
3057+ return True
3058+
3059+ hooks_dir = claude_user_dir / 'hooks'
3060+ hooks_dir .mkdir (parents = True , exist_ok = True )
3061+
3062+ for file in hook_files :
3063+ # Strip query parameters from URL to get clean filename
3064+ clean_file = file .split ('?' )[0 ] if '?' in file else file
3065+ filename = Path (clean_file ).name
3066+ destination = hooks_dir / filename
3067+ # Handle hook files (download or copy)
3068+ if config_source :
3069+ handle_resource (file , destination , config_source , base_url , auth_param )
3070+ else :
3071+ # This shouldn't happen, but handle gracefully
3072+ error (f'No config source provided for hook file: { file } ' )
3073+ return False
3074+
3075+ return True
3076+
3077+
30343078def create_additional_settings (
30353079 hooks : dict [str , Any ],
30363080 claude_user_dir : Path ,
30373081 command_name : str ,
30383082 model : str | None = None ,
30393083 permissions : dict [str , Any ] | None = None ,
30403084 env : dict [str , str ] | None = None ,
3041- config_source : str | None = None ,
3042- base_url : str | None = None ,
3043- auth_param : str | None = None ,
30443085 include_co_authored_by : bool | None = None ,
30453086) -> bool :
30463087 """Create {command_name}-additional-settings.json with environment-specific settings.
@@ -3055,9 +3096,6 @@ def create_additional_settings(
30553096 model: Optional model alias or custom model name
30563097 permissions: Optional permissions configuration dict
30573098 env: Optional environment variables dict
3058- config_source: Optional config source for resolving resource paths
3059- base_url: Optional base URL for resolving resources
3060- auth_param: Optional authentication parameter
30613099 include_co_authored_by: Optional flag to include co-authored-by in commits
30623100
30633101 Returns:
@@ -3098,31 +3136,13 @@ def create_additional_settings(
30983136 info (f'Setting includeCoAuthoredBy: { include_co_authored_by } ' )
30993137
31003138 # Handle hooks if present
3101- hook_files : list [str ] = []
31023139 hook_events : list [dict [str , Any ]] = []
31033140
31043141 if hooks :
31053142 settings ['hooks' ] = {}
3106- # Extract files and events from the hooks configuration
3107- hook_files = hooks .get ('files' , [])
3143+ # Extract events from the hooks configuration (files are downloaded separately)
31083144 hook_events = hooks .get ('events' , [])
31093145
3110- # Process all hook files first
3111- if hook_files :
3112- hooks_dir = claude_user_dir / 'hooks'
3113- hooks_dir .mkdir (parents = True , exist_ok = True )
3114- for file in hook_files :
3115- # Strip query parameters from URL to get clean filename
3116- clean_file = file .split ('?' )[0 ] if '?' in file else file
3117- filename = Path (clean_file ).name
3118- destination = hooks_dir / filename
3119- # Handle hook files (download or copy)
3120- if config_source :
3121- handle_resource (file , destination , config_source , base_url , auth_param )
3122- else :
3123- # This shouldn't happen, but handle gracefully
3124- error (f'No config source provided for hook file: { file } ' )
3125-
31263146 # Process each hook event
31273147 for hook in hook_events :
31283148 event = hook .get ('event' )
@@ -4076,44 +4096,46 @@ def main() -> None:
40764096
40774097 # Check if command creation is needed
40784098 if command_name :
4079- # Step 11: Configure hooks and settings
4099+ # Step 11: Download hooks
40804100 print ()
4081- print (f'{ Colors .CYAN } Step 11: Configuring hooks and settings ...{ Colors .NC } ' )
4101+ print (f'{ Colors .CYAN } Step 11: Downloading hooks...{ Colors .NC } ' )
40824102 hooks = config .get ('hooks' , {})
4103+ download_hook_files (hooks , claude_user_dir , config_source , base_url , args .auth )
4104+
4105+ # Step 12: Configure settings
4106+ print ()
4107+ print (f'{ Colors .CYAN } Step 12: Configuring settings...{ Colors .NC } ' )
40834108 create_additional_settings (
40844109 hooks ,
40854110 claude_user_dir ,
40864111 command_name ,
40874112 model ,
40884113 permissions ,
40894114 env_variables ,
4090- config_source ,
4091- base_url ,
4092- args .auth ,
40934115 include_co_authored_by ,
40944116 )
40954117
4096- # Step 12 : Create launcher script
4118+ # Step 13 : Create launcher script
40974119 print ()
4098- print (f'{ Colors .CYAN } Step 12 : Creating launcher script...{ Colors .NC } ' )
4120+ print (f'{ Colors .CYAN } Step 13 : Creating launcher script...{ Colors .NC } ' )
40994121 # Strip query parameters from system prompt filename (must match download logic)
41004122 prompt_filename : str | None = None
41014123 if system_prompt :
41024124 clean_prompt = system_prompt .split ('?' )[0 ] if '?' in system_prompt else system_prompt
41034125 prompt_filename = Path (clean_prompt ).name
41044126 launcher_path = create_launcher_script (claude_user_dir , command_name , prompt_filename , mode )
41054127
4106- # Step 13 : Register global command
4128+ # Step 14 : Register global command
41074129 if launcher_path :
41084130 print ()
4109- print (f'{ Colors .CYAN } Step 13 : Registering global { command_name } command...{ Colors .NC } ' )
4131+ print (f'{ Colors .CYAN } Step 14 : Registering global { command_name } command...{ Colors .NC } ' )
41104132 register_global_command (launcher_path , command_name )
41114133 else :
41124134 warning ('Launcher script was not created' )
41134135 else :
41144136 # Skip command creation
41154137 print ()
4116- print (f'{ Colors .CYAN } Steps 11-13 : Skipping command creation (no command-name specified)...{ Colors .NC } ' )
4138+ print (f'{ Colors .CYAN } Steps 11-14 : Skipping command creation (no command-name specified)...{ Colors .NC } ' )
41174139 info ('Environment configuration completed successfully' )
41184140 info ('To create a custom command, add "command-name: your-command-name" to your config' )
41194141
@@ -4132,9 +4154,9 @@ def main() -> None:
41324154 print (f' * Skills: { len (skills )} installed' )
41334155 if system_prompt :
41344156 if mode == 'append' :
4135- print (f ' * System prompt: Appending to default ( { system_prompt } ) ' )
4157+ print (' * System prompt: appending to default' )
41364158 else : # mode == 'replace'
4137- print (f ' * System prompt: Replacing default ( { system_prompt } ) ' )
4159+ print (' * System prompt: replacing default' )
41384160 if model :
41394161 print (f' * Model: { model } ' )
41404162 print (f' * MCP servers: { len (mcp_servers )} configured' )
@@ -4156,9 +4178,9 @@ def main() -> None:
41564178 set_vars = sum (1 for v in os_env_variables .values () if v is not None )
41574179 del_vars = sum (1 for v in os_env_variables .values () if v is None )
41584180 if set_vars > 0 :
4159- print (f' * OS env variables set : { set_vars } ' )
4181+ print (f' * OS environment variables: { set_vars } configured ' )
41604182 if del_vars > 0 :
4161- print (f' * OS env variables deleted : { del_vars } ' )
4183+ print (f' * OS environment variables: { del_vars } deleted ' )
41624184 # Only show hooks count if command_name was specified (hooks was defined)
41634185 if command_name :
41644186 hooks = config .get ('hooks' , {})
@@ -4190,7 +4212,7 @@ def main() -> None:
41904212 print ()
41914213 print (f'{ Colors .YELLOW } Documentation:{ Colors .NC } ' )
41924214 print (' * Setup Guide: https://github.com/alex-feel/claude-code-toolbox' )
4193- print (' * Claude Code Docs: https://docs.anthropic .com/claude-code ' )
4215+ print (' * Claude Code Docs: https://code.claude .com/docs ' )
41944216 print ()
41954217
41964218 # If running elevated via UAC, add a pause so user can see the results
0 commit comments