From ed19e8c1346dc8243dba7018e67fb9039aa273e3 Mon Sep 17 00:00:00 2001 From: btipling Date: Sat, 22 Aug 2026 06:54:33 +0000 Subject: [PATCH 1/3] docs(harness): Shift+click select + copy for read-only textLayout bodies (plan #753) Verification-first outcome for plan #753: parent #752 (PR #762) already installed a shift_click extension branch on the shared TextLayoutWidget, so read-only transcript text (the same widget) already gets click-anchor + Shift+click extend + Ctrl/Cmd+C copy with no second seam. This PR is the living-docs hardening for that verified read-only path; no native/harness code change. - docs/harness-limits.md: Read-only body text Shift+click row in Transcript copy/paste + a desktop-only Keyboard & focus row; restate within-a-single- textLayout and cross-message unsupported; TEAL text_select, Ctrl/Cmd+C browser-reserved copy of the active range, plain-click clear, desktop-only. Fixes #753 (Refs #749, #752) --- docs/harness-limits.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/docs/harness-limits.md b/docs/harness-limits.md index 3291026..82d453f 100644 --- a/docs/harness-limits.md +++ b/docs/harness-limits.md @@ -63,6 +63,7 @@ closed). | **Ctrl+I** | Arm the **leader** prefix (800 ms). Within the window press **`?`** to toggle help; **Ctrl+I** re-arms (a bare `i` does **not** β€” it swallows and disarms); **`t`** toggles **thinking default-collapsed** (collapse thinking by default, including the active Busy turn; in-memory only, resets to on on reload/New/Clear); **Escape** cancels; an unmatched key swallows (never lands in the prompt); a reserved browser chord (Ctrl+Shift+I Inspect) still yields to the browser | | Tab / Ctrl+Left / Ctrl+Right | DOM nav / text caret (not harness chords; Ctrl+Left/Right are word-jumps, left to the textEntry) | | **Shift+click** (composer / queue-row editor focused; desktop only) | **Range-selects** the text in that `textEntry` field β€” a stock web behavior the canvas was missing. Click to place the caret (or drag-select a base range), then **Shift+click** to extend the selection from an anchor edge to the clicked point; further Shift+clicks keep extending from the same anchor edge, and a Shift+click never counts toward the next word/line double-click. The range uses the **existing TEAL `text_select` fill** (no new hex). **Ctrl/Cmd+C** then copies that substring to the system clipboard (the chord stays browser-reserved). A **plain** (non-shift) click still moves the caret and clears the range. Touch/mobile has no shift key β€” **πŸ“‹** stays the reliable copy path and canvas Shift+click is documented desktop-only | +| **Shift+click** (read-only body text; desktop only) | **Range-selects** text inside a single **read-only** `textLayout` (transcript rich-MD bodies, fenced code, thinking/preview/skill rows): a plain click anchors, **Shift+click** extends the highlighted range from that anchor, and **Ctrl/Cmd+C** copies the active slice. Selection never spans two `textLayout`s / messages. See Transcript copy / paste β†’ Read-only body text Shift+click | | Composer focus | Requested on ready and after each send | ## Touch / mobile (~390px) @@ -202,7 +203,8 @@ see Group boundaries). | Clipboard payload | **Message source** UTF-8 as stored in the Wasm ring (markdown as produced) β€” not re-serialized paint colors or β€œβ€¦ N more” chrome | | Drag-select | Best-effort **within a single** `textLayout` only (rich MD is many widgets per body). Whole-reply drag-select is not the product path | | Cross-message selection | Not supported | -| Composer / queue-row editor Shift+click | Desktop **Shift+click** range-selects within the focused **editable** `textEntry` field (composer or queue-row editor), and **Ctrl/Cmd+C** copies that substring. In-canvas **read-only** `textLayout` (rich MD is many widgets per body) is still single-`textLayout`-bounded drag-select only β€” Shift+click there is a tracked child follow-up, not this surface | +| Composer / queue-row editor Shift+click | Desktop **Shift+click** range-selects within the focused **editable** `textEntry` field (composer or queue-row editor), and **Ctrl/Cmd+C** copies that substring | +| Read-only body text Shift+click | Desktop **Shift+click** range-selects inside a single **read-only** `textLayout` (transcript rich-MD bodies, fenced code, thinking/preview/skill rows, tool-run detail): a plain left click sets an anchor, then **Shift+click** extends the highlighted range from that anchor to the clicked point inside the **same widget** (further Shift+clicks keep extending from the same anchor edge; a Shift+click never counts toward the next word/line double-click). Highlight uses the **existing TEAL `text_select` fill** β€” no new hex. **Ctrl/Cmd+C** copies the active slice to the system clipboard (the chord stays browser-reserved; an empty range copies nothing). Selection stays **within one** `textLayout` β€” rich MD is many widgets per body β€” and a Shift+click in a **different** widget never spans (cross-message / cross-widget selection stays unsupported). A plain (non-shift) click clears the range and sets a new anchor. **πŸ“‹** stays the reliable copy path everywhere; canvas Shift+click is **desktop-only** (touch has no shift key) | | Composer paste | Supported via dvui text entry when the composer is focused. Composer is **multi-line** β€” pasted newlines are preserved; submission is normalized (CRLF β†’ LF) and clamped to the prompt submit cap (`SUBMIT_CAP`). Leading whitespace / blank first lines in a paste are **preserved** on submit (not stripped); only a wholly blank/whitespace prompt is rejected | | Mobile / touch | **πŸ“‹** (copy) is the supported path; multi-block drag-select on canvas is unreliable | | Secure context | System clipboard write needs https (or localhost); silent no-op possible if the browser blocks clipboard | From 84da4d967a133660bad6d398b240499e02055244 Mon Sep 17 00:00:00 2001 From: btipling Date: Sat, 22 Aug 2026 07:06:59 +0000 Subject: [PATCH 2/3] docs(harness): exclude links from read-only Shift+click select (plan #753, adv-review L1/L6/L8/L1) --- docs/harness-limits.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/harness-limits.md b/docs/harness-limits.md index 82d453f..bbec6a6 100644 --- a/docs/harness-limits.md +++ b/docs/harness-limits.md @@ -63,7 +63,7 @@ closed). | **Ctrl+I** | Arm the **leader** prefix (800 ms). Within the window press **`?`** to toggle help; **Ctrl+I** re-arms (a bare `i` does **not** β€” it swallows and disarms); **`t`** toggles **thinking default-collapsed** (collapse thinking by default, including the active Busy turn; in-memory only, resets to on on reload/New/Clear); **Escape** cancels; an unmatched key swallows (never lands in the prompt); a reserved browser chord (Ctrl+Shift+I Inspect) still yields to the browser | | Tab / Ctrl+Left / Ctrl+Right | DOM nav / text caret (not harness chords; Ctrl+Left/Right are word-jumps, left to the textEntry) | | **Shift+click** (composer / queue-row editor focused; desktop only) | **Range-selects** the text in that `textEntry` field β€” a stock web behavior the canvas was missing. Click to place the caret (or drag-select a base range), then **Shift+click** to extend the selection from an anchor edge to the clicked point; further Shift+clicks keep extending from the same anchor edge, and a Shift+click never counts toward the next word/line double-click. The range uses the **existing TEAL `text_select` fill** (no new hex). **Ctrl/Cmd+C** then copies that substring to the system clipboard (the chord stays browser-reserved). A **plain** (non-shift) click still moves the caret and clears the range. Touch/mobile has no shift key β€” **πŸ“‹** stays the reliable copy path and canvas Shift+click is documented desktop-only | -| **Shift+click** (read-only body text; desktop only) | **Range-selects** text inside a single **read-only** `textLayout` (transcript rich-MD bodies, fenced code, thinking/preview/skill rows): a plain click anchors, **Shift+click** extends the highlighted range from that anchor, and **Ctrl/Cmd+C** copies the active slice. Selection never spans two `textLayout`s / messages. See Transcript copy / paste β†’ Read-only body text Shift+click | +| **Shift+click** (read-only body text; desktop only) | **Range-selects** text inside a single **read-only** `textLayout` (transcript rich-MD bodies, fenced code, thinking/preview/skill rows, tool-run detail): a plain click anchors, **Shift+click** extends the highlighted range from that anchor, and **Ctrl/Cmd+C** copies the active slice. **A link is still a link first** β€” a **Shift+click (or plain click) on a link inside a body navigates / copies per the [Links] row and does *not* extend the range**; Shift+click range-selection is for non-link body text (use πŸ“‹ for reliable body copy). Selection never spans two `textLayout`s / messages. See Transcript copy / paste β†’ Read-only body text Shift+click | | Composer focus | Requested on ready and after each send | ## Touch / mobile (~390px) @@ -204,7 +204,7 @@ see Group boundaries). | Drag-select | Best-effort **within a single** `textLayout` only (rich MD is many widgets per body). Whole-reply drag-select is not the product path | | Cross-message selection | Not supported | | Composer / queue-row editor Shift+click | Desktop **Shift+click** range-selects within the focused **editable** `textEntry` field (composer or queue-row editor), and **Ctrl/Cmd+C** copies that substring | -| Read-only body text Shift+click | Desktop **Shift+click** range-selects inside a single **read-only** `textLayout` (transcript rich-MD bodies, fenced code, thinking/preview/skill rows, tool-run detail): a plain left click sets an anchor, then **Shift+click** extends the highlighted range from that anchor to the clicked point inside the **same widget** (further Shift+clicks keep extending from the same anchor edge; a Shift+click never counts toward the next word/line double-click). Highlight uses the **existing TEAL `text_select` fill** β€” no new hex. **Ctrl/Cmd+C** copies the active slice to the system clipboard (the chord stays browser-reserved; an empty range copies nothing). Selection stays **within one** `textLayout` β€” rich MD is many widgets per body β€” and a Shift+click in a **different** widget never spans (cross-message / cross-widget selection stays unsupported). A plain (non-shift) click clears the range and sets a new anchor. **πŸ“‹** stays the reliable copy path everywhere; canvas Shift+click is **desktop-only** (touch has no shift key) | +| Read-only body text Shift+click | Desktop **Shift+click** range-selects inside a single **read-only** `textLayout` (transcript rich-MD bodies, fenced code, thinking/preview/skill rows, tool-run detail): a plain left click sets an anchor, then **Shift+click** extends the highlighted range from that anchor to the clicked point inside the **same widget** (further Shift+clicks keep extending from the same anchor edge; a Shift+click never counts toward the next word/line double-click). Highlight uses the **existing TEAL `text_select` fill** β€” no new hex. **Ctrl/Cmd+C** copies the active slice to the system clipboard (the chord stays browser-reserved); an **empty range (caret-only) is an empty write** β€” it can blank the clipboard, so select a range before copying or use πŸ“‹. **Links are links first:** a **plain or Shift+click on a link** inside a read-only body **navigates / copies per the [Links] row** and does **not** extend the range β€” Shift+click range-selection is for non-link body text (use πŸ“‹ for reliable copy of link-heavy bodies). Selection stays **within one** `textLayout` β€” rich MD is many widgets per body β€” and a Shift+click in a **different** widget never spans (cross-message / cross-widget selection stays unsupported). A plain (non-shift) click clears the range and sets a new anchor. **πŸ“‹** stays the reliable copy path everywhere; canvas Shift+click is **desktop-only** (touch has no shift key) | | Composer paste | Supported via dvui text entry when the composer is focused. Composer is **multi-line** β€” pasted newlines are preserved; submission is normalized (CRLF β†’ LF) and clamped to the prompt submit cap (`SUBMIT_CAP`). Leading whitespace / blank first lines in a paste are **preserved** on submit (not stripped); only a wholly blank/whitespace prompt is rejected | | Mobile / touch | **πŸ“‹** (copy) is the supported path; multi-block drag-select on canvas is unreliable | | Secure context | System clipboard write needs https (or localhost); silent no-op possible if the browser blocks clipboard | From b6ab66b16e982345627985a023538e4f38a42ed4 Mon Sep 17 00:00:00 2001 From: btipling Date: Sat, 22 Aug 2026 08:07:32 +0000 Subject: [PATCH 3/3] docs: fix dangling [Links] shortcut refs to **Links** row (round 3 Review Nit) --- docs/harness-limits.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/harness-limits.md b/docs/harness-limits.md index bbec6a6..c3afaf0 100644 --- a/docs/harness-limits.md +++ b/docs/harness-limits.md @@ -63,7 +63,7 @@ closed). | **Ctrl+I** | Arm the **leader** prefix (800 ms). Within the window press **`?`** to toggle help; **Ctrl+I** re-arms (a bare `i` does **not** β€” it swallows and disarms); **`t`** toggles **thinking default-collapsed** (collapse thinking by default, including the active Busy turn; in-memory only, resets to on on reload/New/Clear); **Escape** cancels; an unmatched key swallows (never lands in the prompt); a reserved browser chord (Ctrl+Shift+I Inspect) still yields to the browser | | Tab / Ctrl+Left / Ctrl+Right | DOM nav / text caret (not harness chords; Ctrl+Left/Right are word-jumps, left to the textEntry) | | **Shift+click** (composer / queue-row editor focused; desktop only) | **Range-selects** the text in that `textEntry` field β€” a stock web behavior the canvas was missing. Click to place the caret (or drag-select a base range), then **Shift+click** to extend the selection from an anchor edge to the clicked point; further Shift+clicks keep extending from the same anchor edge, and a Shift+click never counts toward the next word/line double-click. The range uses the **existing TEAL `text_select` fill** (no new hex). **Ctrl/Cmd+C** then copies that substring to the system clipboard (the chord stays browser-reserved). A **plain** (non-shift) click still moves the caret and clears the range. Touch/mobile has no shift key β€” **πŸ“‹** stays the reliable copy path and canvas Shift+click is documented desktop-only | -| **Shift+click** (read-only body text; desktop only) | **Range-selects** text inside a single **read-only** `textLayout` (transcript rich-MD bodies, fenced code, thinking/preview/skill rows, tool-run detail): a plain click anchors, **Shift+click** extends the highlighted range from that anchor, and **Ctrl/Cmd+C** copies the active slice. **A link is still a link first** β€” a **Shift+click (or plain click) on a link inside a body navigates / copies per the [Links] row and does *not* extend the range**; Shift+click range-selection is for non-link body text (use πŸ“‹ for reliable body copy). Selection never spans two `textLayout`s / messages. See Transcript copy / paste β†’ Read-only body text Shift+click | +| **Shift+click** (read-only body text; desktop only) | **Range-selects** text inside a single **read-only** `textLayout` (transcript rich-MD bodies, fenced code, thinking/preview/skill rows, tool-run detail): a plain click anchors, **Shift+click** extends the highlighted range from that anchor, and **Ctrl/Cmd+C** copies the active slice. **A link is still a link first** β€” a **Shift+click (or plain click) on a link inside a body navigates / copies per the **Links** row and does *not* extend the range**; Shift+click range-selection is for non-link body text (use πŸ“‹ for reliable body copy). Selection never spans two `textLayout`s / messages. See Transcript copy / paste β†’ Read-only body text Shift+click | | Composer focus | Requested on ready and after each send | ## Touch / mobile (~390px) @@ -204,7 +204,7 @@ see Group boundaries). | Drag-select | Best-effort **within a single** `textLayout` only (rich MD is many widgets per body). Whole-reply drag-select is not the product path | | Cross-message selection | Not supported | | Composer / queue-row editor Shift+click | Desktop **Shift+click** range-selects within the focused **editable** `textEntry` field (composer or queue-row editor), and **Ctrl/Cmd+C** copies that substring | -| Read-only body text Shift+click | Desktop **Shift+click** range-selects inside a single **read-only** `textLayout` (transcript rich-MD bodies, fenced code, thinking/preview/skill rows, tool-run detail): a plain left click sets an anchor, then **Shift+click** extends the highlighted range from that anchor to the clicked point inside the **same widget** (further Shift+clicks keep extending from the same anchor edge; a Shift+click never counts toward the next word/line double-click). Highlight uses the **existing TEAL `text_select` fill** β€” no new hex. **Ctrl/Cmd+C** copies the active slice to the system clipboard (the chord stays browser-reserved); an **empty range (caret-only) is an empty write** β€” it can blank the clipboard, so select a range before copying or use πŸ“‹. **Links are links first:** a **plain or Shift+click on a link** inside a read-only body **navigates / copies per the [Links] row** and does **not** extend the range β€” Shift+click range-selection is for non-link body text (use πŸ“‹ for reliable copy of link-heavy bodies). Selection stays **within one** `textLayout` β€” rich MD is many widgets per body β€” and a Shift+click in a **different** widget never spans (cross-message / cross-widget selection stays unsupported). A plain (non-shift) click clears the range and sets a new anchor. **πŸ“‹** stays the reliable copy path everywhere; canvas Shift+click is **desktop-only** (touch has no shift key) | +| Read-only body text Shift+click | Desktop **Shift+click** range-selects inside a single **read-only** `textLayout` (transcript rich-MD bodies, fenced code, thinking/preview/skill rows, tool-run detail): a plain left click sets an anchor, then **Shift+click** extends the highlighted range from that anchor to the clicked point inside the **same widget** (further Shift+clicks keep extending from the same anchor edge; a Shift+click never counts toward the next word/line double-click). Highlight uses the **existing TEAL `text_select` fill** β€” no new hex. **Ctrl/Cmd+C** copies the active slice to the system clipboard (the chord stays browser-reserved); an **empty range (caret-only) is an empty write** β€” it can blank the clipboard, so select a range before copying or use πŸ“‹. **Links are links first:** a **plain or Shift+click on a link** inside a read-only body **navigates / copies per the **Links** row** and does **not** extend the range β€” Shift+click range-selection is for non-link body text (use πŸ“‹ for reliable copy of link-heavy bodies). Selection stays **within one** `textLayout` β€” rich MD is many widgets per body β€” and a Shift+click in a **different** widget never spans (cross-message / cross-widget selection stays unsupported). A plain (non-shift) click clears the range and sets a new anchor. **πŸ“‹** stays the reliable copy path everywhere; canvas Shift+click is **desktop-only** (touch has no shift key) | | Composer paste | Supported via dvui text entry when the composer is focused. Composer is **multi-line** β€” pasted newlines are preserved; submission is normalized (CRLF β†’ LF) and clamped to the prompt submit cap (`SUBMIT_CAP`). Leading whitespace / blank first lines in a paste are **preserved** on submit (not stripped); only a wholly blank/whitespace prompt is rejected | | Mobile / touch | **πŸ“‹** (copy) is the supported path; multi-block drag-select on canvas is unreliable | | Secure context | System clipboard write needs https (or localhost); silent no-op possible if the browser blocks clipboard |