Repository navigation
Conversation
Mobile listed and searched the folder holding the .code-workspace, so unlisted siblings showed up and listed folders outside it were missing. The file tree and @ mention search now span the folders the workspace file lists, one labelled top-level folder per root, with a repo an isolated run covers swapped for its worktree. resolveProjectFileRoots and its label helpers move from apps/web to packages/client-runtime so web and mobile share them. Projects without a workspace file are unchanged.
There was a problem hiding this comment.
Copilot review overview
🟡 Changes recommended
Slash-containing root labels can collide hierarchically, nesting roots and making files in another root inaccessible.
Review effort: Balanced
Findings: 1
Open (1)
What changed in this PR
Extends .code-workspace folder-list behavior to mobile and shares root-resolution logic with web.
Changes:
- Moves project-file-root utilities into
client-runtime. - Adds multi-root mobile file trees, navigation, refresh, and isolated-worktree handling.
- Makes mobile
@search use labeled workspace roots and absolute links.
| File | Description |
|---|---|
packages/client-runtime/src/projectFileRoots.ts |
Centralizes root resolution and labeling. |
packages/client-runtime/src/projectFileRoots.test.ts |
Tests shared root behavior. |
packages/client-runtime/package.json |
Exports the shared utility. |
apps/web/src/lib/projectFileRoots.test.ts |
Retains web link integration coverage. |
apps/web/src/components/files/FilePreviewPanel.tsx |
Uses the shared types and key helper. |
apps/web/src/components/files/filePath.ts |
Removes migrated label helpers. |
apps/web/src/components/files/filePath.test.ts |
Removes migrated tests. |
apps/web/src/components/files/FileBrowserPanel.tsx |
Imports shared root helpers. |
apps/web/src/components/files/FileBreadcrumbs.tsx |
Imports shared labels and types. |
apps/web/src/components/ChatView.tsx |
Uses shared root resolution. |
apps/web/src/components/chat/ChatComposer.tsx |
Uses shared root metadata. |
apps/mobile/src/state/queries.ts |
Sends root lists with path searches. |
apps/mobile/src/features/threads/use-composer-command-menu.ts |
Labels and inserts multi-root results. |
apps/mobile/src/features/threads/ThreadRouteScreen.tsx |
Supplies roots to the files inspector. |
apps/mobile/src/features/threads/ThreadComposer.tsx |
Resolves roots for thread mentions. |
apps/mobile/src/features/threads/NewTaskDraftScreen.tsx |
Resolves roots for draft mentions. |
apps/mobile/src/features/files/useProjectFileRoots.ts |
Reads and resolves workspace folders. |
apps/mobile/src/features/files/useFileTreeEntries.ts |
Builds and queries multi-root trees. |
apps/mobile/src/features/files/ThreadFilesRouteScreen.tsx |
Maps tree paths to absolute files. |
apps/mobile/src/features/files/thread-file-navigator-pane.tsx |
Integrates roots into the navigator. |
apps/mobile/src/features/files/fileTree.ts |
Adds rooted path conversions. |
apps/mobile/src/features/files/fileTree.test.ts |
Tests rooted path conversions. |
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
There was a problem hiding this comment.
Copilot review overview
🟡 Changes recommended
Root labels can still retain a prefix collision when both conflicting labels have reached their full paths, making part of the file tree inaccessible.
Review effort: Balanced
Findings: 1
Open (1)
Resolved since last review (1)
| if (label === otherLabel && canGrow(root)) growing.add(root); | ||
| if (otherLabel.startsWith(`${label}/`)) growing.add(canGrow(root) ? root : other); | ||
| } | ||
| } | ||
| const grown = [...growing].filter(canGrow); | ||
| if (grown.length === 0) break; |
There was a problem hiding this comment.
Leaving this one. The loop only stops with a prefix pair once both labels are full paths, which means /api/docs really is inside /api; api/docs/readme.md resolves to /api/docs/readme.md under either root, so nothing becomes unreachable.

What Changed
For a
.code-workspaceproject, the mobile file tree and@search now span the folders the file lists, as web does since #325. The tree shows one top-level folder per listed root, named by its label, and an isolated run lists the worktree's files under the repo's name.@results are described bylabel/dirand insert an absolute-path link. The tree waits for the first read of the folder list instead of showing the whole workspace folder.resolveProjectFileRootsand its label helpers moved fromapps/webtopackages/client-runtime(@t3tools/client-runtime/project-file-roots) so web and mobile share one implementation. Web only changes its imports. No contract or server changes: the list and search RPCs already acceptroots.Why
Follow-up 4 (mobile half) from the review of #325 on #323. Mobile still used the whole workspace folder, so unlisted sibling folders showed up and listed folders outside it, like
../notes, were missing.Not covered here: multi-repo projects without a workspace file keep the single cwd on mobile, and mobile chat file links are not matched against the roots the way #331 did for web.
UI Changes
Not yet verified on a device. Typecheck and unit tests pass; a recording is still to come.
_Video:
compare.mp4