diff --git a/.lane/memory/src/tools.ts/01M5CT5AR9NBSN9BZBSR9MQKXN-wire-2-text-is-what-native2.md b/.lane/attic/src/tools.ts/01M5CT5AR9NBSN9BZBSR9MQKXN-wire-2-text-is-what-native2.md similarity index 100% rename from .lane/memory/src/tools.ts/01M5CT5AR9NBSN9BZBSR9MQKXN-wire-2-text-is-what-native2.md rename to .lane/attic/src/tools.ts/01M5CT5AR9NBSN9BZBSR9MQKXN-wire-2-text-is-what-native2.md diff --git a/.lane/memory/native2/Sources/DesktopMac/WebText.swift/01M5D5AB2Y625F1Q2BN8VF36VS-safari-on-macos-27-dropped-a.md b/.lane/memory/native2/Sources/DesktopMac/WebText.swift/01M5D5AB2Y625F1Q2BN8VF36VS-safari-on-macos-27-dropped-a.md index 8dbee2b6..4fcb4b27 100644 --- a/.lane/memory/native2/Sources/DesktopMac/WebText.swift/01M5D5AB2Y625F1Q2BN8VF36VS-safari-on-macos-27-dropped-a.md +++ b/.lane/memory/native2/Sources/DesktopMac/WebText.swift/01M5D5AB2Y625F1Q2BN8VF36VS-safari-on-macos-27-dropped-a.md @@ -4,8 +4,9 @@ anchor: '@file' created: 2026-10-20T17:21:33Z norm: '1' sig: 1574ff353918c008 -body_hash: 334362b01e56eab9 -raw_hash: 3dd4db75427ff129 +body_hash: 6243d6c3b242a4db +raw_hash: 5bd16c78dfed21ca +vouched: 2026-10-20T17:37:48Z lines: 1-182 --- diff --git a/.lane/memory/native2/Sources/DesktopMac/WebText.swift/01M5D67S6R6K06W6RAC521M5X6-safari-focuses-its-address-f.md b/.lane/memory/native2/Sources/DesktopMac/WebText.swift/01M5D67S6R6K06W6RAC521M5X6-safari-focuses-its-address-f.md new file mode 100644 index 00000000..a16d620f --- /dev/null +++ b/.lane/memory/native2/Sources/DesktopMac/WebText.swift/01M5D67S6R6K06W6RAC521M5X6-safari-focuses-its-address-f.md @@ -0,0 +1,12 @@ +--- +id: 01M5D67S6R6K06W6RAC521M5X6 +anchor: '@file' +created: 2026-10-20T17:37:38Z +norm: '1' +sig: 1574ff353918c008 +body_hash: 6243d6c3b242a4db +raw_hash: 5bd16c78dfed21ca +lines: 1-191 +--- + +Safari focuses its address field when it opens a page in the background, so Copy after a marker selection copied the URL; focus the web area before selecting, since focusing can move the selection diff --git a/.lane/memory/scripts/live-check.mjs/01M5D313RP70TNMETX3F6PX3PD-one-argument-perl-system-spl.md b/.lane/memory/scripts/live-check.mjs/01M5D313RP70TNMETX3F6PX3PD-one-argument-perl-system-spl.md index 76f1d8d0..c1da392d 100644 --- a/.lane/memory/scripts/live-check.mjs/01M5D313RP70TNMETX3F6PX3PD-one-argument-perl-system-spl.md +++ b/.lane/memory/scripts/live-check.mjs/01M5D313RP70TNMETX3F6PX3PD-one-argument-perl-system-spl.md @@ -4,9 +4,9 @@ anchor: '@file' created: 2026-10-20T16:41:34Z norm: '1' sig: 4949218de757741f -body_hash: f04bf517db564cdd -raw_hash: 4b9cffb06024b51f -vouched: 2026-10-20T17:21:46Z +body_hash: e345c7c433c48cd2 +raw_hash: 3a89db569859919a +vouched: 2026-10-20T17:37:48Z lines: 1-1211 --- diff --git a/.lane/memory/scripts/live-check.mjs/01M5D67S7ETJK13EGGXAS4PCRP-safari-disables-copy-and-has.md b/.lane/memory/scripts/live-check.mjs/01M5D67S7ETJK13EGGXAS4PCRP-safari-disables-copy-and-has.md new file mode 100644 index 00000000..7ab7f6e7 --- /dev/null +++ b/.lane/memory/scripts/live-check.mjs/01M5D67S7ETJK13EGGXAS4PCRP-safari-disables-copy-and-has.md @@ -0,0 +1,12 @@ +--- +id: 01M5D67S7ETJK13EGGXAS4PCRP +anchor: '@file' +created: 2026-10-20T17:37:38Z +norm: '1' +sig: 4949218de757741f +body_hash: e345c7c433c48cd2 +raw_hash: 3a89db569859919a +lines: 1-1217 +--- + +Safari disables Copy and has no in-window keyboard focus while inactive, so the #88 copy runs Edit > Copy after desktop_activate; background Command-C and Edit > Copy are refused diff --git a/.lane/memory/src/tools.ts/01M5D682W73BEYBRAPTSK672XW-wire-2-text-is-what-native2.md b/.lane/memory/src/tools.ts/01M5D682W73BEYBRAPTSK672XW-wire-2-text-is-what-native2.md new file mode 100644 index 00000000..b47495ae --- /dev/null +++ b/.lane/memory/src/tools.ts/01M5D682W73BEYBRAPTSK672XW-wire-2-text-is-what-native2.md @@ -0,0 +1,13 @@ +--- +id: 01M5D682W73BEYBRAPTSK672XW +anchor: '@file' +created: 2026-10-20T17:37:48Z +norm: '1' +sig: 78473a106add9cfc +body_hash: 4ecc23ca1544c692 +raw_hash: 4973bb5ae4651c19 +lines: 1-971 +supersedes: 01M5CT5AR9NBSN9BZBSR9MQKXN +--- + +wire 2 text is what native2 serves (scripts/contract.mjs runs dist/mcp.js --wire 2, so regenerate ContractText after editing it); wire 1 text is only for the Peekaboo stack a release can switch back to diff --git a/CHANGELOG.md b/CHANGELOG.md index 7be0c771..f3dbd8b9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,11 @@ Notable changes to Desktop Tools, newest first. Each release's GitHub release no ## [Unreleased] +### Fixed + +- `desktop_select` selects text in a web page that isn't a field, such as a paragraph or a link, through WebKit's text markers. An image pasted into a web field is refused with `PASTE_UNVERIFIABLE_RECEIVER` before the focus check, since the page's handling can't be read back. ([#88](https://github.com/githubnext/desktop-tools/issues/88), [#99](https://github.com/githubnext/desktop-tools/issues/99)) +- Text selected in a Safari page with `desktop_select` can be copied: selecting focuses the page, as a click would, so Edit > Copy in the activated Safari copies the selection instead of the page's address. Safari copies only while active, so `desktop_activate` it and choose Edit > Copy with `desktop_menu`; the tool description and docs said to press Command-C, which Safari ignores in the background. ([#188](https://github.com/githubnext/desktop-tools/issues/188)) + ## [0.17.0] - 2026-10-20 ### Changed diff --git a/dist/tools.js b/dist/tools.js index 46a1ab0f..00d0e090 100644 --- a/dist/tools.js +++ b/dist/tools.js @@ -775,7 +775,7 @@ export function desktopTools({ place, app, wire = 1 }) { { name: "desktop_select", op: "select", - description: `Select literal text in one element from a fresh desktop_inspect snapshot, or place the caret before or after it (selection). The element is an editable field, web page text such as a paragraph or link, or the text of a PDF page in Preview. Background. Completed when the selection reads back as exactly that text. Missing or ambiguous text is refused; add prefix or suffix, the text immediately around it. To copy, press c with command through desktop_key; Preview copies only while active, so desktop_activate it and use desktop_menu Edit > Copy.`, + description: `Select literal text in one element from a fresh desktop_inspect snapshot, or place the caret before or after it (selection). The element is an editable field, web page text such as a paragraph or link, or the text of a PDF page in Preview. Background. Completed when the selection reads back as exactly that text. Missing or ambiguous text is refused; add prefix or suffix, the text immediately around it. To copy a field's selection, press c with command through desktop_key; Safari and Preview copy only while active, so desktop_activate the app and use desktop_menu Edit > Copy.`, parameters: { type: "object", required: ["snapshot", "element", "text"], diff --git a/docs/tools.md b/docs/tools.md index 0fb24aec..c0c27551 100644 --- a/docs/tools.md +++ b/docs/tools.md @@ -203,7 +203,7 @@ The host replaces the field's contents with key events. The fill is completed wh `desktop_insert` also pastes an image or files into a native text area, such as TextEdit's rich text, Mail or Notes, in place of text; see [the details](#details-by-tool) for how it confirms the paste and when it refuses. -`desktop_select` sets a field's `AXSelectedTextRange` and reads it back. Text in a web page has no such range, so for an element inside a web area, such as a paragraph, heading or link, the host uses WebKit's text markers instead. It finds the requested range from the element's own start, sets the web area's selected marker range, and reads it back: the result is `completed` only when the selection covers exactly the requested text, and `unknown` otherwise. A long element may need the host to walk the text one marker at a time; that walk stops after 2,048 steps or 300 ms, and the selection is refused before anything is selected, with a hint to select within a smaller element. Offsets are UTF-16 units within the element, as for fields. To copy the selection, press `c` with `command` through `desktop_key`, then `desktop_clipboard_read`. Text on a PDF page in Preview is selected the same way, through the page's text element, even though that element reports itself disabled and has no selection until one is set. Preview disables Copy while it is in the background, so `desktop_activate` it first, then choose Edit > Copy with `desktop_menu`. Not yet checked on a live system: other selectable text outside web pages that isn't a field, such as a read-only native text view, which works only if it exposes a settable `AXSelectedTextRange` and is refused otherwise. +`desktop_select` sets a field's `AXSelectedTextRange` and reads it back. Text in a web page has no such range, so for an element inside a web area, such as a paragraph, heading or link, the host uses WebKit's text markers instead. It focuses the web area, as a click in the page would, so that Copy acts on the page rather than on Safari's address field, finds the requested range from the element's own start, sets the web area's selected marker range, and reads it back: the result is `completed` only when the selection covers exactly the requested text, and `unknown` otherwise. A long element may need the host to walk the text one marker at a time; that walk stops after 2,048 steps or 300 ms, and the selection is refused before anything is selected, with a hint to select within a smaller element. Offsets are UTF-16 units within the element, as for fields. To copy a field's selection, press `c` with `command` through `desktop_key`, then `desktop_clipboard_read`. Safari disables Copy while it is in the background, and its keyboard focus isn't in the window then, so `desktop_activate` it first and choose Edit > Copy with `desktop_menu`. Text on a PDF page in Preview is selected the same way, through the page's text element, even though that element reports itself disabled and has no selection until one is set. Preview disables Copy while it is in the background, so `desktop_activate` it first, then choose Edit > Copy with `desktop_menu`. Not yet checked on a live system: other selectable text outside web pages that isn't a field, such as a read-only native text view, which works only if it exposes a settable `AXSelectedTextRange` and is refused otherwise. `desktop_inspect` lists the actions each element offers in `actions`. A pop-up button has no settable value: click it, then pick the item from the next observation, which puts an open menu's items first. A `