safari-mcp 2.10.1 → 2.10.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +1 -1
- package/safari.js +29 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "safari-mcp",
|
|
3
|
-
"version": "2.10.
|
|
3
|
+
"version": "2.10.2",
|
|
4
4
|
"mcpName": "io.github.achiya-automation/safari-mcp",
|
|
5
5
|
"description": "Safari browser automation for AI agents — native macOS, zero Chrome overhead. 80 tools via AppleScript + JavaScript.",
|
|
6
6
|
"type": "module",
|
package/safari.js
CHANGED
|
@@ -1330,6 +1330,35 @@ export async function fill({ selector, value, ref }) {
|
|
|
1330
1330
|
const val = value.replace(/\\/g, "\\\\").replace(/'/g, "\\'").replace(/\n/g, "\\n").replace(/\r/g, "");
|
|
1331
1331
|
const result = await runJS(
|
|
1332
1332
|
`(function(){try{var el=document.querySelector('${sel}');if(!el){var q=function(r){var a=r.querySelectorAll('*');for(var i=0;i<a.length;i++){if(a[i].shadowRoot){el=a[i].shadowRoot.querySelector('${sel}');if(el)return el;el=q(a[i].shadowRoot);if(el)return el;}}return null;};el=q(document);}if(!el)return 'Element not found: ${sel}';el.focus();if(el.isContentEditable||el.getAttribute('contenteditable')==='true'){` +
|
|
1333
|
+
// Quill editor detection (LinkedIn share composer in 2026 — they migrated from
|
|
1334
|
+
// ProseMirror, Slack message editor, many enterprise apps). The Quill instance is
|
|
1335
|
+
// attached to `.ql-container.__quill` (v2) or accessible via React Fiber's
|
|
1336
|
+
// memoizedProps/stateNode. Without proper API access, fill-by-DOM crashes Quill's
|
|
1337
|
+
// internal Delta state and dismisses the dialog (the v2.10.0 LinkedIn bug repro).
|
|
1338
|
+
`var qlEditor=el.classList&&el.classList.contains('ql-editor')?el:el.closest('.ql-editor');` +
|
|
1339
|
+
`if(qlEditor){` +
|
|
1340
|
+
`var qlContainer=qlEditor.closest('.ql-container')||qlEditor.parentElement;` +
|
|
1341
|
+
`var quill=(qlContainer&&qlContainer.__quill)||null;` +
|
|
1342
|
+
// Fallback: walk React Fiber to find the Quill instance attached as a prop or stateNode
|
|
1343
|
+
`if(!quill&&qlContainer){var qfk=Object.keys(qlContainer).find(function(k){return k.indexOf('__reactFiber')===0||k.indexOf('__reactInternalInstance')===0;});if(qfk){var qf=qlContainer[qfk];for(var qd=0;qd<25&&qf;qd++){var qp=qf.memoizedProps;if(qp&&qp.quill&&typeof qp.quill.setContents==='function'){quill=qp.quill;break;}var qsn=qf.stateNode;if(qsn&&qsn.quill&&typeof qsn.quill.setContents==='function'){quill=qsn.quill;break;}qf=qf.return;}}}` +
|
|
1344
|
+
`if(quill&&typeof quill.setContents==='function'){` +
|
|
1345
|
+
`try{` +
|
|
1346
|
+
// Convert escaped string back to real string for Quill API.
|
|
1347
|
+
// The val template var has \\n / \\\\ / \\' applied, so we need to unescape for setText.
|
|
1348
|
+
`var qlText='${val}'.replace(/\\\\n/g,'\\n').replace(/\\\\'/g,"'").replace(/\\\\\\\\/g,'\\\\');` +
|
|
1349
|
+
// setContents with a plain text Delta — bypasses clipboard, no synthetic events,
|
|
1350
|
+
// doesn't trigger LinkedIn's focusout-dismiss handler.
|
|
1351
|
+
`quill.setContents([{insert: qlText + '\\n'}], 'api');` +
|
|
1352
|
+
`quill.setSelection(qlText.length, 0, 'api');` +
|
|
1353
|
+
// Verify the text actually committed
|
|
1354
|
+
`var qlActual=quill.getText().replace(/\\n+$/,'');` +
|
|
1355
|
+
`if(qlActual.indexOf(qlText.substring(0, Math.min(20, qlText.length)))>=0){return 'Filled CE (Quill setContents)';}` +
|
|
1356
|
+
`}catch(_qE){}` +
|
|
1357
|
+
`}` +
|
|
1358
|
+
// Quill instance not found via direct or Fiber — route to native paste fallback.
|
|
1359
|
+
// Quill respects real isTrusted clipboard events, so CGEvent Cmd+V works.
|
|
1360
|
+
`return '__NATIVE_PASTE_DIALOG__';` +
|
|
1361
|
+
`}` +
|
|
1333
1362
|
// Lexical editor detection (LinkedIn share composer, modern Meta/Shopify apps).
|
|
1334
1363
|
// Three lookup strategies, cheapest first:
|
|
1335
1364
|
// A) [data-lexical-editor="true"] on ancestor with __lexicalEditor property.
|