@@ -21,8 +21,14 @@ class GitHubAbilities
2121 class RemoteWorkspaceBackend
2222 {
2323 public static array $ show_input = array ();
24+ public static array $ read_input = array ();
25+ public static array $ list_input = array ();
26+ public static array $ grep_input = array ();
2427 public static array $ worktree_input = array ();
2528 public static bool $ show_returns_remote_success = false ;
29+ public static bool $ read_returns_remote_success = false ;
30+ public static bool $ list_returns_remote_success = false ;
31+ public static bool $ grep_returns_remote_success = false ;
2632 public static bool $ worktree_returns_remote_success = false ;
2733
2834 public static function should_handle (): bool
@@ -65,6 +71,65 @@ public function worktree_add( string $repo_name, string $branch, ?string $from =
6571 'Remote workspace repository "wpcom-codebox" is not registered. Call workspace_clone first. '
6672 );
6773 }
74+
75+ public function read_file ( string $ handle , string $ path , int $ max_size , ?int $ offset = null , ?int $ limit = null ): array |\WP_Error
76+ {
77+ self ::$ read_input = compact ('handle ' , 'path ' , 'max_size ' , 'offset ' , 'limit ' );
78+ if ( self ::$ read_returns_remote_success ) {
79+ return array (
80+ 'success ' => true ,
81+ 'backend ' => 'github_api ' ,
82+ 'content ' => 'remote file ' ,
83+ 'path ' => $ path ,
84+ 'size ' => 11 ,
85+ );
86+ }
87+
88+ return new \WP_Error (
89+ 'remote_workspace_repo_not_found ' ,
90+ 'Remote workspace repository "wpcom-codebox" is not registered. Call workspace_clone first. '
91+ );
92+ }
93+
94+ public function list_directory ( string $ handle , ?string $ path = null ): array |\WP_Error
95+ {
96+ self ::$ list_input = compact ('handle ' , 'path ' );
97+ if ( self ::$ list_returns_remote_success ) {
98+ return array (
99+ 'success ' => true ,
100+ 'backend ' => 'github_api ' ,
101+ 'repo ' => $ handle ,
102+ 'path ' => $ path ?? '/ ' ,
103+ 'entries ' => array (),
104+ );
105+ }
106+
107+ return new \WP_Error (
108+ 'remote_workspace_repo_not_found ' ,
109+ 'Remote workspace repository "wpcom-codebox" is not registered. Call workspace_clone first. '
110+ );
111+ }
112+
113+ public function grep ( string $ handle , string $ pattern , ?string $ path = null , ?string $ include_pattern = null , int $ max_results = 100 , int $ context_lines = 0 ): array |\WP_Error
114+ {
115+ self ::$ grep_input = compact ('handle ' , 'pattern ' , 'path ' , 'include_pattern ' , 'max_results ' , 'context_lines ' );
116+ if ( self ::$ grep_returns_remote_success ) {
117+ return array (
118+ 'success ' => true ,
119+ 'backend ' => 'github_api ' ,
120+ 'repo ' => $ handle ,
121+ 'path ' => $ path ?? '/ ' ,
122+ 'pattern ' => $ pattern ,
123+ 'matches ' => array (),
124+ 'count ' => 0 ,
125+ );
126+ }
127+
128+ return new \WP_Error (
129+ 'remote_workspace_repo_not_found ' ,
130+ 'Remote workspace repository "wpcom-codebox" is not registered. Call workspace_clone first. '
131+ );
132+ }
68133 }
69134
70135 class Workspace
@@ -111,6 +176,64 @@ public function worktree_add(
111176 );
112177 }
113178 }
179+
180+ class WorkspaceReader
181+ {
182+ public static array $ read_input = array ();
183+ public static array $ list_input = array ();
184+ public static array $ grep_input = array ();
185+
186+ public function __construct ( private Workspace $ workspace )
187+ {
188+ }
189+
190+ public function read_file ( string $ name , string $ path , int $ max_size , ?int $ offset = null , ?int $ limit = null ): array
191+ {
192+ self ::$ read_input = compact ('name ' , 'path ' , 'max_size ' , 'offset ' , 'limit ' );
193+ return array (
194+ 'success ' => true ,
195+ 'content ' => 'local file ' ,
196+ 'path ' => $ path ,
197+ 'size ' => 10 ,
198+ );
199+ }
200+
201+ public function list_directory ( string $ name , ?string $ path = null ): array
202+ {
203+ self ::$ list_input = compact ('name ' , 'path ' );
204+ return array (
205+ 'success ' => true ,
206+ 'repo ' => $ name ,
207+ 'path ' => $ path ?? '/ ' ,
208+ 'entries ' => array (
209+ array (
210+ 'name ' => 'README.md ' ,
211+ 'type ' => 'file ' ,
212+ 'size ' => 10 ,
213+ ),
214+ ),
215+ );
216+ }
217+
218+ public function grep ( string $ name , string $ pattern , ?string $ path = null , ?string $ include_pattern = null , int $ max_results = 100 , int $ context_lines = 0 ): array
219+ {
220+ self ::$ grep_input = compact ('name ' , 'pattern ' , 'path ' , 'include_pattern ' , 'max_results ' , 'context_lines ' );
221+ return array (
222+ 'success ' => true ,
223+ 'repo ' => $ name ,
224+ 'path ' => $ path ?? '/ ' ,
225+ 'pattern ' => $ pattern ,
226+ 'matches ' => array (
227+ array (
228+ 'file ' => 'README.md ' ,
229+ 'line ' => 1 ,
230+ 'text ' => 'local file ' ,
231+ ),
232+ ),
233+ 'count ' => 1 ,
234+ );
235+ }
236+ }
114237}
115238
116239namespace DataMachineCode \Support {
@@ -201,6 +324,58 @@ function is_wp_error( $value ): bool
201324 $ assert ('workspace path returns local worktree when duplicate remote exists ' , is_array ($ duplicate_path ) && '/Users/chubes/Developer/wpcom-codebox@fix-listed-primary-resolution ' === ( $ duplicate_path ['path ' ] ?? '' ));
202325 $ assert ('workspace path marks local worktree handle as existing ' , is_array ($ duplicate_path ) && true === ( $ duplicate_path ['exists ' ] ?? null ));
203326
327+ \DataMachineCode \Workspace \RemoteWorkspaceBackend::$ read_returns_remote_success = true ;
328+ \DataMachineCode \Workspace \RemoteWorkspaceBackend::$ read_input = array ();
329+ \DataMachineCode \Workspace \WorkspaceReader::$ read_input = array ();
330+ $ read = \DataMachineCode \Abilities \WorkspaceAbilities::readFile (
331+ array (
332+ 'repo ' => 'wpcom-codebox ' ,
333+ 'path ' => 'README.md ' ,
334+ 'max_size ' => 500 ,
335+ 'offset ' => 2 ,
336+ 'limit ' => 3 ,
337+ )
338+ );
339+
340+ $ assert ('remote read is not consulted when local primary exists ' , array () === \DataMachineCode \Workspace \RemoteWorkspaceBackend::$ read_input );
341+ $ assert ('local read attempted for local primary ' , 'wpcom-codebox ' === ( \DataMachineCode \Workspace \WorkspaceReader::$ read_input ['name ' ] ?? '' ));
342+ $ assert ('read preserves options locally ' , 500 === ( \DataMachineCode \Workspace \WorkspaceReader::$ read_input ['max_size ' ] ?? null ) && 2 === ( \DataMachineCode \Workspace \WorkspaceReader::$ read_input ['offset ' ] ?? null ) && 3 === ( \DataMachineCode \Workspace \WorkspaceReader::$ read_input ['limit ' ] ?? null ));
343+ $ assert ('read returns local file result ' , is_array ($ read ) && 'local file ' === ( $ read ['content ' ] ?? '' ));
344+
345+ \DataMachineCode \Workspace \RemoteWorkspaceBackend::$ list_returns_remote_success = true ;
346+ \DataMachineCode \Workspace \RemoteWorkspaceBackend::$ list_input = array ();
347+ \DataMachineCode \Workspace \WorkspaceReader::$ list_input = array ();
348+ $ list = \DataMachineCode \Abilities \WorkspaceAbilities::listDirectory (
349+ array (
350+ 'repo ' => 'wpcom-codebox ' ,
351+ 'path ' => 'inc ' ,
352+ )
353+ );
354+
355+ $ assert ('remote list is not consulted when local primary exists ' , array () === \DataMachineCode \Workspace \RemoteWorkspaceBackend::$ list_input );
356+ $ assert ('local list attempted for local primary ' , 'wpcom-codebox ' === ( \DataMachineCode \Workspace \WorkspaceReader::$ list_input ['name ' ] ?? '' ));
357+ $ assert ('list preserves path locally ' , 'inc ' === ( \DataMachineCode \Workspace \WorkspaceReader::$ list_input ['path ' ] ?? '' ));
358+ $ assert ('list returns local entries ' , is_array ($ list ) && 'README.md ' === ( $ list ['entries ' ][0 ]['name ' ] ?? '' ));
359+
360+ \DataMachineCode \Workspace \RemoteWorkspaceBackend::$ grep_returns_remote_success = true ;
361+ \DataMachineCode \Workspace \RemoteWorkspaceBackend::$ grep_input = array ();
362+ \DataMachineCode \Workspace \WorkspaceReader::$ grep_input = array ();
363+ $ grep = \DataMachineCode \Abilities \WorkspaceAbilities::grepFiles (
364+ array (
365+ 'repo ' => 'wpcom-codebox ' ,
366+ 'pattern ' => 'local ' ,
367+ 'path ' => 'inc ' ,
368+ 'include ' => '*.php ' ,
369+ 'max_results ' => 7 ,
370+ 'context_lines ' => 2 ,
371+ )
372+ );
373+
374+ $ assert ('remote grep is not consulted when local primary exists ' , array () === \DataMachineCode \Workspace \RemoteWorkspaceBackend::$ grep_input );
375+ $ assert ('local grep attempted for local primary ' , 'wpcom-codebox ' === ( \DataMachineCode \Workspace \WorkspaceReader::$ grep_input ['name ' ] ?? '' ));
376+ $ assert ('grep preserves options locally ' , '*.php ' === ( \DataMachineCode \Workspace \WorkspaceReader::$ grep_input ['include_pattern ' ] ?? '' ) && 7 === ( \DataMachineCode \Workspace \WorkspaceReader::$ grep_input ['max_results ' ] ?? null ) && 2 === ( \DataMachineCode \Workspace \WorkspaceReader::$ grep_input ['context_lines ' ] ?? null ));
377+ $ assert ('grep returns local matches ' , is_array ($ grep ) && 1 === ( $ grep ['count ' ] ?? null ));
378+
204379 \DataMachineCode \Workspace \RemoteWorkspaceBackend::$ worktree_returns_remote_success = true ;
205380 \DataMachineCode \Workspace \RemoteWorkspaceBackend::$ worktree_input = array ();
206381 $ worktree = \DataMachineCode \Abilities \WorkspaceAbilities::worktreeAdd (
0 commit comments