Skip to content

[STA-6940] Deliver chat, workspace composer, and feedback file drops at their elements (3/6) - #25781

Merged
brennanb2025 merged 23 commits into
mainfrom
brennanb2025/sta-6940-pr3-chat-composer-feedback
Oct 7, 2026
Merged

brennanb2025 merged 23 commits into
mainfrom
brennanb2025/sta-6940-pr3-chat-composer-feedback

Conversation

@brennanb2025

@brennanb2025 brennanb2025 commented Oct 6, 2026 •

Copy link
Copy Markdown
Contributor
Files Added Deleted Net
Test 23 $\color{#1a7f37}{\Huge{\mathbf{+}}}$​1419 $\color{#cf222e}{\Huge{\mathbf{−}}}$​300 $\color{#1a7f37}{\Huge{\mathbf{+}}}$​1119
Prod 25 $\color{#1a7f37}{\Huge{\mathbf{+}}}$​427 $\color{#cf222e}{\Huge{\mathbf{−}}}$​279 $\color{#1a7f37}{\Huge{\mathbf{+}}}$​148

ELI5

A file dragged onto a chat could go to a different mounted composer because delivery was broadcast to the window and filtered by routing markers or whichever composer mounted last. A non-image file dropped onto feedback could also open in the editor behind the dialog. Earlier versions of this migration used the task-source repository as a folder project's attachment destination, rejected files in floating chat without a catalog row, and could keep refusing files after its composer became available again.

This is PR 3 of 6 for STA-6940: native chat, workspace cards with an attachment destination, and feedback handle file drops on the element under the cursor. Chat without a usable composer and the current quick-create workspace card refuse files with the “not allowed” cursor, without a toast or an accepting ring.

Dependencies: PR1 (#25749) and PR2 (#25748) are both MERGED, squashed into main as 5345ba34bf2 and 5b1bb78d14b. PR3 has no pending dependency. Its original implementation starts after stacking merge 1146abc847f6946c268d67ef319a8fd83e7c8874; later main syncs, including 0c95de36943, 89ffd1cc68c, and e0e04d71063, remain in history. The final sync merges main 1617ff32eff18756c2a39d63f9512cbe7ac0f692 into the reviewed head e0e04d7106358493503ec729174248efb46e887c in merge commit 91fc85018e9685b6206adf17c3d2122c523eab21. History is preserved without rebasing or force-pushing.

This final sync adds no feature beyond the changes already on main. It preserves main's paired-server attachment support (#25146), including pending file chips, host previews, and uploads that finish while a prompt card replaces the composer, alongside PR3's element-owned drop delivery.

What Changed

  • Each chat pane captures its pane, draft, session, workspace and host before file preparation and rechecks the destination after file reads, SSH upload and composition settlement. Hidden mounted chats cannot receive the drop. File/HTML drags attach files without inserting HTML. Availability comes from the live child composer; floating chat keeps its explicitly local ownership rule without needing a workspace catalog row.
  • Workspace cards capture the selected project path and host when they have an attachment destination. Mounting another card cannot take their pending drop; changing project, host or SSH connection invalidates it. Folder projects use their recorded folder path, even when their task-source repository is elsewhere.
  • QA I1: a single OS drop attaches exactly once on normal composition commit, double commit, cancellation, or blur. The two mentions reported by QA are not reproduced as duplicate delivery of one drop; that run also contained an earlier drop during an irregular composition. A separate queue-lifetime bug is confirmed: starting another composition without ending the first left its drop queued for a later composition. The field now settles the interrupted composition, including its queued attachments, synchronously before the new composition takes ownership. No deduplication hides separate legitimate drops, and the captured-destination check and whole-batch rejection remain in place. These DOM tests establish the defect and fix; they do not establish the exact cause of the historical Electron gesture.
  • QA W1: main's legacy OS drop does apply the file to quick-create's attachment state. A test mounting the real card with a selected local project against main's card, preload and legacy listener confirms that behavior. However, the card has no attachment display or agent prompt, and main's quick-create and folder-create launch paths do not consume that attachment state: there is no usable attachment destination. This PR takes the approved refusal alternative. Quick-create omits the attachment callback; the owner requires both a project/host and that callback, and the ring uses the same acceptance condition. Dropping attaches nothing, calls no preparation API, and shows dropEffect = none without a toast. Full composer attachment destinations retain element-owned delivery.
  • Feedback reads image bytes on the dialog content. Images attach once on desktop and web; non-image files are claimed and ignored without opening an editor behind the dialog.
  • Remove the chat broadcast subscriber, chat routing markers, workspace composer listener and mount-order stack. Keep the paperclip picker, editor/draft keys, internal-drag provenance checks, screenshot preparation and upload logic. Terminal, explorer, sidebar, tab-strip and editor delivery stay on their existing routes in this PR.
  • Merge resolutions: keep PR3's live boolean/function availability check in use-os-file-drop-owner.ts and its refused-drop regression test; main contains PR2's older boolean-only version. In feedback-drop tests, keep the element-owner assertion and omit main's now-obsolete comment describing window capture. Main's other changes remain, including the new resume test. Remove that test's obsolete dropScopeKey prop because PR3 removed it from the field; composerScopeKey and draftScopeKey are untouched.
  • Latest merge resolution (main a3ecee0dce1): the only text conflict was the import list of NativeChatComposerField.tsx; it keeps PR3's flushSync import (used to settle an interrupted composition) and drops the ImageOff icon import, because main replaced the old one-line attachment notice with its notice card. Everything else from both sides stays: no drop-scope prop or drop-routing markers on the field, and main's notice card and @-file suggestion menu render as on main. PR3's own composition-drop test was updated to main's new field props (the notice list from main's real notice hook, and the @-file suggestion props); no production code changed in this merge beyond the import line.
  • Final sync resolutions (main 1617ff32eff1, merge 91fc85018e9):
    • native-chat-attachment-upload.ts: retain PR3's explicit host lookup, shared local-floating-workspace rule, and folder-aware destination; add main's paired-server session owner, capability check, and upload functions. The focused runtime never becomes a fallback destination.
    • use-native-chat-external-attachments.ts: keep the destination captured before file preparation and all destinationIsCurrent checks; run main's paired-server upload through that captured delivery. Pending chips still settle into their captured chat while its composer is unmounted, as on main; a changed destination refuses them. Local reads and SSH uploads retain their mounted-composer checks.
    • Auto-merged NativeChatComposer.tsx and NativeChatComposerField.tsx: keep main's pending chips, attachment host previews, hidden rich-text image chips, Send hold, and prompt recall, together with PR3's element-owner hook and interrupted-composition settlement. Neither the old broadcast subscriber nor the field's drop-routing markers return.
    • Auto-merged attachment-upload and drop-scope tests: retain both sides' cases and main's pending-chip controls. Update PR3's floating-drop and composition-drop fixtures to pass those controls.
    • New checks cover a captured paired-server drop becoming obsolete before delivery or during upload, its upload settling while the composer is unmounted, and the accepting chat's “Drop to attach to this chat” drag-over overlay. git grep -n dropScopeKey is empty, and production chat/composer code has no onFileDrop subscriber. Folder-project attachment destinations remain the recorded folder path.

Why

The browser identifies the element receiving a drop. Binding delivery to that element's captured destination removes the need for every mounted composer to reconstruct ownership from a window-wide broadcast. Ending an interrupted composition before a replacement begins gives its attachment queue a definite end. Refusing the prompt-less quick-create card avoids accepting files into state that cannot be shown or delivered.

Differences from the common pattern:

  • Intended: capture listeners run before descendant editors, and the closest registered element chooses between nested chat and terminal surfaces.
  • Intended: path attachments retain main-process screenshot copies and downstream SSH upload; feedback retains its image-byte path.
  • Intended: quick-create refuses files because it has no attachment destination; composers with a destination retain file attachment. No new notice is added.
  • Intended: only an interrupted composition restart synchronously commits settlement before the browser starts the replacement composition. Ordinary composition events retain their existing path.
  • Intended: cancellation-only navigation guards support the web build.
  • Temporary: preload's release rule and legacy routing markers remain until PR6. PR4 migrates terminals and title bars; PR5 migrates explorer, project sidebar, tab strips and editor areas; PR6 removes the remaining broadcast/drop-routing machinery.
  • Temporary: web chat still refuses path attachments, and terminal-backed chat on a paired server still refuses client-local paths. Main now supports attachments in structured chats on paired servers; this merge preserves that support. Browser file-byte delivery remains a separate follow-up. Feedback's byte attachments work on web now.

Linked Issue

STA-6940

Visual Proof

Separate QA agents ran this branch as a hidden Orca dev window with an isolated profile, native chat and structured native chat on, and simulated OS file drops through the Chrome DevTools Protocol. The chats were confirmed to be restructured Claude chats (structured agent sessions, no terminal). The first run was on head ff58070250; a second run re-checked the two fixes on head c62129a7dfe.

1. A drop on chat B leaves chat A untouched. After a file was dropped on the other chat, chat A still holds only its own dropped file and image.

Chat A unchanged after a drop on chat B

2. Image paste from the real clipboard. Exactly one pasted image (blue) is added next to the dropped one.

Image paste into the chat

3. Feedback dialog. A dropped image attaches to the form; a text file dropped on the dialog afterwards no longer opens in the editor behind it.

Feedback dialog after an image and a text-file drop

4. Drop during a restarted input-method composition (fix). The file dropped during the first composition is attached exactly once, and does not reappear after a later composition.

File attached once after a composition restart

5. New-workspace card (fix). Dragging a file over the quick-create card no longer shows an accepting drop ring; dropping it attaches nothing.

New-workspace card refusing a drag

Not covered: a chat in the "cannot take files" state (not reachable through the UI; covered by DOM tests), real SSH, WSL and remote-runtime hosts, Linux and Windows.

Testing

  • I manually tested these changes locally
  • Automated tests added/updated

Final sync at 91fc85018e9: 84 explicitly named files, 791 tests passed. Every file was checked to exist before running ORCA_BACKGROUND_LAUNCH=1 bash /tmp/sta-6940-pr3-tests.sh; that script uses a Bash file array and node_modules/.bin/vitest run --config config/vitest.config.ts. The list includes the full prior 58-file PR3 suite and main's changed attachment, pending-chip, composer, draft, prompt-recall, and lifecycle tests. The final sync adds four regression cases within the existing test files; no app was launched.

Exact named Vitest files
src/renderer/src/components/native-chat/native-chat-element-file-drop.test.tsx
src/renderer/src/components/native-chat/native-chat-floating-file-drop.test.tsx
src/renderer/src/components/NewWorkspaceComposerCard.file-drop.test.tsx
src/renderer/src/components/native-chat/native-chat-composer-drop-scope.test.tsx
src/renderer/src/components/native-chat/native-chat-external-attachments-destination.test.tsx
src/renderer/src/components/native-chat/use-native-chat-external-attachments.test.tsx
src/renderer/src/components/terminal-pane/TerminalPaneHeaderOverlay.test.tsx
src/renderer/src/components/terminal-pane/terminal-drop-handler.test.ts
src/renderer/src/components/terminal-pane/terminal-drop-internal-handler.test.ts
src/renderer/src/components/terminal-pane/terminal-drop-local-workspace.test.ts
src/renderer/src/components/terminal-pane/terminal-drop-pane-resolution.test.ts
src/renderer/src/components/terminal-pane/terminal-drop-runtime-catalog-owner.test.ts
src/renderer/src/components/terminal-pane/terminal-drop-transport-owner.test.ts
src/renderer/src/components/terminal-pane/terminal-drop-worktree-path.test.ts
src/renderer/src/components/terminal-pane/use-terminal-pane-global-effects-file-drop.test.ts
src/main/window/dropped-path-preparation.test.ts
src/main/window/native-file-drop-relay.test.ts
src/preload/app-restart-checkpoint-routing.test.ts
src/preload/preload-native-file-drop-release.test.ts
src/renderer/src/components/automations/automation-editor-prompt-options.test.ts
src/renderer/src/components/sidebar/WorktreeList.status-lane-lineage-drop.test.tsx
src/renderer/src/components/sidebar/use-feedback-image-drop.test.tsx
src/renderer/src/components/sidebar/workspace-status.test.ts
src/renderer/src/hooks/use-os-file-drop-owner.test.tsx
src/renderer/src/lib/os-file-drop-cancellation-guard.test.ts
src/renderer/src/lib/os-file-drop-preload-integration.test.tsx
src/renderer/src/web/web-preload-api-filesystem.test.ts
src/renderer/src/components/native-chat/native-chat-pane-file-drop.test.tsx
src/renderer/src/components/native-chat/native-chat-composer-workspace-file-drop.test.tsx
src/renderer/src/components/native-chat/native-chat-view-file-drop.test.tsx
src/renderer/src/components/native-chat/native-chat-attachment-upload.test.ts
src/renderer/src/hooks/composer-state/attachment-drop-lifetime.test.tsx
src/renderer/src/hooks/composer-state/attachment-drop-failure.test.tsx
src/renderer/src/hooks/composer-native-file-drop.test.ts
src/renderer/src/components/native-chat/native-chat-composer-autogrow.test.tsx
src/renderer/src/components/native-chat/native-chat-composer-composition.test.tsx
src/renderer/src/components/NewWorkspaceComposerCard.test.tsx
src/renderer/src/components/NewWorkspaceComposerCard.start-from.test.tsx
src/renderer/src/components/NewWorkspaceComposerCard.set-location.test.tsx
src/renderer/src/components/NewWorkspaceComposerCard.set-location-warm.test.tsx
src/renderer/src/hooks/composer-drop-result.test.ts
src/renderer/src/hooks/composer-state/composer-attachment-target.test.ts
src/renderer/src/web/web-preload-api-composition.test.ts
config/scripts/vitest-sqlite-runtime-boundary.test.ts
src/renderer/src/components/native-chat/use-native-chat-file-attachment-actions.test.tsx
src/renderer/src/hooks/useComposerState.integration.test.ts
src/renderer/src/components/native-chat/native-chat-composer-field-resume.test.tsx
src/renderer/src/components/native-chat/native-chat-composer-ime-file-drop.test.tsx
src/renderer/src/components/NewWorkspaceComposerCard.quick-file-drop.test.tsx
src/renderer/src/components/native-chat/NativeChatComposerNotices.test.tsx
src/renderer/src/components/native-chat/NativeChatStructuredSession.notice-card.test.tsx
src/renderer/src/components/native-chat/native-chat-structured-send-composition-clear.test.tsx
src/renderer/src/components/native-chat/native-chat-structured-session-notices.command-failure.test.tsx
src/renderer/src/components/native-chat/structured-child-records-switch.test.tsx
src/renderer/src/components/native-chat/use-native-chat-composer-notice.test.tsx
src/renderer/src/components/native-chat/use-native-chat-structured-composer-send.test.tsx
src/renderer/src/components/native-chat/NativeChatAutocompleteMenus.test.tsx
src/renderer/src/components/native-chat/use-native-chat-mention-files.test.tsx
src/renderer/src/components/native-chat/NativeChatComposer.paste-remount.test.tsx
src/renderer/src/components/native-chat/NativeChatComposer.test.tsx
src/renderer/src/components/native-chat/NativeChatContextUsageRing.test.tsx
src/renderer/src/components/native-chat/NativeChatImageAttachmentPreview.test.tsx
src/renderer/src/components/native-chat/NativeChatStructuredSession.launch-lifecycle.test.tsx
src/renderer/src/components/native-chat/NativeChatStructuredSession.test.tsx
src/renderer/src/components/native-chat/native-chat-composer-draft-lifecycle.test.tsx
src/renderer/src/components/native-chat/native-chat-composer-draft-store.test.ts
src/renderer/src/components/native-chat/native-chat-composer-prompt-recall.test.tsx
src/renderer/src/components/native-chat/native-chat-pending-attachment-cache.test.ts
src/renderer/src/components/native-chat/native-chat-queue-send-confirm.test.tsx
src/renderer/src/components/native-chat/native-chat-submission-navigation.test.tsx
src/renderer/src/components/native-chat/structured-agent-session-message-hand-back.test.ts
src/renderer/src/components/native-chat/use-native-chat-composer-attachments.test.tsx
src/renderer/src/components/native-chat/use-native-chat-composer-catalog.test.tsx
src/renderer/src/components/native-chat/use-native-chat-composer-image-input.test.tsx
src/renderer/src/components/native-chat/use-native-chat-composer-keydown.steer.test.tsx
src/renderer/src/components/native-chat/use-native-chat-composer-keydown.test.tsx
src/renderer/src/components/native-chat/use-native-chat-composer-paste-session-attachments.test.tsx
src/renderer/src/components/native-chat/use-native-chat-composer-submit.test.tsx
src/renderer/src/components/native-chat/use-structured-agent-session-legacy-recovery.test.tsx
src/renderer/src/components/native-chat/use-structured-agent-session.clear-send.test.tsx
src/renderer/src/components/native-chat/use-structured-native-chat-pane-commands.test.tsx
src/renderer/src/lib/structured-agent-session-empty-chat-reuse.test.ts
src/renderer/src/store/slices/native-chat-launch-draft-teardown.test.ts
src/renderer/src/store/slices/workspace-chat-draft-removal.test.ts

Regression evidence:

  • Both new regression files run against production code from head ff58070250088eb5d0709890060341fac2bf572c: 2 expected failures, 5 passes. The failed cases are composition restart without an end and quick-create's accepting cursor; the five normal/double/cancel/blur composition cases already pass. Both files pass after the fixes.
  • A separate test of the real selected-local-project card against origin/main's card, preload, attachment handler and legacy listener passed: one OS file drop stored /drop/notes.txt in quick-create's otherwise-unused attachment state. Source inspection of the real footer, quick creation and folder creation confirms the missing display/delivery destination. Files were temporarily swapped for this check and restored before final verification.
  • Earlier migration checks remain recorded: PR1 + PR2 baseline 24 files / 206 tests passed, the initial migration had 10 expected failures across 3 named files before implementation, and the folder/floating/availability follow-up had 13 expected failures and 15 passes across 4 named files before its fixes. The previous maintenance at ff58070250 passed 46 files / 381 tests and full CI.

Final sync local checks: pnpm install --frozen-lockfile passed; deleted config/tsconfig.*.tsbuildinfo; pnpm tc:web and pnpm tc:node passed, one at a time. The first web check caught the two PR3 fixtures missing main's required pending-chip controls; both were corrected before the passing checks and 791-test run. Full oxlint on all 44 changed source files passed. pnpm run check:code-quality:changed passed with zero new findings before the commit; the pre-push CI checks also run it against the merged main base. pnpm run check:react-doctor:changed against the merged base passed with zero errors and four warnings (the card and composer complexity, sequential local-file reads, and synchronous composition settlement). Its pre-commit scan included main's unrelated changes because the merge was still pending; neither of its two unchanged-main errors is in PR3's final diff, and the final 44-file scan passes. pnpm's incidental @pnpm/exe block is restored, so the committed lockfile is unchanged. orca-ci-checks --no-typecheck passed all 22 checks before push, including localization verification, full repository lint, type-aware lint, and both changed-code gates against main 1617ff32eff1; the scoped typechecks above already passed.

Previous maintenance checks:

Previous maintenance checks: pnpm install --frozen-lockfile and deleted config/tsconfig.*.tsbuildinfo. After the first merge, pnpm tc:node passed but pnpm tc:web failed with one error that was on main itself, not from this PR: main's native-chat-composer-field-resume.test.tsx (added by #25835) still passed the onAcceptMention prop that #26017 had renamed. This PR did not carry that fix; once #26097 landed on main it was merged in, and on the final head 0c95de36943 pnpm tc:web and pnpm tc:node both pass. Full oxlint on all 43 changed source files passed; pnpm run check:code-quality:changed reported zero new findings; pnpm run check:react-doctor:changed on the 43 PR files reported zero errors, three warnings (the same as before). pnpm's incidental @pnpm/exe lockfile block was restored; there is no lockfile change.

Earlier maintenance also passed:

  • pnpm install --frozen-lockfile; deleted config/tsconfig.*.tsbuildinfo before checking.
  • pnpm tc:web, then pnpm tc:node, one at a time. The first web check caught two missing required props in the new test fixtures; the final checks both pass.
  • Full node_modules/.bin/oxlint on all 43 changed source files, including line limits; formatting and normal commit hooks passed. After CI caught a broad object parameter in the new card test, it was replaced with a named drag-transfer type; full lint and the anti-slop check then passed on all 46 currently changed source files, both new regression files passed (7 tests), and pnpm tc:web passed again.
  • pnpm run check:code-quality:changed: zero new findings against main d3e1494674f3.
  • pnpm run check:react-doctor:changed: zero errors, three warnings (card complexity, sequential file reads, and synchronous settlement skipping view transitions). The synchronous update occurs only at an irregular composition restart, where the old draft must be committed before the next composition owns the field.
  • No new user-visible copy or locale changes. Restored pnpm's incidental @pnpm/exe lockfile block; there is no lockfile change.

Current-head CI (91fc85018e9685b6206adf17c3d2122c523eab21): pending the final-sync push. It will be watched with one blocking gh pr checks 25781 --watch --fail-fast --interval 60 command; no live UI run is part of this maintenance.

Earlier full CI passed at 0c95de36943 in PR Checks run 37584573067, attempt 1, including all five unit-test shards. The prior main-only typecheck failure was fixed on main by #26097, then merged here; PR3 did not carry an independent main fix. These are historical results, not validation of the new merge head.

Local tests ran on macOS with ORCA_BACKGROUND_LAUNCH=1. No local app build or live Electron, Linux, Windows, WSL, SSH or remote-runtime session was exercised. Browser hit-testing across Electron's isolated worlds and real OS drag gestures remain unverified by this worker.

Review

The native chat scope suite retains authorization, owner-change and SSH-upload coverage. Composition tests mount the real field, editor, draft store, pane owner and attachment hooks. Quick-create tests mount the real card sections and use its real composer state with a selected local project. No new feature, documentation file, routing fallback or user-visible string is introduced. NativeChatComposer.tsx remains shorter than the main version merged here.

Agent skill upstream boundary

  • Not applicable; no upstream skill source is copied or translated.

Notes

PR1 and PR2 are merged; PR3 has no pending dependency and remains ready for review. The final main sync preserves both the reviewed drop migration and main's attachment behavior. This worker does not merge the PR. The quick-create refusal and interrupted-composition settlement remain the two explicitly requested QA fixes.

Checklist

  • This PR is focused on the three planned drop surfaces
  • I explained the problem, user-facing change, mechanism and alternatives
  • Before/after screenshots or videos attached for UI changes
  • Self-reviewed for correctness, security and performance
  • Cross-platform, SSH/remote and folder-workspace impact considered
  • Final-sync CI passes; local tests, typechecks and scoped quality checks pass, and live UI/platform limits are disclosed above

Preserve element-owned drops while integrating the upstream multi-file
paperclip picker and all-or-nothing attachment limit.

Resolve NativeChatComposer through its existing file-drop hook, keep the
host-qualified attachment resolver with the current workspace state type,
retain captured destinations and unmount checks through attachment reads
and uploads, and keep attachment actions picker-only without a broadcast
subscriber. Update picker fixtures and the upstream subscriber test.

Validation: web and Node typechecks, full Oxlint on 39 PR3 files, and
372 tests across 45 explicitly named files pass.
@brennanb2025

Copy link
Copy Markdown
Contributor Author

Review summary

This PR went through an independent code review, a fix round, a re-review, a review of its merge resolutions, two rendered checks in a real Orca window, and a second fix round for what the rendered check found. The reviewers and the rendered-check agents did not write the code. Their reports are summarized here because they were kept off GitHub while the work was in progress.

First review (head 015f710ea39): four findings

  1. Folder projects uploaded into the wrong directory (serious). Dropping a file on the new-workspace card for a folder project sent it into the project's task source repository instead of the folder itself.
  2. Native chat in the floating terminal lost file drops and the paperclip picker (serious). The floating workspace intentionally has no catalog entry, so the chat said "Worktree not ready" and attached nothing.
  3. A refusal message that could never appear. A chat that cannot take files ends the drag with the "not allowed" cursor, so no drop event ever arrives to show the message.
  4. Stale availability. After a chat's composer was disabled and re-enabled, the drop target could keep refusing until something else re-rendered.

Fixes (head 036f0db1312), re-review: approved

  1. The destination path now follows what is selected: a folder project uses its folder.
  2. The floating workspace is treated as local through the existing rule, before any catalog lookup.
  3. The message was removed: a chat that cannot take files right now shows only the "not allowed" cursor, which is how drops with no target behave everywhere else.
  4. Availability is read when the drag happens.

Bringing the branch up to date

Merging PR 2 and newer main hit four conflicts in the chat attachment code, where this PR's element-owned drops met main's new multi-file picker and attachment limit. A separate review checked each resolution (git show --remerge-diff) and approved: both behaviours are kept, and no second attachment path or old broadcast subscriber came back. One test that asserted the old broadcast subscription was updated, because this PR deletes that subscription. A newer main test still passed the removed dropScopeKey prop; it was updated too.

Rendered check (head ff58070250): two problems found, both fixed (head c62129a7dfe)

  1. A drop during input-method composition could be delivered late. If a composition was restarted before it ended, the drop queued during it was stranded and only delivered by the next composition, which looked like a duplicate. It is now delivered before the new composition starts.
  2. The new-workspace card showed an accepting drop ring but did nothing. On main the quick-create card stores a dropped file in attachment state it never uses, so the drop silently goes nowhere. The card now refuses the drop with the "not allowed" cursor and no ring.

A second rendered check on head c62129a7dfe confirmed both fixes; screenshots are in the description.

Not verified

  • Two chats in one workspace could not be opened in the second rendered check, because this build keeps one Claude chat tab per workspace. Hidden-chat isolation is shown from the first rendered check.
  • A chat in the "cannot take files" state could not be produced through the UI, since the composer stays usable while Claude works; it is covered by DOM-level tests.
  • Real SSH, WSL and remote-runtime hosts, Linux and Windows.

@brennanb2025
brennanb2025 marked this pull request as ready for review October 7, 2026 06:11
@coderabbitai

coderabbitai Bot commented Oct 7, 2026 •

Copy link
Copy Markdown
Contributor

Review in Change Stack →

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration
  • Configuration used: Repository UI
  • Review profile: CHILL
  • Plan: Advanced
  • Run ID: 68b6d41b-d3b3-45cb-a1be-caeb3dd345f3
📥 Commits

Reviewing files that changed from the base of the PR and between e0e04d7 and 91fc850.

📒 Files selected for processing (10)
  • src/renderer/src/components/native-chat/NativeChatComposer.tsx
  • src/renderer/src/components/native-chat/NativeChatComposerField.tsx
  • src/renderer/src/components/native-chat/native-chat-attachment-upload.test.ts
  • src/renderer/src/components/native-chat/native-chat-attachment-upload.ts
  • src/renderer/src/components/native-chat/native-chat-composer-drop-scope.test.tsx
  • src/renderer/src/components/native-chat/native-chat-composer-ime-file-drop.test.tsx
  • src/renderer/src/components/native-chat/native-chat-element-file-drop.test.tsx
  • src/renderer/src/components/native-chat/native-chat-floating-file-drop.test.tsx
  • src/renderer/src/components/native-chat/use-native-chat-external-attachments.test.tsx
  • src/renderer/src/components/native-chat/use-native-chat-external-attachments.ts

Included review availability: This review used your included allowance. Your plan provides up to 10 included reviews per hour; 3 remain after this review.


📝 Walkthrough

Walkthrough

The changes add element-owned file-drop handling for workspace composers, native chat panes, and the feedback dialog. Drop processing captures a destination and checks ownership or connection state before applying prepared paths. Native chat attachment ownership now resolves from known worktrees and execution hosts. The changes also add tests for destination changes, drop ownership, rejected drops, and file drops during composition.

Priority: ➖ Normal

Merge Risk: ⚪ Minimal · up to 91fc8

The change moves file drops to element-owned handlers with destination and ownership checks, and it adds tests. No concrete merge-blocking risk was identified in the supplied files.

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 19.23% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 52 functions across 41 files. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Title check ✅ Passed The title clearly identifies the main change: element-level file-drop delivery for chat, workspace composers, and feedback. The issue identifier and PR sequence suffix add useful context without makin…
Description check ✅ Passed The description follows the repository template and provides the user impact, implementation details, rationale, linked issue, visual proof, testing results, limitations, review notes, and checklist s…
  • Fix all pre-merge checks with AI
✨ Finishing Touches 💡 1
📝 Generate docstrings 💡
  • Commit to this branch
  • Create a new PR
  • Autopilot · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

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.

Resolve NativeChatComposerField imports: keep PR3's flushSync (interrupted
composition settlement) and drop the old ImageOff notice import that main's
notice card replaced. Adapt PR3's IME file-drop test to main's notices and
@-file suggestion props.
Keep element-owned destinations alongside paired-server attachment uploads, pending chips, and composer remount settlement. Update fixtures for pending chips and cover destination changes and the accepting drag overlay.
@brennanb2025
brennanb2025 merged commit 2803be7 into main Oct 7, 2026
33 checks passed
@brennanb2025
brennanb2025 deleted the brennanb2025/sta-6940-pr3-chat-composer-feedback branch October 8, 2026 02:03
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant