Files
orca/src/cli/folder-workspace-selector.ts
T
Jinwoo Hong f341558b82 feat(cli): match folder workspaces by path: and name:, keep same-id ps rows apart (#39637)
* feat(cli): match folder workspaces by path: and name:, and keep same-id ps rows apart

Adds one runtime matcher for worktrees and folder workspaces. With the new
matchFolderWorkspaces opt-in (advertised as workspace-selector.folder-match.v1),
path: and name: also match folder workspaces; branch:, issue: and identity:
stay repo-backed. Several matches refuse with each choice's kind, host, path
and selector; a folder id shared by two folder workspaces refuses with the
repair step. The CLI resolves path:/name: through it, so terminal, file and
ports commands reach a folder workspace, and create/set parents record a
folder parent. Explicit ambiguous parents report LINEAGE_PARENT_AMBIGUOUS.

worktree ps now keeps rows that share an id on different hosts apart, with
their own host, identity, metadata and activity; activity whose host can't
be proven attaches to neither.

* test: let the cross-version ps harness pass the host-qualified summary lookup

* fix(cli): read each ps row's own host session; qualify folder selector help

* fix(runtime): refuse unscoped duplicate folder ids; hand lineage the matcher's typed result

Unscoped folder:<id> refuses a duplicated id even when only one copy's host
is derivable; a host-scoped lookup still picks that host's copy. A wsl: hook
stamp counts as local host evidence. The lineage controller receives the
worktree-or-folder candidate directly instead of re-deriving the kind.

* docs(cli): guide the ambiguity fallback through truncated ps and id: selectors

* fix(cli): report an ambiguous parent by its own choices; cover per-host sessions

* fix(cli): send parents to the runtime parent resolver as typed; translate WSL paths for folders too

Parent selectors skip the CLI's show-based folder lookup, so worktree.create
and worktree.set classify them with parent rules: a folder spanning hosts is
a valid parent, and ambiguity reports LINEAGE_PARENT_AMBIGUOUS. Caller-distro
Linux path translation now also matches folder workspaces.

* chore(rpc): import the computer-use recovery data directly instead of through an alias

* fix(runtime): report a missing set parent as LINEAGE_PARENT_NOT_FOUND, as create does

worktree set and worktree create now share one explicit-parent error
conversion: several matches give LINEAGE_PARENT_AMBIGUOUS and none give
LINEAGE_PARENT_NOT_FOUND, so a missing parent is no longer reported as a
bare selector_not_found that could mean the child.
2026-11-07 23:35:33 -05:00

36 lines
1.2 KiB
TypeScript

import type { RuntimeWorktreeRecord } from '../shared/runtime-types'
import { parseWorkspaceKey } from '../shared/workspace-scope'
import type { RuntimeClient } from './runtime-client'
import { RuntimeClientError } from './runtime/types'
export function mayNameFolderWorkspace(selector: string): boolean {
return selector.startsWith('path:') || selector.startsWith('name:')
}
/**
* path: and name: also name folder workspaces. The runtime's matcher (opted in) answers with the
* folder's key, which every command accepts; an older runtime ignores the opt-in and keeps its
* repo-only meaning. A miss is left for the command to report.
*/
export async function resolveFolderWorkspaceSelector(
selector: string,
client: RuntimeClient
): Promise<string> {
if (!mayNameFolderWorkspace(selector)) {
return selector
}
try {
const shown = await client.call<{ worktree: RuntimeWorktreeRecord }>('worktree.show', {
worktree: selector,
matchFolderWorkspaces: true
})
const { id } = shown.result.worktree
return parseWorkspaceKey(id)?.type === 'folder' ? id : selector
} catch (error) {
if (error instanceof RuntimeClientError && error.code === 'selector_not_found') {
return selector
}
throw error
}
}