Repository navigation
Description
What T3 does
Add Project is a typed path with an in-app browser, not an OS folder dialog. The palette keeps a query that is simultaneously the path input and the browse cursor: getAddProjectInitialQuery seeds it with ~/, filterFilesystemBrowseEntries lists the directory server-side, arrow keys descend (appendBrowsePathSegment), and Enter on a path that does not exist still works because project.create carries createWorkspaceRootIfMissing: true (apps/web/src/components/CommandPalette.tsx:1771, packages/contracts/src/orchestration.ts:642).
The clone flow reuses that same control for step 2 instead of inventing a dialog: once a repository is chosen, the repo folder is pinned onto the browsed path, so the proposed destination reads <folder you are browsing>/<repo> live (getCloneDestinationPath, getCloneDestinationBrowsePath, packages/client-runtime/src/operations/projects.ts:216-248). Picking a directory that already has the repo's name uses it directly rather than producing repo/repo. Validation is shared with manual add: ~ expansion, explicit-relative paths need an active project, Windows-style paths rejected off Windows (resolveAddProjectPath).
Because the browse is an RPC against the environment, the same UI works for a project on a remote machine. A native dialog cannot do that.
Solenta today
projects:addViaDialog (electron/ipc.js:263) opens dialog.showOpenDialog and passes result.filePaths[0] to addProject. That is the whole flow. Consequences:
- Cannot add a path that does not exist yet (no create-if-missing) except through the separate
createProjectmkdir +git initpath. - Cannot type or paste a path, cannot use
~. - Cannot browse anything but the local machine's filesystem, which blocks project add for Headless server mode and SSH remote environments #245 (headless server / SSH environments) by construction.
- Nowhere to hang a clone destination step for Clone from URL and publish a local repo in add-project #459.
Why it matters
This is the prerequisite for two things we already want. #459 needs a destination picker that can pin a repo folder onto a chosen parent; #245 needs any project path UI that is not showOpenDialog. Doing it once, as an IPC-backed browse, serves both, and the OS dialog can stay as a "Browse..." shortcut for the local case.
Scope suggestion
fs:browse({environment, path})IPC returning directories (+ a bounded frecency listing for the empty query).- Add-project input: typeable path,
~expansion, keyboard descend/ascend, entries filtered by what is typed, create-if-missing on submit, existing-project detection that opens the project instead of erroring. - Keep
showOpenDialogas a secondary button on local. - Land it ahead of the clone flow in Clone from URL and publish a local repo in add-project #459 so the destination step is a reuse, not a second control.
Activity
currentbits commentedon Aug 20, 2026
Started on the typed/browsable add-project path (thread 2a0cd518). Plan: shared browse-path helpers (T3-shaped, including clone destination pinning for #459 reuse),
fs:browse({environment, path})IPC (local + SSH), create-if-missing + existing-project open on add, PathBrowser in the add-project modal, native dialog kept as Browse… on local.currentbits commentedon Aug 20, 2026
Implemented on
coder/fork-add-project-typeable-browsable-dest-2a0cd5.fs:browse({environment, path, cwd})— local readdir orlsover SSH (environment=user@host). Empty/~/~/prepends up to 8 recent project paths.~/, keyboard descend/ascend, client-side filter. Native Browse… stays as a localshowOpenDialogshortcut (hidden on web).~expansion, existing-project match returns the same id, create-if-missing (mkdir + git init) only when the path does not exist. Existing non-git dirs still rejected.getCloneDestinationPath, pinned folder) are insrc/browsePath.tsfor Clone from URL and publish a local repo in add-project #459 reuse — no clone UI in this PR.currentbits commentedon Aug 20, 2026
Landed on main in b701a0d.
Add-existing is now a typed path with an in-app browser (
PathBrowser+fs:browse); the OS folder dialog stays as a local-only Browse… shortcut. Missing paths are mkdir'd + git-init'd, existing non-repos are git-init'd (main's #6xx behaviour, kept through the merge), and an already-added path returns the existing project instead of duplicating it. SSH hosts browse overssh.Merge conflict with the 'not a git folder' work was resolved in favour of
ensureGitWorkTreefor both the existing and created paths; mkdir rollback only fires for a directory the call created. Verified: 26/26 renderer (browsePath, addProjectBrowse, addProjectCreate, webDegrade, windowsDoctor), 78/78 electron (services, fs-browse, ipc-seam), tsc clean.