safari-pilot 0.1.0
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/.claude-plugin/plugin.json +35 -0
- package/.mcp.json +11 -0
- package/LICENSE +21 -0
- package/README.md +324 -0
- package/bin/.gitkeep +0 -0
- package/bin/Safari Pilot.app/Contents/CodeResources +0 -0
- package/bin/Safari Pilot.app/Contents/Info.plist +58 -0
- package/bin/Safari Pilot.app/Contents/MacOS/Safari Pilot +0 -0
- package/bin/Safari Pilot.app/Contents/PkgInfo +1 -0
- package/bin/Safari Pilot.app/Contents/PlugIns/Safari Pilot Extension.appex/Contents/Info.plist +55 -0
- package/bin/Safari Pilot.app/Contents/PlugIns/Safari Pilot Extension.appex/Contents/MacOS/Safari Pilot Extension +0 -0
- package/bin/Safari Pilot.app/Contents/PlugIns/Safari Pilot Extension.appex/Contents/Resources/background.js +294 -0
- package/bin/Safari Pilot.app/Contents/PlugIns/Safari Pilot Extension.appex/Contents/Resources/content-isolated.js +80 -0
- package/bin/Safari Pilot.app/Contents/PlugIns/Safari Pilot Extension.appex/Contents/Resources/content-main.js +310 -0
- package/bin/Safari Pilot.app/Contents/PlugIns/Safari Pilot Extension.appex/Contents/Resources/icons/icon-128.png +0 -0
- package/bin/Safari Pilot.app/Contents/PlugIns/Safari Pilot Extension.appex/Contents/Resources/icons/icon-48.png +0 -0
- package/bin/Safari Pilot.app/Contents/PlugIns/Safari Pilot Extension.appex/Contents/Resources/icons/icon-96.png +0 -0
- package/bin/Safari Pilot.app/Contents/PlugIns/Safari Pilot Extension.appex/Contents/Resources/manifest.json +39 -0
- package/bin/Safari Pilot.app/Contents/PlugIns/Safari Pilot Extension.appex/Contents/_CodeSignature/CodeResources +194 -0
- package/bin/Safari Pilot.app/Contents/Resources/AppIcon.icns +0 -0
- package/bin/Safari Pilot.app/Contents/Resources/Assets.car +0 -0
- package/bin/Safari Pilot.app/Contents/Resources/Base.lproj/Main.html +19 -0
- package/bin/Safari Pilot.app/Contents/Resources/Base.lproj/Main.storyboardc/Info.plist +0 -0
- package/bin/Safari Pilot.app/Contents/Resources/Base.lproj/Main.storyboardc/MainMenu.nib +0 -0
- package/bin/Safari Pilot.app/Contents/Resources/Base.lproj/Main.storyboardc/NSWindowController-B8D-0N-5wS.nib +0 -0
- package/bin/Safari Pilot.app/Contents/Resources/Base.lproj/Main.storyboardc/XfG-lQ-9wD-view-m2S-Jp-Qdl.nib +0 -0
- package/bin/Safari Pilot.app/Contents/Resources/Icon.png +0 -0
- package/bin/Safari Pilot.app/Contents/Resources/Script.js +22 -0
- package/bin/Safari Pilot.app/Contents/Resources/Style.css +45 -0
- package/bin/Safari Pilot.app/Contents/_CodeSignature/CodeResources +236 -0
- package/bin/Safari Pilot.zip +0 -0
- package/bin/SafariPilotd +0 -0
- package/dist/engine-selector.d.ts +10 -0
- package/dist/engine-selector.js +55 -0
- package/dist/engine-selector.js.map +1 -0
- package/dist/engines/applescript.d.ts +53 -0
- package/dist/engines/applescript.js +290 -0
- package/dist/engines/applescript.js.map +1 -0
- package/dist/engines/daemon.d.ts +19 -0
- package/dist/engines/daemon.js +187 -0
- package/dist/engines/daemon.js.map +1 -0
- package/dist/engines/engine.d.ts +15 -0
- package/dist/engines/engine.js +42 -0
- package/dist/engines/engine.js.map +1 -0
- package/dist/engines/extension.d.ts +34 -0
- package/dist/engines/extension.js +66 -0
- package/dist/engines/extension.js.map +1 -0
- package/dist/errors.d.ts +128 -0
- package/dist/errors.js +250 -0
- package/dist/errors.js.map +1 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +11 -0
- package/dist/index.js.map +1 -0
- package/dist/security/audit-log.d.ts +23 -0
- package/dist/security/audit-log.js +68 -0
- package/dist/security/audit-log.js.map +1 -0
- package/dist/security/circuit-breaker.d.ts +29 -0
- package/dist/security/circuit-breaker.js +114 -0
- package/dist/security/circuit-breaker.js.map +1 -0
- package/dist/security/domain-policy.d.ts +29 -0
- package/dist/security/domain-policy.js +96 -0
- package/dist/security/domain-policy.js.map +1 -0
- package/dist/security/human-approval.d.ts +20 -0
- package/dist/security/human-approval.js +150 -0
- package/dist/security/human-approval.js.map +1 -0
- package/dist/security/idpi-scanner.d.ts +20 -0
- package/dist/security/idpi-scanner.js +102 -0
- package/dist/security/idpi-scanner.js.map +1 -0
- package/dist/security/kill-switch.d.ts +51 -0
- package/dist/security/kill-switch.js +103 -0
- package/dist/security/kill-switch.js.map +1 -0
- package/dist/security/rate-limiter.d.ts +30 -0
- package/dist/security/rate-limiter.js +70 -0
- package/dist/security/rate-limiter.js.map +1 -0
- package/dist/security/screenshot-redaction.d.ts +42 -0
- package/dist/security/screenshot-redaction.js +134 -0
- package/dist/security/screenshot-redaction.js.map +1 -0
- package/dist/security/tab-ownership.d.ts +46 -0
- package/dist/security/tab-ownership.js +85 -0
- package/dist/security/tab-ownership.js.map +1 -0
- package/dist/server.d.ts +53 -0
- package/dist/server.js +347 -0
- package/dist/server.js.map +1 -0
- package/dist/tools/clipboard.d.ts +15 -0
- package/dist/tools/clipboard.js +128 -0
- package/dist/tools/clipboard.js.map +1 -0
- package/dist/tools/compound.d.ts +68 -0
- package/dist/tools/compound.js +491 -0
- package/dist/tools/compound.js.map +1 -0
- package/dist/tools/extraction.d.ts +26 -0
- package/dist/tools/extraction.js +414 -0
- package/dist/tools/extraction.js.map +1 -0
- package/dist/tools/frames.d.ts +22 -0
- package/dist/tools/frames.js +165 -0
- package/dist/tools/frames.js.map +1 -0
- package/dist/tools/interaction.d.ts +30 -0
- package/dist/tools/interaction.js +651 -0
- package/dist/tools/interaction.js.map +1 -0
- package/dist/tools/navigation.d.ts +41 -0
- package/dist/tools/navigation.js +316 -0
- package/dist/tools/navigation.js.map +1 -0
- package/dist/tools/network.d.ts +27 -0
- package/dist/tools/network.js +721 -0
- package/dist/tools/network.js.map +1 -0
- package/dist/tools/performance.d.ts +16 -0
- package/dist/tools/performance.js +240 -0
- package/dist/tools/performance.js.map +1 -0
- package/dist/tools/permissions.d.ts +25 -0
- package/dist/tools/permissions.js +308 -0
- package/dist/tools/permissions.js.map +1 -0
- package/dist/tools/service-workers.d.ts +15 -0
- package/dist/tools/service-workers.js +136 -0
- package/dist/tools/service-workers.js.map +1 -0
- package/dist/tools/shadow.d.ts +21 -0
- package/dist/tools/shadow.js +126 -0
- package/dist/tools/shadow.js.map +1 -0
- package/dist/tools/storage.d.ts +30 -0
- package/dist/tools/storage.js +679 -0
- package/dist/tools/storage.js.map +1 -0
- package/dist/tools/structured-extraction.d.ts +22 -0
- package/dist/tools/structured-extraction.js +433 -0
- package/dist/tools/structured-extraction.js.map +1 -0
- package/dist/tools/wait.d.ts +18 -0
- package/dist/tools/wait.js +182 -0
- package/dist/tools/wait.js.map +1 -0
- package/dist/types.d.ts +85 -0
- package/dist/types.js +2 -0
- package/dist/types.js.map +1 -0
- package/extension/background.js +294 -0
- package/extension/content-isolated.js +80 -0
- package/extension/content-main.js +310 -0
- package/extension/icons/icon-128.png +0 -0
- package/extension/icons/icon-48.png +0 -0
- package/extension/icons/icon-96.png +0 -0
- package/extension/manifest.json +39 -0
- package/hooks/session-end.sh +67 -0
- package/hooks/session-start.sh +66 -0
- package/package.json +46 -0
- package/scripts/build-extension.sh +135 -0
- package/scripts/postinstall.sh +91 -0
- package/scripts/preuninstall.sh +25 -0
- package/scripts/update-daemon.sh +62 -0
- package/skills/safari-pilot/SKILL.md +157 -0
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
set -euo pipefail
|
|
3
|
+
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
|
|
4
|
+
ROOT="$(cd "$SCRIPT_DIR/.." && pwd)"
|
|
5
|
+
|
|
6
|
+
# Only run on macOS
|
|
7
|
+
if [[ "$(uname -s)" != "Darwin" ]]; then
|
|
8
|
+
echo "safari-pilot: Skipping postinstall — macOS only"
|
|
9
|
+
exit 0
|
|
10
|
+
fi
|
|
11
|
+
|
|
12
|
+
# Detect architecture
|
|
13
|
+
ARCH=$(uname -m) # arm64 or x86_64
|
|
14
|
+
|
|
15
|
+
# Download pre-built daemon binary from GitHub Releases
|
|
16
|
+
DAEMON_DIR="$ROOT/bin"
|
|
17
|
+
mkdir -p "$DAEMON_DIR"
|
|
18
|
+
|
|
19
|
+
# For now, try to build locally if swift is available
|
|
20
|
+
if command -v swift &>/dev/null; then
|
|
21
|
+
echo "safari-pilot: Building daemon locally..."
|
|
22
|
+
cd "$ROOT/daemon" && swift build -c release 2>&1 || true
|
|
23
|
+
if [ -f ".build/release/SafariPilotd" ]; then
|
|
24
|
+
cp .build/release/SafariPilotd "$DAEMON_DIR/SafariPilotd"
|
|
25
|
+
chmod +x "$DAEMON_DIR/SafariPilotd"
|
|
26
|
+
echo "safari-pilot: Daemon built successfully"
|
|
27
|
+
fi
|
|
28
|
+
else
|
|
29
|
+
echo "safari-pilot: Swift not available — daemon will not be available"
|
|
30
|
+
echo "safari-pilot: Install Xcode Command Line Tools for daemon support"
|
|
31
|
+
fi
|
|
32
|
+
|
|
33
|
+
# Install LaunchAgent if daemon was built
|
|
34
|
+
if [ -f "$DAEMON_DIR/SafariPilotd" ]; then
|
|
35
|
+
PLIST_SRC="$ROOT/daemon/com.safari-pilot.daemon.plist"
|
|
36
|
+
PLIST_DST="$HOME/Library/LaunchAgents/com.safari-pilot.daemon.plist"
|
|
37
|
+
|
|
38
|
+
if [ -f "$PLIST_SRC" ]; then
|
|
39
|
+
# Replace placeholders
|
|
40
|
+
sed "s|__DAEMON_PATH__|$DAEMON_DIR/SafariPilotd|g; s|__LOG_PATH__|$HOME/.safari-pilot|g" "$PLIST_SRC" > "$PLIST_DST"
|
|
41
|
+
mkdir -p "$HOME/.safari-pilot"
|
|
42
|
+
echo "safari-pilot: LaunchAgent installed at $PLIST_DST"
|
|
43
|
+
fi
|
|
44
|
+
fi
|
|
45
|
+
|
|
46
|
+
# Download signed Safari extension from GitHub Releases
|
|
47
|
+
EXTENSION_ZIP="$DAEMON_DIR/Safari Pilot.zip"
|
|
48
|
+
EXTENSION_APP="$DAEMON_DIR/Safari Pilot.app"
|
|
49
|
+
|
|
50
|
+
if [ ! -d "$EXTENSION_APP" ]; then
|
|
51
|
+
echo "safari-pilot: Downloading signed Safari extension..."
|
|
52
|
+
RELEASE_URL="https://github.com/RTinkslinger/safari-pilot/releases/latest/download/Safari%20Pilot.zip"
|
|
53
|
+
if command -v curl &>/dev/null; then
|
|
54
|
+
curl -fsSL "$RELEASE_URL" -o "$EXTENSION_ZIP" 2>/dev/null || true
|
|
55
|
+
elif command -v wget &>/dev/null; then
|
|
56
|
+
wget -q "$RELEASE_URL" -O "$EXTENSION_ZIP" 2>/dev/null || true
|
|
57
|
+
fi
|
|
58
|
+
|
|
59
|
+
if [ -f "$EXTENSION_ZIP" ]; then
|
|
60
|
+
# Extract the .app from the zip
|
|
61
|
+
ditto -x -k "$EXTENSION_ZIP" "$DAEMON_DIR/" 2>/dev/null || unzip -qo "$EXTENSION_ZIP" -d "$DAEMON_DIR/" 2>/dev/null || true
|
|
62
|
+
rm -f "$EXTENSION_ZIP"
|
|
63
|
+
|
|
64
|
+
if [ -d "$EXTENSION_APP" ]; then
|
|
65
|
+
echo "safari-pilot: Safari extension downloaded successfully"
|
|
66
|
+
echo ""
|
|
67
|
+
echo " ┌─────────────────────────────────────────────────────────────┐"
|
|
68
|
+
echo " │ Safari Extension Setup │"
|
|
69
|
+
echo " │ │"
|
|
70
|
+
echo " │ 1. Open the app: │"
|
|
71
|
+
echo " │ open \"$EXTENSION_APP\" │"
|
|
72
|
+
echo " │ │"
|
|
73
|
+
echo " │ 2. Enable in Safari: │"
|
|
74
|
+
echo " │ Safari > Settings > Extensions > Safari Pilot Extension │"
|
|
75
|
+
echo " │ │"
|
|
76
|
+
echo " │ Signed with Developer ID and notarized by Apple. │"
|
|
77
|
+
echo " └─────────────────────────────────────────────────────────────┘"
|
|
78
|
+
echo ""
|
|
79
|
+
else
|
|
80
|
+
echo "safari-pilot: Extension extraction failed — download manually from:"
|
|
81
|
+
echo " https://github.com/RTinkslinger/safari-pilot/releases/latest"
|
|
82
|
+
fi
|
|
83
|
+
else
|
|
84
|
+
echo "safari-pilot: Could not download extension — download manually from:"
|
|
85
|
+
echo " https://github.com/RTinkslinger/safari-pilot/releases/latest"
|
|
86
|
+
fi
|
|
87
|
+
else
|
|
88
|
+
echo "safari-pilot: Safari extension already present"
|
|
89
|
+
fi
|
|
90
|
+
|
|
91
|
+
echo "safari-pilot: Postinstall complete"
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
set -euo pipefail
|
|
3
|
+
|
|
4
|
+
# Only run on macOS
|
|
5
|
+
if [[ "$(uname -s)" != "Darwin" ]]; then
|
|
6
|
+
exit 0
|
|
7
|
+
fi
|
|
8
|
+
|
|
9
|
+
LABEL="com.safari-pilot.daemon"
|
|
10
|
+
PLIST="$HOME/Library/LaunchAgents/$LABEL.plist"
|
|
11
|
+
|
|
12
|
+
# Unload LaunchAgent
|
|
13
|
+
if [ -f "$PLIST" ]; then
|
|
14
|
+
launchctl bootout gui/$(id -u) "$LABEL" 2>/dev/null || true
|
|
15
|
+
rm -f "$PLIST"
|
|
16
|
+
echo "safari-pilot: LaunchAgent removed"
|
|
17
|
+
fi
|
|
18
|
+
|
|
19
|
+
# Clean up data directory
|
|
20
|
+
DATA_DIR="$HOME/.safari-pilot"
|
|
21
|
+
if [ -d "$DATA_DIR" ]; then
|
|
22
|
+
echo "safari-pilot: Keeping data at $DATA_DIR (remove manually if desired)"
|
|
23
|
+
fi
|
|
24
|
+
|
|
25
|
+
echo "safari-pilot: Uninstall complete"
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
# Safe binary update via versioned path + symlink swap + launchctl kickstart
|
|
3
|
+
set -euo pipefail
|
|
4
|
+
|
|
5
|
+
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
|
|
6
|
+
ROOT="$(cd "$SCRIPT_DIR/.." && pwd)"
|
|
7
|
+
DAEMON_DIR="$ROOT/bin"
|
|
8
|
+
DAEMON_BIN="$DAEMON_DIR/SafariPilotd"
|
|
9
|
+
LABEL="com.safari-pilot.daemon"
|
|
10
|
+
PLIST="$HOME/Library/LaunchAgents/$LABEL.plist"
|
|
11
|
+
|
|
12
|
+
# Only run on macOS
|
|
13
|
+
if [[ "$(uname -s)" != "Darwin" ]]; then
|
|
14
|
+
echo "update-daemon: macOS only"
|
|
15
|
+
exit 1
|
|
16
|
+
fi
|
|
17
|
+
|
|
18
|
+
# Build new binary into a versioned staging path
|
|
19
|
+
VERSION="${1:-$(date +%Y%m%d%H%M%S)}"
|
|
20
|
+
STAGED="$DAEMON_DIR/SafariPilotd.$VERSION"
|
|
21
|
+
|
|
22
|
+
echo "update-daemon: Building daemon (version: $VERSION)..."
|
|
23
|
+
|
|
24
|
+
if ! command -v swift &>/dev/null; then
|
|
25
|
+
echo "update-daemon: Swift not found — cannot build daemon"
|
|
26
|
+
exit 1
|
|
27
|
+
fi
|
|
28
|
+
|
|
29
|
+
cd "$ROOT/daemon"
|
|
30
|
+
swift build -c release 2>&1
|
|
31
|
+
if [ ! -f ".build/release/SafariPilotd" ]; then
|
|
32
|
+
echo "update-daemon: Build failed — binary not produced"
|
|
33
|
+
exit 1
|
|
34
|
+
fi
|
|
35
|
+
|
|
36
|
+
cp .build/release/SafariPilotd "$STAGED"
|
|
37
|
+
chmod +x "$STAGED"
|
|
38
|
+
echo "update-daemon: New binary staged at $STAGED"
|
|
39
|
+
|
|
40
|
+
# Stop the running daemon if loaded
|
|
41
|
+
if launchctl list "$LABEL" &>/dev/null 2>&1; then
|
|
42
|
+
echo "update-daemon: Stopping running daemon..."
|
|
43
|
+
launchctl stop "$LABEL" || true
|
|
44
|
+
fi
|
|
45
|
+
|
|
46
|
+
# Atomic swap: replace current binary with staged version
|
|
47
|
+
mv "$STAGED" "$DAEMON_BIN"
|
|
48
|
+
echo "update-daemon: Binary swapped at $DAEMON_BIN"
|
|
49
|
+
|
|
50
|
+
# Kickstart (restart) the daemon if the plist is installed
|
|
51
|
+
if [ -f "$PLIST" ]; then
|
|
52
|
+
# Reload to pick up new binary
|
|
53
|
+
launchctl unload "$PLIST" 2>/dev/null || true
|
|
54
|
+
launchctl load "$PLIST"
|
|
55
|
+
launchctl kickstart -k "gui/$(id -u)/$LABEL" 2>/dev/null || launchctl start "$LABEL" || true
|
|
56
|
+
echo "update-daemon: Daemon restarted via launchctl"
|
|
57
|
+
else
|
|
58
|
+
echo "update-daemon: No LaunchAgent plist found — daemon not restarted automatically"
|
|
59
|
+
echo "update-daemon: Run postinstall.sh to install the LaunchAgent"
|
|
60
|
+
fi
|
|
61
|
+
|
|
62
|
+
echo "update-daemon: Update complete (version: $VERSION)"
|
|
@@ -0,0 +1,157 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: safari-pilot
|
|
3
|
+
description: >
|
|
4
|
+
Native Safari browser automation for AI agents on macOS. Use when browsing websites,
|
|
5
|
+
filling forms, extracting data, testing web apps, or any task involving web pages on Mac.
|
|
6
|
+
Triggers on: "browse in Safari", "use Safari", "navigate to", "fill form", "extract from",
|
|
7
|
+
"test this page", "check website", or any URL when on macOS.
|
|
8
|
+
allowed-tools:
|
|
9
|
+
- mcp__safari__safari_health_check
|
|
10
|
+
- mcp__safari__safari_emergency_stop
|
|
11
|
+
- mcp__safari__safari_navigate
|
|
12
|
+
- mcp__safari__safari_navigate_back
|
|
13
|
+
- mcp__safari__safari_navigate_forward
|
|
14
|
+
- mcp__safari__safari_reload
|
|
15
|
+
- mcp__safari__safari_new_tab
|
|
16
|
+
- mcp__safari__safari_close_tab
|
|
17
|
+
- mcp__safari__safari_list_tabs
|
|
18
|
+
- mcp__safari__safari_click
|
|
19
|
+
- mcp__safari__safari_double_click
|
|
20
|
+
- mcp__safari__safari_fill
|
|
21
|
+
- mcp__safari__safari_select_option
|
|
22
|
+
- mcp__safari__safari_check
|
|
23
|
+
- mcp__safari__safari_hover
|
|
24
|
+
- mcp__safari__safari_type
|
|
25
|
+
- mcp__safari__safari_press_key
|
|
26
|
+
- mcp__safari__safari_scroll
|
|
27
|
+
- mcp__safari__safari_drag
|
|
28
|
+
- mcp__safari__safari_handle_dialog
|
|
29
|
+
- mcp__safari__safari_snapshot
|
|
30
|
+
- mcp__safari__safari_get_text
|
|
31
|
+
- mcp__safari__safari_get_html
|
|
32
|
+
- mcp__safari__safari_get_attribute
|
|
33
|
+
- mcp__safari__safari_evaluate
|
|
34
|
+
- mcp__safari__safari_take_screenshot
|
|
35
|
+
- mcp__safari__safari_get_console_messages
|
|
36
|
+
- mcp__safari__safari_list_network_requests
|
|
37
|
+
- mcp__safari__safari_get_network_request
|
|
38
|
+
- mcp__safari__safari_intercept_requests
|
|
39
|
+
- mcp__safari__safari_network_throttle
|
|
40
|
+
- mcp__safari__safari_network_offline
|
|
41
|
+
- mcp__safari__safari_mock_request
|
|
42
|
+
- mcp__safari__safari_websocket_listen
|
|
43
|
+
- mcp__safari__safari_websocket_filter
|
|
44
|
+
- mcp__safari__safari_get_cookies
|
|
45
|
+
- mcp__safari__safari_set_cookie
|
|
46
|
+
- mcp__safari__safari_delete_cookie
|
|
47
|
+
- mcp__safari__safari_storage_state_export
|
|
48
|
+
- mcp__safari__safari_storage_state_import
|
|
49
|
+
- mcp__safari__safari_local_storage_get
|
|
50
|
+
- mcp__safari__safari_local_storage_set
|
|
51
|
+
- mcp__safari__safari_session_storage_get
|
|
52
|
+
- mcp__safari__safari_session_storage_set
|
|
53
|
+
- mcp__safari__safari_idb_list
|
|
54
|
+
- mcp__safari__safari_idb_get
|
|
55
|
+
- mcp__safari__safari_query_shadow
|
|
56
|
+
- mcp__safari__safari_click_shadow
|
|
57
|
+
- mcp__safari__safari_list_frames
|
|
58
|
+
- mcp__safari__safari_switch_frame
|
|
59
|
+
- mcp__safari__safari_eval_in_frame
|
|
60
|
+
- mcp__safari__safari_permission_get
|
|
61
|
+
- mcp__safari__safari_permission_set
|
|
62
|
+
- mcp__safari__safari_override_geolocation
|
|
63
|
+
- mcp__safari__safari_override_timezone
|
|
64
|
+
- mcp__safari__safari_override_locale
|
|
65
|
+
- mcp__safari__safari_override_useragent
|
|
66
|
+
- mcp__safari__safari_clipboard_read
|
|
67
|
+
- mcp__safari__safari_clipboard_write
|
|
68
|
+
- mcp__safari__safari_sw_list
|
|
69
|
+
- mcp__safari__safari_sw_unregister
|
|
70
|
+
- mcp__safari__safari_begin_trace
|
|
71
|
+
- mcp__safari__safari_end_trace
|
|
72
|
+
- mcp__safari__safari_get_page_metrics
|
|
73
|
+
- mcp__safari__safari_smart_scrape
|
|
74
|
+
- mcp__safari__safari_extract_tables
|
|
75
|
+
- mcp__safari__safari_extract_links
|
|
76
|
+
- mcp__safari__safari_extract_images
|
|
77
|
+
- mcp__safari__safari_extract_metadata
|
|
78
|
+
- mcp__safari__safari_wait_for
|
|
79
|
+
- mcp__safari__safari_test_flow
|
|
80
|
+
- mcp__safari__safari_monitor_page
|
|
81
|
+
- mcp__safari__safari_paginate_scrape
|
|
82
|
+
- mcp__safari__safari_media_control
|
|
83
|
+
---
|
|
84
|
+
|
|
85
|
+
# You are Safari Pilot
|
|
86
|
+
|
|
87
|
+
You control Safari natively on macOS via AppleScript and a background daemon. This is not Playwright in a wrapper — you are issuing real AppleScript commands to a real browser that the user can see and interact with. Every tab you open is tracked; every action is audited. You own the session, the user owns the machine.
|
|
88
|
+
|
|
89
|
+
Your mental model: you are a co-pilot, not an autopilot. Safari is running on the user's desktop. You navigate it, fill it, read it, and report back. If something looks wrong in a snapshot, stop and say so before continuing.
|
|
90
|
+
|
|
91
|
+
## Core Pattern: Navigate → Snapshot → Act → Verify
|
|
92
|
+
|
|
93
|
+
This is the loop for every task, regardless of complexity:
|
|
94
|
+
|
|
95
|
+
1. **Navigate** — `safari_new_tab` to open a clean tab you own, then `safari_navigate` to reach the target URL.
|
|
96
|
+
2. **Snapshot** — `safari_snapshot` to get the accessibility tree. This is your ground truth. Read it before touching anything.
|
|
97
|
+
3. **Act** — Click, fill, select, scroll. Use the most specific selector available from the snapshot.
|
|
98
|
+
4. **Verify** — `safari_snapshot` again after every significant action. Confirm the page state changed as expected before proceeding.
|
|
99
|
+
|
|
100
|
+
Never act on assumptions about what's on a page. Always snapshot first.
|
|
101
|
+
|
|
102
|
+
## Tab Ownership
|
|
103
|
+
|
|
104
|
+
Safari has tabs you didn't open. Don't touch them.
|
|
105
|
+
|
|
106
|
+
- Always call `safari_list_tabs` at the start of a session to see what's already open.
|
|
107
|
+
- Open your own tab with `safari_new_tab` before navigating. Never reuse existing tabs unless the user explicitly asks.
|
|
108
|
+
- Track the tab URL you opened. All subsequent operations on that task use that tab.
|
|
109
|
+
- When a task finishes, close your tab with `safari_close_tab` unless the user wants to keep it.
|
|
110
|
+
|
|
111
|
+
The security layer enforces ownership — tools will reject operations on tabs you don't own. Work with this, not around it.
|
|
112
|
+
|
|
113
|
+
## Engine Awareness
|
|
114
|
+
|
|
115
|
+
Three execution paths are available, selected automatically based on what the operation needs:
|
|
116
|
+
|
|
117
|
+
**Daemon (fast path)** — A native macOS process that injects JavaScript directly. Used when available for latency-sensitive operations. Sub-100ms for most reads.
|
|
118
|
+
|
|
119
|
+
**AppleScript (fallback)** — `osascript` bridging into Safari. Always available. ~200-400ms per call. This is the reliable floor.
|
|
120
|
+
|
|
121
|
+
**Extension (deep DOM)** — The Safari Web Extension enables cross-origin XHR interception, shadow DOM queries, and service worker access. Required for `safari_intercept_requests`, `safari_query_shadow`, `safari_sw_list`, `safari_eval_in_frame` on cross-origin iframes. If a tool returns `EXTENSION_REQUIRED`, the user needs to install and enable the extension.
|
|
122
|
+
|
|
123
|
+
You don't choose the engine — `safari_health_check` tells you what's available, and the server selects the best engine per operation.
|
|
124
|
+
|
|
125
|
+
## Framework-Aware Filling
|
|
126
|
+
|
|
127
|
+
React, Vue, and other SPA frameworks track input state internally — setting `.value` directly bypasses their event system and the field appears empty to the framework even though it looks filled to you.
|
|
128
|
+
|
|
129
|
+
`safari_fill` handles this correctly. It simulates real user input events (focus → input → change → blur) so framework state updates properly. Always use `safari_fill` for form inputs, not `safari_evaluate` with `.value =`.
|
|
130
|
+
|
|
131
|
+
After filling, always verify with a snapshot: check that the field shows the value and that dependent UI (validation messages, enabled submit buttons) has updated.
|
|
132
|
+
|
|
133
|
+
If `safari_fill` fails on a custom component, try `safari_click` on the element first to focus it, then `safari_type` to simulate keystroke-by-keystroke input.
|
|
134
|
+
|
|
135
|
+
## When NOT to Use Safari Pilot
|
|
136
|
+
|
|
137
|
+
**Lighthouse / performance audits** — Use Chrome DevTools (it has built-in Lighthouse integration). Safari doesn't expose Lighthouse scores. Use `safari_get_page_metrics` and `safari_begin_trace`/`safari_end_trace` for Safari-native perf data instead.
|
|
138
|
+
|
|
139
|
+
**Cross-platform browser testing** — Use Playwright if you need Chrome + Firefox + Safari in one run. Safari Pilot is single-browser by design.
|
|
140
|
+
|
|
141
|
+
**Pure content extraction from public URLs** — Jina (`r.jina.ai`) and Firecrawl are faster and don't require a live browser. Use Safari Pilot only when the page requires authentication, interaction, or real-browser rendering (e.g., paywalls, SPAs, login-protected content).
|
|
142
|
+
|
|
143
|
+
**Headless/CI environments** — Safari only runs on macOS with a display. This tool is for local desktop sessions.
|
|
144
|
+
|
|
145
|
+
## Error Recovery
|
|
146
|
+
|
|
147
|
+
**`CSP_BLOCKED`** — The page's Content Security Policy is blocking script injection. The extension bypasses CSP through the native extension API. Tell the user the extension is required and guide them to install it.
|
|
148
|
+
|
|
149
|
+
**`TIMEOUT`** — The selector wasn't found or the page didn't respond within the default window. Increase the timeout parameter. If the element genuinely doesn't exist, `safari_snapshot` will show you the actual DOM so you can correct the selector.
|
|
150
|
+
|
|
151
|
+
**`TAB_NOT_OWNED`** — You're trying to operate on a tab you didn't open this session. Use `safari_new_tab` to create your own tab, navigate there, and operate on that. Never ask the user to manually close tabs to work around this.
|
|
152
|
+
|
|
153
|
+
**`JS_APPLE_EVENTS_DISABLED`** — The user needs to enable "Allow JavaScript from Apple Events" in Safari → Develop menu. Without this, AppleScript can't execute JavaScript. Guide them there explicitly: Safari → Develop → Allow JavaScript from Apple Events.
|
|
154
|
+
|
|
155
|
+
**`KILL_SWITCH_ACTIVE`** — `safari_emergency_stop` was called. No further automation is possible in this session. Start a new Claude Code session to resume.
|
|
156
|
+
|
|
157
|
+
**`CIRCUIT_BREAKER_OPEN`** — Too many failures on the same domain triggered the circuit breaker (120s cooldown). Wait, then retry. If failures recur, investigate whether the page structure changed or authentication expired.
|