@@ -14,7 +14,7 @@ use crate::frontmatter;
1414use crate :: table:: Table ;
1515use crate :: util:: home_dir;
1616
17- pub fn run ( filter_lang : Option < & str > , json_output : bool ) -> Result < ( ) > {
17+ pub fn run ( filter_lang : Option < & str > , audit : bool , json_output : bool ) -> Result < ( ) > {
1818 let ways_dir = home_dir ( ) . join ( ".claude/hooks/ways" ) ;
1919 let xdg_way = xdg_cache_dir ( ) . join ( "claude-ways/user" ) ;
2020 let excluded = crate :: util:: load_excluded_segments ( ) ;
@@ -71,19 +71,41 @@ pub fn run(filter_lang: Option<&str>, json_output: bool) -> Result<()> {
7171 println ! ( "Multi corpus: {multi_corpus_count} ways" ) ;
7272 println ! ( ) ;
7373
74+ // Language coverage summary
75+ let all_supported = get_all_language_codes ( ) ;
76+ let non_en: Vec < & str > = all_supported. iter ( )
77+ . filter ( |c| * c != "en" )
78+ . map ( |s| s. as_str ( ) )
79+ . collect ( ) ;
80+
7481 if !all_locales. is_empty ( ) {
75- println ! ( "Language stubs found: {}" , all_locales. iter( ) . cloned( ) . collect:: <Vec <_>>( ) . join( ", " ) ) ;
76- println ! ( ) ;
82+ println ! ( "Covered ({}/{}): {} + en" ,
83+ all_locales. len( ) , non_en. len( ) ,
84+ all_locales. iter( ) . cloned( ) . collect:: <Vec <_>>( ) . join( ", " ) ,
85+ ) ;
86+ }
87+
88+ let uncovered: Vec < String > = non_en. iter ( )
89+ . filter ( |code| !all_locales. contains ( * * code) )
90+ . map ( |s| s. to_string ( ) )
91+ . collect ( ) ;
92+
93+ if !uncovered. is_empty ( ) {
94+ println ! ( "Uncovered ({}/{}): {}" ,
95+ uncovered. len( ) , non_en. len( ) ,
96+ uncovered. join( ", " ) ,
97+ ) ;
7798 }
99+ println ! ( ) ;
78100
79101 // Summary counts
80102 let en_count = ways. iter ( ) . filter ( |w| w. embed_model == "en" ) . count ( ) ;
81103 let multi_count = ways. iter ( ) . filter ( |w| w. embed_model == "multilingual" ) . count ( ) ;
82104 println ! ( "Ways: {} total ({} en, {} multilingual)" , ways. len( ) , en_count, multi_count) ;
83105 println ! ( ) ;
84106
85- // Per-way detail
86- if !ways. is_empty ( ) {
107+ // Per-way detail (only in audit mode)
108+ if audit && !ways. is_empty ( ) {
87109 let mut t = Table :: new ( & [ "Way" , "Model" , "Locales" ] ) ;
88110 t. max_width ( 0 , 45 ) ;
89111 for w in & ways {
@@ -97,6 +119,8 @@ pub fn run(filter_lang: Option<&str>, json_output: bool) -> Result<()> {
97119 t. add ( vec ! [ & w. id, & w. embed_model, & locales] ) ;
98120 }
99121 t. print ( ) ;
122+ } else if !audit {
123+ println ! ( "Run `ways language --audit` for per-way detail." ) ;
100124 }
101125
102126 // Warnings
@@ -266,6 +290,21 @@ fn line_count(path: &Path) -> usize {
266290 . unwrap_or ( 0 )
267291}
268292
293+ /// Get all language codes from languages.json, sorted.
294+ fn get_all_language_codes ( ) -> Vec < String > {
295+ let parsed: serde_json:: Value = match serde_json:: from_str ( agents:: LANGUAGES_JSON ) {
296+ Ok ( v) => v,
297+ Err ( _) => return Vec :: new ( ) ,
298+ } ;
299+ let mut codes: Vec < String > = parsed
300+ . get ( "languages" )
301+ . and_then ( |v| v. as_object ( ) )
302+ . map ( |m| m. keys ( ) . cloned ( ) . collect ( ) )
303+ . unwrap_or_default ( ) ;
304+ codes. sort ( ) ;
305+ codes
306+ }
307+
269308fn xdg_cache_dir ( ) -> PathBuf {
270309 std:: env:: var ( "XDG_CACHE_HOME" )
271310 . map ( PathBuf :: from)
0 commit comments