On load, ensures the Playwright browser target (default: chromium) is installed via `npx --yes playwright install chromium --with-deps` (background when missing, so profile startup is not blocked), then symlinks the installed binary at /usr/local/bin/google-chrome-stable (+ chromium). That exact name is what dsh-ego-browser's PATH scan and its bundled --no-sandbox wrapper both look for, so root/Docker containers get a working agent browser with zero manual PATH, env-var or wrapper steps. Pre-existing user binaries/wrappers are never clobbered. Ships as a dsh bundle (plain ESM, no build step); install via `dsh plugin --profile web add github:<you>/dsh-browser-install#main` and update with `dsh plugin --profile web update` (branch ref resolves the tip).
122 lines
7.6 KiB
Markdown
122 lines
7.6 KiB
Markdown
# dsh-browser-install
|
|
|
|
Automatically installs **Playwright Chromium** (`npx playwright install chromium --with-deps`) into the Docker container running DeepSeek Harness, and bridges the installed binary onto `PATH` so the **dsh-ego-browser** side-bar plugin finds it — no manual "find the binary / symlink it / set `EGO_LINUX_*` env vars / wrap it with `--no-sandbox`" steps for agents ever again.
|
|
|
|
## Why this plugin exists
|
|
|
|
`dsh-ego-browser` discovers its browser the following way (see `lib/index.js` → `resolveEgoEnv` and `runtime/ego-linux/src/chrome.mjs`):
|
|
|
|
1. It scans `PATH` + fixed locations for `google-chrome`, `google-chrome-stable`, `chromium`, `chromium-browser`, … and
|
|
2. on **root** hosts (docker default), it hands the found binary to a bundled `--no-sandbox` wrapper that only looks at fixed paths (`/usr/bin/*`, `/opt/google/...`, `/usr/local/bin/google-chrome-stable`, `/snap/bin/chromium`).
|
|
|
|
Playwright installs Chromium into `~/.cache/ms-playwright/chromium-<rev>/chrome-linux{,64}/chrome` — a location **invisible to both scans**. That is why agents kept having to hunt the binary down, symlink/wrap it, and set `EGO_LINUX_CHROME` / `EGO_LINUX_EXTRA_ARGS` by hand.
|
|
|
|
This plugin does exactly that bridging once, automatically:
|
|
|
|
- on load it checks the Playwright cache (idempotent, no-op when the browser is already there),
|
|
- if the browser is missing it runs `npx --yes playwright install chromium --with-deps` **in the background** (profile startup is never blocked for minutes), and
|
|
- it then symlinks the installed binary at `/usr/local/bin/google-chrome-stable` and `/usr/local/bin/chromium` — the exact names ego-browser's PATH scan *and* its bundled `--no-sandbox` wrapper look for. On this root container, the chain then resolves to: root detected → bundled `--no-sandbox` wrapper → `--no-sandbox` launch; no `DISPLAY` → automatic headless. **No env vars, no manual wrapper, no agent steps.**
|
|
|
|
Nothing is ever clobbered: a pre-existing system Chrome or a user wrapper keeps winning (the plugin only creates links where nothing of its own/an external binary exists).
|
|
|
|
## Install (from git — recommended)
|
|
|
|
Replace `<you>` with your GitHub account name:
|
|
|
|
```sh
|
|
dsh plugin --profile web add github:<you>/dsh-browser-install#main
|
|
```
|
|
|
|
- The `#main` **branch ref is what makes updates work**: `pnpm update` re-resolves the branch tip (verified against pnpm 12.8.1), so after you push new commits simply run
|
|
|
|
```sh
|
|
dsh plugin --profile web update # all deps
|
|
dsh plugin --profile web update dsh-browser-install # just this one
|
|
```
|
|
|
|
- Bundle changes only become active after a profile restart: `dsh --profile web`.
|
|
- No build step: the bundle ships plain ESM and declares no `prepare` script, so pnpm's default block on git-dependency build scripts never applies — nothing to `allowBuilds` in `pnpm-workspace.yaml`.
|
|
- pnpm installs git deps over HTTPS, so keep the repo public (or set up credentials on the host).
|
|
|
|
## Alternative: install from a local checkout
|
|
|
|
```sh
|
|
dsh plugin --profile web add /root/workspaces/Plugin\ Development/dsh-browser-install
|
|
```
|
|
|
|
A directory install is a symlinked `file:` dependency — handy while iterating. For persistent installs and updates, prefer the git flow above.
|
|
|
|
## Restart and verify
|
|
|
|
Restart the profile, then check the plugin loaded and did its job:
|
|
|
|
```sh
|
|
dsh --profile web
|
|
```
|
|
|
|
```sh
|
|
dsh --profile web --dump-config | grep -A3 browser-install
|
|
ls -la /usr/local/bin/google-chrome-stable # -> .../ms-playwright/chromium-*/chrome-linux64/chrome
|
|
```
|
|
|
|
Then from any agent session, `ego_doctor` should report a browser binary, and `ego_space_open`/`ego_navigate` work with no environment prep.
|
|
|
|
> Non-root hosts: set `symlinkDir` to a directory on your `PATH` (e.g. `~/.local/bin`). On root only `/usr/local/bin` is needed — it also satisfies the bundled `--no-sandbox` wrapper's absolute-path list.
|
|
|
|
## Config
|
|
|
|
All fields are optional. Override them in your profile's `cordis.patch.yml` (or in the bundle row's `config`):
|
|
|
|
```yaml
|
|
- id: browser-install
|
|
name: "dsh-browser-install"
|
|
config:
|
|
withDeps: true # run `--with-deps` (apt system deps); needs root/apt
|
|
target: chromium # chromium | chromium-headless-shell | chrome
|
|
package: playwright # npx package spec, e.g. "playwright@1.54.1"
|
|
forceInstall: false # always re-run the install on load
|
|
installOnStartup: true # install in background when the browser is missing
|
|
cacheDir: "" # empty = $PLAYWRIGHT_BROWSERS_PATH | ~/.cache/ms-playwright
|
|
symlinkDir: /usr/local/bin
|
|
symlinkNames: [google-chrome-stable, chromium]
|
|
installTimeoutMs: 600000
|
|
```
|
|
|
|
| Field | Default | Meaning |
|
|
|---|---|---|
|
|
| `installOnStartup` | `true` | Run the Playwright install when the plugin loads **and** no matching browser is found. The install runs in the background so profile startup is not blocked. |
|
|
| `forceInstall` | `false` | Always run the install on load, even when a browser is already present (e.g. after a Playwright upgrade). |
|
|
| `package` | `playwright` | Package spec passed to `npx --yes <package> install ...`. Pin with e.g. `playwright@1.54.1`. |
|
|
| `target` | `chromium` | Which Playwright browser to ensure: `chromium` (full build), `chromium-headless-shell`, or `chrome` (Google Chrome). Default matches what ego-browser expects. |
|
|
| `withDeps` | `true` | Pass `--with-deps` so Playwright also installs the browser's system dependencies via apt (requires root; the DSH image runs as root). |
|
|
| `cacheDir` | auto | Playwright browsers cache root. Empty = `$PLAYWRIGHT_BROWSERS_PATH`, else `~/.cache/ms-playwright`. When set here, the installer child also gets `PLAYWRIGHT_BROWSERS_PATH`. |
|
|
| `symlinkDir` | `/usr/local/bin` | Directory for the PATH links; must be on the DSH process `PATH`. |
|
|
| `symlinkNames` | `[google-chrome-stable, chromium]` | Link names to create. `google-chrome-stable` is the one ego-browser's PATH scan and its `--no-sandbox` wrapper both check. |
|
|
| `installTimeoutMs` | `600000` | Max time for the background install before it is killed. |
|
|
|
|
## Behaviour notes
|
|
|
|
- **No-clobber links:** a link whose target lives inside the Playwright cache is treated as ours and refreshed to the newest installed revision; any other existing file/symlink is left untouched (and wins).
|
|
- **Lifecycle:** the background installer child is killed if the plugin is unloaded mid-install (`ctx.effect`). The PATH links are intentionally *not* removed on unload — a running browser may be using them and they are harmless, idempotent shared state.
|
|
- **Error visibility:** install failures, symlink errors, and a `symlinkDir` missing from `PATH` are all logged loudly under the `dsh-browser-install` logger scope, so an agent can read the reason instead of guessing.
|
|
- **ego-browser settings untouched:** the plugin does not modify dsh-ego-browser's config or any `EGO_LINUX_*` env vars — it only fills the gap (install + visible symlink) that makes ego-browser's existing auto-adaptation work (root → `--no-sandbox` wrapper, no DISPLAY → headless).
|
|
|
|
## Uninstall
|
|
|
|
```sh
|
|
dsh plugin --profile web remove dsh-browser-install
|
|
```
|
|
|
|
The symlinks are left in place (harmless; the browser keeps working for ego-browser). Remove them manually if you truly want them gone:
|
|
|
|
```sh
|
|
rm -f /usr/local/bin/google-chrome-stable /usr/local/bin/chromium
|
|
```
|
|
|
|
## Development
|
|
|
|
Pure helpers (`resolveCacheDir`, `resolveBrowserBinary`, `planSymlinks`, `applySymlinkPlan`, `buildInstallCmd`) are exported for testing; the plugin itself needs no build step (plain ESM, no TypeScript compile).
|
|
|
|
- Node ≥ 22 (the harness image ships v24).
|
|
- Requires DSH ≥ 0.1.2-rc.1 (same baseline as dsh-ego-browser).
|
|
- Runtime dependency: `@deepseek-ai/schemastery` (already present in the profile). |