dsh-reload
支持免重启热重载插件模块与重新发现技能 适合插件开发者,用于在修改代码后快速热重载而无需重启应用。
安裝
npx -p @deepseek-ai/dsh dsh plugin --profile web add github:louisyeaaah/dsh-reload說明文件
閱讀完整 README ↗Usage
reload_plugin({}) # 1. list the plugin rows: package name, entry id, running or not
reload_plugin({ name: 'dsh-video' }) # 2. reload by package name (entry id works too: 'tool-video')
reload_plugin({ name: 'dsh-video', dryRun: true }) # 3. preview which modules would be cleared, change nothing
reload_skill({ name: 'my-skill' }) # 4. force re-discovery and diagnose this skill
reload_plugin({ filter: '@deepseek-ai/' }) lists every row instead of the default (third-party and local rows, plus every row that is not running). reload_skill() without a name only refreshes; reload_skill({ cwd: '/path/to/repo' }) resolves project skill roots from another directory (an absolute path; ~ is not expanded). Humans can type /reload-plugin dsh-video and /reload-skill my-skill instead.
Real output (the plugin reloading itself, v0.1.1 → v0.1.2; only the path prefix is shortened to ``):
✅ Reloaded: include:tool-reload (dsh-reload)
Module: file:///profiles/
/node_modules/dsh-reload/lib/index.js
Package root: /profiles/
/node_modules/dsh-reload
Local modules cleared and re-evaluated (5):
• file:///profiles/
/node_modules/dsh-reload/lib/index.js
• file:///profiles/
/node_modules/dsh-reload/lib/plugin-reload.js
• file:///profiles/
/node_modules/dsh-reload/lib/shared.js
• file:///profiles/
/node_modules/dsh-reload/lib/skill-provider.js
• file:///profiles/
/node_modules/dsh-reload/lib/skill-reload.js
No change in the tool list.
Elapsed 11ms
— dsh-reload v0.1.2 ← the version stamp changed, so the new code is live
Behaviour:
- Only the target plugin's own modules are cleared — files under its package root, excluding nested
node_modules. Shared dependencies stay in the cache, so no other plugin is swapped out along the way. apply()runs again, so tools, services, commands and prompt sections are all updated.- If any step fails, the module cache is restored and the old modules are initialised again, and the report says so, instead of leaving the plugin half-loaded.
- If the row exists but has no active fiber (it never started, or its startup failed), the call activates it rather than reloading it; a
disabled: truerow is reported, not force-enabled. - If the plugin has a
dsh.clienthalf, the report notes that the browser half still needs one page refresh. - The tool-list diff is read through the root context. Reloading
dsh-reloaddisposes its ownctx, so reading through it would report every tool as removed.
The skill report
reload_skill states whether the invalidation succeeded, the total number of skills and whether that observation was complete, the added / removed / changed counts against the snapshot taken before the refresh, and the current catalog with each skill's source, provider and file path. When a provider is failing — or when the skill you asked about is not in the catalog — it also finds the skill on disk (same root rules), reports frontmatter problems (missing, not kebab-case, name not matching the directory), lists the roots it scanned, and calls each provider's list() individually to show which one throws. That last part is the only way to see a provider that fails as a whole: the registry skips such a provider and marks the observation incomplete, without telling the model.
Fallback skill provider
With fallbackRoots: true (the default) the plugin registers its own skill provider. It scans the same roots by the same rules but tolerates failures per root: an unreadable root loses only that root's skills, the rest still appear. It registers at the global layer, and registry lookup prefers the nearest layer, so while the host's own provider works it wins and skills are not duplicated; when the host provider fails, the fallback is the only source.
Roots, in priority order (identical real paths are de-duplicated):
| Source | Path |
|---|---|
cwd-dsh | /.dsh/skills |
cwd-agents | /.agents/skills |
project-dsh / project-agents | the same two directories under the nearest .git ancestor |
custom | customSkillDirs |
user-dsh | $DSH_HOME/skills (default ~/.dsh/skills, .system skipped) |
user-agents | $DSH_AGENTS_HOME/skills (default ~/.agents/skills) |
One deliberate difference from the host rules: the host uses only the nearest .git ancestor as the project root. Where $HOME is itself a git repository, every ~/project/... session gets $HOME as its project root and /.dsh/skills can never be scanned. The fallback provider additionally treats the session working directory itself as a root, at the highest priority; set includeProjectRoots: false to turn that off.
By default the roots are fingerprinted every 2 s and invalidate() is called when a fingerprint changes, so a newly added skill appears without a tool call.
Configuration
- insert:
- id: tool-reload
name: 'dsh-reload'
config:
fallbackRoots: true # register the fallback skill provider
customSkillDirs: [] # extra skill roots
watchIntervalMs: 2000 # fallback provider poll interval; 0 = no polling
includeProjectRoots: true # scan /.dsh/skills and the project root
| Key | Default | Meaning |
|---|---|---|
fallbackRoots | true | Register the fallback filesystem skill provider. With false a provider is still registered — the plugin needs the invalidate() handle that comes with the registration — but it lists nothing. |
customSkillDirs | [] | Extra skill roots, scanned after the project roots and before the user roots. |
watchIntervalMs | 2000 | Poll interval for the fallback provider's roots; 0 disables polling. Values below 250 ms are clamped to 250 ms. |
includeProjectRoots | true | Scan /.dsh/skills, /.agents/skills and the equivalents under the .git ancestor. |
The shipped cordis.patch.yml sets the first three; includeProjectRoots defaults to true and only needs writing when you want it off.