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
AI-managed SSH connections with a live multi-tab terminal panel for DeepSeek Harness.
SSH terminal panel + AI connection manager for DeepSeek Harness (DSH).
The AI agent can autonomously create, address, and tear down SSH connections
right from the conversation (ssh_connect / ssh_exec / ssh_list /
ssh_status / ssh_disconnect / ssh_exec_read / ssh_exec_kill /
ssh_delete), while a XShell/Uniterm-style multi-tab terminal panel in the
Web GUI shows every command — model and human — in real time on the same
screen.
ssh_exec on a saved
name automatically re-establishes the connection from its saved settings.ai | user — connections created by the AI are ai;
connections created from the Settings page are user. The AI can never see
or touch user connections (ssh_list hides them; ssh_exec/ssh_status/
ssh_disconnect/ssh_delete reject them explicitly). A one-way
user → ai transfer (with explicit confirmation, also offered under the
tab bar for a user-created active tab) grants the AI access to a live
connection without disconnecting it.ssh_disconnect, Settings "Disconnect" button). A
"reconnected — the shell state was reset" notice is shown after an
automatic reconnect.ai
connection, keystrokes are dropped server-side with a visible "AI is
executing…" hint; a model ssh_exec against a connection whose shared
terminal shell is still active waits until the shell falls quiet (no
output/input for shellQuietWaitMs, default 2 s) or returns a readable
"busy" result instead of interleaving output. user connections are never
mutexed.ssh_disconnect keeps the tab open showing "disconnected" (one
click to reconnect); a model connect that has no tab re-opens one
automatically. The tab bar's "+" opens saved connections — each pick
opens a fresh tab/session, even when that connection is already connected
in another tab — or starts a manual entry.user@host:path$,
input echo and cd updates all come from the remote shell, exactly like a
native SSH client. There is no input box and no copy control — click
the terminal and type; keystrokes go straight into the remote shell
(arrows, Tab, Ctrl-C, paste, IME supported). A blinking block cursor shows
while the terminal is focused. AI-run commands appear in the same
scrollback with source tags. Multi-tab, ANSI colors, scrollback.dsh-ssh settings namespace (heartbeat, reconnect
policy, timeouts, output caps, records path) can be overridden through the
DSH settings system / profile patch.pnpm-lock.yaml)web profilescripts/test-acceptance.mjs)# from npm (recommended)
dsh plugin --profile web add @jmcc-guo/dsh-ssh
# or directly from GitHub
dsh plugin --profile web add "github:jmcc-guo/dsh-ssh#v0.1.3"
# or from a local checkout
dsh plugin --profile web add <path-to-this-repo>
The bundle patch (cordis.patch.yml) mounts the dsh-ssh row. Override
config in the profile patch with the same row id:
- id: dsh-ssh
config:
heartbeatIntervalMs: 20000
reconnectMaxAttempts: 8
outputLimitBytes: 2097152
Restart the profile process afterwards (plugin-set changes and the client bundle graph are composed at boot).
ssh2 and its full dependency closure are shipped bundled inside the
package (bundleDependencies), so installing @jmcc-guo/dsh-ssh never runs
dependency build scripts: no allowBuilds edits, no
ERR_PNPM_IGNORED_BUILDS. ssh2 runs on its pure-JS implementation, which is
fully functional (verified against a real SSH server); the optional native
crypto binding is intentionally not compiled.
pnpm peers check may report "missing peer" for the @deepseek-ai/* packages
even though DSH provides them: with the hoisted profile layout, external
plugins resolve host packages at runtime from the shared profiles/node_modules
tree, which pnpm's static peer check does not cross. The warnings are benign —
the plugin loads fine (verified at runtime).
dsh-ssh)| Key | Default | Meaning |
|---|---|---|
heartbeatIntervalMs |
30000 | ssh2 keep-alive interval |
keepaliveCountMax |
3 | keep-alive failures before the connection is considered dead |
connectTimeoutMs |
15000 | SSH handshake / TCP connect timeout |
reconnectBaseDelayMs |
2000 | first auto-reconnect delay (doubles per attempt) |
reconnectMaxDelayMs |
60000 | backoff cap |
reconnectMaxAttempts |
5 | max automatic reconnect attempts |
execTimeoutMs |
120000 | default ssh_exec completion wait |
busyWaitTimeoutMs |
20000 | default mutex wait when the connection is busy |
reconnectWaitTimeoutMs |
30000 | default wait while reconnecting |
shellQuietWaitMs |
2000 | shared-shell silence required before AI may run |
outputLimitBytes |
1048576 | per-connection terminal buffer cap |
execOutputMaxBytes |
200000 | cap on output returned to the model per command |
recordsPath |
$DSH_HOME/storages/dsh-ssh/connections.json |
records file override |
ssh_connect — create a new AI connection (host/port/user + auth by
credential reference or key file path) or re-establish an existing one.ssh_exec — run a command on an AI connection by name; auto-reconnects
when offline, waits through reconnect/busy states (with timeouts), returns
output + exit code; long commands return an execId for
ssh_exec_read / ssh_exec_kill.ssh_exec_read — incremental output of a running (or finished) command.ssh_exec_kill — terminate a running command (SIGINT through the pty).ssh_list — AI-visible connections with live status (never user ones).ssh_status — detailed status of one AI connection.ssh_disconnect — explicit disconnect (no auto-reconnect; optional
delete); the panel tab stays open showing "disconnected".ssh_delete — delete a saved AI connection record (disconnects first).Secret rule for the model: never pass passwords or private keys inline in
tool arguments (they are recorded verbatim in the session log and rejected).
Use auth.passwordRef / auth.privateKeyRef (a stored credential or
environment variable) or auth.privateKeyPath (a key file on the host).
New secrets can be stored through the panel's connection form, which routes
them into the DSH credential store.
/ssh/ws) applies the harness browser-trust fence:
loopback/trusted-host Host, same-origin Origin, cross-site fetch-metadata
rejection.ai-source connection the host drops
keystrokes (input mutex).lib/index.js plugin entry: config schema, manager + tools + panel channel wiring
lib/manager.js SshManager — connection lifecycle, keep-alive/reconnect, mutex, PTY shells
lib/tools.js model tools (ssh_connect / ssh_exec / ssh_exec_read / ssh_exec_kill / ...)
lib/ws.js panel WebSocket channel (/ssh/ws) with the browser-trust fence
lib/store.js persisted connection records
lib/client.js Web GUI client: multi-tab terminal panel + settings UI
cordis.patch.yml bundle patch that mounts the dsh-ssh row
scripts/ test suites (see below)
scripts/ contains the acceptance suite and helpers (requires a reachable
SSH server; the included tests target a WSL OpenSSH instance):
node scripts/test-acceptance.mjs # 65-check manager-level acceptance suite
node scripts/smoke.mjs # quick smoke test
node scripts/test-panel-ws.mjs # panel WebSocket channel drive (test web instance on :3081)
node scripts/test-rename.mjs # focused rename test (no SSH server needed)
Issues and pull requests are welcome. Keep the model-facing surface (tool names, parameter semantics, result shapes) backward compatible, and make sure secrets never end up in logs, records or tool results.
MIT
CLASSIFICATION EVIDENCE
系统优先读取 GitHub Topics,再与站内分类词典和词根规则比对。