safari-mcp 2.8.2 → 2.8.3
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 +41 -1
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "safari-mcp",
|
|
3
|
-
"version": "2.8.
|
|
3
|
+
"version": "2.8.3",
|
|
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
|
@@ -156,7 +156,8 @@ let _activeTabIndex = null; // null = use front document (default)
|
|
|
156
156
|
let _activeTabURL = null; // URL-based tracking (stable even when tabs shift)
|
|
157
157
|
let _lastResolveTime = 0; // Cache: skip resolve if verified recently
|
|
158
158
|
let _lastTabCount = null; // Track tab count for smart cache invalidation
|
|
159
|
-
|
|
159
|
+
let _activeTabMarker = null; // window.__mcpTabMarker — survives same-tab navigation, bulletproof tab identity
|
|
160
|
+
const RESOLVE_CACHE_MS = 100; // Brief cache — was 500, reduced to catch tabs added by user/popups (v2.8.3 fix)
|
|
160
161
|
|
|
161
162
|
// ========== DIAGNOSTIC LOG ==========
|
|
162
163
|
// File-based log for profile/focus issues — survives MCP restart, visible to user
|
|
@@ -331,7 +332,41 @@ export function setActiveTabURL(url) { _activeTabURL = url; _lastResolveTime = D
|
|
|
331
332
|
|
|
332
333
|
// Resolve our tracked URL to current tab index — single combined osascript call
|
|
333
334
|
async function resolveActiveTab() {
|
|
335
|
+
if (!_activeTabURL && !_activeTabMarker) return _activeTabIndex;
|
|
336
|
+
|
|
337
|
+
// Strategy 1: window.__mcpTabMarker (bulletproof — survives navigation, redirects, query changes)
|
|
338
|
+
// Only attempted if we have a marker AND a cached index hint
|
|
339
|
+
if (_activeTabMarker && _activeTabIndex) {
|
|
340
|
+
try {
|
|
341
|
+
const safeMarker = _activeTabMarker.replace(/'/g, "\\'");
|
|
342
|
+
// Single JS call: check cached index first, then walk all tabs to find marker
|
|
343
|
+
const checkScript = `(function(){return window.__mcpTabMarker==='${safeMarker}'?'1':'0'})()`;
|
|
344
|
+
const matchAtCached = await osascriptFast(
|
|
345
|
+
`tell application "Safari" to do JavaScript "${checkScript}" in tab ${_activeTabIndex} of ${getTargetWindowRef()}`
|
|
346
|
+
).catch(() => '0');
|
|
347
|
+
if (String(matchAtCached).trim() === '1') return _activeTabIndex;
|
|
348
|
+
// Cached index doesn't match — scan all tabs for marker
|
|
349
|
+
const tabCountStr = await osascriptFast(
|
|
350
|
+
`tell application "Safari" to return count of tabs of ${getTargetWindowRef()}`
|
|
351
|
+
).catch(() => '0');
|
|
352
|
+
const tabCount = Number(tabCountStr) || 0;
|
|
353
|
+
for (let i = tabCount; i >= 1; i--) {
|
|
354
|
+
const m = await osascriptFast(
|
|
355
|
+
`tell application "Safari" to do JavaScript "${checkScript}" in tab ${i} of ${getTargetWindowRef()}`
|
|
356
|
+
).catch(() => '0');
|
|
357
|
+
if (String(m).trim() === '1') {
|
|
358
|
+
_activeTabIndex = i;
|
|
359
|
+
_lastTabCount = tabCount;
|
|
360
|
+
return i;
|
|
361
|
+
}
|
|
362
|
+
}
|
|
363
|
+
// Marker not found anywhere — page reloaded or tab closed
|
|
364
|
+
_activeTabMarker = null;
|
|
365
|
+
} catch { /* fall through to URL strategy */ }
|
|
366
|
+
}
|
|
367
|
+
|
|
334
368
|
if (!_activeTabURL) return _activeTabIndex;
|
|
369
|
+
|
|
335
370
|
try {
|
|
336
371
|
const safeUrl = _activeTabURL.replace(/"/g, '\\"');
|
|
337
372
|
const domain = _activeTabURL.replace(/^https?:\/\//, '').split('/')[0].replace(/"/g, '\\"');
|
|
@@ -2112,6 +2147,11 @@ export async function newTab(url = "") {
|
|
|
2112
2147
|
_activeTabURL = url || null;
|
|
2113
2148
|
_lastResolveTime = Date.now();
|
|
2114
2149
|
_lastTabCount = Number(tabCount); // Update tab count cache
|
|
2150
|
+
// Set bulletproof tab marker — survives same-tab navigation, redirects, query changes (v2.8.3)
|
|
2151
|
+
_activeTabMarker = `MCP_${SESSION_ID}_${Date.now().toString(36)}_${Math.random().toString(36).slice(2, 8)}`;
|
|
2152
|
+
await osascriptFast(
|
|
2153
|
+
`tell application "Safari" to do JavaScript "window.__mcpTabMarker='${_activeTabMarker}'" in tab ${_activeTabIndex} of ${getTargetWindowRef()}`
|
|
2154
|
+
).catch(() => {});
|
|
2115
2155
|
// Wait for page load if URL given
|
|
2116
2156
|
if (url) {
|
|
2117
2157
|
try {
|