safari-pilot 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (143) hide show
  1. package/.claude-plugin/plugin.json +35 -0
  2. package/.mcp.json +11 -0
  3. package/LICENSE +21 -0
  4. package/README.md +324 -0
  5. package/bin/.gitkeep +0 -0
  6. package/bin/Safari Pilot.app/Contents/CodeResources +0 -0
  7. package/bin/Safari Pilot.app/Contents/Info.plist +58 -0
  8. package/bin/Safari Pilot.app/Contents/MacOS/Safari Pilot +0 -0
  9. package/bin/Safari Pilot.app/Contents/PkgInfo +1 -0
  10. package/bin/Safari Pilot.app/Contents/PlugIns/Safari Pilot Extension.appex/Contents/Info.plist +55 -0
  11. package/bin/Safari Pilot.app/Contents/PlugIns/Safari Pilot Extension.appex/Contents/MacOS/Safari Pilot Extension +0 -0
  12. package/bin/Safari Pilot.app/Contents/PlugIns/Safari Pilot Extension.appex/Contents/Resources/background.js +294 -0
  13. package/bin/Safari Pilot.app/Contents/PlugIns/Safari Pilot Extension.appex/Contents/Resources/content-isolated.js +80 -0
  14. package/bin/Safari Pilot.app/Contents/PlugIns/Safari Pilot Extension.appex/Contents/Resources/content-main.js +310 -0
  15. package/bin/Safari Pilot.app/Contents/PlugIns/Safari Pilot Extension.appex/Contents/Resources/icons/icon-128.png +0 -0
  16. package/bin/Safari Pilot.app/Contents/PlugIns/Safari Pilot Extension.appex/Contents/Resources/icons/icon-48.png +0 -0
  17. package/bin/Safari Pilot.app/Contents/PlugIns/Safari Pilot Extension.appex/Contents/Resources/icons/icon-96.png +0 -0
  18. package/bin/Safari Pilot.app/Contents/PlugIns/Safari Pilot Extension.appex/Contents/Resources/manifest.json +39 -0
  19. package/bin/Safari Pilot.app/Contents/PlugIns/Safari Pilot Extension.appex/Contents/_CodeSignature/CodeResources +194 -0
  20. package/bin/Safari Pilot.app/Contents/Resources/AppIcon.icns +0 -0
  21. package/bin/Safari Pilot.app/Contents/Resources/Assets.car +0 -0
  22. package/bin/Safari Pilot.app/Contents/Resources/Base.lproj/Main.html +19 -0
  23. package/bin/Safari Pilot.app/Contents/Resources/Base.lproj/Main.storyboardc/Info.plist +0 -0
  24. package/bin/Safari Pilot.app/Contents/Resources/Base.lproj/Main.storyboardc/MainMenu.nib +0 -0
  25. package/bin/Safari Pilot.app/Contents/Resources/Base.lproj/Main.storyboardc/NSWindowController-B8D-0N-5wS.nib +0 -0
  26. package/bin/Safari Pilot.app/Contents/Resources/Base.lproj/Main.storyboardc/XfG-lQ-9wD-view-m2S-Jp-Qdl.nib +0 -0
  27. package/bin/Safari Pilot.app/Contents/Resources/Icon.png +0 -0
  28. package/bin/Safari Pilot.app/Contents/Resources/Script.js +22 -0
  29. package/bin/Safari Pilot.app/Contents/Resources/Style.css +45 -0
  30. package/bin/Safari Pilot.app/Contents/_CodeSignature/CodeResources +236 -0
  31. package/bin/Safari Pilot.zip +0 -0
  32. package/bin/SafariPilotd +0 -0
  33. package/dist/engine-selector.d.ts +10 -0
  34. package/dist/engine-selector.js +55 -0
  35. package/dist/engine-selector.js.map +1 -0
  36. package/dist/engines/applescript.d.ts +53 -0
  37. package/dist/engines/applescript.js +290 -0
  38. package/dist/engines/applescript.js.map +1 -0
  39. package/dist/engines/daemon.d.ts +19 -0
  40. package/dist/engines/daemon.js +187 -0
  41. package/dist/engines/daemon.js.map +1 -0
  42. package/dist/engines/engine.d.ts +15 -0
  43. package/dist/engines/engine.js +42 -0
  44. package/dist/engines/engine.js.map +1 -0
  45. package/dist/engines/extension.d.ts +34 -0
  46. package/dist/engines/extension.js +66 -0
  47. package/dist/engines/extension.js.map +1 -0
  48. package/dist/errors.d.ts +128 -0
  49. package/dist/errors.js +250 -0
  50. package/dist/errors.js.map +1 -0
  51. package/dist/index.d.ts +2 -0
  52. package/dist/index.js +11 -0
  53. package/dist/index.js.map +1 -0
  54. package/dist/security/audit-log.d.ts +23 -0
  55. package/dist/security/audit-log.js +68 -0
  56. package/dist/security/audit-log.js.map +1 -0
  57. package/dist/security/circuit-breaker.d.ts +29 -0
  58. package/dist/security/circuit-breaker.js +114 -0
  59. package/dist/security/circuit-breaker.js.map +1 -0
  60. package/dist/security/domain-policy.d.ts +29 -0
  61. package/dist/security/domain-policy.js +96 -0
  62. package/dist/security/domain-policy.js.map +1 -0
  63. package/dist/security/human-approval.d.ts +20 -0
  64. package/dist/security/human-approval.js +150 -0
  65. package/dist/security/human-approval.js.map +1 -0
  66. package/dist/security/idpi-scanner.d.ts +20 -0
  67. package/dist/security/idpi-scanner.js +102 -0
  68. package/dist/security/idpi-scanner.js.map +1 -0
  69. package/dist/security/kill-switch.d.ts +51 -0
  70. package/dist/security/kill-switch.js +103 -0
  71. package/dist/security/kill-switch.js.map +1 -0
  72. package/dist/security/rate-limiter.d.ts +30 -0
  73. package/dist/security/rate-limiter.js +70 -0
  74. package/dist/security/rate-limiter.js.map +1 -0
  75. package/dist/security/screenshot-redaction.d.ts +42 -0
  76. package/dist/security/screenshot-redaction.js +134 -0
  77. package/dist/security/screenshot-redaction.js.map +1 -0
  78. package/dist/security/tab-ownership.d.ts +46 -0
  79. package/dist/security/tab-ownership.js +85 -0
  80. package/dist/security/tab-ownership.js.map +1 -0
  81. package/dist/server.d.ts +53 -0
  82. package/dist/server.js +347 -0
  83. package/dist/server.js.map +1 -0
  84. package/dist/tools/clipboard.d.ts +15 -0
  85. package/dist/tools/clipboard.js +128 -0
  86. package/dist/tools/clipboard.js.map +1 -0
  87. package/dist/tools/compound.d.ts +68 -0
  88. package/dist/tools/compound.js +491 -0
  89. package/dist/tools/compound.js.map +1 -0
  90. package/dist/tools/extraction.d.ts +26 -0
  91. package/dist/tools/extraction.js +414 -0
  92. package/dist/tools/extraction.js.map +1 -0
  93. package/dist/tools/frames.d.ts +22 -0
  94. package/dist/tools/frames.js +165 -0
  95. package/dist/tools/frames.js.map +1 -0
  96. package/dist/tools/interaction.d.ts +30 -0
  97. package/dist/tools/interaction.js +651 -0
  98. package/dist/tools/interaction.js.map +1 -0
  99. package/dist/tools/navigation.d.ts +41 -0
  100. package/dist/tools/navigation.js +316 -0
  101. package/dist/tools/navigation.js.map +1 -0
  102. package/dist/tools/network.d.ts +27 -0
  103. package/dist/tools/network.js +721 -0
  104. package/dist/tools/network.js.map +1 -0
  105. package/dist/tools/performance.d.ts +16 -0
  106. package/dist/tools/performance.js +240 -0
  107. package/dist/tools/performance.js.map +1 -0
  108. package/dist/tools/permissions.d.ts +25 -0
  109. package/dist/tools/permissions.js +308 -0
  110. package/dist/tools/permissions.js.map +1 -0
  111. package/dist/tools/service-workers.d.ts +15 -0
  112. package/dist/tools/service-workers.js +136 -0
  113. package/dist/tools/service-workers.js.map +1 -0
  114. package/dist/tools/shadow.d.ts +21 -0
  115. package/dist/tools/shadow.js +126 -0
  116. package/dist/tools/shadow.js.map +1 -0
  117. package/dist/tools/storage.d.ts +30 -0
  118. package/dist/tools/storage.js +679 -0
  119. package/dist/tools/storage.js.map +1 -0
  120. package/dist/tools/structured-extraction.d.ts +22 -0
  121. package/dist/tools/structured-extraction.js +433 -0
  122. package/dist/tools/structured-extraction.js.map +1 -0
  123. package/dist/tools/wait.d.ts +18 -0
  124. package/dist/tools/wait.js +182 -0
  125. package/dist/tools/wait.js.map +1 -0
  126. package/dist/types.d.ts +85 -0
  127. package/dist/types.js +2 -0
  128. package/dist/types.js.map +1 -0
  129. package/extension/background.js +294 -0
  130. package/extension/content-isolated.js +80 -0
  131. package/extension/content-main.js +310 -0
  132. package/extension/icons/icon-128.png +0 -0
  133. package/extension/icons/icon-48.png +0 -0
  134. package/extension/icons/icon-96.png +0 -0
  135. package/extension/manifest.json +39 -0
  136. package/hooks/session-end.sh +67 -0
  137. package/hooks/session-start.sh +66 -0
  138. package/package.json +46 -0
  139. package/scripts/build-extension.sh +135 -0
  140. package/scripts/postinstall.sh +91 -0
  141. package/scripts/preuninstall.sh +25 -0
  142. package/scripts/update-daemon.sh +62 -0
  143. package/skills/safari-pilot/SKILL.md +157 -0
@@ -0,0 +1,15 @@
1
+ import type { ToolResponse } from '../types.js';
2
+ import type { AppleScriptEngine } from '../engines/applescript.js';
3
+ import type { ToolDefinition } from './navigation.js';
4
+ type Handler = (params: Record<string, unknown>) => Promise<ToolResponse>;
5
+ export declare class ServiceWorkerTools {
6
+ private readonly engine;
7
+ constructor(engine: AppleScriptEngine);
8
+ getDefinitions(): ToolDefinition[];
9
+ getHandler(name: string): Handler;
10
+ private handleSwList;
11
+ private handleSwUnregister;
12
+ private parseJson;
13
+ private errorResponse;
14
+ }
15
+ export {};
@@ -0,0 +1,136 @@
1
+ /**
2
+ * JS that lists all registered service worker registrations for the current origin.
3
+ * Returns an array of {scope, scriptURL, state} objects.
4
+ */
5
+ const SW_LIST_JS = `
6
+ (async () => {
7
+ if (!('serviceWorker' in navigator)) {
8
+ return JSON.stringify({ registrations: [], supported: false });
9
+ }
10
+ const regs = await navigator.serviceWorker.getRegistrations();
11
+ const registrations = regs.map(r => ({
12
+ scope: r.scope,
13
+ scriptURL: (r.active || r.installing || r.waiting)?.scriptURL ?? null,
14
+ state: r.active ? 'active' : r.installing ? 'installing' : r.waiting ? 'waiting' : 'unknown',
15
+ updateViaCache: r.updateViaCache,
16
+ }));
17
+ return JSON.stringify({ registrations, supported: true });
18
+ })()
19
+ `.trim();
20
+ /**
21
+ * Build JS that unregisters a specific service worker by scope.
22
+ */
23
+ function buildSwUnregisterJs(scope) {
24
+ const escapedScope = JSON.stringify(scope);
25
+ return `
26
+ (async () => {
27
+ if (!('serviceWorker' in navigator)) {
28
+ return JSON.stringify({ unregistered: false, error: 'Service workers not supported' });
29
+ }
30
+ const regs = await navigator.serviceWorker.getRegistrations();
31
+ const target = regs.find(r => r.scope === ${escapedScope});
32
+ if (!target) {
33
+ return JSON.stringify({ unregistered: false, error: 'No service worker found for scope: ' + ${escapedScope} });
34
+ }
35
+ const result = await target.unregister();
36
+ return JSON.stringify({ unregistered: result, scope: ${escapedScope} });
37
+ })()
38
+ `.trim();
39
+ }
40
+ export class ServiceWorkerTools {
41
+ engine;
42
+ constructor(engine) {
43
+ this.engine = engine;
44
+ }
45
+ // ── Public API ──────────────────────────────────────────────────────────────
46
+ getDefinitions() {
47
+ return [
48
+ {
49
+ name: 'safari_sw_list',
50
+ description: 'List all registered service workers for the page\'s origin. ' +
51
+ 'Returns an array of registrations with their scope, scriptURL, and lifecycle state.',
52
+ inputSchema: {
53
+ type: 'object',
54
+ properties: {
55
+ tabUrl: { type: 'string', description: 'Current URL of the tab to inspect' },
56
+ },
57
+ required: ['tabUrl'],
58
+ },
59
+ requirements: {},
60
+ },
61
+ {
62
+ name: 'safari_sw_unregister',
63
+ description: 'Unregister a specific service worker by its scope URL.',
64
+ inputSchema: {
65
+ type: 'object',
66
+ properties: {
67
+ tabUrl: { type: 'string', description: 'Current URL of the tab to execute in' },
68
+ scope: { type: 'string', description: 'The scope URL of the service worker to unregister (e.g. "https://example.com/")' },
69
+ },
70
+ required: ['tabUrl', 'scope'],
71
+ },
72
+ requirements: {},
73
+ },
74
+ ];
75
+ }
76
+ getHandler(name) {
77
+ switch (name) {
78
+ case 'safari_sw_list':
79
+ return (p) => this.handleSwList(p);
80
+ case 'safari_sw_unregister':
81
+ return (p) => this.handleSwUnregister(p);
82
+ default:
83
+ throw new Error(`ServiceWorkerTools: unknown tool "${name}"`);
84
+ }
85
+ }
86
+ // ── Handlers ────────────────────────────────────────────────────────────────
87
+ async handleSwList(params) {
88
+ const start = Date.now();
89
+ const tabUrl = params['tabUrl'];
90
+ const script = this.engine.buildTabScript(tabUrl, SW_LIST_JS);
91
+ const result = await this.engine.execute(script);
92
+ if (!result.ok) {
93
+ return this.errorResponse(result.error?.message ?? 'Failed to list service workers', start);
94
+ }
95
+ const data = this.parseJson(result.value) ?? { registrations: [], supported: false };
96
+ return {
97
+ content: [{ type: 'text', text: JSON.stringify(data) }],
98
+ metadata: { engine: 'applescript', degraded: false, latencyMs: Date.now() - start },
99
+ };
100
+ }
101
+ async handleSwUnregister(params) {
102
+ const start = Date.now();
103
+ const tabUrl = params['tabUrl'];
104
+ const scope = params['scope'];
105
+ const js = buildSwUnregisterJs(scope);
106
+ const script = this.engine.buildTabScript(tabUrl, js);
107
+ const result = await this.engine.execute(script);
108
+ if (!result.ok) {
109
+ return this.errorResponse(result.error?.message ?? 'Failed to unregister service worker', start);
110
+ }
111
+ const data = this.parseJson(result.value) ?? { unregistered: false };
112
+ return {
113
+ content: [{ type: 'text', text: JSON.stringify(data) }],
114
+ metadata: { engine: 'applescript', degraded: false, latencyMs: Date.now() - start },
115
+ };
116
+ }
117
+ // ── Private helpers ─────────────────────────────────────────────────────────
118
+ parseJson(value) {
119
+ if (!value)
120
+ return undefined;
121
+ try {
122
+ const parsed = JSON.parse(value);
123
+ return typeof parsed === 'object' && parsed !== null ? parsed : undefined;
124
+ }
125
+ catch {
126
+ return undefined;
127
+ }
128
+ }
129
+ errorResponse(message, start) {
130
+ return {
131
+ content: [{ type: 'text', text: JSON.stringify({ error: message }) }],
132
+ metadata: { engine: 'applescript', degraded: true, latencyMs: Date.now() - start },
133
+ };
134
+ }
135
+ }
136
+ //# sourceMappingURL=service-workers.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"service-workers.js","sourceRoot":"","sources":["../../src/tools/service-workers.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,21 @@
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 ShadowTools {
11
+ private engine;
12
+ private handlers;
13
+ constructor(engine: AppleScriptEngine);
14
+ private registerHandlers;
15
+ getDefinitions(): ToolDefinition[];
16
+ getHandler(name: string): Handler | undefined;
17
+ private handleQueryShadow;
18
+ private handleClickShadow;
19
+ private makeResponse;
20
+ }
21
+ export {};
@@ -0,0 +1,126 @@
1
+ export class ShadowTools {
2
+ engine;
3
+ handlers = new Map();
4
+ constructor(engine) {
5
+ this.engine = engine;
6
+ this.registerHandlers();
7
+ }
8
+ registerHandlers() {
9
+ this.handlers.set('safari_query_shadow', this.handleQueryShadow.bind(this));
10
+ this.handlers.set('safari_click_shadow', this.handleClickShadow.bind(this));
11
+ }
12
+ // ── Public API ──────────────────────────────────────────────────────────────
13
+ getDefinitions() {
14
+ return [
15
+ {
16
+ name: 'safari_query_shadow',
17
+ description: 'Query an element inside a Shadow DOM tree. Pierces the shadow boundary by accessing the ' +
18
+ 'host element\'s shadowRoot and querying within it. Returns element metadata when found.',
19
+ inputSchema: {
20
+ type: 'object',
21
+ properties: {
22
+ tabUrl: { type: 'string', description: 'Current URL of the tab' },
23
+ hostSelector: { type: 'string', description: 'CSS selector for the shadow host element (the element with a shadowRoot)' },
24
+ shadowSelector: { type: 'string', description: 'CSS selector to query inside the shadow root' },
25
+ },
26
+ required: ['tabUrl', 'hostSelector', 'shadowSelector'],
27
+ },
28
+ requirements: { requiresShadowDom: true },
29
+ },
30
+ {
31
+ name: 'safari_click_shadow',
32
+ description: 'Click an element inside a Shadow DOM tree. Pierces the shadow boundary and dispatches ' +
33
+ 'the full click event sequence (mousedown, mouseup, click) on the shadow element.',
34
+ inputSchema: {
35
+ type: 'object',
36
+ properties: {
37
+ tabUrl: { type: 'string', description: 'Current URL of the tab' },
38
+ hostSelector: { type: 'string', description: 'CSS selector for the shadow host element' },
39
+ shadowSelector: { type: 'string', description: 'CSS selector for the element to click inside the shadow root' },
40
+ },
41
+ required: ['tabUrl', 'hostSelector', 'shadowSelector'],
42
+ },
43
+ requirements: { requiresShadowDom: true },
44
+ },
45
+ ];
46
+ }
47
+ getHandler(name) {
48
+ return this.handlers.get(name);
49
+ }
50
+ // ── Handlers ────────────────────────────────────────────────────────────────
51
+ async handleQueryShadow(params) {
52
+ const start = Date.now();
53
+ const tabUrl = params['tabUrl'];
54
+ const hostSelector = params['hostSelector'];
55
+ const shadowSelector = params['shadowSelector'];
56
+ const escapedHost = hostSelector.replace(/\\/g, '\\\\').replace(/'/g, "\\'");
57
+ const escapedShadow = shadowSelector.replace(/\\/g, '\\\\').replace(/'/g, "\\'");
58
+ const js = `
59
+ var host = document.querySelector('${escapedHost}');
60
+ if (!host) throw Object.assign(new Error('Shadow host not found: ${escapedHost}'), { name: 'ELEMENT_NOT_FOUND' });
61
+ var root = host.shadowRoot;
62
+ if (!root) throw Object.assign(new Error('Element has no shadowRoot: ${escapedHost}'), { name: 'SHADOW_ROOT_NOT_FOUND' });
63
+ var el = root.querySelector('${escapedShadow}');
64
+ if (!el) throw Object.assign(new Error('Shadow element not found: ${escapedShadow}'), { name: 'ELEMENT_NOT_FOUND' });
65
+
66
+ var rect = el.getBoundingClientRect();
67
+ return {
68
+ found: true,
69
+ element: {
70
+ tagName: el.tagName,
71
+ id: el.id || undefined,
72
+ className: el.className || undefined,
73
+ textContent: (el.textContent || '').slice(0, 200),
74
+ rect: { x: rect.x, y: rect.y, width: rect.width, height: rect.height },
75
+ },
76
+ };
77
+ `;
78
+ const result = await this.engine.executeJsInTab(tabUrl, js);
79
+ if (!result.ok)
80
+ throw new Error(result.error?.message ?? 'Shadow query failed');
81
+ return this.makeResponse(result.value ? JSON.parse(result.value) : { found: false }, Date.now() - start);
82
+ }
83
+ async handleClickShadow(params) {
84
+ const start = Date.now();
85
+ const tabUrl = params['tabUrl'];
86
+ const hostSelector = params['hostSelector'];
87
+ const shadowSelector = params['shadowSelector'];
88
+ const escapedHost = hostSelector.replace(/\\/g, '\\\\').replace(/'/g, "\\'");
89
+ const escapedShadow = shadowSelector.replace(/\\/g, '\\\\').replace(/'/g, "\\'");
90
+ const js = `
91
+ var host = document.querySelector('${escapedHost}');
92
+ if (!host) throw Object.assign(new Error('Shadow host not found: ${escapedHost}'), { name: 'ELEMENT_NOT_FOUND' });
93
+ var root = host.shadowRoot;
94
+ if (!root) throw Object.assign(new Error('Element has no shadowRoot: ${escapedHost}'), { name: 'SHADOW_ROOT_NOT_FOUND' });
95
+ var el = root.querySelector('${escapedShadow}');
96
+ if (!el) throw Object.assign(new Error('Shadow element not found: ${escapedShadow}'), { name: 'ELEMENT_NOT_FOUND' });
97
+
98
+ var rect = el.getBoundingClientRect();
99
+ var opts = { bubbles: true, cancelable: true, view: window, clientX: rect.x + rect.width / 2, clientY: rect.y + rect.height / 2 };
100
+ el.dispatchEvent(new MouseEvent('mousedown', opts));
101
+ el.dispatchEvent(new MouseEvent('mouseup', opts));
102
+ el.dispatchEvent(new MouseEvent('click', opts));
103
+
104
+ return {
105
+ clicked: true,
106
+ element: {
107
+ tagName: el.tagName,
108
+ id: el.id || undefined,
109
+ textContent: (el.textContent || '').slice(0, 100),
110
+ },
111
+ };
112
+ `;
113
+ const result = await this.engine.executeJsInTab(tabUrl, js);
114
+ if (!result.ok)
115
+ throw new Error(result.error?.message ?? 'Shadow click failed');
116
+ return this.makeResponse(result.value ? JSON.parse(result.value) : { clicked: true }, Date.now() - start);
117
+ }
118
+ // ── Private helpers ─────────────────────────────────────────────────────────
119
+ makeResponse(data, latencyMs = 0) {
120
+ return {
121
+ content: [{ type: 'text', text: JSON.stringify(data) }],
122
+ metadata: { engine: 'applescript', degraded: false, latencyMs },
123
+ };
124
+ }
125
+ }
126
+ //# sourceMappingURL=shadow.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"shadow.js","sourceRoot":"","sources":["../../src/tools/shadow.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,30 @@
1
+ import type { AppleScriptEngine } from '../engines/applescript.js';
2
+ import type { ToolResponse, ToolRequirements } from '../types.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 StorageTools {
11
+ private engine;
12
+ private handlers;
13
+ constructor(engine: AppleScriptEngine);
14
+ private registerHandlers;
15
+ getDefinitions(): ToolDefinition[];
16
+ getHandler(name: string): Handler | undefined;
17
+ private handleGetCookies;
18
+ private handleSetCookie;
19
+ private handleDeleteCookie;
20
+ private handleStorageStateExport;
21
+ private handleStorageStateImport;
22
+ private handleLocalStorageGet;
23
+ private handleLocalStorageSet;
24
+ private handleSessionStorageGet;
25
+ private handleSessionStorageSet;
26
+ private handleIdbList;
27
+ private handleIdbGet;
28
+ private makeResponse;
29
+ }
30
+ export {};