dsh-plugin-code-reviewer
Đã xác minhdsh-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. 本地静态代码审查与工业协议解析工具插件。
Cài đặt
dsh plugin add dsh-plugin-code-reviewer Xác nhận layer đã áp bằng dsh --profile default --dump-config — xem hướng dẫn cài plugin.
Mã nguồn
Phát hành lên npm mà không có repository công khai. Hãy kiểm tra nội dung package trước khi cài.
Thẻ
Tác giả
Readme
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 — thenext-tag line; npmlatestis stale).@deepseek-ai/cordis:^4.0.1(peerDependency — host provides it; types-only in code).
Pitfalls / 坑(从真实 spike 提炼,防呆)
- Node version: DSH requires Node ^22.19.0 || >=24.0.0. 旧版本只告警 EBADENGINE,建议升级。
- npm dist-tag trap (the big one):
@deepseek-ai/dsh-toolslatest是过期的 0.0.1-rc.1,正确版本在nexttag(0.1.0-rc.x)。本脚手架已锁 next 版本,勿手动npm i覆盖。 - Version-line alignment: 所有
@deepseek-ai/dsh-*包统一同一 0.1.0-rc.x 线,避免装两份模块。 @deepseek-ai/cordis是 peerDep:只import type(编译期擦除),运行时 ctx 由宿主传入。- Pure ESM:package.json 必须
"type": "module";tsc 用module: esnext+moduleResolution: bundler。 dsh plugin add <dir>的相对路径锚定调用目录——要在插件父目录执行。- bundle 的
cordis.patch.yml里name用包名(走 node_modules 解析),不要用相对路径。 - 注册是 effect:
ctx.tools.register()卸载自动清理;自己的资源(timer/连接)包ctx.effect()。 - 加载顺序靠服务依赖(inject),不靠文件顺序。
- 端到端(模型真正调工具)需
DEEPSEEK_API_KEY;无 key 时 --verify 只证明加载/列出。