跳到主要内容

dsh-plugin-code-reviewer

已验证

dsh-plugin-code-reviewer · v0.1.0 · MIT

3 local deterministic tools for DeepSeek Harness: code_review (14 static rules incl. OPC UA/Modbus/MQTT/serial/timeout), mqtt_probe (MQTT packet decoder), opcua_validate (NodeId validator). SCADA/MES/LIMS source scanner. 本地静态代码审查与工业协议解析工具插件。

安装

dsh plugin add dsh-plugin-code-reviewer

dsh --profile default --dump-config 确认 layer 已生效 —— 参见安装指南

源码

发布到 npm 但没有公开仓库。安装前请检查包内容。

标签

作者

说明文档

dsh-plugin-code-reviewer banner

dsh-plugin-code-reviewer

DeepSeek Harness 工具插件(由 create-dsh-plugin 生成并定制)。 A DSH tool plugin — local deterministic code review for SCADA/MES/LIMS source. npm: dsh-plugin-code-reviewer · GitHub topic: dsh-plugin

三个工具,全部纯本地执行、不调用模型、无需 API key

工具 作用
code_review 对源码文件/目录做静态代码审查:14 条规则(通用 + 工业协议专属)
mqtt_probe 解析 MQTT 报文(十六进制输入):固定头/PUBLISH/CONNECT 深解
opcua_validate 批量校验 OPC UA 节点地址(NodeId)语法,输出逐条 valid/reason

📦 安装

npm i dsh-plugin-code-reviewer
dsh plugin --profile my-profile add dsh-plugin-code-reviewer
dsh --profile my-profile
# 看到: [dsh-plugin-code-reviewer] tools: code_review=true, mqtt_probe=true, opcua_validate=true

或本地开发模式:dsh plugin --profile my-profile add ./factory-tools(在插件父目录执行)。

🛠️ 工具一:code_review — 静态代码审查

规则(14 条)

规则 级别 说明
todo-marker low TODO/FIXME/HACK/XXX 遗留标记
console-leftover medium 残留调试输出(console.* / Console.WriteLine / Debug.WriteLine / printf)
hardcoded-secret high 硬编码 password/token/api_key 等凭据
hardcoded-ip low 硬编码 IP(工业现场可能是合法 PLC/IPC 地址,需人工确认)
sql-concat high SQL 字符串拼接,疑似注入风险
eval-usage high eval / new Function
await-no-try medium 有 await 但全文件无 try/catch(启发式)
long-line low 行超 120 字符
trailing-ws low 行尾空白
opcua-address medium 工业:OPC UA 节点地址格式错误
modbus-range medium 工业:Modbus 地址越界(%MW>65535 / %MD>4294967295)或非标准段(2xxxx 保留、5xxxx+)
mqtt-topic medium 工业:MQTT 主题非法(空主题 / # 不在末尾)
com-hardcode low 工业:硬编码 COM 口 / SerialPort
no-timeout medium 工业:通信 API 无超时/取消机制(启发式)

支持扩展名:.ts/.js/.tsx/.jsx/.mjs/.cjs/.py/.cs/.java/.go/.rs/.c/.h/.cpp/.hpp/.sql/.sh/.ps1/.vb;目录递归限深 4 层、最多 200 文件、最多 200 findings。

对话示例

用 code_review 审查 D:\mes\src 目录
→ 参数:path="D:\mes\src"(自动按扩展名扫描)
只审一个文件前 500 行:path="D:\mes\Program.cs", maxLines=500

真实输出(来自 demo/ 目录扫描)

{
  "target": "D:\\...\\factory-tools\\demo",
  "filesScanned": 2,
  "findings": [
    { "file": "sample.cs", "line": 15, "severity": "high", "rule": "sql-concat",
      "message": "疑似 SQL 字符串拼接,存在注入风险,建议改用参数化查询 / 预编译语句",
      "snippet": "var sql = \"SELECT BatchNo, Qty, Status FROM dbo.Batch WHERE BatchId = \" + batchId;" },
    { "file": "plc_comms.cs", "line": 11, "severity": "medium", "rule": "opcua-address",
      "message": "OPC UA 节点地址疑似格式错误(合法形态:ns=2;s=Temperature / ns=1;i=85 / nsu=<uri>;i=2)",
      "snippet": "private const string NodeId = \"ns=2;Temperature\";" },
    { "file": "plc_comms.cs", "line": 14, "severity": "medium", "rule": "modbus-range",
      "message": "Modbus 地址 %MW200000 超出范围(%MW ≤ 65535,%MD ≤ 4294967295)", "snippet": "…" }
  ],
  "summary": "扫描 2 个文件,发现 14 个问题(1 high / 8 medium / 5 low)。详见 findings。"
}

📡 工具二:mqtt_probe — MQTT 报文解析

解析固定头(类型/DUP/QoS/RETAIN/剩余长度变长编码);PUBLISH 深解主题、报文 ID、负载;CONNECT 深解协议名/级别/连接标志/保活/ClientId。

对话示例

解析这段 MQTT 报文:10 10 00 04 4D 51 54 54 04 02 00 3C 00 04 64 65 6D 6F
→ 参数:hex="10 10 00 04 4D 51 54 54 04 02 00 3C 00 04 64 65 6D 6F"

真实输出(CONNECT 报文)

{
  "valid": true, "packetType": 1, "packetTypeName": "CONNECT",
  "flags": { "dup": false, "qos": 0, "retain": false },
  "remainingLength": 16, "remainingLengthBytes": 1,
  "protocolName": "MQTT", "protocolLevel": 4, "keepAlive": 60, "clientId": "demo",
  "summary": "类型=CONNECT(1) · 剩余长度=16 · DUP=false QoS=0 RETAIN=false · 协议=MQTT v4 保活=60s ClientId=\"demo\""
}

非法/截断输入返回 error 字段(invalid-hex / too-short / truncated / bad-remaining-length)。

🔤 工具三:opcua_validate — OPC UA 节点地址校验

批量校验 NodeId 语法:ns=<数字>; / nsu=<uri>; + s=/i=/g=/b=,可选 svr= 前缀;裸标识符按 ns=0 补全。

对话示例

校验这些节点地址:
ns=2;s=Temperature
ns=2;Temperature
ns=1;i=85
ns=2;i=abc

真实输出

{
  "ids": [
    { "id": "ns=2;s=Temperature", "valid": true, "normalized": "ns=2;s=Temperature" },
    { "id": "ns=2;Temperature", "valid": false, "reason": "缺少标识符类型(应为 s=/i=/g=/b= 开头)" },
    { "id": "ns=1;i=85", "valid": true, "normalized": "ns=1;i=85" },
    { "id": "ns=2;i=abc", "valid": false, "reason": "i= 需要整数,实际 \"abc\"" }
  ],
  "validCount": 2, "invalidCount": 2, "summary": "共 4 条:合法 2,非法 2。"
}

🧪 自检 / Self-test

npm run build
node test/selftest.mjs     # 21 项断言:三工具注册/输出结构/解析正确性

开发 / Development

npm install
npm run build               # tsc → dist/index.js (pure ESM)
npm test                    # build + selftest(发布前自动执行 prepublishOnly)

Dependencies pinned / 依赖锁定

  • @deepseek-ai/dsh-tools: 0.1.0-rc.6 (exact — the next-tag line; npm latest is stale).
  • @deepseek-ai/cordis: ^4.0.1 (peerDependency — host provides it; types-only in code).

Pitfalls / 坑(从真实 spike 提炼,防呆)

  1. Node version: DSH requires Node ^22.19.0 || >=24.0.0. 旧版本只告警 EBADENGINE,建议升级。
  2. npm dist-tag trap (the big one): @deepseek-ai/dsh-tools latest 是过期的 0.0.1-rc.1,正确版本在 next tag(0.1.0-rc.x)。本脚手架已锁 next 版本,勿手动 npm i 覆盖。
  3. Version-line alignment: 所有 @deepseek-ai/dsh-* 包统一同一 0.1.0-rc.x 线,避免装两份模块。
  4. @deepseek-ai/cordis 是 peerDep:只 import type(编译期擦除),运行时 ctx 由宿主传入。
  5. Pure ESM:package.json 必须 "type": "module";tsc 用 module: esnext + moduleResolution: bundler
  6. dsh plugin add <dir> 的相对路径锚定调用目录——要在插件父目录执行。
  7. bundle 的 cordis.patch.ymlname 用包名(走 node_modules 解析),不要用相对路径。
  8. 注册是 effect:ctx.tools.register() 卸载自动清理;自己的资源(timer/连接)包 ctx.effect()
  9. 加载顺序靠服务依赖(inject),不靠文件顺序。
  10. 端到端(模型真正调工具)需 DEEPSEEK_API_KEY;无 key 时 --verify 只证明加载/列出。