safari-pilot 0.1.4 → 0.1.26
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/commands/start.md +41 -0
- package/.claude-plugin/commands/stop.md +57 -0
- package/.claude-plugin/plugin.json +4 -0
- package/README.md +105 -26
- package/bin/Safari Pilot.app/Contents/CodeResources +0 -0
- package/bin/Safari Pilot.app/Contents/Info.plist +7 -7
- package/bin/Safari Pilot.app/Contents/MacOS/Safari Pilot +0 -0
- package/bin/Safari Pilot.app/Contents/PlugIns/Safari Pilot Extension.appex/Contents/Info.plist +6 -6
- 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 +1008 -262
- package/bin/Safari Pilot.app/Contents/PlugIns/Safari Pilot Extension.appex/Contents/Resources/build.config.js +14 -0
- package/bin/Safari Pilot.app/Contents/PlugIns/Safari Pilot Extension.appex/Contents/Resources/content-isolated.js +516 -0
- package/bin/Safari Pilot.app/Contents/PlugIns/Safari Pilot Extension.appex/Contents/Resources/content-main.js +269 -0
- package/bin/Safari Pilot.app/Contents/PlugIns/Safari Pilot Extension.appex/Contents/Resources/lib/handshake-machine.js +48 -0
- package/bin/Safari Pilot.app/Contents/PlugIns/Safari Pilot Extension.appex/Contents/Resources/lib/route-command.js +27 -0
- package/bin/Safari Pilot.app/Contents/PlugIns/Safari Pilot Extension.appex/Contents/Resources/lib/storage-keys.js +18 -0
- package/bin/Safari Pilot.app/Contents/PlugIns/Safari Pilot Extension.appex/Contents/Resources/manifest.json +14 -6
- package/bin/Safari Pilot.app/Contents/PlugIns/Safari Pilot Extension.appex/Contents/Resources/native/SafariWebExtensionHandler.swift +23 -0
- package/bin/Safari Pilot.app/Contents/PlugIns/Safari Pilot Extension.appex/Contents/_CodeSignature/CodeResources +63 -8
- package/bin/Safari Pilot.app/Contents/Resources/Assets.car +0 -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/_CodeSignature/CodeResources +9 -9
- package/bin/Safari Pilot.zip +0 -0
- package/bin/SafariPilotd +0 -0
- package/daemon/com.safari-pilot.daemon.plist +20 -0
- package/dist/aria.d.ts +50 -0
- package/dist/aria.js +466 -0
- package/dist/aria.js.map +1 -0
- package/dist/auto-wait.d.ts +38 -0
- package/dist/auto-wait.js +386 -0
- package/dist/auto-wait.js.map +1 -0
- package/dist/benchmark/eval.d.ts +30 -0
- package/dist/benchmark/eval.js +234 -0
- package/dist/benchmark/eval.js.map +1 -0
- package/dist/benchmark/fixture-server.d.ts +11 -0
- package/dist/benchmark/fixture-server.js +163 -0
- package/dist/benchmark/fixture-server.js.map +1 -0
- package/dist/benchmark/reporter.d.ts +59 -0
- package/dist/benchmark/reporter.js +333 -0
- package/dist/benchmark/reporter.js.map +1 -0
- package/dist/benchmark/runner.d.ts +22 -0
- package/dist/benchmark/runner.js +486 -0
- package/dist/benchmark/runner.js.map +1 -0
- package/dist/benchmark/stream-parser.d.ts +36 -0
- package/dist/benchmark/stream-parser.js +199 -0
- package/dist/benchmark/stream-parser.js.map +1 -0
- package/dist/benchmark/task-loader.d.ts +26 -0
- package/dist/benchmark/task-loader.js +147 -0
- package/dist/benchmark/task-loader.js.map +1 -0
- package/dist/benchmark/types.d.ts +129 -0
- package/dist/benchmark/types.js +67 -0
- package/dist/benchmark/types.js.map +1 -0
- package/dist/benchmark/worker.d.ts +32 -0
- package/dist/benchmark/worker.js +209 -0
- package/dist/benchmark/worker.js.map +1 -0
- package/dist/config.d.ts +52 -0
- package/dist/config.js +181 -0
- package/dist/config.js.map +1 -0
- package/dist/engine-selector.d.ts +16 -0
- package/dist/engine-selector.js +40 -6
- package/dist/engine-selector.js.map +1 -1
- package/dist/engines/applescript.d.ts +21 -5
- package/dist/engines/applescript.js +85 -86
- package/dist/engines/applescript.js.map +1 -1
- package/dist/engines/daemon.d.ts +49 -1
- package/dist/engines/daemon.js +264 -17
- package/dist/engines/daemon.js.map +1 -1
- package/dist/engines/engine-proxy.d.ts +53 -0
- package/dist/engines/engine-proxy.js +84 -0
- package/dist/engines/engine-proxy.js.map +1 -0
- package/dist/engines/engine.d.ts +14 -0
- package/dist/engines/engine.js +21 -0
- package/dist/engines/engine.js.map +1 -1
- package/dist/engines/extension.d.ts +25 -2
- package/dist/engines/extension.js +130 -5
- package/dist/engines/extension.js.map +1 -1
- package/dist/engines/js-helpers.d.ts +20 -0
- package/dist/engines/js-helpers.js +112 -0
- package/dist/engines/js-helpers.js.map +1 -0
- package/dist/errors.d.ts +190 -5
- package/dist/errors.js +320 -4
- package/dist/errors.js.map +1 -1
- package/dist/escape.d.ts +16 -0
- package/dist/escape.js +32 -0
- package/dist/escape.js.map +1 -0
- package/dist/index.js +78 -2
- package/dist/index.js.map +1 -1
- package/dist/locator.d.ts +62 -0
- package/dist/locator.js +472 -0
- package/dist/locator.js.map +1 -0
- package/dist/path-resolve.d.ts +6 -0
- package/dist/path-resolve.js +97 -0
- package/dist/path-resolve.js.map +1 -0
- package/dist/security/audit-log.d.ts +3 -3
- package/dist/security/audit-log.js +2 -0
- package/dist/security/audit-log.js.map +1 -1
- package/dist/security/circuit-breaker.d.ts +33 -0
- package/dist/security/circuit-breaker.js +74 -15
- package/dist/security/circuit-breaker.js.map +1 -1
- package/dist/security/domain-policy.d.ts +10 -3
- package/dist/security/domain-policy.js +32 -9
- package/dist/security/domain-policy.js.map +1 -1
- package/dist/security/human-approval.d.ts +11 -0
- package/dist/security/human-approval.js +19 -3
- package/dist/security/human-approval.js.map +1 -1
- package/dist/security/idpi-annotator.d.ts +30 -0
- package/dist/security/{idpi-scanner.js → idpi-annotator.js} +39 -14
- package/dist/security/idpi-annotator.js.map +1 -0
- package/dist/security/rate-limiter.d.ts +7 -0
- package/dist/security/rate-limiter.js +17 -8
- package/dist/security/rate-limiter.js.map +1 -1
- package/dist/security/screenshot-policy.d.ts +7 -0
- package/dist/security/screenshot-policy.js +37 -0
- package/dist/security/screenshot-policy.js.map +1 -0
- package/dist/security/tab-ownership.d.ts +28 -10
- package/dist/security/tab-ownership.js +57 -27
- package/dist/security/tab-ownership.js.map +1 -1
- package/dist/server.d.ts +124 -4
- package/dist/server.js +1113 -69
- package/dist/server.js.map +1 -1
- package/dist/tools/_frame-routing-helper.d.ts +6 -0
- package/dist/tools/_frame-routing-helper.js +25 -0
- package/dist/tools/_frame-routing-helper.js.map +1 -0
- package/dist/tools/auth.d.ts +20 -0
- package/dist/tools/auth.js +135 -0
- package/dist/tools/auth.js.map +1 -0
- package/dist/tools/clipboard.d.ts +2 -2
- package/dist/tools/clipboard.js +4 -6
- package/dist/tools/clipboard.js.map +1 -1
- package/dist/tools/compound.d.ts +2 -0
- package/dist/tools/compound.js +27 -8
- package/dist/tools/compound.js.map +1 -1
- package/dist/tools/downloads.d.ts +33 -0
- package/dist/tools/downloads.js +491 -0
- package/dist/tools/downloads.js.map +1 -0
- package/dist/tools/extension-diagnostics.d.ts +31 -0
- package/dist/tools/extension-diagnostics.js +130 -0
- package/dist/tools/extension-diagnostics.js.map +1 -0
- package/dist/tools/extraction.d.ts +6 -2
- package/dist/tools/extraction.js +226 -135
- package/dist/tools/extraction.js.map +1 -1
- package/dist/tools/file-upload.d.ts +21 -0
- package/dist/tools/file-upload.js +212 -0
- package/dist/tools/file-upload.js.map +1 -0
- package/dist/tools/frames.d.ts +2 -3
- package/dist/tools/frames.js +49 -55
- package/dist/tools/frames.js.map +1 -1
- package/dist/tools/har.d.ts +105 -0
- package/dist/tools/har.js +215 -0
- package/dist/tools/har.js.map +1 -0
- package/dist/tools/interaction.d.ts +14 -2
- package/dist/tools/interaction.js +324 -121
- package/dist/tools/interaction.js.map +1 -1
- package/dist/tools/mime.d.ts +5 -0
- package/dist/tools/mime.js +103 -0
- package/dist/tools/mime.js.map +1 -0
- package/dist/tools/navigation.d.ts +5 -0
- package/dist/tools/navigation.js +78 -29
- package/dist/tools/navigation.js.map +1 -1
- package/dist/tools/network.d.ts +4 -2
- package/dist/tools/network.js +195 -16
- package/dist/tools/network.js.map +1 -1
- package/dist/tools/pdf.d.ts +70 -0
- package/dist/tools/pdf.js +560 -0
- package/dist/tools/pdf.js.map +1 -0
- package/dist/tools/performance.d.ts +2 -2
- package/dist/tools/performance.js +6 -9
- package/dist/tools/performance.js.map +1 -1
- package/dist/tools/permissions.d.ts +2 -2
- package/dist/tools/permissions.js +11 -10
- package/dist/tools/permissions.js.map +1 -1
- package/dist/tools/service-workers.d.ts +2 -2
- package/dist/tools/service-workers.js +4 -6
- package/dist/tools/service-workers.js.map +1 -1
- package/dist/tools/shadow.d.ts +2 -2
- package/dist/tools/shadow.js +14 -8
- package/dist/tools/shadow.js.map +1 -1
- package/dist/tools/storage.d.ts +2 -2
- package/dist/tools/storage.js +106 -37
- package/dist/tools/storage.js.map +1 -1
- package/dist/tools/structured-extraction.d.ts +2 -2
- package/dist/tools/structured-extraction.js +8 -7
- package/dist/tools/structured-extraction.js.map +1 -1
- package/dist/tools/wait.d.ts +3 -3
- package/dist/tools/wait.js +6 -8
- package/dist/tools/wait.js.map +1 -1
- package/dist/trace-collector.d.ts +231 -0
- package/dist/trace-collector.js +584 -0
- package/dist/trace-collector.js.map +1 -0
- package/dist/trace.d.ts +3 -0
- package/dist/trace.js +27 -0
- package/dist/trace.js.map +1 -0
- package/dist/types.d.ts +68 -1
- package/extension/background.js +1131 -260
- package/extension/build.config.js +14 -0
- package/extension/content-isolated.js +556 -0
- package/extension/content-main.js +269 -0
- package/extension/lib/handshake-machine.js +48 -0
- package/extension/lib/route-command.js +27 -0
- package/extension/lib/storage-keys.js +18 -0
- package/extension/manifest.json +14 -6
- package/extension/native/SafariWebExtensionHandler.swift +23 -0
- package/hooks/distribution-check.sh +75 -0
- package/hooks/e2e-coverage-check.sh +33 -0
- package/hooks/e2e-no-mocks.sh +37 -0
- package/hooks/pre-publish-verify.sh +59 -0
- package/hooks/safari-pilot-guard.sh +82 -0
- package/hooks/session-end.sh +12 -0
- package/launchagents/com.safari-pilot.health-check.plist +22 -0
- package/package.json +21 -7
- package/safari-pilot.config.json +44 -0
- package/scripts/build-extension.sh +89 -13
- package/scripts/health-check.sh +36 -0
- package/scripts/postinstall.sh +104 -19
- package/scripts/pre-tag-check.sh +149 -0
- package/scripts/preuninstall.sh +4 -0
- package/scripts/promote-stable.sh +44 -0
- package/scripts/test-e2e-harness.sh +64 -0
- package/scripts/trace-merge.sh +13 -0
- package/scripts/trace-rotate.sh +13 -0
- package/scripts/update-daemon.sh +23 -4
- package/scripts/verify-artifact-integrity.sh +85 -0
- package/scripts/verify-extension-smoke.sh +43 -0
- package/skills/safari-pilot/SKILL.md +32 -1
- package/dist/security/idpi-scanner.d.ts +0 -20
- package/dist/security/idpi-scanner.js.map +0 -1
- package/dist/security/screenshot-redaction.d.ts +0 -42
- package/dist/security/screenshot-redaction.js +0 -134
- package/dist/security/screenshot-redaction.js.map +0 -1
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: start
|
|
3
|
+
description: Start the Safari Pilot daemon (idempotent — safe to call if already running)
|
|
4
|
+
allowed-tools: Bash
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
Start the SafariPilotd daemon process. This is idempotent — if the daemon is already running, report its PID and exit.
|
|
8
|
+
|
|
9
|
+
## Steps
|
|
10
|
+
|
|
11
|
+
1. Check if the daemon is already running:
|
|
12
|
+
```bash
|
|
13
|
+
pgrep -f SafariPilotd
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
2. **If already running**, report the PID and exit:
|
|
17
|
+
> Safari Pilot daemon already running (PID: {pid})
|
|
18
|
+
|
|
19
|
+
3. **If not running**, start it:
|
|
20
|
+
```bash
|
|
21
|
+
DAEMON_BIN="${CLAUDE_PLUGIN_ROOT}/bin/SafariPilotd"
|
|
22
|
+
DATA_DIR="${HOME}/.safari-pilot"
|
|
23
|
+
mkdir -p "$DATA_DIR"
|
|
24
|
+
"$DAEMON_BIN" --daemon >> "$DATA_DIR/daemon.log" 2>&1 &
|
|
25
|
+
echo $! > "$DATA_DIR/daemon.pid"
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
4. Verify it started (check PID is alive):
|
|
29
|
+
```bash
|
|
30
|
+
kill -0 $(cat ~/.safari-pilot/daemon.pid) 2>/dev/null
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
5. Report the result:
|
|
34
|
+
> Safari Pilot daemon started (PID: {pid})
|
|
35
|
+
>
|
|
36
|
+
> The Safari extension is managed separately in Safari > Settings > Extensions.
|
|
37
|
+
|
|
38
|
+
## If the daemon binary is missing
|
|
39
|
+
|
|
40
|
+
Report:
|
|
41
|
+
> SafariPilotd not found at {path}. Run `npm install` in the safari-pilot directory to build it, or install Xcode Command Line Tools if Swift is not available.
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: stop
|
|
3
|
+
description: Stop the Safari Pilot daemon gracefully
|
|
4
|
+
allowed-tools: Bash
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
Stop the SafariPilotd daemon process. Attempts graceful SIGTERM shutdown, falls back to SIGKILL if needed.
|
|
8
|
+
|
|
9
|
+
## Steps
|
|
10
|
+
|
|
11
|
+
1. Find the daemon PID from the PID file or process list:
|
|
12
|
+
```bash
|
|
13
|
+
PID_FILE="${HOME}/.safari-pilot/daemon.pid"
|
|
14
|
+
if [ -f "$PID_FILE" ]; then
|
|
15
|
+
PID=$(cat "$PID_FILE")
|
|
16
|
+
else
|
|
17
|
+
PID=$(pgrep -f SafariPilotd)
|
|
18
|
+
fi
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
2. **If PID was found**, verify the process is actually alive:
|
|
22
|
+
```bash
|
|
23
|
+
kill -0 "$PID" 2>/dev/null
|
|
24
|
+
```
|
|
25
|
+
If the process is not alive, clean up the stale PID file and report:
|
|
26
|
+
```bash
|
|
27
|
+
rm -f "${HOME}/.safari-pilot/daemon.pid"
|
|
28
|
+
```
|
|
29
|
+
> Safari Pilot daemon is not running (cleaned up stale PID file).
|
|
30
|
+
|
|
31
|
+
3. **If no PID was found or process is dead**, report and exit:
|
|
32
|
+
> Safari Pilot daemon is not running.
|
|
33
|
+
|
|
34
|
+
4. **If running**, send SIGTERM for graceful shutdown:
|
|
35
|
+
```bash
|
|
36
|
+
kill "$PID" 2>/dev/null
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
5. Wait up to 3 seconds for the process to exit:
|
|
40
|
+
```bash
|
|
41
|
+
for i in 1 2 3; do
|
|
42
|
+
kill -0 "$PID" 2>/dev/null || break
|
|
43
|
+
sleep 1
|
|
44
|
+
done
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
6. Check if it stopped:
|
|
48
|
+
- **If stopped**: clean up the PID file and report:
|
|
49
|
+
```bash
|
|
50
|
+
rm -f "${HOME}/.safari-pilot/daemon.pid"
|
|
51
|
+
```
|
|
52
|
+
> Safari Pilot daemon stopped (was PID: {pid})
|
|
53
|
+
- **If still running after 3s**: report the fallback command:
|
|
54
|
+
> Daemon did not stop gracefully. To force kill: `kill -9 {pid}`
|
|
55
|
+
|
|
56
|
+
7. Always note:
|
|
57
|
+
> The Safari extension remains active independently in Safari > Settings > Extensions.
|
package/README.md
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
|
|
5
5
|
Safari Pilot gives Claude Code direct control of Safari through AppleScript and a persistent Swift daemon — no Chrome, no Playwright, no third-party code touching your browser. Your real Safari, with all your logins, automated natively.
|
|
6
6
|
|
|
7
|
-
> **
|
|
7
|
+
> **82 tools** | **3 engine tiers** | **92x faster than raw AppleScript** | **9 security layers** | **macOS 14+ recommended** (12+ minimum)
|
|
8
8
|
|
|
9
9
|
---
|
|
10
10
|
|
|
@@ -69,7 +69,13 @@ The extension unlocks advanced features that are impossible without it.
|
|
|
69
69
|
6. Set to **"Allow on all websites"** when prompted
|
|
70
70
|
7. Click **"Manage Profiles"** and enable for your active profile
|
|
71
71
|
|
|
72
|
-
The extension is signed with Developer ID and notarized by Apple — it persists permanently across Safari restarts.
|
|
72
|
+
The extension is signed with Developer ID and notarized by Apple — it persists permanently across Safari restarts.
|
|
73
|
+
|
|
74
|
+
> **Troubleshooting:** If Safari shows **"Safari detected an app or service that interfered with clicking"** when you try to enable the extension, this is a Safari security feature triggered by other apps on your Mac that have Accessibility, Screen Recording, or Input Monitoring permissions (e.g., terminal emulators, screen sharing tools, window managers). To work around it:
|
|
75
|
+
> 1. Go to **Safari > Develop > Allow Unsigned Extensions** (check it temporarily)
|
|
76
|
+
> 2. Enable Safari Pilot in **Safari > Settings > Extensions**
|
|
77
|
+
> 3. Quit and reopen Safari
|
|
78
|
+
> 4. Optionally uncheck "Allow Unsigned Extensions" — the notarized extension stays enabled
|
|
73
79
|
|
|
74
80
|
**What the extension adds:**
|
|
75
81
|
|
|
@@ -85,7 +91,8 @@ Without the extension, Safari Pilot still works for ~80% of use cases (navigatio
|
|
|
85
91
|
|
|
86
92
|
### System Requirements
|
|
87
93
|
|
|
88
|
-
- **macOS
|
|
94
|
+
- **macOS 14.0 (Sonoma)** or later — recommended; required for the extension engine (the daemon's HTTP poll server uses Hummingbird, which requires macOS 14+)
|
|
95
|
+
- **macOS 12.0 (Monterey)** — minimum; daemon + AppleScript engines work, extension features are unavailable
|
|
89
96
|
- **Safari** (pre-installed on every Mac)
|
|
90
97
|
- **Node.js 20+**
|
|
91
98
|
|
|
@@ -113,7 +120,7 @@ Monitor news.ycombinator.com for any post about our company
|
|
|
113
120
|
Open my X.com bookmarks and extract the top 5 posts with author profiles
|
|
114
121
|
```
|
|
115
122
|
|
|
116
|
-
## Tool Catalog (
|
|
123
|
+
## Tool Catalog (82 Tools)
|
|
117
124
|
|
|
118
125
|
### Navigation (7)
|
|
119
126
|
`safari_navigate` | `safari_navigate_back` | `safari_navigate_forward` | `safari_reload` | `safari_new_tab` | `safari_close_tab` | `safari_list_tabs`
|
|
@@ -121,20 +128,26 @@ Open my X.com bookmarks and extract the top 5 posts with author profiles
|
|
|
121
128
|
### Interaction (11)
|
|
122
129
|
`safari_click` | `safari_double_click` | `safari_fill` | `safari_select_option` | `safari_check` | `safari_hover` | `safari_type` | `safari_press_key` | `safari_scroll` | `safari_drag` | `safari_handle_dialog`
|
|
123
130
|
|
|
131
|
+
### File Upload (1)
|
|
132
|
+
`safari_file_upload` — programmatic upload to standard `<input type=file>` elements, including hidden inputs behind `<label>` (use `force: true`). 25 MiB / file × 4 / call. Path B architecture: out-of-band byte transport via daemon staging → extension fetch. Does NOT support drag-and-drop dropzones, custom pickers, or native OS dialogs.
|
|
133
|
+
|
|
124
134
|
### Extraction (7)
|
|
125
135
|
`safari_snapshot` | `safari_get_text` | `safari_get_html` | `safari_get_attribute` | `safari_evaluate` | `safari_take_screenshot` | `safari_get_console_messages`
|
|
126
136
|
|
|
127
|
-
### Network (
|
|
128
|
-
`safari_list_network_requests` | `safari_get_network_request` | `safari_intercept_requests` | `safari_network_throttle` | `safari_network_offline` | `safari_mock_request` | `safari_websocket_listen` | `safari_websocket_filter`
|
|
137
|
+
### Network (10)
|
|
138
|
+
`safari_list_network_requests` | `safari_get_network_request` | `safari_intercept_requests` | `safari_network_throttle` | `safari_network_offline` | `safari_mock_request` | `safari_websocket_listen` | `safari_websocket_filter` | `safari_dump_har` | `safari_route_from_har`
|
|
129
139
|
|
|
130
140
|
### Storage (11)
|
|
131
141
|
`safari_get_cookies` | `safari_set_cookie` | `safari_delete_cookie` | `safari_storage_state_export` | `safari_storage_state_import` | `safari_local_storage_get` | `safari_local_storage_set` | `safari_session_storage_get` | `safari_session_storage_set` | `safari_idb_list` | `safari_idb_get`
|
|
132
142
|
|
|
143
|
+
### Authentication (2)
|
|
144
|
+
`safari_authenticate` | `safari_clear_authentication` — HTTP Basic auth via DNR header injection (extension required).
|
|
145
|
+
|
|
133
146
|
### Shadow DOM (2)
|
|
134
147
|
`safari_query_shadow` | `safari_click_shadow`
|
|
135
148
|
|
|
136
|
-
### Frames (
|
|
137
|
-
`safari_list_frames` | `
|
|
149
|
+
### Frames (2)
|
|
150
|
+
`safari_list_frames` | `safari_eval_in_frame`
|
|
138
151
|
|
|
139
152
|
### Permissions & Overrides (6)
|
|
140
153
|
`safari_permission_get` | `safari_permission_set` | `safari_override_geolocation` | `safari_override_timezone` | `safari_override_locale` | `safari_override_useragent`
|
|
@@ -154,9 +167,18 @@ Open my X.com bookmarks and extract the top 5 posts with author profiles
|
|
|
154
167
|
### Compound Workflows (4)
|
|
155
168
|
`safari_test_flow` | `safari_monitor_page` | `safari_paginate_scrape` | `safari_media_control`
|
|
156
169
|
|
|
170
|
+
### Downloads (1)
|
|
171
|
+
`safari_wait_for_download` — wait for download triggered by a click, capture metadata + optional `saveAs`.
|
|
172
|
+
|
|
173
|
+
### PDF (1)
|
|
174
|
+
`safari_export_pdf` — export the frontmost Safari tab as a PDF via WKWebView.
|
|
175
|
+
|
|
157
176
|
### Wait (1)
|
|
158
177
|
`safari_wait_for` — 7 condition types: selector, selectorHidden, text, textGone, urlMatch, networkidle, function
|
|
159
178
|
|
|
179
|
+
### Diagnostics (2)
|
|
180
|
+
`safari_extension_health` | `safari_extension_debug_dump` — observability for the extension engine. Read-only; safe to call any time.
|
|
181
|
+
|
|
160
182
|
### System (2)
|
|
161
183
|
`safari_health_check` | `safari_emergency_stop`
|
|
162
184
|
|
|
@@ -224,11 +246,11 @@ Safari Pilot runs on your local machine with access to your real browser session
|
|
|
224
246
|
|
|
225
247
|
**Domain Policy** — Per-domain rate limits prevent runaway automation. Banking and financial domains flagged as untrusted by default.
|
|
226
248
|
|
|
227
|
-
**Rate Limiter + Circuit Breaker** —
|
|
249
|
+
**Rate Limiter + Circuit Breaker** — Configurable via `safari-pilot.config.json`. Defaults: 120 actions/minute, circuit breaker trips at 5 errors with 120s cooldown.
|
|
228
250
|
|
|
229
251
|
**IDPI Scanner** — Indirect Prompt Injection defense. Scans extracted text for 9 known injection patterns.
|
|
230
252
|
|
|
231
|
-
**Kill Switch** — `safari_emergency_stop` immediately halts all automation.
|
|
253
|
+
**Kill Switch** — `safari_emergency_stop` immediately halts all automation. Configurable auto-activation on error threshold.
|
|
232
254
|
|
|
233
255
|
**Human Approval** — Sensitive actions (OAuth consent, financial forms, downloads) flagged for explicit approval.
|
|
234
256
|
|
|
@@ -238,6 +260,34 @@ Safari Pilot runs on your local machine with access to your real browser session
|
|
|
238
260
|
|
|
239
261
|
**No Credential Access** — Safari Pilot **never** accesses the macOS Keychain. Authentication works through real browser interaction.
|
|
240
262
|
|
|
263
|
+
## Configuration
|
|
264
|
+
|
|
265
|
+
All security settings are tunable via `safari-pilot.config.json` in the package root:
|
|
266
|
+
|
|
267
|
+
```json
|
|
268
|
+
{
|
|
269
|
+
"schemaVersion": "1.0",
|
|
270
|
+
"rateLimit": { "maxActionsPerMinute": 120, "windowMs": 60000 },
|
|
271
|
+
"circuitBreaker": { "errorThreshold": 5, "windowMs": 60000, "cooldownMs": 120000 },
|
|
272
|
+
"domainPolicy": { "defaultMaxActionsPerMinute": 60, "blocked": [], "trusted": [] },
|
|
273
|
+
"killSwitch": { "autoActivation": false, "maxErrors": 5, "windowSeconds": 60 },
|
|
274
|
+
"audit": { "maxEntries": 10000, "logPath": "~/.safari-pilot/audit.log" },
|
|
275
|
+
"daemon": { "timeoutMs": 30000 },
|
|
276
|
+
"healthCheck": { "timeoutMs": 3000 }
|
|
277
|
+
}
|
|
278
|
+
```
|
|
279
|
+
|
|
280
|
+
Missing file → all defaults. Partial file → deep-merge with defaults. Sensitive domain protections (banking, PayPal, etc.) cannot be overridden via config.
|
|
281
|
+
|
|
282
|
+
Set `SAFARI_PILOT_CONFIG` env var to use a custom config path.
|
|
283
|
+
|
|
284
|
+
### Daemon Lifecycle
|
|
285
|
+
|
|
286
|
+
```bash
|
|
287
|
+
/safari-pilot start # Start daemon, report PID (idempotent)
|
|
288
|
+
/safari-pilot stop # Graceful shutdown with SIGKILL fallback
|
|
289
|
+
```
|
|
290
|
+
|
|
241
291
|
## Development
|
|
242
292
|
|
|
243
293
|
### Building from Source
|
|
@@ -246,33 +296,37 @@ Safari Pilot runs on your local machine with access to your real browser session
|
|
|
246
296
|
# TypeScript server
|
|
247
297
|
npm run build
|
|
248
298
|
|
|
249
|
-
# Swift daemon
|
|
250
|
-
|
|
251
|
-
cp .build/release/SafariPilotd ../bin/
|
|
299
|
+
# Swift daemon (rebuild + atomic swap + launchctl restart)
|
|
300
|
+
bash scripts/update-daemon.sh
|
|
252
301
|
|
|
253
|
-
# Safari extension (
|
|
302
|
+
# Safari extension (Xcode archive → sign → notarize)
|
|
254
303
|
bash scripts/build-extension.sh
|
|
255
304
|
```
|
|
256
305
|
|
|
257
306
|
### Testing
|
|
258
307
|
|
|
259
308
|
```bash
|
|
260
|
-
#
|
|
261
|
-
npm test
|
|
309
|
+
# Default — unit tests, no Safari required
|
|
310
|
+
npm test # 398 unit tests
|
|
311
|
+
npm run test:unit # alias for above
|
|
262
312
|
|
|
263
|
-
#
|
|
264
|
-
npm run test:
|
|
265
|
-
npm run test:
|
|
266
|
-
npm run test:security # 27 security-focused tests
|
|
267
|
-
npm run test:e2e # 31 tests against real Safari
|
|
313
|
+
# Real Safari required (production stack must be running)
|
|
314
|
+
npm run test:e2e # ~30 e2e tests across 12+ files
|
|
315
|
+
npm run test:e2e:harness # 5 tests requiring DEBUG_HARNESS build (auto-rebuilds release after)
|
|
268
316
|
|
|
269
|
-
#
|
|
270
|
-
|
|
317
|
+
# Both
|
|
318
|
+
npm run test:all # unit + e2e
|
|
271
319
|
|
|
272
|
-
#
|
|
273
|
-
|
|
320
|
+
# Swift daemon (real Swift types, mocked at NSAppleScript boundary only)
|
|
321
|
+
cd daemon && swift test # 153 tests
|
|
274
322
|
```
|
|
275
323
|
|
|
324
|
+
**Test policy:**
|
|
325
|
+
- Unit tests (`test/unit/`) cover pure logic; can mock Node boundaries (`fs`, `net`, `child_process`) but never internal modules.
|
|
326
|
+
- E2E tests (`test/e2e/`) spawn a real MCP server, drive Safari through the real stack, and use ZERO mocks (enforced by pre-commit hook). They fail closed on any `vi.mock` or direct `import from '../../src/'`.
|
|
327
|
+
- The harness-dependent tests (`t21`, `t22`, `t27`, `t44`, `t55a`) require `SAFARI_PILOT_TEST_MODE=1` build markers stripped from production. `npm run test:e2e:harness` automates the test build → run → release-rebuild flow. Local-only (refuses on CI).
|
|
328
|
+
- See `CLAUDE.md` "End-to-End Testing (HARD RULES)" for the full contract.
|
|
329
|
+
|
|
276
330
|
### Adding a New Tool
|
|
277
331
|
|
|
278
332
|
1. Add the handler to the appropriate module in `src/tools/`
|
|
@@ -280,6 +334,31 @@ bash test/canary/install-test.sh
|
|
|
280
334
|
3. Write tests in `test/unit/tools/`
|
|
281
335
|
4. The server auto-registers tools from all modules in `initialize()`
|
|
282
336
|
5. Add the tool name to `skills/safari-pilot/SKILL.md` allowed-tools
|
|
337
|
+
6. If touching `extension/*` or `daemon/Sources/*`, follow `CLAUDE.md` "Extension Build: Hard Rules" — version bump in lockstep, ditto with metadata-stripping flags, run `bash scripts/pre-tag-check.sh` before any tag push.
|
|
338
|
+
|
|
339
|
+
### Releasing a new version
|
|
340
|
+
|
|
341
|
+
The release pipeline is automated via `.github/workflows/release.yml` on tag push. Before tagging, run the local SOP gate:
|
|
342
|
+
|
|
343
|
+
```bash
|
|
344
|
+
# 1. Bump versions in lockstep
|
|
345
|
+
# Edit package.json + extension/manifest.json (must match)
|
|
346
|
+
|
|
347
|
+
# 2. Rebuild extension if extension/* changed
|
|
348
|
+
bash scripts/build-extension.sh
|
|
349
|
+
|
|
350
|
+
# 3. Local install rehearsal
|
|
351
|
+
open "bin/Safari Pilot.app" # verify in Safari Settings
|
|
352
|
+
|
|
353
|
+
# 4. Mandatory pre-tag check (mirrors every CI verify step)
|
|
354
|
+
bash scripts/pre-tag-check.sh # must print "ALL CHECKS PASSED"
|
|
355
|
+
|
|
356
|
+
# 5. Commit, tag, push
|
|
357
|
+
git tag -a v0.1.X -m "..."
|
|
358
|
+
git push origin main && git push origin v0.1.X
|
|
359
|
+
```
|
|
360
|
+
|
|
361
|
+
The pre-tag check catches: AppleDouble (`._*`) metadata in zip, codesign --deep --strict failures, missing entitlements, version mismatch, dangling tag, prepublish hook misconfiguration, unit test regressions. It runs in seconds and saves CI round-trips.
|
|
283
362
|
|
|
284
363
|
## What Safari Pilot Does NOT Replace
|
|
285
364
|
|
|
@@ -308,7 +387,7 @@ The daemon detects Safari crashes (error codes -600/-609) and retries with expon
|
|
|
308
387
|
Safari Pilot is built from scratch — no code from third-party Safari MCP packages. Every line that touches your browser is first-party and auditable. We also add 9 security layers, a persistent Swift daemon (92x faster), and structured extraction tools.
|
|
309
388
|
|
|
310
389
|
**Q: Does the Swift daemon run all the time?**
|
|
311
|
-
|
|
390
|
+
The daemon starts on Claude Code session start (via the SessionStart hook) and stays running between sessions for fast restart. Use `/safari-pilot stop` to shut it down manually. The LaunchAgent auto-restarts it if it crashes.
|
|
312
391
|
|
|
313
392
|
**Q: Do I need the Safari extension?**
|
|
314
393
|
No — Safari Pilot works without it for ~80% of use cases. The extension adds Shadow DOM traversal, CSP bypass, dialog interception, and network mocking. Install it from the [GitHub Release](https://github.com/RTinkslinger/safari-pilot/releases/latest) if you need those features.
|
|
Binary file
|
|
@@ -23,29 +23,29 @@
|
|
|
23
23
|
<key>CFBundlePackageType</key>
|
|
24
24
|
<string>APPL</string>
|
|
25
25
|
<key>CFBundleShortVersionString</key>
|
|
26
|
-
<string>0.1.
|
|
26
|
+
<string>0.1.26</string>
|
|
27
27
|
<key>CFBundleSupportedPlatforms</key>
|
|
28
28
|
<array>
|
|
29
29
|
<string>MacOSX</string>
|
|
30
30
|
</array>
|
|
31
31
|
<key>CFBundleVersion</key>
|
|
32
|
-
<string>
|
|
32
|
+
<string>202605041322</string>
|
|
33
33
|
<key>DTCompiler</key>
|
|
34
34
|
<string>com.apple.compilers.llvm.clang.1_0</string>
|
|
35
35
|
<key>DTPlatformBuild</key>
|
|
36
|
-
<string>
|
|
36
|
+
<string>25E251</string>
|
|
37
37
|
<key>DTPlatformName</key>
|
|
38
38
|
<string>macosx</string>
|
|
39
39
|
<key>DTPlatformVersion</key>
|
|
40
40
|
<string>26.4</string>
|
|
41
41
|
<key>DTSDKBuild</key>
|
|
42
|
-
<string>
|
|
42
|
+
<string>25E251</string>
|
|
43
43
|
<key>DTSDKName</key>
|
|
44
44
|
<string>macosx26.4</string>
|
|
45
45
|
<key>DTXcode</key>
|
|
46
|
-
<string>
|
|
46
|
+
<string>2641</string>
|
|
47
47
|
<key>DTXcodeBuild</key>
|
|
48
|
-
<string>
|
|
48
|
+
<string>17E202</string>
|
|
49
49
|
<key>LSMinimumSystemVersion</key>
|
|
50
50
|
<string>26.4</string>
|
|
51
51
|
<key>NSMainStoryboardFile</key>
|
|
@@ -53,6 +53,6 @@
|
|
|
53
53
|
<key>NSPrincipalClass</key>
|
|
54
54
|
<string>NSApplication</string>
|
|
55
55
|
<key>SFSafariWebExtensionConverterVersion</key>
|
|
56
|
-
<string>26.4</string>
|
|
56
|
+
<string>26.4.1</string>
|
|
57
57
|
</dict>
|
|
58
58
|
</plist>
|
|
Binary file
|
package/bin/Safari Pilot.app/Contents/PlugIns/Safari Pilot Extension.appex/Contents/Info.plist
CHANGED
|
@@ -19,29 +19,29 @@
|
|
|
19
19
|
<key>CFBundlePackageType</key>
|
|
20
20
|
<string>XPC!</string>
|
|
21
21
|
<key>CFBundleShortVersionString</key>
|
|
22
|
-
<string>0.1.
|
|
22
|
+
<string>0.1.26</string>
|
|
23
23
|
<key>CFBundleSupportedPlatforms</key>
|
|
24
24
|
<array>
|
|
25
25
|
<string>MacOSX</string>
|
|
26
26
|
</array>
|
|
27
27
|
<key>CFBundleVersion</key>
|
|
28
|
-
<string>
|
|
28
|
+
<string>202605041322</string>
|
|
29
29
|
<key>DTCompiler</key>
|
|
30
30
|
<string>com.apple.compilers.llvm.clang.1_0</string>
|
|
31
31
|
<key>DTPlatformBuild</key>
|
|
32
|
-
<string>
|
|
32
|
+
<string>25E251</string>
|
|
33
33
|
<key>DTPlatformName</key>
|
|
34
34
|
<string>macosx</string>
|
|
35
35
|
<key>DTPlatformVersion</key>
|
|
36
36
|
<string>26.4</string>
|
|
37
37
|
<key>DTSDKBuild</key>
|
|
38
|
-
<string>
|
|
38
|
+
<string>25E251</string>
|
|
39
39
|
<key>DTSDKName</key>
|
|
40
40
|
<string>macosx26.4</string>
|
|
41
41
|
<key>DTXcode</key>
|
|
42
|
-
<string>
|
|
42
|
+
<string>2641</string>
|
|
43
43
|
<key>DTXcodeBuild</key>
|
|
44
|
-
<string>
|
|
44
|
+
<string>17E202</string>
|
|
45
45
|
<key>LSMinimumSystemVersion</key>
|
|
46
46
|
<string>10.14</string>
|
|
47
47
|
<key>NSExtension</key>
|