dsh-browser-plus 0.0.0-stage → 0.5.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/CHANGELOG.md +166 -0
- package/LICENSE +22 -0
- package/NOTICE.md +7 -0
- package/README.en.md +100 -0
- package/README.md +99 -2
- package/assets/dsh-browser-plus-256.png +0 -0
- package/assets/dsh-browser-plus-512.png +0 -0
- package/assets/dsh-browser-plus-small.svg +9 -0
- package/assets/dsh-browser-plus.ico +0 -0
- package/assets/dsh-browser-plus.svg +11 -0
- package/assets/readme-workspace.png +0 -0
- package/cordis.patch.yml +17 -0
- package/docs/MIGRATION.md +48 -0
- package/docs/README.md +22 -0
- package/docs/SOAK-CHECKLIST.md +98 -0
- package/docs/architecture.md +88 -0
- package/docs/tool-reference.md +124 -0
- package/docs/user-guide.md +121 -0
- package/docs/why-browser.md +45 -0
- package/lib/browser/runtime.d.ts +225 -0
- package/lib/browser/runtime.js +302 -0
- package/lib/browser/types.d.ts +668 -0
- package/lib/browser/types.js +18 -0
- package/lib/browser-electron/auth-cookies.d.ts +54 -0
- package/lib/browser-electron/auth-cookies.js +83 -0
- package/lib/browser-electron/chrome-state.d.ts +187 -0
- package/lib/browser-electron/chrome-state.js +12 -0
- package/lib/browser-electron/entry.d.ts +66 -0
- package/lib/browser-electron/entry.js +62 -0
- package/lib/browser-electron/fingerprint.d.ts +29 -0
- package/lib/browser-electron/fingerprint.js +42 -0
- package/lib/browser-electron/host-main.d.ts +18 -0
- package/lib/browser-electron/host-main.js +2494 -0
- package/lib/browser-electron/icon.d.ts +11 -0
- package/lib/browser-electron/icon.js +23 -0
- package/lib/browser-electron/page-chrome.d.ts +21 -0
- package/lib/browser-electron/page-chrome.js +2034 -0
- package/lib/browser-electron/provider.d.ts +709 -0
- package/lib/browser-electron/provider.js +2575 -0
- package/lib/browser-electron/remote-host.d.ts +143 -0
- package/lib/browser-electron/remote-host.js +952 -0
- package/lib/browser-electron/task-summary.d.ts +2 -0
- package/lib/browser-electron/task-summary.js +12 -0
- package/lib/browser-electron/task-thumbnail.d.ts +11 -0
- package/lib/browser-electron/task-thumbnail.js +9 -0
- package/lib/browser-electron/write-guard.d.ts +41 -0
- package/lib/browser-electron/write-guard.js +123 -0
- package/lib/index.d.ts +16 -0
- package/lib/index.js +14 -0
- package/lib/tool-browser/index.d.ts +31 -0
- package/lib/tool-browser/index.js +1931 -0
- package/package.json +95 -4
- package/screenshots.json +3 -0
- package/scripts/build-icons.mjs +80 -0
- package/scripts/capture-window.ps1 +79 -0
- package/scripts/crop-image.ps1 +20 -0
- package/scripts/smoke-browser-tools.mjs +1968 -0
- package/scripts/smoke-chrome-world.mjs +63 -0
- package/scripts/smoke-electron-host.mjs +50 -0
- package/src/browser/runtime.ts +470 -0
- package/src/browser/types.ts +649 -0
- package/src/browser-electron/auth-cookies.ts +125 -0
- package/src/browser-electron/chrome-state.ts +174 -0
- package/src/browser-electron/entry.ts +115 -0
- package/src/browser-electron/fingerprint.ts +45 -0
- package/src/browser-electron/host-main.ts +2330 -0
- package/src/browser-electron/icon.ts +26 -0
- package/src/browser-electron/page-chrome.ts +2046 -0
- package/src/browser-electron/provider.ts +3088 -0
- package/src/browser-electron/remote-host.ts +1004 -0
- package/src/browser-electron/task-summary.ts +10 -0
- package/src/browser-electron/task-thumbnail.ts +17 -0
- package/src/browser-electron/write-guard.ts +134 -0
- package/src/index.ts +52 -0
- package/src/tool-browser/index.ts +1974 -0
- package/src/types/electron-shim.d.ts +143 -0
|
@@ -0,0 +1,709 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Electron-backed browser provider: `WebContentsView` sessions driven over
|
|
3
|
+
* `webContents.debugger` (CDP). The provider itself does not import Electron — it operates through the {@link ElectronBrowserViewHost} seam, which the
|
|
4
|
+
* desktop shell implements with real Electron objects. That keeps this
|
|
5
|
+
* package testable under plain Node and leaves the Electron dependency to the
|
|
6
|
+
* shell that owns the `BrowserWindow`.
|
|
7
|
+
* @module dsh-browser-plus/browser-electron
|
|
8
|
+
*/
|
|
9
|
+
import type { BrowserChallenge, BrowserClearAuthRequest, BrowserClearAuthResult, BrowserContentRequest, BrowserContentResult, BrowserDragRequest, BrowserDragResult, BrowserPointerResult, BrowserPointerTarget, BrowserExecuteRequest, BrowserExecuteResult, BrowserFillRequest, BrowserFillResult, BrowserHandoffState, BrowserHistoryEntry, BrowserOpenOptions, BrowserOpenRequest, BrowserPressKeyRequest, BrowserProvider, BrowserRefRequest, BrowserScrapeRequest, BrowserScrapeStatus, BrowserScrollIntoViewRequest, BrowserScrollRequest, BrowserScrollResult, BrowserSessionId, BrowserSnapshotResult, BrowserSpaceInfo, BrowserTab, BrowserTaskInfo, BrowserTaskUpdate, BrowserUploadFileRequest, BrowserUploadFileResult, BrowserWaitForRequest, BrowserWaitForResult, ExportedCookie } from '../browser/types.ts';
|
|
10
|
+
/** Stable provider id registered with `ctx.browser`. */
|
|
11
|
+
export declare const ELECTRON_BROWSER_PROVIDER_ID = "electron";
|
|
12
|
+
/**
|
|
13
|
+
* One tab request raised by the injected chrome because a human used it.
|
|
14
|
+
*
|
|
15
|
+
* The host owns the pixels, the tab strip and the per-view secret, so it is the
|
|
16
|
+
* only party that can authenticate such a request; the provider owns the tab
|
|
17
|
+
* model, so it is the only party that may act on one. `tabId` is the host's own
|
|
18
|
+
* view id, which is also the provider's `ElectronViewHandle.id`, so no extra
|
|
19
|
+
* mapping table is needed.
|
|
20
|
+
*/
|
|
21
|
+
export interface ChromeHostEvent {
|
|
22
|
+
/** For a 'move-tab' event: the index the tab was dropped at, after removal. */
|
|
23
|
+
readonly toIndex?: number;
|
|
24
|
+
readonly type: 'new-tab' | 'close-tab' | 'activate-tab' | 'move-tab';
|
|
25
|
+
/** Task key of the chrome that raised it. */
|
|
26
|
+
readonly taskKey: string;
|
|
27
|
+
/** Host view id of the tab; absent for `new-tab`. */
|
|
28
|
+
readonly tabId?: string;
|
|
29
|
+
/** For `new-tab`: open this http(s) url in the new tab (a bookmark click). */
|
|
30
|
+
readonly url?: string;
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* The minimal Electron surface this provider needs. Implemented by the
|
|
34
|
+
* desktop shell with a real `WebContentsView`; a fake implements it in tests.
|
|
35
|
+
*/
|
|
36
|
+
export interface ElectronBrowserViewHost {
|
|
37
|
+
/**
|
|
38
|
+
* Subscribe to tab requests the host raises without being asked (a human
|
|
39
|
+
* clicking the chrome's own `+`, `×` or tab strip). Optional: a host whose
|
|
40
|
+
* chrome cannot speak first simply never raises one.
|
|
41
|
+
* @param listener - invoked once per authenticated chrome request.
|
|
42
|
+
*/
|
|
43
|
+
onChromeEvent?(listener: (event: ChromeHostEvent) => void): void;
|
|
44
|
+
/**
|
|
45
|
+
* Create a new browser view and return a handle to its webContents-like
|
|
46
|
+
* surface. `key` (default 'default') identifies an isolated browser task in
|
|
47
|
+
* the shared BrowserWindow; `label` names that task. The host owns view
|
|
48
|
+
* attachment, sizing, task visibility, and removal; the provider owns
|
|
49
|
+
* CDP-driven behavior.
|
|
50
|
+
*/
|
|
51
|
+
createView(key?: string, label?: string): ElectronViewHandle;
|
|
52
|
+
/**
|
|
53
|
+
* Destroy a view created by this host. Called on session close; idempotent
|
|
54
|
+
* for an already-destroyed view.
|
|
55
|
+
* @param handle - the handle returned by {@link createView}.
|
|
56
|
+
*/
|
|
57
|
+
destroyView(handle: ElectronViewHandle): void;
|
|
58
|
+
/**
|
|
59
|
+
* Notify the host that this session selected a tab. In the shared-window
|
|
60
|
+
* host, a background task updates its active view without changing the
|
|
61
|
+
* human-selected visible task. Optional for headless/probe hosts.
|
|
62
|
+
* @param handle - the handle selected by its session.
|
|
63
|
+
*/
|
|
64
|
+
showView?(handle: ElectronViewHandle): void;
|
|
65
|
+
/**
|
|
66
|
+
* Send a CDP `Input.*` command to the host's chrome frame view.
|
|
67
|
+
*
|
|
68
|
+
* The frame is not a tab and has no handle, so this is its own channel. It
|
|
69
|
+
* exists because the chrome can live in a view of its own (which is what lets
|
|
70
|
+
* the page viewport really shrink): input aimed at a page never reaches that
|
|
71
|
+
* view, and CDP input targets a webContents regardless of view stacking, so
|
|
72
|
+
* the page cannot stand in for it. Optional for hosts without a frame view.
|
|
73
|
+
* @param method - a CDP Input domain command, e.g. 'Input.dispatchMouseEvent'.
|
|
74
|
+
* @param params - that command's parameters.
|
|
75
|
+
*/
|
|
76
|
+
chromeInput?(method: string, params?: Record<string, unknown>): Promise<void>;
|
|
77
|
+
/**
|
|
78
|
+
* Evaluate an expression inside the chrome frame's own document.
|
|
79
|
+
*
|
|
80
|
+
* The frame is a view of its own, so no page-directed call can read it. This is
|
|
81
|
+
* how the tests assert the toolbar's own animations instead of inferring them
|
|
82
|
+
* from the page's copy of the chrome. Optional for hosts without a frame view.
|
|
83
|
+
* @param expression - JavaScript evaluated in the frame, by value.
|
|
84
|
+
*/
|
|
85
|
+
chromeEval?(expression: string): Promise<unknown>;
|
|
86
|
+
/**
|
|
87
|
+
* Append one operation to the human-facing trail for a view. Optional.
|
|
88
|
+
* @param viewId - the view to attribute the operation to.
|
|
89
|
+
* @param entry - the trail entry ({ action, params, ok, at }).
|
|
90
|
+
*/
|
|
91
|
+
trace?(viewId: string, entry: unknown): void;
|
|
92
|
+
/**
|
|
93
|
+
* Cheap local usability probe for this host. MUST NOT make network calls and
|
|
94
|
+
* MUST NOT throw (a throw is reported as unavailable). Optional: a host that
|
|
95
|
+
* omits it is assumed usable, which keeps a desktop shell's shell-owned
|
|
96
|
+
* viewHost and test fakes working. A self-hosted host reports false when the
|
|
97
|
+
* pinned Electron binary cannot be resolved, so the seam can pick another
|
|
98
|
+
* provider (BROWSER_PROVIDER_UNAVAILABLE / BROWSER_PROVIDER_AMBIGUOUS)
|
|
99
|
+
* instead of failing later on the first open().
|
|
100
|
+
*/
|
|
101
|
+
isAvailable?(): boolean;
|
|
102
|
+
/** List browser tasks with their labels. Legacy method name retained for compatibility. */
|
|
103
|
+
listWindows?(): Promise<Array<{
|
|
104
|
+
key: string;
|
|
105
|
+
label: string;
|
|
106
|
+
}>>;
|
|
107
|
+
/** List task summaries when the host exposes a visible workspace. */
|
|
108
|
+
listTasks?(): Promise<readonly BrowserTaskInfo[]>;
|
|
109
|
+
/** Read one task summary from the visible workspace. */
|
|
110
|
+
getTask?(key: string): Promise<BrowserTaskInfo | undefined>;
|
|
111
|
+
/** Apply a task status/control update to the visible workspace. */
|
|
112
|
+
updateTask?(key: string, update: BrowserTaskUpdate): Promise<BrowserTaskInfo | undefined>;
|
|
113
|
+
}
|
|
114
|
+
/**
|
|
115
|
+
* A CDP-capable view handle. This is the subset of Electron's
|
|
116
|
+
* `WebContents`/`WebContentsView` the provider drives; the shell's real
|
|
117
|
+
* implementation adapts `webContents.debugger` to it.
|
|
118
|
+
*/
|
|
119
|
+
export interface ElectronViewHandle {
|
|
120
|
+
/** Unique id of the backing view, used for diagnostics. */
|
|
121
|
+
readonly id: string;
|
|
122
|
+
/**
|
|
123
|
+
* Send one CDP command and resolve with its result. Rejects when the
|
|
124
|
+
* debugger is not attached or the command fails.
|
|
125
|
+
* @param method - CDP method, e.g. `Page.navigate`.
|
|
126
|
+
* @param params - CDP command parameters.
|
|
127
|
+
* @returns the CDP `result` object.
|
|
128
|
+
*/
|
|
129
|
+
sendCommand(method: string, params?: Record<string, unknown>): Promise<Record<string, unknown>>;
|
|
130
|
+
/**
|
|
131
|
+
* Read the most recent auto-accepted JS dialog for this view (and clear it).
|
|
132
|
+
* Optional: hosts without JS-dialog supervision omit it.
|
|
133
|
+
* @returns the dialog detail ({ type, message, prompt? }) or null.
|
|
134
|
+
*/
|
|
135
|
+
clearDialog?(): Promise<unknown>;
|
|
136
|
+
/** Optional: hosts without JS-dialog supervision omit it. */
|
|
137
|
+
setDialogPolicy?(policy: DialogPolicy): Promise<unknown>;
|
|
138
|
+
/** Optional: bounded console capture. */
|
|
139
|
+
readConsole?(clear?: boolean): Promise<unknown>;
|
|
140
|
+
/** Optional: bounded network capture. */
|
|
141
|
+
readNetwork?(clear?: boolean): Promise<unknown>;
|
|
142
|
+
/**
|
|
143
|
+
* Remove cookies matching a domain/name filter. Optional: hosts without a
|
|
144
|
+
* deletable cookie store omit it.
|
|
145
|
+
*/
|
|
146
|
+
clearCookies?(filter: {
|
|
147
|
+
readonly domain?: string;
|
|
148
|
+
readonly name?: string;
|
|
149
|
+
readonly all?: boolean;
|
|
150
|
+
}): Promise<{
|
|
151
|
+
readonly removed: number;
|
|
152
|
+
readonly names: readonly string[];
|
|
153
|
+
}>;
|
|
154
|
+
/** Set this view's browser task label; it titles the shared window only when selected. Optional. */
|
|
155
|
+
label?(label: string): Promise<void>;
|
|
156
|
+
/**
|
|
157
|
+
* Re-apply the host's own page chrome to the current document. Optional: a host
|
|
158
|
+
* that does not own the chrome omits it, and the provider then injects its own
|
|
159
|
+
* tokenless copy as a fallback.
|
|
160
|
+
*/
|
|
161
|
+
reinstallChrome?(): Promise<void>;
|
|
162
|
+
}
|
|
163
|
+
/**
|
|
164
|
+
* How the host answers a JS dialog (alert/confirm/prompt).
|
|
165
|
+
*
|
|
166
|
+
* A dialog freezes the renderer until it is answered, so the default stays
|
|
167
|
+
* `accept` - automation must never hang on one. `dismiss` is for pages whose
|
|
168
|
+
* confirmation is part of what is being driven (delete prompts and the like),
|
|
169
|
+
* and `promptText` supplies the value for a prompt.
|
|
170
|
+
*/
|
|
171
|
+
/** One captured console message. */
|
|
172
|
+
export interface BrowserConsoleMessage {
|
|
173
|
+
level: string;
|
|
174
|
+
text: string;
|
|
175
|
+
at: string;
|
|
176
|
+
}
|
|
177
|
+
/** One captured network request. */
|
|
178
|
+
export interface BrowserNetworkRequest {
|
|
179
|
+
method: string;
|
|
180
|
+
url: string;
|
|
181
|
+
status?: number;
|
|
182
|
+
mime?: string;
|
|
183
|
+
kind?: string;
|
|
184
|
+
failed?: string;
|
|
185
|
+
ms?: number;
|
|
186
|
+
at: string;
|
|
187
|
+
}
|
|
188
|
+
/** Device/viewport/media emulation for one tab (browser_emulate). */
|
|
189
|
+
export interface EmulateOptions {
|
|
190
|
+
readonly width?: number;
|
|
191
|
+
readonly height?: number;
|
|
192
|
+
readonly deviceScaleFactor?: number;
|
|
193
|
+
readonly mobile?: boolean;
|
|
194
|
+
readonly userAgent?: string;
|
|
195
|
+
readonly colorScheme?: 'light' | 'dark' | 'no-preference';
|
|
196
|
+
/** Undo everything this tool set on the tab. */
|
|
197
|
+
readonly clear?: boolean;
|
|
198
|
+
}
|
|
199
|
+
export interface DialogPolicy {
|
|
200
|
+
readonly behavior: 'accept' | 'dismiss';
|
|
201
|
+
readonly promptText?: string;
|
|
202
|
+
}
|
|
203
|
+
/** Provider config: navigation admission defaults and snapshot caps. */
|
|
204
|
+
export interface ElectronBrowserProviderConfig {
|
|
205
|
+
/** Allow navigation only to HTTP(S) URLs; reject anything else. Default true. */
|
|
206
|
+
readonly httpOnly?: boolean;
|
|
207
|
+
/** Maximum snapshot elements before truncation. Default 60. */
|
|
208
|
+
readonly snapshotMaxElements?: number;
|
|
209
|
+
/** Maximum content characters before truncation when no maxChars is given. Default 100_000. */
|
|
210
|
+
readonly contentMaxChars?: number;
|
|
211
|
+
/**
|
|
212
|
+
* Absolute directories a screenshot or download may write into. Defaults to
|
|
213
|
+
* the workspace and the OS temp directory ({@link defaultWriteRoots}); an
|
|
214
|
+
* empty list denies every write.
|
|
215
|
+
*/
|
|
216
|
+
readonly writeRoots?: readonly string[];
|
|
217
|
+
/**
|
|
218
|
+
* Absolute directories `browser_upload_file` may read from. Defaults to the
|
|
219
|
+
* same roots as {@link writeRoots}; an empty list denies every upload.
|
|
220
|
+
*/
|
|
221
|
+
readonly readRoots?: readonly string[];
|
|
222
|
+
}
|
|
223
|
+
/**
|
|
224
|
+
* CDP method/params for `Page.navigate`, as sent to {@link ElectronViewHandle.sendCommand}.
|
|
225
|
+
*/
|
|
226
|
+
export interface CdpNavigateParams {
|
|
227
|
+
readonly url: string;
|
|
228
|
+
}
|
|
229
|
+
/**
|
|
230
|
+
* CDP method/params for `Input.dispatchMouseEvent` (a click press+release pair).
|
|
231
|
+
*/
|
|
232
|
+
export interface CdpMouseParams {
|
|
233
|
+
readonly type: 'mousePressed' | 'mouseReleased' | 'mouseMoved';
|
|
234
|
+
readonly x: number;
|
|
235
|
+
readonly y: number;
|
|
236
|
+
readonly button: 'left' | 'right' | 'middle' | 'none';
|
|
237
|
+
readonly clickCount?: number;
|
|
238
|
+
/** Buttons held during the event; 1 while a left drag is in flight. */
|
|
239
|
+
readonly buttons?: number;
|
|
240
|
+
/** CDP modifier bitmask (Alt 1, Ctrl 2, Meta 4, Shift 8); see modifierMask. */
|
|
241
|
+
readonly modifiers?: number;
|
|
242
|
+
}
|
|
243
|
+
/** CDP method/params for `Input.insertText`. */
|
|
244
|
+
export interface CdpInsertTextParams {
|
|
245
|
+
readonly text: string;
|
|
246
|
+
}
|
|
247
|
+
/** CDP method/params for `Runtime.evaluate`. */
|
|
248
|
+
export interface CdpEvaluateParams {
|
|
249
|
+
readonly expression: string;
|
|
250
|
+
readonly returnByValue: boolean;
|
|
251
|
+
readonly awaitPromise?: boolean;
|
|
252
|
+
}
|
|
253
|
+
/** CDP method for a full-page screenshot capture. */
|
|
254
|
+
export declare const CDP_PAGE_CAPTURE_SCREENSHOT = "Page.captureScreenshot";
|
|
255
|
+
/** CDP method for runtime evaluation (the execute path). */
|
|
256
|
+
export declare const CDP_RUNTIME_EVALUATE = "Runtime.evaluate";
|
|
257
|
+
/**
|
|
258
|
+
* Decide how to hand a script to `Runtime.evaluate`.
|
|
259
|
+
*
|
|
260
|
+
* CDP evaluates an *expression*, so a script made of statements is a syntax
|
|
261
|
+
* error there. Try the expression form first - that keeps bare expressions and
|
|
262
|
+
* object literals returning their value, which is what the tool has always
|
|
263
|
+
* done - then fall back to a statement body. `const x = 1; return x` is the
|
|
264
|
+
* shape people actually type, and it used to come back as a bare SyntaxError.
|
|
265
|
+
*/
|
|
266
|
+
export declare function buildEvaluateBody(script: string): {
|
|
267
|
+
body: string;
|
|
268
|
+
} | {
|
|
269
|
+
error: string;
|
|
270
|
+
};
|
|
271
|
+
/** CDP method for keyboard input. */
|
|
272
|
+
export declare const CDP_INPUT_DISPATCH_KEY_EVENT = "Input.dispatchKeyEvent";
|
|
273
|
+
/** CDP method for navigation. */
|
|
274
|
+
export declare const CDP_PAGE_NAVIGATE = "Page.navigate";
|
|
275
|
+
/** CDP methods used by native browser navigation controls. */
|
|
276
|
+
export declare const CDP_PAGE_GET_NAVIGATION_HISTORY = "Page.getNavigationHistory";
|
|
277
|
+
export declare const CDP_PAGE_NAVIGATE_TO_HISTORY_ENTRY = "Page.navigateToHistoryEntry";
|
|
278
|
+
export declare const CDP_PAGE_RELOAD = "Page.reload";
|
|
279
|
+
export declare const CDP_PAGE_STOP_LOADING = "Page.stopLoading";
|
|
280
|
+
/**
|
|
281
|
+
* Browser provider over Electron views. Sessions hold an ordered list of
|
|
282
|
+
* tabs; each tab is one view created by the host. The active tab receives
|
|
283
|
+
* every operation; switching tabs calls the host's optional `showView` and
|
|
284
|
+
* never loses state. Navigation is admitted only for HTTP(S) targets unless
|
|
285
|
+
* {@link ElectronBrowserProviderConfig.httpOnly} is disabled.
|
|
286
|
+
*/
|
|
287
|
+
export declare class ElectronBrowserProvider implements BrowserProvider {
|
|
288
|
+
private readonly host;
|
|
289
|
+
readonly id = "electron";
|
|
290
|
+
private readonly sessions;
|
|
291
|
+
/** Stable task-key index so callers can recover a session after tool-layer state loss. */
|
|
292
|
+
private readonly sessionsByTask;
|
|
293
|
+
private readonly taskStates;
|
|
294
|
+
private readonly httpOnly;
|
|
295
|
+
private readonly snapshotMaxElements;
|
|
296
|
+
private readonly contentMaxChars;
|
|
297
|
+
private readonly writeRoots;
|
|
298
|
+
private readonly readRoots;
|
|
299
|
+
/** Background scrape batches, keyed by id; rows live on disk, not here. */
|
|
300
|
+
private readonly scrapes;
|
|
301
|
+
constructor(host: ElectronBrowserViewHost, config?: ElectronBrowserProviderConfig);
|
|
302
|
+
/**
|
|
303
|
+
* Apply one authenticated chrome request to the session that owns its task.
|
|
304
|
+
*
|
|
305
|
+
* Every field is re-checked here: the host authenticates the sender, this
|
|
306
|
+
* method decides whether the request still makes sense against the live tab
|
|
307
|
+
* model. A request that resolves to nothing (a stale strip, a tab closed a
|
|
308
|
+
* moment ago, a task with no session) is dropped rather than thrown, because
|
|
309
|
+
* a human click must never surface as an error inside a running tool call.
|
|
310
|
+
*/
|
|
311
|
+
private handleChromeEvent;
|
|
312
|
+
/**
|
|
313
|
+
* Usable whenever the host can create views. A host that exposes a local
|
|
314
|
+
* {@link ElectronBrowserViewHost.isAvailable} probe is believed; a host that
|
|
315
|
+
* omits it (a desktop shell's known-good viewHost, or a test fake) is assumed
|
|
316
|
+
* usable. The probe is cheap and local, so this stays callable from the seam's
|
|
317
|
+
* provider-selection path; the host owns any caching it needs.
|
|
318
|
+
*/
|
|
319
|
+
available(): boolean;
|
|
320
|
+
/**
|
|
321
|
+
* Open or recover the browser session for a task key. The tool layer normally
|
|
322
|
+
* caches this id, but the Provider is authoritative so a scoped tool reload or
|
|
323
|
+
* a lost cache cannot create a second task session with a different tab set.
|
|
324
|
+
* Sessions keep isolated tabs, active tab, and history while the host keeps one
|
|
325
|
+
* human-selected task view visible in the shared BrowserWindow.
|
|
326
|
+
*/
|
|
327
|
+
open(options?: BrowserOpenOptions): Promise<BrowserSessionId>;
|
|
328
|
+
/** Open a URL in the active tab (default) or a new tab. */
|
|
329
|
+
openUrl(session: BrowserSessionId, request: BrowserOpenRequest, signal?: AbortSignal): Promise<void>;
|
|
330
|
+
/** List the session's tabs with their titles. */
|
|
331
|
+
listTabs(session: BrowserSessionId): Promise<readonly BrowserTab[]>;
|
|
332
|
+
/** Switch to a tab by id; background task tabs stay hidden until user-selected. */
|
|
333
|
+
switchTab(session: BrowserSessionId, tabId: string): Promise<void>;
|
|
334
|
+
/**
|
|
335
|
+
* Close one tab; closing the active tab activates the next. Resolves false when
|
|
336
|
+
* the id is not open in this session, so a miss is distinguishable from a close.
|
|
337
|
+
*/
|
|
338
|
+
closeTab(session: BrowserSessionId, tabId: string): Promise<boolean>;
|
|
339
|
+
/** Close every tab and reset to one blank tab. */
|
|
340
|
+
reset(session: BrowserSessionId): Promise<void>;
|
|
341
|
+
/**
|
|
342
|
+
* Dispatch one input command under the same hang guard as the CDP reads. A
|
|
343
|
+
* renderer blocked in synchronous JS never acknowledges, so an unbounded await
|
|
344
|
+
* here would hang the tool call until the caller's budget expired.
|
|
345
|
+
* @param handle - the view to dispatch into.
|
|
346
|
+
* @param method - the CDP input method.
|
|
347
|
+
* @param params - its parameters.
|
|
348
|
+
* @param signal - optional caller signal.
|
|
349
|
+
*/
|
|
350
|
+
private dispatchInput;
|
|
351
|
+
/**
|
|
352
|
+
* Tell a renderer it is focused, once, before synthesized input.
|
|
353
|
+
*
|
|
354
|
+
* Chromium drops a synthesized mouse *press* when the renderer does not
|
|
355
|
+
* believe it has focus — which is the normal state for a background task's
|
|
356
|
+
* view, and on a real page even for the visible one while its window is not
|
|
357
|
+
* active. Moves are not gated, so hover looked fine while every click
|
|
358
|
+
* resolved its target, reported success, and left the page untouched.
|
|
359
|
+
*
|
|
360
|
+
* Focus emulation keeps this on the trusted CDP input path: no synthetic
|
|
361
|
+
* DOM click, so the events stay isTrusted and nothing about the page's
|
|
362
|
+
* view of the browser changes.
|
|
363
|
+
*/
|
|
364
|
+
private ensureInputFocus;
|
|
365
|
+
/**
|
|
366
|
+
* Admit one URL for a provider-driven fetch (navigation or download).
|
|
367
|
+
* The whole check is gated by `httpOnly`: when it is disabled, callers are
|
|
368
|
+
* trusted with any scheme. When it is enabled, only HTTP(S) is admitted and
|
|
369
|
+
* URL-embedded credentials are refused, so a target can never be reached
|
|
370
|
+
* with in-URL auth.
|
|
371
|
+
* @param url - the candidate URL.
|
|
372
|
+
* @param subject - the operation name used in the error text.
|
|
373
|
+
*/
|
|
374
|
+
private admitUrl;
|
|
375
|
+
/** Navigate the active tab's view to a URL, honoring HTTP(S)-only admission. */
|
|
376
|
+
navigate(session: BrowserSessionId, request: {
|
|
377
|
+
readonly url: string;
|
|
378
|
+
}, signal?: AbortSignal): Promise<void>;
|
|
379
|
+
/**
|
|
380
|
+
* Navigate one tab. A scrape worker passes its own tab so a batch never races
|
|
381
|
+
* a tool call for the session's active tab.
|
|
382
|
+
* @param show - bring the tab to the front; a background worker passes false.
|
|
383
|
+
* @param settleMs - post-ready paint delay; a DOM-only reader passes 0.
|
|
384
|
+
*/
|
|
385
|
+
private navigateTab;
|
|
386
|
+
/** Navigate to the previous history entry when one exists. */
|
|
387
|
+
back(session: BrowserSessionId, signal?: AbortSignal): Promise<boolean>;
|
|
388
|
+
/** Navigate to the next history entry when one exists. */
|
|
389
|
+
forward(session: BrowserSessionId, signal?: AbortSignal): Promise<boolean>;
|
|
390
|
+
/** Reload the active page and restore the browser chrome afterwards. */
|
|
391
|
+
reload(session: BrowserSessionId, signal?: AbortSignal): Promise<void>;
|
|
392
|
+
/** Stop loading the active page. */
|
|
393
|
+
stopLoading(session: BrowserSessionId, signal?: AbortSignal): Promise<void>;
|
|
394
|
+
/** Execute JS in the active tab's page context. */
|
|
395
|
+
execute(session: BrowserSessionId, request: BrowserExecuteRequest, signal?: AbortSignal): Promise<BrowserExecuteResult>;
|
|
396
|
+
/** Evaluate in one tab's page context. */
|
|
397
|
+
private executeTab;
|
|
398
|
+
/** Produce an AI-friendly snapshot of the active tab. */
|
|
399
|
+
snapshot(session: BrowserSessionId, options?: {
|
|
400
|
+
query?: string;
|
|
401
|
+
limit?: number;
|
|
402
|
+
}, signal?: AbortSignal): Promise<BrowserSnapshotResult>;
|
|
403
|
+
/** Click one element that belongs to a retained exact page snapshot. */
|
|
404
|
+
clickRef(session: BrowserSessionId, request: BrowserRefRequest, signal?: AbortSignal): Promise<void>;
|
|
405
|
+
/** Scroll one element that belongs to a retained exact page snapshot into view. */
|
|
406
|
+
scrollIntoView(session: BrowserSessionId, request: BrowserScrollIntoViewRequest, signal?: AbortSignal): Promise<BrowserScrollResult>;
|
|
407
|
+
/** Check whether a human-verification challenge is blocking the active tab. */
|
|
408
|
+
detectChallenge(session: BrowserSessionId, signal?: AbortSignal): Promise<BrowserChallenge>;
|
|
409
|
+
/** Fetch page content in a requested format. */
|
|
410
|
+
content(session: BrowserSessionId, request: BrowserContentRequest, signal?: AbortSignal): Promise<BrowserContentResult>;
|
|
411
|
+
/** Click at viewport coordinates (CDP mousePressed + mouseReleased). */
|
|
412
|
+
click(session: BrowserSessionId, target: BrowserPointerTarget, signal?: AbortSignal): Promise<BrowserPointerResult>;
|
|
413
|
+
/** Double-click a target (physical input; clickCount 2). */
|
|
414
|
+
doubleClick(session: BrowserSessionId, target: BrowserPointerTarget, signal?: AbortSignal): Promise<BrowserPointerResult>;
|
|
415
|
+
/** Move the pointer over a target (no click). */
|
|
416
|
+
hover(session: BrowserSessionId, target: BrowserPointerTarget, signal?: AbortSignal): Promise<BrowserPointerResult>;
|
|
417
|
+
/**
|
|
418
|
+
* Press on one target, move to another, release.
|
|
419
|
+
*
|
|
420
|
+
* A hand does not teleport: the intermediate moves are what pointer-based
|
|
421
|
+
* sliders and sortable libraries listen for, so a press straight onto the
|
|
422
|
+
* destination would be ignored. Note this drives *pointer* drags only —
|
|
423
|
+
* HTML5 drag-and-drop needs dragstart/drop, which synthesized mouse moves do
|
|
424
|
+
* not produce; use the page's own controls, or a click-based reorder, there.
|
|
425
|
+
*/
|
|
426
|
+
drag(session: BrowserSessionId, request: BrowserDragRequest, signal?: AbortSignal): Promise<BrowserDragResult>;
|
|
427
|
+
/** Scroll the active page by CSS-pixel deltas and return the final position. */
|
|
428
|
+
scroll(session: BrowserSessionId, request: BrowserScrollRequest, signal?: AbortSignal): Promise<BrowserScrollResult>;
|
|
429
|
+
/**
|
|
430
|
+
* Attach a local file to the first matching file input. Uses the CDP DOM
|
|
431
|
+
* domain (nodeId path), which — unlike a synthetic change event — makes the
|
|
432
|
+
* input's files list true (real file selection), so pages that read
|
|
433
|
+
* input.files or upload on change behave exactly like a real pick.
|
|
434
|
+
*/
|
|
435
|
+
uploadFile(session: BrowserSessionId, request: BrowserUploadFileRequest, signal?: AbortSignal): Promise<BrowserUploadFileResult>;
|
|
436
|
+
/**
|
|
437
|
+
* Poll until an element matching the selector exists (and is visible).
|
|
438
|
+
* Bounds the total wait; a timeout surfaces as BROWSER_WAIT_TIMEOUT.
|
|
439
|
+
*/
|
|
440
|
+
waitForElement(session: BrowserSessionId, request: BrowserWaitForRequest, signal?: AbortSignal): Promise<BrowserWaitForResult>;
|
|
441
|
+
/** Poll one tab until the selector matches. */
|
|
442
|
+
private waitForElementTab;
|
|
443
|
+
/** Type into the focused element. */
|
|
444
|
+
type(session: BrowserSessionId, request: {
|
|
445
|
+
readonly text: string;
|
|
446
|
+
}, signal?: AbortSignal): Promise<void>;
|
|
447
|
+
/**
|
|
448
|
+
* Drive the host's chrome frame view with a raw CDP command.
|
|
449
|
+
*
|
|
450
|
+
* The chrome can live in a view of its own so the page viewport can really
|
|
451
|
+
* shrink; that view is not a tab, so this is the only way to click the toolbar
|
|
452
|
+
* (the click tests use it, and so does anything that needs to exercise the
|
|
453
|
+
* chrome the way a person does).
|
|
454
|
+
*/
|
|
455
|
+
chromeInput(method: string, params?: Record<string, unknown>): Promise<void>;
|
|
456
|
+
/**
|
|
457
|
+
* Read a value back out of the chrome frame's own document.
|
|
458
|
+
*
|
|
459
|
+
* The frame is not a tab, so a page-directed evaluate cannot see it; without
|
|
460
|
+
* this the toolbar's animations could only be inferred from the page's copy.
|
|
461
|
+
*/
|
|
462
|
+
chromeEval(expression: string): Promise<unknown>;
|
|
463
|
+
/** Press a key into the page (keyDown + keyUp), as a physical-input path
|
|
464
|
+
* for shortcuts and keyboard-driven UI. */
|
|
465
|
+
pressKey(session: BrowserSessionId, request: BrowserPressKeyRequest, signal?: AbortSignal): Promise<void>;
|
|
466
|
+
/**
|
|
467
|
+
* Fill a form's fields in one batch. Runs one page-context script that
|
|
468
|
+
* resolves each field (selector, or name/label/placeholder among visible
|
|
469
|
+
* controls), sets its value with the native prototype setter (React/Vue
|
|
470
|
+
* controlled inputs included) plus input/change events, handles
|
|
471
|
+
* select/checkbox/radio/contenteditable, and optionally submits the form.
|
|
472
|
+
*/
|
|
473
|
+
fillForm(session: BrowserSessionId, request: BrowserFillRequest, signal?: AbortSignal): Promise<BrowserFillResult>;
|
|
474
|
+
/**
|
|
475
|
+
* Download a URL to a local file, keeping the session's cookies/login.
|
|
476
|
+
* Requires the self-hosted host (which implements view-level download); the
|
|
477
|
+
* desktop shell's embedded views delegate downloads to the real browser UI.
|
|
478
|
+
*/
|
|
479
|
+
download(session: BrowserSessionId, request: {
|
|
480
|
+
readonly url: string;
|
|
481
|
+
readonly savePath: string;
|
|
482
|
+
}, signal?: AbortSignal): Promise<{
|
|
483
|
+
readonly path: string;
|
|
484
|
+
}>;
|
|
485
|
+
/**
|
|
486
|
+
* Export the session's cookies (login state) as serializable objects.
|
|
487
|
+
* Self-hosted only; the desktop shell's embedded views use the real profile.
|
|
488
|
+
*/
|
|
489
|
+
flushAuth(session: BrowserSessionId): Promise<readonly ExportedCookie[]>;
|
|
490
|
+
/**
|
|
491
|
+
* Remove cookies for one site scope. Challenge cookies that rotate their names
|
|
492
|
+
* (WAF challenges) otherwise pile up generation after generation, and two live
|
|
493
|
+
* generations in one request can be rejected by the site. Self-hosted only.
|
|
494
|
+
*/
|
|
495
|
+
clearAuth(session: BrowserSessionId, request: BrowserClearAuthRequest): Promise<BrowserClearAuthResult>;
|
|
496
|
+
/**
|
|
497
|
+
* Import cookies from a JSON export on disk.
|
|
498
|
+
*
|
|
499
|
+
* The path is read-guarded exactly like browser_upload_file: a prompt-injected
|
|
500
|
+
* path must not turn this into a way to read a file the operator never allowed.
|
|
501
|
+
* A browser cookie export cannot be produced automatically — Chrome and Edge
|
|
502
|
+
* 127+ encrypt cookie values with App-Bound Encryption, so a copied profile
|
|
503
|
+
* yields nothing — which is why this takes a file the user exported.
|
|
504
|
+
*/
|
|
505
|
+
importAuth(session: BrowserSessionId, path: string): Promise<{
|
|
506
|
+
restored: number;
|
|
507
|
+
failed: number;
|
|
508
|
+
}>;
|
|
509
|
+
/** Import cookies into the session (restore login state). Self-hosted only. */
|
|
510
|
+
restoreAuth(session: BrowserSessionId, cookies: readonly ExportedCookie[]): Promise<number>;
|
|
511
|
+
/**
|
|
512
|
+
* Start a background scrape batch.
|
|
513
|
+
*
|
|
514
|
+
* It runs detached on purpose: one tool call has a ~60s budget while a large
|
|
515
|
+
* batch takes minutes. Progress is polled with scrapeStatus, and each row is
|
|
516
|
+
* appended the moment it is produced, so a stopped or interrupted batch keeps
|
|
517
|
+
* everything it managed. `outPath` is write-guarded like any other browser
|
|
518
|
+
* write, and truncated up front so a re-run never mixes two batches.
|
|
519
|
+
*/
|
|
520
|
+
startScrape(session: BrowserSessionId, request: BrowserScrapeRequest): Promise<BrowserScrapeStatus>;
|
|
521
|
+
/** Progress of one batch. */
|
|
522
|
+
scrapeStatus(id: string): Promise<BrowserScrapeStatus>;
|
|
523
|
+
/** Ask a running batch to stop; rows already written stay. */
|
|
524
|
+
stopScrape(id: string): Promise<BrowserScrapeStatus>;
|
|
525
|
+
/** Every batch this process knows about, oldest first. */
|
|
526
|
+
listScrapes(): Promise<readonly BrowserScrapeStatus[]>;
|
|
527
|
+
private scrapeJob;
|
|
528
|
+
/**
|
|
529
|
+
* Visit each URL once, appending one JSONL row per page.
|
|
530
|
+
*
|
|
531
|
+
* Workers pull from one shared index, so `concurrency` sets the throughput
|
|
532
|
+
* without changing the work. Rows therefore land in completion order; each row
|
|
533
|
+
* carries its URL's index as `seq` so the caller can restore the original.
|
|
534
|
+
*/
|
|
535
|
+
private runScrape;
|
|
536
|
+
/** Drop a batch's private tabs (and their views) once the batch is over. */
|
|
537
|
+
private destroyScrapeTabs;
|
|
538
|
+
/** Capture the current page, optionally full-page. PNG only (CDP JPEG hangs on Electron 43). */
|
|
539
|
+
screenshot(session: BrowserSessionId, request?: {
|
|
540
|
+
readonly fullPage?: boolean;
|
|
541
|
+
readonly savePath?: string;
|
|
542
|
+
}, signal?: AbortSignal): Promise<{
|
|
543
|
+
readonly dataUrl: string;
|
|
544
|
+
readonly path?: string;
|
|
545
|
+
}>;
|
|
546
|
+
/** Build the data URL and optionally write the PNG to disk. */
|
|
547
|
+
private saveScreenshot;
|
|
548
|
+
/**
|
|
549
|
+
* Pick up (and forget) any JS dialog the host auto-accepted, so the
|
|
550
|
+
* operation trail shows the human/agent what the page asked. Best-effort.
|
|
551
|
+
*/
|
|
552
|
+
private drainDialog;
|
|
553
|
+
/**
|
|
554
|
+
* Set how the host answers the next JS dialog, and report the resulting state.
|
|
555
|
+
*
|
|
556
|
+
* The policy lives in the host (it answers the CDP event there, where a
|
|
557
|
+
* round-trip would already be too late), so this is a push, not a pull.
|
|
558
|
+
*/
|
|
559
|
+
setDialogPolicy(session: BrowserSessionId, policy: DialogPolicy): Promise<{
|
|
560
|
+
dialog: unknown;
|
|
561
|
+
policy: DialogPolicy;
|
|
562
|
+
}>;
|
|
563
|
+
/**
|
|
564
|
+
* Console messages the host captured for the active tab.
|
|
565
|
+
*
|
|
566
|
+
* Reading does NOT clear by default: debugging is usually a look-again loop, so
|
|
567
|
+
* `clear: true` is explicit. The host keeps a bounded ring, so old entries fall
|
|
568
|
+
* off on their own.
|
|
569
|
+
*/
|
|
570
|
+
consoleMessages(session: BrowserSessionId, options?: {
|
|
571
|
+
limit?: number;
|
|
572
|
+
level?: string;
|
|
573
|
+
clear?: boolean;
|
|
574
|
+
}): Promise<{
|
|
575
|
+
messages: BrowserConsoleMessage[];
|
|
576
|
+
}>;
|
|
577
|
+
/** Network requests the host captured for the active tab (bounded ring). */
|
|
578
|
+
networkRequests(session: BrowserSessionId, options?: {
|
|
579
|
+
limit?: number;
|
|
580
|
+
failedOnly?: boolean;
|
|
581
|
+
urlContains?: string;
|
|
582
|
+
clear?: boolean;
|
|
583
|
+
}): Promise<{
|
|
584
|
+
requests: BrowserNetworkRequest[];
|
|
585
|
+
}>;
|
|
586
|
+
/**
|
|
587
|
+
* Apply device/viewport/media emulation to the active tab.
|
|
588
|
+
*
|
|
589
|
+
* Plain CDP through the existing command path, so no host change was needed.
|
|
590
|
+
* `clear` undoes all three: metrics, user agent, and emulated media.
|
|
591
|
+
*/
|
|
592
|
+
emulate(session: BrowserSessionId, options?: EmulateOptions): Promise<{
|
|
593
|
+
applied: string[];
|
|
594
|
+
}>;
|
|
595
|
+
/**
|
|
596
|
+
* Drain any dialog that opened since the last input call, then report the last
|
|
597
|
+
* one and the current policy.
|
|
598
|
+
*
|
|
599
|
+
* `dialogState` alone is not enough for the tool: the host only hands a dialog
|
|
600
|
+
* over when something drains it, so an inspect that does not drain misses exactly
|
|
601
|
+
* the dialog the caller just triggered. (Found on the real machine.)
|
|
602
|
+
*/
|
|
603
|
+
inspectDialog(session: BrowserSessionId): Promise<{
|
|
604
|
+
dialog: unknown;
|
|
605
|
+
policy: DialogPolicy;
|
|
606
|
+
}>;
|
|
607
|
+
/** The last JS dialog the host reported, plus the current policy. */
|
|
608
|
+
dialogState(session: BrowserSessionId): {
|
|
609
|
+
dialog: unknown;
|
|
610
|
+
policy: DialogPolicy;
|
|
611
|
+
};
|
|
612
|
+
/** Name this browser task (space). */
|
|
613
|
+
setSpace(session: BrowserSessionId, label: string): Promise<void>;
|
|
614
|
+
/** List every browser task (space) with its label. */
|
|
615
|
+
listSpaces(): Promise<readonly BrowserSpaceInfo[]>;
|
|
616
|
+
/** List browser tasks with live collaboration status. */
|
|
617
|
+
listTasks(): Promise<readonly BrowserTaskInfo[]>;
|
|
618
|
+
/** Read the collaboration state for one session's task. */
|
|
619
|
+
getTask(session: BrowserSessionId): Promise<BrowserTaskInfo>;
|
|
620
|
+
/** Apply one visible task state update and mirror it to a supporting host. */
|
|
621
|
+
updateTask(session: BrowserSessionId, update: BrowserTaskUpdate): Promise<BrowserTaskInfo>;
|
|
622
|
+
/** Hand control to the user or return it to Agent-driven actions. */
|
|
623
|
+
setHandoff(session: BrowserSessionId, state: BrowserHandoffState): Promise<BrowserTaskInfo>;
|
|
624
|
+
/** Append one operation to the session's history. */
|
|
625
|
+
private record;
|
|
626
|
+
/** Return the session's chronological operation log (newest last). */
|
|
627
|
+
history(session: BrowserSessionId): Promise<readonly BrowserHistoryEntry[]>;
|
|
628
|
+
/**
|
|
629
|
+
* Replay one recorded operation by sequence number. Navigate/click/type are
|
|
630
|
+
* re-issued against the current page; execute re-runs its script. The
|
|
631
|
+
* replayed step is appended to history as a new entry.
|
|
632
|
+
* @param session - the session id.
|
|
633
|
+
* @param seq - the recorded entry's sequence number to replay.
|
|
634
|
+
*/
|
|
635
|
+
replay(session: BrowserSessionId, seq: number): Promise<void>;
|
|
636
|
+
/** Close the session and destroy all its views. Idempotent. */
|
|
637
|
+
close(session: BrowserSessionId): Promise<void>;
|
|
638
|
+
/** Recover the live session associated with a stable task key. */
|
|
639
|
+
private sessionForTask;
|
|
640
|
+
/** Look up a session or throw the unknown-session error. */
|
|
641
|
+
private session;
|
|
642
|
+
/** The active tab of a session. */
|
|
643
|
+
private activeTab;
|
|
644
|
+
/** Navigate through the browser history while preserving page readiness behavior. */
|
|
645
|
+
private navigateHistory;
|
|
646
|
+
/** Drop every reference that was captured before a document transition. */
|
|
647
|
+
private invalidateSnapshots;
|
|
648
|
+
/** Resolve one exact snapshot reference, rejecting any changed or missing target. */
|
|
649
|
+
private resolveSnapshotTarget;
|
|
650
|
+
/** Sync provider fallback cache from the host's authoritative workspace state. */
|
|
651
|
+
private rememberHostedTask;
|
|
652
|
+
/** Build the provider-side task summary when a host has no richer workspace. */
|
|
653
|
+
private localTaskInfo;
|
|
654
|
+
/** Create a tab with its short-lived snapshot reference store. */
|
|
655
|
+
private createTab;
|
|
656
|
+
/** Append a fresh tab and make it active. */
|
|
657
|
+
private newTab;
|
|
658
|
+
/** Notify the host of the active tab; it preserves the human-selected task view. */
|
|
659
|
+
/**
|
|
660
|
+
* Fire-and-forget host call: these run while the provider keeps going, so a rejection
|
|
661
|
+
* must never escape. Electron's host answers `unknown view` for a handle it no longer
|
|
662
|
+
* knows (a host restart leaves the provider holding stale ones), and an unhandled
|
|
663
|
+
* rejection surfaces as *some other* tool call failing - Ctrl+W did exactly that.
|
|
664
|
+
* The desired end state (view gone) holds either way, so swallowing is right here.
|
|
665
|
+
*/
|
|
666
|
+
private ignoreHostFailure;
|
|
667
|
+
private showActive;
|
|
668
|
+
/** Read the current URL of a view through CDP. */
|
|
669
|
+
private currentUrl;
|
|
670
|
+
}
|
|
671
|
+
/**
|
|
672
|
+
* The in-page half of {@link resolvePointerTarget}: resolve the element, scroll
|
|
673
|
+
* it into view, and return its centre.
|
|
674
|
+
*
|
|
675
|
+
* Exported so it can be exercised. The matching rule — the innermost visible
|
|
676
|
+
* element whose label contains the text wins — is the part most likely to be
|
|
677
|
+
* wrong, and Node has no DOM to check it against.
|
|
678
|
+
*/
|
|
679
|
+
export declare function pointerTargetScript(selector: string | undefined, text: string | undefined): string;
|
|
680
|
+
/**
|
|
681
|
+
* Minimal DOM shape {@link renderMarkdown} reads; a real DOM node fits it.
|
|
682
|
+
*/
|
|
683
|
+
export interface MarkdownNode {
|
|
684
|
+
readonly nodeType?: number;
|
|
685
|
+
readonly tagName?: string | null;
|
|
686
|
+
readonly textContent?: string | null;
|
|
687
|
+
readonly childNodes?: ArrayLike<MarkdownNode> | null;
|
|
688
|
+
readonly href?: string | null;
|
|
689
|
+
readonly src?: string | null;
|
|
690
|
+
readonly alt?: string | null;
|
|
691
|
+
}
|
|
692
|
+
/**
|
|
693
|
+
* Best-effort markdown rendering of a DOM subtree, used by
|
|
694
|
+
* {@link ElectronBrowserProvider.content} for `format: 'markdown'`.
|
|
695
|
+
*
|
|
696
|
+
* Deliberately self-contained (no closures over module state, no imports):
|
|
697
|
+
* the provider embeds this function's source in the page with
|
|
698
|
+
* `Function.prototype.toString`, so the tests exercise the very code the page
|
|
699
|
+
* runs.
|
|
700
|
+
*
|
|
701
|
+
* Block containers (div/p/section/article/li/headings/...) recurse into their
|
|
702
|
+
* children and are joined with newlines, while adjacent inline runs are
|
|
703
|
+
* concatenated — text split by <b>/<span> stays one paragraph, and a container
|
|
704
|
+
* never emits its own `textContent` on top of its children (the old walker did,
|
|
705
|
+
* which flattened real pages — everything is wrapped in divs — to plain text).
|
|
706
|
+
* @param root - the subtree root (an element, or a text node).
|
|
707
|
+
* @returns the markdown text.
|
|
708
|
+
*/
|
|
709
|
+
export declare function renderMarkdown(root: MarkdownNode): string;
|