@@ -427,6 +427,35 @@ def _get_skills_dir(project_path: Path, selected_ai: str) -> Path:
427427 return project_path / ".agents" / "skills"
428428
429429
430+ def _cli_error_detail (exc : BaseException ) -> str :
431+ """Return a compact one-line exception detail for CLI output."""
432+ detail = str (exc ).replace ("\n " , " " ).strip ()
433+ return detail or exc .__class__ .__name__
434+
435+
436+ def _cli_phase_label (phase : str , target_kind : str , target : str | None = None ) -> str :
437+ """Format a stable operation label for user-visible diagnostics."""
438+ label = f"{ phase } { target_kind } " .strip ()
439+ if target :
440+ label = f"{ label } '{ target } '"
441+ return label
442+
443+
444+ def _print_cli_warning (
445+ phase : str ,
446+ target_kind : str ,
447+ target : str | None ,
448+ exc : BaseException ,
449+ * ,
450+ continuing : str | None = None ,
451+ ) -> None :
452+ """Print a warning that names the failed CLI phase and target."""
453+ label = _cli_phase_label (phase , target_kind , target )
454+ console .print (f"[yellow]Warning:[/yellow] Failed to { label } : { _cli_error_detail (exc )} " )
455+ if continuing :
456+ console .print (f"[dim]{ continuing } [/dim]" )
457+
458+
430459# Constants kept for backward compatibility with presets and extensions.
431460DEFAULT_SKILLS_DIR = ".agents/skills"
432461SKILL_DESCRIPTIONS = {
@@ -859,9 +888,8 @@ def init(
859888 git_messages .append ("bundled extension not found" )
860889 except Exception as ext_err :
861890 git_has_error = True
862- sanitized_ext = str (ext_err ).replace ('\n ' , ' ' ).strip ()
863891 git_messages .append (
864- f"extension install failed: { sanitized_ext [:120 ]} "
892+ f"extension install failed during optional git setup : { _cli_error_detail ( ext_err ) [:120 ]} "
865893 )
866894 summary = "; " .join (git_messages )
867895 if git_has_error :
@@ -899,8 +927,10 @@ def init(
899927 else :
900928 tracker .skip ("workflow" , "bundled workflow not found" )
901929 except Exception as wf_err :
902- sanitized_wf = str (wf_err ).replace ('\n ' , ' ' ).strip ()
903- tracker .error ("workflow" , f"install failed: { sanitized_wf [:120 ]} " )
930+ tracker .error (
931+ "workflow" ,
932+ f"install bundled workflow 'speckit' failed: { _cli_error_detail (wf_err )[:120 ]} " ,
933+ )
904934
905935 # Fix permissions after all installs (scripts + extensions)
906936 ensure_executable_scripts (project_path , tracker = tracker )
@@ -962,7 +992,13 @@ def init(
962992 zip_path = preset_catalog .download_pack (preset )
963993 preset_manager .install_from_zip (zip_path , speckit_ver )
964994 except PresetError as preset_err :
965- console .print (f"[yellow]Warning:[/yellow] Failed to install preset '{ preset } ': { preset_err } " )
995+ _print_cli_warning (
996+ "install" ,
997+ "preset" ,
998+ preset ,
999+ preset_err ,
1000+ continuing = "Continuing without the optional preset." ,
1001+ )
9661002 finally :
9671003 if zip_path is not None :
9681004 # Clean up downloaded ZIP to avoid cache accumulation
@@ -972,7 +1008,14 @@ def init(
9721008 # Best-effort cleanup; failure to delete is non-fatal
9731009 pass
9741010 except Exception as preset_err :
975- console .print (f"[yellow]Warning:[/yellow] Failed to install preset: { preset_err } " )
1011+ # Optional preset install must not abort project initialization.
1012+ _print_cli_warning (
1013+ "install" ,
1014+ "preset" ,
1015+ preset ,
1016+ preset_err ,
1017+ continuing = "Continuing without the optional preset." ,
1018+ )
9761019
9771020 tracker .complete ("final" , "project ready" )
9781021 except (typer .Exit , SystemExit ):
@@ -1693,20 +1736,29 @@ def integration_install(
16931736 if new_default == integration .key :
16941737 _update_init_options_for_integration (project_root , integration , script_type = selected_script )
16951738
1696- except Exception as e :
1739+ except Exception as exc :
16971740 # Attempt rollback of any files written by setup
16981741 try :
16991742 integration .teardown (project_root , manifest , force = True )
17001743 except Exception as rollback_err :
17011744 # Suppress so the original setup error remains the primary failure
1702- console .print (f"[yellow]Warning:[/yellow] Failed to roll back integration changes: { rollback_err } " )
1745+ _print_cli_warning (
1746+ "rollback" ,
1747+ "integration" ,
1748+ key ,
1749+ rollback_err ,
1750+ continuing = "The original install failure is still the primary error." ,
1751+ )
17031752 if installed_keys :
17041753 _write_integration_json (
17051754 project_root , default_key , installed_keys , _integration_settings (current )
17061755 )
17071756 else :
17081757 _remove_integration_json (project_root )
1709- console .print (f"[red]Error:[/red] Failed to install integration: { e } " )
1758+ console .print (
1759+ f"[red]Error:[/red] Failed to { _cli_phase_label ('install' , 'integration' , key )} : "
1760+ f"{ _cli_error_detail (exc )} "
1761+ )
17101762 raise typer .Exit (1 )
17111763
17121764 name = (integration .config or {}).get ("name" , key )
@@ -2070,9 +2122,12 @@ def integration_switch(
20702122 ext_mgr = ExtensionManager (project_root )
20712123 ext_mgr .unregister_agent_artifacts (installed_key )
20722124 except Exception as ext_err :
2073- console .print (
2074- f"[yellow]Warning:[/yellow] Could not clean up extension artifacts "
2075- f"(commands, skills, registry entries) for '{ installed_key } ': { ext_err } "
2125+ _print_cli_warning (
2126+ "clean up extension artifacts for" ,
2127+ "integration" ,
2128+ installed_key ,
2129+ ext_err ,
2130+ continuing = "Continuing with integration switch; old extension artifacts may need manual cleanup." ,
20762131 )
20772132
20782133 # Clear metadata so a failed Phase 2 doesn't leave stale references
@@ -2167,18 +2222,27 @@ def integration_switch(
21672222 ext_mgr = ExtensionManager (project_root )
21682223 ext_mgr .register_enabled_extensions_for_agent (target )
21692224 except Exception as ext_err :
2170- console .print (
2171- f"[yellow]Warning:[/yellow] Could not register extension commands, skills, "
2172- f"or related artifacts for '{ target } ': { ext_err } "
2225+ _print_cli_warning (
2226+ "register extension artifacts for" ,
2227+ "integration" ,
2228+ target ,
2229+ ext_err ,
2230+ continuing = "The integration switch succeeded, but installed extensions may need re-registration." ,
21732231 )
21742232
2175- except Exception as e :
2233+ except Exception as exc :
21762234 # Attempt rollback of any files written by setup
21772235 try :
21782236 target_integration .teardown (project_root , manifest , force = True )
21792237 except Exception as rollback_err :
21802238 # Suppress so the original setup error remains the primary failure
2181- console .print (f"[yellow]Warning:[/yellow] Failed to roll back integration '{ target } ': { rollback_err } " )
2239+ _print_cli_warning (
2240+ "rollback" ,
2241+ "integration" ,
2242+ target ,
2243+ rollback_err ,
2244+ continuing = "The original switch failure is still the primary error." ,
2245+ )
21822246 if installed_keys :
21832247 fallback_key = installed_keys [0 ]
21842248 fallback_integration = get_integration (fallback_key )
@@ -2207,7 +2271,10 @@ def integration_switch(
22072271 )
22082272 else :
22092273 _remove_integration_json (project_root )
2210- console .print (f"[red]Error:[/red] Failed to install integration '{ target } ': { e } " )
2274+ console .print (
2275+ f"[red]Error:[/red] Failed to { _cli_phase_label ('install' , 'integration' , target )} "
2276+ f"during switch: { _cli_error_detail (exc )} "
2277+ )
22112278 raise typer .Exit (1 )
22122279
22132280 name = (target_integration .config or {}).get ("name" , target )
@@ -2342,7 +2409,8 @@ def integration_upgrade(
23422409 except Exception as exc :
23432410 # Don't teardown — setup overwrites in-place, so teardown would
23442411 # delete files that were working before the upgrade. Just report.
2345- console .print (f"[red]Error:[/red] Failed to upgrade integration: { exc } " )
2412+ console .print (f"[red]Error:[/red] Failed to { _cli_phase_label ('upgrade' , 'integration' , key )} ." )
2413+ console .print (f"[dim]Details:[/dim] { _cli_error_detail (exc )} " )
23462414 console .print ("[yellow]The previous integration files may still be in place.[/yellow]" )
23472415 raise typer .Exit (1 )
23482416
0 commit comments