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
package/dist/server.js
ADDED
|
@@ -0,0 +1,347 @@
|
|
|
1
|
+
import { execFile } from 'node:child_process';
|
|
2
|
+
import { promisify } from 'node:util';
|
|
3
|
+
import { selectEngine } from './engine-selector.js';
|
|
4
|
+
import { AppleScriptEngine } from './engines/applescript.js';
|
|
5
|
+
import { DaemonEngine } from './engines/daemon.js';
|
|
6
|
+
import { NavigationTools } from './tools/navigation.js';
|
|
7
|
+
import { InteractionTools } from './tools/interaction.js';
|
|
8
|
+
import { ExtractionTools } from './tools/extraction.js';
|
|
9
|
+
import { NetworkTools } from './tools/network.js';
|
|
10
|
+
import { StorageTools } from './tools/storage.js';
|
|
11
|
+
import { ShadowTools } from './tools/shadow.js';
|
|
12
|
+
import { FrameTools } from './tools/frames.js';
|
|
13
|
+
import { PermissionTools } from './tools/permissions.js';
|
|
14
|
+
import { ClipboardTools } from './tools/clipboard.js';
|
|
15
|
+
import { ServiceWorkerTools } from './tools/service-workers.js';
|
|
16
|
+
import { PerformanceTools } from './tools/performance.js';
|
|
17
|
+
import { StructuredExtractionTools } from './tools/structured-extraction.js';
|
|
18
|
+
import { WaitTools } from './tools/wait.js';
|
|
19
|
+
import { CompoundTools } from './tools/compound.js';
|
|
20
|
+
import { KillSwitch } from './security/kill-switch.js';
|
|
21
|
+
import { TabOwnership } from './security/tab-ownership.js';
|
|
22
|
+
import { AuditLog } from './security/audit-log.js';
|
|
23
|
+
import { DomainPolicy } from './security/domain-policy.js';
|
|
24
|
+
import { RateLimiter } from './security/rate-limiter.js';
|
|
25
|
+
import { CircuitBreaker } from './security/circuit-breaker.js';
|
|
26
|
+
import { IdpiScanner } from './security/idpi-scanner.js';
|
|
27
|
+
import { RateLimitedError, CircuitBreakerOpenError } from './errors.js';
|
|
28
|
+
const execFileAsync = promisify(execFile);
|
|
29
|
+
// Per-check timeout: short enough to keep the total health check fast,
|
|
30
|
+
// long enough to survive a sluggish osascript startup (~100-300 ms typical).
|
|
31
|
+
const HEALTH_CHECK_TIMEOUT_MS = 3000;
|
|
32
|
+
async function checkSafariRunning() {
|
|
33
|
+
try {
|
|
34
|
+
await execFileAsync('osascript', ['-e', 'tell application "Safari" to return name'], {
|
|
35
|
+
timeout: HEALTH_CHECK_TIMEOUT_MS,
|
|
36
|
+
});
|
|
37
|
+
return { name: 'safari_running', ok: true };
|
|
38
|
+
}
|
|
39
|
+
catch (err) {
|
|
40
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
41
|
+
return { name: 'safari_running', ok: false, detail: message };
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
async function checkJsFromAppleEvents() {
|
|
45
|
+
try {
|
|
46
|
+
const result = await execFileAsync('osascript', ['-e', 'tell application "Safari" to do JavaScript "1+1" in current tab of front window'], { timeout: HEALTH_CHECK_TIMEOUT_MS });
|
|
47
|
+
const value = result.stdout.trim();
|
|
48
|
+
return { name: 'js_apple_events', ok: value === '2', detail: value !== '2' ? `Unexpected: ${value}` : undefined };
|
|
49
|
+
}
|
|
50
|
+
catch (err) {
|
|
51
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
52
|
+
return {
|
|
53
|
+
name: 'js_apple_events',
|
|
54
|
+
ok: false,
|
|
55
|
+
detail: message.includes('-1743') || message.includes('permission') || message.includes('Apple Events')
|
|
56
|
+
? 'JS from Apple Events is disabled. Enable in Safari > Develop > Allow JavaScript from Apple Events'
|
|
57
|
+
: message,
|
|
58
|
+
};
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
async function checkScreenRecording() {
|
|
62
|
+
try {
|
|
63
|
+
// screencapture -x captures without sound; a permission error means SR is blocked
|
|
64
|
+
await execFileAsync('screencapture', ['-x', '-t', 'png', '/dev/null'], { timeout: HEALTH_CHECK_TIMEOUT_MS });
|
|
65
|
+
return { name: 'screen_recording', ok: true };
|
|
66
|
+
}
|
|
67
|
+
catch (err) {
|
|
68
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
69
|
+
return {
|
|
70
|
+
name: 'screen_recording',
|
|
71
|
+
ok: false,
|
|
72
|
+
detail: 'Screen Recording permission not granted. Enable in System Settings > Privacy & Security > Screen Recording',
|
|
73
|
+
};
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
// ── Tool names that skip ownership enforcement ──────────────────────────────
|
|
77
|
+
const SKIP_OWNERSHIP_TOOLS = new Set([
|
|
78
|
+
'safari_list_tabs',
|
|
79
|
+
'safari_new_tab',
|
|
80
|
+
'safari_health_check',
|
|
81
|
+
]);
|
|
82
|
+
export class SafariPilotServer {
|
|
83
|
+
tools = new Map();
|
|
84
|
+
engines = new Map();
|
|
85
|
+
engineAvailability = { daemon: false, extension: false };
|
|
86
|
+
sessionId = `sess_${Date.now().toString(36)}`;
|
|
87
|
+
_engine = null;
|
|
88
|
+
// ── Security layers ─────────────────────────────────────────────────────────
|
|
89
|
+
killSwitch;
|
|
90
|
+
tabOwnership;
|
|
91
|
+
auditLog;
|
|
92
|
+
domainPolicy;
|
|
93
|
+
rateLimiter;
|
|
94
|
+
circuitBreaker;
|
|
95
|
+
idpiScanner;
|
|
96
|
+
constructor() {
|
|
97
|
+
this.auditLog = new AuditLog();
|
|
98
|
+
this.killSwitch = new KillSwitch({ auditLog: this.auditLog });
|
|
99
|
+
this.tabOwnership = new TabOwnership();
|
|
100
|
+
this.domainPolicy = new DomainPolicy();
|
|
101
|
+
this.rateLimiter = new RateLimiter();
|
|
102
|
+
this.circuitBreaker = new CircuitBreaker();
|
|
103
|
+
this.idpiScanner = new IdpiScanner();
|
|
104
|
+
}
|
|
105
|
+
async initialize() {
|
|
106
|
+
// Instantiate and probe the DaemonEngine first (fastest path)
|
|
107
|
+
const daemonEngine = new DaemonEngine();
|
|
108
|
+
const daemonAvailable = await daemonEngine.isAvailable();
|
|
109
|
+
this.setEngineAvailability({ daemon: daemonAvailable, extension: false });
|
|
110
|
+
if (daemonAvailable) {
|
|
111
|
+
this.engines.set('daemon', daemonEngine);
|
|
112
|
+
}
|
|
113
|
+
else {
|
|
114
|
+
// Ensure daemon is cleaned up if it failed to start
|
|
115
|
+
await daemonEngine.shutdown();
|
|
116
|
+
}
|
|
117
|
+
// Instantiate the AppleScript engine (always available as fallback)
|
|
118
|
+
const engine = new AppleScriptEngine();
|
|
119
|
+
this._engine = engine;
|
|
120
|
+
// Register health check tool (real implementation)
|
|
121
|
+
this.registerTool({
|
|
122
|
+
name: 'safari_health_check',
|
|
123
|
+
description: 'Verify all required macOS permissions and system prerequisites are met.',
|
|
124
|
+
inputSchema: {
|
|
125
|
+
type: 'object',
|
|
126
|
+
properties: {
|
|
127
|
+
verbose: {
|
|
128
|
+
type: 'boolean',
|
|
129
|
+
description: 'Include detailed system info',
|
|
130
|
+
default: false,
|
|
131
|
+
},
|
|
132
|
+
},
|
|
133
|
+
},
|
|
134
|
+
requirements: {},
|
|
135
|
+
handler: async (params) => this.handleHealthCheck(params),
|
|
136
|
+
});
|
|
137
|
+
// Instantiate all tool modules
|
|
138
|
+
const navTools = new NavigationTools(engine);
|
|
139
|
+
const interactionTools = new InteractionTools(engine);
|
|
140
|
+
const extractionTools = new ExtractionTools(engine);
|
|
141
|
+
const networkTools = new NetworkTools(engine);
|
|
142
|
+
const storageTools = new StorageTools(engine);
|
|
143
|
+
const shadowTools = new ShadowTools(engine);
|
|
144
|
+
const frameTools = new FrameTools(engine);
|
|
145
|
+
const permissionTools = new PermissionTools(engine);
|
|
146
|
+
const clipboardTools = new ClipboardTools(engine);
|
|
147
|
+
const serviceWorkerTools = new ServiceWorkerTools(engine);
|
|
148
|
+
const performanceTools = new PerformanceTools(engine);
|
|
149
|
+
const structuredExtractionTools = new StructuredExtractionTools(engine);
|
|
150
|
+
const waitTools = new WaitTools(engine);
|
|
151
|
+
const compoundTools = new CompoundTools(engine);
|
|
152
|
+
const modules = [
|
|
153
|
+
navTools,
|
|
154
|
+
interactionTools,
|
|
155
|
+
extractionTools,
|
|
156
|
+
networkTools,
|
|
157
|
+
storageTools,
|
|
158
|
+
shadowTools,
|
|
159
|
+
frameTools,
|
|
160
|
+
permissionTools,
|
|
161
|
+
clipboardTools,
|
|
162
|
+
serviceWorkerTools,
|
|
163
|
+
performanceTools,
|
|
164
|
+
structuredExtractionTools,
|
|
165
|
+
waitTools,
|
|
166
|
+
compoundTools,
|
|
167
|
+
];
|
|
168
|
+
for (const module of modules) {
|
|
169
|
+
for (const def of module.getDefinitions()) {
|
|
170
|
+
const handler = module.getHandler(def.name);
|
|
171
|
+
if (!handler) {
|
|
172
|
+
throw new Error(`No handler found for tool "${def.name}"`);
|
|
173
|
+
}
|
|
174
|
+
this.registerTool({
|
|
175
|
+
...def,
|
|
176
|
+
handler,
|
|
177
|
+
});
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
// Emergency stop — system tool, registered directly (not via a module)
|
|
181
|
+
this.registerTool({
|
|
182
|
+
name: 'safari_emergency_stop',
|
|
183
|
+
description: 'Emergency stop — immediately close all agent-owned tabs, activate kill switch, and block all further automation.',
|
|
184
|
+
inputSchema: {
|
|
185
|
+
type: 'object',
|
|
186
|
+
properties: {
|
|
187
|
+
reason: { type: 'string', description: 'Reason for the emergency stop' },
|
|
188
|
+
},
|
|
189
|
+
},
|
|
190
|
+
requirements: {},
|
|
191
|
+
handler: async (params) => {
|
|
192
|
+
const reason = params['reason'] ?? 'emergency_stop called';
|
|
193
|
+
this.killSwitch.activate(reason);
|
|
194
|
+
return {
|
|
195
|
+
content: [{ type: 'text', text: JSON.stringify({ stopped: true, reason }) }],
|
|
196
|
+
metadata: { engine: 'applescript', degraded: false, latencyMs: 0 },
|
|
197
|
+
};
|
|
198
|
+
},
|
|
199
|
+
});
|
|
200
|
+
}
|
|
201
|
+
async handleHealthCheck(params) {
|
|
202
|
+
const start = Date.now();
|
|
203
|
+
const checks = [];
|
|
204
|
+
// 1. Safari running?
|
|
205
|
+
const safariCheck = await checkSafariRunning();
|
|
206
|
+
checks.push(safariCheck);
|
|
207
|
+
// 2. JS from Apple Events enabled?
|
|
208
|
+
const jsCheck = await checkJsFromAppleEvents();
|
|
209
|
+
checks.push(jsCheck);
|
|
210
|
+
// 3. Screen Recording permission?
|
|
211
|
+
const srCheck = await checkScreenRecording();
|
|
212
|
+
checks.push(srCheck);
|
|
213
|
+
// 4. Daemon available?
|
|
214
|
+
checks.push({ name: 'daemon', ok: this.engineAvailability.daemon });
|
|
215
|
+
// 5. Extension connected?
|
|
216
|
+
checks.push({ name: 'extension', ok: this.engineAvailability.extension });
|
|
217
|
+
const healthy = checks.every((c) => c.name === 'daemon' || c.name === 'extension' || c.ok);
|
|
218
|
+
const failedChecks = checks.filter((c) => !c.ok).map((c) => c.name);
|
|
219
|
+
return {
|
|
220
|
+
content: [
|
|
221
|
+
{
|
|
222
|
+
type: 'text',
|
|
223
|
+
text: JSON.stringify({
|
|
224
|
+
healthy,
|
|
225
|
+
checks,
|
|
226
|
+
failedChecks,
|
|
227
|
+
sessionId: this.sessionId,
|
|
228
|
+
}),
|
|
229
|
+
},
|
|
230
|
+
],
|
|
231
|
+
metadata: {
|
|
232
|
+
engine: 'applescript',
|
|
233
|
+
degraded: !healthy,
|
|
234
|
+
latencyMs: Date.now() - start,
|
|
235
|
+
},
|
|
236
|
+
};
|
|
237
|
+
}
|
|
238
|
+
registerTool(tool) {
|
|
239
|
+
this.tools.set(tool.name, tool);
|
|
240
|
+
}
|
|
241
|
+
getToolNames() {
|
|
242
|
+
return Array.from(this.tools.keys());
|
|
243
|
+
}
|
|
244
|
+
async callTool(name, params) {
|
|
245
|
+
const tool = this.tools.get(name);
|
|
246
|
+
if (!tool)
|
|
247
|
+
throw new Error(`Unknown tool: ${name}`);
|
|
248
|
+
return tool.handler(params);
|
|
249
|
+
}
|
|
250
|
+
/**
|
|
251
|
+
* Execute a tool through the full security pipeline:
|
|
252
|
+
* kill switch → tab ownership → domain policy → rate limiter →
|
|
253
|
+
* circuit breaker → tool execution → audit log
|
|
254
|
+
*/
|
|
255
|
+
async executeToolWithSecurity(name, params) {
|
|
256
|
+
const start = Date.now();
|
|
257
|
+
// 1. Kill switch check — blocks all automation when active
|
|
258
|
+
this.killSwitch.checkBeforeAction();
|
|
259
|
+
// 2. Extract URL / domain from params
|
|
260
|
+
const url = (params['tabUrl'] ?? params['url'] ?? '');
|
|
261
|
+
let domain;
|
|
262
|
+
try {
|
|
263
|
+
domain = new URL(url || 'about:blank').hostname;
|
|
264
|
+
}
|
|
265
|
+
catch {
|
|
266
|
+
domain = '';
|
|
267
|
+
}
|
|
268
|
+
// 3. Tab ownership check — skip for tools that operate without a specific tab
|
|
269
|
+
if (params['tabUrl'] && !SKIP_OWNERSHIP_TOOLS.has(name)) {
|
|
270
|
+
const tabUrl = params['tabUrl'];
|
|
271
|
+
const tabId = this.tabOwnership.findByUrl(tabUrl);
|
|
272
|
+
if (tabId !== undefined) {
|
|
273
|
+
this.tabOwnership.assertOwnership(tabId);
|
|
274
|
+
}
|
|
275
|
+
// If tabId is undefined the tool handler will surface its own error;
|
|
276
|
+
// ownership enforcement only applies to tabs we know about.
|
|
277
|
+
}
|
|
278
|
+
// 4. Domain policy evaluation
|
|
279
|
+
const policy = this.domainPolicy.evaluate(url);
|
|
280
|
+
// 5. Rate limit check — check before recording so we don't consume quota on blocked calls
|
|
281
|
+
const limitCheck = this.rateLimiter.checkLimit(domain);
|
|
282
|
+
if (!limitCheck.allowed) {
|
|
283
|
+
throw new RateLimitedError(domain, policy.maxActionsPerMinute);
|
|
284
|
+
}
|
|
285
|
+
this.rateLimiter.recordAction(domain);
|
|
286
|
+
// 6. Circuit breaker check
|
|
287
|
+
if (this.circuitBreaker.isOpen(domain)) {
|
|
288
|
+
throw new CircuitBreakerOpenError(domain, 120);
|
|
289
|
+
}
|
|
290
|
+
// 7. Execute the tool, record circuit breaker outcome, and audit
|
|
291
|
+
try {
|
|
292
|
+
const result = await this.callTool(name, params);
|
|
293
|
+
this.circuitBreaker.recordSuccess(domain);
|
|
294
|
+
// 8. Audit log — success path
|
|
295
|
+
this.auditLog.record({
|
|
296
|
+
tool: name,
|
|
297
|
+
tabUrl: url,
|
|
298
|
+
engine: 'applescript',
|
|
299
|
+
params,
|
|
300
|
+
result: 'ok',
|
|
301
|
+
elapsed_ms: Date.now() - start,
|
|
302
|
+
session: this.sessionId,
|
|
303
|
+
});
|
|
304
|
+
return result;
|
|
305
|
+
}
|
|
306
|
+
catch (error) {
|
|
307
|
+
this.circuitBreaker.recordFailure(domain);
|
|
308
|
+
// 8. Audit log — error path
|
|
309
|
+
this.auditLog.record({
|
|
310
|
+
tool: name,
|
|
311
|
+
tabUrl: url,
|
|
312
|
+
engine: 'applescript',
|
|
313
|
+
params,
|
|
314
|
+
result: 'error',
|
|
315
|
+
elapsed_ms: Date.now() - start,
|
|
316
|
+
session: this.sessionId,
|
|
317
|
+
});
|
|
318
|
+
throw error;
|
|
319
|
+
}
|
|
320
|
+
}
|
|
321
|
+
getSelectedEngine(requirements) {
|
|
322
|
+
return selectEngine(requirements, this.engineAvailability);
|
|
323
|
+
}
|
|
324
|
+
setEngineAvailability(availability) {
|
|
325
|
+
this.engineAvailability = availability;
|
|
326
|
+
}
|
|
327
|
+
getSessionId() {
|
|
328
|
+
return this.sessionId;
|
|
329
|
+
}
|
|
330
|
+
getEngine() {
|
|
331
|
+
return this._engine;
|
|
332
|
+
}
|
|
333
|
+
async start() {
|
|
334
|
+
await this.initialize();
|
|
335
|
+
console.error('Safari Pilot MCP server started');
|
|
336
|
+
}
|
|
337
|
+
async shutdown() {
|
|
338
|
+
for (const engine of this.engines.values()) {
|
|
339
|
+
await engine.shutdown();
|
|
340
|
+
}
|
|
341
|
+
}
|
|
342
|
+
}
|
|
343
|
+
export async function createServer() {
|
|
344
|
+
const server = new SafariPilotServer();
|
|
345
|
+
return server;
|
|
346
|
+
}
|
|
347
|
+
//# sourceMappingURL=server.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"server.js","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import type { ToolResponse } from '../types.js';
|
|
2
|
+
import type { AppleScriptEngine } from '../engines/applescript.js';
|
|
3
|
+
import type { ToolDefinition } from './navigation.js';
|
|
4
|
+
type Handler = (params: Record<string, unknown>) => Promise<ToolResponse>;
|
|
5
|
+
export declare class ClipboardTools {
|
|
6
|
+
private readonly engine;
|
|
7
|
+
constructor(engine: AppleScriptEngine);
|
|
8
|
+
getDefinitions(): ToolDefinition[];
|
|
9
|
+
getHandler(name: string): Handler;
|
|
10
|
+
private handleClipboardRead;
|
|
11
|
+
private handleClipboardWrite;
|
|
12
|
+
private parseJson;
|
|
13
|
+
private errorResponse;
|
|
14
|
+
}
|
|
15
|
+
export {};
|
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* JS that reads clipboard text.
|
|
3
|
+
* navigator.clipboard.readText() requires a user gesture in Safari; if it
|
|
4
|
+
* rejects, we surface a capability flag so callers can branch accordingly.
|
|
5
|
+
*/
|
|
6
|
+
const CLIPBOARD_READ_JS = `
|
|
7
|
+
(async () => {
|
|
8
|
+
try {
|
|
9
|
+
const text = await navigator.clipboard.readText();
|
|
10
|
+
return JSON.stringify({ text, clipboardAvailable: true });
|
|
11
|
+
} catch (err) {
|
|
12
|
+
return JSON.stringify({ text: null, clipboardAvailable: false, error: String(err) });
|
|
13
|
+
}
|
|
14
|
+
})()
|
|
15
|
+
`.trim();
|
|
16
|
+
/** JS that writes text to the clipboard. */
|
|
17
|
+
function buildClipboardWriteJs(text) {
|
|
18
|
+
const escaped = JSON.stringify(text);
|
|
19
|
+
return `
|
|
20
|
+
(async () => {
|
|
21
|
+
try {
|
|
22
|
+
await navigator.clipboard.writeText(${escaped});
|
|
23
|
+
return JSON.stringify({ written: true, text: ${escaped} });
|
|
24
|
+
} catch (err) {
|
|
25
|
+
return JSON.stringify({ written: false, error: String(err) });
|
|
26
|
+
}
|
|
27
|
+
})()
|
|
28
|
+
`.trim();
|
|
29
|
+
}
|
|
30
|
+
export class ClipboardTools {
|
|
31
|
+
engine;
|
|
32
|
+
constructor(engine) {
|
|
33
|
+
this.engine = engine;
|
|
34
|
+
}
|
|
35
|
+
// ── Public API ──────────────────────────────────────────────────────────────
|
|
36
|
+
getDefinitions() {
|
|
37
|
+
return [
|
|
38
|
+
{
|
|
39
|
+
name: 'safari_clipboard_read',
|
|
40
|
+
description: 'Read the current clipboard text content from the page context. ' +
|
|
41
|
+
'Returns the clipboard text and a clipboardAvailable flag. ' +
|
|
42
|
+
'Note: navigator.clipboard.readText() requires a prior user gesture in Safari — ' +
|
|
43
|
+
'if unavailable, clipboardAvailable will be false.',
|
|
44
|
+
inputSchema: {
|
|
45
|
+
type: 'object',
|
|
46
|
+
properties: {
|
|
47
|
+
tabUrl: { type: 'string', description: 'Current URL of the tab to read clipboard from' },
|
|
48
|
+
},
|
|
49
|
+
required: ['tabUrl'],
|
|
50
|
+
},
|
|
51
|
+
requirements: {},
|
|
52
|
+
},
|
|
53
|
+
{
|
|
54
|
+
name: 'safari_clipboard_write',
|
|
55
|
+
description: 'Write text to the clipboard from the page context via navigator.clipboard.writeText().',
|
|
56
|
+
inputSchema: {
|
|
57
|
+
type: 'object',
|
|
58
|
+
properties: {
|
|
59
|
+
tabUrl: { type: 'string', description: 'Current URL of the tab to execute clipboard write in' },
|
|
60
|
+
text: { type: 'string', description: 'Text to write to the clipboard' },
|
|
61
|
+
},
|
|
62
|
+
required: ['tabUrl', 'text'],
|
|
63
|
+
},
|
|
64
|
+
requirements: {},
|
|
65
|
+
},
|
|
66
|
+
];
|
|
67
|
+
}
|
|
68
|
+
getHandler(name) {
|
|
69
|
+
switch (name) {
|
|
70
|
+
case 'safari_clipboard_read':
|
|
71
|
+
return (p) => this.handleClipboardRead(p);
|
|
72
|
+
case 'safari_clipboard_write':
|
|
73
|
+
return (p) => this.handleClipboardWrite(p);
|
|
74
|
+
default:
|
|
75
|
+
throw new Error(`ClipboardTools: unknown tool "${name}"`);
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
// ── Handlers ────────────────────────────────────────────────────────────────
|
|
79
|
+
async handleClipboardRead(params) {
|
|
80
|
+
const start = Date.now();
|
|
81
|
+
const tabUrl = params['tabUrl'];
|
|
82
|
+
const script = this.engine.buildTabScript(tabUrl, CLIPBOARD_READ_JS);
|
|
83
|
+
const result = await this.engine.execute(script);
|
|
84
|
+
if (!result.ok) {
|
|
85
|
+
return this.errorResponse(result.error?.message ?? 'Clipboard read failed', start);
|
|
86
|
+
}
|
|
87
|
+
const data = this.parseJson(result.value) ?? { text: null, clipboardAvailable: false };
|
|
88
|
+
return {
|
|
89
|
+
content: [{ type: 'text', text: JSON.stringify(data) }],
|
|
90
|
+
metadata: { engine: 'applescript', degraded: false, latencyMs: Date.now() - start },
|
|
91
|
+
};
|
|
92
|
+
}
|
|
93
|
+
async handleClipboardWrite(params) {
|
|
94
|
+
const start = Date.now();
|
|
95
|
+
const tabUrl = params['tabUrl'];
|
|
96
|
+
const text = params['text'];
|
|
97
|
+
const js = buildClipboardWriteJs(text);
|
|
98
|
+
const script = this.engine.buildTabScript(tabUrl, js);
|
|
99
|
+
const result = await this.engine.execute(script);
|
|
100
|
+
if (!result.ok) {
|
|
101
|
+
return this.errorResponse(result.error?.message ?? 'Clipboard write failed', start);
|
|
102
|
+
}
|
|
103
|
+
const data = this.parseJson(result.value) ?? { written: false };
|
|
104
|
+
return {
|
|
105
|
+
content: [{ type: 'text', text: JSON.stringify(data) }],
|
|
106
|
+
metadata: { engine: 'applescript', degraded: false, latencyMs: Date.now() - start },
|
|
107
|
+
};
|
|
108
|
+
}
|
|
109
|
+
// ── Private helpers ─────────────────────────────────────────────────────────
|
|
110
|
+
parseJson(value) {
|
|
111
|
+
if (!value)
|
|
112
|
+
return undefined;
|
|
113
|
+
try {
|
|
114
|
+
const parsed = JSON.parse(value);
|
|
115
|
+
return typeof parsed === 'object' && parsed !== null ? parsed : undefined;
|
|
116
|
+
}
|
|
117
|
+
catch {
|
|
118
|
+
return undefined;
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
errorResponse(message, start) {
|
|
122
|
+
return {
|
|
123
|
+
content: [{ type: 'text', text: JSON.stringify({ error: message }) }],
|
|
124
|
+
metadata: { engine: 'applescript', degraded: true, latencyMs: Date.now() - start },
|
|
125
|
+
};
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
//# sourceMappingURL=clipboard.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"clipboard.js","sourceRoot":"","sources":["../../src/tools/clipboard.ts"],"names":[],"mappings":"AAMA;;;;GAIG;AACH,MAAM,iBAAiB,GAAG;;;;;;;;;CASzB,CAAC,IAAI,EAAE,CAAC;AAET,4CAA4C;AAC5C,SAAS,qBAAqB,CAAC,IAAY;IACzC,MAAM,OAAO,GAAG,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC;IACrC,OAAO;;;0CAGiC,OAAO;mDACE,OAAO;;;;;CAKzD,CAAC,IAAI,EAAE,CAAC;AACT,CAAC;AAED,MAAM,OAAO,cAAc;IACI;IAA7B,YAA6B,MAAyB;QAAzB,WAAM,GAAN,MAAM,CAAmB;IAAG,CAAC;IAE1D,+EAA+E;IAE/E,cAAc;QACZ,OAAO;YACL;gBACE,IAAI,EAAE,uBAAuB;gBAC7B,WAAW,EACT,iEAAiE;oBACjE,4DAA4D;oBAC5D,iFAAiF;oBACjF,mDAAmD;gBACrD,WAAW,EAAE;oBACX,IAAI,EAAE,QAAQ;oBACd,UAAU,EAAE;wBACV,MAAM,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,WAAW,EAAE,+CAA+C,EAAE;qBACzF;oBACD,QAAQ,EAAE,CAAC,QAAQ,CAAC;iBACrB;gBACD,YAAY,EAAE,EAAsB;aACrC;YACD;gBACE,IAAI,EAAE,wBAAwB;gBAC9B,WAAW,EAAE,wFAAwF;gBACrG,WAAW,EAAE;oBACX,IAAI,EAAE,QAAQ;oBACd,UAAU,EAAE;wBACV,MAAM,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,WAAW,EAAE,sDAAsD,EAAE;wBAC/F,IAAI,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,WAAW,EAAE,gCAAgC,EAAE;qBACxE;oBACD,QAAQ,EAAE,CAAC,QAAQ,EAAE,MAAM,CAAC;iBAC7B;gBACD,YAAY,EAAE,EAAsB;aACrC;SACF,CAAC;IACJ,CAAC;IAED,UAAU,CAAC,IAAY;QACrB,QAAQ,IAAI,EAAE,CAAC;YACb,KAAK,uBAAuB;gBAC1B,OAAO,CAAC,CAAC,EAAE,EAAE,CAAC,IAAI,CAAC,mBAAmB,CAAC,CAAC,CAAC,CAAC;YAC5C,KAAK,wBAAwB;gBAC3B,OAAO,CAAC,CAAC,EAAE,EAAE,CAAC,IAAI,CAAC,oBAAoB,CAAC,CAAC,CAAC,CAAC;YAC7C;gBACE,MAAM,IAAI,KAAK,CAAC,iCAAiC,IAAI,GAAG,CAAC,CAAC;QAC9D,CAAC;IACH,CAAC;IAED,+EAA+E;IAEvE,KAAK,CAAC,mBAAmB,CAAC,MAA+B;QAC/D,MAAM,KAAK,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;QACzB,MAAM,MAAM,GAAG,MAAM,CAAC,QAAQ,CAAW,CAAC;QAE1C,MAAM,MAAM,GAAG,IAAI,CAAC,MAAM,CAAC,cAAc,CAAC,MAAM,EAAE,iBAAiB,CAAC,CAAC;QACrE,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,MAAM,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC;QAEjD,IAAI,CAAC,MAAM,CAAC,EAAE,EAAE,CAAC;YACf,OAAO,IAAI,CAAC,aAAa,CAAC,MAAM,CAAC,KAAK,EAAE,OAAO,IAAI,uBAAuB,EAAE,KAAK,CAAC,CAAC;QACrF,CAAC;QAED,MAAM,IAAI,GAAG,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,KAAK,CAAC,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,kBAAkB,EAAE,KAAK,EAAE,CAAC;QACvF,OAAO;YACL,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,EAAE,CAAC;YACvD,QAAQ,EAAE,EAAE,MAAM,EAAE,aAAa,EAAE,QAAQ,EAAE,KAAK,EAAE,SAAS,EAAE,IAAI,CAAC,GAAG,EAAE,GAAG,KAAK,EAAE;SACpF,CAAC;IACJ,CAAC;IAEO,KAAK,CAAC,oBAAoB,CAAC,MAA+B;QAChE,MAAM,KAAK,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;QACzB,MAAM,MAAM,GAAG,MAAM,CAAC,QAAQ,CAAW,CAAC;QAC1C,MAAM,IAAI,GAAG,MAAM,CAAC,MAAM,CAAW,CAAC;QAEtC,MAAM,EAAE,GAAG,qBAAqB,CAAC,IAAI,CAAC,CAAC;QACvC,MAAM,MAAM,GAAG,IAAI,CAAC,MAAM,CAAC,cAAc,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC;QACtD,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,MAAM,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC;QAEjD,IAAI,CAAC,MAAM,CAAC,EAAE,EAAE,CAAC;YACf,OAAO,IAAI,CAAC,aAAa,CAAC,MAAM,CAAC,KAAK,EAAE,OAAO,IAAI,wBAAwB,EAAE,KAAK,CAAC,CAAC;QACtF,CAAC;QAED,MAAM,IAAI,GAAG,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,KAAK,CAAC,IAAI,EAAE,OAAO,EAAE,KAAK,EAAE,CAAC;QAChE,OAAO;YACL,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,EAAE,CAAC;YACvD,QAAQ,EAAE,EAAE,MAAM,EAAE,aAAa,EAAE,QAAQ,EAAE,KAAK,EAAE,SAAS,EAAE,IAAI,CAAC,GAAG,EAAE,GAAG,KAAK,EAAE;SACpF,CAAC;IACJ,CAAC;IAED,+EAA+E;IAEvE,SAAS,CAAC,KAAc;QAC9B,IAAI,CAAC,KAAK;YAAE,OAAO,SAAS,CAAC;QAC7B,IAAI,CAAC;YACH,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC;YACjC,OAAO,OAAO,MAAM,KAAK,QAAQ,IAAI,MAAM,KAAK,IAAI,CAAC,CAAC,CAAE,MAAkC,CAAC,CAAC,CAAC,SAAS,CAAC;QACzG,CAAC;QAAC,MAAM,CAAC;YACP,OAAO,SAAS,CAAC;QACnB,CAAC;IACH,CAAC;IAEO,aAAa,CAAC,OAAe,EAAE,KAAa;QAClD,OAAO;YACL,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,EAAE,KAAK,EAAE,OAAO,EAAE,CAAC,EAAE,CAAC;YACrE,QAAQ,EAAE,EAAE,MAAM,EAAE,aAAa,EAAE,QAAQ,EAAE,IAAI,EAAE,SAAS,EAAE,IAAI,CAAC,GAAG,EAAE,GAAG,KAAK,EAAE;SACnF,CAAC;IACJ,CAAC;CACF"}
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
import type { ToolResponse, ToolRequirements } from '../types.js';
|
|
2
|
+
import type { AppleScriptEngine } from '../engines/applescript.js';
|
|
3
|
+
export interface ToolDefinition {
|
|
4
|
+
name: string;
|
|
5
|
+
description: string;
|
|
6
|
+
inputSchema: Record<string, unknown>;
|
|
7
|
+
requirements: ToolRequirements;
|
|
8
|
+
}
|
|
9
|
+
type Handler = (params: Record<string, unknown>) => Promise<ToolResponse>;
|
|
10
|
+
export interface FlowStep {
|
|
11
|
+
action: 'navigate' | 'click' | 'fill' | 'wait' | 'assert';
|
|
12
|
+
selector?: string;
|
|
13
|
+
value?: string;
|
|
14
|
+
assert?: {
|
|
15
|
+
type: 'text' | 'element' | 'url';
|
|
16
|
+
expected: string;
|
|
17
|
+
};
|
|
18
|
+
}
|
|
19
|
+
export interface FlowStepResult {
|
|
20
|
+
step: number;
|
|
21
|
+
result: string;
|
|
22
|
+
passed: boolean;
|
|
23
|
+
}
|
|
24
|
+
export interface TestFlowResult {
|
|
25
|
+
passed: boolean;
|
|
26
|
+
steps: FlowStepResult[];
|
|
27
|
+
failedAt?: number;
|
|
28
|
+
screenshot?: string;
|
|
29
|
+
}
|
|
30
|
+
export interface PageChange {
|
|
31
|
+
check: number;
|
|
32
|
+
timestamp: string;
|
|
33
|
+
diff: string;
|
|
34
|
+
}
|
|
35
|
+
export interface MonitorResult {
|
|
36
|
+
changes: PageChange[];
|
|
37
|
+
checksPerformed: number;
|
|
38
|
+
finalSnapshot?: string;
|
|
39
|
+
}
|
|
40
|
+
export interface ScrapedPage {
|
|
41
|
+
pageNum: number;
|
|
42
|
+
url: string;
|
|
43
|
+
data: unknown;
|
|
44
|
+
}
|
|
45
|
+
export interface PaginateResult {
|
|
46
|
+
pages: ScrapedPage[];
|
|
47
|
+
totalPages: number;
|
|
48
|
+
}
|
|
49
|
+
export interface MediaState {
|
|
50
|
+
action: string;
|
|
51
|
+
currentTime: number;
|
|
52
|
+
duration: number;
|
|
53
|
+
paused: boolean;
|
|
54
|
+
muted: boolean;
|
|
55
|
+
volume: number;
|
|
56
|
+
playbackRate: number;
|
|
57
|
+
}
|
|
58
|
+
export declare class CompoundTools {
|
|
59
|
+
private readonly engine;
|
|
60
|
+
constructor(engine: AppleScriptEngine);
|
|
61
|
+
getDefinitions(): ToolDefinition[];
|
|
62
|
+
getHandler(name: string): Handler;
|
|
63
|
+
private handleTestFlow;
|
|
64
|
+
private handleMonitorPage;
|
|
65
|
+
private handlePaginateScrape;
|
|
66
|
+
private handleMediaControl;
|
|
67
|
+
}
|
|
68
|
+
export {};
|