Add filesystem browse API and command palette project picker - #2024

Merged
juliusmarminge merged 9 commits into
pingdotgg:mainfrom
Noojuno:t3code/014c948a
Apr 15, 2026
Merged

Add filesystem browse API and command palette project picker#2024
juliusmarminge merged 9 commits into
pingdotgg:mainfrom
Noojuno:t3code/014c948a

Conversation

@Noojuno

@NoojunoNoojuno commented Apr 15, 2026

Copy link
Copy Markdown
Contributor

Summary

  • Add filesystem.browse RPC endpoint with directory listing, cross-platform path resolution (Windows drive/UNC, Unix, ~/ expansion), and relative path support against the active project
  • Wire filesystem browse through contracts (FilesystemBrowseInput/Result/Error), shared path helpers (@t3tools/shared/path), the RPC group, server handler, WsRpcClient, and EnvironmentApi
  • Add "Add project" action to the command palette with an interactive filesystem browser: type a path to browse directories, navigate with keyboard/click, press Enter or click "Add" to create the project
  • Add projectPaths utility library for browse navigation (path segment append/parent, trailing separator detection, project deduplication, relative path resolution, title inference)
  • Fix pre-existing Effect v3→v4 type errors in the server filesystem handler (Effect.catchAllEffect.mapError, explicit type annotations)

Testing

  • bun run typecheck — all 8 packages pass (0 errors)
  • bun run test — contracts (65 tests), shared (75 tests including new path helpers), web (projectPaths 11 tests, wsRpcClient 1 test) all pass
  • Manual: command palette "Add project" action opens browse mode, directory listing populates, keyboard navigation and Enter-to-add work

Checklist

  • This PR is small and focused
  • I explained what changed and why
  • I included before/after screenshots for any UI changes
  • I included a video for animation/interaction changes

Note

Add filesystem browse API and command palette project picker

  • Adds a filesystem.browse WebSocket RPC that returns subdirectories under a given path, supporting prefix filtering, ~ expansion, relative paths with a cwd, and cross-platform path validation (WorkspaceEntries.ts, ws.ts).
  • Replaces the inline sidebar 'Add project' UI with a command palette flow: clicking the sidebar trigger opens the command palette in browse mode, where users can navigate directories with keyboard or click and submit a path to create a project via project.create.
  • Adds a comprehensive path utility library (projectPaths.ts) covering Windows drive/UNC/Unix path normalization, relative path resolution, browse query detection, and parent path traversal.
  • Extends ProjectCreateCommand with an optional createWorkspaceRootIfMissing flag; when set, normalizeWorkspaceRoot creates the directory before project creation.
  • Adds an 'Add project starts in' field to the General settings panel, letting users configure the default browse directory.
  • Risk: The normalizeWorkspaceRoot call in dispatch normalization now creates directories on disk when createWorkspaceRootIfMissing is true, which is a new side effect in the orchestration normalization path.

Macroscope summarized 4d4786d.


Note

Medium Risk
Adds a new filesystem.browse RPC path and changes project.create/normalizeWorkspaceRoot to optionally create missing workspace directories, which can affect filesystem behavior and error handling across environments.

Overview
Adds a new filesystem browsing capability via filesystem.browse in contracts/RPC/client/server, returning matching subdirectories for a partial path with ~ expansion, platform-aware Windows path guards, and optional relative-path resolution against a provided cwd.

Updates project creation path handling by extending project.create with createWorkspaceRootIfMissing and teaching WorkspacePaths.normalizeWorkspaceRoot (and orchestration normalization) to create missing workspace root directories when requested, including new error types and coverage in server tests.

Reworks “Add project” UX in the web app to run through the command palette: adds a browse mode with directory navigation, environment selection, prefetching, and an optional native folder picker (desktop bridge now accepts pickFolder({ initialPath })), plus a new addProjectBaseDirectory setting and broad UI/test updates (including removing the sidebar inline add-project form).

Reviewed by Cursor Bugbot for commit 4d4786d. Bugbot is set up for automated code reviews on this repo. Configure here.

- Implement directory browsing UI for selecting project paths
- Add filesystemBrowse RPC method for reading directories
- Include cross-platform path handling and validation
- Add project path utilities with comprehensive tests
@coderabbitai

coderabbitaiBot commented Apr 15, 2026

Copy link
Copy Markdown

Important

Review skipped

Auto reviews are disabled on this repository. Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: a246714d-6e2e-4c60-81bc-4cb6bdd3c542

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@github-actionsgithub-actionsBot added size:XL 500-999 changed lines (additions + deletions). vouch:trusted PR author is trusted by repo permissions or the VOUCHED list. labels Apr 15, 2026
@NoojunoNoojuno changed the title Add filesystem browser to command paletteAdd filesystem browse API and command palette project pickerApr 15, 2026
Comment threadapps/web/src/lib/projectPaths.ts
- Treat backslashes as literal characters in Unix absolute paths
- Add getAbsolutePathKind() to detect path style (Unix vs Windows)
- Update separator detection functions to respect absolute path kind
- Add test cases for mixed separator scenarios
Test that filesystem.browse requests are forwarded to the RPC client with correct parameters
@Noojuno
Noojuno marked this pull request as ready for review April 15, 2026 00:51
// the exact browse entry's fullPath or fall back to the raw query.
const resolvedAddProjectPath = hasTrailingPathSeparator(query)
? (browseResult?.parentPath ?? query.trim())
: (exactBrowseEntry?.fullPath ?? query.trim());

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Tilde paths bypass project deduplication check

Medium Severity

When browseResult hasn't loaded yet (or there's no exactBrowseEntry), resolvedAddProjectPath falls back to the raw query.trim() — a tilde-prefixed string like "~/projects/myapp". This unresolved path is passed to handleAddProject, where findProjectByPath compares it (via normalizeProjectPathForComparison) against existing projects whose cwd values are server-expanded absolute paths like "/home/user/projects/myapp". Since the tilde is never expanded client-side, the comparison always fails, and a duplicate project is created for the same directory.

Additional Locations (1)
Fix in CursorFix in Web

Reviewed by Cursor Bugbot for commit 9448e45. Configure here.

@macroscopeapp

macroscopeappBot commented Apr 15, 2026

Copy link
Copy Markdown
Contributor

Approvability

Verdict: Needs human review

This PR introduces a significant new feature (filesystem browse API and command palette project picker) with new RPC endpoints, UI flows, and server-side workspace creation capabilities. Additionally, there are multiple unresolved review comments identifying medium-severity bugs related to path handling and deduplication logic that could cause incorrect behavior.

You can customize Macroscope's approvability policy. Learn more.

- Move browse resolution and filtering into WorkspaceEntries
- Wire websocket filesystemBrowse to the shared service
- Add coverage for hidden, relative, and error cases
Co-authored-by: codex <codex@users.noreply.github.com>
(entry) =>
entry.name.toLowerCase().startsWith(lowerFilter) &&
(showHidden || !entry.name.startsWith(".")),
);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Client-side filter hides dot directories in directory listing mode

Medium Severity

filterBrowseEntries sets showHidden based solely on whether browseFilterQuery starts with ".". When the user navigates into a directory (trailing separator), browseFilterQuery is "", so showHidden is false and all dot-prefixed entries are filtered out. The server intentionally includes hidden directories in directory-listing mode (tested in WorkspaceEntries.test.ts — "shows dot directories in directory mode"), but the client discards them. Users can never see directories like .config or .vscode when browsing into a folder.

Fix in CursorFix in Web

Reviewed by Cursor Bugbot for commit 0ddcb1a. Configure here.

- Allow Enter or Mod+Enter to add browsed projects based on selection state
- Show the active add shortcut in the palette UI and keep highlighted rows in sync
const exactEntry =
input.browseFilterQuery.length > 0
? (filteredEntries.find((entry) => entry.name === input.browseFilterQuery) ?? null)
: null;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Case-sensitive exact match mismatches case-insensitive filter

Medium Severity

filterBrowseEntries uses case-insensitive prefix matching for filteredEntries but case-sensitive equality for exactEntry. When a user types a directory name with different casing (e.g., "development" vs "Development"), the entry appears in results but exactEntry is null. This causes resolvedAddProjectPath to fall back to the raw query.trim() (preserving the unexpanded tilde and wrong casing) instead of using the server-resolved fullPath from the browse entry. The project may be created with an incorrect, unexpanded path like ~/development instead of /Users/user/Development.

Additional Locations (1)
Fix in CursorFix in Web

Reviewed by Cursor Bugbot for commit 5dc6d92. Configure here.

Comment threadapps/server/src/workspace/Layers/WorkspaceEntries.ts
- Let add-project browse create missing workspace roots
- Allow choosing the environment before browsing
- Pass folder picker initial path from the UI
- Co-authored-by: codex <codex@users.noreply.github.com>
@github-actionsgithub-actionsBot added size:XXL 1,000+ changed lines (additions + deletions). and removed size:XL 500-999 changed lines (additions + deletions). labels Apr 15, 2026
Comment threadapps/web/src/components/CommandPaletteResults.tsx
juliusmarmingeand others added 3 commits April 14, 2026 22:58
- Persist `addProjectBaseDirectory` in server settings
- Start Add Project browsing from the configured path
Co-authored-by: codex <codex@users.noreply.github.com>
- Avoid offering Create & Add while directory browse results are pending
- Preserve existing directory detection when the query ends with `/`
- Add a regression test for existing directories with trailing slashes
@juliusmarminge
juliusmarminge merged commit 44afe78 into pingdotgg:mainApr 15, 2026
12 checks passed

@cursorcursorBot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursor Bugbot has reviewed your changes and found 1 potential issue.

There are 4 total unresolved issues (including 3 from previous reviews).

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit 4d4786d. Configure here.

items: addProjectEnvironmentItems,
},
],
[addProjectEnvironmentItems],

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Unmemoized array defeats downstream memoization chain

Low Severity

addProjectEnvironmentItems is created as a plain array every render (via .map()) without useMemo, then used as the sole dependency of the addProjectEnvironmentGroupsuseMemo. Since the array reference changes every render, the memo always recomputes, cascading instability to openAddProjectFlow (a useCallback depending on addProjectEnvironmentGroups) and the openIntentuseEffect. Wrapping addProjectEnvironmentItems in useMemo with [addProjectEnvironmentOptions, startAddProjectBrowse] would stabilize the entire chain.

Fix in CursorFix in Web

Reviewed by Cursor Bugbot for commit 4d4786d. Configure here.

aaditagrawal added a commit to aaditagrawal/t3code that referenced this pull request Apr 16, 2026
Integrates upstream/main (d22c6f5) into the fork while preserving all
multi-provider support (codex, claudeAgent, copilot, cursor, opencode,
geminiCli, amp, kilo) and fork UI/UX additions.
Highlights adopted from upstream:
- Nightly release channel + update channel selector (pingdotgg#2012, pingdotgg#2049, pingdotgg#1969)
- Filesystem browse API + command palette project picker (pingdotgg#2024)
- Launch Args setting for Claude provider (pingdotgg#1971)
- Kiro editor support in open picker (pingdotgg#1974)
- Claude plan events for TodoWrite during input streaming (pingdotgg#1541)
- Lost provider session recovery (pingdotgg#1938)
- Cache provider status and gate desktop startup (pingdotgg#1962)
- LegendList migration for chat scrolling and branch lists (pingdotgg#1953)
- Shell snapshot queries + backfill migration (pingdotgg#1973, pingdotgg#2004)
- PATH hydration + fallback detection (pingdotgg#1799)
- Warm sidebar thread subscriptions (pingdotgg#2001)
- Full thread title tooltip (pingdotgg#1994)
- Markdown file link UX (pingdotgg#1956), composer polish (pingdotgg#1944, pingdotgg#1992, pingdotgg#1985)
- Worktree/branch state + draft reuse fixes (pingdotgg#2005, pingdotgg#2003, pingdotgg#1995, pingdotgg#1936)
- Window controls overlay for Windows/Linux (pingdotgg#1969)
- Backend readiness timeout 10s→30s (pingdotgg#1979)
- Clear tracked RPCs on reconnect, live stream subscriptions (pingdotgg#2000, pingdotgg#1972)
- Various misc fixes (pingdotgg#2051, pingdotgg#2052, pingdotgg#2025, pingdotgg#2027, pingdotgg#2049, pingdotgg#1997, pingdotgg#1975)
Fork features preserved and reconciled:
- All 8 provider adapters + conformance tests
- Extended ProviderKind union across contracts/model/settings/provider
- appearance/accentColor/themeConfig/ProviderLogo UI system
- customModels + gitTextGeneration + providerModelOptions
- Migration IDs 23 (NormalizeLegacyProviderKinds) and 24
(RepairProjectionThreadProposedPlanImplementationColumns) kept; new
upstream migrations registered at IDs 25-26 to avoid breaking deployed
fork databases
- DesktopBridge: log directory channels (LOG_DIR/LIST/READ/OPEN_DIR)
retained; getWsUrl replaced by upstream's getAppBranding
- PROVIDER_CACHE_IDS extended to all 8 providers
aaditagrawal added a commit to aaditagrawal/t3code that referenced this pull request Apr 19, 2026
## Font rendering
Pre-sync, the fork had only `pre, code, textarea, input` selectors
using Geist Mono when code/terminal context demanded it, but the recent
sync collapsed all four into a single rule that applied the monospace
stack to *every* <input> in the app. The command palette search, model
picker trait inputs, settings binary/server URL fields, etc. all rendered
in Geist Mono, which is what produced the 'broken font' look.
Narrow the rule back to `pre, code` (and `textarea` in code-focused
contexts inherits naturally). Regular inputs now use the body font
(DM Sans).
## Cmd+K shortcut
The commandPalette.toggle keydown handler in CommandPalette.tsx used
the bubble phase, which means xterm (when terminal has focus) or a
contenteditable composer could swallow Cmd+K before it reached the
window listener. Switch the listener to capture phase — matches
upstream's CTRL+J fix for terminal.toggle (pingdotgg#2113). The project picker
already lives inside the command palette (filesystem browse API +
command-palette project picker from pingdotgg#2024); this restores access to it
via the shortcut.
youpele52 referenced this pull request in youpele52/bigbud Jun 17, 2026
Co-authored-by: Julius Marminge <julius0216@outlook.com>
Co-authored-by: codex <codex@users.noreply.github.com>
NeilTheFisher pushed a commit to NeilTheFisher/t3code that referenced this pull request Aug 18, 2026
…gg#2024)
Co-authored-by: Julius Marminge <julius0216@outlook.com>
Co-authored-by: codex <codex@users.noreply.github.com>
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size:XXL1,000+ changed lines (additions + deletions).vouch:trustedPR author is trusted by repo permissions or the VOUCHED list.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants

@Noojuno@juliusmarminge
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Add copy buttons to all
 blocks\n(function() {\n function addCopyButtons() {\n document.querySelectorAll('pre code').forEach(function(codeBlock) {\n if (codeBlock.parentElement.hasAttribute('data-copy-added')) return;\n codeBlock.parentElement.setAttribute('data-copy-added', 'true');\n \n var btn = document.createElement('button');\n btn.textContent = 'Copy';\n btn.style.cssText = 'position:absolute;top:4px;right:4px;padding:2px 8px;font-size:11px;background:#4ecdc4;border:none;border-radius:4px;color:#1a1a2e;cursor:pointer;opacity:0.7;transition:opacity 0.2s;';\n btn.onmouseover = function() { this.style.opacity = '1'; };\n btn.onmouseout = function() { this.style.opacity = '0.7'; };\n btn.onclick = function() {\n navigator.clipboard.writeText(codeBlock.textContent).then(function() {\n btn.textContent = 'Copied!';\n setTimeout(function() { btn.textContent = 'Copy'; }, 1500);\n });\n };\n codeBlock.parentElement.style.position = 'relative';\n codeBlock.parentElement.appendChild(btn);\n });\n }\n \n addCopyButtons();\n \n // Re-run on dynamic content\n var observer = new MutationObserver(addCopyButtons);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Add Copy Buttons to Code Blocks");
}
} catch(__e) { console.warn('[Userscript:Add Copy Buttons to Code Blocks]', __e); }
})();
(function(){
try {
var __m = "github.com";
var __re = new RegExp('^' + "github\\.com" + '
Skip to content

Add filesystem browse API and command palette project picker - #2024

Merged
juliusmarminge merged 9 commits into
pingdotgg:mainfrom
Noojuno:t3code/014c948a
Apr 15, 2026
Merged

Add filesystem browse API and command palette project picker#2024
juliusmarminge merged 9 commits into
pingdotgg:mainfrom
Noojuno:t3code/014c948a

Conversation

@Noojuno

@NoojunoNoojuno commented Apr 15, 2026

Copy link
Copy Markdown
Contributor

Summary

  • Add filesystem.browse RPC endpoint with directory listing, cross-platform path resolution (Windows drive/UNC, Unix, ~/ expansion), and relative path support against the active project
  • Wire filesystem browse through contracts (FilesystemBrowseInput/Result/Error), shared path helpers (@t3tools/shared/path), the RPC group, server handler, WsRpcClient, and EnvironmentApi
  • Add "Add project" action to the command palette with an interactive filesystem browser: type a path to browse directories, navigate with keyboard/click, press Enter or click "Add" to create the project
  • Add projectPaths utility library for browse navigation (path segment append/parent, trailing separator detection, project deduplication, relative path resolution, title inference)
  • Fix pre-existing Effect v3→v4 type errors in the server filesystem handler (Effect.catchAllEffect.mapError, explicit type annotations)

Testing

  • bun run typecheck — all 8 packages pass (0 errors)
  • bun run test — contracts (65 tests), shared (75 tests including new path helpers), web (projectPaths 11 tests, wsRpcClient 1 test) all pass
  • Manual: command palette "Add project" action opens browse mode, directory listing populates, keyboard navigation and Enter-to-add work

Checklist

  • This PR is small and focused
  • I explained what changed and why
  • I included before/after screenshots for any UI changes
  • I included a video for animation/interaction changes

Note

Add filesystem browse API and command palette project picker

  • Adds a filesystem.browse WebSocket RPC that returns subdirectories under a given path, supporting prefix filtering, ~ expansion, relative paths with a cwd, and cross-platform path validation (WorkspaceEntries.ts, ws.ts).
  • Replaces the inline sidebar 'Add project' UI with a command palette flow: clicking the sidebar trigger opens the command palette in browse mode, where users can navigate directories with keyboard or click and submit a path to create a project via project.create.
  • Adds a comprehensive path utility library (projectPaths.ts) covering Windows drive/UNC/Unix path normalization, relative path resolution, browse query detection, and parent path traversal.
  • Extends ProjectCreateCommand with an optional createWorkspaceRootIfMissing flag; when set, normalizeWorkspaceRoot creates the directory before project creation.
  • Adds an 'Add project starts in' field to the General settings panel, letting users configure the default browse directory.
  • Risk: The normalizeWorkspaceRoot call in dispatch normalization now creates directories on disk when createWorkspaceRootIfMissing is true, which is a new side effect in the orchestration normalization path.

Macroscope summarized 4d4786d.


Note

Medium Risk
Adds a new filesystem.browse RPC path and changes project.create/normalizeWorkspaceRoot to optionally create missing workspace directories, which can affect filesystem behavior and error handling across environments.

Overview
Adds a new filesystem browsing capability via filesystem.browse in contracts/RPC/client/server, returning matching subdirectories for a partial path with ~ expansion, platform-aware Windows path guards, and optional relative-path resolution against a provided cwd.

Updates project creation path handling by extending project.create with createWorkspaceRootIfMissing and teaching WorkspacePaths.normalizeWorkspaceRoot (and orchestration normalization) to create missing workspace root directories when requested, including new error types and coverage in server tests.

Reworks “Add project” UX in the web app to run through the command palette: adds a browse mode with directory navigation, environment selection, prefetching, and an optional native folder picker (desktop bridge now accepts pickFolder({ initialPath })), plus a new addProjectBaseDirectory setting and broad UI/test updates (including removing the sidebar inline add-project form).

Reviewed by Cursor Bugbot for commit 4d4786d. Bugbot is set up for automated code reviews on this repo. Configure here.

- Implement directory browsing UI for selecting project paths
- Add filesystemBrowse RPC method for reading directories
- Include cross-platform path handling and validation
- Add project path utilities with comprehensive tests
@coderabbitai

coderabbitaiBot commented Apr 15, 2026

Copy link
Copy Markdown

Important

Review skipped

Auto reviews are disabled on this repository. Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: a246714d-6e2e-4c60-81bc-4cb6bdd3c542

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@github-actionsgithub-actionsBot added size:XL 500-999 changed lines (additions + deletions). vouch:trusted PR author is trusted by repo permissions or the VOUCHED list. labels Apr 15, 2026
@NoojunoNoojuno changed the title Add filesystem browser to command paletteAdd filesystem browse API and command palette project pickerApr 15, 2026
Comment threadapps/web/src/lib/projectPaths.ts
- Treat backslashes as literal characters in Unix absolute paths
- Add getAbsolutePathKind() to detect path style (Unix vs Windows)
- Update separator detection functions to respect absolute path kind
- Add test cases for mixed separator scenarios
Test that filesystem.browse requests are forwarded to the RPC client with correct parameters
@Noojuno
Noojuno marked this pull request as ready for review April 15, 2026 00:51
// the exact browse entry's fullPath or fall back to the raw query.
const resolvedAddProjectPath = hasTrailingPathSeparator(query)
? (browseResult?.parentPath ?? query.trim())
: (exactBrowseEntry?.fullPath ?? query.trim());

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Tilde paths bypass project deduplication check

Medium Severity

When browseResult hasn't loaded yet (or there's no exactBrowseEntry), resolvedAddProjectPath falls back to the raw query.trim() — a tilde-prefixed string like "~/projects/myapp". This unresolved path is passed to handleAddProject, where findProjectByPath compares it (via normalizeProjectPathForComparison) against existing projects whose cwd values are server-expanded absolute paths like "/home/user/projects/myapp". Since the tilde is never expanded client-side, the comparison always fails, and a duplicate project is created for the same directory.

Additional Locations (1)
Fix in CursorFix in Web

Reviewed by Cursor Bugbot for commit 9448e45. Configure here.

@macroscopeapp

macroscopeappBot commented Apr 15, 2026

Copy link
Copy Markdown
Contributor

Approvability

Verdict: Needs human review

This PR introduces a significant new feature (filesystem browse API and command palette project picker) with new RPC endpoints, UI flows, and server-side workspace creation capabilities. Additionally, there are multiple unresolved review comments identifying medium-severity bugs related to path handling and deduplication logic that could cause incorrect behavior.

You can customize Macroscope's approvability policy. Learn more.

- Move browse resolution and filtering into WorkspaceEntries
- Wire websocket filesystemBrowse to the shared service
- Add coverage for hidden, relative, and error cases
Co-authored-by: codex <codex@users.noreply.github.com>
(entry) =>
entry.name.toLowerCase().startsWith(lowerFilter) &&
(showHidden || !entry.name.startsWith(".")),
);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Client-side filter hides dot directories in directory listing mode

Medium Severity

filterBrowseEntries sets showHidden based solely on whether browseFilterQuery starts with ".". When the user navigates into a directory (trailing separator), browseFilterQuery is "", so showHidden is false and all dot-prefixed entries are filtered out. The server intentionally includes hidden directories in directory-listing mode (tested in WorkspaceEntries.test.ts — "shows dot directories in directory mode"), but the client discards them. Users can never see directories like .config or .vscode when browsing into a folder.

Fix in CursorFix in Web

Reviewed by Cursor Bugbot for commit 0ddcb1a. Configure here.

- Allow Enter or Mod+Enter to add browsed projects based on selection state
- Show the active add shortcut in the palette UI and keep highlighted rows in sync
const exactEntry =
input.browseFilterQuery.length > 0
? (filteredEntries.find((entry) => entry.name === input.browseFilterQuery) ?? null)
: null;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Case-sensitive exact match mismatches case-insensitive filter

Medium Severity

filterBrowseEntries uses case-insensitive prefix matching for filteredEntries but case-sensitive equality for exactEntry. When a user types a directory name with different casing (e.g., "development" vs "Development"), the entry appears in results but exactEntry is null. This causes resolvedAddProjectPath to fall back to the raw query.trim() (preserving the unexpanded tilde and wrong casing) instead of using the server-resolved fullPath from the browse entry. The project may be created with an incorrect, unexpanded path like ~/development instead of /Users/user/Development.

Additional Locations (1)
Fix in CursorFix in Web

Reviewed by Cursor Bugbot for commit 5dc6d92. Configure here.

Comment threadapps/server/src/workspace/Layers/WorkspaceEntries.ts
- Let add-project browse create missing workspace roots
- Allow choosing the environment before browsing
- Pass folder picker initial path from the UI
- Co-authored-by: codex <codex@users.noreply.github.com>
@github-actionsgithub-actionsBot added size:XXL 1,000+ changed lines (additions + deletions). and removed size:XL 500-999 changed lines (additions + deletions). labels Apr 15, 2026
Comment threadapps/web/src/components/CommandPaletteResults.tsx
juliusmarmingeand others added 3 commits April 14, 2026 22:58
- Persist `addProjectBaseDirectory` in server settings
- Start Add Project browsing from the configured path
Co-authored-by: codex <codex@users.noreply.github.com>
- Avoid offering Create & Add while directory browse results are pending
- Preserve existing directory detection when the query ends with `/`
- Add a regression test for existing directories with trailing slashes
@juliusmarminge
juliusmarminge merged commit 44afe78 into pingdotgg:mainApr 15, 2026
12 checks passed

@cursorcursorBot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursor Bugbot has reviewed your changes and found 1 potential issue.

There are 4 total unresolved issues (including 3 from previous reviews).

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit 4d4786d. Configure here.

items: addProjectEnvironmentItems,
},
],
[addProjectEnvironmentItems],

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Unmemoized array defeats downstream memoization chain

Low Severity

addProjectEnvironmentItems is created as a plain array every render (via .map()) without useMemo, then used as the sole dependency of the addProjectEnvironmentGroupsuseMemo. Since the array reference changes every render, the memo always recomputes, cascading instability to openAddProjectFlow (a useCallback depending on addProjectEnvironmentGroups) and the openIntentuseEffect. Wrapping addProjectEnvironmentItems in useMemo with [addProjectEnvironmentOptions, startAddProjectBrowse] would stabilize the entire chain.

Fix in CursorFix in Web

Reviewed by Cursor Bugbot for commit 4d4786d. Configure here.

aaditagrawal added a commit to aaditagrawal/t3code that referenced this pull request Apr 16, 2026
Integrates upstream/main (d22c6f5) into the fork while preserving all
multi-provider support (codex, claudeAgent, copilot, cursor, opencode,
geminiCli, amp, kilo) and fork UI/UX additions.
Highlights adopted from upstream:
- Nightly release channel + update channel selector (pingdotgg#2012, pingdotgg#2049, pingdotgg#1969)
- Filesystem browse API + command palette project picker (pingdotgg#2024)
- Launch Args setting for Claude provider (pingdotgg#1971)
- Kiro editor support in open picker (pingdotgg#1974)
- Claude plan events for TodoWrite during input streaming (pingdotgg#1541)
- Lost provider session recovery (pingdotgg#1938)
- Cache provider status and gate desktop startup (pingdotgg#1962)
- LegendList migration for chat scrolling and branch lists (pingdotgg#1953)
- Shell snapshot queries + backfill migration (pingdotgg#1973, pingdotgg#2004)
- PATH hydration + fallback detection (pingdotgg#1799)
- Warm sidebar thread subscriptions (pingdotgg#2001)
- Full thread title tooltip (pingdotgg#1994)
- Markdown file link UX (pingdotgg#1956), composer polish (pingdotgg#1944, pingdotgg#1992, pingdotgg#1985)
- Worktree/branch state + draft reuse fixes (pingdotgg#2005, pingdotgg#2003, pingdotgg#1995, pingdotgg#1936)
- Window controls overlay for Windows/Linux (pingdotgg#1969)
- Backend readiness timeout 10s→30s (pingdotgg#1979)
- Clear tracked RPCs on reconnect, live stream subscriptions (pingdotgg#2000, pingdotgg#1972)
- Various misc fixes (pingdotgg#2051, pingdotgg#2052, pingdotgg#2025, pingdotgg#2027, pingdotgg#2049, pingdotgg#1997, pingdotgg#1975)
Fork features preserved and reconciled:
- All 8 provider adapters + conformance tests
- Extended ProviderKind union across contracts/model/settings/provider
- appearance/accentColor/themeConfig/ProviderLogo UI system
- customModels + gitTextGeneration + providerModelOptions
- Migration IDs 23 (NormalizeLegacyProviderKinds) and 24
(RepairProjectionThreadProposedPlanImplementationColumns) kept; new
upstream migrations registered at IDs 25-26 to avoid breaking deployed
fork databases
- DesktopBridge: log directory channels (LOG_DIR/LIST/READ/OPEN_DIR)
retained; getWsUrl replaced by upstream's getAppBranding
- PROVIDER_CACHE_IDS extended to all 8 providers
aaditagrawal added a commit to aaditagrawal/t3code that referenced this pull request Apr 19, 2026
## Font rendering
Pre-sync, the fork had only `pre, code, textarea, input` selectors
using Geist Mono when code/terminal context demanded it, but the recent
sync collapsed all four into a single rule that applied the monospace
stack to *every* <input> in the app. The command palette search, model
picker trait inputs, settings binary/server URL fields, etc. all rendered
in Geist Mono, which is what produced the 'broken font' look.
Narrow the rule back to `pre, code` (and `textarea` in code-focused
contexts inherits naturally). Regular inputs now use the body font
(DM Sans).
## Cmd+K shortcut
The commandPalette.toggle keydown handler in CommandPalette.tsx used
the bubble phase, which means xterm (when terminal has focus) or a
contenteditable composer could swallow Cmd+K before it reached the
window listener. Switch the listener to capture phase — matches
upstream's CTRL+J fix for terminal.toggle (pingdotgg#2113). The project picker
already lives inside the command palette (filesystem browse API +
command-palette project picker from pingdotgg#2024); this restores access to it
via the shortcut.
youpele52 referenced this pull request in youpele52/bigbud Jun 17, 2026
Co-authored-by: Julius Marminge <julius0216@outlook.com>
Co-authored-by: codex <codex@users.noreply.github.com>
NeilTheFisher pushed a commit to NeilTheFisher/t3code that referenced this pull request Aug 18, 2026
…gg#2024)
Co-authored-by: Julius Marminge <julius0216@outlook.com>
Co-authored-by: codex <codex@users.noreply.github.com>
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size:XXL1,000+ changed lines (additions + deletions).vouch:trustedPR author is trusted by repo permissions or the VOUCHED list.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants

@Noojuno@juliusmarminge
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Force GitHub README to respect dark mode\n(function() {\n var style = document.createElement('style');\n style.textContent = '\n .markdown-body {\n color-scheme: dark light;\n }\n .markdown-body pre { background: #161b22 !important; }\n .markdown-body code { background: rgba(110, 118, 129, 0.4) !important; }\n .markdown-body table th, .markdown-body table td { border-color: #30363d !important; }\n .markdown-body img { background: #0d1117; }\n .markdown-body blockquote { border-left-color: #8b949e; }\n .markdown-body hr { border-color: #30363d; }\n ';\n document.head.appendChild(style);\n})();", "GitHub Dark Mode README Fix"); } } catch(__e) { console.warn('[Userscript:GitHub Dark Mode README Fix]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Add filesystem browse API and command palette project picker - #2024

Merged
juliusmarminge merged 9 commits into
pingdotgg:mainfrom
Noojuno:t3code/014c948a
Apr 15, 2026
Merged

Add filesystem browse API and command palette project picker#2024
juliusmarminge merged 9 commits into
pingdotgg:mainfrom
Noojuno:t3code/014c948a

Conversation

@Noojuno

@NoojunoNoojuno commented Apr 15, 2026

Copy link
Copy Markdown
Contributor

Summary

  • Add filesystem.browse RPC endpoint with directory listing, cross-platform path resolution (Windows drive/UNC, Unix, ~/ expansion), and relative path support against the active project
  • Wire filesystem browse through contracts (FilesystemBrowseInput/Result/Error), shared path helpers (@t3tools/shared/path), the RPC group, server handler, WsRpcClient, and EnvironmentApi
  • Add "Add project" action to the command palette with an interactive filesystem browser: type a path to browse directories, navigate with keyboard/click, press Enter or click "Add" to create the project
  • Add projectPaths utility library for browse navigation (path segment append/parent, trailing separator detection, project deduplication, relative path resolution, title inference)
  • Fix pre-existing Effect v3→v4 type errors in the server filesystem handler (Effect.catchAllEffect.mapError, explicit type annotations)

Testing

  • bun run typecheck — all 8 packages pass (0 errors)
  • bun run test — contracts (65 tests), shared (75 tests including new path helpers), web (projectPaths 11 tests, wsRpcClient 1 test) all pass
  • Manual: command palette "Add project" action opens browse mode, directory listing populates, keyboard navigation and Enter-to-add work

Checklist

  • This PR is small and focused
  • I explained what changed and why
  • I included before/after screenshots for any UI changes
  • I included a video for animation/interaction changes

Note

Add filesystem browse API and command palette project picker

  • Adds a filesystem.browse WebSocket RPC that returns subdirectories under a given path, supporting prefix filtering, ~ expansion, relative paths with a cwd, and cross-platform path validation (WorkspaceEntries.ts, ws.ts).
  • Replaces the inline sidebar 'Add project' UI with a command palette flow: clicking the sidebar trigger opens the command palette in browse mode, where users can navigate directories with keyboard or click and submit a path to create a project via project.create.
  • Adds a comprehensive path utility library (projectPaths.ts) covering Windows drive/UNC/Unix path normalization, relative path resolution, browse query detection, and parent path traversal.
  • Extends ProjectCreateCommand with an optional createWorkspaceRootIfMissing flag; when set, normalizeWorkspaceRoot creates the directory before project creation.
  • Adds an 'Add project starts in' field to the General settings panel, letting users configure the default browse directory.
  • Risk: The normalizeWorkspaceRoot call in dispatch normalization now creates directories on disk when createWorkspaceRootIfMissing is true, which is a new side effect in the orchestration normalization path.

Macroscope summarized 4d4786d.


Note

Medium Risk
Adds a new filesystem.browse RPC path and changes project.create/normalizeWorkspaceRoot to optionally create missing workspace directories, which can affect filesystem behavior and error handling across environments.

Overview
Adds a new filesystem browsing capability via filesystem.browse in contracts/RPC/client/server, returning matching subdirectories for a partial path with ~ expansion, platform-aware Windows path guards, and optional relative-path resolution against a provided cwd.

Updates project creation path handling by extending project.create with createWorkspaceRootIfMissing and teaching WorkspacePaths.normalizeWorkspaceRoot (and orchestration normalization) to create missing workspace root directories when requested, including new error types and coverage in server tests.

Reworks “Add project” UX in the web app to run through the command palette: adds a browse mode with directory navigation, environment selection, prefetching, and an optional native folder picker (desktop bridge now accepts pickFolder({ initialPath })), plus a new addProjectBaseDirectory setting and broad UI/test updates (including removing the sidebar inline add-project form).

Reviewed by Cursor Bugbot for commit 4d4786d. Bugbot is set up for automated code reviews on this repo. Configure here.

- Implement directory browsing UI for selecting project paths
- Add filesystemBrowse RPC method for reading directories
- Include cross-platform path handling and validation
- Add project path utilities with comprehensive tests
@coderabbitai

coderabbitaiBot commented Apr 15, 2026

Copy link
Copy Markdown

Important

Review skipped

Auto reviews are disabled on this repository. Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: a246714d-6e2e-4c60-81bc-4cb6bdd3c542

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@github-actionsgithub-actionsBot added size:XL 500-999 changed lines (additions + deletions). vouch:trusted PR author is trusted by repo permissions or the VOUCHED list. labels Apr 15, 2026
@NoojunoNoojuno changed the title Add filesystem browser to command paletteAdd filesystem browse API and command palette project pickerApr 15, 2026
Comment threadapps/web/src/lib/projectPaths.ts
- Treat backslashes as literal characters in Unix absolute paths
- Add getAbsolutePathKind() to detect path style (Unix vs Windows)
- Update separator detection functions to respect absolute path kind
- Add test cases for mixed separator scenarios
Test that filesystem.browse requests are forwarded to the RPC client with correct parameters
@Noojuno
Noojuno marked this pull request as ready for review April 15, 2026 00:51
// the exact browse entry's fullPath or fall back to the raw query.
const resolvedAddProjectPath = hasTrailingPathSeparator(query)
? (browseResult?.parentPath ?? query.trim())
: (exactBrowseEntry?.fullPath ?? query.trim());

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Tilde paths bypass project deduplication check

Medium Severity

When browseResult hasn't loaded yet (or there's no exactBrowseEntry), resolvedAddProjectPath falls back to the raw query.trim() — a tilde-prefixed string like "~/projects/myapp". This unresolved path is passed to handleAddProject, where findProjectByPath compares it (via normalizeProjectPathForComparison) against existing projects whose cwd values are server-expanded absolute paths like "/home/user/projects/myapp". Since the tilde is never expanded client-side, the comparison always fails, and a duplicate project is created for the same directory.

Additional Locations (1)
Fix in CursorFix in Web

Reviewed by Cursor Bugbot for commit 9448e45. Configure here.

@macroscopeapp

macroscopeappBot commented Apr 15, 2026

Copy link
Copy Markdown
Contributor

Approvability

Verdict: Needs human review

This PR introduces a significant new feature (filesystem browse API and command palette project picker) with new RPC endpoints, UI flows, and server-side workspace creation capabilities. Additionally, there are multiple unresolved review comments identifying medium-severity bugs related to path handling and deduplication logic that could cause incorrect behavior.

You can customize Macroscope's approvability policy. Learn more.

- Move browse resolution and filtering into WorkspaceEntries
- Wire websocket filesystemBrowse to the shared service
- Add coverage for hidden, relative, and error cases
Co-authored-by: codex <codex@users.noreply.github.com>
(entry) =>
entry.name.toLowerCase().startsWith(lowerFilter) &&
(showHidden || !entry.name.startsWith(".")),
);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Client-side filter hides dot directories in directory listing mode

Medium Severity

filterBrowseEntries sets showHidden based solely on whether browseFilterQuery starts with ".". When the user navigates into a directory (trailing separator), browseFilterQuery is "", so showHidden is false and all dot-prefixed entries are filtered out. The server intentionally includes hidden directories in directory-listing mode (tested in WorkspaceEntries.test.ts — "shows dot directories in directory mode"), but the client discards them. Users can never see directories like .config or .vscode when browsing into a folder.

Fix in CursorFix in Web

Reviewed by Cursor Bugbot for commit 0ddcb1a. Configure here.

- Allow Enter or Mod+Enter to add browsed projects based on selection state
- Show the active add shortcut in the palette UI and keep highlighted rows in sync
const exactEntry =
input.browseFilterQuery.length > 0
? (filteredEntries.find((entry) => entry.name === input.browseFilterQuery) ?? null)
: null;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Case-sensitive exact match mismatches case-insensitive filter

Medium Severity

filterBrowseEntries uses case-insensitive prefix matching for filteredEntries but case-sensitive equality for exactEntry. When a user types a directory name with different casing (e.g., "development" vs "Development"), the entry appears in results but exactEntry is null. This causes resolvedAddProjectPath to fall back to the raw query.trim() (preserving the unexpanded tilde and wrong casing) instead of using the server-resolved fullPath from the browse entry. The project may be created with an incorrect, unexpanded path like ~/development instead of /Users/user/Development.

Additional Locations (1)
Fix in CursorFix in Web

Reviewed by Cursor Bugbot for commit 5dc6d92. Configure here.

Comment threadapps/server/src/workspace/Layers/WorkspaceEntries.ts
- Let add-project browse create missing workspace roots
- Allow choosing the environment before browsing
- Pass folder picker initial path from the UI
- Co-authored-by: codex <codex@users.noreply.github.com>
@github-actionsgithub-actionsBot added size:XXL 1,000+ changed lines (additions + deletions). and removed size:XL 500-999 changed lines (additions + deletions). labels Apr 15, 2026
Comment threadapps/web/src/components/CommandPaletteResults.tsx
juliusmarmingeand others added 3 commits April 14, 2026 22:58
- Persist `addProjectBaseDirectory` in server settings
- Start Add Project browsing from the configured path
Co-authored-by: codex <codex@users.noreply.github.com>
- Avoid offering Create & Add while directory browse results are pending
- Preserve existing directory detection when the query ends with `/`
- Add a regression test for existing directories with trailing slashes
@juliusmarminge
juliusmarminge merged commit 44afe78 into pingdotgg:mainApr 15, 2026
12 checks passed

@cursorcursorBot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursor Bugbot has reviewed your changes and found 1 potential issue.

There are 4 total unresolved issues (including 3 from previous reviews).

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit 4d4786d. Configure here.

items: addProjectEnvironmentItems,
},
],
[addProjectEnvironmentItems],

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Unmemoized array defeats downstream memoization chain

Low Severity

addProjectEnvironmentItems is created as a plain array every render (via .map()) without useMemo, then used as the sole dependency of the addProjectEnvironmentGroupsuseMemo. Since the array reference changes every render, the memo always recomputes, cascading instability to openAddProjectFlow (a useCallback depending on addProjectEnvironmentGroups) and the openIntentuseEffect. Wrapping addProjectEnvironmentItems in useMemo with [addProjectEnvironmentOptions, startAddProjectBrowse] would stabilize the entire chain.

Fix in CursorFix in Web

Reviewed by Cursor Bugbot for commit 4d4786d. Configure here.

aaditagrawal added a commit to aaditagrawal/t3code that referenced this pull request Apr 16, 2026
Integrates upstream/main (d22c6f5) into the fork while preserving all
multi-provider support (codex, claudeAgent, copilot, cursor, opencode,
geminiCli, amp, kilo) and fork UI/UX additions.
Highlights adopted from upstream:
- Nightly release channel + update channel selector (pingdotgg#2012, pingdotgg#2049, pingdotgg#1969)
- Filesystem browse API + command palette project picker (pingdotgg#2024)
- Launch Args setting for Claude provider (pingdotgg#1971)
- Kiro editor support in open picker (pingdotgg#1974)
- Claude plan events for TodoWrite during input streaming (pingdotgg#1541)
- Lost provider session recovery (pingdotgg#1938)
- Cache provider status and gate desktop startup (pingdotgg#1962)
- LegendList migration for chat scrolling and branch lists (pingdotgg#1953)
- Shell snapshot queries + backfill migration (pingdotgg#1973, pingdotgg#2004)
- PATH hydration + fallback detection (pingdotgg#1799)
- Warm sidebar thread subscriptions (pingdotgg#2001)
- Full thread title tooltip (pingdotgg#1994)
- Markdown file link UX (pingdotgg#1956), composer polish (pingdotgg#1944, pingdotgg#1992, pingdotgg#1985)
- Worktree/branch state + draft reuse fixes (pingdotgg#2005, pingdotgg#2003, pingdotgg#1995, pingdotgg#1936)
- Window controls overlay for Windows/Linux (pingdotgg#1969)
- Backend readiness timeout 10s→30s (pingdotgg#1979)
- Clear tracked RPCs on reconnect, live stream subscriptions (pingdotgg#2000, pingdotgg#1972)
- Various misc fixes (pingdotgg#2051, pingdotgg#2052, pingdotgg#2025, pingdotgg#2027, pingdotgg#2049, pingdotgg#1997, pingdotgg#1975)
Fork features preserved and reconciled:
- All 8 provider adapters + conformance tests
- Extended ProviderKind union across contracts/model/settings/provider
- appearance/accentColor/themeConfig/ProviderLogo UI system
- customModels + gitTextGeneration + providerModelOptions
- Migration IDs 23 (NormalizeLegacyProviderKinds) and 24
(RepairProjectionThreadProposedPlanImplementationColumns) kept; new
upstream migrations registered at IDs 25-26 to avoid breaking deployed
fork databases
- DesktopBridge: log directory channels (LOG_DIR/LIST/READ/OPEN_DIR)
retained; getWsUrl replaced by upstream's getAppBranding
- PROVIDER_CACHE_IDS extended to all 8 providers
aaditagrawal added a commit to aaditagrawal/t3code that referenced this pull request Apr 19, 2026
## Font rendering
Pre-sync, the fork had only `pre, code, textarea, input` selectors
using Geist Mono when code/terminal context demanded it, but the recent
sync collapsed all four into a single rule that applied the monospace
stack to *every* <input> in the app. The command palette search, model
picker trait inputs, settings binary/server URL fields, etc. all rendered
in Geist Mono, which is what produced the 'broken font' look.
Narrow the rule back to `pre, code` (and `textarea` in code-focused
contexts inherits naturally). Regular inputs now use the body font
(DM Sans).
## Cmd+K shortcut
The commandPalette.toggle keydown handler in CommandPalette.tsx used
the bubble phase, which means xterm (when terminal has focus) or a
contenteditable composer could swallow Cmd+K before it reached the
window listener. Switch the listener to capture phase — matches
upstream's CTRL+J fix for terminal.toggle (pingdotgg#2113). The project picker
already lives inside the command palette (filesystem browse API +
command-palette project picker from pingdotgg#2024); this restores access to it
via the shortcut.
youpele52 referenced this pull request in youpele52/bigbud Jun 17, 2026
Co-authored-by: Julius Marminge <julius0216@outlook.com>
Co-authored-by: codex <codex@users.noreply.github.com>
NeilTheFisher pushed a commit to NeilTheFisher/t3code that referenced this pull request Aug 18, 2026
…gg#2024)
Co-authored-by: Julius Marminge <julius0216@outlook.com>
Co-authored-by: codex <codex@users.noreply.github.com>
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size:XXL1,000+ changed lines (additions + deletions).vouch:trustedPR author is trusted by repo permissions or the VOUCHED list.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants

@Noojuno@juliusmarminge
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Highlight search terms from Google/DuckDuckGo/Bing referrer\n(function() {\n var ref = document.referrer;\n var terms = [];\n \n if (ref.includes('google.com') || ref.includes('duckduckgo.com') || ref.includes('bing.com')) {\n var url = new URL(ref);\n var q = url.searchParams.get('q') || url.searchParams.get('p');\n if (q) {\n terms = q.split(/\\s+/).filter(function(t) { return t.length > 2; });\n }\n }\n \n if (terms.length === 0) return;\n \n var style = document.createElement('style');\n style.textContent = '.userscript-highlight { background: #fbbf24; color: #1a1a2e; padding: 1px 3px; border-radius: 2px; }';\n document.head.appendChild(style);\n \n function highlight(node) {\n if (node.nodeType === 3) { // text node\n var text = node.textContent;\n var found = false;\n terms.forEach(function(term) {\n var regex = new RegExp('(' + term.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\') + ')', 'gi');\n if (regex.test(text)) {\n found = true;\n var frag = document.createDocumentFragment();\n var parts = text.split(regex);\n parts.forEach(function(part, i) {\n if (i % 2 === 0) {\n frag.appendChild(document.createTextNode(part));\n } else {\n var span = document.createElement('span');\n span.className = 'userscript-highlight';\n span.textContent = part;\n frag.appendChild(span);\n }\n });\n node.parentNode.replaceChild(frag, node);\n }\n });\n } else if (node.nodeType === 1 && node.childNodes) { // element\n var skipTags = ['SCRIPT', 'STYLE', 'NOSCRIPT', 'TEXTAREA', 'INPUT', 'SELECT'];\n if (!skipTags.includes(node.tagName)) {\n Array.from(node.childNodes).forEach(highlight);\n }\n }\n }\n \n highlight(document.body);\n \n // Re-highlight on dynamic content\n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1 || node.nodeType === 3) highlight(node);\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Highlight Search Terms"); } } catch(__e) { console.warn('[Userscript:Highlight Search Terms]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Add filesystem browse API and command palette project picker - #2024

Merged
juliusmarminge merged 9 commits into
pingdotgg:mainfrom
Noojuno:t3code/014c948a
Apr 15, 2026
Merged

Add filesystem browse API and command palette project picker#2024
juliusmarminge merged 9 commits into
pingdotgg:mainfrom
Noojuno:t3code/014c948a

Conversation

@Noojuno

@NoojunoNoojuno commented Apr 15, 2026

Copy link
Copy Markdown
Contributor

Summary

  • Add filesystem.browse RPC endpoint with directory listing, cross-platform path resolution (Windows drive/UNC, Unix, ~/ expansion), and relative path support against the active project
  • Wire filesystem browse through contracts (FilesystemBrowseInput/Result/Error), shared path helpers (@t3tools/shared/path), the RPC group, server handler, WsRpcClient, and EnvironmentApi
  • Add "Add project" action to the command palette with an interactive filesystem browser: type a path to browse directories, navigate with keyboard/click, press Enter or click "Add" to create the project
  • Add projectPaths utility library for browse navigation (path segment append/parent, trailing separator detection, project deduplication, relative path resolution, title inference)
  • Fix pre-existing Effect v3→v4 type errors in the server filesystem handler (Effect.catchAllEffect.mapError, explicit type annotations)

Testing

  • bun run typecheck — all 8 packages pass (0 errors)
  • bun run test — contracts (65 tests), shared (75 tests including new path helpers), web (projectPaths 11 tests, wsRpcClient 1 test) all pass
  • Manual: command palette "Add project" action opens browse mode, directory listing populates, keyboard navigation and Enter-to-add work

Checklist

  • This PR is small and focused
  • I explained what changed and why
  • I included before/after screenshots for any UI changes
  • I included a video for animation/interaction changes

Note

Add filesystem browse API and command palette project picker

  • Adds a filesystem.browse WebSocket RPC that returns subdirectories under a given path, supporting prefix filtering, ~ expansion, relative paths with a cwd, and cross-platform path validation (WorkspaceEntries.ts, ws.ts).
  • Replaces the inline sidebar 'Add project' UI with a command palette flow: clicking the sidebar trigger opens the command palette in browse mode, where users can navigate directories with keyboard or click and submit a path to create a project via project.create.
  • Adds a comprehensive path utility library (projectPaths.ts) covering Windows drive/UNC/Unix path normalization, relative path resolution, browse query detection, and parent path traversal.
  • Extends ProjectCreateCommand with an optional createWorkspaceRootIfMissing flag; when set, normalizeWorkspaceRoot creates the directory before project creation.
  • Adds an 'Add project starts in' field to the General settings panel, letting users configure the default browse directory.
  • Risk: The normalizeWorkspaceRoot call in dispatch normalization now creates directories on disk when createWorkspaceRootIfMissing is true, which is a new side effect in the orchestration normalization path.

Macroscope summarized 4d4786d.


Note

Medium Risk
Adds a new filesystem.browse RPC path and changes project.create/normalizeWorkspaceRoot to optionally create missing workspace directories, which can affect filesystem behavior and error handling across environments.

Overview
Adds a new filesystem browsing capability via filesystem.browse in contracts/RPC/client/server, returning matching subdirectories for a partial path with ~ expansion, platform-aware Windows path guards, and optional relative-path resolution against a provided cwd.

Updates project creation path handling by extending project.create with createWorkspaceRootIfMissing and teaching WorkspacePaths.normalizeWorkspaceRoot (and orchestration normalization) to create missing workspace root directories when requested, including new error types and coverage in server tests.

Reworks “Add project” UX in the web app to run through the command palette: adds a browse mode with directory navigation, environment selection, prefetching, and an optional native folder picker (desktop bridge now accepts pickFolder({ initialPath })), plus a new addProjectBaseDirectory setting and broad UI/test updates (including removing the sidebar inline add-project form).

Reviewed by Cursor Bugbot for commit 4d4786d. Bugbot is set up for automated code reviews on this repo. Configure here.

- Implement directory browsing UI for selecting project paths
- Add filesystemBrowse RPC method for reading directories
- Include cross-platform path handling and validation
- Add project path utilities with comprehensive tests
@coderabbitai

coderabbitaiBot commented Apr 15, 2026

Copy link
Copy Markdown

Important

Review skipped

Auto reviews are disabled on this repository. Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: a246714d-6e2e-4c60-81bc-4cb6bdd3c542

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@github-actionsgithub-actionsBot added size:XL 500-999 changed lines (additions + deletions). vouch:trusted PR author is trusted by repo permissions or the VOUCHED list. labels Apr 15, 2026
@NoojunoNoojuno changed the title Add filesystem browser to command paletteAdd filesystem browse API and command palette project pickerApr 15, 2026
Comment threadapps/web/src/lib/projectPaths.ts
- Treat backslashes as literal characters in Unix absolute paths
- Add getAbsolutePathKind() to detect path style (Unix vs Windows)
- Update separator detection functions to respect absolute path kind
- Add test cases for mixed separator scenarios
Test that filesystem.browse requests are forwarded to the RPC client with correct parameters
@Noojuno
Noojuno marked this pull request as ready for review April 15, 2026 00:51
// the exact browse entry's fullPath or fall back to the raw query.
const resolvedAddProjectPath = hasTrailingPathSeparator(query)
? (browseResult?.parentPath ?? query.trim())
: (exactBrowseEntry?.fullPath ?? query.trim());

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Tilde paths bypass project deduplication check

Medium Severity

When browseResult hasn't loaded yet (or there's no exactBrowseEntry), resolvedAddProjectPath falls back to the raw query.trim() — a tilde-prefixed string like "~/projects/myapp". This unresolved path is passed to handleAddProject, where findProjectByPath compares it (via normalizeProjectPathForComparison) against existing projects whose cwd values are server-expanded absolute paths like "/home/user/projects/myapp". Since the tilde is never expanded client-side, the comparison always fails, and a duplicate project is created for the same directory.

Additional Locations (1)
Fix in CursorFix in Web

Reviewed by Cursor Bugbot for commit 9448e45. Configure here.

@macroscopeapp

macroscopeappBot commented Apr 15, 2026

Copy link
Copy Markdown
Contributor

Approvability

Verdict: Needs human review

This PR introduces a significant new feature (filesystem browse API and command palette project picker) with new RPC endpoints, UI flows, and server-side workspace creation capabilities. Additionally, there are multiple unresolved review comments identifying medium-severity bugs related to path handling and deduplication logic that could cause incorrect behavior.

You can customize Macroscope's approvability policy. Learn more.

- Move browse resolution and filtering into WorkspaceEntries
- Wire websocket filesystemBrowse to the shared service
- Add coverage for hidden, relative, and error cases
Co-authored-by: codex <codex@users.noreply.github.com>
(entry) =>
entry.name.toLowerCase().startsWith(lowerFilter) &&
(showHidden || !entry.name.startsWith(".")),
);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Client-side filter hides dot directories in directory listing mode

Medium Severity

filterBrowseEntries sets showHidden based solely on whether browseFilterQuery starts with ".". When the user navigates into a directory (trailing separator), browseFilterQuery is "", so showHidden is false and all dot-prefixed entries are filtered out. The server intentionally includes hidden directories in directory-listing mode (tested in WorkspaceEntries.test.ts — "shows dot directories in directory mode"), but the client discards them. Users can never see directories like .config or .vscode when browsing into a folder.

Fix in CursorFix in Web

Reviewed by Cursor Bugbot for commit 0ddcb1a. Configure here.

- Allow Enter or Mod+Enter to add browsed projects based on selection state
- Show the active add shortcut in the palette UI and keep highlighted rows in sync
const exactEntry =
input.browseFilterQuery.length > 0
? (filteredEntries.find((entry) => entry.name === input.browseFilterQuery) ?? null)
: null;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Case-sensitive exact match mismatches case-insensitive filter

Medium Severity

filterBrowseEntries uses case-insensitive prefix matching for filteredEntries but case-sensitive equality for exactEntry. When a user types a directory name with different casing (e.g., "development" vs "Development"), the entry appears in results but exactEntry is null. This causes resolvedAddProjectPath to fall back to the raw query.trim() (preserving the unexpanded tilde and wrong casing) instead of using the server-resolved fullPath from the browse entry. The project may be created with an incorrect, unexpanded path like ~/development instead of /Users/user/Development.

Additional Locations (1)
Fix in CursorFix in Web

Reviewed by Cursor Bugbot for commit 5dc6d92. Configure here.

Comment threadapps/server/src/workspace/Layers/WorkspaceEntries.ts
- Let add-project browse create missing workspace roots
- Allow choosing the environment before browsing
- Pass folder picker initial path from the UI
- Co-authored-by: codex <codex@users.noreply.github.com>
@github-actionsgithub-actionsBot added size:XXL 1,000+ changed lines (additions + deletions). and removed size:XL 500-999 changed lines (additions + deletions). labels Apr 15, 2026
Comment threadapps/web/src/components/CommandPaletteResults.tsx
juliusmarmingeand others added 3 commits April 14, 2026 22:58
- Persist `addProjectBaseDirectory` in server settings
- Start Add Project browsing from the configured path
Co-authored-by: codex <codex@users.noreply.github.com>
- Avoid offering Create & Add while directory browse results are pending
- Preserve existing directory detection when the query ends with `/`
- Add a regression test for existing directories with trailing slashes
@juliusmarminge
juliusmarminge merged commit 44afe78 into pingdotgg:mainApr 15, 2026
12 checks passed

@cursorcursorBot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursor Bugbot has reviewed your changes and found 1 potential issue.

There are 4 total unresolved issues (including 3 from previous reviews).

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit 4d4786d. Configure here.

items: addProjectEnvironmentItems,
},
],
[addProjectEnvironmentItems],

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Unmemoized array defeats downstream memoization chain

Low Severity

addProjectEnvironmentItems is created as a plain array every render (via .map()) without useMemo, then used as the sole dependency of the addProjectEnvironmentGroupsuseMemo. Since the array reference changes every render, the memo always recomputes, cascading instability to openAddProjectFlow (a useCallback depending on addProjectEnvironmentGroups) and the openIntentuseEffect. Wrapping addProjectEnvironmentItems in useMemo with [addProjectEnvironmentOptions, startAddProjectBrowse] would stabilize the entire chain.

Fix in CursorFix in Web

Reviewed by Cursor Bugbot for commit 4d4786d. Configure here.

aaditagrawal added a commit to aaditagrawal/t3code that referenced this pull request Apr 16, 2026
Integrates upstream/main (d22c6f5) into the fork while preserving all
multi-provider support (codex, claudeAgent, copilot, cursor, opencode,
geminiCli, amp, kilo) and fork UI/UX additions.
Highlights adopted from upstream:
- Nightly release channel + update channel selector (pingdotgg#2012, pingdotgg#2049, pingdotgg#1969)
- Filesystem browse API + command palette project picker (pingdotgg#2024)
- Launch Args setting for Claude provider (pingdotgg#1971)
- Kiro editor support in open picker (pingdotgg#1974)
- Claude plan events for TodoWrite during input streaming (pingdotgg#1541)
- Lost provider session recovery (pingdotgg#1938)
- Cache provider status and gate desktop startup (pingdotgg#1962)
- LegendList migration for chat scrolling and branch lists (pingdotgg#1953)
- Shell snapshot queries + backfill migration (pingdotgg#1973, pingdotgg#2004)
- PATH hydration + fallback detection (pingdotgg#1799)
- Warm sidebar thread subscriptions (pingdotgg#2001)
- Full thread title tooltip (pingdotgg#1994)
- Markdown file link UX (pingdotgg#1956), composer polish (pingdotgg#1944, pingdotgg#1992, pingdotgg#1985)
- Worktree/branch state + draft reuse fixes (pingdotgg#2005, pingdotgg#2003, pingdotgg#1995, pingdotgg#1936)
- Window controls overlay for Windows/Linux (pingdotgg#1969)
- Backend readiness timeout 10s→30s (pingdotgg#1979)
- Clear tracked RPCs on reconnect, live stream subscriptions (pingdotgg#2000, pingdotgg#1972)
- Various misc fixes (pingdotgg#2051, pingdotgg#2052, pingdotgg#2025, pingdotgg#2027, pingdotgg#2049, pingdotgg#1997, pingdotgg#1975)
Fork features preserved and reconciled:
- All 8 provider adapters + conformance tests
- Extended ProviderKind union across contracts/model/settings/provider
- appearance/accentColor/themeConfig/ProviderLogo UI system
- customModels + gitTextGeneration + providerModelOptions
- Migration IDs 23 (NormalizeLegacyProviderKinds) and 24
(RepairProjectionThreadProposedPlanImplementationColumns) kept; new
upstream migrations registered at IDs 25-26 to avoid breaking deployed
fork databases
- DesktopBridge: log directory channels (LOG_DIR/LIST/READ/OPEN_DIR)
retained; getWsUrl replaced by upstream's getAppBranding
- PROVIDER_CACHE_IDS extended to all 8 providers
aaditagrawal added a commit to aaditagrawal/t3code that referenced this pull request Apr 19, 2026
## Font rendering
Pre-sync, the fork had only `pre, code, textarea, input` selectors
using Geist Mono when code/terminal context demanded it, but the recent
sync collapsed all four into a single rule that applied the monospace
stack to *every* <input> in the app. The command palette search, model
picker trait inputs, settings binary/server URL fields, etc. all rendered
in Geist Mono, which is what produced the 'broken font' look.
Narrow the rule back to `pre, code` (and `textarea` in code-focused
contexts inherits naturally). Regular inputs now use the body font
(DM Sans).
## Cmd+K shortcut
The commandPalette.toggle keydown handler in CommandPalette.tsx used
the bubble phase, which means xterm (when terminal has focus) or a
contenteditable composer could swallow Cmd+K before it reached the
window listener. Switch the listener to capture phase — matches
upstream's CTRL+J fix for terminal.toggle (pingdotgg#2113). The project picker
already lives inside the command palette (filesystem browse API +
command-palette project picker from pingdotgg#2024); this restores access to it
via the shortcut.
youpele52 referenced this pull request in youpele52/bigbud Jun 17, 2026
Co-authored-by: Julius Marminge <julius0216@outlook.com>
Co-authored-by: codex <codex@users.noreply.github.com>
NeilTheFisher pushed a commit to NeilTheFisher/t3code that referenced this pull request Aug 18, 2026
…gg#2024)
Co-authored-by: Julius Marminge <julius0216@outlook.com>
Co-authored-by: codex <codex@users.noreply.github.com>
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size:XXL1,000+ changed lines (additions + deletions).vouch:trustedPR author is trusted by repo permissions or the VOUCHED list.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants

@Noojuno@juliusmarminge
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Strip utm_, fbclid, gclid, etc. from all links on page\n(function() {\n var trackingParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content',\n 'fbclid', 'gclid', 'dclid', 'msclkid', 'yclid',\n 'ref', 'ref_src', 'source', 'medium', 'campaign'];\n \n function cleanUrl(url) {\n try {\n var u = new URL(url, window.location.origin);\n var changed = false;\n trackingParams.forEach(function(p) {\n if (u.searchParams.has(p)) {\n u.searchParams.delete(p);\n changed = true;\n }\n });\n return changed ? u.toString() : url;\n } catch (e) {\n return url;\n }\n }\n \n function cleanLinks() {\n document.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n \n cleanLinks();\n \n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1) {\n if (node.tagName === 'A') cleanLinks();\n node.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Remove Tracking Parameters from Links"); } } catch(__e) { console.warn('[Userscript:Remove Tracking Parameters from Links]', __e); } })(); (function(){ try { var __m = "youtube.com"; var __re = new RegExp('^' + "youtube\\.com" + '
Skip to content

Add filesystem browse API and command palette project picker - #2024

Merged
juliusmarminge merged 9 commits into
pingdotgg:mainfrom
Noojuno:t3code/014c948a
Apr 15, 2026
Merged

Add filesystem browse API and command palette project picker#2024
juliusmarminge merged 9 commits into
pingdotgg:mainfrom
Noojuno:t3code/014c948a

Conversation

@Noojuno

@NoojunoNoojuno commented Apr 15, 2026

Copy link
Copy Markdown
Contributor

Summary

  • Add filesystem.browse RPC endpoint with directory listing, cross-platform path resolution (Windows drive/UNC, Unix, ~/ expansion), and relative path support against the active project
  • Wire filesystem browse through contracts (FilesystemBrowseInput/Result/Error), shared path helpers (@t3tools/shared/path), the RPC group, server handler, WsRpcClient, and EnvironmentApi
  • Add "Add project" action to the command palette with an interactive filesystem browser: type a path to browse directories, navigate with keyboard/click, press Enter or click "Add" to create the project
  • Add projectPaths utility library for browse navigation (path segment append/parent, trailing separator detection, project deduplication, relative path resolution, title inference)
  • Fix pre-existing Effect v3→v4 type errors in the server filesystem handler (Effect.catchAllEffect.mapError, explicit type annotations)

Testing

  • bun run typecheck — all 8 packages pass (0 errors)
  • bun run test — contracts (65 tests), shared (75 tests including new path helpers), web (projectPaths 11 tests, wsRpcClient 1 test) all pass
  • Manual: command palette "Add project" action opens browse mode, directory listing populates, keyboard navigation and Enter-to-add work

Checklist

  • This PR is small and focused
  • I explained what changed and why
  • I included before/after screenshots for any UI changes
  • I included a video for animation/interaction changes

Note

Add filesystem browse API and command palette project picker

  • Adds a filesystem.browse WebSocket RPC that returns subdirectories under a given path, supporting prefix filtering, ~ expansion, relative paths with a cwd, and cross-platform path validation (WorkspaceEntries.ts, ws.ts).
  • Replaces the inline sidebar 'Add project' UI with a command palette flow: clicking the sidebar trigger opens the command palette in browse mode, where users can navigate directories with keyboard or click and submit a path to create a project via project.create.
  • Adds a comprehensive path utility library (projectPaths.ts) covering Windows drive/UNC/Unix path normalization, relative path resolution, browse query detection, and parent path traversal.
  • Extends ProjectCreateCommand with an optional createWorkspaceRootIfMissing flag; when set, normalizeWorkspaceRoot creates the directory before project creation.
  • Adds an 'Add project starts in' field to the General settings panel, letting users configure the default browse directory.
  • Risk: The normalizeWorkspaceRoot call in dispatch normalization now creates directories on disk when createWorkspaceRootIfMissing is true, which is a new side effect in the orchestration normalization path.

Macroscope summarized 4d4786d.


Note

Medium Risk
Adds a new filesystem.browse RPC path and changes project.create/normalizeWorkspaceRoot to optionally create missing workspace directories, which can affect filesystem behavior and error handling across environments.

Overview
Adds a new filesystem browsing capability via filesystem.browse in contracts/RPC/client/server, returning matching subdirectories for a partial path with ~ expansion, platform-aware Windows path guards, and optional relative-path resolution against a provided cwd.

Updates project creation path handling by extending project.create with createWorkspaceRootIfMissing and teaching WorkspacePaths.normalizeWorkspaceRoot (and orchestration normalization) to create missing workspace root directories when requested, including new error types and coverage in server tests.

Reworks “Add project” UX in the web app to run through the command palette: adds a browse mode with directory navigation, environment selection, prefetching, and an optional native folder picker (desktop bridge now accepts pickFolder({ initialPath })), plus a new addProjectBaseDirectory setting and broad UI/test updates (including removing the sidebar inline add-project form).

Reviewed by Cursor Bugbot for commit 4d4786d. Bugbot is set up for automated code reviews on this repo. Configure here.

- Implement directory browsing UI for selecting project paths
- Add filesystemBrowse RPC method for reading directories
- Include cross-platform path handling and validation
- Add project path utilities with comprehensive tests
@coderabbitai

coderabbitaiBot commented Apr 15, 2026

Copy link
Copy Markdown

Important

Review skipped

Auto reviews are disabled on this repository. Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: a246714d-6e2e-4c60-81bc-4cb6bdd3c542

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@github-actionsgithub-actionsBot added size:XL 500-999 changed lines (additions + deletions). vouch:trusted PR author is trusted by repo permissions or the VOUCHED list. labels Apr 15, 2026
@NoojunoNoojuno changed the title Add filesystem browser to command paletteAdd filesystem browse API and command palette project pickerApr 15, 2026
Comment threadapps/web/src/lib/projectPaths.ts
- Treat backslashes as literal characters in Unix absolute paths
- Add getAbsolutePathKind() to detect path style (Unix vs Windows)
- Update separator detection functions to respect absolute path kind
- Add test cases for mixed separator scenarios
Test that filesystem.browse requests are forwarded to the RPC client with correct parameters
@Noojuno
Noojuno marked this pull request as ready for review April 15, 2026 00:51
// the exact browse entry's fullPath or fall back to the raw query.
const resolvedAddProjectPath = hasTrailingPathSeparator(query)
? (browseResult?.parentPath ?? query.trim())
: (exactBrowseEntry?.fullPath ?? query.trim());

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Tilde paths bypass project deduplication check

Medium Severity

When browseResult hasn't loaded yet (or there's no exactBrowseEntry), resolvedAddProjectPath falls back to the raw query.trim() — a tilde-prefixed string like "~/projects/myapp". This unresolved path is passed to handleAddProject, where findProjectByPath compares it (via normalizeProjectPathForComparison) against existing projects whose cwd values are server-expanded absolute paths like "/home/user/projects/myapp". Since the tilde is never expanded client-side, the comparison always fails, and a duplicate project is created for the same directory.

Additional Locations (1)
Fix in CursorFix in Web

Reviewed by Cursor Bugbot for commit 9448e45. Configure here.

@macroscopeapp

macroscopeappBot commented Apr 15, 2026

Copy link
Copy Markdown
Contributor

Approvability

Verdict: Needs human review

This PR introduces a significant new feature (filesystem browse API and command palette project picker) with new RPC endpoints, UI flows, and server-side workspace creation capabilities. Additionally, there are multiple unresolved review comments identifying medium-severity bugs related to path handling and deduplication logic that could cause incorrect behavior.

You can customize Macroscope's approvability policy. Learn more.

- Move browse resolution and filtering into WorkspaceEntries
- Wire websocket filesystemBrowse to the shared service
- Add coverage for hidden, relative, and error cases
Co-authored-by: codex <codex@users.noreply.github.com>
(entry) =>
entry.name.toLowerCase().startsWith(lowerFilter) &&
(showHidden || !entry.name.startsWith(".")),
);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Client-side filter hides dot directories in directory listing mode

Medium Severity

filterBrowseEntries sets showHidden based solely on whether browseFilterQuery starts with ".". When the user navigates into a directory (trailing separator), browseFilterQuery is "", so showHidden is false and all dot-prefixed entries are filtered out. The server intentionally includes hidden directories in directory-listing mode (tested in WorkspaceEntries.test.ts — "shows dot directories in directory mode"), but the client discards them. Users can never see directories like .config or .vscode when browsing into a folder.

Fix in CursorFix in Web

Reviewed by Cursor Bugbot for commit 0ddcb1a. Configure here.

- Allow Enter or Mod+Enter to add browsed projects based on selection state
- Show the active add shortcut in the palette UI and keep highlighted rows in sync
const exactEntry =
input.browseFilterQuery.length > 0
? (filteredEntries.find((entry) => entry.name === input.browseFilterQuery) ?? null)
: null;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Case-sensitive exact match mismatches case-insensitive filter

Medium Severity

filterBrowseEntries uses case-insensitive prefix matching for filteredEntries but case-sensitive equality for exactEntry. When a user types a directory name with different casing (e.g., "development" vs "Development"), the entry appears in results but exactEntry is null. This causes resolvedAddProjectPath to fall back to the raw query.trim() (preserving the unexpanded tilde and wrong casing) instead of using the server-resolved fullPath from the browse entry. The project may be created with an incorrect, unexpanded path like ~/development instead of /Users/user/Development.

Additional Locations (1)
Fix in CursorFix in Web

Reviewed by Cursor Bugbot for commit 5dc6d92. Configure here.

Comment threadapps/server/src/workspace/Layers/WorkspaceEntries.ts
- Let add-project browse create missing workspace roots
- Allow choosing the environment before browsing
- Pass folder picker initial path from the UI
- Co-authored-by: codex <codex@users.noreply.github.com>
@github-actionsgithub-actionsBot added size:XXL 1,000+ changed lines (additions + deletions). and removed size:XL 500-999 changed lines (additions + deletions). labels Apr 15, 2026
Comment threadapps/web/src/components/CommandPaletteResults.tsx
juliusmarmingeand others added 3 commits April 14, 2026 22:58
- Persist `addProjectBaseDirectory` in server settings
- Start Add Project browsing from the configured path
Co-authored-by: codex <codex@users.noreply.github.com>
- Avoid offering Create & Add while directory browse results are pending
- Preserve existing directory detection when the query ends with `/`
- Add a regression test for existing directories with trailing slashes
@juliusmarminge
juliusmarminge merged commit 44afe78 into pingdotgg:mainApr 15, 2026
12 checks passed

@cursorcursorBot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursor Bugbot has reviewed your changes and found 1 potential issue.

There are 4 total unresolved issues (including 3 from previous reviews).

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit 4d4786d. Configure here.

items: addProjectEnvironmentItems,
},
],
[addProjectEnvironmentItems],

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Unmemoized array defeats downstream memoization chain

Low Severity

addProjectEnvironmentItems is created as a plain array every render (via .map()) without useMemo, then used as the sole dependency of the addProjectEnvironmentGroupsuseMemo. Since the array reference changes every render, the memo always recomputes, cascading instability to openAddProjectFlow (a useCallback depending on addProjectEnvironmentGroups) and the openIntentuseEffect. Wrapping addProjectEnvironmentItems in useMemo with [addProjectEnvironmentOptions, startAddProjectBrowse] would stabilize the entire chain.

Fix in CursorFix in Web

Reviewed by Cursor Bugbot for commit 4d4786d. Configure here.

aaditagrawal added a commit to aaditagrawal/t3code that referenced this pull request Apr 16, 2026
Integrates upstream/main (d22c6f5) into the fork while preserving all
multi-provider support (codex, claudeAgent, copilot, cursor, opencode,
geminiCli, amp, kilo) and fork UI/UX additions.
Highlights adopted from upstream:
- Nightly release channel + update channel selector (pingdotgg#2012, pingdotgg#2049, pingdotgg#1969)
- Filesystem browse API + command palette project picker (pingdotgg#2024)
- Launch Args setting for Claude provider (pingdotgg#1971)
- Kiro editor support in open picker (pingdotgg#1974)
- Claude plan events for TodoWrite during input streaming (pingdotgg#1541)
- Lost provider session recovery (pingdotgg#1938)
- Cache provider status and gate desktop startup (pingdotgg#1962)
- LegendList migration for chat scrolling and branch lists (pingdotgg#1953)
- Shell snapshot queries + backfill migration (pingdotgg#1973, pingdotgg#2004)
- PATH hydration + fallback detection (pingdotgg#1799)
- Warm sidebar thread subscriptions (pingdotgg#2001)
- Full thread title tooltip (pingdotgg#1994)
- Markdown file link UX (pingdotgg#1956), composer polish (pingdotgg#1944, pingdotgg#1992, pingdotgg#1985)
- Worktree/branch state + draft reuse fixes (pingdotgg#2005, pingdotgg#2003, pingdotgg#1995, pingdotgg#1936)
- Window controls overlay for Windows/Linux (pingdotgg#1969)
- Backend readiness timeout 10s→30s (pingdotgg#1979)
- Clear tracked RPCs on reconnect, live stream subscriptions (pingdotgg#2000, pingdotgg#1972)
- Various misc fixes (pingdotgg#2051, pingdotgg#2052, pingdotgg#2025, pingdotgg#2027, pingdotgg#2049, pingdotgg#1997, pingdotgg#1975)
Fork features preserved and reconciled:
- All 8 provider adapters + conformance tests
- Extended ProviderKind union across contracts/model/settings/provider
- appearance/accentColor/themeConfig/ProviderLogo UI system
- customModels + gitTextGeneration + providerModelOptions
- Migration IDs 23 (NormalizeLegacyProviderKinds) and 24
(RepairProjectionThreadProposedPlanImplementationColumns) kept; new
upstream migrations registered at IDs 25-26 to avoid breaking deployed
fork databases
- DesktopBridge: log directory channels (LOG_DIR/LIST/READ/OPEN_DIR)
retained; getWsUrl replaced by upstream's getAppBranding
- PROVIDER_CACHE_IDS extended to all 8 providers
aaditagrawal added a commit to aaditagrawal/t3code that referenced this pull request Apr 19, 2026
## Font rendering
Pre-sync, the fork had only `pre, code, textarea, input` selectors
using Geist Mono when code/terminal context demanded it, but the recent
sync collapsed all four into a single rule that applied the monospace
stack to *every* <input> in the app. The command palette search, model
picker trait inputs, settings binary/server URL fields, etc. all rendered
in Geist Mono, which is what produced the 'broken font' look.
Narrow the rule back to `pre, code` (and `textarea` in code-focused
contexts inherits naturally). Regular inputs now use the body font
(DM Sans).
## Cmd+K shortcut
The commandPalette.toggle keydown handler in CommandPalette.tsx used
the bubble phase, which means xterm (when terminal has focus) or a
contenteditable composer could swallow Cmd+K before it reached the
window listener. Switch the listener to capture phase — matches
upstream's CTRL+J fix for terminal.toggle (pingdotgg#2113). The project picker
already lives inside the command palette (filesystem browse API +
command-palette project picker from pingdotgg#2024); this restores access to it
via the shortcut.
youpele52 referenced this pull request in youpele52/bigbud Jun 17, 2026
Co-authored-by: Julius Marminge <julius0216@outlook.com>
Co-authored-by: codex <codex@users.noreply.github.com>
NeilTheFisher pushed a commit to NeilTheFisher/t3code that referenced this pull request Aug 18, 2026
…gg#2024)
Co-authored-by: Julius Marminge <julius0216@outlook.com>
Co-authored-by: codex <codex@users.noreply.github.com>
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size:XXL1,000+ changed lines (additions + deletions).vouch:trustedPR author is trusted by repo permissions or the VOUCHED list.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants

@Noojuno@juliusmarminge
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Auto-enable theater mode on YouTube\n(function() {\n function tryTheater() {\n var btn = document.querySelector('button[aria-label=\"Theater mode\"], ytd-player #player button[title=\"Theater mode\"]');\n if (btn && !btn.classList.contains('activated')) {\n btn.click();\n }\n }\n \n // Try immediately\n tryTheater();\n \n // Try after navigation (SPA)\n var lastUrl = location.href;\n setInterval(function() {\n if (location.href !== lastUrl) {\n lastUrl = location.href;\n setTimeout(tryTheater, 500);\n }\n }, 1000);\n \n // Also try on player load\n var observer = new MutationObserver(tryTheater);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "YouTube Theater Mode Default"); } } catch(__e) { console.warn('[Userscript:YouTube Theater Mode Default]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Add filesystem browse API and command palette project picker - #2024

Merged
juliusmarminge merged 9 commits into
pingdotgg:mainfrom
Noojuno:t3code/014c948a
Apr 15, 2026
Merged

Add filesystem browse API and command palette project picker#2024
juliusmarminge merged 9 commits into
pingdotgg:mainfrom
Noojuno:t3code/014c948a

Conversation

@Noojuno

@NoojunoNoojuno commented Apr 15, 2026

Copy link
Copy Markdown
Contributor

Summary

  • Add filesystem.browse RPC endpoint with directory listing, cross-platform path resolution (Windows drive/UNC, Unix, ~/ expansion), and relative path support against the active project
  • Wire filesystem browse through contracts (FilesystemBrowseInput/Result/Error), shared path helpers (@t3tools/shared/path), the RPC group, server handler, WsRpcClient, and EnvironmentApi
  • Add "Add project" action to the command palette with an interactive filesystem browser: type a path to browse directories, navigate with keyboard/click, press Enter or click "Add" to create the project
  • Add projectPaths utility library for browse navigation (path segment append/parent, trailing separator detection, project deduplication, relative path resolution, title inference)
  • Fix pre-existing Effect v3→v4 type errors in the server filesystem handler (Effect.catchAllEffect.mapError, explicit type annotations)

Testing

  • bun run typecheck — all 8 packages pass (0 errors)
  • bun run test — contracts (65 tests), shared (75 tests including new path helpers), web (projectPaths 11 tests, wsRpcClient 1 test) all pass
  • Manual: command palette "Add project" action opens browse mode, directory listing populates, keyboard navigation and Enter-to-add work

Checklist

  • This PR is small and focused
  • I explained what changed and why
  • I included before/after screenshots for any UI changes
  • I included a video for animation/interaction changes

Note

Add filesystem browse API and command palette project picker

  • Adds a filesystem.browse WebSocket RPC that returns subdirectories under a given path, supporting prefix filtering, ~ expansion, relative paths with a cwd, and cross-platform path validation (WorkspaceEntries.ts, ws.ts).
  • Replaces the inline sidebar 'Add project' UI with a command palette flow: clicking the sidebar trigger opens the command palette in browse mode, where users can navigate directories with keyboard or click and submit a path to create a project via project.create.
  • Adds a comprehensive path utility library (projectPaths.ts) covering Windows drive/UNC/Unix path normalization, relative path resolution, browse query detection, and parent path traversal.
  • Extends ProjectCreateCommand with an optional createWorkspaceRootIfMissing flag; when set, normalizeWorkspaceRoot creates the directory before project creation.
  • Adds an 'Add project starts in' field to the General settings panel, letting users configure the default browse directory.
  • Risk: The normalizeWorkspaceRoot call in dispatch normalization now creates directories on disk when createWorkspaceRootIfMissing is true, which is a new side effect in the orchestration normalization path.

Macroscope summarized 4d4786d.


Note

Medium Risk
Adds a new filesystem.browse RPC path and changes project.create/normalizeWorkspaceRoot to optionally create missing workspace directories, which can affect filesystem behavior and error handling across environments.

Overview
Adds a new filesystem browsing capability via filesystem.browse in contracts/RPC/client/server, returning matching subdirectories for a partial path with ~ expansion, platform-aware Windows path guards, and optional relative-path resolution against a provided cwd.

Updates project creation path handling by extending project.create with createWorkspaceRootIfMissing and teaching WorkspacePaths.normalizeWorkspaceRoot (and orchestration normalization) to create missing workspace root directories when requested, including new error types and coverage in server tests.

Reworks “Add project” UX in the web app to run through the command palette: adds a browse mode with directory navigation, environment selection, prefetching, and an optional native folder picker (desktop bridge now accepts pickFolder({ initialPath })), plus a new addProjectBaseDirectory setting and broad UI/test updates (including removing the sidebar inline add-project form).

Reviewed by Cursor Bugbot for commit 4d4786d. Bugbot is set up for automated code reviews on this repo. Configure here.

- Implement directory browsing UI for selecting project paths
- Add filesystemBrowse RPC method for reading directories
- Include cross-platform path handling and validation
- Add project path utilities with comprehensive tests
@coderabbitai

coderabbitaiBot commented Apr 15, 2026

Copy link
Copy Markdown

Important

Review skipped

Auto reviews are disabled on this repository. Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: a246714d-6e2e-4c60-81bc-4cb6bdd3c542

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@github-actionsgithub-actionsBot added size:XL 500-999 changed lines (additions + deletions). vouch:trusted PR author is trusted by repo permissions or the VOUCHED list. labels Apr 15, 2026
@NoojunoNoojuno changed the title Add filesystem browser to command paletteAdd filesystem browse API and command palette project pickerApr 15, 2026
Comment threadapps/web/src/lib/projectPaths.ts
- Treat backslashes as literal characters in Unix absolute paths
- Add getAbsolutePathKind() to detect path style (Unix vs Windows)
- Update separator detection functions to respect absolute path kind
- Add test cases for mixed separator scenarios
Test that filesystem.browse requests are forwarded to the RPC client with correct parameters
@Noojuno
Noojuno marked this pull request as ready for review April 15, 2026 00:51
// the exact browse entry's fullPath or fall back to the raw query.
const resolvedAddProjectPath = hasTrailingPathSeparator(query)
? (browseResult?.parentPath ?? query.trim())
: (exactBrowseEntry?.fullPath ?? query.trim());

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Tilde paths bypass project deduplication check

Medium Severity

When browseResult hasn't loaded yet (or there's no exactBrowseEntry), resolvedAddProjectPath falls back to the raw query.trim() — a tilde-prefixed string like "~/projects/myapp". This unresolved path is passed to handleAddProject, where findProjectByPath compares it (via normalizeProjectPathForComparison) against existing projects whose cwd values are server-expanded absolute paths like "/home/user/projects/myapp". Since the tilde is never expanded client-side, the comparison always fails, and a duplicate project is created for the same directory.

Additional Locations (1)
Fix in CursorFix in Web

Reviewed by Cursor Bugbot for commit 9448e45. Configure here.

@macroscopeapp

macroscopeappBot commented Apr 15, 2026

Copy link
Copy Markdown
Contributor

Approvability

Verdict: Needs human review

This PR introduces a significant new feature (filesystem browse API and command palette project picker) with new RPC endpoints, UI flows, and server-side workspace creation capabilities. Additionally, there are multiple unresolved review comments identifying medium-severity bugs related to path handling and deduplication logic that could cause incorrect behavior.

You can customize Macroscope's approvability policy. Learn more.

- Move browse resolution and filtering into WorkspaceEntries
- Wire websocket filesystemBrowse to the shared service
- Add coverage for hidden, relative, and error cases
Co-authored-by: codex <codex@users.noreply.github.com>
(entry) =>
entry.name.toLowerCase().startsWith(lowerFilter) &&
(showHidden || !entry.name.startsWith(".")),
);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Client-side filter hides dot directories in directory listing mode

Medium Severity

filterBrowseEntries sets showHidden based solely on whether browseFilterQuery starts with ".". When the user navigates into a directory (trailing separator), browseFilterQuery is "", so showHidden is false and all dot-prefixed entries are filtered out. The server intentionally includes hidden directories in directory-listing mode (tested in WorkspaceEntries.test.ts — "shows dot directories in directory mode"), but the client discards them. Users can never see directories like .config or .vscode when browsing into a folder.

Fix in CursorFix in Web

Reviewed by Cursor Bugbot for commit 0ddcb1a. Configure here.

- Allow Enter or Mod+Enter to add browsed projects based on selection state
- Show the active add shortcut in the palette UI and keep highlighted rows in sync
const exactEntry =
input.browseFilterQuery.length > 0
? (filteredEntries.find((entry) => entry.name === input.browseFilterQuery) ?? null)
: null;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Case-sensitive exact match mismatches case-insensitive filter

Medium Severity

filterBrowseEntries uses case-insensitive prefix matching for filteredEntries but case-sensitive equality for exactEntry. When a user types a directory name with different casing (e.g., "development" vs "Development"), the entry appears in results but exactEntry is null. This causes resolvedAddProjectPath to fall back to the raw query.trim() (preserving the unexpanded tilde and wrong casing) instead of using the server-resolved fullPath from the browse entry. The project may be created with an incorrect, unexpanded path like ~/development instead of /Users/user/Development.

Additional Locations (1)
Fix in CursorFix in Web

Reviewed by Cursor Bugbot for commit 5dc6d92. Configure here.

Comment threadapps/server/src/workspace/Layers/WorkspaceEntries.ts
- Let add-project browse create missing workspace roots
- Allow choosing the environment before browsing
- Pass folder picker initial path from the UI
- Co-authored-by: codex <codex@users.noreply.github.com>
@github-actionsgithub-actionsBot added size:XXL 1,000+ changed lines (additions + deletions). and removed size:XL 500-999 changed lines (additions + deletions). labels Apr 15, 2026
Comment threadapps/web/src/components/CommandPaletteResults.tsx
juliusmarmingeand others added 3 commits April 14, 2026 22:58
- Persist `addProjectBaseDirectory` in server settings
- Start Add Project browsing from the configured path
Co-authored-by: codex <codex@users.noreply.github.com>
- Avoid offering Create & Add while directory browse results are pending
- Preserve existing directory detection when the query ends with `/`
- Add a regression test for existing directories with trailing slashes
@juliusmarminge
juliusmarminge merged commit 44afe78 into pingdotgg:mainApr 15, 2026
12 checks passed

@cursorcursorBot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursor Bugbot has reviewed your changes and found 1 potential issue.

There are 4 total unresolved issues (including 3 from previous reviews).

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit 4d4786d. Configure here.

items: addProjectEnvironmentItems,
},
],
[addProjectEnvironmentItems],

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Unmemoized array defeats downstream memoization chain

Low Severity

addProjectEnvironmentItems is created as a plain array every render (via .map()) without useMemo, then used as the sole dependency of the addProjectEnvironmentGroupsuseMemo. Since the array reference changes every render, the memo always recomputes, cascading instability to openAddProjectFlow (a useCallback depending on addProjectEnvironmentGroups) and the openIntentuseEffect. Wrapping addProjectEnvironmentItems in useMemo with [addProjectEnvironmentOptions, startAddProjectBrowse] would stabilize the entire chain.

Fix in CursorFix in Web

Reviewed by Cursor Bugbot for commit 4d4786d. Configure here.

aaditagrawal added a commit to aaditagrawal/t3code that referenced this pull request Apr 16, 2026
Integrates upstream/main (d22c6f5) into the fork while preserving all
multi-provider support (codex, claudeAgent, copilot, cursor, opencode,
geminiCli, amp, kilo) and fork UI/UX additions.
Highlights adopted from upstream:
- Nightly release channel + update channel selector (pingdotgg#2012, pingdotgg#2049, pingdotgg#1969)
- Filesystem browse API + command palette project picker (pingdotgg#2024)
- Launch Args setting for Claude provider (pingdotgg#1971)
- Kiro editor support in open picker (pingdotgg#1974)
- Claude plan events for TodoWrite during input streaming (pingdotgg#1541)
- Lost provider session recovery (pingdotgg#1938)
- Cache provider status and gate desktop startup (pingdotgg#1962)
- LegendList migration for chat scrolling and branch lists (pingdotgg#1953)
- Shell snapshot queries + backfill migration (pingdotgg#1973, pingdotgg#2004)
- PATH hydration + fallback detection (pingdotgg#1799)
- Warm sidebar thread subscriptions (pingdotgg#2001)
- Full thread title tooltip (pingdotgg#1994)
- Markdown file link UX (pingdotgg#1956), composer polish (pingdotgg#1944, pingdotgg#1992, pingdotgg#1985)
- Worktree/branch state + draft reuse fixes (pingdotgg#2005, pingdotgg#2003, pingdotgg#1995, pingdotgg#1936)
- Window controls overlay for Windows/Linux (pingdotgg#1969)
- Backend readiness timeout 10s→30s (pingdotgg#1979)
- Clear tracked RPCs on reconnect, live stream subscriptions (pingdotgg#2000, pingdotgg#1972)
- Various misc fixes (pingdotgg#2051, pingdotgg#2052, pingdotgg#2025, pingdotgg#2027, pingdotgg#2049, pingdotgg#1997, pingdotgg#1975)
Fork features preserved and reconciled:
- All 8 provider adapters + conformance tests
- Extended ProviderKind union across contracts/model/settings/provider
- appearance/accentColor/themeConfig/ProviderLogo UI system
- customModels + gitTextGeneration + providerModelOptions
- Migration IDs 23 (NormalizeLegacyProviderKinds) and 24
(RepairProjectionThreadProposedPlanImplementationColumns) kept; new
upstream migrations registered at IDs 25-26 to avoid breaking deployed
fork databases
- DesktopBridge: log directory channels (LOG_DIR/LIST/READ/OPEN_DIR)
retained; getWsUrl replaced by upstream's getAppBranding
- PROVIDER_CACHE_IDS extended to all 8 providers
aaditagrawal added a commit to aaditagrawal/t3code that referenced this pull request Apr 19, 2026
## Font rendering
Pre-sync, the fork had only `pre, code, textarea, input` selectors
using Geist Mono when code/terminal context demanded it, but the recent
sync collapsed all four into a single rule that applied the monospace
stack to *every* <input> in the app. The command palette search, model
picker trait inputs, settings binary/server URL fields, etc. all rendered
in Geist Mono, which is what produced the 'broken font' look.
Narrow the rule back to `pre, code` (and `textarea` in code-focused
contexts inherits naturally). Regular inputs now use the body font
(DM Sans).
## Cmd+K shortcut
The commandPalette.toggle keydown handler in CommandPalette.tsx used
the bubble phase, which means xterm (when terminal has focus) or a
contenteditable composer could swallow Cmd+K before it reached the
window listener. Switch the listener to capture phase — matches
upstream's CTRL+J fix for terminal.toggle (pingdotgg#2113). The project picker
already lives inside the command palette (filesystem browse API +
command-palette project picker from pingdotgg#2024); this restores access to it
via the shortcut.
youpele52 referenced this pull request in youpele52/bigbud Jun 17, 2026
Co-authored-by: Julius Marminge <julius0216@outlook.com>
Co-authored-by: codex <codex@users.noreply.github.com>
NeilTheFisher pushed a commit to NeilTheFisher/t3code that referenced this pull request Aug 18, 2026
…gg#2024)
Co-authored-by: Julius Marminge <julius0216@outlook.com>
Co-authored-by: codex <codex@users.noreply.github.com>
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size:XXL1,000+ changed lines (additions + deletions).vouch:trustedPR author is trusted by repo permissions or the VOUCHED list.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants

@Noojuno@juliusmarminge
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Remove or un-stick sticky/fixed headers that block content\n(function() {\n function unstick() {\n document.querySelectorAll('header, nav, [role=\"banner\"], .header, .navbar, .sticky, .fixed-top, [style*=\"position: fixed\"], [style*=\"position:sticky\"]').forEach(function(el) {\n if (el.style.position === 'fixed' || el.style.position === 'sticky' || \n getComputedStyle(el).position === 'fixed' || getComputedStyle(el).position === 'sticky') {\n el.style.position = 'static';\n el.style.top = 'auto';\n el.style.zIndex = 'auto';\n }\n });\n }\n \n unstick();\n \n var observer = new MutationObserver(unstick);\n observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] });\n})();", "Kill Sticky Headers"); } } catch(__e) { console.warn('[Userscript:Kill Sticky Headers]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Add filesystem browse API and command palette project picker - #2024

Merged
juliusmarminge merged 9 commits into
pingdotgg:mainfrom
Noojuno:t3code/014c948a
Apr 15, 2026
Merged

Add filesystem browse API and command palette project picker#2024
juliusmarminge merged 9 commits into
pingdotgg:mainfrom
Noojuno:t3code/014c948a

Conversation

@Noojuno

@NoojunoNoojuno commented Apr 15, 2026

Copy link
Copy Markdown
Contributor

Summary

  • Add filesystem.browse RPC endpoint with directory listing, cross-platform path resolution (Windows drive/UNC, Unix, ~/ expansion), and relative path support against the active project
  • Wire filesystem browse through contracts (FilesystemBrowseInput/Result/Error), shared path helpers (@t3tools/shared/path), the RPC group, server handler, WsRpcClient, and EnvironmentApi
  • Add "Add project" action to the command palette with an interactive filesystem browser: type a path to browse directories, navigate with keyboard/click, press Enter or click "Add" to create the project
  • Add projectPaths utility library for browse navigation (path segment append/parent, trailing separator detection, project deduplication, relative path resolution, title inference)
  • Fix pre-existing Effect v3→v4 type errors in the server filesystem handler (Effect.catchAllEffect.mapError, explicit type annotations)

Testing

  • bun run typecheck — all 8 packages pass (0 errors)
  • bun run test — contracts (65 tests), shared (75 tests including new path helpers), web (projectPaths 11 tests, wsRpcClient 1 test) all pass
  • Manual: command palette "Add project" action opens browse mode, directory listing populates, keyboard navigation and Enter-to-add work

Checklist

  • This PR is small and focused
  • I explained what changed and why
  • I included before/after screenshots for any UI changes
  • I included a video for animation/interaction changes

Note

Add filesystem browse API and command palette project picker

  • Adds a filesystem.browse WebSocket RPC that returns subdirectories under a given path, supporting prefix filtering, ~ expansion, relative paths with a cwd, and cross-platform path validation (WorkspaceEntries.ts, ws.ts).
  • Replaces the inline sidebar 'Add project' UI with a command palette flow: clicking the sidebar trigger opens the command palette in browse mode, where users can navigate directories with keyboard or click and submit a path to create a project via project.create.
  • Adds a comprehensive path utility library (projectPaths.ts) covering Windows drive/UNC/Unix path normalization, relative path resolution, browse query detection, and parent path traversal.
  • Extends ProjectCreateCommand with an optional createWorkspaceRootIfMissing flag; when set, normalizeWorkspaceRoot creates the directory before project creation.
  • Adds an 'Add project starts in' field to the General settings panel, letting users configure the default browse directory.
  • Risk: The normalizeWorkspaceRoot call in dispatch normalization now creates directories on disk when createWorkspaceRootIfMissing is true, which is a new side effect in the orchestration normalization path.

Macroscope summarized 4d4786d.


Note

Medium Risk
Adds a new filesystem.browse RPC path and changes project.create/normalizeWorkspaceRoot to optionally create missing workspace directories, which can affect filesystem behavior and error handling across environments.

Overview
Adds a new filesystem browsing capability via filesystem.browse in contracts/RPC/client/server, returning matching subdirectories for a partial path with ~ expansion, platform-aware Windows path guards, and optional relative-path resolution against a provided cwd.

Updates project creation path handling by extending project.create with createWorkspaceRootIfMissing and teaching WorkspacePaths.normalizeWorkspaceRoot (and orchestration normalization) to create missing workspace root directories when requested, including new error types and coverage in server tests.

Reworks “Add project” UX in the web app to run through the command palette: adds a browse mode with directory navigation, environment selection, prefetching, and an optional native folder picker (desktop bridge now accepts pickFolder({ initialPath })), plus a new addProjectBaseDirectory setting and broad UI/test updates (including removing the sidebar inline add-project form).

Reviewed by Cursor Bugbot for commit 4d4786d. Bugbot is set up for automated code reviews on this repo. Configure here.

- Implement directory browsing UI for selecting project paths
- Add filesystemBrowse RPC method for reading directories
- Include cross-platform path handling and validation
- Add project path utilities with comprehensive tests
@coderabbitai

coderabbitaiBot commented Apr 15, 2026

Copy link
Copy Markdown

Important

Review skipped

Auto reviews are disabled on this repository. Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: a246714d-6e2e-4c60-81bc-4cb6bdd3c542

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@github-actionsgithub-actionsBot added size:XL 500-999 changed lines (additions + deletions). vouch:trusted PR author is trusted by repo permissions or the VOUCHED list. labels Apr 15, 2026
@NoojunoNoojuno changed the title Add filesystem browser to command paletteAdd filesystem browse API and command palette project pickerApr 15, 2026
Comment threadapps/web/src/lib/projectPaths.ts
- Treat backslashes as literal characters in Unix absolute paths
- Add getAbsolutePathKind() to detect path style (Unix vs Windows)
- Update separator detection functions to respect absolute path kind
- Add test cases for mixed separator scenarios
Test that filesystem.browse requests are forwarded to the RPC client with correct parameters
@Noojuno
Noojuno marked this pull request as ready for review April 15, 2026 00:51
// the exact browse entry's fullPath or fall back to the raw query.
const resolvedAddProjectPath = hasTrailingPathSeparator(query)
? (browseResult?.parentPath ?? query.trim())
: (exactBrowseEntry?.fullPath ?? query.trim());

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Tilde paths bypass project deduplication check

Medium Severity

When browseResult hasn't loaded yet (or there's no exactBrowseEntry), resolvedAddProjectPath falls back to the raw query.trim() — a tilde-prefixed string like "~/projects/myapp". This unresolved path is passed to handleAddProject, where findProjectByPath compares it (via normalizeProjectPathForComparison) against existing projects whose cwd values are server-expanded absolute paths like "/home/user/projects/myapp". Since the tilde is never expanded client-side, the comparison always fails, and a duplicate project is created for the same directory.

Additional Locations (1)
Fix in CursorFix in Web

Reviewed by Cursor Bugbot for commit 9448e45. Configure here.

@macroscopeapp

macroscopeappBot commented Apr 15, 2026

Copy link
Copy Markdown
Contributor

Approvability

Verdict: Needs human review

This PR introduces a significant new feature (filesystem browse API and command palette project picker) with new RPC endpoints, UI flows, and server-side workspace creation capabilities. Additionally, there are multiple unresolved review comments identifying medium-severity bugs related to path handling and deduplication logic that could cause incorrect behavior.

You can customize Macroscope's approvability policy. Learn more.

- Move browse resolution and filtering into WorkspaceEntries
- Wire websocket filesystemBrowse to the shared service
- Add coverage for hidden, relative, and error cases
Co-authored-by: codex <codex@users.noreply.github.com>
(entry) =>
entry.name.toLowerCase().startsWith(lowerFilter) &&
(showHidden || !entry.name.startsWith(".")),
);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Client-side filter hides dot directories in directory listing mode

Medium Severity

filterBrowseEntries sets showHidden based solely on whether browseFilterQuery starts with ".". When the user navigates into a directory (trailing separator), browseFilterQuery is "", so showHidden is false and all dot-prefixed entries are filtered out. The server intentionally includes hidden directories in directory-listing mode (tested in WorkspaceEntries.test.ts — "shows dot directories in directory mode"), but the client discards them. Users can never see directories like .config or .vscode when browsing into a folder.

Fix in CursorFix in Web

Reviewed by Cursor Bugbot for commit 0ddcb1a. Configure here.

- Allow Enter or Mod+Enter to add browsed projects based on selection state
- Show the active add shortcut in the palette UI and keep highlighted rows in sync
const exactEntry =
input.browseFilterQuery.length > 0
? (filteredEntries.find((entry) => entry.name === input.browseFilterQuery) ?? null)
: null;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Case-sensitive exact match mismatches case-insensitive filter

Medium Severity

filterBrowseEntries uses case-insensitive prefix matching for filteredEntries but case-sensitive equality for exactEntry. When a user types a directory name with different casing (e.g., "development" vs "Development"), the entry appears in results but exactEntry is null. This causes resolvedAddProjectPath to fall back to the raw query.trim() (preserving the unexpanded tilde and wrong casing) instead of using the server-resolved fullPath from the browse entry. The project may be created with an incorrect, unexpanded path like ~/development instead of /Users/user/Development.

Additional Locations (1)
Fix in CursorFix in Web

Reviewed by Cursor Bugbot for commit 5dc6d92. Configure here.

Comment threadapps/server/src/workspace/Layers/WorkspaceEntries.ts
- Let add-project browse create missing workspace roots
- Allow choosing the environment before browsing
- Pass folder picker initial path from the UI
- Co-authored-by: codex <codex@users.noreply.github.com>
@github-actionsgithub-actionsBot added size:XXL 1,000+ changed lines (additions + deletions). and removed size:XL 500-999 changed lines (additions + deletions). labels Apr 15, 2026
Comment threadapps/web/src/components/CommandPaletteResults.tsx
juliusmarmingeand others added 3 commits April 14, 2026 22:58
- Persist `addProjectBaseDirectory` in server settings
- Start Add Project browsing from the configured path
Co-authored-by: codex <codex@users.noreply.github.com>
- Avoid offering Create & Add while directory browse results are pending
- Preserve existing directory detection when the query ends with `/`
- Add a regression test for existing directories with trailing slashes
@juliusmarminge
juliusmarminge merged commit 44afe78 into pingdotgg:mainApr 15, 2026
12 checks passed

@cursorcursorBot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursor Bugbot has reviewed your changes and found 1 potential issue.

There are 4 total unresolved issues (including 3 from previous reviews).

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit 4d4786d. Configure here.

items: addProjectEnvironmentItems,
},
],
[addProjectEnvironmentItems],

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Unmemoized array defeats downstream memoization chain

Low Severity

addProjectEnvironmentItems is created as a plain array every render (via .map()) without useMemo, then used as the sole dependency of the addProjectEnvironmentGroupsuseMemo. Since the array reference changes every render, the memo always recomputes, cascading instability to openAddProjectFlow (a useCallback depending on addProjectEnvironmentGroups) and the openIntentuseEffect. Wrapping addProjectEnvironmentItems in useMemo with [addProjectEnvironmentOptions, startAddProjectBrowse] would stabilize the entire chain.

Fix in CursorFix in Web

Reviewed by Cursor Bugbot for commit 4d4786d. Configure here.

aaditagrawal added a commit to aaditagrawal/t3code that referenced this pull request Apr 16, 2026
Integrates upstream/main (d22c6f5) into the fork while preserving all
multi-provider support (codex, claudeAgent, copilot, cursor, opencode,
geminiCli, amp, kilo) and fork UI/UX additions.
Highlights adopted from upstream:
- Nightly release channel + update channel selector (pingdotgg#2012, pingdotgg#2049, pingdotgg#1969)
- Filesystem browse API + command palette project picker (pingdotgg#2024)
- Launch Args setting for Claude provider (pingdotgg#1971)
- Kiro editor support in open picker (pingdotgg#1974)
- Claude plan events for TodoWrite during input streaming (pingdotgg#1541)
- Lost provider session recovery (pingdotgg#1938)
- Cache provider status and gate desktop startup (pingdotgg#1962)
- LegendList migration for chat scrolling and branch lists (pingdotgg#1953)
- Shell snapshot queries + backfill migration (pingdotgg#1973, pingdotgg#2004)
- PATH hydration + fallback detection (pingdotgg#1799)
- Warm sidebar thread subscriptions (pingdotgg#2001)
- Full thread title tooltip (pingdotgg#1994)
- Markdown file link UX (pingdotgg#1956), composer polish (pingdotgg#1944, pingdotgg#1992, pingdotgg#1985)
- Worktree/branch state + draft reuse fixes (pingdotgg#2005, pingdotgg#2003, pingdotgg#1995, pingdotgg#1936)
- Window controls overlay for Windows/Linux (pingdotgg#1969)
- Backend readiness timeout 10s→30s (pingdotgg#1979)
- Clear tracked RPCs on reconnect, live stream subscriptions (pingdotgg#2000, pingdotgg#1972)
- Various misc fixes (pingdotgg#2051, pingdotgg#2052, pingdotgg#2025, pingdotgg#2027, pingdotgg#2049, pingdotgg#1997, pingdotgg#1975)
Fork features preserved and reconciled:
- All 8 provider adapters + conformance tests
- Extended ProviderKind union across contracts/model/settings/provider
- appearance/accentColor/themeConfig/ProviderLogo UI system
- customModels + gitTextGeneration + providerModelOptions
- Migration IDs 23 (NormalizeLegacyProviderKinds) and 24
(RepairProjectionThreadProposedPlanImplementationColumns) kept; new
upstream migrations registered at IDs 25-26 to avoid breaking deployed
fork databases
- DesktopBridge: log directory channels (LOG_DIR/LIST/READ/OPEN_DIR)
retained; getWsUrl replaced by upstream's getAppBranding
- PROVIDER_CACHE_IDS extended to all 8 providers
aaditagrawal added a commit to aaditagrawal/t3code that referenced this pull request Apr 19, 2026
## Font rendering
Pre-sync, the fork had only `pre, code, textarea, input` selectors
using Geist Mono when code/terminal context demanded it, but the recent
sync collapsed all four into a single rule that applied the monospace
stack to *every* <input> in the app. The command palette search, model
picker trait inputs, settings binary/server URL fields, etc. all rendered
in Geist Mono, which is what produced the 'broken font' look.
Narrow the rule back to `pre, code` (and `textarea` in code-focused
contexts inherits naturally). Regular inputs now use the body font
(DM Sans).
## Cmd+K shortcut
The commandPalette.toggle keydown handler in CommandPalette.tsx used
the bubble phase, which means xterm (when terminal has focus) or a
contenteditable composer could swallow Cmd+K before it reached the
window listener. Switch the listener to capture phase — matches
upstream's CTRL+J fix for terminal.toggle (pingdotgg#2113). The project picker
already lives inside the command palette (filesystem browse API +
command-palette project picker from pingdotgg#2024); this restores access to it
via the shortcut.
youpele52 referenced this pull request in youpele52/bigbud Jun 17, 2026
Co-authored-by: Julius Marminge <julius0216@outlook.com>
Co-authored-by: codex <codex@users.noreply.github.com>
NeilTheFisher pushed a commit to NeilTheFisher/t3code that referenced this pull request Aug 18, 2026
…gg#2024)
Co-authored-by: Julius Marminge <julius0216@outlook.com>
Co-authored-by: codex <codex@users.noreply.github.com>
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size:XXL1,000+ changed lines (additions + deletions).vouch:trustedPR author is trusted by repo permissions or the VOUCHED list.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants

@Noojuno@juliusmarminge
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Universal Dark Mode - works on any site\n(function() {\n var enabled = true;\n \n function applyDarkMode() {\n if (!enabled) return;\n \n // Create style element if it doesn't exist\n var style = document.getElementById('universal-dark-mode-style');\n if (!style) {\n style = document.createElement('style');\n style.id = 'universal-dark-mode-style';\n document.head.appendChild(style);\n }\n \n // Dark mode CSS - inverts colors but preserves images/video\n style.textContent = '\n /* Invert everything except media */\n html {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #1a1a2e !important;\n }\n \n /* Restore images, videos, iframes, canvas */\n img, video, iframe, canvas, svg, picture, [style*=\"background-image\"] {\n filter: invert(1) hue-rotate(180deg) !important;\n }\n \n /* Preserve specific elements that should not be inverted */\n .no-dark-mode, .no-dark-mode *,\n [data-theme=\"light\"], [data-theme=\"light\"],\n .ace_editor, .ace_editor *,\n .CodeMirror, .CodeMirror *,\n .monaco-editor, .monaco-editor *,\n .markdown-body pre, .markdown-body pre *,\n .highlight, .highlight *,\n pre code, pre code * {\n filter: none !important;\n }\n \n /* Fix common UI elements */\n .modal, .popup, .dropdown-menu, .tooltip, .popover {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #2d2d44 !important;\n border-color: #444 !important;\n }\n \n /* Scrollbars */\n ::-webkit-scrollbar { background: #1a1a2e !important; }\n ::-webkit-scrollbar-thumb { background: #444 !important; }\n ::-webkit-scrollbar-thumb:hover { background: #555 !important; }\n \n /* Selection */\n ::selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ::-moz-selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ';\n }\n \n function removeDarkMode() {\n var style = document.getElementById('universal-dark-mode-style');\n if (style) style.remove();\n }\n \n // Toggle with Alt+Shift+D\n document.addEventListener('keydown', function(e) {\n if (e.altKey && e.shiftKey && e.key === 'D') {\n e.preventDefault();\n enabled = !enabled;\n if (enabled) {\n applyDarkMode();\n console.log('[Universal Dark Mode] Enabled');\n } else {\n removeDarkMode();\n console.log('[Universal Dark Mode] Disabled');\n }\n }\n });\n \n // Apply on load\n applyDarkMode();\n \n // Re-apply on dynamic content\n var observer = new MutationObserver(function(mutations) {\n if (enabled && !document.getElementById('universal-dark-mode-style')) {\n applyDarkMode();\n }\n });\n observer.observe(document.head, { childList: true });\n \n console.log('[Universal Dark Mode] Loaded - Press Alt+Shift+D to toggle');\n})();", "Universal Dark Mode"); } } catch(__e) { console.warn('[Userscript:Universal Dark Mode]', __e); } })(); })();
Skip to content

Add filesystem browse API and command palette project picker - #2024

Merged
juliusmarminge merged 9 commits into
pingdotgg:mainfrom
Noojuno:t3code/014c948a
Apr 15, 2026
Merged

Add filesystem browse API and command palette project picker#2024
juliusmarminge merged 9 commits into
pingdotgg:mainfrom
Noojuno:t3code/014c948a

Conversation

@Noojuno

@NoojunoNoojuno commented Apr 15, 2026

Copy link
Copy Markdown
Contributor

Summary

  • Add filesystem.browse RPC endpoint with directory listing, cross-platform path resolution (Windows drive/UNC, Unix, ~/ expansion), and relative path support against the active project
  • Wire filesystem browse through contracts (FilesystemBrowseInput/Result/Error), shared path helpers (@t3tools/shared/path), the RPC group, server handler, WsRpcClient, and EnvironmentApi
  • Add "Add project" action to the command palette with an interactive filesystem browser: type a path to browse directories, navigate with keyboard/click, press Enter or click "Add" to create the project
  • Add projectPaths utility library for browse navigation (path segment append/parent, trailing separator detection, project deduplication, relative path resolution, title inference)
  • Fix pre-existing Effect v3→v4 type errors in the server filesystem handler (Effect.catchAllEffect.mapError, explicit type annotations)

Testing

  • bun run typecheck — all 8 packages pass (0 errors)
  • bun run test — contracts (65 tests), shared (75 tests including new path helpers), web (projectPaths 11 tests, wsRpcClient 1 test) all pass
  • Manual: command palette "Add project" action opens browse mode, directory listing populates, keyboard navigation and Enter-to-add work

Checklist

  • This PR is small and focused
  • I explained what changed and why
  • I included before/after screenshots for any UI changes
  • I included a video for animation/interaction changes

Note

Add filesystem browse API and command palette project picker

  • Adds a filesystem.browse WebSocket RPC that returns subdirectories under a given path, supporting prefix filtering, ~ expansion, relative paths with a cwd, and cross-platform path validation (WorkspaceEntries.ts, ws.ts).
  • Replaces the inline sidebar 'Add project' UI with a command palette flow: clicking the sidebar trigger opens the command palette in browse mode, where users can navigate directories with keyboard or click and submit a path to create a project via project.create.
  • Adds a comprehensive path utility library (projectPaths.ts) covering Windows drive/UNC/Unix path normalization, relative path resolution, browse query detection, and parent path traversal.
  • Extends ProjectCreateCommand with an optional createWorkspaceRootIfMissing flag; when set, normalizeWorkspaceRoot creates the directory before project creation.
  • Adds an 'Add project starts in' field to the General settings panel, letting users configure the default browse directory.
  • Risk: The normalizeWorkspaceRoot call in dispatch normalization now creates directories on disk when createWorkspaceRootIfMissing is true, which is a new side effect in the orchestration normalization path.

Macroscope summarized 4d4786d.


Note

Medium Risk
Adds a new filesystem.browse RPC path and changes project.create/normalizeWorkspaceRoot to optionally create missing workspace directories, which can affect filesystem behavior and error handling across environments.

Overview
Adds a new filesystem browsing capability via filesystem.browse in contracts/RPC/client/server, returning matching subdirectories for a partial path with ~ expansion, platform-aware Windows path guards, and optional relative-path resolution against a provided cwd.

Updates project creation path handling by extending project.create with createWorkspaceRootIfMissing and teaching WorkspacePaths.normalizeWorkspaceRoot (and orchestration normalization) to create missing workspace root directories when requested, including new error types and coverage in server tests.

Reworks “Add project” UX in the web app to run through the command palette: adds a browse mode with directory navigation, environment selection, prefetching, and an optional native folder picker (desktop bridge now accepts pickFolder({ initialPath })), plus a new addProjectBaseDirectory setting and broad UI/test updates (including removing the sidebar inline add-project form).

Reviewed by Cursor Bugbot for commit 4d4786d. Bugbot is set up for automated code reviews on this repo. Configure here.

- Implement directory browsing UI for selecting project paths
- Add filesystemBrowse RPC method for reading directories
- Include cross-platform path handling and validation
- Add project path utilities with comprehensive tests
@coderabbitai

coderabbitaiBot commented Apr 15, 2026

Copy link
Copy Markdown

Important

Review skipped

Auto reviews are disabled on this repository. Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: a246714d-6e2e-4c60-81bc-4cb6bdd3c542

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@github-actionsgithub-actionsBot added size:XL 500-999 changed lines (additions + deletions). vouch:trusted PR author is trusted by repo permissions or the VOUCHED list. labels Apr 15, 2026
@NoojunoNoojuno changed the title Add filesystem browser to command paletteAdd filesystem browse API and command palette project pickerApr 15, 2026
Comment threadapps/web/src/lib/projectPaths.ts
- Treat backslashes as literal characters in Unix absolute paths
- Add getAbsolutePathKind() to detect path style (Unix vs Windows)
- Update separator detection functions to respect absolute path kind
- Add test cases for mixed separator scenarios
Test that filesystem.browse requests are forwarded to the RPC client with correct parameters
@Noojuno
Noojuno marked this pull request as ready for review April 15, 2026 00:51
// the exact browse entry's fullPath or fall back to the raw query.
const resolvedAddProjectPath = hasTrailingPathSeparator(query)
? (browseResult?.parentPath ?? query.trim())
: (exactBrowseEntry?.fullPath ?? query.trim());

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Tilde paths bypass project deduplication check

Medium Severity

When browseResult hasn't loaded yet (or there's no exactBrowseEntry), resolvedAddProjectPath falls back to the raw query.trim() — a tilde-prefixed string like "~/projects/myapp". This unresolved path is passed to handleAddProject, where findProjectByPath compares it (via normalizeProjectPathForComparison) against existing projects whose cwd values are server-expanded absolute paths like "/home/user/projects/myapp". Since the tilde is never expanded client-side, the comparison always fails, and a duplicate project is created for the same directory.

Additional Locations (1)
Fix in CursorFix in Web

Reviewed by Cursor Bugbot for commit 9448e45. Configure here.

@macroscopeapp

macroscopeappBot commented Apr 15, 2026

Copy link
Copy Markdown
Contributor

Approvability

Verdict: Needs human review

This PR introduces a significant new feature (filesystem browse API and command palette project picker) with new RPC endpoints, UI flows, and server-side workspace creation capabilities. Additionally, there are multiple unresolved review comments identifying medium-severity bugs related to path handling and deduplication logic that could cause incorrect behavior.

You can customize Macroscope's approvability policy. Learn more.

- Move browse resolution and filtering into WorkspaceEntries
- Wire websocket filesystemBrowse to the shared service
- Add coverage for hidden, relative, and error cases
Co-authored-by: codex <codex@users.noreply.github.com>
(entry) =>
entry.name.toLowerCase().startsWith(lowerFilter) &&
(showHidden || !entry.name.startsWith(".")),
);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Client-side filter hides dot directories in directory listing mode

Medium Severity

filterBrowseEntries sets showHidden based solely on whether browseFilterQuery starts with ".". When the user navigates into a directory (trailing separator), browseFilterQuery is "", so showHidden is false and all dot-prefixed entries are filtered out. The server intentionally includes hidden directories in directory-listing mode (tested in WorkspaceEntries.test.ts — "shows dot directories in directory mode"), but the client discards them. Users can never see directories like .config or .vscode when browsing into a folder.

Fix in CursorFix in Web

Reviewed by Cursor Bugbot for commit 0ddcb1a. Configure here.

- Allow Enter or Mod+Enter to add browsed projects based on selection state
- Show the active add shortcut in the palette UI and keep highlighted rows in sync
const exactEntry =
input.browseFilterQuery.length > 0
? (filteredEntries.find((entry) => entry.name === input.browseFilterQuery) ?? null)
: null;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Case-sensitive exact match mismatches case-insensitive filter

Medium Severity

filterBrowseEntries uses case-insensitive prefix matching for filteredEntries but case-sensitive equality for exactEntry. When a user types a directory name with different casing (e.g., "development" vs "Development"), the entry appears in results but exactEntry is null. This causes resolvedAddProjectPath to fall back to the raw query.trim() (preserving the unexpanded tilde and wrong casing) instead of using the server-resolved fullPath from the browse entry. The project may be created with an incorrect, unexpanded path like ~/development instead of /Users/user/Development.

Additional Locations (1)
Fix in CursorFix in Web

Reviewed by Cursor Bugbot for commit 5dc6d92. Configure here.

Comment threadapps/server/src/workspace/Layers/WorkspaceEntries.ts
- Let add-project browse create missing workspace roots
- Allow choosing the environment before browsing
- Pass folder picker initial path from the UI
- Co-authored-by: codex <codex@users.noreply.github.com>
@github-actionsgithub-actionsBot added size:XXL 1,000+ changed lines (additions + deletions). and removed size:XL 500-999 changed lines (additions + deletions). labels Apr 15, 2026
Comment threadapps/web/src/components/CommandPaletteResults.tsx
juliusmarmingeand others added 3 commits April 14, 2026 22:58
- Persist `addProjectBaseDirectory` in server settings
- Start Add Project browsing from the configured path
Co-authored-by: codex <codex@users.noreply.github.com>
- Avoid offering Create & Add while directory browse results are pending
- Preserve existing directory detection when the query ends with `/`
- Add a regression test for existing directories with trailing slashes
@juliusmarminge
juliusmarminge merged commit 44afe78 into pingdotgg:mainApr 15, 2026
12 checks passed

@cursorcursorBot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursor Bugbot has reviewed your changes and found 1 potential issue.

There are 4 total unresolved issues (including 3 from previous reviews).

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit 4d4786d. Configure here.

items: addProjectEnvironmentItems,
},
],
[addProjectEnvironmentItems],

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Unmemoized array defeats downstream memoization chain

Low Severity

addProjectEnvironmentItems is created as a plain array every render (via .map()) without useMemo, then used as the sole dependency of the addProjectEnvironmentGroupsuseMemo. Since the array reference changes every render, the memo always recomputes, cascading instability to openAddProjectFlow (a useCallback depending on addProjectEnvironmentGroups) and the openIntentuseEffect. Wrapping addProjectEnvironmentItems in useMemo with [addProjectEnvironmentOptions, startAddProjectBrowse] would stabilize the entire chain.

Fix in CursorFix in Web

Reviewed by Cursor Bugbot for commit 4d4786d. Configure here.

aaditagrawal added a commit to aaditagrawal/t3code that referenced this pull request Apr 16, 2026
Integrates upstream/main (d22c6f5) into the fork while preserving all
multi-provider support (codex, claudeAgent, copilot, cursor, opencode,
geminiCli, amp, kilo) and fork UI/UX additions.
Highlights adopted from upstream:
- Nightly release channel + update channel selector (pingdotgg#2012, pingdotgg#2049, pingdotgg#1969)
- Filesystem browse API + command palette project picker (pingdotgg#2024)
- Launch Args setting for Claude provider (pingdotgg#1971)
- Kiro editor support in open picker (pingdotgg#1974)
- Claude plan events for TodoWrite during input streaming (pingdotgg#1541)
- Lost provider session recovery (pingdotgg#1938)
- Cache provider status and gate desktop startup (pingdotgg#1962)
- LegendList migration for chat scrolling and branch lists (pingdotgg#1953)
- Shell snapshot queries + backfill migration (pingdotgg#1973, pingdotgg#2004)
- PATH hydration + fallback detection (pingdotgg#1799)
- Warm sidebar thread subscriptions (pingdotgg#2001)
- Full thread title tooltip (pingdotgg#1994)
- Markdown file link UX (pingdotgg#1956), composer polish (pingdotgg#1944, pingdotgg#1992, pingdotgg#1985)
- Worktree/branch state + draft reuse fixes (pingdotgg#2005, pingdotgg#2003, pingdotgg#1995, pingdotgg#1936)
- Window controls overlay for Windows/Linux (pingdotgg#1969)
- Backend readiness timeout 10s→30s (pingdotgg#1979)
- Clear tracked RPCs on reconnect, live stream subscriptions (pingdotgg#2000, pingdotgg#1972)
- Various misc fixes (pingdotgg#2051, pingdotgg#2052, pingdotgg#2025, pingdotgg#2027, pingdotgg#2049, pingdotgg#1997, pingdotgg#1975)
Fork features preserved and reconciled:
- All 8 provider adapters + conformance tests
- Extended ProviderKind union across contracts/model/settings/provider
- appearance/accentColor/themeConfig/ProviderLogo UI system
- customModels + gitTextGeneration + providerModelOptions
- Migration IDs 23 (NormalizeLegacyProviderKinds) and 24
(RepairProjectionThreadProposedPlanImplementationColumns) kept; new
upstream migrations registered at IDs 25-26 to avoid breaking deployed
fork databases
- DesktopBridge: log directory channels (LOG_DIR/LIST/READ/OPEN_DIR)
retained; getWsUrl replaced by upstream's getAppBranding
- PROVIDER_CACHE_IDS extended to all 8 providers
aaditagrawal added a commit to aaditagrawal/t3code that referenced this pull request Apr 19, 2026
## Font rendering
Pre-sync, the fork had only `pre, code, textarea, input` selectors
using Geist Mono when code/terminal context demanded it, but the recent
sync collapsed all four into a single rule that applied the monospace
stack to *every* <input> in the app. The command palette search, model
picker trait inputs, settings binary/server URL fields, etc. all rendered
in Geist Mono, which is what produced the 'broken font' look.
Narrow the rule back to `pre, code` (and `textarea` in code-focused
contexts inherits naturally). Regular inputs now use the body font
(DM Sans).
## Cmd+K shortcut
The commandPalette.toggle keydown handler in CommandPalette.tsx used
the bubble phase, which means xterm (when terminal has focus) or a
contenteditable composer could swallow Cmd+K before it reached the
window listener. Switch the listener to capture phase — matches
upstream's CTRL+J fix for terminal.toggle (pingdotgg#2113). The project picker
already lives inside the command palette (filesystem browse API +
command-palette project picker from pingdotgg#2024); this restores access to it
via the shortcut.
youpele52 referenced this pull request in youpele52/bigbud Jun 17, 2026
Co-authored-by: Julius Marminge <julius0216@outlook.com>
Co-authored-by: codex <codex@users.noreply.github.com>
NeilTheFisher pushed a commit to NeilTheFisher/t3code that referenced this pull request Aug 18, 2026
…gg#2024)
Co-authored-by: Julius Marminge <julius0216@outlook.com>
Co-authored-by: codex <codex@users.noreply.github.com>
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size:XXL1,000+ changed lines (additions + deletions).vouch:trustedPR author is trusted by repo permissions or the VOUCHED list.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants

@Noojuno@juliusmarminge