44
55import asyncio
66import os
7+ import sys
78from pathlib import Path
89from typing import Any
910
@@ -444,8 +445,29 @@ def cache_dir_cmd() -> None:
444445 console .print (str (default_cache_dir ()))
445446
446447
448+ def _cache_json_print (payload : Any ) -> None :
449+ """Print machine-readable JSON to stdout (not the stderr console)."""
450+ import json
451+ from dataclasses import asdict , is_dataclass
452+
453+ def _to_jsonable (value : Any ) -> Any :
454+ if isinstance (value , Path ):
455+ return str (value )
456+ if is_dataclass (value ) and not isinstance (value , type ):
457+ return {k : _to_jsonable (v ) for k , v in asdict (value ).items ()}
458+ if isinstance (value , list ):
459+ return [_to_jsonable (item ) for item in value ]
460+ if isinstance (value , dict ):
461+ return {k : _to_jsonable (v ) for k , v in value .items ()}
462+ return value
463+
464+ typer .echo (json .dumps (_to_jsonable (payload ), indent = 2 ))
465+
466+
447467@cache_app .command ("list" )
448- def cache_list_cmd () -> None :
468+ def cache_list_cmd (
469+ json_out : bool = typer .Option (False , "--json" , help = "Output as JSON" ),
470+ ) -> None :
449471 from create_awesome_python_app .cache import (
450472 format_age ,
451473 format_bytes ,
@@ -454,6 +476,9 @@ def cache_list_cmd() -> None:
454476 )
455477
456478 entries = list_cache_entries ()
479+ if json_out :
480+ _cache_json_print (entries )
481+ return
457482 if not entries :
458483 console .print ("[dim]No cached templates or extensions.[/dim]" )
459484 console .print (
@@ -488,10 +513,38 @@ def cache_list_cmd() -> None:
488513def cache_clean_cmd (
489514 id : str | None = typer .Argument (None ),
490515 catalog : bool = typer .Option (False , "--catalog" ),
516+ json_out : bool = typer .Option (False , "--json" , help = "Output as JSON" ),
517+ force : bool = typer .Option (
518+ False , "--force" , "-f" , help = "Skip interactive confirmation"
519+ ),
491520) -> None :
492521 from create_awesome_python_app .cache import clean_cache
493522
523+ # Targeted cleans (id / --catalog) never prompt.
524+ if not catalog and id is None and not json_out and not force :
525+ if not sys .stdin .isatty ():
526+ console .print (
527+ "[yellow]Non-interactive shell — use --json or --force to skip "
528+ "the prompt, or specify an id to target a specific entry.[/yellow]"
529+ )
530+ return
531+ import questionary
532+
533+ from create_awesome_python_app .prompt_style import CPA_PROMPT_STYLE
534+
535+ confirmed = questionary .confirm (
536+ "Remove ALL cached templates and extensions?" ,
537+ default = False ,
538+ style = CPA_PROMPT_STYLE ,
539+ ).ask ()
540+ if not confirmed :
541+ console .print ("[dim]Clean cancelled.[/dim]" )
542+ return
543+
494544 result = clean_cache (id , catalog = catalog )
545+ if json_out :
546+ _cache_json_print (result )
547+ return
495548 if result .not_found :
496549 console .print (f"[yellow]No cache entry found for id: { id } [/yellow]" )
497550 return
@@ -503,10 +556,18 @@ def cache_clean_cmd(
503556
504557
505558@cache_app .command ("verify" )
506- def cache_verify_cmd (id : str | None = typer .Argument (None )) -> None :
559+ def cache_verify_cmd (
560+ id : str | None = typer .Argument (None ),
561+ json_out : bool = typer .Option (False , "--json" , help = "Output as JSON" ),
562+ ) -> None :
507563 from create_awesome_python_app .cache import verify_cache
508564
509565 results = verify_cache (id )
566+ if json_out :
567+ _cache_json_print (results )
568+ if any (not bool (entry .fsck_ok ) for entry in results ):
569+ raise typer .Exit (1 )
570+ raise typer .Exit (0 )
510571 if not results :
511572 console .print ("[dim]No cached entries.[/dim]" )
512573 raise typer .Exit (0 )
@@ -527,10 +588,15 @@ def cache_verify_cmd(id: str | None = typer.Argument(None)) -> None:
527588
528589
529590@cache_app .command ("outdated" )
530- def cache_outdated_cmd () -> None :
591+ def cache_outdated_cmd (
592+ json_out : bool = typer .Option (False , "--json" , help = "Output as JSON" ),
593+ ) -> None :
531594 from create_awesome_python_app .cache import check_outdated
532595
533596 results = check_outdated ()
597+ if json_out :
598+ _cache_json_print (results )
599+ return
534600 if not results :
535601 console .print ("[dim]No cached entries to check.[/dim]" )
536602 return
@@ -590,10 +656,17 @@ def cache_update_cmd(id: str | None = typer.Argument(None)) -> None:
590656
591657
592658@cache_app .command ("doctor" )
593- def cache_doctor_cmd () -> None :
659+ def cache_doctor_cmd (
660+ json_out : bool = typer .Option (False , "--json" , help = "Output as JSON" ),
661+ ) -> None :
594662 from create_awesome_python_app .cache import run_doctor
595663
596664 results = run_doctor ()
665+ if json_out :
666+ _cache_json_print (results )
667+ if any (not row .ok for row in results ):
668+ raise typer .Exit (1 )
669+ raise typer .Exit (0 )
597670 all_ok = True
598671 for row in results :
599672 mark = "[green]✓[/green]" if row .ok else "[red]✗[/red]"
0 commit comments