Support file tree path drops into terminal tabs#296
Conversation
✅ Deploy Preview for grand-selkie-225f87 canceled.
|
|
Warning Review limit reached
More reviews will be available in 48 minutes and 41 seconds. Learn how PR review limits work. Your organization has run out of usage credits. Purchase more in the billing tab. ⌛ How to resolve this issue?After more reviews become available, a review can be triggered using the We recommend that you space out your commits to avoid hitting the rate limit. 🚦 How do rate limits work?CodeRabbit enforces hourly rate limits for each developer per organization. Our paid plans include higher PR review limits than trial, open-source, and free plans. In all cases, reviews become available again over time. During sustained high-volume PR review activity, CodeRabbit may temporarily slow when the next review becomes available. Please see our Fair Usage Limits Policy for further information. ℹ️ Review info⚙️ Run configurationConfiguration used: defaults Review profile: CHILL Plan: Pro Run ID: 📒 Files selected for processing (1)
📝 WalkthroughWalkthroughThis pull request implements file tree drag-and-drop into terminal tabs. It establishes a shared drag-drop payload contract with serialization utilities, adds drag initiation in FileTreePanel, exposes terminal tab elements via ref callbacks in TabStrip, and implements drop handling in TerminalTabs to activate tabs and write paths to the PTY. ChangesFile tree drag-and-drop to terminal tabs
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~20 minutes Poem
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches🧪 Generate unit tests (beta)
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. Comment |
|
@codex review |
There was a problem hiding this comment.
Pull request overview
This PR adds support for dragging file-tree paths into terminal tabs/panes and writing those paths into the target PTY session.
Changes:
- Added shared file-tree terminal drop payload helpers.
- Wired file-tree drag start/end handling to dispatch terminal drop events.
- Added terminal tab/pane drop targets and tests for payload/drop handling.
Reviewed changes
Copilot reviewed 8 out of 8 changed files in this pull request and generated 2 comments.
Show a summary per file
| File | Description |
|---|---|
src/shared/lib/fileTreeTerminalDrop.ts |
Defines the drag payload format, serialization helpers, target lookup, and terminal input formatting. |
src/shared/lib/fileTreeTerminalDrop.test.ts |
Adds coverage for payload round-tripping and path formatting. |
src/features/projects/FileTreePanel.tsx |
Creates file-tree drag payloads and dispatches custom terminal drop events on drag end. |
src/features/projects/FileTreePanel.test.tsx |
Adds coverage for click suppression and drag payload generation. |
src/features/terminal/TerminalTabs.tsx |
Registers terminal tabs/pane as drop targets and writes dropped paths to PTY sessions. |
src/features/terminal/TerminalTabs.test.tsx |
Adds terminal drop behavior coverage. |
src/features/terminal/TabStrip.tsx |
Exposes tab element refs so terminal tabs can be marked as drop targets. |
src/test/setup.ts |
Adds a writeToPty mock for tests. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| fireEvent.dragOver(terminalTab, { dataTransfer }); | ||
| fireEvent.drop(terminalTab, { dataTransfer }); |
| return paths | ||
| .filter((path) => path.length > 0) | ||
| .join(" "); |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: f1abc51a1a
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| export function formatTerminalPathInput(paths: readonly string[]) { | ||
| return paths | ||
| .filter((path) => path.length > 0) | ||
| .join(" "); |
There was a problem hiding this comment.
Escape dropped paths before writing them
When any dropped file or directory contains spaces, this formatter writes the raw absolute path into the PTY and separates paths with a single space, so a normal shell command like cat /root/path with spaces/file.ts is parsed as multiple arguments instead of one path. This affects common project/file names with spaces; quote or shell-escape each path before joining so the terminal receives usable path arguments.
Useful? React with 👍 / 👎.
| if (payload) { | ||
| const target = getFileTreeTerminalDropTargetAtPoint( | ||
| event.clientX, | ||
| event.clientY, | ||
| ); | ||
| target?.dispatchEvent( |
There was a problem hiding this comment.
Ignore canceled drags before dispatching terminal drops
This dispatches the terminal-drop event for any dragend that finishes over a terminal target, even if the user canceled the drag (for example by pressing Escape while hovering over the terminal); MDN documents dropEffect === "none" on dragend for canceled drags (https://developer.mozilla.org/en-US/docs/Web/API/HTML_Drag_and_Drop_API/Drag_operations#finishing_the_drag). In that scenario the path is still written into the PTY despite no drop being performed, so the handler needs to distinguish a real accepted drop from cancellation.
Useful? React with 👍 / 👎.
| fireEvent.dragOver(terminalTab, { dataTransfer }); | ||
| fireEvent.drop(terminalTab, { dataTransfer }); |
There was a problem hiding this comment.
Dispatch the custom terminal-drop event in this test
This test fires native dragOver/drop events, but the component added in this change only listens for FILE_TREE_TERMINAL_DROP_EVENT via addEventListener, not for the browser drop event. As written, handleTerminalPathDrop never runs and writeToPtyMock remains uncalled, so the new test fails unless it dispatches the same custom event that FileTreePanel sends on drag end.
Useful? React with 👍 / 👎.
There was a problem hiding this comment.
Actionable comments posted: 4
🧹 Nitpick comments (2)
src/features/projects/FileTreePanel.test.tsx (1)
278-305: 💤 Low valueConsider extracting
createTestDataTransferto a shared test utility.This helper is duplicated in
src/shared/lib/fileTreeTerminalDrop.test.ts(lines 10-28). While test helpers are often locally defined, extracting it tosrc/test/testUtils.tsor similar would reduce duplication and ensure consistency.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/features/projects/FileTreePanel.test.tsx` around lines 278 - 305, The createTestDataTransfer helper is duplicated; extract the function createTestDataTransfer into a shared test utilities module (e.g., export it from a new test utils file) and replace the local copies with imports, ensuring the exported function preserves the same behavior (returns a DataTransfer-like object with dropEffect, effectAllowed, files, items, types, clearData, getData, setData, setDragImage and uses vi.fn for spies). Update the tests that used the duplicated implementation to import createTestDataTransfer from the new shared module and remove the local definitions so all tests reuse the single exported helper.src/features/terminal/TerminalTabs.tsx (1)
220-241: ⚖️ Poor tradeoff
createTerminalDropRefreturns a new callback every render, forcing listener teardown/re-add on each commit.Because a fresh function instance is passed as
refon every render, React invokes the previous callback withnull(removing the listener + attribute) and the new one with the node after each commit. This works but is wasteful. Consider memoizing per-tab refs (e.g. aMap<sessionId, RefCallback>kept in a ref) so identities stay stable across renders.Also applies to: 255-255, 417-421
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/features/terminal/TerminalTabs.tsx` around lines 220 - 241, createTerminalDropRef currently yields a new ref callback every render which forces React to call the old callback with null (tearing down listeners/attributes) and then reattach on the new callback; to fix, memoize stable ref callbacks per tab id by keeping a Map<string, RefCallback> in a React ref (e.g., useRef(new Map())), return the cached callback for tab.id from createTerminalDropRef, and ensure the cached callback manages its own cleanup (removing FILE_TREE_TERMINAL_DROP_EVENT listener and FILE_TREE_TERMINAL_DROP_TARGET_ATTR) and calls handleTerminalPathDrop with the CustomEvent<FileTreeTerminalDropEventDetail> when triggered; update all usages (including the other occurrences noted) to use the memoized callbacks so listener identity remains stable across renders.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@src/features/terminal/TerminalTabs.test.tsx`:
- Around line 142-167: The test fails because it dispatches native drag/drop
events but TerminalTabs listens for the custom FILE_TREE_TERMINAL_DROP_EVENT
(via createTerminalDropRef) so handleTerminalPathDrop and writeToPty never run;
fix the test by dispatching a CustomEvent with the same shape used in production
(event type FILE_TREE_TERMINAL_DROP_EVENT and detail.payload matching
writeFileTreeTerminalDropPayload), target the tab element (terminal-session
element or terminal tab) with dispatchEvent(element.dispatchEvent(new
CustomEvent(...))), import FILE_TREE_TERMINAL_DROP_EVENT from
"`@/shared/lib/fileTreeTerminalDrop`", and remove now-unused helpers/imports
(createTestDataTransfer, createFileTreeDrop, fireEvent usage for native drop,
and writeFileTreeTerminalDropPayload) to satisfy noUnusedLocals.
In `@src/features/terminal/TerminalTabs.tsx`:
- Around line 205-218: In handleTerminalPathDrop, the call to writeToPty({
sessionId: tab.id, data }) returns a Promise that isn’t handled; wrap this call
with proper error handling—either make handleTerminalPathDrop async and await
writeToPty inside a try/catch, or append .catch(...) to writeToPty—to log or
surface IPC errors. Keep existing calls to setActiveTab and setTerminalActive
unchanged and ensure errors reference the sessionId/tab.id and data context for
easier debugging.
In `@src/shared/lib/fileTreeTerminalDrop.test.ts`:
- Around line 48-55: The test in fileTreeTerminalDrop.test.ts currently asserts
unescaped space-containing paths and must be updated to expect properly
shell-escaped/quoted output from formatTerminalPathInput; change the expected
string to match the escaping convention implemented in formatTerminalPathInput
(e.g., wrap paths with spaces in single-quotes or otherwise escape spaces) so
the test asserts the escaped form (refer to formatTerminalPathInput and the
related escape logic in fileTreeTerminalDrop.ts around the earlier comment).
Ensure the test still passes multiple-path input and checks the exact
escaped/quoted concatenation returned by formatTerminalPathInput.
In `@src/shared/lib/fileTreeTerminalDrop.ts`:
- Around line 102-106: The current formatTerminalPathInput(paths) blindly joins
with spaces and must instead perform shell-aware escaping; update
formatTerminalPathInput to accept an optional shell parameter (or detect via
process.env.SHELL / process.platform) and escape each path per-shell before
joining. For Unix-like shells, wrap each path in single quotes and escape
embedded single quotes by replacing ' with '\'' (i.e. "'\"'\"'"); for
PowerShell/Windows, wrap in double quotes and escape embedded " appropriately
(e.g. by doubling or using PowerShell backtick); ensure the function returns the
joined, escaped paths string used when writing to the PTY so paths with
spaces/special chars are preserved.
---
Nitpick comments:
In `@src/features/projects/FileTreePanel.test.tsx`:
- Around line 278-305: The createTestDataTransfer helper is duplicated; extract
the function createTestDataTransfer into a shared test utilities module (e.g.,
export it from a new test utils file) and replace the local copies with imports,
ensuring the exported function preserves the same behavior (returns a
DataTransfer-like object with dropEffect, effectAllowed, files, items, types,
clearData, getData, setData, setDragImage and uses vi.fn for spies). Update the
tests that used the duplicated implementation to import createTestDataTransfer
from the new shared module and remove the local definitions so all tests reuse
the single exported helper.
In `@src/features/terminal/TerminalTabs.tsx`:
- Around line 220-241: createTerminalDropRef currently yields a new ref callback
every render which forces React to call the old callback with null (tearing down
listeners/attributes) and then reattach on the new callback; to fix, memoize
stable ref callbacks per tab id by keeping a Map<string, RefCallback> in a React
ref (e.g., useRef(new Map())), return the cached callback for tab.id from
createTerminalDropRef, and ensure the cached callback manages its own cleanup
(removing FILE_TREE_TERMINAL_DROP_EVENT listener and
FILE_TREE_TERMINAL_DROP_TARGET_ATTR) and calls handleTerminalPathDrop with the
CustomEvent<FileTreeTerminalDropEventDetail> when triggered; update all usages
(including the other occurrences noted) to use the memoized callbacks so
listener identity remains stable across renders.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro
Run ID: 9465e04a-d0a0-4e45-93dc-32c4d1dfd51f
📒 Files selected for processing (8)
src/features/projects/FileTreePanel.test.tsxsrc/features/projects/FileTreePanel.tsxsrc/features/terminal/TabStrip.tsxsrc/features/terminal/TerminalTabs.test.tsxsrc/features/terminal/TerminalTabs.tsxsrc/shared/lib/fileTreeTerminalDrop.test.tssrc/shared/lib/fileTreeTerminalDrop.tssrc/test/setup.ts
| const dataTransfer = createFileTreeDrop([ | ||
| "/root/src/index.ts", | ||
| "/root/src/components", | ||
| ]); | ||
| const terminalTab = screen.getByRole("tab", { name: /Terminal 2/ }); | ||
|
|
||
| fireEvent.dragOver(terminalTab, { dataTransfer }); | ||
| fireEvent.drop(terminalTab, { dataTransfer }); | ||
|
|
||
| await waitFor(() => { | ||
| expect(writeToPtyMock).toHaveBeenCalledWith({ | ||
| sessionId: "session-2", | ||
| data: "/root/src/index.ts /root/src/components", | ||
| }); | ||
| }); | ||
| expect(useTerminalStore.getState().profiles[profileId].activeTabId).toBe( | ||
| "session-2", | ||
| ); | ||
| expect( | ||
| useFileViewerTabsStore.getState().profiles[profileId]?.fileTabActive, | ||
| ).toBe(false); | ||
| expect(screen.getByTestId("terminal-session-2")).toHaveAttribute( | ||
| "data-active", | ||
| "true", | ||
| ); | ||
| }); |
There was a problem hiding this comment.
Test never triggers the drop handler — root cause of the failing pipeline.
TerminalTabs attaches its listener for the custom FILE_TREE_TERMINAL_DROP_EVENT (createTerminalDropRef), not the native drop event. Firing fireEvent.dragOver/fireEvent.drop dispatches native events that no listener handles, so handleTerminalPathDrop (and thus writeToPty) never runs — matching the Number of calls: 0 failure at Line 152. Dispatch the custom event with a detail.payload instead.
💚 Proposed fix
- const dataTransfer = createFileTreeDrop([
- "/root/src/index.ts",
- "/root/src/components",
- ]);
- const terminalTab = screen.getByRole("tab", { name: /Terminal 2/ });
-
- fireEvent.dragOver(terminalTab, { dataTransfer });
- fireEvent.drop(terminalTab, { dataTransfer });
+ const absolutePaths = ["/root/src/index.ts", "/root/src/components"];
+ const payload = createFileTreeTerminalDropPayload({
+ profileId,
+ rootPath: "/root",
+ relativePaths: absolutePaths.map((p) => p.replace("/root/", "")),
+ absolutePaths,
+ });
+ const terminalTab = screen.getByRole("tab", { name: /Terminal 2/ });
+
+ terminalTab.dispatchEvent(
+ new CustomEvent(FILE_TREE_TERMINAL_DROP_EVENT, {
+ bubbles: true,
+ detail: { clientX: 0, clientY: 0, payload },
+ }),
+ );Note: with this change createTestDataTransfer, createFileTreeDrop, fireEvent, and the writeFileTreeTerminalDropPayload import become unused and must be removed (project enforces noUnusedLocals). You will also need to import FILE_TREE_TERMINAL_DROP_EVENT from @/shared/lib/fileTreeTerminalDrop.
🧰 Tools
🪛 GitHub Check: Frontend
[failure] 152-152: src/features/terminal/TerminalTabs.test.tsx > terminalTabs file tree drops > activates the dropped terminal tab and writes dropped paths to its PTY
AssertionError: expected "vi.fn()" to be called with arguments: [ { sessionId: 'session-2', …(1) } ]
Number of calls: 0
Ignored nodes: comments, script, style
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@src/features/terminal/TerminalTabs.test.tsx` around lines 142 - 167, The test
fails because it dispatches native drag/drop events but TerminalTabs listens for
the custom FILE_TREE_TERMINAL_DROP_EVENT (via createTerminalDropRef) so
handleTerminalPathDrop and writeToPty never run; fix the test by dispatching a
CustomEvent with the same shape used in production (event type
FILE_TREE_TERMINAL_DROP_EVENT and detail.payload matching
writeFileTreeTerminalDropPayload), target the tab element (terminal-session
element or terminal tab) with dispatchEvent(element.dispatchEvent(new
CustomEvent(...))), import FILE_TREE_TERMINAL_DROP_EVENT from
"`@/shared/lib/fileTreeTerminalDrop`", and remove now-unused helpers/imports
(createTestDataTransfer, createFileTreeDrop, fireEvent usage for native drop,
and writeFileTreeTerminalDropPayload) to satisfy noUnusedLocals.
| function handleTerminalPathDrop( | ||
| detail: FileTreeTerminalDropEventDetail, | ||
| tab: { id: string }, | ||
| ) { | ||
| const { payload } = detail; | ||
| if (payload.profileId !== profileId) return; | ||
|
|
||
| const data = formatTerminalPathInput(payload.absolutePaths); | ||
| if (!data) return; | ||
|
|
||
| setActiveTab(profileId, tab.id); | ||
| setTerminalActive(profileId); | ||
| writeToPty({ sessionId: tab.id, data }); | ||
| } |
There was a problem hiding this comment.
writeToPty rejection is unhandled.
writeToPty returns a promise that is neither awaited nor caught here; an IPC failure becomes an unhandled rejection. Add minimal error handling.
🛡️ Proposed fix
setActiveTab(profileId, tab.id);
setTerminalActive(profileId);
- writeToPty({ sessionId: tab.id, data });
+ writeToPty({ sessionId: tab.id, data }).catch(() => {
+ // PTY write failed; nothing actionable on the UI side
+ });
}📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| function handleTerminalPathDrop( | |
| detail: FileTreeTerminalDropEventDetail, | |
| tab: { id: string }, | |
| ) { | |
| const { payload } = detail; | |
| if (payload.profileId !== profileId) return; | |
| const data = formatTerminalPathInput(payload.absolutePaths); | |
| if (!data) return; | |
| setActiveTab(profileId, tab.id); | |
| setTerminalActive(profileId); | |
| writeToPty({ sessionId: tab.id, data }); | |
| } | |
| function handleTerminalPathDrop( | |
| detail: FileTreeTerminalDropEventDetail, | |
| tab: { id: string }, | |
| ) { | |
| const { payload } = detail; | |
| if (payload.profileId !== profileId) return; | |
| const data = formatTerminalPathInput(payload.absolutePaths); | |
| if (!data) return; | |
| setActiveTab(profileId, tab.id); | |
| setTerminalActive(profileId); | |
| writeToPty({ sessionId: tab.id, data }).catch(() => { | |
| // PTY write failed; nothing actionable on the UI side | |
| }); | |
| } |
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@src/features/terminal/TerminalTabs.tsx` around lines 205 - 218, In
handleTerminalPathDrop, the call to writeToPty({ sessionId: tab.id, data })
returns a Promise that isn’t handled; wrap this call with proper error
handling—either make handleTerminalPathDrop async and await writeToPty inside a
try/catch, or append .catch(...) to writeToPty—to log or surface IPC errors.
Keep existing calls to setActiveTab and setTerminalActive unchanged and ensure
errors reference the sessionId/tab.id and data context for easier debugging.
| it("formats terminal input as raw absolute paths", () => { | ||
| expect( | ||
| formatTerminalPathInput([ | ||
| "/root/src/index.ts", | ||
| "/root/path with spaces/file.ts", | ||
| ]), | ||
| ).toBe("/root/src/index.ts /root/path with spaces/file.ts"); | ||
| }); |
There was a problem hiding this comment.
Test validates broken shell parsing behavior.
This test expects unquoted paths with spaces to be joined with a single space, which produces invalid shell input. The expected result "/root/src/index.ts /root/path with spaces/file.ts" would be mis-parsed by shells as multiple arguments. Once formatTerminalPathInput is fixed to add proper shell escaping/quoting (see comment on lines 102-106 in fileTreeTerminalDrop.ts), update this test to verify the escaped output.
📝 Expected test update after fixing formatTerminalPathInput
If using single-quote escaping for Unix shells:
it("formats terminal input as raw absolute paths", () => {
expect(
formatTerminalPathInput([
"/root/src/index.ts",
"/root/path with spaces/file.ts",
]),
- ).toBe("/root/src/index.ts /root/path with spaces/file.ts");
+ ).toBe("'/root/src/index.ts' '/root/path with spaces/file.ts'");
});🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@src/shared/lib/fileTreeTerminalDrop.test.ts` around lines 48 - 55, The test
in fileTreeTerminalDrop.test.ts currently asserts unescaped space-containing
paths and must be updated to expect properly shell-escaped/quoted output from
formatTerminalPathInput; change the expected string to match the escaping
convention implemented in formatTerminalPathInput (e.g., wrap paths with spaces
in single-quotes or otherwise escape spaces) so the test asserts the escaped
form (refer to formatTerminalPathInput and the related escape logic in
fileTreeTerminalDrop.ts around the earlier comment). Ensure the test still
passes multiple-path input and checks the exact escaped/quoted concatenation
returned by formatTerminalPathInput.
| export function formatTerminalPathInput(paths: readonly string[]) { | ||
| return paths | ||
| .filter((path) => path.length > 0) | ||
| .join(" "); | ||
| } |
There was a problem hiding this comment.
❓ Verification inconclusive
🏁 Script executed:
#!/bin/bash
# Verify shell quoting behavior for paths with spaces
echo "Testing shell argument parsing with spaces:"
echo
echo "Unquoted path with spaces (will split incorrectly):"
echo /root/path with spaces/file.ts | xargs -n1 echo "Arg:"
echo
echo "Single-quoted path (preserves literal, correct):"
echo '/root/path with spaces/file.ts' | xargs -n1 echo "Arg:"
echo
echo "Escaped spaces (also correct):"
echo /root/path\ with\ spaces/file.ts | xargs -n1 echo "Arg:"Repository: AkaraChen/2code
Length of output: 376
Fix shell-escaping for terminal path arguments
formatTerminalPathInput joins paths with a single space but does not quote/escape them; when this string is written into a shell command line (via PTY), paths containing spaces/special characters will be split into multiple arguments, breaking common inputs.
The provided shell-parsing snippet doesn’t properly validate quoting behavior for the PTY case because the local shell strips quote characters before xargs performs its splitting.
🛡️ Proposed fix (apply for Unix-like shells)
export function formatTerminalPathInput(paths: readonly string[]) {
- return paths
- .filter((path) => path.length > 0)
- .join(" ");
+ return paths
+ .filter((path) => path.length > 0)
+ .map((path) => `'${path.replace(/'/g, "'\\''")}'`)
+ .join(" ");
}Need shell/OS-specific escaping (PowerShell vs bash/zsh differ); Unix single-quote wrapping shouldn’t be applied blindly if the active terminal shell is PowerShell/Windows.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@src/shared/lib/fileTreeTerminalDrop.ts` around lines 102 - 106, The current
formatTerminalPathInput(paths) blindly joins with spaces and must instead
perform shell-aware escaping; update formatTerminalPathInput to accept an
optional shell parameter (or detect via process.env.SHELL / process.platform)
and escape each path per-shell before joining. For Unix-like shells, wrap each
path in single quotes and escape embedded single quotes by replacing ' with '\''
(i.e. "'\"'\"'"); for PowerShell/Windows, wrap in double quotes and escape
embedded " appropriately (e.g. by doubling or using PowerShell backtick); ensure
the function returns the joined, escaped paths string used when writing to the
PTY so paths with spaces/special chars are preserved.
Summary
Validation
Summary by CodeRabbit
Release Notes
New Features
Tests