dsh-plugin-forge-preset:把「寫插件、讀插件、改插件」的做法固化進預設

前言

DSH 的理念是「一切皆插件」。實際寫過插件的人大多會遇到三類問題:從零起一個新插件時,規範散落在會話裏,每次都靠口述;裝了一個別人寫的插件,想知道它註冊了哪些槽位、路由和 UI 結構,只能整文件讀,token 燒得很快;想把某個插件的寫法搬過來或改成自己的版本,沒有明確的改造路徑,改完也不知道有沒有破壞原行爲。

wodaimnd/dsh-plugin-forge-preset 針對的就是這三件事。它是維護者 wodaimnd 寫的一個 DSH agent 預設(不是普通插件),裝上後模式下拉里多出一項「插件工坊」,會話裏可以直接說「幫我寫個插件」,也可以說「看看這個插件怎麼實現的」「把這個插件改成我要的樣子」。它的定位是把插件開發的規範固化在文件裏,而不是活在一次會話裏。

它是什麼

一句話:一個預設容器。presets/ 下每個子目錄是一個模式,plugin-forge 是正式的「插件工坊」,demo-mini 是架構驗證用的演示模式(可刪)。包版本 1.0.0,MIT 許可,作者 Kewei Chen。社區目錄裏的分類爲「客戶端」,星標數爲 0。

它和逆向模式(reverse)的區別值得先說清楚。兩者都做「拆開別人的東西」,但對象不同:

  • 逆向模式拆 APK / IPA / PE / SO / 協議,產出是算法還原、脫殼產物;
  • 插件工坊拆的是 DSH 插件的 JS bundle,拆的是槽位註冊、路由、工具行、UI 結構,產出是能安裝的新插件。

插件源碼本來就是可讀的 JS,所以 jadx / Frida / IDA 這套工具鏈在這裏用不上。

四個執行角色

插件內部有四個角色,併發上限 3 個,都是葉子節點(maxDepth: 1),不會無限往下派任務:

角色 幹什麼 觸發時機
插件測繪 出結構地圖、契約表、「能改/慎改/別碰」三分 要讀懂一個插件時
代碼吸收 判斷哪塊值得吸、遷入並驗證行爲不變 要借別人寫法時
改造分叉 選路線(原地改 / 複製分叉 / 補丁層)、七處替換、雙驗證 要改一個插件時
迴歸驗證 樁環境結構驗證 + 與原版差異對比 每次改造後

技能清單

說明一下:README 的小節標題寫的是「六個技能」,但下面的表格實際列了 7 項,按表格爲準。

技能 作用 關鍵產出
plugin-author 從零寫插件:對齊 → 代碼 → 16 項自檢 完整可安裝插件 + 規範全文
preset-scaffold 加新 agent 預設:建目錄 → 寫兩件套 → 驗證 新模式的完整模板與約束
plugin-search 代碼定位:大綱 → 結構化搜索 → 定向讀取 精確行號,不整文件讀
plugin-index 跨文件盤點:符號 / 引用 / 槽位 / 路由 SQL 級查詢,替代重複掃描
plugin-recon 摸清別人的插件 結構地圖 + 契約表 + 三分清單
plugin-harvest 吸收可用代碼 吸收清單 + 遷入代碼 + 驗證腳本
plugin-fork 改造成自己的版本 改造方案 + 分叉產物 + 雙驗證

技能裝在 $DSH_HOME/plugin-forge/skills/,由插件啓動時從包內同步。所有預設共享這一個技能庫,所以給插件工坊加的技能,新預設自動可用。

檢索工具與 token 預算

這是插件裏最實用的部分。四個工具按問題類型選:單文件降維用大綱器,跨文件查庫用索引庫,按語法結構找用 ast-grep,找字面量用宿主 grep。

下面是資料裏給出的實測數據:

tokens / 耗時
全文讀 6 個真實插件文件 95,064 tokens
只讀結構大綱 1,470 tokens(省 98.5%)
單文件最極端(222KB) 全文 60,876 → 大綱 835 tokens
建全庫索引(126 文件 / 1.5MB) 456ms
索引庫單次查詢 0.05ms

用法如下,第一步是單文件或單插件的大綱:

# ① 單文件或單插件:先出大綱(讀大文件之前必做)
node tools/outline.mjs '<插件目錄>' --tokens

第二步是跨文件問題,建一次索引,之後都走查詢:

node tools/index.mjs build 'G:\AI PGRM\DSH\plugins'
node tools/index.mjs find PanelPage        # 全庫幾處定義
node tools/index.mjs refs handleOperation  # 誰引用了它
node tools/index.mjs slots                 # 哪些插件註冊了什麼槽位
node tools/index.mjs routes                # 全部路由
node tools/index.mjs effects network       # 所有網絡請求點
node tools/index.mjs stats                 # 庫規模 + 同名多定義

第三步是結構化搜索,README 強調規則:ast-grep 的 pattern 必須帶 $OBJ. 前綴,否則會漏掉 ctx.slots.register(...) 這種最常見寫法:

ast-grep run -p '$OBJ.slots.register({ name: $NAME, $$$REST }, $COMP)' -l js '<目錄>'
ast-grep run -p '$OBJ.webServer.register({ $$$REST })' -l js '<目錄>'

拿到行號後再定向讀,而不是整文件讀。硬規則也寫在 README 裏:讀任何大於 20KB 的文件之前,必須先跑 outline。

ast-grep 需要自行安裝,它 55MB,不在本包內,期望版本 0.51.1 或更高。不在 PATH 時插件會自動降級爲「大綱器 + 宿主 grep」,功能可用但結構匹配精度下降。另外 sg.exe 是棄用別名,不要用。

索引庫有三個已知邊界:引用是「調用點 + 大寫參數」而非全量標識符,小寫變量名作參數傳遞時查不到,這時改用 ast-grep;動態路由標註爲 (動態: route),不做猜測;增量更新依賴 mtime,改文件但 mtime 沒變會滯後,刪庫重建即可。

提示詞固化在哪

這是插件存在的核心目的:規範不能只活在會話裏。提示詞的分佈如下:

位置 內容 大小
presets/plugin-forge/persona.md 人設與判斷規則(唯一真源) 19KB
presets/plugin-forge/agent.cordis.yml 條目列表,人設位置用 %%PERSONA%% 8.6KB
skills/plugin-author/SKILL.md 執行骨架:三步流程、判據表、輸出格式 4.2KB(渲染 4261/8192)
skills/plugin-author/references/ runtime-contract / skeletons / ux / data-and-ownership / gates / failure-modes / prohibitions 合計約 57KB
docs/prompt-v2.1.md 完整規範原文(含逐條理由與變更史) 70KB

拆成 SKILL.md + references 的原因很實際:宿主對 SKILL.md 有 8192 字符硬上限,超了會被修剪器裁掉後半段。SKILL.md 只放骨架與導航,長文按需讀 references/,不計入預算。

改人設的正確方式是改源文件再加校驗:

# 1. 改 presets/plugin-forge/persona.md(唯一真源)
# 2. 校驗(不寫盤)
python build-composition.py --check
# 3. 重啓 dsh

agent.cordis.yml 裏只有一行 %%PERSONA%%,落地時自動注入全文。不要直接改 .agent-presets/plugin-forge/agent.cordis.yml 這份落地副本,下次啓動會被源覆蓋。

安裝

包以 @local/dsh-plugin-forge-preset 的名字通過 link: 依賴裝進 profile,README 給的是 PowerShell 步驟,不是 dsh plugin add:

# 1) 包目錄放到任意位置,然後加進 profile 依賴
$profile = $env:DSH_PROFILE_DIR
$pkg = Get-Content -Raw -Encoding UTF8 "$profile\package.json" | ConvertFrom-Json
$pkg.dependencies | Add-Member -NotePropertyName '@local/dsh-plugin-forge-preset' `
  -NotePropertyValue 'link:<包目錄絕對路徑>' -Force
$pkg.dsh.profile.bundles += '@local/dsh-plugin-forge-preset'
$pkg | ConvertTo-Json -Depth 12 | Set-Content "$profile\package.json" -Encoding UTF8

# 2) 建 junction,讓 Loader 能按包名解析
New-Item -ItemType Junction -Path "$profile\node_modules\@local\dsh-plugin-forge-preset" `
  -Target '<包目錄絕對路徑>'

重啓 DSH 後,模式下拉里就會出現「插件工坊」。

運行時行爲與排障

啓動時插件依次做四件事:把 preset.yml + agent.cordis.yml 落到 $DSH_HOME/.agent-presets/plugin-forge/;把 skills/ 同步到 $DSH_HOME/plugin-forge/skills/;等 agentPresets 服務就緒(最長 20 秒),然後調 ctx.agentPresets.register() 聲明進下拉;把結果寫進 $DSH_HOME/plugin-forge/preset-declare.json。

第三步是必須的。Web 的模式下拉只認 register(),只把目錄寫到 .agent-presets 不會被掃到,README 把這稱爲「插件裝得完整、下拉里卻沒有它」的唯一根因。

裝完直接看 preset-declare.json 判斷結果:

{
  "ok": true,
  "phase": "registered",
  "id": "plugin-forge",
  "name": "插件工坊",
  "plugins": 19,
  "broken": null,
  "skillsDir": "...",
  "presetDir": "..."
}

phase 的含義如下:

phase 含義 怎麼辦
registered 正常 無
registered-broken 已聲明但掛載失敗 看 broken 字段
waiting-registry 等 agentPresets 服務 通常幾秒內自動過去
registry-timeout 20 秒沒等到服務 檢查 @deepseek-ai/dsh-agent-preset-registry 是否在 profile 裏
install-failed 預設文件落地失敗 看 error,檢查 $DSH_HOME 寫權限

配置項表中,README 明確給出的只有 syncSkills(默認 true,控制是否把本包技能同步到 $DSH_HOME/plugin-forge/skills)。其餘配置項資料裏沒有出現,這裏不列。

包內還聲明瞭 dsh.forge.effects:fs:read 任意絕對路徑(測繪別人的插件)、fs:write 到 $DSH_HOME/.agent-presets/plugin-forge(落地預設)、fs:write 到 $DSH_HOME/plugin-forge(技能同步與狀態文件)、http:loopback:/api/dsh-plugin-forge-preset(設置頁數據路由)。

繼續加新預設

加一個新預設不需要改任何 JS:

  1. 在 presets/ 下建目錄,目錄名 = preset id,需匹配 ^[a-z0-9][a-z0-9-]{0,31}$
  2. 寫 preset.yml:name / description / order(前兩個必須單行,order 必須數字)
  3. 寫 agent.cordis.yml:條目列表,至少含 persona、skill-filesystem、一個 shell 工具
  4. 人設長時用 %%PERSONA%% 佔位符 + 同目錄 persona.md
  5. 重啓 dsh

停用有兩檔:放空文件 presets/<id>/.preset-off,或者把目錄改名加下劃線(如 _<id>),結果都是不落地、不註冊、副本保留。徹底移除就是刪掉整個預設目錄,下次啓動會自動清掉 .agent-presets/<id>。

中文優先

插件約定 UI 文案、按鈕、錯誤提示一律簡體中文,插件展示名與描述一律簡體中文,默認不做多語言——不創建 en.json,不留雙語字典,不寫 locale 切換,只有用戶明確要求時才做雙語。package.json 裏雖然有 ./locale/*.json 的 exports 字段,但按 README 的約定,默認不帶多語言資源。

適用場景與注意

適合兩類人。一類是本來就要在 DSH 上寫插件的人:需要按規範從零起插件、跑 16 項自檢,省掉重複詢問。另一類是想讀懂或改造別人插件的人:用測繪 / 吸收 / 分叉三檔流程,配合省 token 的檢索工具,避免整文件讀。

使用時有幾點要留意:

  • 插件以當前 dsh 進程的權限運行,資料裏聲明的 fs:read 是任意絕對路徑,安裝前應先檢查源碼與許可證。
  • 定製人設或規範時改 presets/ 下的源文件,不要改 .agent-presets/ 裏的落地副本。
  • 想用滿檢索能力需要自行安裝 ast-grep(0.51.1 及以上),不裝也能降級運行。
  • 索引庫的引用關係不是全量標識符,跨文件結論拿不準時用 ast-grep 複覈。

結尾

這個插件的價值不在於多了一個模式,而在於把插件開發的規範從會話裏搬到了文件裏,並配了大綱器、索引庫和結構搜索來把 token 成本壓到可承受的水平。如果要裝,先看目錄頁和倉庫裏的 README,源碼與許可證確認無誤後再放進 profile。

  • 社區目錄頁:https://www.skillhub.cn/plugins/wodaimnd/dsh-plugin-forge-preset
  • GitHub:https://github.com/wodaimnd/dsh-plugin-forge-preset
羽毛球分组比赛记分
小程序二维码

欢迎使用《羽毛球分组比赛记分》微信小程序

小夜