Files
orca/src
Neil 85565a9302 reland(workspace): set project location from the create-worktree host picker (#14965)
* feat(workspace): reland set project location from the create-worktree host picker

Relands #14868 (reverted by #14912) with a fix for the regression that caused the
revert: setting a project location could change the path before Orca used it.

The retarget-after-setup path read the raw store record to find a just-created
setup, because the memoized picker options had not refreshed yet:

    useAppStore.getState().projectHostSetups.find(
      (candidate) => candidate.id === setupId && candidate.setupState === 'ready'
    )

That hand-rolls a second selection path that skips every rule the option builder
applies — repo eligibility, ephemeral-VM and runtime-owned SSH host exclusion,
and the one-setup-per-host dedupe whose own comment notes that
resolveWorkspaceCreationTarget takes the first project+host match and ignores the
rest. So the composer could be retargeted at a setup other than the canonical one
for that host, pointing creation at a different location than the one chosen.

Resolves through buildProjectHostSetupOptions against fresh store state instead,
so the fallback and the steady-state picker agree by construction.

STA-4547

* fix(workspace): sanitize the clone prefill and drop an abandoned set-location

Review follow-ups on this PR.

The "Clone from URL" prefill seeded the field with the verbatim `git remote` URL,
which can embed a PAT (`https://x-access-token:ghp_...@github.com/...`). The
clone then runs on the *target* host, writing that token into its .git/config —
a credential the user never typed into this flow, now readable by anyone on a
shared host. Strip it with the same sanitizer `getProvisionedRootRecipeRepoUrl`
already applies to the ephemeral-VM recipe URL. Extracted to
resolveProjectCloneUrlPrefill so the rule is directly testable.

The dialog also stays dismissable while a submit is in flight, and an SSH clone
is unbounded. A clone the user backed out of minutes earlier still called
onReady, silently moving the run target and resetting start-from under a form
they had since pointed at another host. Drop the result if the dialog went away.

* fix(workspace): re-arm the abandoned guard on mount

StrictMode runs mount/cleanup/mount, so latching `abandoned` on the first
cleanup left it true for the rest of the session and permanently suppressed
onReady — the app wraps its root in StrictMode. Reset it on mount.
2026-08-16 16:50:58 -07:00
..