safari-pilot 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.claude-plugin/plugin.json +35 -0
- package/.mcp.json +11 -0
- package/LICENSE +21 -0
- package/README.md +324 -0
- package/bin/.gitkeep +0 -0
- package/bin/Safari Pilot.app/Contents/CodeResources +0 -0
- package/bin/Safari Pilot.app/Contents/Info.plist +58 -0
- package/bin/Safari Pilot.app/Contents/MacOS/Safari Pilot +0 -0
- package/bin/Safari Pilot.app/Contents/PkgInfo +1 -0
- package/bin/Safari Pilot.app/Contents/PlugIns/Safari Pilot Extension.appex/Contents/Info.plist +55 -0
- package/bin/Safari Pilot.app/Contents/PlugIns/Safari Pilot Extension.appex/Contents/MacOS/Safari Pilot Extension +0 -0
- package/bin/Safari Pilot.app/Contents/PlugIns/Safari Pilot Extension.appex/Contents/Resources/background.js +294 -0
- package/bin/Safari Pilot.app/Contents/PlugIns/Safari Pilot Extension.appex/Contents/Resources/content-isolated.js +80 -0
- package/bin/Safari Pilot.app/Contents/PlugIns/Safari Pilot Extension.appex/Contents/Resources/content-main.js +310 -0
- package/bin/Safari Pilot.app/Contents/PlugIns/Safari Pilot Extension.appex/Contents/Resources/icons/icon-128.png +0 -0
- package/bin/Safari Pilot.app/Contents/PlugIns/Safari Pilot Extension.appex/Contents/Resources/icons/icon-48.png +0 -0
- package/bin/Safari Pilot.app/Contents/PlugIns/Safari Pilot Extension.appex/Contents/Resources/icons/icon-96.png +0 -0
- package/bin/Safari Pilot.app/Contents/PlugIns/Safari Pilot Extension.appex/Contents/Resources/manifest.json +39 -0
- package/bin/Safari Pilot.app/Contents/PlugIns/Safari Pilot Extension.appex/Contents/_CodeSignature/CodeResources +194 -0
- package/bin/Safari Pilot.app/Contents/Resources/AppIcon.icns +0 -0
- package/bin/Safari Pilot.app/Contents/Resources/Assets.car +0 -0
- package/bin/Safari Pilot.app/Contents/Resources/Base.lproj/Main.html +19 -0
- package/bin/Safari Pilot.app/Contents/Resources/Base.lproj/Main.storyboardc/Info.plist +0 -0
- package/bin/Safari Pilot.app/Contents/Resources/Base.lproj/Main.storyboardc/MainMenu.nib +0 -0
- package/bin/Safari Pilot.app/Contents/Resources/Base.lproj/Main.storyboardc/NSWindowController-B8D-0N-5wS.nib +0 -0
- package/bin/Safari Pilot.app/Contents/Resources/Base.lproj/Main.storyboardc/XfG-lQ-9wD-view-m2S-Jp-Qdl.nib +0 -0
- package/bin/Safari Pilot.app/Contents/Resources/Icon.png +0 -0
- package/bin/Safari Pilot.app/Contents/Resources/Script.js +22 -0
- package/bin/Safari Pilot.app/Contents/Resources/Style.css +45 -0
- package/bin/Safari Pilot.app/Contents/_CodeSignature/CodeResources +236 -0
- package/bin/Safari Pilot.zip +0 -0
- package/bin/SafariPilotd +0 -0
- package/dist/engine-selector.d.ts +10 -0
- package/dist/engine-selector.js +55 -0
- package/dist/engine-selector.js.map +1 -0
- package/dist/engines/applescript.d.ts +53 -0
- package/dist/engines/applescript.js +290 -0
- package/dist/engines/applescript.js.map +1 -0
- package/dist/engines/daemon.d.ts +19 -0
- package/dist/engines/daemon.js +187 -0
- package/dist/engines/daemon.js.map +1 -0
- package/dist/engines/engine.d.ts +15 -0
- package/dist/engines/engine.js +42 -0
- package/dist/engines/engine.js.map +1 -0
- package/dist/engines/extension.d.ts +34 -0
- package/dist/engines/extension.js +66 -0
- package/dist/engines/extension.js.map +1 -0
- package/dist/errors.d.ts +128 -0
- package/dist/errors.js +250 -0
- package/dist/errors.js.map +1 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +11 -0
- package/dist/index.js.map +1 -0
- package/dist/security/audit-log.d.ts +23 -0
- package/dist/security/audit-log.js +68 -0
- package/dist/security/audit-log.js.map +1 -0
- package/dist/security/circuit-breaker.d.ts +29 -0
- package/dist/security/circuit-breaker.js +114 -0
- package/dist/security/circuit-breaker.js.map +1 -0
- package/dist/security/domain-policy.d.ts +29 -0
- package/dist/security/domain-policy.js +96 -0
- package/dist/security/domain-policy.js.map +1 -0
- package/dist/security/human-approval.d.ts +20 -0
- package/dist/security/human-approval.js +150 -0
- package/dist/security/human-approval.js.map +1 -0
- package/dist/security/idpi-scanner.d.ts +20 -0
- package/dist/security/idpi-scanner.js +102 -0
- package/dist/security/idpi-scanner.js.map +1 -0
- package/dist/security/kill-switch.d.ts +51 -0
- package/dist/security/kill-switch.js +103 -0
- package/dist/security/kill-switch.js.map +1 -0
- package/dist/security/rate-limiter.d.ts +30 -0
- package/dist/security/rate-limiter.js +70 -0
- package/dist/security/rate-limiter.js.map +1 -0
- package/dist/security/screenshot-redaction.d.ts +42 -0
- package/dist/security/screenshot-redaction.js +134 -0
- package/dist/security/screenshot-redaction.js.map +1 -0
- package/dist/security/tab-ownership.d.ts +46 -0
- package/dist/security/tab-ownership.js +85 -0
- package/dist/security/tab-ownership.js.map +1 -0
- package/dist/server.d.ts +53 -0
- package/dist/server.js +347 -0
- package/dist/server.js.map +1 -0
- package/dist/tools/clipboard.d.ts +15 -0
- package/dist/tools/clipboard.js +128 -0
- package/dist/tools/clipboard.js.map +1 -0
- package/dist/tools/compound.d.ts +68 -0
- package/dist/tools/compound.js +491 -0
- package/dist/tools/compound.js.map +1 -0
- package/dist/tools/extraction.d.ts +26 -0
- package/dist/tools/extraction.js +414 -0
- package/dist/tools/extraction.js.map +1 -0
- package/dist/tools/frames.d.ts +22 -0
- package/dist/tools/frames.js +165 -0
- package/dist/tools/frames.js.map +1 -0
- package/dist/tools/interaction.d.ts +30 -0
- package/dist/tools/interaction.js +651 -0
- package/dist/tools/interaction.js.map +1 -0
- package/dist/tools/navigation.d.ts +41 -0
- package/dist/tools/navigation.js +316 -0
- package/dist/tools/navigation.js.map +1 -0
- package/dist/tools/network.d.ts +27 -0
- package/dist/tools/network.js +721 -0
- package/dist/tools/network.js.map +1 -0
- package/dist/tools/performance.d.ts +16 -0
- package/dist/tools/performance.js +240 -0
- package/dist/tools/performance.js.map +1 -0
- package/dist/tools/permissions.d.ts +25 -0
- package/dist/tools/permissions.js +308 -0
- package/dist/tools/permissions.js.map +1 -0
- package/dist/tools/service-workers.d.ts +15 -0
- package/dist/tools/service-workers.js +136 -0
- package/dist/tools/service-workers.js.map +1 -0
- package/dist/tools/shadow.d.ts +21 -0
- package/dist/tools/shadow.js +126 -0
- package/dist/tools/shadow.js.map +1 -0
- package/dist/tools/storage.d.ts +30 -0
- package/dist/tools/storage.js +679 -0
- package/dist/tools/storage.js.map +1 -0
- package/dist/tools/structured-extraction.d.ts +22 -0
- package/dist/tools/structured-extraction.js +433 -0
- package/dist/tools/structured-extraction.js.map +1 -0
- package/dist/tools/wait.d.ts +18 -0
- package/dist/tools/wait.js +182 -0
- package/dist/tools/wait.js.map +1 -0
- package/dist/types.d.ts +85 -0
- package/dist/types.js +2 -0
- package/dist/types.js.map +1 -0
- package/extension/background.js +294 -0
- package/extension/content-isolated.js +80 -0
- package/extension/content-main.js +310 -0
- package/extension/icons/icon-128.png +0 -0
- package/extension/icons/icon-48.png +0 -0
- package/extension/icons/icon-96.png +0 -0
- package/extension/manifest.json +39 -0
- package/hooks/session-end.sh +67 -0
- package/hooks/session-start.sh +66 -0
- package/package.json +46 -0
- package/scripts/build-extension.sh +135 -0
- package/scripts/postinstall.sh +91 -0
- package/scripts/preuninstall.sh +25 -0
- package/scripts/update-daemon.sh +62 -0
- package/skills/safari-pilot/SKILL.md +157 -0
|
@@ -0,0 +1,414 @@
|
|
|
1
|
+
import { execFile } from 'node:child_process';
|
|
2
|
+
import { readFile, unlink } from 'node:fs/promises';
|
|
3
|
+
import { tmpdir } from 'node:os';
|
|
4
|
+
import { join } from 'node:path';
|
|
5
|
+
export class ExtractionTools {
|
|
6
|
+
engine;
|
|
7
|
+
handlers = new Map();
|
|
8
|
+
constructor(engine) {
|
|
9
|
+
this.engine = engine;
|
|
10
|
+
this.registerHandlers();
|
|
11
|
+
}
|
|
12
|
+
registerHandlers() {
|
|
13
|
+
this.handlers.set('safari_snapshot', this.handleSnapshot.bind(this));
|
|
14
|
+
this.handlers.set('safari_get_text', this.handleGetText.bind(this));
|
|
15
|
+
this.handlers.set('safari_get_html', this.handleGetHtml.bind(this));
|
|
16
|
+
this.handlers.set('safari_get_attribute', this.handleGetAttribute.bind(this));
|
|
17
|
+
this.handlers.set('safari_evaluate', this.handleEvaluate.bind(this));
|
|
18
|
+
this.handlers.set('safari_take_screenshot', this.handleTakeScreenshot.bind(this));
|
|
19
|
+
this.handlers.set('safari_get_console_messages', this.handleGetConsoleMessages.bind(this));
|
|
20
|
+
}
|
|
21
|
+
// ── Public API ──────────────────────────────────────────────────────────────
|
|
22
|
+
getDefinitions() {
|
|
23
|
+
return [
|
|
24
|
+
{
|
|
25
|
+
name: 'safari_snapshot',
|
|
26
|
+
description: 'Capture the page accessibility tree as a compact representation. The primary way the agent "sees" the page. ' +
|
|
27
|
+
'Returns roles, names, states, and interactive element metadata.',
|
|
28
|
+
inputSchema: {
|
|
29
|
+
type: 'object',
|
|
30
|
+
properties: {
|
|
31
|
+
tabUrl: { type: 'string', description: 'Current URL of the tab' },
|
|
32
|
+
scope: {
|
|
33
|
+
type: 'string',
|
|
34
|
+
description: 'CSS selector to scope snapshot, or "page" for full page',
|
|
35
|
+
default: 'page',
|
|
36
|
+
},
|
|
37
|
+
format: {
|
|
38
|
+
type: 'string',
|
|
39
|
+
enum: ['yaml', 'json'],
|
|
40
|
+
description: 'Output format for the snapshot',
|
|
41
|
+
default: 'yaml',
|
|
42
|
+
},
|
|
43
|
+
maxDepth: { type: 'number', description: 'Maximum DOM traversal depth', default: 10 },
|
|
44
|
+
includeHidden: {
|
|
45
|
+
type: 'boolean',
|
|
46
|
+
description: 'Include hidden elements in snapshot',
|
|
47
|
+
default: false,
|
|
48
|
+
},
|
|
49
|
+
},
|
|
50
|
+
required: ['tabUrl'],
|
|
51
|
+
},
|
|
52
|
+
requirements: {},
|
|
53
|
+
},
|
|
54
|
+
{
|
|
55
|
+
name: 'safari_get_text',
|
|
56
|
+
description: 'Extract the visible text content of the page or a specific element.',
|
|
57
|
+
inputSchema: {
|
|
58
|
+
type: 'object',
|
|
59
|
+
properties: {
|
|
60
|
+
tabUrl: { type: 'string', description: 'Current URL of the tab' },
|
|
61
|
+
selector: { type: 'string', description: 'CSS selector. If omitted, returns full page text.' },
|
|
62
|
+
maxLength: { type: 'number', description: 'Maximum characters to return', default: 50000 },
|
|
63
|
+
},
|
|
64
|
+
required: ['tabUrl'],
|
|
65
|
+
},
|
|
66
|
+
requirements: {},
|
|
67
|
+
},
|
|
68
|
+
{
|
|
69
|
+
name: 'safari_get_html',
|
|
70
|
+
description: 'Get the HTML content of an element or the full page.',
|
|
71
|
+
inputSchema: {
|
|
72
|
+
type: 'object',
|
|
73
|
+
properties: {
|
|
74
|
+
tabUrl: { type: 'string', description: 'Current URL of the tab' },
|
|
75
|
+
selector: { type: 'string', description: 'CSS selector. If omitted, returns full page HTML.' },
|
|
76
|
+
outer: {
|
|
77
|
+
type: 'boolean',
|
|
78
|
+
description: 'true = outerHTML (includes the element itself), false = innerHTML (just contents)',
|
|
79
|
+
default: true,
|
|
80
|
+
},
|
|
81
|
+
},
|
|
82
|
+
required: ['tabUrl'],
|
|
83
|
+
},
|
|
84
|
+
requirements: {},
|
|
85
|
+
},
|
|
86
|
+
{
|
|
87
|
+
name: 'safari_get_attribute',
|
|
88
|
+
description: 'Get a specific attribute value from an element.',
|
|
89
|
+
inputSchema: {
|
|
90
|
+
type: 'object',
|
|
91
|
+
properties: {
|
|
92
|
+
tabUrl: { type: 'string', description: 'Current URL of the tab' },
|
|
93
|
+
selector: { type: 'string', description: 'CSS selector for the element' },
|
|
94
|
+
attribute: { type: 'string', description: 'Attribute name: href, src, data-id, aria-label, etc.' },
|
|
95
|
+
},
|
|
96
|
+
required: ['tabUrl', 'selector', 'attribute'],
|
|
97
|
+
},
|
|
98
|
+
requirements: {},
|
|
99
|
+
},
|
|
100
|
+
{
|
|
101
|
+
name: 'safari_evaluate',
|
|
102
|
+
description: 'Execute arbitrary JavaScript in the page context and return the result. ' +
|
|
103
|
+
'The most flexible extraction tool. Script must return a JSON-serializable value.',
|
|
104
|
+
inputSchema: {
|
|
105
|
+
type: 'object',
|
|
106
|
+
properties: {
|
|
107
|
+
tabUrl: { type: 'string', description: 'Current URL of the tab' },
|
|
108
|
+
script: { type: 'string', description: 'JavaScript code to execute. Must return a value.' },
|
|
109
|
+
timeout: { type: 'number', description: 'Execution timeout in milliseconds', default: 10000 },
|
|
110
|
+
},
|
|
111
|
+
required: ['tabUrl', 'script'],
|
|
112
|
+
},
|
|
113
|
+
requirements: {},
|
|
114
|
+
},
|
|
115
|
+
{
|
|
116
|
+
name: 'safari_take_screenshot',
|
|
117
|
+
description: 'Capture a screenshot of the Safari window via screencapture CLI. ' +
|
|
118
|
+
'Returns the image as base64-encoded PNG. Requires Screen Recording permission.',
|
|
119
|
+
inputSchema: {
|
|
120
|
+
type: 'object',
|
|
121
|
+
properties: {
|
|
122
|
+
tabUrl: { type: 'string', description: 'Current URL of the tab (used to bring it to front)' },
|
|
123
|
+
fullPage: {
|
|
124
|
+
type: 'boolean',
|
|
125
|
+
description: 'Capture the full scrollable page (not just viewport)',
|
|
126
|
+
default: false,
|
|
127
|
+
},
|
|
128
|
+
path: {
|
|
129
|
+
type: 'string',
|
|
130
|
+
description: 'Optional file path to save the screenshot. If omitted, returns base64 data.',
|
|
131
|
+
},
|
|
132
|
+
format: { type: 'string', enum: ['png', 'jpeg'], description: 'Image format', default: 'png' },
|
|
133
|
+
quality: { type: 'number', description: 'JPEG quality 0-100', default: 80 },
|
|
134
|
+
},
|
|
135
|
+
required: [],
|
|
136
|
+
},
|
|
137
|
+
requirements: {},
|
|
138
|
+
},
|
|
139
|
+
{
|
|
140
|
+
name: 'safari_get_console_messages',
|
|
141
|
+
description: 'Retrieve console messages (log, warn, error, info) captured from the page.',
|
|
142
|
+
inputSchema: {
|
|
143
|
+
type: 'object',
|
|
144
|
+
properties: {
|
|
145
|
+
tabUrl: { type: 'string', description: 'Current URL of the tab' },
|
|
146
|
+
level: {
|
|
147
|
+
type: 'string',
|
|
148
|
+
enum: ['all', 'log', 'warn', 'error', 'info'],
|
|
149
|
+
description: 'Filter by log level',
|
|
150
|
+
default: 'all',
|
|
151
|
+
},
|
|
152
|
+
limit: { type: 'number', description: 'Maximum messages to return', default: 100 },
|
|
153
|
+
clear: { type: 'boolean', description: 'Clear the buffer after reading', default: false },
|
|
154
|
+
},
|
|
155
|
+
required: ['tabUrl'],
|
|
156
|
+
},
|
|
157
|
+
requirements: {},
|
|
158
|
+
},
|
|
159
|
+
];
|
|
160
|
+
}
|
|
161
|
+
getHandler(name) {
|
|
162
|
+
return this.handlers.get(name);
|
|
163
|
+
}
|
|
164
|
+
// ── Handlers ────────────────────────────────────────────────────────────────
|
|
165
|
+
async handleSnapshot(params) {
|
|
166
|
+
const start = Date.now();
|
|
167
|
+
const tabUrl = params['tabUrl'];
|
|
168
|
+
const scope = params['scope'] ?? 'page';
|
|
169
|
+
const maxDepth = typeof params['maxDepth'] === 'number' ? params['maxDepth'] : 10;
|
|
170
|
+
const includeHidden = params['includeHidden'] === true;
|
|
171
|
+
const scopeSelector = scope === 'page' || !scope ? '' : scope.replace(/'/g, "\\'");
|
|
172
|
+
const js = `
|
|
173
|
+
var maxD = ${maxDepth};
|
|
174
|
+
var inclHidden = ${includeHidden};
|
|
175
|
+
var scopeSelector = '${scopeSelector}';
|
|
176
|
+
|
|
177
|
+
function getRole(el) {
|
|
178
|
+
if (el.getAttribute('role')) return el.getAttribute('role');
|
|
179
|
+
var tag = el.tagName.toLowerCase();
|
|
180
|
+
var typeMap = {
|
|
181
|
+
a: 'link', button: 'button', input: 'textbox', select: 'combobox',
|
|
182
|
+
textarea: 'textbox', img: 'img', h1: 'heading', h2: 'heading', h3: 'heading',
|
|
183
|
+
h4: 'heading', h5: 'heading', h6: 'heading', nav: 'navigation', main: 'main',
|
|
184
|
+
form: 'form', table: 'table', ul: 'list', ol: 'list', li: 'listitem'
|
|
185
|
+
};
|
|
186
|
+
return typeMap[tag] || '';
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
function getName(el) {
|
|
190
|
+
return el.getAttribute('aria-label') || el.getAttribute('alt') ||
|
|
191
|
+
el.getAttribute('title') || el.getAttribute('placeholder') ||
|
|
192
|
+
(el.labels && el.labels[0] ? el.labels[0].textContent.trim() : '') ||
|
|
193
|
+
(el.textContent || '').trim().slice(0, 80);
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
function getState(el) {
|
|
197
|
+
var states = [];
|
|
198
|
+
if (el.tagName === 'INPUT' || el.tagName === 'TEXTAREA' || el.tagName === 'SELECT') {
|
|
199
|
+
if (el.required) states.push('required');
|
|
200
|
+
if (el.disabled) states.push('disabled');
|
|
201
|
+
if (el.readOnly) states.push('readonly');
|
|
202
|
+
if (el.type === 'checkbox' || el.type === 'radio') states.push(el.checked ? 'checked' : 'unchecked');
|
|
203
|
+
if (el.type) states.push('type=' + el.type);
|
|
204
|
+
}
|
|
205
|
+
if (el.tagName === 'BUTTON' || (el.tagName === 'INPUT' && el.type === 'submit')) {
|
|
206
|
+
states.push(el.disabled ? 'disabled' : 'enabled');
|
|
207
|
+
}
|
|
208
|
+
var level = el.tagName.match(/^H(\\d)$/i);
|
|
209
|
+
if (level) states.push('level=' + level[1]);
|
|
210
|
+
return states;
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
function isInteractive(el) {
|
|
214
|
+
var tag = el.tagName.toLowerCase();
|
|
215
|
+
return ['a', 'button', 'input', 'select', 'textarea'].indexOf(tag) !== -1 ||
|
|
216
|
+
el.getAttribute('role') === 'button' || el.getAttribute('tabindex') !== null ||
|
|
217
|
+
el.onclick !== null;
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
var lines = [];
|
|
221
|
+
var elementCount = 0;
|
|
222
|
+
var interactiveCount = 0;
|
|
223
|
+
|
|
224
|
+
function walk(node, depth) {
|
|
225
|
+
if (depth > maxD) return;
|
|
226
|
+
if (node.nodeType !== 1) return;
|
|
227
|
+
if (!inclHidden && (node.offsetParent === null && getComputedStyle(node).position !== 'fixed')) return;
|
|
228
|
+
|
|
229
|
+
var role = getRole(node);
|
|
230
|
+
var name = getName(node);
|
|
231
|
+
if (role || isInteractive(node)) {
|
|
232
|
+
elementCount++;
|
|
233
|
+
if (isInteractive(node)) interactiveCount++;
|
|
234
|
+
var indent = '';
|
|
235
|
+
for (var i = 0; i < depth; i++) indent += ' ';
|
|
236
|
+
var states = getState(node);
|
|
237
|
+
var stateStr = states.length ? ' [' + states.join(', ') + ']' : '';
|
|
238
|
+
var idStr = node.id ? ' #' + node.id : '';
|
|
239
|
+
var hrefStr = node.tagName === 'A' && node.href ? ' -> ' + new URL(node.href).pathname : '';
|
|
240
|
+
lines.push(indent + '- ' + (role || node.tagName.toLowerCase()) + (name ? ' "' + name.replace(/"/g, '\\\\"').slice(0, 80) + '"' : '') + stateStr + idStr + hrefStr);
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
for (var ci = 0; ci < node.children.length; ci++) {
|
|
244
|
+
walk(node.children[ci], depth + (role ? 1 : 0));
|
|
245
|
+
}
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
var root = scopeSelector ? document.querySelector(scopeSelector) : document.body;
|
|
249
|
+
if (!root) throw Object.assign(new Error('Scope element not found'), { name: 'ELEMENT_NOT_FOUND' });
|
|
250
|
+
walk(root, 0);
|
|
251
|
+
|
|
252
|
+
return {
|
|
253
|
+
snapshot: lines.join('\\n'),
|
|
254
|
+
url: window.location.href,
|
|
255
|
+
title: document.title,
|
|
256
|
+
elementCount: elementCount,
|
|
257
|
+
interactiveCount: interactiveCount,
|
|
258
|
+
};
|
|
259
|
+
`;
|
|
260
|
+
const result = await this.engine.executeJsInTab(tabUrl, js);
|
|
261
|
+
if (!result.ok)
|
|
262
|
+
throw new Error(result.error?.message ?? 'Snapshot failed');
|
|
263
|
+
return this.makeResponse(result.value ? JSON.parse(result.value) : {}, Date.now() - start);
|
|
264
|
+
}
|
|
265
|
+
async handleGetText(params) {
|
|
266
|
+
const start = Date.now();
|
|
267
|
+
const tabUrl = params['tabUrl'];
|
|
268
|
+
const selector = params['selector'];
|
|
269
|
+
const maxLength = typeof params['maxLength'] === 'number' ? params['maxLength'] : 50000;
|
|
270
|
+
const escapedSelector = selector ? selector.replace(/'/g, "\\'") : '';
|
|
271
|
+
const js = `
|
|
272
|
+
var el = ${selector ? `document.querySelector('${escapedSelector}')` : 'document.body'};
|
|
273
|
+
if (!el) throw Object.assign(new Error('Element not found'), { name: 'ELEMENT_NOT_FOUND' });
|
|
274
|
+
var max = ${maxLength};
|
|
275
|
+
var text = el.innerText || el.textContent || '';
|
|
276
|
+
return { text: text.slice(0, max), length: text.length, truncated: text.length > max };
|
|
277
|
+
`;
|
|
278
|
+
const result = await this.engine.executeJsInTab(tabUrl, js);
|
|
279
|
+
if (!result.ok)
|
|
280
|
+
throw new Error(result.error?.message ?? 'Get text failed');
|
|
281
|
+
return this.makeResponse(result.value ? JSON.parse(result.value) : {}, Date.now() - start);
|
|
282
|
+
}
|
|
283
|
+
async handleGetHtml(params) {
|
|
284
|
+
const start = Date.now();
|
|
285
|
+
const tabUrl = params['tabUrl'];
|
|
286
|
+
const selector = params['selector'];
|
|
287
|
+
const outer = params['outer'] !== false;
|
|
288
|
+
const escapedSelector = selector ? selector.replace(/'/g, "\\'") : '';
|
|
289
|
+
const js = `
|
|
290
|
+
var el = ${selector ? `document.querySelector('${escapedSelector}')` : 'document.documentElement'};
|
|
291
|
+
if (!el) throw Object.assign(new Error('Element not found'), { name: 'ELEMENT_NOT_FOUND' });
|
|
292
|
+
var html = ${outer ? 'el.outerHTML' : 'el.innerHTML'};
|
|
293
|
+
return { html: html, length: html.length };
|
|
294
|
+
`;
|
|
295
|
+
const result = await this.engine.executeJsInTab(tabUrl, js);
|
|
296
|
+
if (!result.ok)
|
|
297
|
+
throw new Error(result.error?.message ?? 'Get HTML failed');
|
|
298
|
+
return this.makeResponse(result.value ? JSON.parse(result.value) : {}, Date.now() - start);
|
|
299
|
+
}
|
|
300
|
+
async handleGetAttribute(params) {
|
|
301
|
+
const start = Date.now();
|
|
302
|
+
const tabUrl = params['tabUrl'];
|
|
303
|
+
const selector = params['selector'];
|
|
304
|
+
const attribute = params['attribute'];
|
|
305
|
+
const escapedSelector = selector.replace(/'/g, "\\'");
|
|
306
|
+
const escapedAttribute = attribute.replace(/'/g, "\\'");
|
|
307
|
+
const js = `
|
|
308
|
+
var el = document.querySelector('${escapedSelector}');
|
|
309
|
+
if (!el) throw Object.assign(new Error('Element not found'), { name: 'ELEMENT_NOT_FOUND' });
|
|
310
|
+
return {
|
|
311
|
+
value: el.getAttribute('${escapedAttribute}'),
|
|
312
|
+
element: { tagName: el.tagName, id: el.id || undefined },
|
|
313
|
+
};
|
|
314
|
+
`;
|
|
315
|
+
const result = await this.engine.executeJsInTab(tabUrl, js);
|
|
316
|
+
if (!result.ok)
|
|
317
|
+
throw new Error(result.error?.message ?? 'Get attribute failed');
|
|
318
|
+
return this.makeResponse(result.value ? JSON.parse(result.value) : {}, Date.now() - start);
|
|
319
|
+
}
|
|
320
|
+
async handleEvaluate(params) {
|
|
321
|
+
const start = Date.now();
|
|
322
|
+
const tabUrl = params['tabUrl'];
|
|
323
|
+
const script = params['script'];
|
|
324
|
+
const timeout = typeof params['timeout'] === 'number' ? params['timeout'] : 10000;
|
|
325
|
+
const js = `
|
|
326
|
+
var __userResult = (function() { ${script} })();
|
|
327
|
+
return { value: __userResult, type: typeof __userResult };
|
|
328
|
+
`;
|
|
329
|
+
const result = await this.engine.executeJsInTab(tabUrl, js, timeout);
|
|
330
|
+
if (!result.ok)
|
|
331
|
+
throw new Error(result.error?.message ?? 'Evaluate failed');
|
|
332
|
+
return this.makeResponse(result.value ? JSON.parse(result.value) : {}, Date.now() - start);
|
|
333
|
+
}
|
|
334
|
+
async handleTakeScreenshot(params) {
|
|
335
|
+
const start = Date.now();
|
|
336
|
+
const format = params['format'] ?? 'png';
|
|
337
|
+
const savePath = params['path'];
|
|
338
|
+
const screenshotFormat = format === 'jpeg' ? 'jpg' : 'png';
|
|
339
|
+
const tmpFile = savePath ?? join(tmpdir(), `safari-pilot-${Date.now()}.${screenshotFormat}`);
|
|
340
|
+
const usingTmpFile = !savePath;
|
|
341
|
+
try {
|
|
342
|
+
await new Promise((resolve, reject) => {
|
|
343
|
+
execFile('screencapture', ['-x', '-t', screenshotFormat, tmpFile], { timeout: 10000 }, (error) => {
|
|
344
|
+
if (error)
|
|
345
|
+
reject(error);
|
|
346
|
+
else
|
|
347
|
+
resolve();
|
|
348
|
+
});
|
|
349
|
+
});
|
|
350
|
+
const buffer = await readFile(tmpFile);
|
|
351
|
+
const base64 = buffer.toString('base64');
|
|
352
|
+
if (usingTmpFile) {
|
|
353
|
+
await unlink(tmpFile).catch(() => { });
|
|
354
|
+
}
|
|
355
|
+
return {
|
|
356
|
+
content: [{ type: 'image', data: base64, mimeType: `image/${screenshotFormat === 'jpg' ? 'jpeg' : 'png'}` }],
|
|
357
|
+
metadata: { engine: 'applescript', degraded: false, latencyMs: Date.now() - start },
|
|
358
|
+
};
|
|
359
|
+
}
|
|
360
|
+
catch (error) {
|
|
361
|
+
if (usingTmpFile) {
|
|
362
|
+
await unlink(tmpFile).catch(() => { });
|
|
363
|
+
}
|
|
364
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
365
|
+
throw new Error(`Screenshot failed: ${message}`);
|
|
366
|
+
}
|
|
367
|
+
}
|
|
368
|
+
async handleGetConsoleMessages(params) {
|
|
369
|
+
const start = Date.now();
|
|
370
|
+
const tabUrl = params['tabUrl'];
|
|
371
|
+
const level = params['level'] ?? 'all';
|
|
372
|
+
const limit = typeof params['limit'] === 'number' ? params['limit'] : 100;
|
|
373
|
+
const clear = params['clear'] === true;
|
|
374
|
+
const js = `
|
|
375
|
+
if (!window.__safariPilotConsole) {
|
|
376
|
+
window.__safariPilotConsole = [];
|
|
377
|
+
var origConsole = {};
|
|
378
|
+
['log', 'warn', 'error', 'info'].forEach(function(method) {
|
|
379
|
+
origConsole[method] = console[method];
|
|
380
|
+
console[method] = function() {
|
|
381
|
+
var args = Array.prototype.slice.call(arguments);
|
|
382
|
+
window.__safariPilotConsole.push({
|
|
383
|
+
level: method,
|
|
384
|
+
text: args.map(function(a) { return typeof a === 'object' ? JSON.stringify(a) : String(a); }).join(' '),
|
|
385
|
+
timestamp: Date.now(),
|
|
386
|
+
});
|
|
387
|
+
origConsole[method].apply(console, args);
|
|
388
|
+
};
|
|
389
|
+
});
|
|
390
|
+
}
|
|
391
|
+
|
|
392
|
+
var filterLevel = '${level}';
|
|
393
|
+
var msgs = window.__safariPilotConsole;
|
|
394
|
+
if (filterLevel !== 'all') msgs = msgs.filter(function(m) { return m.level === filterLevel; });
|
|
395
|
+
var limited = msgs.slice(-${limit});
|
|
396
|
+
|
|
397
|
+
${clear ? 'window.__safariPilotConsole = [];' : ''}
|
|
398
|
+
|
|
399
|
+
return { messages: limited, count: limited.length };
|
|
400
|
+
`;
|
|
401
|
+
const result = await this.engine.executeJsInTab(tabUrl, js);
|
|
402
|
+
if (!result.ok)
|
|
403
|
+
throw new Error(result.error?.message ?? 'Get console messages failed');
|
|
404
|
+
return this.makeResponse(result.value ? JSON.parse(result.value) : { messages: [], count: 0 }, Date.now() - start);
|
|
405
|
+
}
|
|
406
|
+
// ── Private helpers ─────────────────────────────────────────────────────────
|
|
407
|
+
makeResponse(data, latencyMs = 0) {
|
|
408
|
+
return {
|
|
409
|
+
content: [{ type: 'text', text: JSON.stringify(data) }],
|
|
410
|
+
metadata: { engine: 'applescript', degraded: false, latencyMs },
|
|
411
|
+
};
|
|
412
|
+
}
|
|
413
|
+
}
|
|
414
|
+
//# sourceMappingURL=extraction.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"extraction.js","sourceRoot":"","sources":["../../src/tools/extraction.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,22 @@
|
|
|
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 declare class FrameTools {
|
|
11
|
+
private engine;
|
|
12
|
+
private handlers;
|
|
13
|
+
constructor(engine: AppleScriptEngine);
|
|
14
|
+
private registerHandlers;
|
|
15
|
+
getDefinitions(): ToolDefinition[];
|
|
16
|
+
getHandler(name: string): Handler | undefined;
|
|
17
|
+
private handleListFrames;
|
|
18
|
+
private handleSwitchFrame;
|
|
19
|
+
private handleEvalInFrame;
|
|
20
|
+
private makeResponse;
|
|
21
|
+
}
|
|
22
|
+
export {};
|
|
@@ -0,0 +1,165 @@
|
|
|
1
|
+
export class FrameTools {
|
|
2
|
+
engine;
|
|
3
|
+
handlers = new Map();
|
|
4
|
+
constructor(engine) {
|
|
5
|
+
this.engine = engine;
|
|
6
|
+
this.registerHandlers();
|
|
7
|
+
}
|
|
8
|
+
registerHandlers() {
|
|
9
|
+
this.handlers.set('safari_list_frames', this.handleListFrames.bind(this));
|
|
10
|
+
this.handlers.set('safari_switch_frame', this.handleSwitchFrame.bind(this));
|
|
11
|
+
this.handlers.set('safari_eval_in_frame', this.handleEvalInFrame.bind(this));
|
|
12
|
+
}
|
|
13
|
+
// ── Public API ──────────────────────────────────────────────────────────────
|
|
14
|
+
getDefinitions() {
|
|
15
|
+
return [
|
|
16
|
+
{
|
|
17
|
+
name: 'safari_list_frames',
|
|
18
|
+
description: 'List all iframes on the current page. Returns each frame\'s src URL, name attribute, ' +
|
|
19
|
+
'id attribute, and dimensions (width/height).',
|
|
20
|
+
inputSchema: {
|
|
21
|
+
type: 'object',
|
|
22
|
+
properties: {
|
|
23
|
+
tabUrl: { type: 'string', description: 'Current URL of the tab' },
|
|
24
|
+
},
|
|
25
|
+
required: ['tabUrl'],
|
|
26
|
+
},
|
|
27
|
+
requirements: {},
|
|
28
|
+
},
|
|
29
|
+
{
|
|
30
|
+
name: 'safari_switch_frame',
|
|
31
|
+
description: 'Set the active frame context for subsequent commands. Records the frame selector so ' +
|
|
32
|
+
'future tool calls targeting this tab are scoped to the specified iframe.',
|
|
33
|
+
inputSchema: {
|
|
34
|
+
type: 'object',
|
|
35
|
+
properties: {
|
|
36
|
+
tabUrl: { type: 'string', description: 'Current URL of the tab' },
|
|
37
|
+
frameSelector: {
|
|
38
|
+
type: 'string',
|
|
39
|
+
description: 'CSS selector for the iframe element to switch into (e.g. "#my-iframe", "iframe[name=chat]")',
|
|
40
|
+
},
|
|
41
|
+
},
|
|
42
|
+
required: ['tabUrl', 'frameSelector'],
|
|
43
|
+
},
|
|
44
|
+
requirements: {},
|
|
45
|
+
},
|
|
46
|
+
{
|
|
47
|
+
name: 'safari_eval_in_frame',
|
|
48
|
+
description: 'Execute arbitrary JavaScript inside a specific iframe\'s context. Accesses the iframe\'s ' +
|
|
49
|
+
'contentWindow to run the script. Cross-origin frames require the extension engine.',
|
|
50
|
+
inputSchema: {
|
|
51
|
+
type: 'object',
|
|
52
|
+
properties: {
|
|
53
|
+
tabUrl: { type: 'string', description: 'Current URL of the tab' },
|
|
54
|
+
frameSelector: { type: 'string', description: 'CSS selector for the target iframe' },
|
|
55
|
+
script: { type: 'string', description: 'JavaScript code to execute inside the frame' },
|
|
56
|
+
},
|
|
57
|
+
required: ['tabUrl', 'frameSelector', 'script'],
|
|
58
|
+
},
|
|
59
|
+
requirements: { requiresFramesCrossOrigin: true },
|
|
60
|
+
},
|
|
61
|
+
];
|
|
62
|
+
}
|
|
63
|
+
getHandler(name) {
|
|
64
|
+
return this.handlers.get(name);
|
|
65
|
+
}
|
|
66
|
+
// ── Handlers ────────────────────────────────────────────────────────────────
|
|
67
|
+
async handleListFrames(params) {
|
|
68
|
+
const start = Date.now();
|
|
69
|
+
const tabUrl = params['tabUrl'];
|
|
70
|
+
const js = `
|
|
71
|
+
var frames = Array.from(document.querySelectorAll('iframe'));
|
|
72
|
+
return {
|
|
73
|
+
count: frames.length,
|
|
74
|
+
frames: frames.map(function(f, idx) {
|
|
75
|
+
var rect = f.getBoundingClientRect();
|
|
76
|
+
return {
|
|
77
|
+
index: idx,
|
|
78
|
+
src: f.src || null,
|
|
79
|
+
name: f.name || null,
|
|
80
|
+
id: f.id || null,
|
|
81
|
+
width: f.width || rect.width,
|
|
82
|
+
height: f.height || rect.height,
|
|
83
|
+
sandbox: f.sandbox ? f.sandbox.value : null,
|
|
84
|
+
};
|
|
85
|
+
}),
|
|
86
|
+
};
|
|
87
|
+
`;
|
|
88
|
+
const result = await this.engine.executeJsInTab(tabUrl, js);
|
|
89
|
+
if (!result.ok)
|
|
90
|
+
throw new Error(result.error?.message ?? 'List frames failed');
|
|
91
|
+
return this.makeResponse(result.value ? JSON.parse(result.value) : { count: 0, frames: [] }, Date.now() - start);
|
|
92
|
+
}
|
|
93
|
+
async handleSwitchFrame(params) {
|
|
94
|
+
const start = Date.now();
|
|
95
|
+
const tabUrl = params['tabUrl'];
|
|
96
|
+
const frameSelector = params['frameSelector'];
|
|
97
|
+
const escapedSelector = frameSelector.replace(/\\/g, '\\\\').replace(/'/g, "\\'");
|
|
98
|
+
// Verify the frame exists before recording the switch
|
|
99
|
+
const js = `
|
|
100
|
+
var frame = document.querySelector('${escapedSelector}');
|
|
101
|
+
if (!frame) throw Object.assign(new Error('Frame not found: ${escapedSelector}'), { name: 'ELEMENT_NOT_FOUND' });
|
|
102
|
+
if (frame.tagName !== 'IFRAME') throw new Error('Element is not an iframe: ${escapedSelector}');
|
|
103
|
+
|
|
104
|
+
return {
|
|
105
|
+
switched: true,
|
|
106
|
+
frame: {
|
|
107
|
+
selector: '${escapedSelector}',
|
|
108
|
+
src: frame.src || null,
|
|
109
|
+
name: frame.name || null,
|
|
110
|
+
id: frame.id || null,
|
|
111
|
+
},
|
|
112
|
+
};
|
|
113
|
+
`;
|
|
114
|
+
const result = await this.engine.executeJsInTab(tabUrl, js);
|
|
115
|
+
if (!result.ok)
|
|
116
|
+
throw new Error(result.error?.message ?? 'Switch frame failed');
|
|
117
|
+
return this.makeResponse(result.value ? JSON.parse(result.value) : { switched: true, frame: { selector: frameSelector } }, Date.now() - start);
|
|
118
|
+
}
|
|
119
|
+
async handleEvalInFrame(params) {
|
|
120
|
+
const start = Date.now();
|
|
121
|
+
const tabUrl = params['tabUrl'];
|
|
122
|
+
const frameSelector = params['frameSelector'];
|
|
123
|
+
const script = params['script'];
|
|
124
|
+
const escapedSelector = frameSelector.replace(/\\/g, '\\\\').replace(/'/g, "\\'");
|
|
125
|
+
// Escape the user script for embedding inside a JS string template
|
|
126
|
+
const escapedScript = script.replace(/\\/g, '\\\\').replace(/`/g, '\\`').replace(/\$/g, '\\$');
|
|
127
|
+
const js = `
|
|
128
|
+
var frame = document.querySelector('${escapedSelector}');
|
|
129
|
+
if (!frame) throw Object.assign(new Error('Frame not found: ${escapedSelector}'), { name: 'ELEMENT_NOT_FOUND' });
|
|
130
|
+
if (frame.tagName !== 'IFRAME') throw new Error('Element is not an iframe: ${escapedSelector}');
|
|
131
|
+
|
|
132
|
+
var win = frame.contentWindow;
|
|
133
|
+
if (!win) throw new Error('Cannot access frame contentWindow (detached or sandboxed)');
|
|
134
|
+
|
|
135
|
+
var userScript = \`${escapedScript}\`;
|
|
136
|
+
var result;
|
|
137
|
+
try {
|
|
138
|
+
result = win.eval(userScript);
|
|
139
|
+
} catch (e) {
|
|
140
|
+
return { ok: false, error: e.message };
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
var serialized;
|
|
144
|
+
try {
|
|
145
|
+
serialized = JSON.stringify(result);
|
|
146
|
+
} catch (_) {
|
|
147
|
+
serialized = String(result);
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
return { ok: true, result: serialized !== undefined ? JSON.parse(serialized) : null };
|
|
151
|
+
`;
|
|
152
|
+
const result = await this.engine.executeJsInTab(tabUrl, js);
|
|
153
|
+
if (!result.ok)
|
|
154
|
+
throw new Error(result.error?.message ?? 'Frame eval failed');
|
|
155
|
+
return this.makeResponse(result.value ? JSON.parse(result.value) : { ok: false, error: 'No result' }, Date.now() - start);
|
|
156
|
+
}
|
|
157
|
+
// ── Private helpers ─────────────────────────────────────────────────────────
|
|
158
|
+
makeResponse(data, latencyMs = 0) {
|
|
159
|
+
return {
|
|
160
|
+
content: [{ type: 'text', text: JSON.stringify(data) }],
|
|
161
|
+
metadata: { engine: 'applescript', degraded: false, latencyMs },
|
|
162
|
+
};
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
//# sourceMappingURL=frames.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"frames.js","sourceRoot":"","sources":["../../src/tools/frames.ts"],"names":[],"mappings":"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"}
|