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
True hot-loading for dsh web: after installing plugins, editing config, or upgrading dsh itself, see the effect immediately — no more manually restarting from the command line.
English | 简体中文
While using dsh web, I found that DSH has three kinds of changes that require a process restart to take effect — installing/removing/updating plugins (bundle layers are composed at startup), editing profile config (cordis.patch.yml), and upgrading the dsh package itself.
Every time, I had to leave the conversation, go to the command line, re-type dsh web, and refresh the page to see the effect:
This skill syncs "hot reload" and "hot restart" — things that DSH already hot-reloads (skills, AGENTS.md, settings) keep hot-reloading; plugin installs now hot-apply without a restart, and everything that genuinely must restart (config edits, dsh upgrade) is restarted safely and automatically by the agent. dsh web becomes truly hot-loadable: install a plugin in conversation, it's active immediately — no more manual restarts.
Three ways to install, pick any:
① Install via conversation (recommended) — say this in a DSH conversation (include the repo URL so the agent knows where to install from):
The agent installs and loads the skill automatically (skills are hot-loaded — ready immediately, no restart needed).
② One-line install — in your own terminal:
npx -y skills add https://github.com/jifeng15/dsh-web-restart -g -y -a universal --copy
npx skills addinstalls the skill files only (agents use the skill's script path — no command needed). To get thedsh-webcommand in your terminal, run once:bash ~/.agents/skills/dsh-web-restart/install.sh --bin-only(it installs to~/bin/dsh-weband auto-adds~/binto your shell PATH).
③ Clone & manual install — if you want to inspect the source first:
git clone https://github.com/jifeng15/dsh-web-restart.git && cd dsh-web-restart
bash install.sh
Ready after install (see "Two Usage Scenarios" below).
After installing this skill, say in conversation "install plugin XX for me" (XX = any other plugin, e.g. dsh-market) or "upgrade dsh for me". The agent will:
dsh-web install for plugins (hot install, no restart) or dsh-web upgrade for dsh itself — the agent calls the script directly, you never touch the command lineFor: users who manage plugins through DSH conversations. This is the skill's primary scenario — it's designed for agents.
First use note: the very first time you hot-install, the agent automatically installs the hot-install component and restarts once (so it can load) — you just refresh that once. After that, every plugin install is no-restart.
If you prefer the terminal, install/remove plugins with the hot commands (no restart), and use restart for everything else:
dsh-web install <spec> # Install plugin: hot install (no restart) if available, else safe restart
dsh-web remove <pkg> # Remove plugin: hot uninstall if available, else safe restart (refuses CLI-managed — use `dsh plugin --profile web remove`)
dsh-web restart # Fallback/other: safe restart after config edits, dsh upgrade, or when hot apply is unavailable
dsh-web session # Report the resolved tmux session (auto-discovered)
dsh-web status # Check status anytime
Hot first, safe restart as fallback:
install/removetry the bundled dsh-web-hot (no restart, PID unchanged). If hot apply is unavailable (plugin not loaded, module-level code update, or the change can't be hot-applied), they fall back to a safe restart automatically.restartremains the unified command for config edits, dsh upgrade, and migration.Why the "extra step" is unavoidable: the skill's automation trigger is the agent — when you install via conversation, the agent is present and auto-invokes it; but when you install from your own terminal, no agent is involved, so you must run it manually once. This one-time step is worth it: it migrates dsh web into tmux hosting, and after that everything (conversation-driven) is fully automatic.
For: CLI users, script automation, and agent-internal calls. All commands automatically handle tmux hosting, port discovery, and session discovery — no preparation needed.
| ✅ Can | ❌ Can't |
|---|---|
| Hot install/uninstall plugins via bundled dsh-web-hot — no restart (falls back to safe restart if unavailable) | Agent continuing seamlessly after restart — restart briefly disconnects, you refresh (structural limit) |
| Auto-restart dsh web after plugin changes, config edits, or dsh upgrade — no manual commands (conversation) | Hot-apply module code updates (Node require cache — must restart) |
reload takes effect after editing profile config (cordis.patch.yml) |
Auto-recover after reboot (you re-run dsh-web start once) |
| No tmux? Auto-installs it (macOS/Linux package managers) | Auto-upgrade non-npm/pnpm dsh installs (only hints) |
dsh web running in a plain terminal? Auto-migrates into tmux (run dsh-web start/restart, or enable the watchdog for fully automatic takeover) |
Skill additions, AGENTS.md edits, etc. (these already hot-reload; not needed here) |
Session not named dsh-web? Auto-discovers the hosting session |
Crash auto-restart is a separate opt-in (run-loop) |
Port not 3080? Auto-discovers (incl. --port 0 random ports) |
— |
| All terminals closed — dsh web keeps running, restartable anytime | — |
In one line: install/uninstall plugins without restarting (hot), and for everything that genuinely must restart (config edits, dsh upgrade, migration), it restarts safely and keeps dsh web resident — you just refresh after the brief disconnect.
dsh-web install <spec> # ★ Install plugin: hot install (no restart) if available, else safe restart
dsh-web remove <pkg> # ★ Remove plugin: hot uninstall if available, else safe restart (refuses CLI-managed — use `dsh plugin --profile web remove`)
dsh-web restart # ★ Fallback/other: unified safe restart after plugin changes, config edits, or dsh upgrade
dsh-web start # Start / auto-takeover (create session if none, migrate into tmux if unmanaged)
dsh-web stop # Stop
dsh-web status # Check session/port/PID/logs
dsh-web attach # Enter tmux for troubleshooting
dsh-web autostart-on # Enable autostart at login (default OFF, user opt-in; launchd/systemd)
dsh-web autostart-off # Disable autostart
dsh-web autostart-status # Check autostart status
dsh-web watchdog-on # Enable launchd watchdog: every 30s, auto-migrate any unmanaged dsh web into tmux (default OFF)
dsh-web watchdog-off # Disable watchdog
dsh-web watchdog-status # Check watchdog status
dsh-web repair # Fix config: same-file duplicate ids, ghost bundles, cross-source duplicates (auto-backup first)
dsh-web health-check # Check port + config tree — is it a process or a config problem?
dsh-web preflight # Boot self-check (auto-run by start/restart): clear cross-source duplicates
Hot install first, safe restart as fallback:
dsh-web install/removetry the bundled hot-plugin (dsh-web-hot) first — installing/uninstalling plugins without a restart. If hot apply is unavailable (plugin not loaded, or the change can't be hot-applied), it falls back to a safe restart automatically.dsh-web restartremains the unified command for everything else (config edits, dsh upgrade, migration).One owner per plugin (single-source): a plugin is mounted from exactly one source — either
dsh plugin --profile web add|remove(thedsh.profile.bundleslist) or hot install (thecordis.patch.ymlpatch layer), never both. If the same plugin ends up in both (e.g. an externaldsh plugin addadopts a previously hot-installed one),preflight(auto-run bystart/restart) andrepairdetect it and drop the patch-layer rows automatically — the next boot can't crash withduplicate loader entry id. On the remove side,dsh-web removerefuses CLI-managed plugins (it would leave a ghost bundle) and points todsh plugin remove.
Autostart is optional and OFF by default — the skill never enables autostart on its own. Run
dsh-web autostart-onwhen you want dsh web to start in tmux after login.
Port notification policy: after
start/restart, the actual port is written to~/.dsh/logs/last-port.txt. If the port is the default (3080), no notification (everyone knows it); if non-default (occupied/random), a system notification shows the actual port — especially useful for unattended autostart.
dsh-web watchdog-on installs a launchd LaunchAgent that checks every 30 s:
if dsh web is listening but not hosted in tmux (e.g. you started it in a
plain terminal), it automatically migrates it into tmux — so after that,
closing the terminal never kills dsh web, no matter how you started it.
The watchdog only migrates a running web; it never starts a stopped one.
Disable with dsh-web watchdog-off. macOS only (Linux systemd timer: future).
| Item | Default | Override |
|---|---|---|
| tmux session name | dsh-web (auto-discovered if not found) |
DSH_WEB_SESSION |
| Port | auto-discovered (explicit config > process --port > process listen port > node scan > default 3080) |
DSH_WEB_PORT |
| Launch command | dsh web |
DSH_CMD |
--port 8080 or --port 0 (random) — the script parses the actual port from the process command line or listening socket.tmux kill-server: reopen dsh web however you like — dsh-web start is easiest (creates tmux + starts + hosts in one step); plain dsh web also works, first restart auto-migrates into tmux (one extra migration, then fully automatic).tmux run-shell -b "sleep 3; tmux send-keys -t dsh-web C-c; sleep 2; tmux send-keys -t dsh-web 'dsh web' Enter"
tmux server is an independent daemon — it doesn't depend on dsh web being alive. Even if the caller (agent) dies with dsh web, the restart still completes.
| Component | Role |
|---|---|
scripts/dsh-web.sh |
Main CLI (start/restart/install/remove/upgrade/status/session/autostart-*) |
hot-plugin/ (dsh-web-hot) |
Host plugin: hot install/uninstall via include.update (no restart) |
scripts/run-loop.sh |
Crash auto-restart loop (3-strike circuit breaker) |
scripts/install-tmux.sh |
Cross-platform tmux auto-install |
install.sh |
One-shot install (skill + CLI + hot-plugin + tmux) |
dsh-web.sh install <spec>
→ POST /dsh-web-hot/install {spec}
→ pnpm add <spec> (profile dir, official registry)
→ read bundle's dsh.bundle.patch → patch rows
→ write cordis.patch.yml (user patch layer, persistent)
→ include.update (hot apply, PID unchanged)
→ record dsh-web-hot.state.json
→ {"ok": true}
dsh-web.sh restart
→ resolve_session (discover actual session, e.g. "0")
→ tmux run-shell -b "sleep 3; C-c; sleep 2; 'dsh web'"
→ tmux server executes independently (completes even if agent dies)
→ 5-8s later dsh web restarts; user refreshes
dsh plugin --profile web add (the bundle list) and hot install (the user patch
layer) both feed include entries into the same loader, whose entry ids must be
unique. If the same plugin ends up in both sources, the next boot dies with
duplicate loader entry id. This project enforces one owner per plugin:
dsh.profile.bundles (install-time guard);preflight (auto-run by start/restart) and repair detect cross-source
duplicates — entry ids declared by bundles ∩ patch-layer rows — and drop the
patch-layer rows (bundles side is authoritative), syncing dsh-web-hot.state.json;dsh-web-hot plugin self-heals at startup for running-process drift (HMR
reloads, manual state edits), hot-unmounting rows via include.update.So an external dsh plugin add that adopts a previously hot-installed plugin is
auto-reconciled before the next boot — no manual cleanup needed.
| Dep | Use | If missing |
|---|---|---|
| tmux | hosting + independent restart | auto-installed |
| pnpm | plugin install (via dsh-web-hot) | hot install degrades to safe restart |
| dsh CLI | install.sh hot-plugin install | hot-plugin skipped |
| curl/lsof/ps/pgrep | probing | — |
tmux run-shell -bnohup ... & background tasks get cleaned up when the caller's turn ends → use tmux serverintegrity → use github:owner/repo#refMIT
ensureWorkspaceAllowed now merges into dsh-market's allowBuilds
object style (name → boolean, incl. its "set this to true or false" template)
instead of overwriting it with our legacy list format. Both tools can now
write the same file without clobbering each other.install.sh installs the dsh-web command and auto-adds its bin dir to
your shell PATH (previously the command was installed but not found).dsh-web watchdog-on: a launchd LaunchAgent checks every 30 s — if dsh
web is listening but not hosted in tmux (e.g. you started it in a plain
terminal), it auto-migrates it into tmux. So no matter how you start dsh web,
closing the terminal no longer kills it. Opt-in (default OFF), managed with
watchdog-status / watchdog-off. The watchdog only migrates a running web —
it never starts a stopped one.start auto-takeover (plain-terminal dsh web → tmux) now creates an empty
tmux session first and launches dsh web only after the old process is stopped and
the port is free. Previously the new instance started immediately and fought the
old one for the port (EADDRINUSE), burning the run-loop's 3-strike breaker.dsh-web remove <pkg> now refuses plugins managed by dsh plugin (present
in dsh.profile.bundles) and points you to dsh plugin --profile web remove <pkg>.
The old fallback removed the dependency but left the bundle entry behind (ghost
bundle). One owner per plugin, now enforced on the remove path too.duplicate loader entry id crash (same plugin mounted via both dsh.profile.bundles and the
hot-install patch layer) is now prevented and auto-repaired:dsh-web repair runs a new cross-source check first: entry ids declared by
bundles ∩ patch-layer rows → drops the patch-layer duplicates (bundles side
is authoritative) and syncs dsh-web-hot.state.json.dsh-web preflight (boot self-check) — start/restart run it before
launching, so an external takeover (e.g. dsh plugin add adopting a
hot-installed plugin) can never crash the next boot.dsh-web-hot startup self-heal — the host plugin drops patch rows for any
hot-managed bundle that dsh.profile.bundles has since adopted (covers
running-process drift / HMR reloads).repair / health-check / auto config backup are now documented
here too (they shipped in v2.0.1 but the README wasn't synced).dsh-web repair: dedup duplicate ids, remove ghost bundles, resync
dsh-web-hot.state.json; auto-backup before any config change (keeps last 10).dsh-web health-check: port readiness + config tree (--dump-config) —
tells you whether it's a process or a config problem.dsh.profile.bundles (prevents the
duplicate loader entry id crash from the hot-install side).dsh-web-hot host plugin hot-applies patch rows via include.update
at runtime; the PID never changes.dsh-web install <spec> (hot first, fallback to safe restart),
dsh-web remove <pkg> (hot first, fallback to safe restart).dsh-web session: report the resolved tmux session (auto-discovered, never
assumes dsh-web).CLASSIFICATION EVIDENCE
系统优先读取 GitHub Topics,再与站内分类词典和词根规则比对。