@@ -497,8 +497,29 @@ def cache_dir_cmd() -> None:
497497 console .print (str (default_cache_dir ()))
498498
499499
500+ def _cache_json_print (payload : Any ) -> None :
501+ """Print machine-readable JSON to stdout (not the stderr console)."""
502+ import json
503+ from dataclasses import asdict , is_dataclass
504+
505+ def _to_jsonable (value : Any ) -> Any :
506+ if isinstance (value , Path ):
507+ return str (value )
508+ if is_dataclass (value ) and not isinstance (value , type ):
509+ return {k : _to_jsonable (v ) for k , v in asdict (value ).items ()}
510+ if isinstance (value , list ):
511+ return [_to_jsonable (item ) for item in value ]
512+ if isinstance (value , dict ):
513+ return {k : _to_jsonable (v ) for k , v in value .items ()}
514+ return value
515+
516+ typer .echo (json .dumps (_to_jsonable (payload ), indent = 2 ))
517+
518+
500519@cache_app .command ("list" )
501- def cache_list_cmd () -> None :
520+ def cache_list_cmd (
521+ json_out : bool = typer .Option (False , "--json" , help = "Output as JSON" ),
522+ ) -> None :
502523 from create_awesome_python_app .cache import (
503524 format_age ,
504525 format_bytes ,
@@ -507,6 +528,9 @@ def cache_list_cmd() -> None:
507528 )
508529
509530 entries = list_cache_entries ()
531+ if json_out :
532+ _cache_json_print (entries )
533+ return
510534 if not entries :
511535 console .print ("[dim]No cached templates or extensions.[/dim]" )
512536 console .print (
@@ -541,10 +565,38 @@ def cache_list_cmd() -> None:
541565def cache_clean_cmd (
542566 id : str | None = typer .Argument (None ),
543567 catalog : bool = typer .Option (False , "--catalog" ),
568+ json_out : bool = typer .Option (False , "--json" , help = "Output as JSON" ),
569+ force : bool = typer .Option (
570+ False , "--force" , "-f" , help = "Skip interactive confirmation"
571+ ),
544572) -> None :
545573 from create_awesome_python_app .cache import clean_cache
546574
575+ # Targeted cleans (id / --catalog) never prompt.
576+ if not catalog and id is None and not json_out and not force :
577+ if not sys .stdin .isatty ():
578+ console .print (
579+ "[yellow]Non-interactive shell — use --json or --force to skip "
580+ "the prompt, or specify an id to target a specific entry.[/yellow]"
581+ )
582+ return
583+ import questionary
584+
585+ from create_awesome_python_app .prompt_style import CPA_PROMPT_STYLE
586+
587+ confirmed = questionary .confirm (
588+ "Remove ALL cached templates and extensions?" ,
589+ default = False ,
590+ style = CPA_PROMPT_STYLE ,
591+ ).ask ()
592+ if not confirmed :
593+ console .print ("[dim]Clean cancelled.[/dim]" )
594+ return
595+
547596 result = clean_cache (id , catalog = catalog )
597+ if json_out :
598+ _cache_json_print (result )
599+ return
548600 if result .not_found :
549601 console .print (f"[yellow]No cache entry found for id: { id } [/yellow]" )
550602 return
@@ -556,10 +608,18 @@ def cache_clean_cmd(
556608
557609
558610@cache_app .command ("verify" )
559- def cache_verify_cmd (id : str | None = typer .Argument (None )) -> None :
611+ def cache_verify_cmd (
612+ id : str | None = typer .Argument (None ),
613+ json_out : bool = typer .Option (False , "--json" , help = "Output as JSON" ),
614+ ) -> None :
560615 from create_awesome_python_app .cache import verify_cache
561616
562617 results = verify_cache (id )
618+ if json_out :
619+ _cache_json_print (results )
620+ if any (not bool (entry .fsck_ok ) for entry in results ):
621+ raise typer .Exit (1 )
622+ raise typer .Exit (0 )
563623 if not results :
564624 console .print ("[dim]No cached entries.[/dim]" )
565625 raise typer .Exit (0 )
@@ -580,10 +640,15 @@ def cache_verify_cmd(id: str | None = typer.Argument(None)) -> None:
580640
581641
582642@cache_app .command ("outdated" )
583- def cache_outdated_cmd () -> None :
643+ def cache_outdated_cmd (
644+ json_out : bool = typer .Option (False , "--json" , help = "Output as JSON" ),
645+ ) -> None :
584646 from create_awesome_python_app .cache import check_outdated
585647
586648 results = check_outdated ()
649+ if json_out :
650+ _cache_json_print (results )
651+ return
587652 if not results :
588653 console .print ("[dim]No cached entries to check.[/dim]" )
589654 return
@@ -643,10 +708,17 @@ def cache_update_cmd(id: str | None = typer.Argument(None)) -> None:
643708
644709
645710@cache_app .command ("doctor" )
646- def cache_doctor_cmd () -> None :
711+ def cache_doctor_cmd (
712+ json_out : bool = typer .Option (False , "--json" , help = "Output as JSON" ),
713+ ) -> None :
647714 from create_awesome_python_app .cache import run_doctor
648715
649716 results = run_doctor ()
717+ if json_out :
718+ _cache_json_print (results )
719+ if any (not row .ok for row in results ):
720+ raise typer .Exit (1 )
721+ raise typer .Exit (0 )
650722 all_ok = True
651723 for row in results :
652724 mark = "[green]✓[/green]" if row .ok else "[red]✗[/red]"
0 commit comments