@@ -773,7 +773,7 @@ def _maybe_refresh(self):
773773 pass
774774
775775 def render (self ):
776- tree = Tree (f"[cyan] { self .title } [/cyan]" , guide_style = "grey50" )
776+ tree = Tree (Text ( self .title , style = ACCENT_COLOR ) , guide_style = "grey50" )
777777 for step in self .steps :
778778 label = step ["label" ]
779779 detail_text = step ["detail" ].strip () if step ["detail" ] else ""
@@ -784,7 +784,7 @@ def render(self):
784784 elif status == "pending" :
785785 symbol = "[green dim]○[/green dim]"
786786 elif status == "running" :
787- symbol = "[cyan ]○[/cyan ]"
787+ symbol = f"[ { ACCENT_COLOR } ]○[/{ ACCENT_COLOR } ]"
788788 elif status == "error" :
789789 symbol = "[red]●[/red]"
790790 elif status == "skipped" :
@@ -859,14 +859,20 @@ def select_with_arrows(
859859 def create_selection_panel ():
860860 """Create the selection panel with current selection highlighted."""
861861 table = Table .grid (padding = (0 , 2 ))
862- table .add_column (style = "cyan" , justify = "left" , width = 3 )
862+ table .add_column (style = ACCENT_COLOR , justify = "left" , width = 3 )
863863 table .add_column (style = "white" , justify = "left" )
864864
865865 for i , key in enumerate (option_keys ):
866866 if i == selected_index :
867- table .add_row ("▶" , f"[cyan]{ key } [/cyan] [dim]({ options [key ]} )[/dim]" )
867+ table .add_row (
868+ "▶" ,
869+ f"[{ ACCENT_COLOR } ]{ key } [/{ ACCENT_COLOR } ] [dim]({ options [key ]} )[/dim]" ,
870+ )
868871 else :
869- table .add_row (" " , f"[cyan]{ key } [/cyan] [dim]({ options [key ]} )[/dim]" )
872+ table .add_row (
873+ " " ,
874+ f"[{ ACCENT_COLOR } ]{ key } [/{ ACCENT_COLOR } ] [dim]({ options [key ]} )[/dim]" ,
875+ )
870876
871877 table .add_row ("" , "" )
872878 table .add_row (
@@ -876,7 +882,7 @@ def create_selection_panel():
876882 return Panel (
877883 table ,
878884 title = f"[bold]{ prompt_text } [/bold]" ,
879- border_style = "cyan" ,
885+ border_style = ACCENT_COLOR ,
880886 padding = (1 , 2 ),
881887 )
882888
@@ -1796,7 +1802,9 @@ def init_git_repo(
17961802 try :
17971803 os .chdir (project_path )
17981804 if not quiet :
1799- console .print ("[cyan]Initializing git repository...[/cyan]" )
1805+ console .print (
1806+ f"[{ ACCENT_COLOR } ]Initializing git repository...[/{ ACCENT_COLOR } ]"
1807+ )
18001808 subprocess .run (["git" , "init" ], check = True , capture_output = True , text = True )
18011809 subprocess .run (["git" , "add" , "." ], check = True , capture_output = True , text = True )
18021810 subprocess .run (
@@ -1987,7 +1995,9 @@ def deep_merge_polite(
19871995 return None
19881996
19891997 if verbose :
1990- console .print (f"[cyan]Merged JSON file:[/cyan] { existing_path .name } " )
1998+ console .print (
1999+ f"[{ ACCENT_COLOR } ]Merged JSON file:[/{ ACCENT_COLOR } ] { existing_path .name } "
2000+ )
19912001
19922002 return merged
19932003
@@ -2009,7 +2019,9 @@ def download_template_from_github(
20092019 client = httpx .Client (verify = ssl_context )
20102020
20112021 if verbose :
2012- console .print ("[cyan]Fetching latest release information...[/cyan]" )
2022+ console .print (
2023+ f"[{ ACCENT_COLOR } ]Fetching latest release information...[/{ ACCENT_COLOR } ]"
2024+ )
20132025 api_url = f"https://api.github.com/repos/{ repo_owner } /{ repo_name } /releases/latest"
20142026
20152027 try :
@@ -2066,13 +2078,15 @@ def download_template_from_github(
20662078 file_size = asset ["size" ]
20672079
20682080 if verbose :
2069- console .print (f"[cyan]Found template:[/cyan] { filename } " )
2070- console .print (f"[cyan]Size:[/cyan] { file_size :,} bytes" )
2071- console .print (f"[cyan]Release:[/cyan] { release_data ['tag_name' ]} " )
2081+ console .print (f"[{ ACCENT_COLOR } ]Found template:[/{ ACCENT_COLOR } ] { filename } " )
2082+ console .print (f"[{ ACCENT_COLOR } ]Size:[/{ ACCENT_COLOR } ] { file_size :,} bytes" )
2083+ console .print (
2084+ f"[{ ACCENT_COLOR } ]Release:[/{ ACCENT_COLOR } ] { release_data ['tag_name' ]} "
2085+ )
20722086
20732087 zip_path = download_dir / filename
20742088 if verbose :
2075- console .print ("[cyan ]Downloading template...[/cyan ]" )
2089+ console .print (f"[ { ACCENT_COLOR } ]Downloading template...[/{ ACCENT_COLOR } ]" )
20762090
20772091 try :
20782092 with client .stream (
@@ -2190,7 +2204,9 @@ def download_and_extract_template(
21902204 tracker .start ("zip-list" )
21912205 tracker .complete ("zip-list" , f"{ len (zip_contents )} entries" )
21922206 elif verbose :
2193- console .print (f"[cyan]ZIP contains { len (zip_contents )} items[/cyan]" )
2207+ console .print (
2208+ f"[{ ACCENT_COLOR } ]ZIP contains { len (zip_contents )} items[/{ ACCENT_COLOR } ]"
2209+ )
21942210
21952211 if is_current_dir :
21962212 with tempfile .TemporaryDirectory () as temp_dir :
@@ -2205,7 +2221,7 @@ def download_and_extract_template(
22052221 )
22062222 elif verbose :
22072223 console .print (
2208- f"[cyan ]Extracted { len (extracted_items )} items to temp location[/cyan ]"
2224+ f"[{ ACCENT_COLOR } ]Extracted { len (extracted_items )} items to temp location[/{ ACCENT_COLOR } ]"
22092225 )
22102226
22112227 source_dir = temp_path
@@ -2216,7 +2232,7 @@ def download_and_extract_template(
22162232 tracker .complete ("flatten" )
22172233 elif verbose :
22182234 console .print (
2219- "[cyan ]Found nested directory structure[/cyan ]"
2235+ f"[ { ACCENT_COLOR } ]Found nested directory structure[/{ ACCENT_COLOR } ]"
22202236 )
22212237
22222238 for item in source_dir .iterdir ():
@@ -2258,7 +2274,7 @@ def download_and_extract_template(
22582274 shutil .copy2 (item , dest_path )
22592275 if verbose and not tracker :
22602276 console .print (
2261- "[cyan ]Template files merged into current directory[/cyan ]"
2277+ f"[ { ACCENT_COLOR } ]Template files merged into current directory[/{ ACCENT_COLOR } ]"
22622278 )
22632279 else :
22642280 zip_ref .extractall (project_path )
@@ -2271,7 +2287,7 @@ def download_and_extract_template(
22712287 )
22722288 elif verbose :
22732289 console .print (
2274- f"[cyan ]Extracted { len (extracted_items )} items to { project_path } :[/cyan ]"
2290+ f"[{ ACCENT_COLOR } ]Extracted { len (extracted_items )} items to { project_path } :[/{ ACCENT_COLOR } ]"
22752291 )
22762292 for item in extracted_items :
22772293 console .print (
@@ -2292,7 +2308,7 @@ def download_and_extract_template(
22922308 tracker .complete ("flatten" )
22932309 elif verbose :
22942310 console .print (
2295- "[cyan ]Flattened nested directory structure[/cyan ]"
2311+ f"[ { ACCENT_COLOR } ]Flattened nested directory structure[/{ ACCENT_COLOR } ]"
22962312 )
22972313
22982314 except Exception as e :
@@ -2373,7 +2389,7 @@ def ensure_executable_scripts(
23732389 else :
23742390 if updated :
23752391 console .print (
2376- f"[cyan ]Updated execute permissions on { updated } script(s) recursively[/cyan ]"
2392+ f"[{ ACCENT_COLOR } ]Updated execute permissions on { updated } script(s) recursively[/{ ACCENT_COLOR } ]"
23772393 )
23782394 if failures :
23792395 console .print ("[yellow]Some scripts could not be updated:[/yellow]" )
@@ -2412,7 +2428,9 @@ def ensure_constitution_from_template(
24122428 tracker .add ("constitution" , "Constitution setup" )
24132429 tracker .complete ("constitution" , "copied from template" )
24142430 else :
2415- console .print ("[cyan]Initialized constitution from template[/cyan]" )
2431+ console .print (
2432+ f"[{ ACCENT_COLOR } ]Initialized constitution from template[/{ ACCENT_COLOR } ]"
2433+ )
24162434 except Exception as e :
24172435 if tracker :
24182436 tracker .add ("constitution" , "Constitution setup" )
@@ -3256,7 +3274,7 @@ def init(
32563274 )
32573275 if force :
32583276 console .print (
3259- "[cyan ]--force supplied: skipping confirmation and proceeding with merge[/cyan ]"
3277+ f"[ { ACCENT_COLOR } ]--force supplied: skipping confirmation and proceeding with merge[/{ ACCENT_COLOR } ]"
32603278 )
32613279 else :
32623280 response = typer .confirm ("Do you want to continue?" )
@@ -3329,7 +3347,7 @@ def init(
33293347 current_dir = Path .cwd ()
33303348
33313349 setup_lines = [
3332- "[cyan ]Specify Project Setup[/cyan ]" ,
3350+ f"[ { ACCENT_COLOR } ]Specify Project Setup[/{ ACCENT_COLOR } ]" ,
33333351 "" ,
33343352 f"{ 'Project' :<15} [green]{ project_path .name } [/green]" ,
33353353 f"{ 'Working Path' :<15} [dim]{ current_dir } [/dim]" ,
@@ -3338,7 +3356,9 @@ def init(
33383356 if not here :
33393357 setup_lines .append (f"{ 'Target Path' :<15} [dim]{ project_path } [/dim]" )
33403358
3341- console .print (Panel ("\n " .join (setup_lines ), border_style = "cyan" , padding = (1 , 2 )))
3359+ console .print (
3360+ Panel ("\n " .join (setup_lines ), border_style = ACCENT_COLOR , padding = (1 , 2 ))
3361+ )
33423362
33433363 should_init_git = False
33443364 if not no_git :
@@ -3354,10 +3374,10 @@ def init(
33543374 install_url = agent_config ["install_url" ]
33553375 if not check_tool (selected_ai ):
33563376 error_panel = Panel (
3357- f"[cyan ]{ selected_ai } [/cyan ] not found\n "
3358- f"Install from: [cyan ]{ install_url } [/cyan ]\n "
3377+ f"[{ ACCENT_COLOR } ]{ selected_ai } [/{ ACCENT_COLOR } ] not found\n "
3378+ f"Install from: [{ ACCENT_COLOR } ]{ install_url } [/{ ACCENT_COLOR } ]\n "
33593379 f"{ agent_config ['name' ]} is required to continue with this project type.\n \n "
3360- "Tip: Use [cyan ]--ignore-agent-tools[/cyan ] to skip this check" ,
3380+ f "Tip: Use [{ ACCENT_COLOR } ]--ignore-agent-tools[/{ ACCENT_COLOR } ] to skip this check" ,
33613381 title = "[red]Agent Detection Error[/red]" ,
33623382 border_style = "red" ,
33633383 padding = (1 , 2 ),
@@ -3385,8 +3405,12 @@ def init(
33853405 else :
33863406 selected_script = default_script
33873407
3388- console .print (f"[cyan]Selected AI assistant:[/cyan] { selected_ai } " )
3389- console .print (f"[cyan]Selected script type:[/cyan] { selected_script } " )
3408+ console .print (
3409+ f"[{ ACCENT_COLOR } ]Selected AI assistant:[/{ ACCENT_COLOR } ] { selected_ai } "
3410+ )
3411+ console .print (
3412+ f"[{ ACCENT_COLOR } ]Selected script type:[/{ ACCENT_COLOR } ] { selected_script } "
3413+ )
33903414
33913415 tracker = StepTracker ("Initialize Specify Project" )
33923416
@@ -3638,10 +3662,10 @@ def init(
36383662 f"[yellow]Warning:[/yellow] Git repository initialization failed\n \n "
36393663 f"{ git_error_message } \n \n "
36403664 f"[dim]You can initialize git manually later with:[/dim]\n "
3641- f"[cyan ]cd { project_path if not here else '.' } [/cyan ]\n "
3642- f"[cyan ]git init[/cyan ]\n "
3643- f"[cyan ]git add .[/cyan ]\n "
3644- f'[cyan ]git commit -m "Initial commit"[/cyan ]' ,
3665+ f"[{ ACCENT_COLOR } ]cd { project_path if not here else '.' } [/{ ACCENT_COLOR } ]\n "
3666+ f"[{ ACCENT_COLOR } ]git init[/{ ACCENT_COLOR } ]\n "
3667+ f"[{ ACCENT_COLOR } ]git add .[/{ ACCENT_COLOR } ]\n "
3668+ f'[{ ACCENT_COLOR } ]git commit -m "Initial commit"[/{ ACCENT_COLOR } ]' ,
36453669 title = "[red]Git Initialization Failed[/red]" ,
36463670 border_style = "red" ,
36473671 padding = (1 , 2 ),
@@ -3685,44 +3709,79 @@ def init(
36853709 cmd = f"export CODEX_HOME={ quoted_path } "
36863710
36873711 steps_lines .append (
3688- f"{ step_num } . Set [cyan ]CODEX_HOME[/cyan ] environment variable before running Codex: [cyan ]{ cmd } [/cyan ]"
3712+ f"{ step_num } . Set [{ ACCENT_COLOR } ]CODEX_HOME[/{ ACCENT_COLOR } ] environment variable before running Codex: [{ ACCENT_COLOR } ]{ cmd } [/{ ACCENT_COLOR } ]"
36893713 )
36903714 step_num += 1
36913715
36923716 steps_lines .append (f"{ step_num } . Start using slash commands with your AI agent:" )
36933717
36943718 steps_lines .append (
3695- " 2.1 [cyan]/speckit.constitution[/] - Establish project principles"
3719+ f" 2.1 [{ ACCENT_COLOR } ]/spec.constitution[/] - Establish project principles"
3720+ )
3721+ steps_lines .append (
3722+ f" 2.2 [{ ACCENT_COLOR } ]/spec.specify[/] - Create baseline specification"
3723+ )
3724+ steps_lines .append (
3725+ f" 2.3 [{ ACCENT_COLOR } ]/spec.plan[/] - Create implementation plan"
3726+ )
3727+ steps_lines .append (
3728+ f" 2.4 [{ ACCENT_COLOR } ]/spec.tasks[/] - Generate actionable tasks"
36963729 )
36973730 steps_lines .append (
3698- " 2.2 [cyan]/speckit.specify [/] - Create baseline specification "
3731+ f " 2.5 [ { ACCENT_COLOR } ]/spec.implement [/] - Execute implementation "
36993732 )
3700- steps_lines .append (" 2.3 [cyan]/speckit.plan[/] - Create implementation plan" )
3701- steps_lines .append (" 2.4 [cyan]/speckit.tasks[/] - Generate actionable tasks" )
3702- steps_lines .append (" 2.5 [cyan]/speckit.implement[/] - Execute implementation" )
37033733
37043734 steps_panel = Panel (
3705- "\n " .join (steps_lines ), title = "Next Steps" , border_style = "cyan" , padding = (1 , 2 )
3735+ "\n " .join (steps_lines ),
3736+ title = "Next Steps" ,
3737+ border_style = ACCENT_COLOR ,
3738+ padding = (1 , 2 ),
37063739 )
37073740 console .print ()
37083741 console .print (steps_panel )
37093742
37103743 enhancement_lines = [
37113744 "Optional commands that you can use for your specs [bright_black](improve quality & confidence)[/bright_black]" ,
37123745 "" ,
3713- "○ [cyan]/speckit .clarify[/] [bright_black](optional)[/bright_black] - Ask structured questions to de-risk ambiguous areas before planning (run before [cyan]/speckit .plan[/] if used)" ,
3714- "○ [cyan]/speckit .analyze[/] [bright_black](optional)[/bright_black] - Cross-artifact consistency & alignment report (after [cyan]/speckit .tasks[/], before [cyan]/speckit .implement[/])" ,
3715- "○ [cyan]/speckit .checklist[/] [bright_black](optional)[/bright_black] - Generate quality checklists to validate requirements completeness, clarity, and consistency (after [cyan]/speckit .plan[/])" ,
3746+ f "○ [{ ACCENT_COLOR } ]/spec .clarify[/] [bright_black](optional)[/bright_black] - Ask structured questions to de-risk ambiguous areas before planning (run before [{ ACCENT_COLOR } ]/spec .plan[/] if used)" ,
3747+ f "○ [{ ACCENT_COLOR } ]/spec .analyze[/] [bright_black](optional)[/bright_black] - Cross-artifact consistency & alignment report (after [{ ACCENT_COLOR } ]/spec .tasks[/], before [{ ACCENT_COLOR } ]/spec .implement[/])" ,
3748+ f "○ [{ ACCENT_COLOR } ]/spec .checklist[/] [bright_black](optional)[/bright_black] - Generate quality checklists to validate requirements completeness, clarity, and consistency (after [{ ACCENT_COLOR } ]/spec .plan[/])" ,
37163749 ]
37173750 enhancements_panel = Panel (
37183751 "\n " .join (enhancement_lines ),
37193752 title = "Enhancement Commands" ,
3720- border_style = "cyan" ,
3753+ border_style = ACCENT_COLOR ,
37213754 padding = (1 , 2 ),
37223755 )
37233756 console .print ()
37243757 console .print (enhancements_panel )
37253758
3759+ # Show pre-installed extensions with their commands
3760+ preinstalled = get_preinstalled_extensions (project_path )
3761+ if preinstalled :
3762+ ext_lines = []
3763+ for ext in preinstalled :
3764+ ext_lines .append (f"[{ ACCENT_COLOR } ]📦 { ext ['name' ]} [/{ ACCENT_COLOR } ]" )
3765+ ext_lines .append (f" { ext ['description' ]} " )
3766+ ext_lines .append ("" )
3767+
3768+ for cmd in ext .get ("commands" , []):
3769+ cmd_display = "/" + cmd .replace ("." , "." )
3770+ ext_lines .append (f" [{ ACCENT_COLOR } ]{ cmd_display } [/{ ACCENT_COLOR } ]" )
3771+
3772+ ext_lines .append ("" )
3773+
3774+ if ext_lines :
3775+ ext_lines = ext_lines [:- 1 ]
3776+ preinstalled_panel = Panel (
3777+ "\n " .join (ext_lines ),
3778+ title = "Pre-Installed Extensions" ,
3779+ border_style = ACCENT_COLOR ,
3780+ padding = (1 , 2 ),
3781+ )
3782+ console .print ()
3783+ console .print (preinstalled_panel )
3784+
37263785
37273786@app .command ()
37283787def check ():
@@ -4996,7 +5055,9 @@ def extension_add(
49965055 speckit_version = get_speckit_version ()
49975056
49985057 try :
4999- with console .status (f"[cyan]Installing extension: { extension } [/cyan]" ):
5058+ with console .status (
5059+ f"[{ ACCENT_COLOR } ]Installing extension: { extension } [/{ ACCENT_COLOR } ]"
5060+ ):
50005061 if dev :
50015062 # Install from local directory
50025063 source_path = Path (extension ).expanduser ().resolve ()
0 commit comments