dsh-builtin-browser 0.4.1 → 0.4.5

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 (57) hide show
  1. package/CHANGELOG.md +1699 -0
  2. package/README.en.md +114 -33
  3. package/README.md +108 -32
  4. package/client.js +478 -29
  5. package/cordis.patch.yml +21 -0
  6. package/desktop-bridge/install.mjs +66 -6
  7. package/desktop-bridge/plugin-browser-bridge.js +426 -167
  8. package/docs/architecture.md +14 -4
  9. package/docs/tool-reference.md +13 -13
  10. package/docs/user-guide.md +58 -3
  11. package/docs/why-browser.md +1 -1
  12. package/lib/browser/types.d.ts +34 -3
  13. package/lib/browser-electron/bridge-connection.d.ts +49 -26
  14. package/lib/browser-electron/bridge-connection.js +185 -22
  15. package/lib/browser-electron/desktop-bridge-host.d.ts +69 -36
  16. package/lib/browser-electron/desktop-bridge-host.js +151 -86
  17. package/lib/browser-electron/entry.d.ts +1 -1
  18. package/lib/browser-electron/entry.js +133 -40
  19. package/lib/browser-electron/ephemeral-profile.d.ts +37 -0
  20. package/lib/browser-electron/ephemeral-profile.js +146 -0
  21. package/lib/browser-electron/history-store.d.ts +36 -2
  22. package/lib/browser-electron/history-store.js +76 -7
  23. package/lib/browser-electron/host-main.js +86 -28
  24. package/lib/browser-electron/provider.d.ts +106 -3
  25. package/lib/browser-electron/provider.js +407 -60
  26. package/lib/browser-electron/remote-host.d.ts +52 -3
  27. package/lib/browser-electron/remote-host.js +259 -25
  28. package/lib/browser-electron/rpc-ops.d.ts +18 -0
  29. package/lib/browser-electron/rpc-ops.js +36 -0
  30. package/lib/browser-electron/settings-route.d.ts +28 -0
  31. package/lib/browser-electron/settings-route.js +68 -0
  32. package/lib/browser-electron/settings-store.d.ts +40 -0
  33. package/lib/browser-electron/settings-store.js +160 -23
  34. package/lib/browser-electron/system-browser.d.ts +102 -12
  35. package/lib/browser-electron/system-browser.js +411 -51
  36. package/lib/index.js +0 -1
  37. package/lib/tool-browser/element-fields.d.ts +145 -0
  38. package/lib/tool-browser/element-fields.js +152 -0
  39. package/lib/tool-browser/index.js +149 -74
  40. package/package.json +10 -4
  41. package/scripts/verify-host-compat.mjs +195 -0
  42. package/src/browser/types.ts +34 -3
  43. package/src/browser-electron/bridge-connection.ts +179 -22
  44. package/src/browser-electron/desktop-bridge-host.ts +146 -84
  45. package/src/browser-electron/entry.ts +132 -39
  46. package/src/browser-electron/ephemeral-profile.ts +152 -0
  47. package/src/browser-electron/history-store.ts +81 -9
  48. package/src/browser-electron/host-main.ts +115 -36
  49. package/src/browser-electron/provider.ts +492 -69
  50. package/src/browser-electron/remote-host.ts +276 -38
  51. package/src/browser-electron/rpc-ops.ts +41 -0
  52. package/src/browser-electron/settings-route.ts +87 -0
  53. package/src/browser-electron/settings-store.ts +173 -24
  54. package/src/browser-electron/system-browser.ts +408 -39
  55. package/src/index.ts +3 -2
  56. package/src/tool-browser/element-fields.ts +167 -0
  57. package/src/tool-browser/index.ts +155 -76
@@ -20,8 +20,13 @@ export interface ElectronBrowserViewHost {
20
20
  * Create a new browser view and return a handle to its webContents-like
21
21
  * surface. The host owns windowing (adding the view to the window, sizing,
22
22
  * removal); the provider owns CDP-driven behavior.
23
+ * @param owner - the conversation this view serves. A host shared by several conversations
24
+ * needs it to keep one conversation's page out of another's; a host with one conversation per
25
+ * process may ignore it. It is per VIEW and not per host on purpose: the desktop's host is a
26
+ * single instance that every conversation runs through, so an owner held there would be one
27
+ * conversation's id applied to all of them.
23
28
  */
24
- createView(): ElectronViewHandle;
29
+ createView(owner?: string): ElectronViewHandle;
25
30
  /**
26
31
  * Destroy a view created by this host. Called on session close; idempotent
27
32
  * for an already-destroyed view.
@@ -61,6 +66,18 @@ export interface ElectronBrowserViewHost {
61
66
  * of failing only at first use.
62
67
  */
63
68
  available?(): boolean;
69
+ /**
70
+ * Tell the human that a toolbar action the agent could not complete has failed.
71
+ *
72
+ * Optional. Declared rather than reached through a cast because this is what issue #16 was:
73
+ * the call used to be unbound, so `this` inside the host's implementation was undefined and
74
+ * its first statement threw — inside an async catch, which turned it into an unhandled
75
+ * rejection that took the whole DSH process down. A declared member is checkable; a cast is
76
+ * not.
77
+ * @param windowId - the window the action came from.
78
+ * @param message - what to show the human.
79
+ */
80
+ notifyUserActionError?(windowId: string, message: string): void;
64
81
  /**
65
82
  * Optional: associate a view with a window group. Views grouped under the
66
83
  * same `windowId` share one window (one window per browser session); a host
@@ -96,7 +113,12 @@ export interface ElectronBrowserViewHost {
96
113
  * (settings: ui.closeWithSession) has to be asked for explicitly there.
97
114
  * @returns a promise that settles once the release was attempted.
98
115
  */
99
- releasePage?(): Promise<void>;
116
+ /**
117
+ * Release this carrier's browser pages for one conversation.
118
+ * @param owner - the conversation whose pages to close. Omit to close every conversation's,
119
+ * which is only correct from a teardown that is itself global.
120
+ */
121
+ releasePage?(owner?: string): Promise<void>;
100
122
  /**
101
123
  * Fold the carrier's presentation away while keeping the page alive.
102
124
  *
@@ -175,6 +197,42 @@ export interface ElectronViewHandle {
175
197
  * then behaves exactly as before.
176
198
  */
177
199
  focus?(): Promise<void>;
200
+ /**
201
+ * Save a URL straight to disk, when the backing view can do that itself.
202
+ *
203
+ * Optional. Declared here rather than reached through a structural cast at the call site:
204
+ * a cast tells the compiler nothing, so a host that implements the interface without this
205
+ * method compiles and then silently does nothing.
206
+ * @param url - the URL to fetch.
207
+ * @param savePath - where to write it.
208
+ */
209
+ download?(url: string, savePath: string): Promise<void>;
210
+ /**
211
+ * Export this view's cookies. Optional; see {@link download} for why it is declared.
212
+ * @returns the cookies, scoped to the view's own page.
213
+ */
214
+ flushAuth?(): Promise<readonly ExportedCookie[]>;
215
+ /**
216
+ * Import cookies into this view. Optional.
217
+ * @param cookies - the cookies to write.
218
+ * @returns how many were accepted.
219
+ */
220
+ restoreAuth?(cookies: readonly ExportedCookie[]): Promise<number>;
221
+ /**
222
+ * Capture this view natively, returning the image and its measured size.
223
+ *
224
+ * Optional. The size is part of the contract because the caller's own tool schema declares
225
+ * `width`/`height`; a host that can measure the image should say so here rather than leaving
226
+ * the provider to guess.
227
+ * @param opts - format, quality and downscale bounds.
228
+ * @returns the encoded image and the pixel size the caller will receive.
229
+ */
230
+ capture?(opts?: ScreenshotOptions): Promise<{
231
+ base64: string;
232
+ mime: string;
233
+ width?: number;
234
+ height?: number;
235
+ }>;
178
236
  }
179
237
  /** Provider config: navigation admission defaults and snapshot caps. */
180
238
  export interface ElectronBrowserProviderConfig {
@@ -204,7 +262,16 @@ export interface ElectronBrowserProviderConfig {
204
262
  readonly settings?: () => BrowserSettings;
205
263
  /** Maximum snapshot elements before truncation. Default 60. */
206
264
  readonly snapshotMaxElements?: number;
207
- /** Maximum content characters before truncation when no maxChars is given. Default 100_000. */
265
+ /**
266
+ * Explicit content cap, overriding the per-format default when set.
267
+ *
268
+ * Honoured again, and it is worth saying why that is a fix rather than a feature: this was
269
+ * `config.contentMaxChars ?? 100_000`, one number for every format, and when the caps became
270
+ * per-format (html and json 50 000, otherwise 20 000) the field was left assigned and never
271
+ * read. A configuration knob that silently does nothing is worse than no knob — it is an
272
+ * operator's decision that quietly went nowhere. Leaving it unset means the per-format
273
+ * default; setting it means the operator meant it.
274
+ */
208
275
  readonly contentMaxChars?: number;
209
276
  /**
210
277
  * Directory `browser_download` save paths must resolve inside (prevents a
@@ -390,8 +457,26 @@ export declare class ElectronBrowserProvider implements BrowserProvider {
390
457
  * Chromium drops `Input.*` events for a view with no display surface, so this
391
458
  * runs before click/type/key and fails loudly (BROWSER_VIEW_NOT_PRESENTED)
392
459
  * rather than reporting a success the page never saw.
460
+ * @param s - the session whose active view must be presented.
461
+ * @param signal - optional cancellation.
462
+ * @returns the view the session's active tab has AFTER the presentation barrier.
393
463
  */
394
464
  private present;
465
+ /**
466
+ * Refuse to send synthesized input to a view that is no longer the one it was located
467
+ * against.
468
+ *
469
+ * `locateHandle` was captured before a page-side locate that can consume its whole
470
+ * 10s budget; the session's active tab is re-read afterwards. If they differ, the human
471
+ * switched tabs mid-flight (the product's whole point is that they can take over), and
472
+ * the coordinates belong to one page while the dispatch would go to another. Comparing
473
+ * the handles turns that into a loud, retryable error instead of input the caller
474
+ * believes landed.
475
+ * @param session - the session id, for the message.
476
+ * @param locateHandle - the view the locate ran in.
477
+ * @param liveHandle - the view that is active now.
478
+ */
479
+ private assertSameView;
395
480
  /**
396
481
  * Give the view web focus before synthesizing keyboard input.
397
482
  *
@@ -498,6 +583,22 @@ export declare class ElectronBrowserProvider implements BrowserProvider {
498
583
  * of text (`a@href` yields an absolute URL).
499
584
  */
500
585
  scrape(session: BrowserSessionId, request: BrowserScrapeRequest, signal?: AbortSignal): Promise<BrowserScrapeResult>;
586
+ /**
587
+ * Refuse an action the settings have switched off.
588
+ *
589
+ * These switches belong to the OPERATOR. The settings document is written through the
590
+ * plugin's own panel and no tool can reach it, so — unlike `browser_restrict`, which the
591
+ * model owns and can lift at will — a refusal here stands for as long as the setting does.
592
+ * That is the point of them: a deployment can take page-script execution, downloads, or
593
+ * login-state writes off the table without relying on the model's cooperation.
594
+ *
595
+ * Read through `settingsSource` on every call rather than captured at construction, so
596
+ * flipping a switch applies to the next command instead of the next restart — the same
597
+ * rule the credentials gate follows.
598
+ * @param action - which switch to consult.
599
+ * @throws BrowserError when that switch is off.
600
+ */
601
+ private assertActionAllowed;
501
602
  /**
502
603
  * Admit a caller-supplied save path for a file the browser writes to disk.
503
604
  * ONE gate for both `browser_download` and `browser_screenshot`: the path
@@ -540,6 +641,8 @@ export declare class ElectronBrowserProvider implements BrowserProvider {
540
641
  screenshot(session: BrowserSessionId, request?: BrowserScreenshotRequest, signal?: AbortSignal): Promise<{
541
642
  readonly dataUrl: string;
542
643
  readonly path?: string;
644
+ readonly width?: number;
645
+ readonly height?: number;
543
646
  }>;
544
647
  /**
545
648
  * Build the data URL and optionally write the image to disk. The caller's