dsh-web-search-ddg
aooyoo
Zero-token DuckDuckGo search provider for the DeepSeek Harness (DSH) web seam — local headless browser, no API key, no m…
PROJECT TOPICS
PROJECT README
An out-of-tree DeepSeek Harness plugin that makes the Web GUI faster over slow or high-latency links (ssh -L, nginx, Tailscale, …) without changing a single line of dsh source. It works purely through public Cordis/dsh extension points:
/, /favicon.svg, /manifest.webmanifest, and prefix /assets that shadow the frontend-static fallback (no route collisions) and replicate its observable behavior exactly, while adding negotiated gzip/brotli compression and immutable Cache-Control for content-hashed shell assets./plugins/<entryId> that shadow the /plugins owner for its own entries (longer prefix wins) and serve client.js / client.js.map with compression and immutable caching; the bundle URL already carries ?rev=<content-hash>.<link rel="preload" as="script" fetchpriority="low"> hints through ctx.webServer.tapIndex for stage-one client bundles./api, event streams, sessions, or any other behavior.dsh.bundle.patch: ./cordis.patch.yml, and dsh plugin add reconciles that bundle into dsh.profile.bundles automatically.client.js / client.js.map.webServer the plugin stays idle; with no clientModules it still serves static routes and preload taps; with no frontend dist it skips static routes and still provides bundle routes and preload taps.The numbers below come from the checked-in benchmark harness tests/benches/bench.mjs, not from ad-hoc local commands: run pnpm fetch-harness to clone the pinned upstream deepseek-harness into gitignored vendor/, pnpm build to build this plugin, then pnpm bench. The harness starts dsh web twice on the same free port with fresh throwaway DSH_HOME directories — once unmodified (baseline) and once with the plugin's bundle mounted through a generated temp patch — so the only difference between the two runs is the plugin overlay. The plugin build used the defaults in cordis.patch.yml (compression: gzip+br, immutableCache: true, preloadClientBundles: immediate). The plain node:http pass measures /, shell assets, and every /plugins/*/client.js bundle; the optional Chrome pass (CHROME_PATH=... pnpm bench) loads the same pages through Chrome DevTools Protocol with Network.emulateNetworkConditions at 50 ms RTT / 2 Mbps down and cache disabled. Raw per-route JSON and server logs are written to gitignored results/run-*/, and the tables below are one such run — rerun pnpm bench at any time to reproduce or refresh them.
| Metric | Baseline | With dsh-plugin-perf | Delta |
|---|---|---|---|
| Encoded bytes received | 4,497,240 | 1,025,900 | −77.2 % |
| Request count | 60 | 63 | +3 preload-related fetches under disabled cache |
TTFB of / |
58.1 ms | 56.7 ms | ~same (HTML itself is not on the critical savings path) |
| Time until last plugin bundle | 17,696.9 ms | 4,649.7 ms | −73.7 % |
Total page load (loadEvent) |
17,855.6 ms | 4,842.9 ms | −72.9 % |
| Metric | Baseline | With dsh-plugin-perf | Delta |
|---|---|---|---|
| Encoded bytes | 4,412,820 | 898,770 | −79.6 % |
| Request count | 43 | 43 | unchanged |
TTFB of / |
29.3 ms | 53.1 ms | first-request brotli warm-up |
| Last plugin bundle | 54.2 ms | 1,552.9 ms | first-request compression cost; subsequent requests hit the in-process compression cache |
| Total page load | 57.4 ms | 1,552.9 ms | see the compression-cache note below |
| Route | Baseline TTFB | Plugin TTFB | Encoding added |
|---|---|---|---|
/assets/index-*.js (442 KB raw) |
3818.2 ms | 1938.6 ms | brotli |
/assets/vendor-*.js (745 KB raw) |
4981.7 ms | 2031.6 ms | brotli |
/plugins/.../dsh-client-connection/client.js |
4170.0 ms | 1481.7 ms | brotli |
/plugins/.../dsh-client-trajectory/client.js |
(part of the 17.7 s tail) | 2204.7 ms | brotli |
The remote-access trace showed the page spends almost all of its time waiting on HTTP: dozens of uncompressed, uncacheable JS/CSS responses over HTTP/1.1 with a six-connection limit. The plugin removes the two largest costs without touching logic: compressed bodies shrink the dominant payload by roughly three quarters, and immutable caching (safe because shell assets are content-hashed and plugin bundles are addressed by ?rev=<content-hash>) makes repeat visits revalidate nothing. Preloading the stage-one bundle tier starts plugin fetches while the shell still executes. All of this happens in transport/serving behavior only: route semantics, MIME handling, 404/405 behavior, the boot manifest, and every /api/event-stream path are untouched, and every registration is a reversible Cordis effect.
Known caveats: the loopback HTTP run shows the first plugin-served response pays compression CPU before the compressed-buffer cache warms up; under a real slow link this is negligible compared with the saved transfer time. With the Chrome benchmark's cache disabled, preloads can add three requests; with normal browser caching the preloaded response is reused by the later script fetch.
install.py is a LOCAL-only installer: it never calls dsh plugin, npx, or a registry, and it never edits the profile's own cordis.patch.yml. Every run rebuilds this checkout's host/client bundles, symlinks the package into the profile node_modules, and updates the profile package.json (link: dependency + dsh.profile.bundles). The profile itself must already exist — run any dsh plugin --profile web ... command once to initialize it.
python3 install.py install --profile web
python3 install.py uninstall --profile web
Options are --profile (default $DSH_PROFILE/web) and --home (default $DSH_HOME/~/.dsh). There is no --skip-build or remote spec: local iteration is python3 install.py install then restart dsh. The self-contained bundle patch inserts this row (override it later with a normal profile patch if needed):
- insert:
- id: web-perf
name: dsh-plugin-perf
config:
compression: gzip+br
immutableCache: true
preloadClientBundles: immediate
A restart of dsh --profile web is required after install/uninstall and after rebuilding this plugin's host code. Host-plane changes (webserver routes, index taps, settings registration) load only at process boot: the shipped web profile disables host-side cordis-plugin-hmr (- id: hmr disabled: true in the web-app bundle patch). The plugin now also ships a client bundle, so while pnpm run dev:web runs from the harness checkout the browser can hot-reload client-side changes; host-side iteration remains python3 install.py install (which always rebuilds) followed by a dsh restart.
Installing the bundle also registers a Performance navigation entry in dsh web → 设置(设置 → 性能). It edits the same durable settings document the host reads at startup and exposes: compression mode, immutable cache, preload tier, auto-detect, probe timeout, compression-cache limits, and the log summary switch. All of these fields are registered with applies: restart, so the UI shows a restart note and changes take effect after restarting dsh --profile web; the bundle patch in cordis.patch.yml remains the composition-level default that user settings override.
| Field | Type | Default | Description |
|---|---|---|---|
compression |
'gzip' \| 'br' \| 'gzip+br' \| 'none' |
gzip |
Content-Encoding(s) the plugin may emit when the request accepts them. |
immutableCache |
boolean |
true |
Emit Cache-Control: public, max-age=31536000, immutable for content-addressed shell assets and plugin bundles. |
preloadClientBundles |
'none' \| 'immediate' \| 'all' |
immediate |
Inject <link rel="preload" as="script"> for stage-one (immediately:true) entries, every entry, or no entries. |
cacheMaxEntries |
number |
128 |
Compressed-buffer cache entries. |
cacheMaxBytes |
number |
67108864 |
Total bytes of cached compressed buffers (64 MiB). |
logSummary |
boolean |
false |
Log one bytes-served summary line on unload. |
autoDetect |
boolean |
true |
Probe the official server at startup and skip each optimization point it already implements. |
probeTimeoutMs |
number |
2000 |
Timeout for one official-capability probe request; probe failures keep the plugin enabled. |
All fields are optional and conservative; the schema is exported as Config (Schemastery) and the plugin also works with no config at all.
src/ — the standalone dsh-plugin-perf plugin (this README).tests/benches/ — before/after benchmark harness and report templates; concrete run data stays in gitignored results/.scripts/fetch-deepseek-harness.sh — generic pinned fetch of deepseek-harness into gitignored vendor/ (DEEPSEEK_HARNESS_REPO / DEEPSEEK_HARNESS_REF overridable).analysis/ — trace/session case reports and reusable measurement scripts (trace_analyze.py, session_timeline.py, cdp_bench.py, throttle_proxy.mjs).pnpm install
pnpm build # tsc --noEmit + tsdown
pnpm test # vitest unit tests with fake webserver/clientModules contexts
Unit tests cover route registration/disposal, compression negotiation, cache headers, traversal safety, preload injection, bundle suffix 404/405 semantics, and graph-change resync. No real dsh process is needed.
pnpm fetch-harness # clones vendor/deepseek-harness (gitignored), ref override: DEEPSEEK_HARNESS_REF
pnpm bench # before/after runs with fresh throwaway DSH_HOME dirs
pnpm bench boots dsh web twice on a free port (baseline, then with the plugin mounted through a generated temp patch), measures with plain node:http, and — when Chrome/Chromium is found or CHROME_PATH is set — also runs an optional CDP trace with emulated network conditions (default 50 ms / 2 Mbps, tunable via BENCH_LATENCY_MS / BENCH_DOWNLOAD_KBPS). Metrics: total encoded bytes, request count, per-route TTFB distribution, TTFB for /, time until the last plugin bundle, and total page-load time. Raw data goes to the gitignored results/ directory; methodology and report templates are in tests/benches/reports/.
CLASSIFICATION EVIDENCE
系统优先读取 GitHub Topics,再与站内分类词典和词根规则比对。