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,53 @@
|
|
|
1
|
+
import { BaseEngine } from './engine.js';
|
|
2
|
+
import type { Engine, EngineError, EngineResult } from '../types.js';
|
|
3
|
+
export declare class AppleScriptEngine extends BaseEngine {
|
|
4
|
+
readonly name: Engine;
|
|
5
|
+
isAvailable(): Promise<boolean>;
|
|
6
|
+
execute(script: string, timeout?: number): Promise<EngineResult>;
|
|
7
|
+
/** Execute a raw AppleScript string directly (for testing/internal use). */
|
|
8
|
+
executeRaw(script: string, timeout?: number): Promise<string>;
|
|
9
|
+
/**
|
|
10
|
+
* Build an AppleScript that targets a tab by URL and executes JS inside it.
|
|
11
|
+
*/
|
|
12
|
+
buildTabScript(url: string, jsCode: string): string;
|
|
13
|
+
/**
|
|
14
|
+
* Build an AppleScript that navigates to a URL (opens new document if needed).
|
|
15
|
+
*/
|
|
16
|
+
buildNavigateScript(url: string): string;
|
|
17
|
+
/**
|
|
18
|
+
* Build an AppleScript that opens a new tab (optionally in a private window).
|
|
19
|
+
*/
|
|
20
|
+
buildNewTabScript(url: string, privateWindow?: boolean): string;
|
|
21
|
+
/**
|
|
22
|
+
* Build an AppleScript that closes the tab matching a given URL.
|
|
23
|
+
*/
|
|
24
|
+
buildCloseTabScript(url: string): string;
|
|
25
|
+
/**
|
|
26
|
+
* Build an AppleScript that lists all open tabs across all windows.
|
|
27
|
+
*/
|
|
28
|
+
buildListTabsScript(): string;
|
|
29
|
+
/**
|
|
30
|
+
* Execute JavaScript in a tab identified by its current URL.
|
|
31
|
+
* Wraps the JS in a try/catch serialization harness so `return` works
|
|
32
|
+
* and results are properly JSON-serialized. Parses the wrapper on the
|
|
33
|
+
* way back so callers get the inner value directly.
|
|
34
|
+
*/
|
|
35
|
+
executeJsInTab(tabUrl: string, jsCode: string, timeout?: number): Promise<EngineResult>;
|
|
36
|
+
/**
|
|
37
|
+
* Wrap a JS snippet in a try/catch serialization harness.
|
|
38
|
+
* Returns a single-line string safe for embedding in AppleScript do JavaScript.
|
|
39
|
+
*/
|
|
40
|
+
wrapJavaScript(jsCode: string): string;
|
|
41
|
+
/**
|
|
42
|
+
* Parse the raw string returned by do JavaScript / osascript stdout.
|
|
43
|
+
* Handles JSON envelope, CSP/ShadowDOM signals, and bare string results.
|
|
44
|
+
*/
|
|
45
|
+
parseJsResult(raw: string): EngineResult;
|
|
46
|
+
/**
|
|
47
|
+
* Parse an AppleScript error from stderr or error message text.
|
|
48
|
+
* Extracts OSA error codes via regex.
|
|
49
|
+
*/
|
|
50
|
+
parseAppleScriptError(stderr: string): EngineError;
|
|
51
|
+
private classifyError;
|
|
52
|
+
private mapJsErrorName;
|
|
53
|
+
}
|
|
@@ -0,0 +1,290 @@
|
|
|
1
|
+
import { execFile } from 'node:child_process';
|
|
2
|
+
import { promisify } from 'node:util';
|
|
3
|
+
import { BaseEngine } from './engine.js';
|
|
4
|
+
const execFileAsync = promisify(execFile);
|
|
5
|
+
const MAX_BUFFER = 10 * 1024 * 1024; // 10 MB
|
|
6
|
+
const DEFAULT_TIMEOUT_MS = 30_000;
|
|
7
|
+
// AppleScript error codes from OSA and Safari
|
|
8
|
+
const AS_ERROR_CODES = {
|
|
9
|
+
[-600]: { code: 'SAFARI_NOT_RUNNING', retryable: true },
|
|
10
|
+
[-609]: { code: 'SAFARI_CRASHED', retryable: true },
|
|
11
|
+
[-1743]: { code: 'PERMISSION_DENIED', retryable: false },
|
|
12
|
+
[-1728]: { code: 'ELEMENT_NOT_FOUND', retryable: true },
|
|
13
|
+
};
|
|
14
|
+
export class AppleScriptEngine extends BaseEngine {
|
|
15
|
+
name = 'applescript';
|
|
16
|
+
async isAvailable() {
|
|
17
|
+
try {
|
|
18
|
+
await execFileAsync('osascript', ['-e', 'tell application "Safari" to return name'], {
|
|
19
|
+
timeout: 5000,
|
|
20
|
+
maxBuffer: MAX_BUFFER,
|
|
21
|
+
});
|
|
22
|
+
return true;
|
|
23
|
+
}
|
|
24
|
+
catch {
|
|
25
|
+
return false;
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
async execute(script, timeout = DEFAULT_TIMEOUT_MS) {
|
|
29
|
+
const start = Date.now();
|
|
30
|
+
try {
|
|
31
|
+
const { stdout } = await execFileAsync('osascript', ['-e', script], {
|
|
32
|
+
timeout,
|
|
33
|
+
maxBuffer: MAX_BUFFER,
|
|
34
|
+
});
|
|
35
|
+
const raw = stdout.trim();
|
|
36
|
+
const result = this.parseJsResult(raw);
|
|
37
|
+
return { ...result, elapsed_ms: Date.now() - start };
|
|
38
|
+
}
|
|
39
|
+
catch (err) {
|
|
40
|
+
const elapsed = Date.now() - start;
|
|
41
|
+
const engineError = this.classifyError(err);
|
|
42
|
+
return { ok: false, error: engineError, elapsed_ms: elapsed };
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
/** Execute a raw AppleScript string directly (for testing/internal use). */
|
|
46
|
+
async executeRaw(script, timeout = DEFAULT_TIMEOUT_MS) {
|
|
47
|
+
const { stdout } = await execFileAsync('osascript', ['-e', script], {
|
|
48
|
+
timeout,
|
|
49
|
+
maxBuffer: MAX_BUFFER,
|
|
50
|
+
});
|
|
51
|
+
return stdout.trim();
|
|
52
|
+
}
|
|
53
|
+
// ── Script builders ─────────────────────────────────────────────────────────
|
|
54
|
+
/**
|
|
55
|
+
* Build an AppleScript that targets a tab by URL and executes JS inside it.
|
|
56
|
+
*/
|
|
57
|
+
buildTabScript(url, jsCode) {
|
|
58
|
+
const escapedUrl = url.replace(/\\/g, '\\\\').replace(/"/g, '\\"');
|
|
59
|
+
const escapedJs = jsCode.replace(/\\/g, '\\\\').replace(/"/g, '\\"');
|
|
60
|
+
return `tell application "Safari"
|
|
61
|
+
set _result to ""
|
|
62
|
+
repeat with _window in every window
|
|
63
|
+
repeat with _tab in every tab of _window
|
|
64
|
+
if URL of _tab is "${escapedUrl}" then
|
|
65
|
+
set _result to do JavaScript "${escapedJs}" in _tab
|
|
66
|
+
return _result
|
|
67
|
+
end if
|
|
68
|
+
end repeat
|
|
69
|
+
end repeat
|
|
70
|
+
return _result
|
|
71
|
+
end tell`;
|
|
72
|
+
}
|
|
73
|
+
/**
|
|
74
|
+
* Build an AppleScript that navigates to a URL (opens new document if needed).
|
|
75
|
+
*/
|
|
76
|
+
buildNavigateScript(url) {
|
|
77
|
+
const escapedUrl = url.replace(/\\/g, '\\\\').replace(/"/g, '\\"');
|
|
78
|
+
return `tell application "Safari"
|
|
79
|
+
if (count of windows) is 0 then
|
|
80
|
+
make new document with properties {URL:"${escapedUrl}"}
|
|
81
|
+
else
|
|
82
|
+
set URL of current tab of front window to "${escapedUrl}"
|
|
83
|
+
end if
|
|
84
|
+
end tell`;
|
|
85
|
+
}
|
|
86
|
+
/**
|
|
87
|
+
* Build an AppleScript that opens a new tab (optionally in a private window).
|
|
88
|
+
*/
|
|
89
|
+
buildNewTabScript(url, privateWindow = false) {
|
|
90
|
+
const escapedUrl = url.replace(/\\/g, '\\\\').replace(/"/g, '\\"');
|
|
91
|
+
if (privateWindow) {
|
|
92
|
+
// Private windows require System Events menu click
|
|
93
|
+
return `tell application "Safari" to activate
|
|
94
|
+
tell application "System Events"
|
|
95
|
+
tell process "Safari"
|
|
96
|
+
click menu item "New Private Window" of menu "File" of menu bar 1
|
|
97
|
+
end tell
|
|
98
|
+
end tell
|
|
99
|
+
tell application "Safari"
|
|
100
|
+
set URL of current tab of front window to "${escapedUrl}"
|
|
101
|
+
end tell`;
|
|
102
|
+
}
|
|
103
|
+
return `tell application "Safari"
|
|
104
|
+
tell front window
|
|
105
|
+
set _tab to make new tab with properties {URL:"${escapedUrl}"}
|
|
106
|
+
set current tab to _tab
|
|
107
|
+
end tell
|
|
108
|
+
end tell`;
|
|
109
|
+
}
|
|
110
|
+
/**
|
|
111
|
+
* Build an AppleScript that closes the tab matching a given URL.
|
|
112
|
+
*/
|
|
113
|
+
buildCloseTabScript(url) {
|
|
114
|
+
const escapedUrl = url.replace(/\\/g, '\\\\').replace(/"/g, '\\"');
|
|
115
|
+
return `tell application "Safari"
|
|
116
|
+
repeat with _window in every window
|
|
117
|
+
repeat with _tab in every tab of _window
|
|
118
|
+
if URL of _tab is "${escapedUrl}" then
|
|
119
|
+
close _tab
|
|
120
|
+
return true
|
|
121
|
+
end if
|
|
122
|
+
end repeat
|
|
123
|
+
end repeat
|
|
124
|
+
return false
|
|
125
|
+
end tell`;
|
|
126
|
+
}
|
|
127
|
+
/**
|
|
128
|
+
* Build an AppleScript that lists all open tabs across all windows.
|
|
129
|
+
*/
|
|
130
|
+
buildListTabsScript() {
|
|
131
|
+
return `tell application "Safari"
|
|
132
|
+
set _output to ""
|
|
133
|
+
repeat with _window in every window
|
|
134
|
+
repeat with _tab in every tab of _window
|
|
135
|
+
set _output to _output & (URL of _tab) & "\\t" & (name of _tab) & "\\n"
|
|
136
|
+
end repeat
|
|
137
|
+
end repeat
|
|
138
|
+
return _output
|
|
139
|
+
end tell`;
|
|
140
|
+
}
|
|
141
|
+
/**
|
|
142
|
+
* Execute JavaScript in a tab identified by its current URL.
|
|
143
|
+
* Wraps the JS in a try/catch serialization harness so `return` works
|
|
144
|
+
* and results are properly JSON-serialized. Parses the wrapper on the
|
|
145
|
+
* way back so callers get the inner value directly.
|
|
146
|
+
*/
|
|
147
|
+
async executeJsInTab(tabUrl, jsCode, timeout) {
|
|
148
|
+
const wrapped = this.wrapJavaScript(jsCode);
|
|
149
|
+
const script = this.buildTabScript(tabUrl, wrapped);
|
|
150
|
+
const result = await this.execute(script, timeout);
|
|
151
|
+
// Parse the JSON wrapper from wrapJavaScript
|
|
152
|
+
if (result.ok && result.value) {
|
|
153
|
+
const parsed = this.parseJsResult(result.value);
|
|
154
|
+
return { ...parsed, elapsed_ms: result.elapsed_ms };
|
|
155
|
+
}
|
|
156
|
+
return result;
|
|
157
|
+
}
|
|
158
|
+
// ── JS wrapping & result parsing ────────────────────────────────────────────
|
|
159
|
+
/**
|
|
160
|
+
* Wrap a JS snippet in a try/catch serialization harness.
|
|
161
|
+
* Returns a single-line string safe for embedding in AppleScript do JavaScript.
|
|
162
|
+
*/
|
|
163
|
+
wrapJavaScript(jsCode) {
|
|
164
|
+
return `(function(){try{var __r=(function(){${jsCode}})();return JSON.stringify({ok:true,value:__r});}catch(e){return JSON.stringify({ok:false,error:{message:e.message,name:e.name}});}})()`;
|
|
165
|
+
}
|
|
166
|
+
/**
|
|
167
|
+
* Parse the raw string returned by do JavaScript / osascript stdout.
|
|
168
|
+
* Handles JSON envelope, CSP/ShadowDOM signals, and bare string results.
|
|
169
|
+
*/
|
|
170
|
+
parseJsResult(raw) {
|
|
171
|
+
const start = Date.now();
|
|
172
|
+
// Detect CSP-blocked execution (Safari returns empty or specific error text)
|
|
173
|
+
if (raw === '' ||
|
|
174
|
+
raw.toLowerCase().includes('content security policy') ||
|
|
175
|
+
raw.toLowerCase().includes('blocked by csp')) {
|
|
176
|
+
if (raw === '' || raw.toLowerCase().includes('content security policy') || raw.toLowerCase().includes('blocked by csp')) {
|
|
177
|
+
// Only classify empty as CSP_BLOCKED if it looks like a blocked signal,
|
|
178
|
+
// but for the harness we rely on the structured envelope. Bare empty = CSP.
|
|
179
|
+
if (raw.toLowerCase().includes('content security policy') || raw.toLowerCase().includes('blocked by csp')) {
|
|
180
|
+
return {
|
|
181
|
+
ok: false,
|
|
182
|
+
error: { code: 'CSP_BLOCKED', message: 'JavaScript execution blocked by Content Security Policy', retryable: false },
|
|
183
|
+
elapsed_ms: Date.now() - start,
|
|
184
|
+
};
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
// Detect shadow DOM closed signal
|
|
189
|
+
if (raw.toLowerCase().includes('shadow') && raw.toLowerCase().includes('closed')) {
|
|
190
|
+
return {
|
|
191
|
+
ok: false,
|
|
192
|
+
error: { code: 'SHADOW_DOM_CLOSED', message: 'Cannot access closed shadow root', retryable: false },
|
|
193
|
+
elapsed_ms: Date.now() - start,
|
|
194
|
+
};
|
|
195
|
+
}
|
|
196
|
+
// Try to parse JSON envelope
|
|
197
|
+
try {
|
|
198
|
+
const parsed = JSON.parse(raw);
|
|
199
|
+
if (typeof parsed === 'object' && parsed !== null && 'ok' in parsed) {
|
|
200
|
+
if (parsed.ok) {
|
|
201
|
+
const val = parsed.value;
|
|
202
|
+
return {
|
|
203
|
+
ok: true,
|
|
204
|
+
value: val === undefined || val === null
|
|
205
|
+
? undefined
|
|
206
|
+
: typeof val === 'string'
|
|
207
|
+
? val
|
|
208
|
+
: JSON.stringify(val),
|
|
209
|
+
elapsed_ms: Date.now() - start,
|
|
210
|
+
};
|
|
211
|
+
}
|
|
212
|
+
else {
|
|
213
|
+
const errName = parsed.error?.name ?? 'Error';
|
|
214
|
+
const errMsg = parsed.error?.message ?? 'Unknown error';
|
|
215
|
+
// Map known JS error names to engine codes
|
|
216
|
+
const code = this.mapJsErrorName(errName);
|
|
217
|
+
return {
|
|
218
|
+
ok: false,
|
|
219
|
+
error: { code, message: errMsg, retryable: false },
|
|
220
|
+
elapsed_ms: Date.now() - start,
|
|
221
|
+
};
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
catch {
|
|
226
|
+
// Not JSON — treat raw string as successful result
|
|
227
|
+
}
|
|
228
|
+
// Raw non-JSON string → treat as success value
|
|
229
|
+
return { ok: true, value: raw, elapsed_ms: Date.now() - start };
|
|
230
|
+
}
|
|
231
|
+
/**
|
|
232
|
+
* Parse an AppleScript error from stderr or error message text.
|
|
233
|
+
* Extracts OSA error codes via regex.
|
|
234
|
+
*/
|
|
235
|
+
parseAppleScriptError(stderr) {
|
|
236
|
+
// AppleScript errors embed the code in parens: "... (-600)"
|
|
237
|
+
const match = stderr.match(/\((-?\d+)\)/);
|
|
238
|
+
if (match) {
|
|
239
|
+
const code = parseInt(match[1], 10);
|
|
240
|
+
const known = AS_ERROR_CODES[code];
|
|
241
|
+
if (known) {
|
|
242
|
+
return {
|
|
243
|
+
code: known.code,
|
|
244
|
+
message: stderr.trim(),
|
|
245
|
+
retryable: known.retryable,
|
|
246
|
+
};
|
|
247
|
+
}
|
|
248
|
+
}
|
|
249
|
+
return {
|
|
250
|
+
code: 'APPLESCRIPT_ERROR',
|
|
251
|
+
message: stderr.trim() || 'Unknown AppleScript error',
|
|
252
|
+
retryable: false,
|
|
253
|
+
};
|
|
254
|
+
}
|
|
255
|
+
// ── Private helpers ─────────────────────────────────────────────────────────
|
|
256
|
+
classifyError(err) {
|
|
257
|
+
if (err && typeof err === 'object') {
|
|
258
|
+
const e = err;
|
|
259
|
+
// Timeout / killed process
|
|
260
|
+
if (e.killed === true || e.signal === 'SIGTERM' || e.signal === 'SIGKILL') {
|
|
261
|
+
return { code: 'TIMEOUT', message: 'osascript process timed out', retryable: true };
|
|
262
|
+
}
|
|
263
|
+
// stderr contains AppleScript error code
|
|
264
|
+
if (e.stderr && typeof e.stderr === 'string' && e.stderr.length > 0) {
|
|
265
|
+
return this.parseAppleScriptError(e.stderr);
|
|
266
|
+
}
|
|
267
|
+
// message may contain the error text
|
|
268
|
+
if (e.message && typeof e.message === 'string') {
|
|
269
|
+
const asMatch = e.message.match(/\((-?\d+)\)/);
|
|
270
|
+
if (asMatch) {
|
|
271
|
+
return this.parseAppleScriptError(e.message);
|
|
272
|
+
}
|
|
273
|
+
}
|
|
274
|
+
}
|
|
275
|
+
return {
|
|
276
|
+
code: 'UNKNOWN_ERROR',
|
|
277
|
+
message: err instanceof Error ? err.message : String(err),
|
|
278
|
+
retryable: false,
|
|
279
|
+
};
|
|
280
|
+
}
|
|
281
|
+
mapJsErrorName(name) {
|
|
282
|
+
switch (name) {
|
|
283
|
+
case 'SecurityError': return 'PERMISSION_DENIED';
|
|
284
|
+
case 'TypeError': return 'TYPE_ERROR';
|
|
285
|
+
case 'ReferenceError': return 'REFERENCE_ERROR';
|
|
286
|
+
default: return 'JS_ERROR';
|
|
287
|
+
}
|
|
288
|
+
}
|
|
289
|
+
}
|
|
290
|
+
//# sourceMappingURL=applescript.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"applescript.js","sourceRoot":"","sources":["../../src/engines/applescript.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { BaseEngine } from './engine.js';
|
|
2
|
+
import type { Engine, EngineResult } from '../types.js';
|
|
3
|
+
export declare class DaemonEngine extends BaseEngine {
|
|
4
|
+
readonly name: Engine;
|
|
5
|
+
private proc;
|
|
6
|
+
private pending;
|
|
7
|
+
private daemonPath;
|
|
8
|
+
private reconnectAttempted;
|
|
9
|
+
private shuttingDown;
|
|
10
|
+
constructor(daemonPath?: string);
|
|
11
|
+
isAvailable(): Promise<boolean>;
|
|
12
|
+
execute(script: string, timeout?: number): Promise<EngineResult>;
|
|
13
|
+
shutdown(): Promise<void>;
|
|
14
|
+
private ensureRunning;
|
|
15
|
+
private spawnDaemon;
|
|
16
|
+
private sendCommand;
|
|
17
|
+
private _dispatchResponse;
|
|
18
|
+
private _rejectAllPending;
|
|
19
|
+
}
|
|
@@ -0,0 +1,187 @@
|
|
|
1
|
+
import { spawn } from 'node:child_process';
|
|
2
|
+
import { BaseEngine } from './engine.js';
|
|
3
|
+
const DEFAULT_TIMEOUT_MS = 30_000;
|
|
4
|
+
let _idCounter = 0;
|
|
5
|
+
class DaemonTimeoutError extends Error {
|
|
6
|
+
constructor(method, timeout) {
|
|
7
|
+
super(`Daemon command "${method}" timed out after ${timeout}ms`);
|
|
8
|
+
this.name = 'DaemonTimeoutError';
|
|
9
|
+
}
|
|
10
|
+
}
|
|
11
|
+
function nextId() {
|
|
12
|
+
return `req-${Date.now()}-${++_idCounter}`;
|
|
13
|
+
}
|
|
14
|
+
export class DaemonEngine extends BaseEngine {
|
|
15
|
+
name = 'daemon';
|
|
16
|
+
proc = null;
|
|
17
|
+
pending = new Map();
|
|
18
|
+
daemonPath;
|
|
19
|
+
reconnectAttempted = false;
|
|
20
|
+
shuttingDown = false;
|
|
21
|
+
constructor(daemonPath) {
|
|
22
|
+
super();
|
|
23
|
+
this.daemonPath = daemonPath
|
|
24
|
+
?? process.env['SAFARI_PILOT_DAEMON']
|
|
25
|
+
?? './bin/SafariPilotd';
|
|
26
|
+
}
|
|
27
|
+
// ── Public interface ────────────────────────────────────────────────────────
|
|
28
|
+
async isAvailable() {
|
|
29
|
+
try {
|
|
30
|
+
await this.ensureRunning();
|
|
31
|
+
const response = await this.sendCommand('ping', {});
|
|
32
|
+
return response.ok === true && response.value === 'pong';
|
|
33
|
+
}
|
|
34
|
+
catch {
|
|
35
|
+
return false;
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
async execute(script, timeout = DEFAULT_TIMEOUT_MS) {
|
|
39
|
+
const start = Date.now();
|
|
40
|
+
try {
|
|
41
|
+
await this.ensureRunning();
|
|
42
|
+
const response = await this.sendCommand('execute', { script }, timeout);
|
|
43
|
+
if (response.ok) {
|
|
44
|
+
// Normalize: trim trailing whitespace (daemon may include trailing newline)
|
|
45
|
+
const value = response.value?.trimEnd();
|
|
46
|
+
return {
|
|
47
|
+
ok: true,
|
|
48
|
+
value,
|
|
49
|
+
elapsed_ms: Date.now() - start,
|
|
50
|
+
};
|
|
51
|
+
}
|
|
52
|
+
return {
|
|
53
|
+
ok: false,
|
|
54
|
+
error: {
|
|
55
|
+
code: response.error?.code ?? 'DAEMON_ERROR',
|
|
56
|
+
message: response.error?.message ?? 'Daemon returned an error',
|
|
57
|
+
retryable: true,
|
|
58
|
+
},
|
|
59
|
+
elapsed_ms: Date.now() - start,
|
|
60
|
+
};
|
|
61
|
+
}
|
|
62
|
+
catch (err) {
|
|
63
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
64
|
+
// DaemonTimeoutError is a tagged subclass so we can identify it precisely
|
|
65
|
+
const isTimeout = err instanceof DaemonTimeoutError;
|
|
66
|
+
return {
|
|
67
|
+
ok: false,
|
|
68
|
+
error: {
|
|
69
|
+
code: isTimeout ? 'TIMEOUT' : 'DAEMON_ERROR',
|
|
70
|
+
message: msg,
|
|
71
|
+
retryable: true,
|
|
72
|
+
},
|
|
73
|
+
elapsed_ms: Date.now() - start,
|
|
74
|
+
};
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
async shutdown() {
|
|
78
|
+
this.shuttingDown = true;
|
|
79
|
+
if (this.proc && !this.proc.killed) {
|
|
80
|
+
// Best-effort graceful shutdown command
|
|
81
|
+
try {
|
|
82
|
+
if (this.proc.stdin?.writable) {
|
|
83
|
+
this.proc.stdin.write(JSON.stringify({ method: 'shutdown' }) + '\n');
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
catch {
|
|
87
|
+
// ignore write errors during shutdown
|
|
88
|
+
}
|
|
89
|
+
this.proc.kill('SIGTERM');
|
|
90
|
+
}
|
|
91
|
+
this._rejectAllPending(new Error('DaemonEngine is shutting down'));
|
|
92
|
+
this.proc = null;
|
|
93
|
+
}
|
|
94
|
+
// ── Private: process lifecycle ───────────────────────────────────────────
|
|
95
|
+
async ensureRunning() {
|
|
96
|
+
if (this.proc && !this.proc.killed) {
|
|
97
|
+
return;
|
|
98
|
+
}
|
|
99
|
+
this.spawnDaemon();
|
|
100
|
+
}
|
|
101
|
+
spawnDaemon() {
|
|
102
|
+
const proc = spawn(this.daemonPath, [], {
|
|
103
|
+
stdio: ['pipe', 'pipe', 'pipe'],
|
|
104
|
+
});
|
|
105
|
+
this.proc = proc;
|
|
106
|
+
this.reconnectAttempted = false;
|
|
107
|
+
// Parse NDJSON lines from stdout using manual line buffering.
|
|
108
|
+
// Using raw `data` events (not readline) so the code works with both
|
|
109
|
+
// real Readable streams and the EventEmitter-based mocks used in tests.
|
|
110
|
+
let lineBuffer = '';
|
|
111
|
+
proc.stdout.on('data', (chunk) => {
|
|
112
|
+
lineBuffer += typeof chunk === 'string' ? chunk : chunk.toString('utf8');
|
|
113
|
+
let newlineIdx;
|
|
114
|
+
while ((newlineIdx = lineBuffer.indexOf('\n')) !== -1) {
|
|
115
|
+
const line = lineBuffer.slice(0, newlineIdx).trim();
|
|
116
|
+
lineBuffer = lineBuffer.slice(newlineIdx + 1);
|
|
117
|
+
if (!line)
|
|
118
|
+
continue;
|
|
119
|
+
try {
|
|
120
|
+
const msg = JSON.parse(line);
|
|
121
|
+
this._dispatchResponse(msg);
|
|
122
|
+
}
|
|
123
|
+
catch {
|
|
124
|
+
// Malformed JSON line — ignore
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
});
|
|
128
|
+
// Handle process exit: reject all pending requests
|
|
129
|
+
proc.on('exit', (code, signal) => {
|
|
130
|
+
if (this.shuttingDown)
|
|
131
|
+
return;
|
|
132
|
+
const reason = `Daemon exited with code=${code ?? 'null'} signal=${signal ?? 'none'}`;
|
|
133
|
+
this._rejectAllPending(new Error(reason));
|
|
134
|
+
// Auto-reconnect once
|
|
135
|
+
if (!this.reconnectAttempted) {
|
|
136
|
+
this.reconnectAttempted = true;
|
|
137
|
+
this.proc = null;
|
|
138
|
+
// Don't auto-spawn here — let the next ensureRunning() call do it
|
|
139
|
+
// to avoid infinite respawn loops
|
|
140
|
+
}
|
|
141
|
+
else {
|
|
142
|
+
this.proc = null;
|
|
143
|
+
}
|
|
144
|
+
});
|
|
145
|
+
proc.on('error', (err) => {
|
|
146
|
+
this._rejectAllPending(err);
|
|
147
|
+
this.proc = null;
|
|
148
|
+
});
|
|
149
|
+
}
|
|
150
|
+
// ── Private: request/response ────────────────────────────────────────────
|
|
151
|
+
sendCommand(method, params, timeout = DEFAULT_TIMEOUT_MS) {
|
|
152
|
+
const id = nextId();
|
|
153
|
+
const payload = JSON.stringify({ id, method, params }) + '\n';
|
|
154
|
+
return new Promise((resolve, reject) => {
|
|
155
|
+
const timer = setTimeout(() => {
|
|
156
|
+
this.pending.delete(id);
|
|
157
|
+
reject(new DaemonTimeoutError(method, timeout));
|
|
158
|
+
}, timeout);
|
|
159
|
+
this.pending.set(id, { resolve, reject, timer });
|
|
160
|
+
if (!this.proc || !this.proc.stdin?.writable) {
|
|
161
|
+
clearTimeout(timer);
|
|
162
|
+
this.pending.delete(id);
|
|
163
|
+
reject(new Error('Daemon process is not running or stdin is closed'));
|
|
164
|
+
return;
|
|
165
|
+
}
|
|
166
|
+
this.proc.stdin.write(payload);
|
|
167
|
+
});
|
|
168
|
+
}
|
|
169
|
+
_dispatchResponse(msg) {
|
|
170
|
+
if (!msg.id)
|
|
171
|
+
return;
|
|
172
|
+
const pending = this.pending.get(msg.id);
|
|
173
|
+
if (!pending)
|
|
174
|
+
return;
|
|
175
|
+
clearTimeout(pending.timer);
|
|
176
|
+
this.pending.delete(msg.id);
|
|
177
|
+
pending.resolve(msg);
|
|
178
|
+
}
|
|
179
|
+
_rejectAllPending(reason) {
|
|
180
|
+
for (const [id, req] of this.pending) {
|
|
181
|
+
clearTimeout(req.timer);
|
|
182
|
+
req.reject(reason);
|
|
183
|
+
this.pending.delete(id);
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
//# sourceMappingURL=daemon.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"daemon.js","sourceRoot":"","sources":["../../src/engines/daemon.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import type { Engine, EngineResult } from '../types.js';
|
|
2
|
+
export interface IEngine {
|
|
3
|
+
readonly name: Engine;
|
|
4
|
+
isAvailable(): Promise<boolean>;
|
|
5
|
+
execute(script: string, timeout?: number): Promise<EngineResult>;
|
|
6
|
+
shutdown(): Promise<void>;
|
|
7
|
+
}
|
|
8
|
+
export declare abstract class BaseEngine implements IEngine {
|
|
9
|
+
abstract readonly name: Engine;
|
|
10
|
+
abstract isAvailable(): Promise<boolean>;
|
|
11
|
+
abstract execute(script: string, timeout?: number): Promise<EngineResult>;
|
|
12
|
+
shutdown(): Promise<void>;
|
|
13
|
+
protected wrapScript(jsCode: string): string;
|
|
14
|
+
protected parseResult(raw: string): EngineResult;
|
|
15
|
+
}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
export class BaseEngine {
|
|
2
|
+
async shutdown() { }
|
|
3
|
+
wrapScript(jsCode) {
|
|
4
|
+
return `(() => {
|
|
5
|
+
try {
|
|
6
|
+
const __result = (() => { ${jsCode} })();
|
|
7
|
+
return JSON.stringify({ ok: true, value: __result });
|
|
8
|
+
} catch (e) {
|
|
9
|
+
return JSON.stringify({
|
|
10
|
+
ok: false,
|
|
11
|
+
error: { message: e.message, name: e.name, stack: e.stack }
|
|
12
|
+
});
|
|
13
|
+
}
|
|
14
|
+
})()`;
|
|
15
|
+
}
|
|
16
|
+
parseResult(raw) {
|
|
17
|
+
const start = Date.now();
|
|
18
|
+
try {
|
|
19
|
+
const parsed = JSON.parse(raw);
|
|
20
|
+
return {
|
|
21
|
+
ok: parsed.ok,
|
|
22
|
+
value: parsed.ok
|
|
23
|
+
? typeof parsed.value === 'string'
|
|
24
|
+
? parsed.value
|
|
25
|
+
: JSON.stringify(parsed.value)
|
|
26
|
+
: undefined,
|
|
27
|
+
error: parsed.ok
|
|
28
|
+
? undefined
|
|
29
|
+
: {
|
|
30
|
+
code: parsed.error?.name || 'INTERNAL_ERROR',
|
|
31
|
+
message: parsed.error?.message || 'Unknown error',
|
|
32
|
+
retryable: false,
|
|
33
|
+
},
|
|
34
|
+
elapsed_ms: Date.now() - start,
|
|
35
|
+
};
|
|
36
|
+
}
|
|
37
|
+
catch {
|
|
38
|
+
return { ok: true, value: raw, elapsed_ms: Date.now() - start };
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
//# sourceMappingURL=engine.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"engine.js","sourceRoot":"","sources":["../../src/engines/engine.ts"],"names":[],"mappings":"AASA,MAAM,OAAgB,UAAU;IAK9B,KAAK,CAAC,QAAQ,KAAmB,CAAC;IAExB,UAAU,CAAC,MAAc;QACjC,OAAO;;gCAEqB,MAAM;;;;;;;;KAQjC,CAAC;IACJ,CAAC;IAES,WAAW,CAAC,GAAW;QAC/B,MAAM,KAAK,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;QACzB,IAAI,CAAC;YACH,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;YAC/B,OAAO;gBACL,EAAE,EAAE,MAAM,CAAC,EAAE;gBACb,KAAK,EAAE,MAAM,CAAC,EAAE;oBACd,CAAC,CAAC,OAAO,MAAM,CAAC,KAAK,KAAK,QAAQ;wBAChC,CAAC,CAAC,MAAM,CAAC,KAAK;wBACd,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,KAAK,CAAC;oBAChC,CAAC,CAAC,SAAS;gBACb,KAAK,EAAE,MAAM,CAAC,EAAE;oBACd,CAAC,CAAC,SAAS;oBACX,CAAC,CAAC;wBACE,IAAI,EAAE,MAAM,CAAC,KAAK,EAAE,IAAI,IAAI,gBAAgB;wBAC5C,OAAO,EAAE,MAAM,CAAC,KAAK,EAAE,OAAO,IAAI,eAAe;wBACjD,SAAS,EAAE,KAAK;qBACjB;gBACL,UAAU,EAAE,IAAI,CAAC,GAAG,EAAE,GAAG,KAAK;aAC/B,CAAC;QACJ,CAAC;QAAC,MAAM,CAAC;YACP,OAAO,EAAE,EAAE,EAAE,IAAI,EAAE,KAAK,EAAE,GAAG,EAAE,UAAU,EAAE,IAAI,CAAC,GAAG,EAAE,GAAG,KAAK,EAAE,CAAC;QAClE,CAAC;IACH,CAAC;CACF"}
|