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.
Files changed (143) hide show
  1. package/.claude-plugin/plugin.json +35 -0
  2. package/.mcp.json +11 -0
  3. package/LICENSE +21 -0
  4. package/README.md +324 -0
  5. package/bin/.gitkeep +0 -0
  6. package/bin/Safari Pilot.app/Contents/CodeResources +0 -0
  7. package/bin/Safari Pilot.app/Contents/Info.plist +58 -0
  8. package/bin/Safari Pilot.app/Contents/MacOS/Safari Pilot +0 -0
  9. package/bin/Safari Pilot.app/Contents/PkgInfo +1 -0
  10. package/bin/Safari Pilot.app/Contents/PlugIns/Safari Pilot Extension.appex/Contents/Info.plist +55 -0
  11. package/bin/Safari Pilot.app/Contents/PlugIns/Safari Pilot Extension.appex/Contents/MacOS/Safari Pilot Extension +0 -0
  12. package/bin/Safari Pilot.app/Contents/PlugIns/Safari Pilot Extension.appex/Contents/Resources/background.js +294 -0
  13. package/bin/Safari Pilot.app/Contents/PlugIns/Safari Pilot Extension.appex/Contents/Resources/content-isolated.js +80 -0
  14. package/bin/Safari Pilot.app/Contents/PlugIns/Safari Pilot Extension.appex/Contents/Resources/content-main.js +310 -0
  15. package/bin/Safari Pilot.app/Contents/PlugIns/Safari Pilot Extension.appex/Contents/Resources/icons/icon-128.png +0 -0
  16. package/bin/Safari Pilot.app/Contents/PlugIns/Safari Pilot Extension.appex/Contents/Resources/icons/icon-48.png +0 -0
  17. package/bin/Safari Pilot.app/Contents/PlugIns/Safari Pilot Extension.appex/Contents/Resources/icons/icon-96.png +0 -0
  18. package/bin/Safari Pilot.app/Contents/PlugIns/Safari Pilot Extension.appex/Contents/Resources/manifest.json +39 -0
  19. package/bin/Safari Pilot.app/Contents/PlugIns/Safari Pilot Extension.appex/Contents/_CodeSignature/CodeResources +194 -0
  20. package/bin/Safari Pilot.app/Contents/Resources/AppIcon.icns +0 -0
  21. package/bin/Safari Pilot.app/Contents/Resources/Assets.car +0 -0
  22. package/bin/Safari Pilot.app/Contents/Resources/Base.lproj/Main.html +19 -0
  23. package/bin/Safari Pilot.app/Contents/Resources/Base.lproj/Main.storyboardc/Info.plist +0 -0
  24. package/bin/Safari Pilot.app/Contents/Resources/Base.lproj/Main.storyboardc/MainMenu.nib +0 -0
  25. package/bin/Safari Pilot.app/Contents/Resources/Base.lproj/Main.storyboardc/NSWindowController-B8D-0N-5wS.nib +0 -0
  26. package/bin/Safari Pilot.app/Contents/Resources/Base.lproj/Main.storyboardc/XfG-lQ-9wD-view-m2S-Jp-Qdl.nib +0 -0
  27. package/bin/Safari Pilot.app/Contents/Resources/Icon.png +0 -0
  28. package/bin/Safari Pilot.app/Contents/Resources/Script.js +22 -0
  29. package/bin/Safari Pilot.app/Contents/Resources/Style.css +45 -0
  30. package/bin/Safari Pilot.app/Contents/_CodeSignature/CodeResources +236 -0
  31. package/bin/Safari Pilot.zip +0 -0
  32. package/bin/SafariPilotd +0 -0
  33. package/dist/engine-selector.d.ts +10 -0
  34. package/dist/engine-selector.js +55 -0
  35. package/dist/engine-selector.js.map +1 -0
  36. package/dist/engines/applescript.d.ts +53 -0
  37. package/dist/engines/applescript.js +290 -0
  38. package/dist/engines/applescript.js.map +1 -0
  39. package/dist/engines/daemon.d.ts +19 -0
  40. package/dist/engines/daemon.js +187 -0
  41. package/dist/engines/daemon.js.map +1 -0
  42. package/dist/engines/engine.d.ts +15 -0
  43. package/dist/engines/engine.js +42 -0
  44. package/dist/engines/engine.js.map +1 -0
  45. package/dist/engines/extension.d.ts +34 -0
  46. package/dist/engines/extension.js +66 -0
  47. package/dist/engines/extension.js.map +1 -0
  48. package/dist/errors.d.ts +128 -0
  49. package/dist/errors.js +250 -0
  50. package/dist/errors.js.map +1 -0
  51. package/dist/index.d.ts +2 -0
  52. package/dist/index.js +11 -0
  53. package/dist/index.js.map +1 -0
  54. package/dist/security/audit-log.d.ts +23 -0
  55. package/dist/security/audit-log.js +68 -0
  56. package/dist/security/audit-log.js.map +1 -0
  57. package/dist/security/circuit-breaker.d.ts +29 -0
  58. package/dist/security/circuit-breaker.js +114 -0
  59. package/dist/security/circuit-breaker.js.map +1 -0
  60. package/dist/security/domain-policy.d.ts +29 -0
  61. package/dist/security/domain-policy.js +96 -0
  62. package/dist/security/domain-policy.js.map +1 -0
  63. package/dist/security/human-approval.d.ts +20 -0
  64. package/dist/security/human-approval.js +150 -0
  65. package/dist/security/human-approval.js.map +1 -0
  66. package/dist/security/idpi-scanner.d.ts +20 -0
  67. package/dist/security/idpi-scanner.js +102 -0
  68. package/dist/security/idpi-scanner.js.map +1 -0
  69. package/dist/security/kill-switch.d.ts +51 -0
  70. package/dist/security/kill-switch.js +103 -0
  71. package/dist/security/kill-switch.js.map +1 -0
  72. package/dist/security/rate-limiter.d.ts +30 -0
  73. package/dist/security/rate-limiter.js +70 -0
  74. package/dist/security/rate-limiter.js.map +1 -0
  75. package/dist/security/screenshot-redaction.d.ts +42 -0
  76. package/dist/security/screenshot-redaction.js +134 -0
  77. package/dist/security/screenshot-redaction.js.map +1 -0
  78. package/dist/security/tab-ownership.d.ts +46 -0
  79. package/dist/security/tab-ownership.js +85 -0
  80. package/dist/security/tab-ownership.js.map +1 -0
  81. package/dist/server.d.ts +53 -0
  82. package/dist/server.js +347 -0
  83. package/dist/server.js.map +1 -0
  84. package/dist/tools/clipboard.d.ts +15 -0
  85. package/dist/tools/clipboard.js +128 -0
  86. package/dist/tools/clipboard.js.map +1 -0
  87. package/dist/tools/compound.d.ts +68 -0
  88. package/dist/tools/compound.js +491 -0
  89. package/dist/tools/compound.js.map +1 -0
  90. package/dist/tools/extraction.d.ts +26 -0
  91. package/dist/tools/extraction.js +414 -0
  92. package/dist/tools/extraction.js.map +1 -0
  93. package/dist/tools/frames.d.ts +22 -0
  94. package/dist/tools/frames.js +165 -0
  95. package/dist/tools/frames.js.map +1 -0
  96. package/dist/tools/interaction.d.ts +30 -0
  97. package/dist/tools/interaction.js +651 -0
  98. package/dist/tools/interaction.js.map +1 -0
  99. package/dist/tools/navigation.d.ts +41 -0
  100. package/dist/tools/navigation.js +316 -0
  101. package/dist/tools/navigation.js.map +1 -0
  102. package/dist/tools/network.d.ts +27 -0
  103. package/dist/tools/network.js +721 -0
  104. package/dist/tools/network.js.map +1 -0
  105. package/dist/tools/performance.d.ts +16 -0
  106. package/dist/tools/performance.js +240 -0
  107. package/dist/tools/performance.js.map +1 -0
  108. package/dist/tools/permissions.d.ts +25 -0
  109. package/dist/tools/permissions.js +308 -0
  110. package/dist/tools/permissions.js.map +1 -0
  111. package/dist/tools/service-workers.d.ts +15 -0
  112. package/dist/tools/service-workers.js +136 -0
  113. package/dist/tools/service-workers.js.map +1 -0
  114. package/dist/tools/shadow.d.ts +21 -0
  115. package/dist/tools/shadow.js +126 -0
  116. package/dist/tools/shadow.js.map +1 -0
  117. package/dist/tools/storage.d.ts +30 -0
  118. package/dist/tools/storage.js +679 -0
  119. package/dist/tools/storage.js.map +1 -0
  120. package/dist/tools/structured-extraction.d.ts +22 -0
  121. package/dist/tools/structured-extraction.js +433 -0
  122. package/dist/tools/structured-extraction.js.map +1 -0
  123. package/dist/tools/wait.d.ts +18 -0
  124. package/dist/tools/wait.js +182 -0
  125. package/dist/tools/wait.js.map +1 -0
  126. package/dist/types.d.ts +85 -0
  127. package/dist/types.js +2 -0
  128. package/dist/types.js.map +1 -0
  129. package/extension/background.js +294 -0
  130. package/extension/content-isolated.js +80 -0
  131. package/extension/content-main.js +310 -0
  132. package/extension/icons/icon-128.png +0 -0
  133. package/extension/icons/icon-48.png +0 -0
  134. package/extension/icons/icon-96.png +0 -0
  135. package/extension/manifest.json +39 -0
  136. package/hooks/session-end.sh +67 -0
  137. package/hooks/session-start.sh +66 -0
  138. package/package.json +46 -0
  139. package/scripts/build-extension.sh +135 -0
  140. package/scripts/postinstall.sh +91 -0
  141. package/scripts/preuninstall.sh +25 -0
  142. package/scripts/update-daemon.sh +62 -0
  143. package/skills/safari-pilot/SKILL.md +157 -0
@@ -0,0 +1,35 @@
1
+ {
2
+ "name": "safari-pilot",
3
+ "version": "0.1.0",
4
+ "description": "Native Safari browser automation for AI agents on macOS",
5
+ "author": "Aakash Kumar",
6
+ "license": "MIT",
7
+ "homepage": "https://github.com/aakashkumar/safari-pilot",
8
+ "components": {
9
+ "mcpServers": {
10
+ "safari": {
11
+ "command": "node",
12
+ "args": ["${CLAUDE_PLUGIN_ROOT}/dist/index.js"],
13
+ "env": {
14
+ "SAFARI_PILOT_DATA": "${CLAUDE_PLUGIN_DATA}",
15
+ "SAFARI_PILOT_DAEMON": "${CLAUDE_PLUGIN_ROOT}/bin/SafariPilotd"
16
+ }
17
+ }
18
+ },
19
+ "skills": ["skills/safari-pilot/SKILL.md"],
20
+ "hooks": [
21
+ {
22
+ "event": "SessionStart",
23
+ "script": "${CLAUDE_PLUGIN_ROOT}/hooks/session-start.sh"
24
+ },
25
+ {
26
+ "event": "Stop",
27
+ "script": "${CLAUDE_PLUGIN_ROOT}/hooks/session-end.sh"
28
+ }
29
+ ]
30
+ },
31
+ "requirements": {
32
+ "os": ["darwin"],
33
+ "minOsVersion": "12.0"
34
+ }
35
+ }
package/.mcp.json ADDED
@@ -0,0 +1,11 @@
1
+ {
2
+ "mcpServers": {
3
+ "safari": {
4
+ "command": "node",
5
+ "args": ["dist/index.js"],
6
+ "env": {
7
+ "NODE_ENV": "production"
8
+ }
9
+ }
10
+ }
11
+ }
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Aakash Kumar
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,324 @@
1
+ # Safari Pilot
2
+
3
+ **Native Safari browser automation for AI agents on macOS.**
4
+
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
+
7
+ > **74 tools** | **3 engine tiers** | **92x faster than raw AppleScript** | **9 security layers** | **macOS 12+**
8
+
9
+ ---
10
+
11
+ ## Why Safari Pilot?
12
+
13
+ | Problem with Chrome-based tools | Safari Pilot solution |
14
+ |---|---|
15
+ | Chrome heats your Mac to 97C during automation | Native WebKit — ~60% less CPU |
16
+ | Playwright/Puppeteer launch clean browsers without your logins | Uses your **real Safari** — Gmail, GitHub, Slack already signed in |
17
+ | Chrome steals window focus mid-work | Safari stays in background, never interrupts |
18
+ | Third-party MCP packages have MAIN world access to your banking tabs | Every line of code is first-party, auditable, open source |
19
+ | 80ms per command via osascript | Persistent Swift daemon: **p50 = 1ms** |
20
+
21
+ ## Installation
22
+
23
+ ### As a Claude Code Plugin (Recommended)
24
+
25
+ ```bash
26
+ claude plugin add safari-pilot
27
+ ```
28
+
29
+ ### Manual Installation
30
+
31
+ ```bash
32
+ git clone https://github.com/aakashkumar/safari-pilot.git
33
+ cd safari-pilot
34
+ npm install
35
+ npm run build
36
+ ```
37
+
38
+ ## Prerequisites
39
+
40
+ - **macOS 12.0 (Monterey)** or later
41
+ - **Safari** (pre-installed on every Mac)
42
+ - **Node.js 20+**
43
+
44
+ ### Required Safari Setting
45
+
46
+ Enable "Allow JavaScript from Apple Events":
47
+
48
+ 1. Open **Safari > Settings > Advanced**
49
+ 2. Check **"Show features for web developers"**
50
+ 3. Go to **Safari > Develop** menu
51
+ 4. Check **"Allow JavaScript from Apple Events"**
52
+
53
+ This is a one-time setting that persists across Safari restarts.
54
+
55
+ ### Optional: Safari Web Extension
56
+
57
+ For advanced features (closed Shadow DOM traversal, CSP bypass, dialog interception, network mocking), install the bundled Safari extension:
58
+
59
+ ```bash
60
+ # Build the extension (requires Xcode)
61
+ bash scripts/build-extension.sh
62
+
63
+ # Open the app to trigger Safari's extension enable prompt
64
+ open "bin/Safari Pilot.app"
65
+ ```
66
+
67
+ Then enable it in **Safari > Settings > Extensions > Safari Pilot**.
68
+
69
+ ## Quick Start
70
+
71
+ Once installed, Safari Pilot activates when Claude Code detects browser tasks:
72
+
73
+ ```
74
+ Browse to github.com/trending and extract the top 10 repositories
75
+ ```
76
+
77
+ ```
78
+ Go to my company dashboard at app.example.com and download the monthly report
79
+ ```
80
+
81
+ ```
82
+ Test the checkout flow on staging.mystore.com — add to cart, fill payment, verify confirmation
83
+ ```
84
+
85
+ ```
86
+ Monitor news.ycombinator.com for any post about our company
87
+ ```
88
+
89
+ ## Tool Catalog (74 Tools)
90
+
91
+ ### Navigation (7)
92
+ `safari_navigate` | `safari_navigate_back` | `safari_navigate_forward` | `safari_reload` | `safari_new_tab` | `safari_close_tab` | `safari_list_tabs`
93
+
94
+ ### Interaction (11)
95
+ `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`
96
+
97
+ ### Extraction (7)
98
+ `safari_snapshot` | `safari_get_text` | `safari_get_html` | `safari_get_attribute` | `safari_evaluate` | `safari_take_screenshot` | `safari_get_console_messages`
99
+
100
+ ### Network (8)
101
+ `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`
102
+
103
+ ### Storage (11)
104
+ `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`
105
+
106
+ ### Shadow DOM (2)
107
+ `safari_query_shadow` | `safari_click_shadow`
108
+
109
+ ### Frames (3)
110
+ `safari_list_frames` | `safari_switch_frame` | `safari_eval_in_frame`
111
+
112
+ ### Permissions & Overrides (6)
113
+ `safari_permission_get` | `safari_permission_set` | `safari_override_geolocation` | `safari_override_timezone` | `safari_override_locale` | `safari_override_useragent`
114
+
115
+ ### Clipboard (2)
116
+ `safari_clipboard_read` | `safari_clipboard_write`
117
+
118
+ ### Service Workers (2)
119
+ `safari_sw_list` | `safari_sw_unregister`
120
+
121
+ ### Performance (3)
122
+ `safari_begin_trace` | `safari_end_trace` | `safari_get_page_metrics`
123
+
124
+ ### Structured Extraction (5)
125
+ `safari_smart_scrape` | `safari_extract_tables` | `safari_extract_links` | `safari_extract_images` | `safari_extract_metadata`
126
+
127
+ ### Compound Workflows (4)
128
+ `safari_test_flow` | `safari_monitor_page` | `safari_paginate_scrape` | `safari_media_control`
129
+
130
+ ### Wait (1)
131
+ `safari_wait_for` — 7 condition types: selector, selectorHidden, text, textGone, urlMatch, networkidle, function
132
+
133
+ ### System (2)
134
+ `safari_health_check` | `safari_emergency_stop`
135
+
136
+ ## Architecture
137
+
138
+ ```
139
+ Claude Code
140
+ |
141
+ | MCP Protocol (stdio)
142
+ v
143
+ +--------------------------------------------------+
144
+ | Safari Pilot MCP Server (TypeScript) |
145
+ | |
146
+ | Security Pipeline: |
147
+ | Kill Switch -> Tab Ownership -> Domain Policy |
148
+ | -> Rate Limiter -> Circuit Breaker -> Audit Log |
149
+ | |
150
+ | Engine Selector: |
151
+ | +-----------+ +-----------+ +----------------+ |
152
+ | | Extension | | Daemon | | AppleScript | |
153
+ | | (deep DOM)| | (1ms p50) | | (fallback) | |
154
+ | +-----------+ +-----------+ +----------------+ |
155
+ +--------------------------------------------------+
156
+ | | |
157
+ v v v
158
+ +--------------------------------------------------+
159
+ | Safari (macOS native) |
160
+ | Your real browser with all your sessions |
161
+ +--------------------------------------------------+
162
+ ```
163
+
164
+ ### Three Engine Tiers
165
+
166
+ | Engine | Latency | Capabilities | When Used |
167
+ |---|---|---|---|
168
+ | **Safari Web Extension** | ~10ms | Shadow DOM, CSP bypass, dialog interception, network mocking | Extension installed + feature requires it |
169
+ | **Swift Daemon** | **1ms p50** | All AppleScript capabilities, persistent process | Default when daemon is running |
170
+ | **AppleScript (osascript)** | ~90ms | Basic navigation, forms, extraction, screenshots | Fallback when daemon unavailable |
171
+
172
+ The engine selector automatically picks the best available engine for each command. If the daemon isn't running, it falls back to raw AppleScript. If a command needs Shadow DOM access and the extension isn't installed, it returns a clear error with instructions.
173
+
174
+ ## Performance
175
+
176
+ Benchmarked on Apple Silicon (M-series), 20 consecutive commands:
177
+
178
+ | Metric | Daemon | AppleScript | Speedup |
179
+ |---|---|---|---|
180
+ | p50 | 0-1ms | 81-92ms | **92x** |
181
+ | p95 | 62ms | 116ms | ~2x |
182
+ | avg | 5ms | 85ms | **17x** |
183
+
184
+ Over a 500-command session, the daemon saves ~40 seconds of pure overhead vs raw AppleScript.
185
+
186
+ ## Security Model
187
+
188
+ Safari Pilot runs on your local machine with access to your real browser sessions. The security model is defense-in-depth:
189
+
190
+ ### Tab Ownership
191
+ The agent can **only** interact with tabs it created via `safari_new_tab`. Your existing tabs (banking, email, personal) are untouchable. Ownership is enforced at the server level — there is no bypass.
192
+
193
+ ### Domain Policy
194
+ Per-domain rate limits prevent runaway automation. Banking and financial domains are flagged as untrusted by default.
195
+
196
+ ### Rate Limiter + Circuit Breaker
197
+ Global limit of 120 actions/minute. Per-domain limits configurable. Circuit breaker trips after 5 consecutive errors, backs off for 120 seconds.
198
+
199
+ ### IDPI Scanner
200
+ Indirect Prompt Injection defense. Scans extracted text for 9 known injection patterns (role reassignment, fake system prompts, base64 payloads, hidden text, etc.).
201
+
202
+ ### Kill Switch
203
+ `safari_emergency_stop` immediately halts all automation and blocks further calls. One command, full stop.
204
+
205
+ ### Human Approval
206
+ Sensitive actions (OAuth consent, financial forms, downloads) are flagged and require explicit approval.
207
+
208
+ ### Audit Logging
209
+ Every tool call is logged with timestamp, tool name, URL, parameters (passwords redacted), result, and latency. Session-end hook produces a summary.
210
+
211
+ ### Screenshot Redaction
212
+ Cross-origin iframes are blurred in screenshots. Password fields are redacted.
213
+
214
+ ### No Credential Access
215
+ Safari Pilot **never** accesses the macOS Keychain. Authentication works through real browser interaction, same as you clicking.
216
+
217
+ ## Development
218
+
219
+ ### Project Structure
220
+
221
+ ```
222
+ safari-pilot/
223
+ ├── src/ # TypeScript MCP server
224
+ │ ├── server.ts # Main server + tool registration
225
+ │ ├── engines/ # AppleScript, Daemon, Extension engines
226
+ │ ├── security/ # 9 security modules
227
+ │ └── tools/ # 14 tool category modules
228
+ ├── daemon/ # Swift persistent daemon
229
+ │ ├── Sources/ # Swift source code
230
+ │ └── Tests/ # Swift tests (custom runner)
231
+ ├── extension/ # Safari Web Extension
232
+ │ ├── manifest.json # Manifest V3
233
+ │ ├── content-main.js # MAIN world (Shadow DOM, React filling)
234
+ │ ├── content-isolated.js # ISOLATED world relay
235
+ │ └── background.js # Service worker + native messaging
236
+ ├── skills/ # Claude Code skill definition
237
+ ├── hooks/ # Session start/end hooks
238
+ ├── scripts/ # Install, update, build scripts
239
+ └── test/ # 1,167 tests
240
+ ├── unit/ # 705 unit tests
241
+ ├── integration/ # 372 integration tests
242
+ ├── security/ # 27 security tests
243
+ ├── e2e/ # 31 E2E tests (real Safari)
244
+ ├── canary/ # Deployment canary test
245
+ └── fixtures/ # HTML test pages
246
+ ```
247
+
248
+ ### Building
249
+
250
+ ```bash
251
+ # TypeScript server
252
+ npm run build
253
+
254
+ # Swift daemon
255
+ cd daemon && swift build -c release
256
+ cp .build/release/SafariPilotd ../bin/
257
+
258
+ # Safari extension (requires Xcode)
259
+ bash scripts/build-extension.sh
260
+ ```
261
+
262
+ ### Testing
263
+
264
+ ```bash
265
+ # All tests
266
+ npm test
267
+
268
+ # By category
269
+ npm run test:unit # 705 tests, no Safari needed
270
+ npm run test:integration # 372 tests, some need Safari
271
+ npm run test:security # 27 security-focused tests
272
+ npm run test:e2e # 31 tests against real Safari
273
+
274
+ # Swift daemon tests
275
+ cd daemon && swift run SafariPilotdTests
276
+
277
+ # Canary deployment
278
+ bash test/canary/install-test.sh
279
+ ```
280
+
281
+ ### Adding a New Tool
282
+
283
+ 1. Add the handler to the appropriate module in `src/tools/`
284
+ 2. Follow the pattern: `getDefinitions()` returns schema, `getHandler()` returns handler
285
+ 3. Write tests in `test/unit/tools/`
286
+ 4. The server auto-registers tools from all modules in `initialize()`
287
+ 5. Add the tool name to `skills/safari-pilot/SKILL.md` allowed-tools
288
+
289
+ ## What Safari Pilot Does NOT Replace
290
+
291
+ | Use Case | Keep Using |
292
+ |---|---|
293
+ | Lighthouse / Core Web Vitals auditing | Chrome DevTools MCP |
294
+ | Cross-platform automation (Linux/Windows) | Playwright MCP |
295
+ | Headless CI browser testing | Playwright |
296
+ | Pure text extraction (no interaction needed) | Jina Reader / Firecrawl |
297
+ | Visual regression testing | Playwright snapshots |
298
+
299
+ Safari Pilot is for **interactive browsing on Mac** — especially authenticated sessions.
300
+
301
+ ## FAQ
302
+
303
+ **Q: Does this work on Linux/Windows?**
304
+ No. Safari is macOS only. The plugin gracefully disables itself on non-macOS systems.
305
+
306
+ **Q: Can the agent see my banking tabs?**
307
+ No. Tab ownership enforcement means the agent can only interact with tabs it opened via `safari_new_tab`. Your existing tabs are invisible to tool calls.
308
+
309
+ **Q: What if Safari crashes during automation?**
310
+ The daemon detects Safari crashes (error codes -600/-609) and retries with exponential backoff. If Safari restarts, automation resumes.
311
+
312
+ **Q: How is this different from safari-mcp?**
313
+ 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.
314
+
315
+ **Q: Does the Swift daemon run all the time?**
316
+ Only when Claude Code is active. The LaunchAgent starts the daemon on demand and it shuts down with the session.
317
+
318
+ ## License
319
+
320
+ MIT — see [LICENSE](LICENSE).
321
+
322
+ ## Author
323
+
324
+ Built by [Aakash Kumar](https://github.com/aakashkumar) with Claude.
package/bin/.gitkeep ADDED
File without changes
@@ -0,0 +1,58 @@
1
+ <?xml version="1.0" encoding="UTF-8"?>
2
+ <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
3
+ <plist version="1.0">
4
+ <dict>
5
+ <key>BuildMachineOSBuild</key>
6
+ <string>25E5233c</string>
7
+ <key>CFBundleDevelopmentRegion</key>
8
+ <string>en</string>
9
+ <key>CFBundleDisplayName</key>
10
+ <string>Safari Pilot</string>
11
+ <key>CFBundleExecutable</key>
12
+ <string>Safari Pilot</string>
13
+ <key>CFBundleIconFile</key>
14
+ <string>AppIcon</string>
15
+ <key>CFBundleIconName</key>
16
+ <string>AppIcon</string>
17
+ <key>CFBundleIdentifier</key>
18
+ <string>com.safari-pilot.app</string>
19
+ <key>CFBundleInfoDictionaryVersion</key>
20
+ <string>6.0</string>
21
+ <key>CFBundleName</key>
22
+ <string>Safari Pilot</string>
23
+ <key>CFBundlePackageType</key>
24
+ <string>APPL</string>
25
+ <key>CFBundleShortVersionString</key>
26
+ <string>1.0</string>
27
+ <key>CFBundleSupportedPlatforms</key>
28
+ <array>
29
+ <string>MacOSX</string>
30
+ </array>
31
+ <key>CFBundleVersion</key>
32
+ <string>1</string>
33
+ <key>DTCompiler</key>
34
+ <string>com.apple.compilers.llvm.clang.1_0</string>
35
+ <key>DTPlatformBuild</key>
36
+ <string>25E236</string>
37
+ <key>DTPlatformName</key>
38
+ <string>macosx</string>
39
+ <key>DTPlatformVersion</key>
40
+ <string>26.4</string>
41
+ <key>DTSDKBuild</key>
42
+ <string>25E236</string>
43
+ <key>DTSDKName</key>
44
+ <string>macosx26.4</string>
45
+ <key>DTXcode</key>
46
+ <string>2640</string>
47
+ <key>DTXcodeBuild</key>
48
+ <string>17E192</string>
49
+ <key>LSMinimumSystemVersion</key>
50
+ <string>26.4</string>
51
+ <key>NSMainStoryboardFile</key>
52
+ <string>Main</string>
53
+ <key>NSPrincipalClass</key>
54
+ <string>NSApplication</string>
55
+ <key>SFSafariWebExtensionConverterVersion</key>
56
+ <string>26.4</string>
57
+ </dict>
58
+ </plist>
@@ -0,0 +1 @@
1
+ APPL????
@@ -0,0 +1,55 @@
1
+ <?xml version="1.0" encoding="UTF-8"?>
2
+ <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
3
+ <plist version="1.0">
4
+ <dict>
5
+ <key>BuildMachineOSBuild</key>
6
+ <string>25E5233c</string>
7
+ <key>CFBundleDevelopmentRegion</key>
8
+ <string>en</string>
9
+ <key>CFBundleDisplayName</key>
10
+ <string>Safari Pilot Extension</string>
11
+ <key>CFBundleExecutable</key>
12
+ <string>Safari Pilot Extension</string>
13
+ <key>CFBundleIdentifier</key>
14
+ <string>com.safari-pilot.app.Extension</string>
15
+ <key>CFBundleInfoDictionaryVersion</key>
16
+ <string>6.0</string>
17
+ <key>CFBundleName</key>
18
+ <string>Safari Pilot Extension</string>
19
+ <key>CFBundlePackageType</key>
20
+ <string>XPC!</string>
21
+ <key>CFBundleShortVersionString</key>
22
+ <string>1.0</string>
23
+ <key>CFBundleSupportedPlatforms</key>
24
+ <array>
25
+ <string>MacOSX</string>
26
+ </array>
27
+ <key>CFBundleVersion</key>
28
+ <string>1</string>
29
+ <key>DTCompiler</key>
30
+ <string>com.apple.compilers.llvm.clang.1_0</string>
31
+ <key>DTPlatformBuild</key>
32
+ <string>25E236</string>
33
+ <key>DTPlatformName</key>
34
+ <string>macosx</string>
35
+ <key>DTPlatformVersion</key>
36
+ <string>26.4</string>
37
+ <key>DTSDKBuild</key>
38
+ <string>25E236</string>
39
+ <key>DTSDKName</key>
40
+ <string>macosx26.4</string>
41
+ <key>DTXcode</key>
42
+ <string>2640</string>
43
+ <key>DTXcodeBuild</key>
44
+ <string>17E192</string>
45
+ <key>LSMinimumSystemVersion</key>
46
+ <string>10.14</string>
47
+ <key>NSExtension</key>
48
+ <dict>
49
+ <key>NSExtensionPointIdentifier</key>
50
+ <string>com.apple.Safari.web-extension</string>
51
+ <key>NSExtensionPrincipalClass</key>
52
+ <string>Safari_Pilot_Extension.SafariWebExtensionHandler</string>
53
+ </dict>
54
+ </dict>
55
+ </plist>