dsh-plugin-safe
Safe wrapper around
dsh pluginfor DeepSeek Harness — install/remove community plugins without breaking the harness.
dsh plugin 的安全包装脚本 —— 装/删社区插件时不再踩两个经典大坑:工具调用全部崩溃 和 全局 dsh 被误删。
The problem / 问题背景
Installing community plugins into a dsh profile makes pnpm hoist physical copies of @deepseek-ai/* packages into <profile>/node_modules. Those copies carry different module-level Symbols from the global dsh install (e.g. TOOL_RUNTIME_SCHEDULER), so the plugins and the agent loop disagree — and every tool call crashes with:
Cannot read properties of undefined (reading 'prepare')
The known fix is replacing those copies with symlinks pointing back at the global install. But pnpm treats symlinked node_modules as writable directories: the next dsh plugin run follows the links and can delete the global dsh packages entirely (ERR_MODULE_NOT_FOUND on the next boot).
dsh-plugin-safe reconciles both requirements around every pnpm operation.
How it works / 原理
before pnpm: remove @deepseek-ai symlinks (profile + fallback farm)
↓
run the real `dsh plugin ...` command
↓
after pnpm: recreate symlinks profile -> farm -> global dsh install
Usage / 用法
# install a plugin (npm or GitHub)
./dsh-plugin-safe.sh add github:owner/repo
./dsh-plugin-safe.sh add some-npm-plugin
# remove / list / update
./dsh-plugin-safe.sh remove some-plugin
./dsh-plugin-safe.sh list
./dsh-plugin-safe.sh install
# other profile (tui, headless, ...)
DSH_PLUGIN_PROFILE=tui ./dsh-plugin-safe.sh add github:owner/repo
The script prints the restart command at the end; bundle changes need a web restart:
pkill -f 'dsh web'; cd ~ && nohup node $(which dsh) web > /tmp/dsh-web-3080.log 2>&1 &
Requirements / 依赖
- macOS / Linux,
bash - dsh installed globally via npm
npmon PATH (used to locate the global install)
Notes / 注意事项
DSH_HOMEoverrides~/.dsh;DSH_PLUGIN_PROFILEselects the profile (defaultweb).- If the global dsh install is missing, the script refuses to run and prints the reinstall command.
- Always review plugin source before installing — community plugins are third-party code.
- pnpm may block git-hosted plugin
preparescripts; add the printed keys underallowBuildsin<profile>/pnpm-workspace.yamland re-run (the script does not touch that file).
License
MIT
Session repair tool / 会话修复工具
dsh-session-repair.mjs diagnoses and repairs corrupted DSH session logs (session.jsonl.zstd) — the kind of corruption a crashed process leaves behind:
- Orphan tool_calls: an
assistant/messagerequests tools that never ran (scheduler crash), so notool/resultexists. Every later "continue" fails withAn assistant message with 'tool_calls' must be followed by tool messages responding to each 'tool_call_id'. - Seq gaps / duplicates: torn writes skip or reuse sequence numbers, failing the replay check (
corrupt session log: seq gap in committed region).
# diagnose one session (read-only)
node dsh-session-repair.mjs ~/.dsh/sessions/<cwd-dir>/<session-id>/session.jsonl.zstd
# diagnose a whole sessions tree
node dsh-session-repair.mjs ~/.dsh/sessions
# repair (backs up the original to <file>.bak-<timestamp> first)
node dsh-session-repair.mjs <session.jsonl.zstd> --fix
How it works: decodes the multi-frame Zstandard log with the dsh-session storage codec, strips orphan tool-call blocks, drops orphan tool/call events, renumbers seq contiguously, and re-encodes with the exact DSH framing (header frame + event frame, zstd checksum). After a repair, restart dsh web so caches invalidate, then reload the session in the GUI.
Requires: zstd CLI and a global @deepseek-ai/dsh install (auto-located via npm root -g).
No comments yet. Be the first to write one.