npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

dsh-web-search-chrome

v0.1.1

Published

Free Google search provider for the DeepSeek Harness web seam (ctx.web): drives local Chrome through the agent-browser CLI (headless, --profile) with no paid search API

Readme

dsh-web-search-chrome

npm version CI License Node

A free search provider for the DeepSeek Harness web capability seam (ctx.web). It drives your local Chrome through the agent-browser CLI — headless by default, with a persistent --profile directory — and needs no paid search API and no API key.

  • Provider id: local-chrome
  • Search engine: Bing by default (engine: bing), Google available via engine: google (Google is frequently gated by IP-reputation anti-bot walls on VPN/datacenter networks; Bing tolerates them far better — see docs/decisions-010.md §D7)
  • Model-facing web_search tool: zero changes — switching the seam's searchProvider is a one-line patch.
  • Every result carries url + title + snippet (+ best-effort publishedAt), exactly the shape dsh-web defines.

⚠️ Privacy (read first): search terms are sent to the search engine from your machine, enter the local Chrome profile's history, and are subject to the engine's normal tracking. Searches run in a dedicated new tab that is closed when the search finishes; your existing tabs are never touched. There is no login state in 0.1 — a fresh, dedicated profile directory is used.

How it works

dsh agent's web_search tool (unchanged)
        ↓ ctx.web.search()
dsh-web-search-chrome  (provider id: local-chrome)
        ↓ serialized subprocess calls
agent-browser CLI  (≥ 0.34.0)
        ↓ --profile <path>  [--headed]
local Chrome  →  bing.com/search?q=<query>&count=<n>&setlang=<hl>   (engine: google → google.com/search)
        ↓ SERP extraction (in-page JS, per-engine selectors)
title / url / snippet / publishedAt  →  WebSearchSource[]

Per search: open a new labeled tab → wait for the DOM → extract the SERP → close the tab. Searches are strictly serialized (one browser instance, one search at a time). Results are cached: in-session (same query returns instantly) and on disk (JSON + TTL, default 24 h).

Installation

Prereq: a DeepSeek Harness (dsh) installation. This is a dsh plugin — it runs inside dsh's ctx.web seam, so install dsh first if you have not: npm install -g @deepseek-ai/dsh (or run it ad-hoc via npx @deepseek-ai/dsh).

Two ways — pick one:

  • Manual (§1–§3 below): explicit commands, good for pinning exact options.
  • Automated via a dsh agent (§4): hand a task to a dsh agent; it installs everything and writes the patch with your real paths (no placeholder edits).

1. Install the CLI and a browser

agent-browser is the only runtime dependency (it bundles/installs Chrome for Testing itself):

npm install -g agent-browser        # ≥ 0.34.0
agent-browser install               # downloads Chrome for Testing
  • Windows (native or WSL): install agent-browser with npm on Windows; WSL can also use it through interop automatically (see Cross-platform notes below).
  • Linux: agent-browser install downloads Chrome for Testing. If Chrome fails to launch, run agent-browser install --with-deps (system libraries) — on minimal distros install nss/nspr/alsa-lib and make sure the loader can find them (see the launch check below).
  • macOS: install Chrome or run agent-browser install.

🔍 Verify Chrome can actually launch — agent-browser doctor is NOT enough. Doctor only checks that the CLI and browser binary exist; it does not load the browser, so missing shared libraries go unnoticed until the first search. Do a real launch before configuring dsh — with no agent-browser daemon running (after a reboot, or pkill -f agent-browser-linux):

agent-browser open example.com      # must print the URL, NOT "Chrome exited early"
agent-browser close --all

⚠️ Why "stop the daemon first": Chrome is spawned by the agent-browser daemon, which inherits the environment of the process that first starts it. A resident daemon can mask a missing-library problem (searches keep working until the daemon dies or the machine reboots), so the check above is only conclusive on a cold daemon.

If it fails with error while loading shared libraries: libnspr4.so (or similar), install the libraries (nss/nspr/alsa-lib; e.g. apt install libnss3 libnspr4 libasound2 on Debian/Ubuntu, pacman -S nss nspr alsa-lib on Arch, or a Homebrew brew install nss nspr alsa-lib) and make sure the process that launches dsh can find them — the daemon is first started by the dsh process on its first search. Export the library path in the shell that starts dsh, or use a wrapper:

# ~/bin/dsh-web — wrapper for distros whose libs live off the loader path
#!/bin/sh
export LD_LIBRARY_PATH="<lib-dirs>:$LD_LIBRARY_PATH"   # e.g. $(brew --prefix nss)/lib:$(brew --prefix nspr)/lib:$(brew --prefix alsa-lib)/lib
exec npm exec @deepseek-ai/dsh web "$@"

2. Install the plugin into a dsh profile

dsh plugin --profile <p> add dsh-web-search-chrome

3. Patch the profile (one line switches the seam)

In <DSH_HOME>/profiles/<p>/cordis.patch.yml (e.g. ~/.dsh/profiles/web/cordis.patch.yml):

- insert:
    - id: web-search-chrome
      name: dsh-web-search-chrome
      config:
        profilePath: /home/you/.dsh-web-search-chrome/profile   # ⚠️ replace /home/you with your real home

- id: web
  config:
    searchProvider: local-chrome        # ← the one-line switch (PRD §8.1)

⚠️ profilePath must be a real, writable path on your machine. The shipped docs/enable-local-chrome.patch.yml uses the placeholder /home/you/...replace it before applying (a literal /home/you directory will not exist and every search will fail with Chrome profile not found).

profilePath is required in 0.1. Use a dedicated directory — it is created on first use. Pointing it at your real Chrome profile (e.g. Default) enables login-state reuse at your own risk; that path is officially v1.1.

⚠️ The switch takes effect on the next profile start. The profile's patch watcher hot-applies cordis.patch.yml to a running process, but plugin modules are cached per process — a live switch to local-chrome cannot load into an already-running process. A ready-to-apply patch file ships at docs/enable-local-chrome.patch.yml: copy it over <DSH_HOME>/profiles/<p>/cordis.patch.yml, then restart the profile.

Verify the composition without booting:

dsh --profile <p> --dump-config | grep -A3 searchProvider   # → local-chrome

Final smoke test (do this after the restart): ask the agent to run a web_search once and confirm it returns real results (e.g. "Use web_search for 'deepseek harness' and report the URLs"). This exercises the full chain (tool → seam → provider → Chrome → engine); the earlier checks only prove config wiring. Requires the profile to have an agent session (the web GUI or a headless-configured profile does).

4. (Alternative) Let a dsh agent install it for you

Instead of the manual steps above, hand the task below to a dsh agent — in the web GUI chat, or one-shot headless:

dsh --profile headless "Install and enable dsh-web-search-chrome for a dsh profile.

1. Detect the platform (WSL vs native, Linux/macOS/Windows).
2. Install the agent-browser CLI if missing: 'npm install -g agent-browser', then
   'agent-browser install' (add --with-deps on Linux if Chrome fails to launch).
   VERIFY CHROME CAN ACTUALLY LAUNCH (doctor is not enough — it misses missing
   shared libraries): run 'agent-browser open example.com' then 'agent-browser
   close --all'. If it fails with 'error while loading shared libraries',
   install nss/nspr/alsa-lib and make sure the dsh process finds them (export
   LD_LIBRARY_PATH in the shell that starts dsh, or use a wrapper script).
3. Install the plugin: 'dsh plugin --profile <profile-name> add dsh-web-search-chrome'.
4. Write \$DSH_HOME/profiles/<profile-name>/cordis.patch.yml (default \$DSH_HOME is
   ~/.dsh). Use the CURRENT USER'S REAL home directory in profilePath — never a
   literal /home/you:

   - insert:
       - id: web-search-chrome
         name: dsh-web-search-chrome
         config:
           profilePath: <real-home>/.dsh-web-search-chrome/profile
   - id: web
     config:
       searchProvider: local-chrome

5. Verify without booting: 'dsh --profile <profile-name> --dump-config' must show
   the web-search-chrome row and 'searchProvider: local-chrome'.
6. Report to the user: the switch takes effect on the NEXT profile start (plugin
   modules are cached per process), so they must restart the profile; after the
   restart a web_search should return results.
Do NOT restart the profile yourself unless the user asks."

The agent performs all steps with shell access and resolves the real profilePath itself, so the /home/you placeholder trap is avoided. Requires the profile's agent preset to have shell tooling enabled (the standard preset does).

⚠️ Concurrency note. The one-shot headless form boots a second dsh process on the same $DSH_HOME as any running profile. If the web GUI is up, prefer pasting the task into the GUI chat; if you use dsh --profile headless while the GUI is running, shared storage writes can race (observed crashing the running GUI). Stop the GUI first, or give the headless run an isolated DSH_HOME (e.g. DSH_HOME=/tmp/… dsh --profile headless "…").

Configuration

| Key | Default | Meaning | |---|---|---| | agentBrowserPath | agent-browser | Executable: a bare name resolved through PATH, or a full path (e.g. a Windows-side exe used from WSL). | | profilePath | required | Chrome profile directory passed to --profile. Created if missing. | | engine | bing | Search engine: bing or google. Bing is the default (far more tolerant of VPN/datacenter IPs); google is available where it works. | | headed | false | Show the Chrome window (--headed) instead of headless. | | hl | en | Engine interface/result language (hl for Google, setlang for Bing). | | num | 10 | Upper bound of results requested from the engine. | | timeoutMs | 20000 | Hard per-search timeout. | | cacheTtlMs | 86400000 | Disk-cache TTL; 0 disables the disk cache (session cache always stays on). | | queueConcurrency | 1 | Serial queue — 0.1 supports exactly 1. | | cachePath | OS cache dir | Disk-cache file override (~/.cache/dsh-web-search-chrome/cache.json on POSIX, %LOCALAPPDATA%\dsh-web-search-chrome\cache.json on Windows). |

Full reference: docs/configuration.md · docs/README.md (documentation index).

Errors (English, actionable — no fallback engine)

| Situation | Message (example) | |---|---| | agent-browser missing | agent-browser CLI not found. Install with: npm install -g agent-browser (>= 0.34.0) | | version too old | agent-browser 0.33.0 is too old; 0.34.0 or newer is required. Upgrade with: npm install -g agent-browser@latest | | profile unusable | Chrome profile not found at "<path>" and could not be created: … / … is not writable. Fix permissions … | | Chrome already running on the profile | Chrome is running. Close all Chrome windows before searching, or point profilePath at a dedicated profile directory. | | engine captcha/anti-bot | Bing returned a captcha/consent page. Open a browser on this network and solve it once, or enable headed mode (headed: true). | | engine consent | Bing returned a consent page. Accept the consent dialog once in a browser on this network, or enable headed mode (headed: true). | | timeout | Search timed out after 20000ms. | | no results | No search results found for query. |

There is deliberately no automatic fallback to another engine — a failure is reported so you can act on it (PRD §2).

Cross-platform notes

  • Resolution order for the agent-browser binary: configured full path → PATH lookup → (WSL detected) Windows npm global via interop (/mnt/c/Users/<user>/AppData/Roaming/npm/agent-browser*) → actionable error.
  • Windows native: install agent-browser with npm on Windows; PATH lookup finds agent-browser.cmd.
  • WSL: either a Linux agent-browser on PATH, or the Windows one through interop (both work; agentBrowserPath can pin the full path).
  • macOS/Linux: plain PATH lookup.

Tested scope (honest)

  • Tested (0.1): WSL2 (Linux) end-to-end — Chrome for Testing via agent-browser, headless + --profile, SERP extraction pipeline for both Bing (default, live E2E verified: model → web_search → real results) and Google (fixture-verified; live on networks Google doesn't gate), cache, queue, error semantics, and the full ctx.web seam with the model-facing web_search tool; Windows interop binary resolution (this box's PATH hit the Windows npm global). Also verified in a live dsh web profile (searchProvider switched to local-chrome, model web_search returning real Bing results through the plugin).
  • Not yet end-to-end tested (v1.1 per PRD): native macOS/Linux desktops and Windows-native dsh. The code paths are platform-neutral (spawn + PATH), but they are marked untested.
  • Anti-bot: Bing tolerates VPN/datacenter IPs well (verified live); Google may serve its "unusual traffic" interstitial to browser traffic on flagged networks — the plugin reports it as an actionable error (engine: google users: reduce frequency ≥ 30 s between searches, use a persistent profile, or route through a residential proxy; solving the interstitial once in headed mode also helps).

Development

Requirements: Node.js ≥ 22 and pnpm (the toolchain — tsdown, vitest 4, pnpm 11 — does not support older Node).

pnpm install
pnpm run build            # tsdown → single-file lib/index.js + lib/index.d.ts
pnpm run typecheck        # tsc --noEmit (strict)
pnpm run lint             # ESLint 9 + typescript-eslint
pnpm test                 # vitest unit tests (self-contained)
pnpm run test:live        # live engine test (needs agent-browser + browser)
pnpm run verify-extraction # runs the SERP extraction pipeline against local fixtures in real Chrome
node scripts/e2e-live.mjs bing   # live engine E2E through ctx.web (bing|google)

The build shape mirrors the deepseek-harness packages: TypeScript source in src/, one tsdown bundle (fixedExtension: falselib/index.js) plus a bundled lib/index.d.ts; node builtins and @deepseek-ai/* stay external.

  • The SERP extraction selectors live in exactly one place: src/serp.ts (EXTRACTION_SCRIPT, engine-adaptive — Bing #b_results / Google #search a:has(h3)). Engine DOM changes are absorbed there.
  • Full documentation index: docs/README.md — configuration reference, §10 decision records (incl. the Bing-default decision §D7), and the M3 acceptance record.

License

MIT — see LICENSE. agent-browser is an external Apache-2.0 CLI; no license contamination.