Skip to content

Commit 8fa599c

Browse files
feat: add targeted worktree safety lookup
1 parent f1cd699 commit 8fa599c

4 files changed

Lines changed: 37 additions & 1 deletion

File tree

inc/Abilities/WorkspaceAbilities.php

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1764,6 +1764,10 @@ private function registerAbilities(): void {
17641764
'type' => 'string',
17651765
'description' => 'Optional repo name to limit the list.',
17661766
),
1767+
'handle' => array(
1768+
'type' => 'string',
1769+
'description' => 'Optional exact worktree handle. Filters before status and disk probes.',
1770+
),
17671771
'state' => array(
17681772
'type' => 'string',
17691773
'description' => 'Optional lifecycle state filter.',
@@ -4006,6 +4010,7 @@ public static function worktreeList( array $input ): array|\WP_Error {
40064010
$opts = array(
40074011
'include_status' => array_key_exists('include_status', $input) ? (bool) $input['include_status'] : false,
40084012
'include_disk' => array_key_exists('include_disk', $input) ? (bool) $input['include_disk'] : false,
4013+
'handle' => isset($input['handle']) ? (string) $input['handle'] : '',
40094014
);
40104015

40114016
return $workspace->worktree_list($repo, $state, $opts);

inc/Cli/Commands/WorkspaceCommand.php

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@ class WorkspaceCommand extends BaseCommand {
4343
private const WORKTREE_OPERATIONS = array(
4444
'add' => array( 'ability' => 'datamachine-code/workspace-worktree-add' ),
4545
'list' => array( 'ability' => 'datamachine-code/workspace-worktree-list' ),
46+
'get' => array( 'ability' => 'datamachine-code/workspace-worktree-list' ),
4647
'remove' => array( 'ability' => 'datamachine-code/workspace-worktree-remove' ),
4748
'prune' => array( 'ability' => 'datamachine-code/workspace-worktree-prune' ),
4849
'cleanup' => array( 'ability' => 'datamachine-code/workspace-worktree-cleanup' ),
@@ -3872,7 +3873,7 @@ public function worktree( array $args, array $assoc_args ): void {
38723873
$operation = $args[0] ?? '';
38733874

38743875
if ( '' === $operation ) {
3875-
WP_CLI::error('Usage: wp datamachine-code workspace worktree <add|list|remove|prune|locks|cleanup|cleanup-artifacts|abandoned|bounded-cleanup-eligible-apply|cleanup-eligible-drain|emergency-cleanup|reconcile-metadata|backfill-origin-session|active-no-signal-report|active-no-signal-finalized-apply|active-no-signal-equivalent-clean-apply|active-no-signal-merged-apply|active-no-signal-remote-clean-apply|active-no-signal-drain|refresh-context|finalize|mark-cleanup-eligible> [<repo>] [<branch>] [--flags]');
3876+
WP_CLI::error('Usage: wp datamachine-code workspace worktree <add|get|list|remove|prune|locks|cleanup|cleanup-artifacts|abandoned|bounded-cleanup-eligible-apply|cleanup-eligible-drain|emergency-cleanup|reconcile-metadata|backfill-origin-session|active-no-signal-report|active-no-signal-finalized-apply|active-no-signal-equivalent-clean-apply|active-no-signal-merged-apply|active-no-signal-remote-clean-apply|active-no-signal-drain|refresh-context|finalize|mark-cleanup-eligible> [<repo>] [<branch>] [--flags]');
38763877
return;
38773878
}
38783879

@@ -4060,6 +4061,16 @@ public function worktree( array $args, array $assoc_args ): void {
40604061
$input['include_disk'] = $want_disk;
40614062
break;
40624063

4064+
case 'get':
4065+
if ( empty($args[1]) ) {
4066+
WP_CLI::error('Usage: worktree get <handle> [--with-status] [--format=json]');
4067+
return;
4068+
}
4069+
$input['handle'] = (string) $args[1];
4070+
$input['include_status'] = true;
4071+
$input['include_disk'] = false;
4072+
break;
4073+
40634074
case 'remove':
40644075
// Accept either the two-arg `<repo> <branch>` form or a single
40654076
// `<repo>@<branch-slug>` handle (as printed by `list`/`path`/cleanup
@@ -4512,6 +4523,7 @@ private function renderWorktreeResult( string $operation, array $result, array $
45124523
}
45134524

45144525
switch ( $operation ) {
4526+
case 'get':
45154527
case 'list':
45164528
$worktrees = $result['worktrees'] ?? array();
45174529
if ( ! empty($assoc_args['stale']) ) {

inc/Workspace/WorkspaceWorktreeLifecycle.php

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -767,6 +767,10 @@ public function worktree_refresh_context( string $handle ): array|\WP_Error {
767767
public function worktree_list( ?string $repo = null, ?string $state = null, array $opts = array() ): array|\WP_Error {
768768
$include_status = array_key_exists('include_status', $opts) ? (bool) $opts['include_status'] : true;
769769
$include_disk = array_key_exists('include_disk', $opts) ? (bool) $opts['include_disk'] : true;
770+
$handle = isset($opts['handle']) ? trim( (string) $opts['handle']) : '';
771+
if ( '' !== $handle && null === $repo ) {
772+
$repo = str_contains($handle, '@') ? strstr($handle, '@', true) : $handle;
773+
}
770774

771775
$skipped_groups = array();
772776
if ( ! $include_status ) {
@@ -841,6 +845,9 @@ public function worktree_list( ?string $repo = null, ?string $state = null, arra
841845
// Show the absolute path so it is still useful, even though it has no `<repo>@<slug>` handle.
842846
$handle = $wt['path'];
843847
}
848+
if ( '' !== (string) ( $opts['handle'] ?? '' ) && $handle !== (string) $opts['handle'] ) {
849+
continue;
850+
}
844851

845852
if ( $include_status ) {
846853
$dirty_result = $this->run_git($wt['path'], 'status --porcelain');

tests/worktree-add-lifecycle.php

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -271,6 +271,18 @@ function create_primary_checkout( string $workspace_root ): void {
271271
$list = $workspace->worktree_list('homeboy', null, array( 'include_status' => false, 'include_disk' => false ));
272272
$handles = array_map(static fn( array $row ): string => (string) $row['handle'], $list['worktrees'] ?? array());
273273
assert_true(in_array('homeboy@audit-primitives-20260616', $handles, true), 'persisted worktree is not visible to worktree_list');
274+
$targeted = $workspace->worktree_list(
275+
null,
276+
null,
277+
array(
278+
'handle' => 'homeboy@audit-primitives-20260616',
279+
'include_status' => true,
280+
'include_disk' => false,
281+
)
282+
);
283+
assert_true(1 === count($targeted['worktrees'] ?? array()), 'targeted worktree lookup returned unrelated rows');
284+
assert_true('homeboy@audit-primitives-20260616' === ( $targeted['worktrees'][0]['handle'] ?? '' ), 'targeted worktree lookup returned the wrong handle');
285+
assert_true(null !== ( $targeted['worktrees'][0]['dirty'] ?? null ), 'targeted worktree lookup did not run the requested status probe');
274286

275287
update_option(
276288
'datamachine_code_remote_workspace_state',

0 commit comments

Comments
 (0)