Hacktoberfest 2026:維護者為十月標記出來的 issue,仍然開放、適合新手。 瀏覽 Hacktoberfest issue

[Bug]: Cmd+C copies the entire conversation instead of the selection

已關閉
#116 2 則留言 1 個 reaction 已指派 0 人 在 GitHub 檢視

還沒有人認領這個 Issue。

評估

難度
4/5
預估耗時
3-5 天
新手友好度
72/100
Issue 類型
缺陷
描述清晰度
描述清楚
活躍度
活躍
技術堆疊
javascript
領域
desktop, frontend

研究方向

Start with the feed's copy listener and the Cmd+A and Mod+C handlers in the bundled renderer, then reproduce the issue with a tall expanded row and a selection inside it. Done means Cmd+C copies only the selection, explicit select-all still produces a transcript, and selections from the diff viewer's open shadow root do not trigger the transcript override.

由索引模型根據 Issue 內容生成。

描述

GUI version

0.1.40

Operating system

macOS (Apple silicon)

Reproduction steps
  1. Open a conversation in which a single chat row can fill the mounted window — e.g. a turn whose work trace is expanded, a turn containing a large inline diff, or a very long answer.
  2. Press Ctrl+O ("Expand or collapse all traces") to expand every trace, or click a turn's "Worked for … · N steps" line to expand just that turn.
  3. Select a few characters inside that turn. A small selection is enough; it does not need to span the conversation.
  4. Press Cmd+C and paste into any text editor.
Expected behavior

Cmd+C copies exactly the current selection. A whole-conversation transcript should only be produced by an explicit select-all action.

Actual behavior

The clipboard receives a plain-text transcript of the entire session — every message, each prefixed with User: / Assistant: — including messages that were never rendered on screen and were never part of the selection. The result is indistinguishable from the app's own select-all. Once it happens it repeats on every subsequent Cmd+C until the selection is cleared, because nothing clears the feed selection after the override.

Contributing factors, from reading the bundled renderer:

  • The feed installs a copy listener that builds a transcript of the whole message list and replaces the clipboard when a geometric predicate passes: the current DOM selection must partially contain (containsNode(row, true)) both the first and the last currently mounted [data-feed-row] element.
  • Because the feed is virtualized (increaseViewportBy: {top: 800, bottom: 800}), the mounted rows are only the viewport ± 800 px window. When one tall row fills that window, the first and last row are the same element, so any selection inside that row satisfies the predicate — even three characters. Tall rows are easy to produce: expanding a trace renders the full reasoning text, tool calls and output cards inside a single row.
  • The predicate is evaluated against the rendered window, but the payload is always the entire session. So the clipboard can contain messages that were never rendered, let alone selected.

Related, same root cause: Mod+C is bound to run.interrupt ("Stops the agent when nothing is selected; copies otherwise"), and the Cmd+A handler only skips INPUT / TEXTAREA / contentEditable targets. Key events originating inside a shadow root are retargeted to the host element, so pressing Cmd+A while focus is inside the diff viewer (diffs-container, an open shadow root) is not excluded — it selects the entire feed, which then trips the transcript override on the next Cmd+C.

Screenshots, recordings, or sanitized logs

Sanitized reconstruction of the predicate (minified identifiers omitted), verified in a stock Chromium 153 harness using the same DOM shape ([data-feed-row] rows inside a scroll container):

const sel = feedEl.ownerDocument.getSelection();
if (!sel || sel.rangeCount === 0 || sel.isCollapsed) return false;
const rows = feedEl.querySelectorAll("[data-feed-row]");
const first = rows[0], last = rows[rows.length - 1];
return sel.containsNode(first, true) && sel.containsNode(last, true);
setup predicate result
6 rows mounted, a few characters selected in a middle row false
6 rows mounted, selection spanning the first to the last mounted row true
1 row mounted (tall row), 3 characters selected inside it true
selection made inside an open shadow root false

Also verified: when the row containing the selection is unmounted, Chromium collapses the selection — so detached/stale selections are not the cause; the geometry alone is.

Fix direction: gate the transcript override on an explicit flag set by the app's own select-all handler instead of inferring intent from selection geometry; if geometry is kept, require full containment (containsNode(row, false)) and emit only the rows actually covered by the selection; clear the feed selection after an override; skip the override when the selection's range root is not the document.

Safety check
  • I removed credentials and private project information from this report.
主要語言
Shell
星號
85
分支
5
平均合併
2 小時 46 分鐘
30 天內合併 PR
1

環境準備

這個專案沒有提供開發容器、Dockerfile 或貢獻指南,環境需要你自己搭建:先看它的 README,通用步驟見我們的新手貢獻指南。

從這裡開始

  1. 先讀完整個 Issue,再讀專案的貢獻指南。
  2. 在 Issue 下留言說明你要接手 —— 這能避免兩個人做同樣的事。
  3. Fork 儲存庫,在一個分支上完成修改。
  4. 送出 Pull Request,並在描述裡引用這個 Issue 編號。

CommandCodeAI/desktop 的其他 Issue

查看 CommandCodeAI/desktop 的全部 Issue

相似的 Issue

更多 Shell/Bash Issue

把新 issue 寄到你的電子郵件信箱

精選適合新手參與的 GitHub issue 摘要。