dsh-inner-browser-use 0.11.44 → 0.13.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.
@@ -1,104 +1,74 @@
1
1
  # Compatibility
2
2
 
3
- What this plugin assumes, and what it degrades to when an assumption fails.
4
-
5
- ## Requirements
6
-
7
- | Capability | Needed for | Missing means |
8
- | --- | --- | --- |
9
- | Desktop app (`dshDesktop.browser`) | Leasing the app's own browser tab | The call answers that the built-in browser is not available; tools stay registered. |
10
- | `sidebar.right.pane.tab` slot | The tab body | Nothing registers; no tab appears in the **+** menu. |
11
- | `ctx.sidebarRightTabs` | Tab type registration | Registration is skipped silently; the tab never appears. |
12
- | `ctx.sidebarRight.openTabIn` | Placing a tab in the column | Tools need the tab opened by hand; the call says so in one sentence. |
13
- | `ctx.webServer.register` | The whole wire | Plugin fails to load, visibly. |
14
- | `ctx.tools.register` | The tool surface | Bridge still runs; the model sees no `browser_*` tools. |
15
- | `EventSource` in the page | Learning that a tab is wanted | Same as the row above. |
16
-
17
- ## What it never touches
18
-
19
- Installing this plugin changes nothing a user already had:
20
-
21
- - Nothing shipped is wrapped or shadowed: the browser tab, its kind, its tools'
22
- behaviour and its partition are the product's; this plugin only drives them.
23
- - No guide card: the `开始` pane renders exactly the entries it had before. A
24
- client test asserts the registered tab type carries no `guide` array.
25
- - No global CSS: every rule is scoped to the page it drives.
26
- - No slot occupant on any slot it does not own, and no `computerUse`/`browserUse`
27
- provider registration, so the shipped browser's own providers keep their seats.
28
- - Removing the bundle removes every one of the above.
29
-
30
- ## Version notes
31
-
32
- - **Node 20+** on the Host. The plugin uses only `node:http`, `node:fs/promises`,
33
- `URL`, and `AbortSignal`.
34
- - **No dependencies.** No bundler, no build step, no post-install script.
35
- - `engines.dsh` is `>= 0.2.0`. Checked against Desktop builds whose sidebar
36
- browser tab kind is `browser` and whose guest handshake is an `about:blank#`
37
- webview carrying the workspace partition; on any other shape the plugin treats
38
- the Desktop bridge as absent rather than guessing.
39
-
40
- ## Coexistence
41
-
42
- - The tab kind is `browser` — the built-in browser's own. This plugin registers no
43
- tab kind of its own.
44
- - The route prefix is `/dsh-inner-browser-use`. Nothing is mounted under `/api`.
45
- - The guest partition is the one the app leases for the workspace
46
- (`dsh-sidebar-browser-<uuid>`). Two plugins leasing the same workspace key share
47
- storage, exactly as two built-in tabs do.
48
-
49
- ## Known limits
50
-
51
- | Limit | Why | Workaround |
52
- | --- | --- | --- |
53
- | A login is kept only if the page can read its cookie | `HttpOnly` cookies are not visible to the page half | Sites that keep the session in a readable cookie come back signed in |
54
- | One storage partition per workspace | The lease key is the workspace CWD | Use one workspace per account you need isolated |
55
- | One chat is on screen at a time | The column shows one chat, so another chat's page does not exist | Open the chat that asks; the call answers in about a second |
56
- | Text-only observations | Frames are JSON over one SSE socket | Use `browser_script` to pull exact values |
57
- | A capture needs that page drawn | The app has no surface to read for a page another tab covers | Bring the chat's tab forward; the call says so |
58
-
59
- ## Downloads land in the chat folder
60
-
61
- The app cancels its own downloads, so a page cannot save a file by itself. The
62
- page half therefore collects what a page offers — an `<a download>`, a `blob:`
63
- address, a `data:` address, or a link whose path ends in an archive, office
64
- document, PDF, text, image or media extension — and hands the bytes to the Host,
65
- which writes them under `<chat folder>/.dsh-inner-browser-use/downloads/`. The
66
- call returns that path, and `browser_download` with no argument prints the files
67
- already collected.
68
-
69
- Limits that come from the page, not from the plugin:
70
-
71
- - One offered file is capped at 7 MB and six are taken in one go; a file the
72
- page could not hand over is named with its size in the answer, so the page can
73
- be asked again. The Host refuses an upload over 8 MB with the size named.
74
- - A page whose `connect-src` forbids the site's own address cannot fetch it; the
75
- plugin then has only what the page already holds, so ask the page for the file
76
- through its own UI.
77
- - A file streams only while the page keeps answering. A page that navigates away
78
- mid-save ends the transfer, and the call says so instead of writing half a file.
79
-
80
- ## Checking an install
81
-
82
- Run these in the chat whose tab is open, in this order. Each line is what a
83
- working install answers.
84
-
85
- 1. `browser_navigate` to `https://example.com/` → title `Example Domain`, one control.
86
- 2. `browser_view` → the same page, so the tab is the one this chat owns.
87
- 3. `browser_script` adding a button, then `browser_click` it → `Clicked #2 [button] clicked at 120,160`.
88
- 4. `browser_screenshot` → a path under `.dsh-inner-browser-use/`, or the sentence
89
- naming the tab to bring forward.
90
- 5. Restart the app once if `browser_selection` answers `unknown tool`: the tool
91
- list is read at start.
92
-
93
- ## A tab that is not the active one
94
-
95
- The strip mounts only the tab it shows, and after a restart the restored tab is
96
- not the active one. Nothing in the tab face switches it: `openTabIn` with
97
- `activate`/`focus`, `focus(id)`, `focus(session, id)`, `active(id)`,
98
- `tab.activate` and `tab.focus` were each tried and left the active tab
99
- unchanged; the tab bar's controls are not inside `sidebarRight.host`, so there is
100
- no element to click.
101
-
102
- A call therefore never depends on that switch. On load, the chat on screen gets
103
- its own tab back and the page it had; every other chat opens nothing, because a
104
- tab lands in the column that is showing.
3
+ What this plugin assumes, and what it does when an assumption fails.
4
+
5
+ | | |
6
+ | --- | --- |
7
+ | Harness | 0.2.0 or newer, with the right column |
8
+ | Runtime | Node 20 or newer |
9
+ | Browser | Google Chrome, Chromium or Canary, 112 or newer |
10
+ | System | macOS 12 or newer; Linux x86_64 or arm64 |
11
+ | License | MIT |
12
+
13
+ ## Where Chrome is looked for
14
+
15
+ The plugin starts a browser it finds at one of these paths, in this order:
16
+
17
+ ```
18
+ /Applications/Google Chrome.app/Contents/MacOS/Google Chrome
19
+ /Applications/Chromium.app/Contents/MacOS/Chromium
20
+ /Applications/Google Chrome Canary.app/Contents/MacOS/Google Chrome Canary
21
+ /usr/bin/google-chrome
22
+ /usr/bin/chromium
23
+ ```
24
+
25
+ That is the whole list. A Chromium kept elsewhere (snap, flatpak, a home directory, a bundled
26
+ runtime) is not found, and there is no setting to point at one. Installing Chrome the ordinary
27
+ way, or placing the binary at `/usr/bin/chromium`, is the supported arrangement.
28
+
29
+ If nothing in the list exists, the first tool call returns `sidecar: no Chrome found on this
30
+ machine` and nothing is written to disk.
31
+
32
+ Chrome 112 is the floor: the mirror needs `--headless=new` and a screencast that survives an
33
+ idle page.
34
+
35
+ ## macOS
36
+
37
+ The browser is launched with `--use-mock-keychain` and `--password-store=basic`, so no keychain
38
+ dialog appears on the person's screen and no password is read from the OS keyring. Chrome's own
39
+ password store inside the profile still works.
40
+
41
+ The profile directory is created under the home directory of whoever runs DSH, which is the
42
+ same user the browser runs as. Running that process as a different user leaves the profile
43
+ unwritable, and running it as root leaves Chrome unable to start its sandbox: run DSH as the
44
+ person using it.
45
+
46
+ ## Linux
47
+
48
+ The two Linux entries above are the same lookup list; put Chrome or Chromium there. The browser
49
+ runs without a display, so no X or Wayland session is needed for the mirror itself.
50
+
51
+ Linux has not been part of the release test pass; macOS is where this plugin is developed and
52
+ checked.
53
+
54
+ ## Windows
55
+
56
+ Not supported. There is no Windows path in the lookup list, and no installation of this plugin
57
+ on Windows has been checked.
58
+
59
+ ## When an assumption fails
60
+
61
+ | Assumption | What happens |
62
+ | --- | --- |
63
+ | No Chrome at a listed path | First tool call returns the error above; no profile, no process. |
64
+ | Harness older than 0.2.0 | The plugin does not load. |
65
+ | A Harness build with no right column | The tools still drive the browser; there is nowhere to show the mirror. |
66
+ | A site that refuses headless | The user agent is replaced with an ordinary desktop Chrome string; a site that insists on a window can be opened with `headless: false`. |
67
+ | A page wider than 1440×900 | The viewport is fixed, so the page lays out for 1440 wide; nothing is scaled. |
68
+ | Two plugin instances, one profile | The second adopts the Chrome already running on that profile rather than starting another. |
69
+ | The debugging file left by a crashed Chrome | It is removed and the browser is started again. |
70
+
71
+ ## Limits by design
72
+
73
+ One page per browser, fixed 1440×900 viewport, no mobile emulation, no downloads, no uploads, no
74
+ script evaluation. The eight tools in the README are the whole surface.
@@ -0,0 +1,108 @@
1
+ <!-- ui-copy-ignore -->
2
+ # Roadmap: from a working mirror to the best computer-use plugin
3
+
4
+ The bar is not "another browser driver". The bar is: an agent can finish a real
5
+ task in this browser with fewer turns, fewer tokens, fewer surprises than with
6
+ Codex, Claude Code, browser-use, Stagehand, Playwright MCP or any screenshot-only
7
+ computer-use model — and the person can watch it happen in the sidebar of the
8
+ chat that asked, while every other chat stays untouched.
9
+
10
+ Written as phases with a number attached, because a phase without a number is a
11
+ wish. Baselines come from `node scripts/bench.mjs`; every phase must move one.
12
+
13
+ ## Where the competition actually wins
14
+
15
+ | Project | What it does well | What it costs |
16
+ | --- | --- | --- |
17
+ | Codex / Claude Code (computer + bash) | free-form shell, one action per turn, human can take over mid-run | no page structure, no refs, screenshots dominate context |
18
+ | browser-use | indexed DOM tree with stable element ids, action model, per-step memory | tree is big; a full read is thousands of tokens |
19
+ | Stagehand | `act` / `observe` / `extract` split, self-healing selectors, natural-language actions | server round trips; two model calls per step |
20
+ | Playwright MCP | accessibility tree with `ref` handles, deterministic waits | text-only; a page read is large; no live picture |
21
+ | Skyvern / CUA screenshot models | works on canvas apps and hostile DOM | ~1 image per step, slow and token-expensive |
22
+
23
+ Our position: **a real Chrome with a live, interactive mirror in the owning
24
+ chat, and a read model that is small by construction** — accessibility refs that
25
+ survive a read, viewport-only text, diffs instead of full re-reads, and one
26
+ batched tool for multi-step work. The mirror is not decoration: it is the human
27
+ takeover surface, and no other plugin can show it inside the asking chat without
28
+ stealing the column from other chats.
29
+
30
+ ## Phase 0 — measurement (done when numbers exist)
31
+
32
+ - `scripts/bench.mjs`: launch→first frame, steady fps, frame KB, read ms /
33
+ chars / approx tokens for a dense page, a text page and a light page, click,
34
+ key, screenshot KB.
35
+ - Record every run in `docs/BENCH.md` with the commit; no phase is "done"
36
+ without a before/after row.
37
+
38
+ ## Phase 1 — read model that costs less (target: dense page read ≤ 1.2k tokens)
39
+
40
+ - Accessibility-tree walk with `ref` handles that stay valid across reads of the
41
+ same page; only elements that exist in the tree get a number.
42
+ - Viewport-limited by default (`inView`), with `mode`: `text` (default),
43
+ `links`, `forms`, `full`; `max_chars` budget; text deduplicated and
44
+ truncation marked, never silent.
45
+ - `changed_only`: after an action, return only added / removed / changed refs —
46
+ the browser-use and Playwright MCP gap.
47
+ - Stable refs: a read re-numbers nothing that did not change, so the model can
48
+ act on numbers from an earlier read and gets a clear "ref 3 is gone, re-read"
49
+ instead of clicking the wrong thing.
50
+
51
+ ## Phase 2 — one call, many steps (target: a login flow in 1 tool call)
52
+
53
+ - `sidecar_do`: ordered steps with per-step waits (`wait_text`, `wait_gone`,
54
+ `wait_idle`, `wait_url`), one result: what changed, the final URL, tokens spent
55
+ on one read instead of five.
56
+ - Auto-wait after every action: navigation start/finish, DOM quiet, and
57
+ `document.readyState`, so the next step never races the page.
58
+ - Ref errors are actionable: which ref, why it is gone, and one call that
59
+ re-reads and retries once.
60
+
61
+ ## Phase 3 — any operation (target: no "can't do that" left)
62
+
63
+ - Hover, drag, double-click, right-click, wheel with modifiers.
64
+ - `select` option by label or value; checkboxes and radios by label.
65
+ - File upload (`DOM.setFileInputFiles`), download capture with a returned path,
66
+ print-to-PDF, full-page and element screenshots.
67
+ - Tabs: new / switch / close / list; iframes addressed by frame id; dialog
68
+ accept/dismiss; `sidecar_eval` for the last 1% of cases; cookies read/write for
69
+ debugging; console + failed requests surfaced in the state read.
70
+ - Keyboard: modifiers, shortcuts, clipboard paste, IME composition unchanged.
71
+
72
+ ## Phase 4 — mirror latency and clarity (target: ≤120 ms input→painted, 60 fps idle)
73
+
74
+ - Adaptive JPEG quality and frame size: drop quality before dropping fps; send a
75
+ small first frame, refine when idle.
76
+ - `Page.startScreencast` tuning (maxWidth/quality/everyNthFrame), Chrome flags
77
+ that stop background throttling, `--disable-frame-rate-limit`.
78
+ - Client: decode off the main thread (`createImageBitmap`), draw only the newest
79
+ frame, no layout thrash, ResizeObserver-driven backing-store sizing for a crisp
80
+ picture at any pane width, DPR-aware.
81
+ - Pointer: keep the 1 ms path; add remote cursor shape to the pane cursor with a
82
+ proper fallback, and a visible "the agent is acting" pulse that never moves the
83
+ system cursor.
84
+
85
+ ## Phase 5 — reliability and safety
86
+
87
+ - Human takeover: typing in the pane pauses the agent's next action and says so;
88
+ a resume action exists.
89
+ - Guarded actions (upload, download, close tab, buy-ish submits) can require a
90
+ confirm flag.
91
+ - Crash recovery: attach to a still-running Chrome, rebuild the page, keep the
92
+ profile; a killed host never leaves a zombie Chrome.
93
+ - Every failure names what happened, what state the page is in, and the next
94
+ call to make.
95
+
96
+ ## Phase 6 — proof and packaging
97
+
98
+ - `docs/BENCH.md` with before/after per phase; a competitor comparison table with
99
+ measured numbers, not adjectives.
100
+ - `docs/VERIFY.md` walk-through that a stranger can run; `scripts/doctor.mjs`
101
+ green; 3 linters zero errors; tests covering every new tool.
102
+ - Packed tarball, CHANGELOG per release, `0.x` bumps that match behaviour.
103
+
104
+ ## Order of work
105
+
106
+ 1. Phase 0 baseline. 2. Phase 1 + 2 together (they share the read model).
107
+ 3. Phase 3 breadth. 4. Phase 4 numbers. 5. Phase 5 hardening. 6. Phase 6 proof,
108
+ then repeat the loop with whatever the numbers say is worst.