1717
1818use WP_CLI ;
1919use DataMachine \Cli \BaseCommand ;
20+ use DataMachineCode \Cli \CliResponseRenderer ;
2021use DataMachineCode \Cli \CliRepeatableOptionParser ;
2122use DataMachineCode \Cleanup \CleanupRunEvidenceStoreInterface ;
2223use DataMachineCode \Cleanup \DataMachineJobCleanupRunEvidenceStore ;
@@ -38,6 +39,26 @@ class WorkspaceCommand extends BaseCommand {
3839
3940 private const METADATA_RECONCILE_DEFAULT_BUDGET = '30s ' ;
4041
42+ private const WORKTREE_OPERATION_ABILITIES = array (
43+ 'add ' => 'datamachine-code/workspace-worktree-add ' ,
44+ 'list ' => 'datamachine-code/workspace-worktree-list ' ,
45+ 'remove ' => 'datamachine-code/workspace-worktree-remove ' ,
46+ 'prune ' => 'datamachine-code/workspace-worktree-prune ' ,
47+ 'cleanup ' => 'datamachine-code/workspace-worktree-cleanup ' ,
48+ 'cleanup-artifacts ' => 'datamachine-code/workspace-worktree-cleanup-artifacts ' ,
49+ 'bounded-cleanup-eligible-apply ' => 'datamachine-code/workspace-worktree-bounded-cleanup-eligible-apply ' ,
50+ 'emergency-cleanup ' => 'datamachine-code/workspace-worktree-emergency-cleanup ' ,
51+ 'reconcile-metadata ' => 'datamachine-code/workspace-worktree-reconcile-metadata ' ,
52+ 'active-no-signal-report ' => 'datamachine-code/workspace-worktree-active-no-signal-report ' ,
53+ 'active-no-signal-finalized-apply ' => 'datamachine-code/workspace-worktree-active-no-signal-finalized-apply ' ,
54+ 'active-no-signal-equivalent-clean-apply ' => 'datamachine-code/workspace-worktree-active-no-signal-equivalent-clean-apply ' ,
55+ 'active-no-signal-merged-apply ' => 'datamachine-code/workspace-worktree-active-no-signal-merged-apply ' ,
56+ 'active-no-signal-remote-clean-apply ' => 'datamachine-code/workspace-worktree-active-no-signal-remote-clean-apply ' ,
57+ 'refresh-context ' => 'datamachine-code/workspace-worktree-refresh-context ' ,
58+ 'finalize ' => 'datamachine-code/workspace-worktree-finalize ' ,
59+ 'mark-cleanup-eligible ' => 'datamachine-code/workspace-worktree-finalize ' ,
60+ );
61+
4162 private ?CleanupRunEvidenceStoreInterface $ cleanup_run_evidence_store = null ;
4263
4364 /**
@@ -317,7 +338,7 @@ private function render_workspace_triage_result( array|\WP_Error $result, array
317338
318339 $ format = (string ) ( $ assoc_args ['format ' ] ?? 'table ' );
319340 if ( 'json ' === $ format ) {
320- WP_CLI :: log ( ( string ) wp_json_encode ($ result, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES ) );
341+ $ this -> renderer ()-> json ($ result );
321342 return ;
322343 }
323344
@@ -409,7 +430,7 @@ private function render_workspace_list_summary( array $result, array $assoc_args
409430
410431 $ format = (string ) ( $ assoc_args ['format ' ] ?? 'table ' );
411432 if ( 'json ' === $ format ) {
412- WP_CLI :: log ( ( string ) wp_json_encode ($ summary, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES ) );
433+ $ this -> renderer ()-> json ($ summary );
413434 return ;
414435 }
415436
@@ -1296,7 +1317,7 @@ private function render_cleanup_control_result( array $result, array $assoc_args
12961317 $ result = $ this ->build_cleanup_operator_summary ($ result );
12971318 }
12981319 if ( 'json ' === $ format ) {
1299- WP_CLI :: log ( ( string ) wp_json_encode ($ result, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES ) );
1320+ $ this -> renderer ()-> json ($ result );
13001321 return ;
13011322 }
13021323 if ( 'yaml ' === $ format && class_exists ('Spyc ' ) ) {
@@ -1330,7 +1351,7 @@ private function render_cleanup_control_result( array $result, array $assoc_args
13301351 $ this ->render_stale_lock_followup ( (array ) $ result ['locks ' ]['stale_locks ' ]);
13311352 }
13321353 if ( ! empty ($ result ['evidence ' ]) ) {
1333- WP_CLI :: log ( ( string ) wp_json_encode ($ result ['evidence ' ], JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES ) );
1354+ $ this -> renderer ()-> json ($ result ['evidence ' ]);
13341355 }
13351356 }
13361357
@@ -1796,7 +1817,7 @@ private function render_cleanup_summary_reason_rows( string $label, array $reaso
17961817 private function render_cleanup_plan_result ( array $ result , array $ assoc_args ): void {
17971818 $ format = (string ) ( $ assoc_args ['format ' ] ?? 'table ' );
17981819 if ( 'json ' === $ format ) {
1799- WP_CLI :: log ( ( string ) wp_json_encode ($ result, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES ) );
1820+ $ this -> renderer ()-> json ($ result );
18001821 return ;
18011822 }
18021823
@@ -2121,8 +2142,7 @@ public function inventory( array $args, array $assoc_args ): void {
21212142 }
21222143
21232144 if ( 'json ' === (string ) ( $ assoc_args ['format ' ] ?? '' ) ) {
2124- $ json = wp_json_encode ($ result , JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES );
2125- WP_CLI ::log (false === $ json ? '{} ' : $ json );
2145+ $ this ->renderer ()->json ($ result );
21262146 return ;
21272147 }
21282148
@@ -2731,7 +2751,7 @@ public function patch( array $args, array $assoc_args ): void {
27312751 }
27322752
27332753 if ( 'json ' === (string ) ( $ assoc_args ['format ' ] ?? 'table ' ) ) {
2734- WP_CLI :: log ( ( string ) wp_json_encode ($ result, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES ) );
2754+ $ this -> renderer ()-> json ($ result );
27352755 return ;
27362756 }
27372757
@@ -3557,7 +3577,7 @@ public function worktree( array $args, array $assoc_args ): void {
35573577 if ( 'backfill-origin-session ' === $ operation ) {
35583578 $ result = WorktreeContextInjector::backfill_legacy_origin_sessions ( ! empty ($ assoc_args ['apply ' ]) );
35593579 if ( 'json ' === (string ) ( $ assoc_args ['format ' ] ?? '' ) ) {
3560- WP_CLI :: line ( ( string ) wp_json_encode ($ result, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES ) );
3580+ $ this -> renderer ()-> json ($ result );
35613581 return ;
35623582 }
35633583
@@ -3588,26 +3608,7 @@ public function worktree( array $args, array $assoc_args ): void {
35883608 return ;
35893609 }
35903610
3591- $ ability_name = match ( $ operation ) {
3592- 'add ' => 'datamachine-code/workspace-worktree-add ' ,
3593- 'list ' => 'datamachine-code/workspace-worktree-list ' ,
3594- 'remove ' => 'datamachine-code/workspace-worktree-remove ' ,
3595- 'prune ' => 'datamachine-code/workspace-worktree-prune ' ,
3596- 'cleanup ' => 'datamachine-code/workspace-worktree-cleanup ' ,
3597- 'cleanup-artifacts ' => 'datamachine-code/workspace-worktree-cleanup-artifacts ' ,
3598- 'bounded-cleanup-eligible-apply ' => 'datamachine-code/workspace-worktree-bounded-cleanup-eligible-apply ' ,
3599- 'emergency-cleanup ' => 'datamachine-code/workspace-worktree-emergency-cleanup ' ,
3600- 'reconcile-metadata ' => 'datamachine-code/workspace-worktree-reconcile-metadata ' ,
3601- 'active-no-signal-report ' => 'datamachine-code/workspace-worktree-active-no-signal-report ' ,
3602- 'active-no-signal-finalized-apply ' => 'datamachine-code/workspace-worktree-active-no-signal-finalized-apply ' ,
3603- 'active-no-signal-equivalent-clean-apply ' => 'datamachine-code/workspace-worktree-active-no-signal-equivalent-clean-apply ' ,
3604- 'active-no-signal-merged-apply ' => 'datamachine-code/workspace-worktree-active-no-signal-merged-apply ' ,
3605- 'active-no-signal-remote-clean-apply ' => 'datamachine-code/workspace-worktree-active-no-signal-remote-clean-apply ' ,
3606- 'refresh-context ' => 'datamachine-code/workspace-worktree-refresh-context ' ,
3607- 'finalize ' => 'datamachine-code/workspace-worktree-finalize ' ,
3608- 'mark-cleanup-eligible ' => 'datamachine-code/workspace-worktree-finalize ' ,
3609- default => '' ,
3610- };
3611+ $ ability_name = self ::WORKTREE_OPERATION_ABILITIES [ $ operation ] ?? '' ;
36113612
36123613 if ( '' === $ ability_name ) {
36133614 WP_CLI ::error (sprintf ('Unknown worktree operation: %s ' , $ operation ));
@@ -3924,8 +3925,7 @@ private function render_worktree_abandoned_result( array $result, array $assoc_a
39243925 if ( empty ($ assoc_args ['verbose ' ]) ) {
39253926 $ result = $ this ->compact_worktree_abandoned_result ($ result );
39263927 }
3927- $ json = wp_json_encode ($ result , JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES );
3928- WP_CLI ::log (false === $ json ? '{} ' : $ json );
3928+ $ this ->renderer ()->json ($ result );
39293929 return ;
39303930 }
39313931
@@ -4087,8 +4087,7 @@ private function compact_worktree_abandoned_steps( array $steps ): array {
40874087 */
40884088 private function renderWorktreeResult ( string $ operation , array $ result , array $ assoc_args ): void {
40894089 if ( 'add ' === $ operation && 'json ' === (string ) ( $ assoc_args ['format ' ] ?? '' ) ) {
4090- $ json = wp_json_encode ($ result , JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES );
4091- WP_CLI ::log (false === $ json ? '{} ' : $ json );
4090+ $ this ->renderer ()->json ($ result );
40924091 return ;
40934092 }
40944093
@@ -4322,8 +4321,7 @@ function ( $wt ) {
43224321 */
43234322 private function render_workspace_lock_result ( array $ result , array $ assoc_args , bool $ prune ): void {
43244323 if ( 'json ' === (string ) ( $ assoc_args ['format ' ] ?? '' ) ) {
4325- $ json = wp_json_encode ($ result , JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES );
4326- WP_CLI ::log (false === $ json ? '{} ' : $ json );
4324+ $ this ->renderer ()->json ($ result );
43274325 return ;
43284326 }
43294327
@@ -4562,8 +4560,7 @@ private function resolve_owner_context_session_id( array $owner_context ): strin
45624560 private function render_workspace_hygiene_report ( array $ report , array $ assoc_args ): void {
45634561 $ format = isset ($ assoc_args ['format ' ]) ? (string ) $ assoc_args ['format ' ] : 'table ' ;
45644562 if ( 'json ' === $ format ) {
4565- $ json = wp_json_encode ($ report , JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES );
4566- WP_CLI ::log (false === $ json ? '{} ' : $ json );
4563+ $ this ->renderer ()->json ($ report );
45674564 return ;
45684565 }
45694566
@@ -4817,8 +4814,7 @@ private function render_worktree_cleanup_result( array $result, array $assoc_arg
48174814 $ report = $ this ->filter_worktree_cleanup_report ($ result , $ only );
48184815
48194816 if ( 'json ' === $ format ) {
4820- $ json = wp_json_encode ($ report , JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES );
4821- WP_CLI ::log (false === $ json ? '{} ' : $ json );
4817+ $ this ->renderer ()->json ($ report );
48224818 return ;
48234819 }
48244820
@@ -5065,8 +5061,7 @@ private function render_worktree_cleanup_progress( array $event ): void {
50655061 private function render_worktree_metadata_reconciliation_result ( array $ result , array $ assoc_args ): void {
50665062 $ format = isset ($ assoc_args ['format ' ]) ? (string ) $ assoc_args ['format ' ] : 'table ' ;
50675063 if ( 'json ' === $ format ) {
5068- $ json = wp_json_encode ($ result , JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES );
5069- WP_CLI ::log (false === $ json ? '{} ' : $ json );
5064+ $ this ->renderer ()->json ($ result );
50705065 return ;
50715066 }
50725067
@@ -5254,8 +5249,7 @@ private function render_worktree_metadata_reconciliation_result( array $result,
52545249 private function render_worktree_active_no_signal_report_result ( array $ result , array $ assoc_args ): void {
52555250 $ format = isset ($ assoc_args ['format ' ]) ? (string ) $ assoc_args ['format ' ] : 'table ' ;
52565251 if ( 'json ' === $ format ) {
5257- $ json = wp_json_encode ($ result , JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES );
5258- WP_CLI ::log (false === $ json ? '{} ' : $ json );
5252+ $ this ->renderer ()->json ($ result );
52595253 return ;
52605254 }
52615255
@@ -5345,8 +5339,7 @@ private function render_worktree_active_no_signal_report_result( array $result,
53455339 private function render_worktree_active_no_signal_finalized_apply_result ( array $ result , array $ assoc_args ): void {
53465340 $ format = isset ($ assoc_args ['format ' ]) ? (string ) $ assoc_args ['format ' ] : 'table ' ;
53475341 if ( 'json ' === $ format ) {
5348- $ json = wp_json_encode ($ result , JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES );
5349- WP_CLI ::log (false === $ json ? '{} ' : $ json );
5342+ $ this ->renderer ()->json ($ result );
53505343 return ;
53515344 }
53525345
@@ -5436,8 +5429,7 @@ private function render_worktree_active_no_signal_finalized_apply_result( array
54365429 private function render_worktree_active_no_signal_equivalent_clean_apply_result ( array $ result , array $ assoc_args ): void {
54375430 $ format = isset ($ assoc_args ['format ' ]) ? (string ) $ assoc_args ['format ' ] : 'table ' ;
54385431 if ( 'json ' === $ format ) {
5439- $ json = wp_json_encode ($ result , JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES );
5440- WP_CLI ::log (false === $ json ? '{} ' : $ json );
5432+ $ this ->renderer ()->json ($ result );
54415433 return ;
54425434 }
54435435
@@ -5527,8 +5519,7 @@ private function render_worktree_active_no_signal_equivalent_clean_apply_result(
55275519 private function render_worktree_active_no_signal_merged_apply_result ( array $ result , array $ assoc_args ): void {
55285520 $ format = isset ($ assoc_args ['format ' ]) ? (string ) $ assoc_args ['format ' ] : 'table ' ;
55295521 if ( 'json ' === $ format ) {
5530- $ json = wp_json_encode ($ result , JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES );
5531- WP_CLI ::log (false === $ json ? '{} ' : $ json );
5522+ $ this ->renderer ()->json ($ result );
55325523 return ;
55335524 }
55345525
@@ -5618,8 +5609,7 @@ private function render_worktree_active_no_signal_merged_apply_result( array $re
56185609 private function render_worktree_active_no_signal_remote_clean_apply_result ( array $ result , array $ assoc_args ): void {
56195610 $ format = isset ($ assoc_args ['format ' ]) ? (string ) $ assoc_args ['format ' ] : 'table ' ;
56205611 if ( 'json ' === $ format ) {
5621- $ json = wp_json_encode ($ result , JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES );
5622- WP_CLI ::log (false === $ json ? '{} ' : $ json );
5612+ $ this ->renderer ()->json ($ result );
56235613 return ;
56245614 }
56255615
@@ -5709,8 +5699,7 @@ private function render_worktree_active_no_signal_remote_clean_apply_result( arr
57095699 private function render_worktree_artifact_cleanup_result ( array $ result , array $ assoc_args ): void {
57105700 $ format = isset ($ assoc_args ['format ' ]) ? (string ) $ assoc_args ['format ' ] : 'table ' ;
57115701 if ( 'json ' === $ format ) {
5712- $ json = wp_json_encode ($ result , JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES );
5713- WP_CLI ::log (false === $ json ? '{} ' : $ json );
5702+ $ this ->renderer ()->json ($ result );
57145703 return ;
57155704 }
57165705
@@ -5857,8 +5846,7 @@ private function render_worktree_bounded_cleanup_eligible_apply_result( array $r
58575846 $ format = isset ($ assoc_args ['format ' ]) ? (string ) $ assoc_args ['format ' ] : 'table ' ;
58585847 if ( 'json ' === $ format ) {
58595848 $ report = ! empty ($ assoc_args ['verbose ' ]) ? $ result : $ this ->compact_worktree_bounded_cleanup_eligible_apply_json ($ result );
5860- $ json = wp_json_encode ($ report , JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES );
5861- WP_CLI ::log (false === $ json ? '{} ' : $ json );
5849+ $ this ->renderer ()->json ($ report );
58625850 return ;
58635851 }
58645852
@@ -6235,8 +6223,7 @@ private function compact_cleanup_row( array $row ): array {
62356223 private function render_worktree_emergency_cleanup_result ( array $ result , array $ assoc_args ): void {
62366224 $ format = isset ($ assoc_args ['format ' ]) ? (string ) $ assoc_args ['format ' ] : 'table ' ;
62376225 if ( 'json ' === $ format ) {
6238- $ json = wp_json_encode ($ result , JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES );
6239- WP_CLI ::log (false === $ json ? '{} ' : $ json );
6226+ $ this ->renderer ()->json ($ result );
62406227 return ;
62416228 }
62426229
@@ -6623,6 +6610,10 @@ private function render_worktree_freshness( array $result ): void {
66236610 // print a potentially-misleading "up to date".
66246611 }
66256612
6613+ private function renderer (): CliResponseRenderer {
6614+ return new CliResponseRenderer ();
6615+ }
6616+
66266617 /**
66276618 * Convert a branch-shaped CLI alias into the exact ref expected downstream.
66286619 *
0 commit comments