Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions README.i18n.yaml
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
# Bilingual consistency record for the repository README files.
# README.md is the default English page; README.zh.md is its Chinese counterpart.
# Values are git blob hashes from the last confirmed-consistent review.
README.md: 1163cc9c9a7332a95f8b2448461243f0813ffdf2
README.zh.md: 6ce7a8314f10dcd45316906f79991e0604b0814c
README.md: 56dca7702cba4338131609d12c549fcf224e3ae1
README.zh.md: f6d2956c563b368203c7e434ef069c9342e27be9
3 changes: 2 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -148,7 +148,8 @@ Local Chrome use requires no configuration; Firefox requires the local bridge to

- Make sure dsh web is running locally (default `http://127.0.0.1:3080`).
- Verify the bridge is loaded: open `http://127.0.0.1:3080/ext/bridge-config`. It should return JSON such as `{"wsUrl":"ws://127.0.0.1:3080/ext/bridge"}`. If it returns a web page instead of JSON, the running dsh predates the bridge registration — restart dsh and refresh the page; the extension reconnects on its own.
- The extension probes ports 3080, 3081, 3090, and 14389 automatically. If dsh runs on another port — or you use a remote `--host 0.0.0.0` deployment — set the address (and bridge token) in the panel settings. Firefox always requires the token.
- Discovery runs once when the panel opens. A filled-in address is tried first; if a **loopback** address does not answer, the panel makes one automatic pass (last working URL → `dsh web` defaults → the plugin's fixed beacon ports 43189–43198 → one sweep of the platform's ephemeral port range). When that pass finds nothing the status reads **No service found** and nothing retries until you reopen the panel or press **Detect**.
- DSH Desktop assigns a random local Web port on every launch, which is why the bridge plugin also listens on a fixed loopback beacon port. If the panel cannot find it, open **Settings → Detect** to list every local instance and click the one to use; the address can still be typed by hand. Remote `--host` deployments need the address and token filled in manually; Firefox always requires the token.

## Development

Expand Down
3 changes: 2 additions & 1 deletion README.zh.md
Original file line number Diff line number Diff line change
Expand Up @@ -148,7 +148,8 @@ Chrome 本机使用无需配置;Firefox 需要填写上述本地桥 token。

- 确认本机 dsh web 正在运行(默认 `http://127.0.0.1:3080`)。
- 确认桥接已加载:浏览器打开 `http://127.0.0.1:3080/ext/bridge-config`,应返回类似 `{"wsUrl":"ws://127.0.0.1:3080/ext/bridge"}` 的 JSON。如果返回的是网页而不是 JSON,说明当前运行的 dsh 早于桥接注册——重启 dsh 并刷新页面即可,扩展会自动重连。
- 扩展会自动探测 3080/3081/3090/14389 端口。若 dsh 运行在其它端口,或使用 `--host 0.0.0.0` 远程部署,请在面板设置中填写地址与桥接 token。Firefox 始终需要 token。
- 面板打开时探测一次:已填地址优先尝试;回环地址连不上时再自动探测一次(上次成功的地址 → `dsh web` 默认端口 → 插件的固定信标端口 43189–43198 → 扫描系统临时端口区间)。都没找到时状态显示「未找到服务」,在重新打开面板或点「自动检测」之前不会重试。
- DSH Desktop 每次启动都会重新随机分配本地 Web 端口,所以桥接插件同时监听一个固定回环信标端口。面板找不到时,打开**设置 → 自动检测**列出本机所有实例,点击其中一条即可填入地址;地址仍可手动填写。远程 `--host` 部署需要手动填写地址和 token;Firefox 始终需要 token。

## 开发

Expand Down
4 changes: 2 additions & 2 deletions extensions/dsh-browser/README.i18n.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -2,5 +2,5 @@
# side as of the last confirmed-consistent state. Both languages carry equal authority;
# after editing either side, bring the other along and re-record with:
# pnpm run verify-translation-pairing --write dsh-browser/extensions/dsh-browser/README.md
README.md: 6b6ea0b302a340fca44d6f461ebf84a7b5419c89
README.zh.md: 36f25412f7e1431aa89a8ac41ef045c9b7676790
README.md: 15ab9e04efa09d46679fa24d82170bbe7dd33fb9
README.zh.md: 0c056575a7a2f1bb197f24adba35f80c0ede671c
55 changes: 53 additions & 2 deletions extensions/dsh-browser/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ The **browser-operation end** of dsh: the model reads and operates the browser p

**Two explicit channels**: browser pages are still rendered as structured text (a numbered interactive-element inventory), so browser tools never take screenshots. Separately, a dsh 0.1.2 host can advertise multimodal image limits; the side panel then accepts PNG, JPEG, WebP, and GIF attachments and renders their durable history references.


## What the model can do

| Capability | Action | Notes |
Expand All @@ -21,6 +22,9 @@ The **browser-operation end** of dsh: the model reads and operates the browser p
| Close tab | `browser_close_tab` | Close a listed tab |
| Read region | `browser_get_text` | Lazy-loaded content / partial text |
| Wait | `browser_wait` | Page load and render-settle detection |
| Inspect elements / CSS | `browser_devtools_elements` / `browser_devtools_set_element_style` / `browser_devtools_set_element_attribute` | High privilege: computed styles, box model, matched rules, live CSS and attribute edits for debugging |
| Run page JavaScript | `browser_console_eval` / `browser_console_logs` | High privilege: evaluate in the page's own context and read recorded console output |
| Capture network | `browser_devtools_network` / `browser_devtools_list_requests` / `browser_devtools_get_request` / `browser_devtools_request_body` | High privilege: captured request list, per-request detail, and bodies (credential headers redacted by default) |
| Chat with images | `session.prompt` / `session.attachment` | Host-gated image selection, image-only sends, and durable history previews |
| Quote what you highlight | side panel composer | The text you select in the page becomes a quote in the composer and rides along with your next message |

Expand Down Expand Up @@ -95,7 +99,7 @@ The recommended zero-configuration command does not require Git or a local clone

Both commands load the same bundle from the local `web` profile. Port 3080 is used by default; append `--port <port>` when it is occupied.

**DSH Desktop users**: the Desktop app assigns a random local Web port by default (`dsh-desktop.port: 0`), so port-based auto-discovery cannot predict it. Pin the port to `43189` in Desktop settings (see the [deepseek-harness-desktop user guide](https://github.com/anywhere-labs/deepseek-harness-desktop/blob/master/docs/user-guide.en.md)); auto-discovery covers that port. Alternatively, enter `http://127.0.0.1:<port>` manually in the side-panel settings.
**DSH Desktop users**: the Desktop app launches its host with `--port 0`, so the OS assigns a different local Web port on every start and no fixed port list can predict it. The bridge plugin therefore also listens on a fixed loopback discovery beacon (`43189`–`43198`, first free port) that advertises the real bridge URL. Discovery runs once when the panel opens: a filled-in address is tried first, and only a loopback address that does not answer falls back to one automatic pass. When nothing is found the status reads "No service found" and nothing retries; open **Settings → Detect** to list every local instance and pick one, or type `http://127.0.0.1:<port>` by hand. To pin the port instead, override the `webserver` row in `~/.dsh/profiles/desktop/cordis.patch.yml` — patch `config` is replaced wholesale, so repeat `host` as well.

Loading or reloading the extension is passive: it does not probe local ports or open a WebSocket until the side panel is opened. A healthy connection established by the user may remain available for background approvals after the panel closes, but it will not reconnect without an open panel if it drops or another browser replaces it.

Expand All @@ -105,6 +109,42 @@ Pages that were already open before extension installation or reload are instrum

For extension-only development, load `extensions/dsh-browser/dist/` from `chrome://extensions`, or run `build:firefox` and load `extensions/dsh-browser/dist-firefox/manifest.json` from `about:debugging#/runtime/this-firefox`. Rebuild and reload after code changes.

## Composer controls: permission, model, commands, and skills

The composer carries the same controls the Web GUI exposes, backed by Host
methods the bridge owns:

- **Permission preset** (left chip): the deployment's preset table
(`read-only`, `workspace-write`, `danger-full-access`, plus `auto` when the
experimental Auto integration is mounted) with the Session's current value.
Selecting a preset runs the Host's own `/permission <preset>` command, so the
`permission/preset` selection and both knob events land in the Session log
exactly as a Web GUI selection would. `Full access` and `Auto review` ask for
an explicit confirmation first; a derived `custom` state is shown but never
selectable, and the menu footnotes the default for future chats. Before the
first message creates the chat, the choice is remembered and applied at
materialization, before that first prompt is admitted.
- **Model and reasoning effort** (right chip): the Session's model directory
grouped by provider, plus the reasoning efforts the selected model declares
(`Default` included). A selection only shapes the **next** assembled turn, so
the chip stays usable while a turn is running. When the directory cannot be
read, the row says why and offers a retry instead of going silently grey; a
missed `turn/end` is repaired from the Host's `running` flag the next time the
panel becomes visible.
- **`/` menu**: typing `/` in an empty line opens the Host command directory
(`/compact`, `/permission`, `/plan`, `/goal`, `/feedback`, `/export`, …) and
the Session's user-invocable skills, including skills marked
`modelInvocable: false` (badged `User only`) that exist precisely for explicit
invocation. `↑`/`↓` move, `Enter`/`Tab` accept, `Esc` closes; picking a row
inserts its exact text so its input stays editable. On submit the panel
arbitrates exactly like the Host adapter: a command name runs through
`commands.execute` (its output never becomes a model message), a skill name is
sent as a literal prompt so the Host injects its instructions, and an
unrecognized `/…` line is **refused** with the draft preserved — start the
line with a space to send it as ordinary text. Commands take no attachments
here, and neither is a provisional chat's directory browsable: it answers
empty until the first message creates the real Session.

## Why browser operation stays text-only

- **Snapshot as the view**: the model's entire view of the page is structured text (title/URL/main/numbered elements/forms), budgeted at 32k chars by default (plugin-configurable, negotiated to the extension via `hello.ok`).
Expand All @@ -117,13 +157,24 @@ For extension-only development, load `extensions/dsh-browser/dist/` from `chrome
- **Unrestricted control is explicit**: **Allow unrestricted browser control** becomes active only after the setting is saved successfully, then lets page reads, page actions, and tab list/follow/close operations run without confirmation. Calls capture their access mode when received, so enabling unrestricted control never retroactively elevates an existing restricted call. Disabling it takes effect immediately, cancels calls that have not dispatched an action, waits for already-dispatched browser operations to settle, and only then saves the restrictive setting. A rapid re-enable remains restricted until that revocation finishes, and concurrent saves persist in request order. Protected-page DOM content remains inaccessible.
- **Conversation continuity**: reopening the panel resumes the most recently active browser conversation by default, falling back to the latest non-empty durable session before creating a new one. This can be disabled in Settings.

## Developer tools (opt-in, high privilege)

The developer-tools group drives the controlled tab through the Chrome debugger protocol (`chrome.debugger`), so it can inspect and edit page elements and CSS, run JavaScript in the page's own context, and capture network traffic — including response bodies, which page-level interception cannot read reliably.

- **Off by default**: every developer-tools call raises its own approval dialog. The dialog has its own heading and can allow once, trust the group for the current side-panel session, or deny. The blanket **Allow unrestricted browser control** switch and the persistent origin allowlist never cover this group.
- **Turn it on deliberately**: **Allow developer tools** in Settings is the only way to run these calls without a per-call prompt. Turning it off detaches the debugger immediately and cancels in-flight devtools calls; the session-scoped grant is cleared the moment the setting changes.
- **One debugger per tab**: Chrome refuses a second debugger, so the browser's own DevTools cannot stay open on the same tab while capture is attached. The tool result explains this and tells you to close DevTools on that tab.
- **Data handling**: capture is in memory only, bounded to 200 requests and 500 console entries, and resets on attach and on every top-level navigation. `Authorization`, `Cookie`, `Set-Cookie`, and similar header values are shown as `[redacted]` unless a call explicitly opts in, and bodies of authentication-shaped URLs are redacted by default.
- **Platform**: Chrome only. The Firefox build does not request the `debugger` permission, so the host never registers the group there.

## Permissions

Chrome uses `sidePanel`; Firefox uses `sidebar_action`. Both request `storage` (settings and recent-session continuity), `notifications` (optional reminders for approvals received while the panel is closed), `tabs` + `activeTab` + `scripting` (observe tab changes and inject/message the explicitly controlled tab, including lazy recovery for pages opened before install), `webNavigation` (enumerate and bind messages to that tab's frame documents), `alarms` (background keepalive), and `http/https` (content-script injection on normal pages). Firefox's AMO manifest declares the browsing activity, website content/activity, and personal communications that the add-on sends to the configured dsh/model service. The extension never changes the visible tab or silently follows a manual switch; background operation happens only after the user chooses to stay on the original tab.
Chrome uses `sidePanel`; Firefox uses `sidebar_action`. Both request `storage` (settings and recent-session continuity), `notifications` (optional reminders for approvals received while the panel is closed), `tabs` + `activeTab` + `scripting` (observe tab changes and inject/message the explicitly controlled tab, including lazy recovery for pages opened before install), `webNavigation` (enumerate and bind messages to that tab's frame documents), `alarms` (background keepalive), and `http/https` (content-script injection on normal pages). Chrome additionally requests `debugger`, which is what the opt-in developer-tools group needs; the Firefox manifest omits it, so the group stays unavailable there. Firefox's AMO manifest declares the browsing activity, website content/activity, and personal communications that the add-on sends to the configured dsh/model service. The extension never changes the visible tab or silently follows a manual switch; background operation happens only after the user chooses to stay on the original tab.

## Known limitations

- Only one extension connection at a time. An unopened browser profile never claims it; if another open panel replaces a live connection, the replaced client yields instead of starting a reconnect fight.
- Developer tools are Chrome-only, need the user's setting or a per-call approval, and cannot attach while the browser's own DevTools is open on the same tab. Attaching shows Chrome's "being debugged" banner for that tab until the call finishes or the setting is turned off.
- Tab affinity is global to that extension connection rather than per chat session.
- Accessible cross-origin iframes are snapshotted and operated with stable `(frame, index)` addresses. Restricted or short-lived frames are reported as unavailable without failing the whole page snapshot.
- Captcha/image-only controls cannot be handled — the tool result reports "elements with no accessible name" and asks the user to complete that step manually.
Expand Down
Loading