@@ -1158,9 +1158,8 @@ private function run_cleanup_review( array $assoc_args ): void {
11581158 $ result = $ ability ? $ ability ->execute (
11591159 array (
11601160 'include_cleanup ' => true ,
1161- 'include_sizes ' => true ,
1161+ 'include_sizes ' => false ,
11621162 'include_worktree_status ' => false ,
1163- 'size_limit ' => 200 ,
11641163 )
11651164 ) : new \WP_Error ('workspace_hygiene_ability_missing ' , 'Workspace hygiene ability not registered. ' );
11661165 $ this ->render_workspace_hygiene_report_from_ability ($ result , $ assoc_args );
@@ -1378,6 +1377,7 @@ private function render_cleanup_operator_summary( array $summary ): void {
13781377 WP_CLI ::log ('Cleanup operator summary: ' );
13791378 $ cleanup_counts = (array ) ( $ summary ['cleanup_counts ' ] ?? array () );
13801379 $ artifacts = (array ) ( $ summary ['artifact_cleanup ' ] ?? array () );
1380+ $ remaining_safe = (int ) ( $ summary ['remaining_safe_candidates ' ] ?? $ summary ['remaining_safely_removable_worktrees ' ] ?? 0 );
13811381 $ this ->format_items (
13821382 array (
13831383 array (
@@ -1400,6 +1400,14 @@ private function render_cleanup_operator_summary( array $summary ): void {
14001400 'metric ' => 'bytes_reclaimed ' ,
14011401 'value ' => $ this ->format_bytes ($ cleanup_counts ['bytes_reclaimed ' ] ?? 0 ),
14021402 ),
1403+ array (
1404+ 'metric ' => 'remaining_safe_candidates ' ,
1405+ 'value ' => $ remaining_safe ,
1406+ ),
1407+ array (
1408+ 'metric ' => 'protected_unpushed_candidates ' ,
1409+ 'value ' => (int ) ( $ summary ['protected_unpushed_candidates ' ] ?? 0 ),
1410+ ),
14031411 array (
14041412 'metric ' => 'remaining_reclaimable_artifacts ' ,
14051413 'value ' => $ this ->format_bytes ($ artifacts ['remaining_reclaimable_artifact_bytes ' ] ?? 0 ),
@@ -1460,24 +1468,28 @@ private function build_cleanup_operator_summary( array $result ): array {
14601468
14611469 return array_filter (
14621470 array (
1463- 'success ' => (bool ) ( $ result ['success ' ] ?? false ),
1464- 'run_id ' => (string ) ( $ result ['run_id ' ] ?? '' ),
1465- 'job_id ' => isset ($ result ['job_id ' ]) ? (int ) $ result ['job_id ' ] : null ,
1466- 'mode ' => (string ) ( $ result ['mode ' ] ?? $ result ['evidence ' ]['engine_data ' ]['cleanup_run ' ]['mode ' ] ?? '' ),
1467- 'state ' => (string ) ( $ result ['state ' ] ?? '' ),
1468- 'status ' => (string ) ( $ result ['status ' ] ?? '' ),
1469- 'parent_status ' => (string ) ( $ result ['parent_status ' ] ?? '' ),
1470- 'created_at ' => (string ) ( $ result ['created_at ' ] ?? '' ),
1471- 'completed_at ' => (string ) ( $ result ['completed_at ' ] ?? $ result ['parent_completed_at ' ] ?? '' ),
1472- 'cleanup_counts ' => array (
1471+ 'success ' => (bool ) ( $ result ['success ' ] ?? false ),
1472+ 'run_id ' => (string ) ( $ result ['run_id ' ] ?? '' ),
1473+ 'job_id ' => isset ($ result ['job_id ' ]) ? (int ) $ result ['job_id ' ] : null ,
1474+ 'mode ' => (string ) ( $ result ['mode ' ] ?? $ result ['evidence ' ]['engine_data ' ]['cleanup_run ' ]['mode ' ] ?? '' ),
1475+ 'state ' => (string ) ( $ result ['state ' ] ?? '' ),
1476+ 'status ' => (string ) ( $ result ['status ' ] ?? '' ),
1477+ 'parent_status ' => (string ) ( $ result ['parent_status ' ] ?? '' ),
1478+ 'created_at ' => (string ) ( $ result ['created_at ' ] ?? '' ),
1479+ 'completed_at ' => (string ) ( $ result ['completed_at ' ] ?? $ result ['parent_completed_at ' ] ?? '' ),
1480+ 'cleanup_counts ' => array (
14731481 'planned ' => (int ) ( $ cleanup_items ['planned_rows ' ] ?? 0 ),
14741482 'applied ' => (int ) ( $ cleanup_items ['applied_rows ' ] ?? 0 ),
14751483 'skipped ' => (int ) ( $ cleanup_items ['skipped_rows ' ] ?? 0 ),
14761484 'failed ' => (int ) ( $ cleanup_items ['failed_rows ' ] ?? 0 ),
14771485 'bytes_reclaimed ' => (int ) ( $ cleanup_items ['bytes_reclaimed ' ] ?? 0 ),
14781486 'freed_human ' => (string ) ( $ cleanup_items ['freed_human ' ] ?? $ this ->format_bytes ($ cleanup_items ['bytes_reclaimed ' ] ?? 0 ) ),
14791487 ),
1480- 'artifact_cleanup ' => array (
1488+ 'total_bytes_reclaimed ' => (int ) ( $ remaining ['total_bytes_reclaimed ' ] ?? $ cleanup_items ['bytes_reclaimed ' ] ?? 0 ),
1489+ 'total_reclaimed_human ' => $ this ->format_bytes ($ remaining ['total_bytes_reclaimed ' ] ?? $ cleanup_items ['bytes_reclaimed ' ] ?? 0 ),
1490+ 'remaining_safe_candidates ' => (int ) ( $ remaining ['remaining_safe_candidates ' ] ?? $ remaining ['remaining_safely_removable_worktrees ' ] ?? 0 ),
1491+ 'protected_unpushed_candidates ' => (int ) ( $ remaining ['protected_unpushed_candidates ' ] ?? 0 ),
1492+ 'artifact_cleanup ' => array (
14811493 'planned ' => (int ) ( $ artifacts ['planned_rows ' ] ?? 0 ),
14821494 'applied ' => (int ) ( $ artifacts ['applied_rows ' ] ?? 0 ),
14831495 'skipped ' => (int ) ( $ artifacts ['skipped_rows ' ] ?? 0 ),
@@ -1486,13 +1498,14 @@ private function build_cleanup_operator_summary( array $result ): array {
14861498 'remaining_reclaimable_artifact_bytes ' => (int ) ( $ remaining ['remaining_reclaimable_artifact_bytes ' ] ?? $ artifacts ['remaining_reclaimable_artifact_bytes ' ] ?? 0 ),
14871499 'remaining_reclaimable_human ' => $ this ->format_bytes ($ remaining ['remaining_reclaimable_artifact_bytes ' ] ?? $ artifacts ['remaining_reclaimable_artifact_bytes ' ] ?? 0 ),
14881500 ),
1489- 'children ' => $ this ->build_cleanup_operator_child_summary ( (array ) ( $ result ['children ' ] ?? $ result ['evidence ' ]['children ' ] ?? array () ) ),
1490- 'by_type ' => (array ) ( $ cleanup_items ['by_type ' ] ?? array () ),
1491- 'skipped_by_reason ' => (array ) ( $ remaining ['skipped_by_reason ' ] ?? $ cleanup_items ['skipped_examples_by_reason ' ] ?? array () ),
1492- 'failed_by_reason ' => (array ) ( $ cleanup_items ['failed_by_reason ' ] ?? $ artifacts ['failed_by_reason ' ] ?? array () ),
1493- 'top_blocked_examples ' => $ this ->cleanup_operator_blocked_examples ($ result ),
1494- 'recommended_commands ' => (array ) ( $ remaining ['recommended_commands ' ] ?? array () ),
1495- 'locks ' => (array ) ( $ result ['locks ' ] ?? array () ),
1501+ 'children ' => $ this ->build_cleanup_operator_child_summary ( (array ) ( $ result ['children ' ] ?? $ result ['evidence ' ]['children ' ] ?? array () ) ),
1502+ 'by_type ' => (array ) ( $ cleanup_items ['by_type ' ] ?? array () ),
1503+ 'skipped_by_reason ' => (array ) ( $ remaining ['skipped_by_reason ' ] ?? $ cleanup_items ['skipped_examples_by_reason ' ] ?? array () ),
1504+ 'failed_by_reason ' => (array ) ( $ cleanup_items ['failed_by_reason ' ] ?? $ artifacts ['failed_by_reason ' ] ?? array () ),
1505+ 'top_blocked_examples ' => $ this ->cleanup_operator_blocked_examples ($ result ),
1506+ 'recommended_commands ' => (array ) ( $ remaining ['recommended_commands ' ] ?? array () ),
1507+ 'next_commands ' => (array ) ( $ remaining ['next_commands ' ] ?? array () ),
1508+ 'locks ' => (array ) ( $ result ['locks ' ] ?? array () ),
14961509 ),
14971510 fn ( $ value ) => null !== $ value && array () !== $ value && '' !== $ value
14981511 );
@@ -1674,13 +1687,21 @@ private function render_cleanup_remaining_work_summary( array $summary ): void {
16741687 WP_CLI ::log ('Remaining work summary: ' );
16751688 $ this ->format_items (
16761689 array (
1690+ array (
1691+ 'metric ' => 'total_bytes_reclaimed ' ,
1692+ 'value ' => $ this ->format_bytes ($ summary ['total_bytes_reclaimed ' ] ?? 0 ),
1693+ ),
16771694 array (
16781695 'metric ' => 'remaining_reclaimable_artifact_bytes ' ,
16791696 'value ' => $ this ->format_bytes ($ summary ['remaining_reclaimable_artifact_bytes ' ] ?? 0 ),
16801697 ),
16811698 array (
1682- 'metric ' => 'remaining_safely_removable_worktrees ' ,
1683- 'value ' => (int ) ( $ summary ['remaining_safely_removable_worktrees ' ] ?? 0 ),
1699+ 'metric ' => 'remaining_safe_candidates ' ,
1700+ 'value ' => (int ) ( $ summary ['remaining_safe_candidates ' ] ?? $ summary ['remaining_safely_removable_worktrees ' ] ?? 0 ),
1701+ ),
1702+ array (
1703+ 'metric ' => 'protected_unpushed_candidates ' ,
1704+ 'value ' => (int ) ( $ summary ['protected_unpushed_candidates ' ] ?? 0 ),
16841705 ),
16851706 ),
16861707 array ( 'metric ' , 'value ' ),
@@ -2063,8 +2084,8 @@ public function remove_repo( array $args, array $assoc_args ): void {
20632084 * [--skip-cleanup]
20642085 * : Skip the local cleanup dry-run summary.
20652086 *
2066- * [--skip -sizes]
2067- * : Skip best-effort workspace size collection.
2087+ * [--include -sizes]
2088+ * : Include best-effort workspace size collection. This can be expensive on huge workspaces; combine with --size-limit .
20682089 *
20692090 * [--include-worktree-status]
20702091 * : Include full per-worktree git status. This can be expensive on huge workspaces.
@@ -2094,7 +2115,7 @@ public function hygiene( array $args, array $assoc_args ): void { // phpcs:ign
20942115
20952116 $ input = array (
20962117 'include_cleanup ' => empty ($ assoc_args ['skip-cleanup ' ]),
2097- 'include_sizes ' => empty ($ assoc_args ['skip -sizes ' ]),
2118+ 'include_sizes ' => ! empty ($ assoc_args ['include -sizes ' ]),
20982119 'include_worktree_status ' => ! empty ($ assoc_args ['include-worktree-status ' ]),
20992120 'refresh_inventory ' => ! empty ($ assoc_args ['refresh-inventory ' ]),
21002121 );
@@ -4853,6 +4874,12 @@ private function render_workspace_hygiene_report( array $report, array $assoc_ar
48534874 WP_CLI ::log ( (string ) $ report ['suggested_cleanup_command ' ]);
48544875 }
48554876
4877+ if ( ! empty ($ report ['suggested_size_command ' ]) ) {
4878+ WP_CLI ::log ('' );
4879+ WP_CLI ::log ('Suggested bounded size review: ' );
4880+ WP_CLI ::log ( (string ) $ report ['suggested_size_command ' ]);
4881+ }
4882+
48564883 foreach ( (array ) ( $ report ['notes ' ] ?? array () ) as $ note ) {
48574884 WP_CLI ::log ('Note: ' . $ note );
48584885 }
@@ -6025,6 +6052,8 @@ private function render_worktree_bounded_cleanup_eligible_apply_result( array $r
60256052 }
60266053 }
60276054
6055+ $ this ->render_active_no_signal_triage_preview ( (array ) ( $ result ['active_no_signal_triage ' ] ?? array () ) );
6056+
60286057 WP_CLI ::log ('' );
60296058 $ remaining = (int ) ( $ continuation ['remaining_total ' ] ?? 0 );
60306059 if ( $ remaining > 0 ) {
@@ -6163,19 +6192,20 @@ private function compact_worktree_bounded_cleanup_eligible_apply_json( array $re
61636192 );
61646193
61656194 $ report = array (
6166- 'success ' => (bool ) ( $ result ['success ' ] ?? true ),
6167- 'mode ' => (string ) ( $ result ['mode ' ] ?? 'bounded_cleanup_eligible_apply ' ),
6168- 'dry_run ' => ! empty ($ result ['dry_run ' ]),
6169- 'destructive ' => ! empty ($ result ['destructive ' ]),
6170- 'workspace_path ' => $ result ['workspace_path ' ] ?? null ,
6171- 'generated_at ' => $ result ['generated_at ' ] ?? null ,
6172- 'summary ' => $ compact_summary ,
6173- 'blocker_buckets ' => $ buckets ,
6174- 'next_actions ' => $ actions ,
6175- 'candidates ' => $ this ->compact_cleanup_rows ($ candidates , 25 ),
6176- 'removed ' => $ this ->compact_cleanup_rows ($ removed , 25 ),
6177- 'continuation ' => $ this ->compact_cleanup_continuation ( (array ) ( $ result ['continuation ' ] ?? $ result ['pagination ' ] ?? array () ) ),
6178- 'evidence ' => $ this ->compact_cleanup_evidence ( (array ) ( $ result ['evidence ' ] ?? array () ), $ skipped ),
6195+ 'success ' => (bool ) ( $ result ['success ' ] ?? true ),
6196+ 'mode ' => (string ) ( $ result ['mode ' ] ?? 'bounded_cleanup_eligible_apply ' ),
6197+ 'dry_run ' => ! empty ($ result ['dry_run ' ]),
6198+ 'destructive ' => ! empty ($ result ['destructive ' ]),
6199+ 'workspace_path ' => $ result ['workspace_path ' ] ?? null ,
6200+ 'generated_at ' => $ result ['generated_at ' ] ?? null ,
6201+ 'summary ' => $ compact_summary ,
6202+ 'blocker_buckets ' => $ buckets ,
6203+ 'next_actions ' => $ actions ,
6204+ 'active_no_signal_triage ' => (array ) ( $ result ['active_no_signal_triage ' ] ?? array () ),
6205+ 'candidates ' => $ this ->compact_cleanup_rows ($ candidates , 25 ),
6206+ 'removed ' => $ this ->compact_cleanup_rows ($ removed , 25 ),
6207+ 'continuation ' => $ this ->compact_cleanup_continuation ( (array ) ( $ result ['continuation ' ] ?? $ result ['pagination ' ] ?? array () ) ),
6208+ 'evidence ' => $ this ->compact_cleanup_evidence ( (array ) ( $ result ['evidence ' ] ?? array () ), $ skipped ),
61796209 );
61806210
61816211 if ( ! empty ($ result ['job_backed ' ]) ) {
@@ -6185,6 +6215,55 @@ private function compact_worktree_bounded_cleanup_eligible_apply_json( array $re
61856215 return array_filter ($ report , fn ( $ value ) => null !== $ value );
61866216 }
61876217
6218+ /**
6219+ * Render concise active/no-signal triage preview from bounded cleanup output.
6220+ *
6221+ * @param array<string,mixed> $preview Triage preview payload.
6222+ * @return void
6223+ */
6224+ private function render_active_no_signal_triage_preview ( array $ preview ): void {
6225+ $ total = (int ) ( $ preview ['total ' ] ?? 0 );
6226+ if ( $ total <= 0 ) {
6227+ return ;
6228+ }
6229+
6230+ WP_CLI ::log ('' );
6231+ WP_CLI ::log (sprintf ('Active/no-signal triage preview: %d unresolved active worktree(s). ' , $ total ));
6232+ $ summary_rows = array ();
6233+ foreach ( (array ) ( $ preview ['by_age ' ] ?? array () ) as $ bucket => $ count ) {
6234+ if ( (int ) $ count > 0 ) {
6235+ $ summary_rows [] = array (
6236+ 'dimension ' => 'age ' ,
6237+ 'bucket ' => (string ) $ bucket ,
6238+ 'count ' => (int ) $ count ,
6239+ );
6240+ }
6241+ }
6242+ foreach ( (array ) ( $ preview ['by_liveness ' ] ?? array () ) as $ bucket => $ count ) {
6243+ $ summary_rows [] = array (
6244+ 'dimension ' => 'liveness ' ,
6245+ 'bucket ' => (string ) $ bucket ,
6246+ 'count ' => (int ) $ count ,
6247+ );
6248+ }
6249+ foreach ( (array ) ( $ preview ['by_repo ' ] ?? array () ) as $ bucket => $ count ) {
6250+ $ summary_rows [] = array (
6251+ 'dimension ' => 'repo ' ,
6252+ 'bucket ' => (string ) $ bucket ,
6253+ 'count ' => (int ) $ count ,
6254+ );
6255+ }
6256+ $ this ->format_items ($ summary_rows , array ( 'dimension ' , 'bucket ' , 'count ' ), array ( 'format ' => 'table ' ), 'dimension ' );
6257+
6258+ WP_CLI ::log ('Non-destructive next commands: ' );
6259+ foreach ( (array ) ( $ preview ['commands ' ] ?? array () ) as $ label => $ command ) {
6260+ WP_CLI ::log (sprintf (' %s: %s ' , (string ) $ label , (string ) $ command ));
6261+ }
6262+ if ( ! empty ($ preview ['safety ' ]) ) {
6263+ WP_CLI ::log ('Safety: ' . (string ) $ preview ['safety ' ]);
6264+ }
6265+ }
6266+
61886267 /**
61896268 * Build skipped blocker buckets with bounded examples.
61906269 *
0 commit comments