🎁 福利专区全网大模型免费应用 + 新用户福利 + 注册活动入口,低成本玩转 AI

视觉调试台 xingyingyuzhui/dsh-corn-bench

DeepSeek Harness
xingyingyuzhui7 天前有提交已提供中文文档扫描:含敏感能力

DSH 插件:Vision bench——在会话视图里做 Keil 调试和 Modbus HMI

30.7/100
综合分
1
GitHub 星标
—
npm 周下载
—/5
用户评分

数据截至 2026/10/26 · 周下载取自 npm 全网(含 CI / 镜像),非本站安装数;综合分由星标、活跃度与兼容性检查合成。

自动兼容检查有告警:未发布到 npm registry,仅可从源码安装。
安装命令 · 需先装 dsh CLI 引擎
dsh plugin --profile web add xingyingyuzhui/dsh-corn-bench
该包不可直接 npm 安装,改从 GitHub 源安装(明细见下方安装检查)

状态速览

判定依据:实装验证 · 静态安装检查 · 自动扫描 · 仓库维护状态
信任档位:已验证
是什么
dsh 原生插件 · search
装得上吗
本站已在 dsh 0.2.1-rc.5 下真实安装成功
非静态推断
L4 · 真实安装等级说明 →
安全吗
本站尚未对该插件做风险分级
暂未覆盖,不等同于无风险
还在维护吗
活跃:最近一次提交在 7 天前
档位由哪些信号合成

本站实装验证(真实安装 L4 覆盖全站;L5 为运行时冒烟或实机截图,覆盖范围小于 L4) · 验证所用 dsh 版本 · 静态安装检查 · 风险分级 · 仓库维护状态。 下方各区块是它的证据明细。

验证判据与等级说明 →
社区实装还没有人打卡 · 装过的第一个就是你
安装兼容性检查⚠ 装前注意

未发布到 npm registry,仅可从源码安装

展开查看检查明细 ↓

以下结论由程序自动检查 npm 包、engines 声明与入口文件得出,未做人工实机验证——能装不等于用着没问题。

✗npm 包dsh-vision-bench(未发布到 npm,仅可源码安装)
✓Node 引擎要求 >=20 · 基线 Node 22.19 满足
✓dsh CLI 依赖未声明 dsh 版本约束
✓入口文件main/exports/bin 已声明

验证方式:npm registry 存在性 + package.json 静态校验 · 最后检查 2026/10/12 15:07:48

安全扫描自动 · 静态分析源码
v2.7.0
🔵 扫描:含敏感能力尚无人工评估
展开查看扫描说明与证据 ↓

静态扫描发现插件具备触达本地系统的能力:执行外部命令、读写/删除本地文件、读取剪贴板或密钥类环境变量(至少其一)。这是能力清单,不是危险判定——具体能力项与证据见下方,安装前请自行判断是否需要。

可执行外部命令读写/删除本地文件发起外部网络请求
查看扫描证据(共 113 处,展示前 96 条)
  • 发起网络请求
    src/infrastructure/host/corn-host-client.mjs:133
    const res = await fetch(url, {
  • 读取本地文件
    src/infrastructure/store/legacy-data-dir.mjs:22
    if (!existsSync(from) || existsSync(to)) return { migrated: false }
  • 写入本地文件
    src/infrastructure/store/legacy-data-dir.mjs:24
    renameSync(from, to)
  • 执行外部命令来自配置/变量
    src/infrastructure/modbus/io-broker.mjs:185
    proc = (spawn(execPath, [workerPath], { stdio: ['pipe', 'pipe', 'pipe'], windowsHide: true, env }))
  • 读取本地文件
    src/infrastructure/store/journal-store.mjs:323
    entries = readdirSync(dir)
  • 读取本地文件
    src/infrastructure/store/journal-store.mjs:332
    logs.push({ path, mtime: statSync(path).mtimeMs })
  • 删除本地文件
    src/infrastructure/store/journal-store.mjs:341
    unlinkSync(log.path)
  • 读取本地文件
    src/infrastructure/store/workspace-store.mjs:360
    if (existsSync(rawPath)) {
  • 读取本地文件
    src/infrastructure/store/workspace-store.mjs:361
    const rawContent = readFileSync(rawPath, 'utf8')
  • 读取本地文件
    src/infrastructure/store/workspace-store.mjs:369
    if (!existsSync(bakPath)) writeFileSync(bakPath, rawContent)
  • 写入本地文件
    src/infrastructure/store/workspace-store.mjs:369
    if (!existsSync(bakPath)) writeFileSync(bakPath, rawContent)
  • 读取本地文件
    src/infrastructure/store/workspace-store.mjs:371
    if (!existsSync(legacyBak)) writeFileSync(legacyBak, rawContent)
  • 写入本地文件
    src/infrastructure/store/workspace-store.mjs:371
    if (!existsSync(legacyBak)) writeFileSync(legacyBak, rawContent)
  • 写入本地文件
    src/infrastructure/store/workspace-store.mjs:377
    mkdirSync(join(storeDir(home), 'workspaces'), { recursive: true })
  • 读取本地文件
    src/application/keil/project-service.mjs:68
    const st = await stat(candidate)
  • 读取本地文件
    src/application/keil/project-service.mjs:124
    const st = await stat(resolved)
  • 读取本地文件
    src/application/keil/project-service.mjs:173
    const st = await stat(resolved)
  • 读取本地文件
    src/infrastructure/files/project-fs.mjs:39
    entries = readdirSync(target, { withFileTypes: true })
  • 读取本地文件
    src/infrastructure/files/project-fs.mjs:59
    const st = statSync(real)
  • 读取本地文件
    src/infrastructure/files/project-fs.mjs:157
    stat = statSync(real)
  • 读取本地文件
    src/infrastructure/files/project-fs.mjs:165
    content = readFileSync(real, 'utf8')
  • 读取本地文件
    src/infrastructure/files/project-fs.mjs:204
    stat = statSync(real)
  • 读取本地文件
    src/infrastructure/files/project-fs.mjs:212
    hash.update(readFileSync(real))
  • 读取本地文件
    src/infrastructure/store/bindings-store.mjs:69
    return normalizeBindings(JSON.parse(readFileSync(bindingsPath( (home)), 'utf8')))
  • 写入本地文件
    src/infrastructure/store/bindings-store.mjs:82
    mkdirSync(storeDir(home), { recursive: true })
  • 读取本地文件
    src/infrastructure/store/global-share-store.mjs:31
    return normalizeGlobalShare(JSON.parse(readFileSync(globalSharePath(home), 'utf8')))
  • 写入本地文件
    src/infrastructure/store/global-share-store.mjs:40
    mkdirSync(storeDir(home), { recursive: true })
  • 发起网络请求
    src/infrastructure/modbus/modbus-transport.mjs:198
    const ran = await broker.request(body, opts)
  • 读取本地文件
    src/shared/workspace-paths.mjs:51
    if (!existsSync(raw)) return { error: '工程文件不存在' }
  • 读取本地文件
    src/shared/workspace-paths.mjs:54
    st = lstatSync(raw)
  • 读取本地文件
    src/shared/workspace-paths.mjs:63
    file = statSync(raw)
  • 读取本地文件
    src/infrastructure/modbus/serial-ports.mjs:170
    const names = opts.readdir ? opts.readdir('/dev') : readdirSync('/dev')
  • 读取本地文件
    src/interfaces/rpc/debug-rpc-handler.mjs:265
    const artifactExists = Boolean(record.artifactPath && existsSync(record.artifactPath))
  • 执行外部命令固定命令
    src/infrastructure/process/run-command.mjs:55
    spawnSync('taskkill', ['/PID', String(pid), '/T', '/F'], { stdio: 'ignore', windowsHide: true })
  • 执行外部命令来自配置/变量
    src/infrastructure/process/run-command.mjs:107
    child = execFile(
  • 读取本地文件
    src/infrastructure/process/run-command.mjs:146
    if (!existsSync(bin)) return { ok: false, error: 'Python 路径不存在: ' + pythonBin }
  • 读取本地文件
    src/infrastructure/process/run-command.mjs:148
    if (!script || !existsSync(script)) return { ok: false, error: '脚本不存在: ' + scriptName }
  • 读取本地文件
    src/infrastructure/persistence/workspace-repository.mjs:65
    if (!existsSync(migrationMarkerPath(dir))) {
  • 读取本地文件
    src/infrastructure/persistence/workspace-repository.mjs:77
    if (existsSync(migrationMarkerPath(dir))) {
  • 读取本地文件
    src/infrastructure/persistence/workspace-repository.mjs:88
    if (existsSync(legacyPath)) {
  • 读取本地文件
    src/infrastructure/keil/keil-project-scanner.mjs:90
    const st = await stat(filePath)
  • 读取本地文件
    src/infrastructure/keil/keil-project-scanner.mjs:163
    const st = await stat(rootPath)
  • 读取本地文件
    src/infrastructure/keil/keil-project-scanner.mjs:199
    entries = await readdir(currentDir, { withFileTypes: true })
  • 读取本地文件
    src/infrastructure/keil/uvprojx-parser.mjs:88
    content = await readFile(p, 'utf8')
  • 读取本地文件
    src/infrastructure/keil/uv4-build-runner.mjs:49
    const raw = await readFile(logPath)
  • 读取本地文件
    src/infrastructure/keil/uv4-build-runner.mjs:173
    const raw = readFileSync(projectPath, 'utf8')
  • 读取本地文件
    src/infrastructure/keil/uv4-build-runner.mjs:207
    if (existsSync(candidatePath) && statSync(candidatePath).isFile()) {
  • 读取本地文件
    src/infrastructure/keil/uv4-build-runner.mjs:207
    if (existsSync(candidatePath) && statSync(candidatePath).isFile()) {
  • 读取本地文件
    src/infrastructure/keil/uv4-build-runner.mjs:222
    if (existsSync(outputDir)) {
  • 读取本地文件
    src/infrastructure/keil/uv4-build-runner.mjs:258
    if (!existsSync(projectPath)) {
  • 写入本地文件
    src/infrastructure/keil/uv4-build-runner.mjs:282
    await mkdir(logDir, { recursive: true })
  • 读取本地文件
    src/infrastructure/files/firmware-snapshot.mjs:10
    hash.update(readFileSync(filePath))
  • 写入本地文件
    src/infrastructure/files/firmware-snapshot.mjs:53
    mkdirSync(dir, { recursive: true })
  • 写入本地文件
    src/infrastructure/files/firmware-snapshot.mjs:55
    copyFileSync(sourcePath, dest)
  • 读取本地文件
    src/infrastructure/files/firmware-snapshot.mjs:56
    const size = statSync(dest).size
  • 删除本地文件递归
    src/infrastructure/files/firmware-snapshot.mjs:103
    rmSync(resolve(dir), { recursive: true, force: true })
  • 写入本地文件
    src/infrastructure/persistence/atomic-json.mjs:13
    mkdirSync(dirname(filePath), { recursive: true })
  • 读取本地文件
    src/infrastructure/persistence/atomic-json.mjs:35
    if (!existsSync(filePath)) return fallback
  • 读取本地文件
    src/infrastructure/persistence/atomic-json.mjs:36
    return JSON.parse(readFileSync(filePath, 'utf8'))
  • 读取本地文件
    src/infrastructure/persistence/atomic-json.mjs:48
    if (!existsSync(filePath)) return false
  • 写入本地文件
    src/infrastructure/persistence/atomic-json.mjs:49
    mkdirSync(dirname(bakPath), { recursive: true })
  • 写入本地文件
    src/infrastructure/persistence/atomic-json.mjs:50
    copyFileSync(filePath, bakPath)
  • 读取本地文件
    src/infrastructure/persistence/atomic-json.mjs:58
    return statSync(filePath).isFile()
  • 读取本地文件
    src/infrastructure/persistence/atomic-json.mjs:67
    if (existsSync(bakPath)) return { ok: false, error: 'backup path is not a file' }
  • 读取本地文件
    src/infrastructure/persistence/atomic-json.mjs:68
    if (!existsSync(filePath)) return { ok: false, error: 'source missing' }
  • 写入本地文件
    src/infrastructure/persistence/atomic-json.mjs:69
    mkdirSync(dirname(bakPath), { recursive: true })
  • 写入本地文件
    src/infrastructure/persistence/atomic-json.mjs:71
    copyFileSync(filePath, tmp)
  • 删除本地文件
    src/infrastructure/persistence/atomic-json.mjs:74
    unlinkSync(tmp)
  • 写入本地文件
    src/infrastructure/persistence/atomic-json.mjs:78
    renameSync(tmp, bakPath)
  • 删除本地文件
    src/infrastructure/persistence/atomic-json.mjs:99
    if (existsSync(filePath)) unlinkSync(filePath)
  • 写入本地文件
    src/application/debug/debug-event-sink.mjs:56
    mkdirSync(dir, { recursive: true })
  • 写入本地文件
    src/application/debug/debug-event-sink.mjs:57
    appendFileSync(join(dir, `${debugSessionId}.ndjson`), `${JSON.stringify(event)}\n`, 'utf8')
  • 读取本地文件
    src/infrastructure/store/agent-policy-store.mjs:39
    return normalizeAgentPolicy(JSON.parse(readFileSync(agentPolicyPath(home), 'utf8')))
  • 写入本地文件
    src/infrastructure/store/agent-policy-store.mjs:52
    mkdirSync(storeDir(home), { recursive: true })
  • 读取本地文件
    src/infrastructure/persistence/workspace-migration.mjs:162
    if (existsSync(marker)) {
  • 读取本地文件
    src/infrastructure/persistence/workspace-migration.mjs:168
    if (!existsSync(legacy)) return { ok: true, skipped: true }
  • 读取本地文件
    src/infrastructure/persistence/workspace-migration.mjs:172
    raw = JSON.parse(readFileSync(legacy, 'utf8'))
  • 写入本地文件
    src/infrastructure/persistence/workspace-migration.mjs:181
    mkdirSync(dir, { recursive: true })
  • 写入本地文件
    src/infrastructure/persistence/workspace-migration.mjs:221
    mkdirSync(dir, { recursive: true })
  • 读取本地文件
    src/infrastructure/persistence/workspace-migration.mjs:225
    if (!existsSync(migrationMarkerPath(dir))) {
  • 读取本地文件
    src/infrastructure/persistence/workspace-migration.mjs:233
    if (!existsSync(journal)) writeTextAtomicSync(journal, '')
  • 写入本地文件
    src/infrastructure/persistence/workspace-migration.mjs:238
    mkdirSync(dir, { recursive: true })
  • 读取本地文件
    src/infrastructure/persistence/workspace-migration.mjs:254
    if (existsSync(bak) && !statSync(bak).isFile()) {
  • 写入本地文件
    src/infrastructure/persistence/workspace-migration.mjs:261
    mkdirSync(dir, { recursive: true })
  • 读取本地文件
    src/infrastructure/keil/uv4-env.mjs:27
    if (existsSync(candidate) && statSync(candidate).isDirectory()) {
  • 读取本地文件
    src/infrastructure/keil/uv4-env.mjs:27
    if (existsSync(candidate) && statSync(candidate).isDirectory()) {
  • 读取本地文件
    src/infrastructure/harness/dsh-contract.mjs:138
    const pkg = JSON.parse(readFileSync(pkgPath, 'utf8'))
  • 读取本地文件
    src/application/commands/handlers/system-command-handler.mjs:8
    const pkg = JSON.parse(readFileSync(join(root, 'package.json'), 'utf8'))
  • 读取本地文件
    src/application/commands/handlers/system-command-handler.mjs:15
    if (existsSync(path)) {
  • 读取本地文件
    src/application/commands/handlers/system-command-handler.mjs:17
    const info = JSON.parse(readFileSync(path, 'utf8'))
  • 读取本地文件
    src/application/debug/debug-launch-spec-service.mjs:56
    if (!root || !existsSync(root)) return []
  • 读取本地文件
    src/application/debug/debug-launch-spec-service.mjs:61
    if (!existsSync(dir)) continue
  • 读取本地文件
    src/application/debug/debug-launch-spec-service.mjs:64
    const entries = readdirSync(dir)
  • 读取本地文件
    src/application/debug/debug-launch-spec-service.mjs:70
    const st = statSync(full)
  • 读取本地文件
    src/application/debug/debug-launch-spec-service.mjs:99
    if (!cwd || !existsSync(cwd)) return []
  • 读取本地文件
    src/application/debug/debug-launch-spec-service.mjs:125
    if (!filePath || !existsSync(filePath)) return ''
扫描于 2026/11/2(0 天前) · 范围 入口闭包 + 发布文件清单 · 来源 GitHub 仓库

静态扫描只反映源码中出现的调用,不构成安全背书;人工评估与自动扫描相互独立、互不覆盖。

依赖的 DSH / Cordis 模块
@deepseek-ai/dsh-agent-presets@deepseek-ai/dsh-persona
给这个插件打分还没有人投票↓
用户评分
还没有人投票,来当第一个

功能亮点

  • 会话视图内调试
  • Keil调试
  • ModbusHMI

README

由 DeepSeek 最新模型翻译生成
Corn · dsh-corn-bench 作者:xingyingyuzhui · 仓库:<https://github.com/xingyingyuzhui/dsh-corn-bench> · 授权:PolyForm Noncommercial 1.0.0(非商业授权) 包名 dsh-corn-bench,Agent 预设 Corn模式(id corn-bench),工具 corn_bench / corn_debug,数据目录 $DSH_HOME/corn-bench/。 从 0.30.2 及更早版本升级:先卸载旧插件,再装 dsh-corn-bench。首次启动会把旧数据目录整体搬到 $DSH_HOME/corn-bench/(绑定、工作区、点表、日志、Agent 权限都在里面);界面的导航偏好也会自动迁移。已有 corn-bench/ 时不覆盖。旧预设不会被自动删除,新建 Session 时选 Corn模式。 版本见 CHANGELOG.md。支持 DSH 0.1.5-rc.1 – 0.2.1-rc.3(三轨:≤0.1.6 目录式;0.1.7 声明式;0.2.x 声明式,契约钉 0.2.1-rc.2)。DSH 0.2.x 需要 Node 24+。0.2.1-rc.3 只改了界面菜单、草稿和模型列表适配,已核对插件接口与 standard 预设没有变化。
展开完整文档(README 剩余 1 节)
Corn · dsh-corn-bench

作者:xingyingyuzhui · 仓库:<https://github.com/xingyingyuzhui/dsh-corn-bench> · 授权:PolyForm Noncommercial 1.0.0(非商业授权)

包名 dsh-corn-bench,Agent 预设 Corn模式(id corn-bench),工具 corn_bench / corn_debug,数据目录 $DSH_HOME/corn-bench/。

从 0.30.2 及更早版本升级:先卸载旧插件,再装 dsh-corn-bench。首次启动会把旧数据目录整体搬到 $DSH_HOME/corn-bench/(绑定、工作区、点表、日志、Agent 权限都在里面);界面的导航偏好也会自动迁移。已有 corn-bench/ 时不覆盖。旧预设不会被自动删除,新建 Session 时选 Corn模式。

版本见 CHANGELOG.md。支持 DSH 0.1.5-rc.1 – 0.2.1-rc.3(三轨:≤0.1.6 目录式;0.1.7 声明式;0.2.x 声明式,契约钉 0.2.1-rc.2)。DSH 0.2.x 需要 Node 24+。0.2.1-rc.3 只改了界面菜单、草稿和模型列表适配,已核对插件接口与 standard 预设没有变化。

会话区里的调试 / 上位机 / 监控工作台。跟 Claw 无关。同一份现场状态同时给界面和当前 Session 的 Agent 用。

| 面 | 现在能做什么 |
| Web | 完整工作台。Host 走 Connection Fetch;有 webServer 时额外挂旧 RPC 与 Agent HTTP 桥。 |
| Desktop | 同一套 UI / Agent / TCP / 仿真,无 Corn 监听端口。实验室用本地 tarball 安装。 |
| 尚未宣称 | 官方 Desktop 产品安装(npm name@version 尚未发布);官方 Desktop 完整 Modbus RTU(serialport 不在 Desktop allowBuilds);Windows + STM32 / Keil 真机。 |

验收矩阵:docs/ACCEPTANCE_NATIVE_WEB_DESKTOP.md。

完整变更见 CHANGELOG.md。

安装

Web

dsh plugin --profile web add github:xingyingyuzhui/dsh-corn-bench

本机开发请 npm pack 再 add 那个 .tgz,不要 link: 源码树(会把 node_modules/、coverage/ 整棵链进 profile):

npm pack
dsh plugin --profile web add ./dsh-corn-bench-.tgz

装完重启 dsh web。打开 调试 / 上位机 / 监控,或 设置 → Corn。新会话选 Corn模式。

Desktop

官方产品安装用打包应用里的 应用 → 桌面插件…。(DSH 0.2.1-rc.3 起,左侧栏、会话视图和右侧栏也多了「更多」菜单,可以在那里浏览插件。)它接受包名、Git 地址、tarball 或本地绝对路径,所以已发布的版本可以立刻装 —— 把下面 ${version} 换成 Releases 里最新标签的版本号:

github:xingyingyuzhui/dsh-corn-bench#v${version}

或下载对应 Release 的 dsh-corn-bench-${version}.tgz(同目录有 .sha256),把它绝对路径填进同一个框。裸包名 dsh-corn-bench 需要 registry 上有这个包 —— 当前 npmjs.org 仍是 404。

本机实验室(先 Cmd+Q 完全退出 DeepSeek Harness):

node scripts/probes/install-desktop-local.mjs

不要执行 dsh plugin --profile desktop。Desktop profile 由 Electron 独占。实验室脚本走 profile 内 file: tarball,只算 lab 证据,不算官方产品安装。

卸载

dsh plugin --profile web remove dsh-corn-bench

Desktop 在 桌面插件… 里移除。绑定写在 $DSH_HOME/corn-bench/bindings.json。用户预设 Corn模式 不会随卸载删除。

三个工作区

会话区标签:调试、上位机、监控。

- 调试:选 .uvprojx(暂不支持 .uvmpw)、Target、编译、烧录;右侧工程结构;运行调试(GDB/MI + OpenOCD)。
- 上位机:连接 / 设备 / 点位。RTU 扫描本机 COM;真实读写走内置 Node Modbus(仿真不启动 Worker)。
- 监控:可视化、告警、串口报文、操作记录。点表值 / 可视化 / 告警 / 报文共享同一实时来源。

设置页 Corn:绑定 Keil UV4(纯 Node,不需要 Python)、OpenOCD(外部兼容绑定)、Modbus/串口运行时。一键 运行自检。

连接状态只看真实链路:未连接 / 连接中 / 已连接 / 断开中 / 连接异常。只使用绑定路径,不在磁盘上搜索。

Corn模式

宿主 dsh-corn-bench 顶层只注入 connection,UI 发 POST /api/corn-bench/dispatch。旧 /corn-bench RPC 与 Agent HTTP 命令桥仅在有 webServer 时挂载。Agent 工具走另一条 loader:dsh-corn-bench/agent(export name 为 dsh-corn-bench-tools),由 Corn模式 预设插入,不和宿主同名。

DSH 0.1.5-rc.1–0.1.6 的 Corn模式是目录式预设:首次安装或升级后执行 node scripts/seed-preset.mjs(或设置页重建),写入 $DSH_HOME/.agent-presets/corn-bench/。DSH 0.1.7+ 由 Host 自动声明注册,无需 seed。新建 Session 后生效。

corn_bench 只出现在这个预设里。Agent 需要时自己调用,不把现场状态塞进每一轮系统提示。

| action | 作用 |
| status | 当前工程、Target、下载包、进行中任务、操作记录、连接真实状态与点位 runtimeStatus |
| ls | 列出工作区内目录和 .uvprojx(不含 .uvmpw) |
| select | 选定工程 |
| build | 编译 |
| map | 当前 Target 的组、源文件、包含关系和函数名;超出上限时带 truncated |
| read | 不传 address 则读点表全部段;传入则单次读 |
| write | 写线圈 / 保持寄存器:values 长度 1 走 FC05/06,大于 1 走 FC15/16;写入后自动回读。Agent 写点需界面批准(上位机确认卡,5 分钟内有效) |
| manual | 请求用户完成现场人工操作;text 必填 |
| visualization | op=list\|get\|add\|update\|remove\|layout。layout 必须带 expectedConfigVersion 与 items[{id,x,y,w,h}];CONFIG_DRIFT 后重新 list/get 再提交 |

另有 corn_debug(与 corn_bench 隔离)和 debug_snapshot。

能力说明

编译与烧录。 失败编译给出错误数、前几条原文、阶段和日志路径;「查看完整日志」在应用内打开(尾部 256KB,可搜索)。烧录走确认卡:目标、固件、大小、sha256,批准后才 program verify reset exit。OpenOCD 只烧录哈希校验后的固件快照。

上位机。 流程:创建连接 → 配置 COM/TCP → 连接 → 添加设备(名称 + 连接内唯一 Unit ID)→ 设备卡片内加点位(唯一键 = 连接+设备+功能码+地址)→ 开始采集。功能码 01/03 可写(FC05/06 单点、FC15/16 批量),02/04 只读。写入后显示 写前值 → 目标值 → 回读值。超时返回 WRITE_OUTCOME_UNKNOWN,不要直接重试,先读回再决定。连接 / 断开中不可改端点参数。也支持从机(Slave)监听,不启动主动轮询。

串口报文。 RTU 记 ADU(含 CRC);TCP 显示协议归一化报文。该页只展示用过的 RTU 通道,负责筛选查看,不负责打开串口。串口由上位机连接持有;Windows 下 COM 独占,占用返回 PORT_IN_USE。

点表 / 告警 / 可视化。 点位可带倍率、偏移、单位、告警上下限;CSV 导入导出。监视开关决定是否进入可视化数据源(每点 600 样本环形缓存)。告警开关关闭后立即把已激活告警转为恢复。可视化以组件为中心:GridStack;曲线/柱状图优先 ECharts(无运行时则 uPlot / CSS);数值卡/开关。关联点位只列已监视且类型匹配的点;数据源失效时组件保留并提示修复。

写入边界。 Host 是工作区唯一写者。配置走 mutateConfig(成功才递增 configVersion);实时值/趋势/告警/报文走同一把 runExclusive 队列上的 mutateRuntime。Agent 改配置无需确认卡;真实线圈/寄存器写入、烧录、复位仍需界面批准。Agent 与 Host 分进程时走 HTTP 命令桥;system.ping 无副作用。失败返回 HOST_UNAVAILABLE / HOST_TIMEOUT / HOST_UNAUTHORIZED / HOST_FORBIDDEN / HOST_INVALID_RESPONSE,不静默降级。缺 Host 句柄时不猜 127.0.0.1:3080。

会话。 Corn 自动服务当前 Session。后台 Session 的操作只记录,不抢焦点。Agent 定位目标时短时高亮,右下角提示「Agent 已定位到 …」。

运行调试(实验性能力已落地,真机暂缓)。 DebugRuntime 是唯一状态权威。GDB/MI + OpenOCD;TargetLease 互斥;启动必须带不可变 ResolvedDebugLaunchSpec 和 approvalRequestId。Keil UVSOCK 仿真器有 fake server 测试,Windows µCorn 真机未做。ProgramModel 用 Lezer C/C++ AST(confidence: 'ast'),启发式分析器降级为 heuristic。corn_debug 的 verify 做场景化断言(表达式、遥测、无告警、stable-for-duration)。

Windows 无 Python 时,从 .tgz 安装即可用 Keil 工程扫描 / 编译和 Modbus 主机读写。Keil 仍要本机 UV4;烧录仍要外部 OpenOCD。macOS 自动测试不能代替 Windows 10/11 实机,见 docs/WINDOWS_ACCEPTANCE_0.27.md(状态 DEFERRED_WINDOWS_ACCEPTANCE)。

还没做:CAN 监视。

开发

实现优先改 src/{domain,application,infrastructure,interfaces,ui};根目录 bench-.mjs 仅为兼容 re-export。架构决策见 docs/architecture/(ADR-024 客户端原语、ADR-025 公共 UI 组件契约)。

npm install
npm test
npm run quality
npm run build

npm test 含 build:check。不要手改生成的 client.js。dsh plugin add 装到运行时后只有生产依赖,不要在那个安装目录跑测试。

归档

原合集仓库已并入本仓库:现行工程计划在 docs/plans/suite/,历史计划与合集变更记录在 docs/archive/suite/。已移除的旧 harness 插件(0.2.1,仅适用 DSH ≤ 0.1.6)源码快照和原合集的完整 git 历史保存在 Release archive/legacy-2026-10。

授权

本项目以 PolyForm Noncommercial License 1.0.0 开源,全文见 LICENSE.md。

- 可以:个人学习、研究、测试、自用,以及非营利组织、教育和公共研究机构使用;可以修改和分发,但必须附上 LICENSE.md(含开头的 Required Notice 署名行)。
- 不可以:任何商业用途(包括把它或修改版用于销售、收费服务、商业产品或公司内部的营利业务)。商业授权请联系作者 xingyingyuzhui。
- 注意:非商业授权不属于 OSI 定义的“开源许可证”,这里的“开源”指源码公开、可在非商业条件下使用。
- 0.30.2 及更早的版本按当时附带的 MIT 授权发布,已取得的副本仍适用 MIT;本授权从 0.31.0 起生效。
- 打包进 client.js 的第三方依赖(CodeMirror、ECharts、TanStack、uPlot、gridstack、modbus-serial、serialport 等)仍按各自的 MIT / ISC / Apache-2.0 / BSD 授权,与本项目的非商业授权不冲突。

Copyright 2026 xingyingyuzhui. Corn 名称与图标归作者所有。
预览分享卡片长什么样 ↓xingyingyuzhui/dsh-corn-bench
分享 · DeepSeek Harness Hub
xingyingyuzhui/dsh-corn-bench

DSH 插件:Vision bench——在会话视图里做 Keil 调试和 Modbus HMI

回到顶部