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

插件面板宿主 jonah791/dsh-panel

DeepSeek Harnessv0.0.1
jonah79147 天前有提交已提供中文文档扫描:含敏感能力

集中托管插件前端,统一渲染派发并记录审计

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

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

自动兼容检查有告警:npm 同名包「dsh-panel」归属 dushaobindoudou/dsh-panel,装到的可能不是本插件。
安装命令 · 需先装 dsh CLI 引擎
dsh plugin --profile web add jonah791/dsh-panel
该包不可直接 npm 安装,改从 GitHub 源安装(明细见下方安装检查)

状态速览

判定依据:实装验证 · 静态安装检查 · 自动扫描 · 仓库维护状态
信任档位:需留意
是什么
dsh 原生插件 · ui
装得上吗
实装验证未通过(unknown),装前请到仓库确认最近更新与 issue
L4 · 真实安装等级说明 →
安全吗
本站尚未对该插件做风险分级
暂未覆盖,不等同于无风险
还在维护吗
更新放缓:最近一次提交在 47 天前
档位由哪些信号合成

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

验证判据与等级说明 →
⚠︎ 实装验证未通过(unknown · 2026/11/4) ——可能是验证环境差异,装前建议到 GitHub 仓库确认最近更新与 issue。
社区实装还没有人打卡 · 装过的第一个就是你
安装兼容性检查⚠ 装前注意

npm 同名包「dsh-panel」归属 dushaobindoudou/dsh-panel,装到的可能不是本插件

展开查看检查明细 ↓

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

✓npm 包dsh-panel @ 0.0.1
✓Node 引擎未声明 engines.node
✓dsh CLI 依赖未声明 dsh 版本约束
✓入口文件main/exports/bin 已声明

验证方式:npm registry 存在性 + package.json 静态校验 · 最后检查 2026/10/8 06:34:24

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

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

读写/删除本地文件
查看扫描证据(共 78 处,展示前 48 条)
  • 写入本地文件
    src/audit.ts:43
    mkdirSync(dir, { recursive: true })
  • 写入本地文件
    src/audit.ts:44
    appendFileSync(join(dir, 'audit.jsonl'), JSON.stringify(record) + '\n', 'utf8')
  • 读取本地文件
    src/index.ts:109
    if (existsSync(file)) {
  • 读取本地文件
    src/index.ts:110
    try { return readFileSync(file, 'utf8') } catch { }
  • 读取本地文件
    src/index.ts:344
    if (!existsSync(target)) continue
  • 读取本地文件
    src/index.ts:346
    const body = readFileSync(target)
  • 读取本地文件
    src/index.ts:393
    if (!existsSync(target.file)) {
  • 读取本地文件
    src/index.ts:398
    if (!statSync(target.file).isFile()) {
  • 读取本地文件
    src/panels/agent-teams.ts:79
    if (!existsSync(file)) return undefined
  • 读取本地文件
    src/panels/agent-teams.ts:81
    return JSON.parse(readFileSync(file, 'utf8')) as T
  • 读取本地文件
    src/panels/agent-teams.ts:106
    if (!existsSync(dir)) return { files, messages, detail }
  • 读取本地文件
    src/panels/agent-teams.ts:107
    for (const name of readdirSync(dir)) {
  • 读取本地文件
    src/panels/agent-teams.ts:110
    if (!statSync(file).isFile()) continue
  • 读取本地文件
    src/panels/agent-teams.ts:115
    n = readFileSync(file, 'utf8').split(/ ? /).filter((l) => l.trim() !== '').length
  • 读取本地文件
    src/panels/audit.ts:52
    if (!existsSync(file)) return { records: [], corrupt: 0, truncated: false, bytes: 0 }
  • 读取本地文件
    src/panels/audit.ts:57
    bytes = statSync(file).size
  • 读取本地文件
    src/panels/audit.ts:77
    raw = readFileSync(file, 'utf8')
  • 读取本地文件
    src/panels/growth-profile.ts:71
    if (!existsSync(file)) return undefined
  • 读取本地文件
    src/panels/growth-profile.ts:73
    return JSON.parse(readFileSync(file, 'utf8')) as T
  • 读取本地文件
    src/panels/growth-profile.ts:103
    if (!existsSync(root)) return out
  • 读取本地文件
    src/panels/growth-profile.ts:104
    for (const name of readdirSync(root)) {
  • 读取本地文件
    src/panels/growth-profile.ts:107
    if (!statSync(dir).isDirectory()) continue
  • 读取本地文件
    src/panels/growth-profile.ts:159
    if (!existsSync(root)) continue
  • 读取本地文件
    src/panels/plugin-manager.ts:40
    if (!existsSync(patchFile)) return out
  • 读取本地文件
    src/panels/plugin-manager.ts:41
    const lines = readFileSync(patchFile, 'utf8').split(/ ? /)
  • 读取本地文件
    src/panels/plugin-manager.ts:67
    for (const entry of readdirSync(dir)) {
  • 读取本地文件
    src/panels/plugin-manager.ts:70
    if (statSync(full).isDirectory()) collectSources(full, out)
  • 读取本地文件
    src/panels/plugin-manager.ts:80
    for (const entry of readdirSync(d)) {
  • 读取本地文件
    src/panels/plugin-manager.ts:83
    const st = statSync(full)
  • 写入本地文件
    src/panels/plugin-manager.ts:170
    writeFileSync(tmp, content, 'utf8')
  • 写入本地文件
    src/panels/plugin-manager.ts:171
    renameSync(tmp, file)
  • 写入本地文件
    src/panels/plugin-manager.ts:213
    writeFileSync(join(dshHomeDir, '.hot-reload-flag'), JSON.stringify({ workspace: join(dshHomeDir, '..'), note }, null, 2), 'utf8')
  • 写入本地文件
    src/panels/taskboard.ts:94
    writeFileSync(tmp, content, 'utf8')
  • 写入本地文件
    src/panels/taskboard.ts:95
    renameSync(tmp, file)
  • 读取本地文件
    src/panels/taskboard.ts:100
    if (!existsSync(file)) return { tasks: [], note: `任务板文件缺失:${file}` }
  • 读取本地文件
    src/panels/taskboard.ts:102
    const parsed = JSON.parse(readFileSync(file, 'utf8')) as { tasks?: unknown }
  • 读取本地文件
    src/panels/taskboard.ts:114
    if (!existsSync(dir)) return out
  • 读取本地文件
    src/panels/taskboard.ts:115
    for (const name of readdirSync(dir)) {
  • 读取本地文件
    src/panels/taskboard.ts:119
    const parsed = JSON.parse(readFileSync(file, 'utf8')) as ArchiveRecord
  • 读取本地文件
    src/panels/taskboard.ts:310
    if (!existsSync(boardFile)) {
  • 写入本地文件
    src/panels/taskboard.ts:329
    mkdirSync(archiveDir, { recursive: true })
  • 写入本地文件
    src/panels/taskboard.ts:336
    renameSync(target, `${target}.corrupt-${localClock(now)}`)
  • 读取本地文件
    src/panels/tavern.ts:215
    const st = statSync(file)
  • 读取本地文件
    src/panels/tavern.ts:231
    if (!existsSync(dir)) return []
  • 读取本地文件
    src/panels/tavern.ts:234
    names = readdirSync(dir)
  • 读取本地文件
    src/panels/tavern.ts:266
    if (!existsSync(dir)) return { exists: false, files: 0, bytes: 0 }
  • 读取本地文件
    src/panels/tavern.ts:272
    entries = readdirSync(current, { withFileTypes: true })
  • 读取本地文件
    src/panels/tavern.ts:290
    bytes += statSync(full).size
扫描于 2026/11/4(0 天前) · 范围 全包扫描(包内未声明入口) · 来源 GitHub 仓库

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

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

功能亮点

  • 托管插件前端
  • 统一渲染派发
  • 记录审计

独立实时前端面板:宿主托管自包含 HTML + HTTP API,零官方 client 依赖。首版=插件管理(替代官方失效的插件 tab)

README

由 DeepSeek 最新模型翻译生成
dsh-panel — 面板宿主(Panel Host) 一句话:把「每个插件各写一套前端」收敛成「每个插件提交一份声明」的前端宿主——一个 URL(http://127.0.0.1:3080/panel/)、一套外壳、一张注册表;贡献方只提供视图规格(ViewSpec)+ 动作表(Action ABI),宿主负责渲染、派发、审计、实测健康与降级。 为什么值得用:自研前端散落各处时,没有人能回答「谁在什么时候对哪个页面做了什么」——安全机制不可观测就等于不存在。本插件把「渲染 / 派发 / 审计 / 实测健康」四件事收进一个宿主:贡献方声明即 effect(插件卸载面板立刻消失,无幽灵),未知动作零副作用,破坏性动作要二次确认,触及「须请示三类」的动作宿主直接拒绝并转请示通道。而且它零官方 client 依赖——官方前端坏了,面板照常可用。 能力 宿主职责:托管外壳与静态资源 · 维护注册表(含实测健康)· 把贡献方的 view() 渲染成视图规格 · 按动作 ABI 派发并每次落一条审计 · 施加超时与降级。
展开完整文档(README 剩余 1 节)
dsh-panel — 面板宿主(Panel Host)

一句话:把「每个插件各写一套前端」收敛成「每个插件提交一份声明」的前端宿主——一个 URL(http://127.0.0.1:3080/panel/)、一套外壳、一张注册表;贡献方只提供视图规格(ViewSpec)+ 动作表(Action ABI),宿主负责渲染、派发、审计、实测健康与降级。

为什么值得用:自研前端散落各处时,没有人能回答「谁在什么时候对哪个页面做了什么」——安全机制不可观测就等于不存在。本插件把「渲染 / 派发 / 审计 / 实测健康」四件事收进一个宿主:贡献方声明即 effect(插件卸载面板立刻消失,无幽灵),未知动作零副作用,破坏性动作要二次确认,触及「须请示三类」的动作宿主直接拒绝并转请示通道。而且它零官方 client 依赖——官方前端坏了,面板照常可用。

能力

宿主职责:托管外壳与静态资源 · 维护注册表(含实测健康)· 把贡献方的 view() 渲染成视图规格 · 按动作 ABI 派发并每次落一条审计 · 施加超时与降级。

接入契约(消费方视角;完整签名见 docs/semantic.md §4):

// 必须用 ctx.inject 等待宿主(不得用 ctx.get('panel') 一次性探测——加载顺序会让它拿到 undefined 且永不重试)
ctx.inject(['panel'], (panelCtx) => {
panelCtx.panel.register({
id: 'my-panel', // 全局唯一 [a-z0-9-]+,重复注册 fail-loud title: '我的面板', order: 100, // 导航排序(小→前) icon: 'plug', // 宿主图标白名单键(非自由 SVG) description: '一句话用途', // 自检面板展示
view: async (params) => ViewSpec,
actions: { /* 动作表 / },
style: { accent: '#f472b6' }, // 可选:自带视觉(宿主只认 token,不认自由 CSS)
}) // 返回 disposer;注册即 effect })

HTTP 面(全部 JSON 响应统一信封 {ok, ...}):

| 方法 | 路径 | 语义 |
| GET | /panel/ | 外壳 HTML(独立资源文件;cache-control: no-store) |
| GET | /panel/assets/ | 宿主静态资源(prefix 路由,白名单目录,禁路径穿越) |
| GET | /api/panel/registry | 注册表投影:[{id,title,order,icon,description,health}](不含视图规格) |
| GET | /api/panel/view?id= | {ok, spec, generatedAt, durationMs, degraded?} |
| POST | /api/panel/action | 派发动作(校验 panelId/actionId,写审计) |
| GET | /api/panel/selfcheck | 宿主自检:贡献健康实测 + 宿主版本 + 计时统计 |

内置面板(宿主自带,随宿主注册):

| id | 标题 | order | 说明 |
| plugin-manager | 插件管理 | 10 | 自研插件清单/构建态与挂载态(启停经 patch + 哨兵生效) |
| taskboard | 任务板 | 20 | 板面与流转:计数、分布图、新建/认领/完成、终态归档 |
| growth-profile | 养成档案 | 30 | 自我模型 + 记忆规模 + 周目存档 + 技能/插件规模(只读) |
| agent-teams | 分身 | 40 | 成员状态、任务清单与 inbox 积压(只读) |
| audit | 面板审计 | 50 | 宿主自己的派发审计(只读,不提供改写通道) |

降级语义:贡献方 view() 抛错 → 该面板显示错误原文,外壳与其余面板不受影响;view() 超过 viewTimeoutMs → 标记超时;未知 panelId/actionId → 400/404 且零副作用(但仍写一条审计)。

快速开始

1) 装依赖:

"dsh-panel": "link:/self-plugins/dsh-panel"

2) 挂组合(零配置可用;下列项按需覆盖):

- id: panel
name: dsh-panel
config:
defaultProfile: web

3) 30 秒验证:

curl -s http://127.0.0.1:3080/api/panel/registry | head -c 300
期望:{"ok":true,"host":{"version":"0.4.0","startedAt":"…"},"panels":[…5 个面板…]}
curl -s http://127.0.0.1:3080/api/panel/selfcheck
期望:ok:true + 各贡献健康度实测 + 宿主版本

浏览器打开 http://127.0.0.1:3080/panel/ → 期望左侧导航 5 项、点任意一项能出内容(而非空壳或 404)。

配置

| 项 | 默认 | 说明 |
| enabled | true | 宿主开关 |
| dshHome | ''(→ $DSH_HOME → ~/.dsh) | DSH 主目录解析起点 |
| profilesDir | ''(→ /profiles) | profile 目录(插件管理面板用) |
| selfPluginsDir | ''(→ /self-plugins) | 自研插件目录(插件管理面板用) |
| defaultProfile | web | 默认 profile 名 |
| viewTimeoutMs | 2000 | 取视图超时(超时 → 该面板降级,外壳不受阻) |
| actionTimeoutMs | 10000 | 派发动作超时 |

落盘与自证(出问题时先看这里)

审计轨:每次派发写一行到 /panel/audit.jsonl(写盘吞错不反噬派发):

{"at":"2026-09-13T09:41:30.712Z","panelId":"taskboard","actionId":"claim","level":"write",
"paramsDigest":"83b51b5ad28488cd","outcome":"ok","durationMs":1,"message":"已认领 t-2a6731ae(claimed,负责人 alice)"}

| 字段 | 含义 |
| at / panelId / actionId | 何时、对哪个面板的哪个动作 |
| level | 动作分级(read/write/destructive)——决定是否要二次确认 |
| paramsDigest | 参数摘要(不落原文,避免把敏感值写进日志) |
| outcome | ok / denied / error(被拦下也有行——这才是审计的意义) |
| durationMs / message | 耗时与人类可读结果/拒绝理由 |

本机实测(2026-09-14):audit.jsonl 4 行,末行即上例。

一条命令答五问(本插件是生态里的正面样板——五问全可答):

tail -3 "$DSH_HOME/panel/audit.jsonl"; curl -s http://127.0.0.1:3080/api/panel/registry
① 线上跑的是哪个构建 → registry 的 host.version + host.startedAt(实测 0.4.0 / 2026-09-14T07:06:07Z) ② 谁发起 / 投给谁 → audit 的 panelId + actionId + at ③ 断在哪一段 → audit 的 outcome(ok/denied/error)+ message;view 断点看 view 响应的 degraded ④ 结果质量 → /api/panel/selfcheck 的实测健康 + 该面板是否 degraded ⑤ 耗时与预算 → audit 的 durationMs(动作)与 view 响应的 durationMs(视图,对照 viewTimeoutMs=2000)

生效判据与回退

生效判据(三选一,按可靠性排序):
1. 行为级:GET /api/panel/registry 返回 ok:true 且 panels 为你预期的数量(本机 5 个)+ host.version 与 package.json 一致;
2. 页面级:浏览器打开 /panel/ 能切到任意面板并看到内容(截图复核,别只看接口——单测全绿时缺陷仍可能只在视觉层暴露);
3. 生态级:plugin_boot_status(dsh-plugin-bootreport)的 liveNow 含本插件。

注意:重新构建 ≠ 生效——产物 mtime 新只证明「构建过」,进程启动时间晚于产物 mtime 才算「在跑它」。本插件构建含两步(tsc + copy-assets.mjs,客户端另有 bundle-client.mjs),只跑 tsc 会得到一个没有外壳资源的宿主。

回退(三档):
- 组合级:preset 给 panel 行加 disabled: true → 面板整体下线,官方 Web GUI 完全不受影响(本插件从不修改官方界面);
- 源码级:git -C self-plugins/dsh-panel revert → 重新构建(含 assets/client)→ 预检 → 哨兵重启;
- 数据级:audit.jsonl 可随时删除(纯审计,无业务状态);贡献方数据不归宿主,宿主从不持久化它们。

测试

npm test # = node --test "tests/*.test.mjs"

51 例离线测试(8 个文件):

| 文件 | 例数 | 覆盖 |
| registry.test.mjs | 12 | 注册表核心:非法 id / 重复 id fail-loud(不静默覆盖)、dispose 后消失(无幽灵)、排序与投影形状、健康度迁移(含恢复) |
| taskboard-write.test.mjs | 9 | 写入通道:板面解析失败 → 拒绝写入、写前写后字节相同(只读可宽容、写入必须苛刻)、并发写、终态归档 |
| taskboard.test.mjs | 6 | 板面视图:计数/分布形状、空板与坏行降级 |
| viewspec-validation.test.mjs | 6 | 视图规格校验:已知 kind 缺必备字段 / chart 取值非法 / form 缺 actionId / 超块数与超嵌套 → 降级;未知 kind 放行 |
| audit-panel.test.mjs | 5 | 审计页:坏行逐行跳过并计数、limit 边界(非法→默认、越界→夹到 500)、>512KB 只读尾部并如实标注 |
| client-bundle.test.mjs | 5 | 零官方 client 依赖:产物 grep + 外壳体积 + 无公网请求断言 |
| panel-style.test.mjs | 5 | 皮肤层:?theme= 优先级、非法 accent 注册 fail-loud、切主题不丢标签页选择 |
| panels-expressiveness.test.mjs | 3 | 表现力块族:块组合渲染、超块数上限降级 |

无网络依赖:视图/动作/审计全在离线夹具上断言(临时目录 + 桩贡献方)。

设计要点

- 注册即 effect,卸载即消失:面板身份是合成级契约——宿主不持久化贡献方数据,插件禁用后面板立刻从注册表消失,绝不出现「幽灵面板」。
- 重复 id 必须 fail-loud:第二个同 id 注册抛错而不是覆盖——撞车 = 配置错误,静默覆盖会让「谁在渲染」变成不可知的谜。
- 必须用 ctx.inject(['panel'], …) 等待宿主,不得 ctx.get('panel'):加载顺序会让一次性探测拿到 undefined 且永不重试,表现为「插件健康但面板 404」——这是实践踩出来的接入纪律。
- 只读可宽容,写入必须苛刻:板面解析失败时拒绝写入(写前写后字节相同),否则空板会覆盖真实数据;读取时坏行跳过并计数即可。
- 审批门优先于确认门:触及「须请示三类」(删数据/动凭据/动核心引擎)的动作,即使调用方带了 confirm:true 也拒绝派发(requires-approval)——宿主不得成为绕过主体性铁律的通道。
- 审计是安全机制的可观测面:被拦下的动作也写行(denied),并且参数只落摘要(paramsDigest)不落原文——记录了「做过什么」又不制造新的泄露面。
- 零官方 client 依赖:外壳是自包含资源(本机实测 lib/assets/shell.html 79,729 字节,/panel/ 一次返回 72,949 字符、cache-control: no-store),构建期才需要 Node 脚本——官方前端坏了面板照常可用,代价是自带一套资源与构建步骤。

相关文档

| 文档 | 内容 |
| docs/semantic.md | 权威契约(284 行):定位与负边界、术语、概念模型、注册契约 / 视图规格 / 动作 ABI / HTTP 面 / 失效降级 / 皮肤层(逐条 [MUST])、信任与安全边界(含能力诚实声明)、与官方 GUI 的关系、迁移路径、可证伪验收 15 条(已证 11 · 待线上 4)、未决问题 Q1–Q6 |
| alice-digital-life | 本插件所属生态的中心索引(全部自研插件) |
| 技能 ui-visual-verification | 界面视觉与交互验收(几何/对比度/跨刷新状态/真实副作用四类断言 + 截图复核清单)——单测全绿时三个缺陷全靠看图发现的教训 |
| 技能 dsh-panel-plugin | 面板插件开发方法论(webServer 托管 + 独立资源 + 同源 fetch + 命名规范),本插件的前身 |
| 技能 semantic-doc-first | 先写「是什么」再让实现逼近它、用实践回修文档的方法(本插件是该方法的第一号实践) |

License

MIT © jonah791

本插件属于我的数字生命爱丽丝(alice-digital-life)的 DSH 自研插件生态。
预览分享卡片长什么样 ↓jonah791/dsh-panel
分享 · DeepSeek Harness Hub
jonah791/dsh-panel

集中托管插件前端,统一渲染派发并记录审计

这是你的仓库?认领条目

回到顶部