safari-pilot 0.1.28 → 0.1.29
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/bin/Safari Pilot.app/Contents/CodeResources +0 -0
- package/bin/Safari Pilot.app/Contents/Info.plist +2 -2
- package/bin/Safari Pilot.app/Contents/MacOS/Safari Pilot +0 -0
- package/bin/Safari Pilot.app/Contents/PlugIns/Safari Pilot Extension.appex/Contents/Info.plist +2 -2
- 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/manifest.json +19 -7
- package/bin/Safari Pilot.app/Contents/PlugIns/Safari Pilot Extension.appex/Contents/_CodeSignature/CodeResources +2 -2
- package/bin/Safari Pilot.app/Contents/Resources/Base.lproj/Main.storyboardc/Info.plist +0 -0
- package/bin/Safari Pilot.app/Contents/Resources/Base.lproj/Main.storyboardc/MainMenu.nib +0 -0
- package/bin/Safari Pilot.app/Contents/Resources/Base.lproj/Main.storyboardc/NSWindowController-B8D-0N-5wS.nib +0 -0
- package/bin/Safari Pilot.app/Contents/_CodeSignature/CodeResources +7 -7
- package/bin/Safari Pilot.zip +0 -0
- package/bin/SafariPilotd +0 -0
- package/dist/discovery/recipe-miner.d.ts +13 -0
- package/dist/discovery/recipe-miner.js +71 -0
- package/dist/discovery/recipe-miner.js.map +1 -0
- package/dist/discovery/tool-index.d.ts +18 -0
- package/dist/discovery/tool-index.js +52 -0
- package/dist/discovery/tool-index.js.map +1 -0
- package/dist/security/human-approval.d.ts +7 -0
- package/dist/security/human-approval.js +6 -0
- package/dist/security/human-approval.js.map +1 -1
- package/dist/server.d.ts +13 -0
- package/dist/server.js +91 -1
- package/dist/server.js.map +1 -1
- package/dist/skills/registry.d.ts +22 -0
- package/dist/skills/registry.js +69 -0
- package/dist/skills/registry.js.map +1 -0
- package/dist/skills/runner.d.ts +11 -0
- package/dist/skills/runner.js +72 -0
- package/dist/skills/runner.js.map +1 -0
- package/dist/tools/compound.js +1 -3
- package/dist/tools/compound.js.map +1 -1
- package/dist/tools/downloads.js +1 -9
- package/dist/tools/downloads.js.map +1 -1
- package/dist/tools/extraction.js +13 -17
- package/dist/tools/extraction.js.map +1 -1
- package/dist/tools/frames.js +2 -6
- package/dist/tools/frames.js.map +1 -1
- package/dist/tools/interaction.js +18 -32
- package/dist/tools/interaction.js.map +1 -1
- package/dist/tools/navigation.js +16 -12
- package/dist/tools/navigation.js.map +1 -1
- package/dist/tools/network.js +7 -24
- package/dist/tools/network.js.map +1 -1
- package/dist/tools/selector-pack.js +2 -4
- package/dist/tools/selector-pack.js.map +1 -1
- package/dist/tools/shadow.js +2 -4
- package/dist/tools/shadow.js.map +1 -1
- package/dist/tools/skills.d.ts +20 -0
- package/dist/tools/skills.js +71 -0
- package/dist/tools/skills.js.map +1 -0
- package/dist/tools/storage.js +9 -24
- package/dist/tools/storage.js.map +1 -1
- package/dist/tools/structured-extraction.js +5 -13
- package/dist/tools/structured-extraction.js.map +1 -1
- package/dist/tools/tool-search.d.ts +20 -0
- package/dist/tools/tool-search.js +54 -0
- package/dist/tools/tool-search.js.map +1 -0
- package/dist/tools/wait.js +3 -3
- package/dist/tools/wait.js.map +1 -1
- package/dist/types.d.ts +9 -0
- package/extension/manifest.json +19 -7
- package/package.json +8 -4
- package/skills/login.SKILL.md +27 -0
- package/skills/paginate-and-scrape.SKILL.md +21 -0
- package/skills/robust-form-fill.SKILL.md +22 -0
|
Binary file
|
|
@@ -23,13 +23,13 @@
|
|
|
23
23
|
<key>CFBundlePackageType</key>
|
|
24
24
|
<string>APPL</string>
|
|
25
25
|
<key>CFBundleShortVersionString</key>
|
|
26
|
-
<string>0.1.
|
|
26
|
+
<string>0.1.29</string>
|
|
27
27
|
<key>CFBundleSupportedPlatforms</key>
|
|
28
28
|
<array>
|
|
29
29
|
<string>MacOSX</string>
|
|
30
30
|
</array>
|
|
31
31
|
<key>CFBundleVersion</key>
|
|
32
|
-
<string>
|
|
32
|
+
<string>202605060230</string>
|
|
33
33
|
<key>DTCompiler</key>
|
|
34
34
|
<string>com.apple.compilers.llvm.clang.1_0</string>
|
|
35
35
|
<key>DTPlatformBuild</key>
|
|
Binary file
|
package/bin/Safari Pilot.app/Contents/PlugIns/Safari Pilot Extension.appex/Contents/Info.plist
CHANGED
|
@@ -19,13 +19,13 @@
|
|
|
19
19
|
<key>CFBundlePackageType</key>
|
|
20
20
|
<string>XPC!</string>
|
|
21
21
|
<key>CFBundleShortVersionString</key>
|
|
22
|
-
<string>0.1.
|
|
22
|
+
<string>0.1.29</string>
|
|
23
23
|
<key>CFBundleSupportedPlatforms</key>
|
|
24
24
|
<array>
|
|
25
25
|
<string>MacOSX</string>
|
|
26
26
|
</array>
|
|
27
27
|
<key>CFBundleVersion</key>
|
|
28
|
-
<string>
|
|
28
|
+
<string>202605060230</string>
|
|
29
29
|
<key>DTCompiler</key>
|
|
30
30
|
<string>com.apple.compilers.llvm.clang.1_0</string>
|
|
31
31
|
<key>DTPlatformBuild</key>
|
|
Binary file
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"manifest_version": 3,
|
|
3
3
|
"name": "Safari Pilot",
|
|
4
|
-
"version": "0.1.
|
|
4
|
+
"version": "0.1.29",
|
|
5
5
|
"description": "Native Safari automation for AI agents",
|
|
6
6
|
"permissions": [
|
|
7
7
|
"activeTab",
|
|
@@ -18,22 +18,34 @@
|
|
|
18
18
|
"content_security_policy": {
|
|
19
19
|
"extension_pages": "script-src 'self'; connect-src 'self' http://localhost:19475 http://127.0.0.1:19475"
|
|
20
20
|
},
|
|
21
|
-
"host_permissions": [
|
|
21
|
+
"host_permissions": [
|
|
22
|
+
"<all_urls>"
|
|
23
|
+
],
|
|
22
24
|
"background": {
|
|
23
|
-
"scripts": [
|
|
25
|
+
"scripts": [
|
|
26
|
+
"background.js"
|
|
27
|
+
],
|
|
24
28
|
"persistent": false
|
|
25
29
|
},
|
|
26
30
|
"content_scripts": [
|
|
27
31
|
{
|
|
28
|
-
"matches": [
|
|
29
|
-
|
|
32
|
+
"matches": [
|
|
33
|
+
"<all_urls>"
|
|
34
|
+
],
|
|
35
|
+
"js": [
|
|
36
|
+
"content-isolated.js"
|
|
37
|
+
],
|
|
30
38
|
"run_at": "document_idle",
|
|
31
39
|
"world": "ISOLATED",
|
|
32
40
|
"all_frames": true
|
|
33
41
|
},
|
|
34
42
|
{
|
|
35
|
-
"matches": [
|
|
36
|
-
|
|
43
|
+
"matches": [
|
|
44
|
+
"<all_urls>"
|
|
45
|
+
],
|
|
46
|
+
"js": [
|
|
47
|
+
"content-main.js"
|
|
48
|
+
],
|
|
37
49
|
"run_at": "document_idle",
|
|
38
50
|
"world": "MAIN",
|
|
39
51
|
"all_frames": true
|
|
@@ -46,7 +46,7 @@
|
|
|
46
46
|
</data>
|
|
47
47
|
<key>Resources/manifest.json</key>
|
|
48
48
|
<data>
|
|
49
|
-
|
|
49
|
+
+aLtOWURQx+rJpvnmelFssvw6sY=
|
|
50
50
|
</data>
|
|
51
51
|
<key>Resources/native/SafariWebExtensionHandler.swift</key>
|
|
52
52
|
<data>
|
|
@@ -129,7 +129,7 @@
|
|
|
129
129
|
<dict>
|
|
130
130
|
<key>hash2</key>
|
|
131
131
|
<data>
|
|
132
|
-
|
|
132
|
+
mrfYAmMwhQqkNTyZU2dzeThoyxd2hZYHwPgFKaNKpxE=
|
|
133
133
|
</data>
|
|
134
134
|
</dict>
|
|
135
135
|
<key>Resources/native/SafariWebExtensionHandler.swift</key>
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
@@ -18,15 +18,15 @@
|
|
|
18
18
|
</data>
|
|
19
19
|
<key>Resources/Base.lproj/Main.storyboardc/Info.plist</key>
|
|
20
20
|
<data>
|
|
21
|
-
|
|
21
|
+
E7+ia1hClIvypqZ7fpu0ykYY1Jo=
|
|
22
22
|
</data>
|
|
23
23
|
<key>Resources/Base.lproj/Main.storyboardc/MainMenu.nib</key>
|
|
24
24
|
<data>
|
|
25
|
-
|
|
25
|
+
ZNKXFL6TEBryOVVZLjtCzviNbTU=
|
|
26
26
|
</data>
|
|
27
27
|
<key>Resources/Base.lproj/Main.storyboardc/NSWindowController-B8D-0N-5wS.nib</key>
|
|
28
28
|
<data>
|
|
29
|
-
|
|
29
|
+
B+v01Kjcwm0FLJsbuBG9NZchRD0=
|
|
30
30
|
</data>
|
|
31
31
|
<key>Resources/Base.lproj/Main.storyboardc/XfG-lQ-9wD-view-m2S-Jp-Qdl.nib</key>
|
|
32
32
|
<data>
|
|
@@ -51,7 +51,7 @@
|
|
|
51
51
|
<dict>
|
|
52
52
|
<key>cdhash</key>
|
|
53
53
|
<data>
|
|
54
|
-
|
|
54
|
+
NpksfTnkkjY5muDgSJktoSnJnSo=
|
|
55
55
|
</data>
|
|
56
56
|
<key>requirement</key>
|
|
57
57
|
<string>anchor apple generic and identifier "com.safari-pilot.app.Extension" and (certificate leaf[field.1.2.840.113635.100.6.1.9] /* exists */ or certificate 1[field.1.2.840.113635.100.6.2.6] /* exists */ and certificate leaf[field.1.2.840.113635.100.6.1.13] /* exists */ and certificate leaf[subject.OU] = V37WLKRXUJ)</string>
|
|
@@ -81,21 +81,21 @@
|
|
|
81
81
|
<dict>
|
|
82
82
|
<key>hash2</key>
|
|
83
83
|
<data>
|
|
84
|
-
|
|
84
|
+
ofN6kk0Yg0dmJF0e6J3yaZ0HWcwDs9vk3OVOSaapviI=
|
|
85
85
|
</data>
|
|
86
86
|
</dict>
|
|
87
87
|
<key>Resources/Base.lproj/Main.storyboardc/MainMenu.nib</key>
|
|
88
88
|
<dict>
|
|
89
89
|
<key>hash2</key>
|
|
90
90
|
<data>
|
|
91
|
-
|
|
91
|
+
JutHRKOObLSCTpKJVIiQRRyzEBJKgzdTdsbgK218f2M=
|
|
92
92
|
</data>
|
|
93
93
|
</dict>
|
|
94
94
|
<key>Resources/Base.lproj/Main.storyboardc/NSWindowController-B8D-0N-5wS.nib</key>
|
|
95
95
|
<dict>
|
|
96
96
|
<key>hash2</key>
|
|
97
97
|
<data>
|
|
98
|
-
|
|
98
|
+
ZQQSp+jq0L/MX6J66senkEoiNwFY6A1DMHS63B664YA=
|
|
99
99
|
</data>
|
|
100
100
|
</dict>
|
|
101
101
|
<key>Resources/Base.lproj/Main.storyboardc/XfG-lQ-9wD-view-m2S-Jp-Qdl.nib</key>
|
package/bin/Safari Pilot.zip
CHANGED
|
Binary file
|
package/bin/SafariPilotd
CHANGED
|
Binary file
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
export interface MineOptions {
|
|
2
|
+
minOccurrences: number;
|
|
3
|
+
minLength: number;
|
|
4
|
+
}
|
|
5
|
+
export interface RecipeCandidate {
|
|
6
|
+
host: string;
|
|
7
|
+
steps: Array<{
|
|
8
|
+
tool: string;
|
|
9
|
+
argSignature: string;
|
|
10
|
+
}>;
|
|
11
|
+
occurrences: number;
|
|
12
|
+
}
|
|
13
|
+
export declare function mineRecipes(rootDir: string, opts: MineOptions): Promise<RecipeCandidate[]>;
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
// src/discovery/recipe-miner.ts
|
|
2
|
+
// Port of Browser Use's browser-harness pattern: read execution traces,
|
|
3
|
+
// extract recurring successful tool sequences, emit candidate skills.
|
|
4
|
+
import { readdir, readFile } from 'node:fs/promises';
|
|
5
|
+
import { stat } from 'node:fs/promises';
|
|
6
|
+
import { join } from 'node:path';
|
|
7
|
+
export async function mineRecipes(rootDir, opts) {
|
|
8
|
+
const traces = await collectTraces(rootDir);
|
|
9
|
+
const counts = new Map();
|
|
10
|
+
for (const trace of traces) {
|
|
11
|
+
if (trace.steps.length < opts.minLength)
|
|
12
|
+
continue;
|
|
13
|
+
const key = trace.host + '|' + trace.steps.map((s) => `${s.tool}:${s.argSignature}`).join('>');
|
|
14
|
+
const existing = counts.get(key);
|
|
15
|
+
if (existing)
|
|
16
|
+
existing.occurrences++;
|
|
17
|
+
else
|
|
18
|
+
counts.set(key, { host: trace.host, steps: trace.steps, occurrences: 1 });
|
|
19
|
+
}
|
|
20
|
+
return [...counts.values()].filter((c) => c.occurrences >= opts.minOccurrences);
|
|
21
|
+
}
|
|
22
|
+
async function collectTraces(root) {
|
|
23
|
+
const out = [];
|
|
24
|
+
let entries;
|
|
25
|
+
try {
|
|
26
|
+
entries = await readdir(root);
|
|
27
|
+
}
|
|
28
|
+
catch {
|
|
29
|
+
return out;
|
|
30
|
+
}
|
|
31
|
+
for (const e of entries) {
|
|
32
|
+
const p = join(root, e);
|
|
33
|
+
const s = await stat(p).catch(() => null);
|
|
34
|
+
if (!s || !s.isDirectory())
|
|
35
|
+
continue;
|
|
36
|
+
try {
|
|
37
|
+
const score = JSON.parse(await readFile(join(p, 'score.json'), 'utf8'));
|
|
38
|
+
if (!score['success'])
|
|
39
|
+
continue;
|
|
40
|
+
const traceText = await readFile(join(p, 'tool-calls.jsonl'), 'utf8');
|
|
41
|
+
const steps = traceText
|
|
42
|
+
.split('\n')
|
|
43
|
+
.filter(Boolean)
|
|
44
|
+
.map((line) => {
|
|
45
|
+
const entry = JSON.parse(line);
|
|
46
|
+
return {
|
|
47
|
+
tool: String(entry.tool),
|
|
48
|
+
argSignature: signature(entry.args),
|
|
49
|
+
};
|
|
50
|
+
});
|
|
51
|
+
const host = inferHost(traceText);
|
|
52
|
+
out.push({ host, steps });
|
|
53
|
+
}
|
|
54
|
+
catch {
|
|
55
|
+
/* skip incomplete run dirs */
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
return out;
|
|
59
|
+
}
|
|
60
|
+
function signature(args) {
|
|
61
|
+
if (!args || typeof args !== 'object')
|
|
62
|
+
return '';
|
|
63
|
+
return Object.keys(args)
|
|
64
|
+
.sort()
|
|
65
|
+
.join(',');
|
|
66
|
+
}
|
|
67
|
+
function inferHost(trace) {
|
|
68
|
+
const m = trace.match(/"url"\s*:\s*"https?:\/\/([^/"]+)/);
|
|
69
|
+
return m?.[1] ?? 'unknown';
|
|
70
|
+
}
|
|
71
|
+
//# sourceMappingURL=recipe-miner.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"recipe-miner.js","sourceRoot":"","sources":["../../src/discovery/recipe-miner.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
export interface ToolEntry {
|
|
2
|
+
name: string;
|
|
3
|
+
description: string;
|
|
4
|
+
tags?: string[];
|
|
5
|
+
}
|
|
6
|
+
export interface ToolHit extends ToolEntry {
|
|
7
|
+
score: number;
|
|
8
|
+
}
|
|
9
|
+
export declare class ToolIndex {
|
|
10
|
+
private entries;
|
|
11
|
+
constructor(entries: ToolEntry[]);
|
|
12
|
+
size(): number;
|
|
13
|
+
tagsFor(name: string): string[];
|
|
14
|
+
search(query: string, topK?: number): ToolHit[];
|
|
15
|
+
private inferTags;
|
|
16
|
+
private tokenize;
|
|
17
|
+
private score;
|
|
18
|
+
}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
// src/discovery/tool-index.ts
|
|
2
|
+
// In-memory tool index for safari_tool_search meta-tool.
|
|
3
|
+
// Keyword overlap scoring with name + tag boost.
|
|
4
|
+
export class ToolIndex {
|
|
5
|
+
entries;
|
|
6
|
+
constructor(entries) {
|
|
7
|
+
this.entries = entries.map((e) => ({
|
|
8
|
+
...e,
|
|
9
|
+
tags: e.tags ?? this.inferTags(e.name),
|
|
10
|
+
}));
|
|
11
|
+
}
|
|
12
|
+
size() {
|
|
13
|
+
return this.entries.length;
|
|
14
|
+
}
|
|
15
|
+
tagsFor(name) {
|
|
16
|
+
return this.entries.find((e) => e.name === name)?.tags ?? [];
|
|
17
|
+
}
|
|
18
|
+
search(query, topK = 8) {
|
|
19
|
+
const tokens = this.tokenize(query);
|
|
20
|
+
if (tokens.length === 0)
|
|
21
|
+
return [];
|
|
22
|
+
const scored = this.entries
|
|
23
|
+
.map((e) => ({ ...e, score: this.score(tokens, e) }))
|
|
24
|
+
.filter((h) => h.score > 0);
|
|
25
|
+
scored.sort((a, b) => b.score - a.score);
|
|
26
|
+
return scored.slice(0, topK);
|
|
27
|
+
}
|
|
28
|
+
inferTags(name) {
|
|
29
|
+
const parts = name.replace(/^safari_/, '').split('_');
|
|
30
|
+
return parts[0] ? [parts[0]] : [];
|
|
31
|
+
}
|
|
32
|
+
tokenize(s) {
|
|
33
|
+
return s
|
|
34
|
+
.toLowerCase()
|
|
35
|
+
.split(/[^a-z0-9]+/)
|
|
36
|
+
.filter((t) => t.length > 1);
|
|
37
|
+
}
|
|
38
|
+
score(queryTokens, e) {
|
|
39
|
+
const haystack = (e.name + ' ' + e.description + ' ' + (e.tags ?? []).join(' ')).toLowerCase();
|
|
40
|
+
let s = 0;
|
|
41
|
+
for (const t of queryTokens) {
|
|
42
|
+
if (haystack.includes(t))
|
|
43
|
+
s += 1;
|
|
44
|
+
if (e.name.toLowerCase().includes(t))
|
|
45
|
+
s += 1; // boost name match
|
|
46
|
+
if (e.tags?.includes(t))
|
|
47
|
+
s += 0.5;
|
|
48
|
+
}
|
|
49
|
+
return s;
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
//# sourceMappingURL=tool-index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tool-index.js","sourceRoot":"","sources":["../../src/discovery/tool-index.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,3 +1,10 @@
|
|
|
1
|
+
/** Cluster G — suggested_next_tools emitted on every HumanApproval denial.
|
|
2
|
+
* Exported so server.ts can attach it to both denial return paths without
|
|
3
|
+
* duplicating the hint text. */
|
|
4
|
+
export declare const HUMAN_APPROVAL_SUGGESTED_NEXT_TOOLS: Array<{
|
|
5
|
+
tool: string;
|
|
6
|
+
reason: string;
|
|
7
|
+
}>;
|
|
1
8
|
export interface ApprovalResult {
|
|
2
9
|
required: boolean;
|
|
3
10
|
reason?: string;
|
|
@@ -1,4 +1,10 @@
|
|
|
1
1
|
import { HumanApprovalRequiredError } from '../errors.js';
|
|
2
|
+
/** Cluster G — suggested_next_tools emitted on every HumanApproval denial.
|
|
3
|
+
* Exported so server.ts can attach it to both denial return paths without
|
|
4
|
+
* duplicating the hint text. */
|
|
5
|
+
export const HUMAN_APPROVAL_SUGGESTED_NEXT_TOOLS = [
|
|
6
|
+
{ tool: 'safari_evaluate', reason: 'Equivalent path that runs through the JS-eval engine (still security-gated).' },
|
|
7
|
+
];
|
|
2
8
|
// ─── Pattern Registry ─────────────────────────────────────────────────────────
|
|
3
9
|
/** OAuth / SSO provider URL patterns. */
|
|
4
10
|
const OAUTH_URL_PATTERNS = [
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"human-approval.js","sourceRoot":"","sources":["../../src/security/human-approval.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,0BAA0B,EAAE,MAAM,cAAc,CAAC;
|
|
1
|
+
{"version":3,"file":"human-approval.js","sourceRoot":"","sources":["../../src/security/human-approval.ts"],"names":[],"mappings":"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"}
|
package/dist/server.d.ts
CHANGED
|
@@ -66,6 +66,19 @@ export declare class SafariPilotServer {
|
|
|
66
66
|
* Returns undefined before the first successful `ensureSessionWindow`.
|
|
67
67
|
*/
|
|
68
68
|
getSessionWindowId(): number | undefined;
|
|
69
|
+
/**
|
|
70
|
+
* Return all tool definitions (name, description, inputSchema, requirements)
|
|
71
|
+
* without requiring `initialize()` to have been called.
|
|
72
|
+
*
|
|
73
|
+
* Uses I/O-free engine instances to satisfy tool module constructors;
|
|
74
|
+
* only `getDefinitions()` is called — no engine I/O occurs.
|
|
75
|
+
*/
|
|
76
|
+
listToolDefinitions(): Array<{
|
|
77
|
+
name: string;
|
|
78
|
+
description: string;
|
|
79
|
+
inputSchema: Record<string, unknown>;
|
|
80
|
+
requirements: ToolRequirements;
|
|
81
|
+
}>;
|
|
69
82
|
private get sessionTabUrl();
|
|
70
83
|
constructor(config?: SafariPilotConfig);
|
|
71
84
|
initialize(): Promise<void>;
|
package/dist/server.js
CHANGED
|
@@ -25,6 +25,10 @@ import { DownloadTools } from './tools/downloads.js';
|
|
|
25
25
|
import { PdfTools } from './tools/pdf.js';
|
|
26
26
|
import { ExtensionDiagnosticsTools } from './tools/extension-diagnostics.js';
|
|
27
27
|
import { FileUploadTools } from './tools/file-upload.js';
|
|
28
|
+
import { ToolIndex } from './discovery/tool-index.js';
|
|
29
|
+
import { ToolSearchTools } from './tools/tool-search.js';
|
|
30
|
+
import { SkillRegistry } from './skills/registry.js';
|
|
31
|
+
import { SkillTools } from './tools/skills.js';
|
|
28
32
|
import { KillSwitch } from './security/kill-switch.js';
|
|
29
33
|
import { TabOwnership } from './security/tab-ownership.js';
|
|
30
34
|
import { AuditLog } from './security/audit-log.js';
|
|
@@ -32,7 +36,7 @@ import { DomainPolicy } from './security/domain-policy.js';
|
|
|
32
36
|
import { RateLimiter } from './security/rate-limiter.js';
|
|
33
37
|
import { CircuitBreaker } from './security/circuit-breaker.js';
|
|
34
38
|
import { IdpiAnnotator } from './security/idpi-annotator.js';
|
|
35
|
-
import { HumanApproval } from './security/human-approval.js';
|
|
39
|
+
import { HumanApproval, HUMAN_APPROVAL_SUGGESTED_NEXT_TOOLS } from './security/human-approval.js';
|
|
36
40
|
import { ScreenshotPolicy } from './security/screenshot-policy.js';
|
|
37
41
|
import { RateLimitedError, HumanApprovalRequiredError, TabUrlNotRecognizedError, SessionTabProtectedError, TabNotOwnedError, DomainNotAllowedError, KillSwitchActiveError, CircuitBreakerOpenError, SessionRecoveryError, SessionWindowInitError, } from './errors.js';
|
|
38
42
|
import { loadConfig, DEFAULT_CONFIG } from './config.js';
|
|
@@ -184,6 +188,62 @@ export class SafariPilotServer {
|
|
|
184
188
|
getSessionWindowId() {
|
|
185
189
|
return this._sessionWindowId;
|
|
186
190
|
}
|
|
191
|
+
/**
|
|
192
|
+
* Return all tool definitions (name, description, inputSchema, requirements)
|
|
193
|
+
* without requiring `initialize()` to have been called.
|
|
194
|
+
*
|
|
195
|
+
* Uses I/O-free engine instances to satisfy tool module constructors;
|
|
196
|
+
* only `getDefinitions()` is called — no engine I/O occurs.
|
|
197
|
+
*/
|
|
198
|
+
listToolDefinitions() {
|
|
199
|
+
const engine = new AppleScriptEngine();
|
|
200
|
+
const proxy = new EngineProxy(engine);
|
|
201
|
+
const daemon = new DaemonEngine();
|
|
202
|
+
const modules = [
|
|
203
|
+
new NavigationTools(engine),
|
|
204
|
+
new InteractionTools(proxy, this),
|
|
205
|
+
new ExtractionTools(proxy, new ScreenshotPolicy(this.config.screenshotPolicy)),
|
|
206
|
+
new NetworkTools(proxy),
|
|
207
|
+
new StorageTools(proxy),
|
|
208
|
+
new AuthTools(proxy),
|
|
209
|
+
new FileUploadTools(proxy, daemon),
|
|
210
|
+
new ShadowTools(proxy),
|
|
211
|
+
new FrameTools(proxy),
|
|
212
|
+
new PermissionTools(proxy),
|
|
213
|
+
new ClipboardTools(proxy),
|
|
214
|
+
new ServiceWorkerTools(proxy),
|
|
215
|
+
new PerformanceTools(proxy),
|
|
216
|
+
new StructuredExtractionTools(proxy),
|
|
217
|
+
new WaitTools(proxy),
|
|
218
|
+
new CompoundTools(engine),
|
|
219
|
+
new DownloadTools(this),
|
|
220
|
+
new PdfTools(this),
|
|
221
|
+
new ExtensionDiagnosticsTools(null),
|
|
222
|
+
new SelectorPackTools(proxy, this.config.selectorPack),
|
|
223
|
+
];
|
|
224
|
+
// Build the tool index from all existing modules and add the search meta-tool.
|
|
225
|
+
const allEntries = modules.flatMap((m) => m
|
|
226
|
+
.getDefinitions()
|
|
227
|
+
.map((d) => ({ name: d.name, description: d.description })));
|
|
228
|
+
modules.push(new ToolSearchTools(proxy, new ToolIndex(allEntries)));
|
|
229
|
+
// Add SkillTools with empty registry (listToolDefinitions is sync — no I/O).
|
|
230
|
+
const emptyDispatch = async () => { throw new Error('listToolDefinitions: dispatch unavailable'); };
|
|
231
|
+
modules.push(new SkillTools(proxy, new SkillRegistry(), emptyDispatch));
|
|
232
|
+
const defs = [];
|
|
233
|
+
for (const mod of modules) {
|
|
234
|
+
for (const d of mod.getDefinitions()) {
|
|
235
|
+
defs.push({ name: d.name, description: d.description, inputSchema: d.inputSchema, requirements: d.requirements });
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
// Also include the emergency stop tool registered directly in initialize()
|
|
239
|
+
defs.push({
|
|
240
|
+
name: 'safari_emergency_stop',
|
|
241
|
+
description: 'Emergency stop — immediately close all agent-owned tabs, activate kill switch, and block all further automation.',
|
|
242
|
+
inputSchema: { type: 'object', properties: { reason: { type: 'string', description: 'Reason for the emergency stop' } } },
|
|
243
|
+
requirements: { idempotent: false },
|
|
244
|
+
});
|
|
245
|
+
return defs;
|
|
246
|
+
}
|
|
187
247
|
get sessionTabUrl() {
|
|
188
248
|
return `http://127.0.0.1:19475/session?id=${this.sessionId}`;
|
|
189
249
|
}
|
|
@@ -303,6 +363,34 @@ export class SafariPilotServer {
|
|
|
303
363
|
extensionDiagnosticsTools,
|
|
304
364
|
selectorPackTools,
|
|
305
365
|
];
|
|
366
|
+
// Build the tool index from all registered modules, then add the search meta-tool.
|
|
367
|
+
const toolIndex = new ToolIndex(modules.flatMap((m) => m.getDefinitions().map((d) => ({ name: d.name, description: d.description }))));
|
|
368
|
+
modules.push(new ToolSearchTools(proxy, toolIndex));
|
|
369
|
+
// Load skill registry async and add SkillTools.
|
|
370
|
+
// NOTE: Sub-step dispatch bypasses the security pipeline (tab-ownership,
|
|
371
|
+
// rate-limit, circuit-breaker, audit). The outer safari_run_skill call is
|
|
372
|
+
// fully secured; inner steps are not individually audited. Accepted trade-off.
|
|
373
|
+
const skillRegistry = await SkillRegistry.fromDir('skills');
|
|
374
|
+
const skillDispatch = async (n, a) => {
|
|
375
|
+
if (n === 'safari_run_skill' || n === 'safari_list_skills') {
|
|
376
|
+
throw new Error(`Skill cannot call meta-tool: ${n}`);
|
|
377
|
+
}
|
|
378
|
+
for (const m of modules) {
|
|
379
|
+
const h = m.getHandler(n);
|
|
380
|
+
if (h) {
|
|
381
|
+
const resp = await h(a);
|
|
382
|
+
const text = resp.content[0]?.text;
|
|
383
|
+
try {
|
|
384
|
+
return text ? JSON.parse(text) : null;
|
|
385
|
+
}
|
|
386
|
+
catch {
|
|
387
|
+
return text;
|
|
388
|
+
}
|
|
389
|
+
}
|
|
390
|
+
}
|
|
391
|
+
throw new Error(`Skill called unknown tool: ${n}`);
|
|
392
|
+
};
|
|
393
|
+
modules.push(new SkillTools(proxy, skillRegistry, skillDispatch));
|
|
306
394
|
for (const module of modules) {
|
|
307
395
|
for (const def of module.getDefinitions()) {
|
|
308
396
|
const handler = module.getHandler(def.name);
|
|
@@ -489,6 +577,7 @@ export class SafariPilotServer {
|
|
|
489
577
|
degraded: true,
|
|
490
578
|
degradedReason: err.message,
|
|
491
579
|
latencyMs: Date.now() - start,
|
|
580
|
+
suggested_next_tools: HUMAN_APPROVAL_SUGGESTED_NEXT_TOOLS,
|
|
492
581
|
},
|
|
493
582
|
};
|
|
494
583
|
}
|
|
@@ -643,6 +732,7 @@ export class SafariPilotServer {
|
|
|
643
732
|
degraded: true,
|
|
644
733
|
degradedReason: `extension_degraded_approval_required: ${err.message}`,
|
|
645
734
|
latencyMs: Date.now() - start,
|
|
735
|
+
suggested_next_tools: HUMAN_APPROVAL_SUGGESTED_NEXT_TOOLS,
|
|
646
736
|
},
|
|
647
737
|
};
|
|
648
738
|
}
|