delivery-board-dsh
Verified@gxx-labs/delivery-board-dsh · v0.3.3 · MIT · Web UI
DSH 插件:左侧栏「项目管理」入口 + 多项目交付看板,首页一览各项目进度与关键状态,点入查看详情;数据落到本机 JSON 文件。UI 复用 DSH 设计系统 primitives 与 --dsw-* 令牌。
Install
dsh plugin add @gxx-labs/delivery-board-dsh Confirm the layer applied with dsh --profile default --dump-config — see the install guide.
Source
Published to npm without a public repository. Inspect the package contents before installing.
Tags
Readme
@gxx-labs/delivery-board-dsh
DSH 插件:左侧栏「项目管理」入口 + 多项目交付看板。首页一屏看清每个项目的 进度与关键状态,点进去看详情并直接编辑。
包名
@gxx-labs/delivery-board-dsh中的-dsh后缀用于标明这是 DeepSeek Harness 插件。 HTTP 路由(/api/delivery-board/*)与数据目录(<DSH_HOME>/delivery-board/) 保持不含后缀,升级到本版本不会影响既有数据。
功能
左侧栏入口 — 在 sidebar.panellist 注册图标与「项目管理」,与「插件」
「自动化任务」并列;点击切换到中央 main 面板。
看板首页
- 顶部统计卡:项目总数 / 进行中 / 阻塞 / 已交付 / 有风险 / 平均进度
- 项目卡片:名称、状态徽章、进度条、客户、负责人、截止日期、风险或逾期标记、 下一步行动、里程碑与任务完成数、风险数
- 搜索(项目 / 客户 / 负责人)与状态筛选(含「有风险」)
- 空态与「无匹配结果」态
新建项目 — 名称(必填)、客户、负责人、状态、优先级、起止日期、概述、下一步行动。
项目详情
- 返回看板;删除项目(二次确认)
- 交付进度:无任务时可手动填写;有任务时由任务完成度自动计算并标注
- 项目信息编辑(上述全部字段)——未改动时保存按钮为禁用的「已保存」
- 里程碑:增 / 勾选完成 / 删;逾期项标红并计入风险
- 任务:增 / 改状态(待办 · 进行中 · 已完成)/ 删
- 风险项:增 / 删,按严重度着色
数据
| 项 | 值 |
|---|---|
| 文件 | <DSH_HOME>/delivery-board/delivery.json(默认 ~/.dsh/delivery-board/delivery.json) |
| 覆盖 | 环境变量 DELIVERY_BOARD_HOME |
| 写入 | 先写 <file>.<pid>.tmp 再 rename 覆盖;进程内写操作串行化 |
读取永不抛错:文件缺失、JSON 损坏、结构非法一律降级为空看板——宁可显示空态, 也不因为一个坏文件白屏。
风险判定:状态为 blocked;或进行中且已过截止日期;或存在逾期未完成的里程碑。
已交付 / 已归档不计风险。「今天」由宿主按本地日期计算并随响应下发,
客户端不做时区推断。
HTTP 接口
| 方法 | 路径 | 说明 |
|---|---|---|
| GET | /api/delivery-board/state |
完整看板快照(含 today 与派生统计) |
| POST | /api/delivery-board/project |
新建(无 id)或更新项目 |
| POST | /api/delivery-board/project/delete |
{ id } |
| POST | /api/delivery-board/project/reorder |
{ ids: [...] } |
| POST | /api/delivery-board/task |
{ projectId, task } |
| POST | /api/delivery-board/task/delete |
{ projectId, taskId } |
| POST | /api/delivery-board/milestone |
{ projectId, milestone } |
| POST | /api/delivery-board/milestone/delete |
{ projectId, milestoneId } |
读开放(同源页面即可);写操作限本机 loopback,非本机返回 403。 写成功后一律回传完整快照,客户端以此为准,不自己算派生指标。
开发
pnpm install
pnpm run build # esbuild → dist/client.js
pnpm test # node:test,95 个用例
pnpm run verify # 校验 bundle 是否符合客户端模块契约
两个容易踩的坑
- 侧栏
id必须等于main的key。ctx.layout.selectPanel(id)在main未注册该 key 时直接抛错。两端共用PANEL_ID常量,并由verify-bundle.mjs与test/bundle.test.mjs双重断言。 - bundle 包装的
id必须等于package.json的包名——客户端加载器按包名 建模块表键,写错会在浏览器里才炸。构建脚本从package.json读取,不硬编码。
另外:package.json 的 dsh.client.inject 是包名数组(仅用于 boot 图排序),
bundle 导出的 inject 是Cordis 服务键,两者语义不同。
为什么用同源路由而不是 Remote/typert
已安装的第三方插件拿不到 host.call(那是动态运行时的契约),而 typert 的
@Remote 契约由 DSH 自身的构建流水线生成、第三方无法手写。同源
webServer 路由 + fetch 是这类插件读写宿主数据的可行路径。
安装
方式一:在 DSH 界面里安装(推荐)
设置 → 插件 → 添加插件,填入包名:
@gxx-labs/delivery-board-dsh
本包声明了 dsh.bundle.patch(指向自带的 cordis.patch.yml),所以 DSH 的
安装器能把它作为 profile layer 正确挂载——Loader 行由包自己提供,无需手工
编辑 profile。
若安装器提示
@gxx-labs/delivery-board-dsh declares no dsh.bundle,说明拿到的是 0.1.0;0.1.1 起已自带 bundle patch,请升级。
方式二:命令行
dsh plugin --profile <profile> add @gxx-labs/delivery-board-dsh
方式三:手工安装(不使用插件管理器时)
# 1. 备份(示例用 desktop profile)
cp ~/.dsh/profiles/desktop/{package.json,pnpm-lock.yaml,cordis.patch.yml} ~/.dsh/profiles/desktop/.backup/
# 2. 在 profile 的 package.json 加依赖
# "@gxx-labs/delivery-board-dsh": "^0.2.0"
# 3. 在 profile 目录安装
pnpm install
# 4. 若无插件管理器代劳,在 cordis.patch.yml 追加
# (行名必须是裸包名,子路径会导致浏览器半不被注册)
# - insert:
# - id: delivery-board-dsh
# name: '@gxx-labs/delivery-board-dsh'
profile 若声明 patchReload: live 且 dsh-hmr 处于 active,改动会热应用;
否则刷新页面,再不行则重启 DSH(Node 会缓存已加载模块的真实路径)。
注意:本插件只依赖宿主的运行时服务与静态种子模块(
react、@deepseek-ai/dsh-client-ui-primitives),没有把@deepseek-ai/*写进 依赖——它们由 DSH 自身提供。装到 profile 里若出现 peer 依赖告警属正常。
前端规范
本插件按 DSH 前端规范(对照 shipped 的 dsh-client-ui-schedule /
dsh-client-ui-plugin-manager)改造:
- 复用 primitives:
Button/Input/Tag/Checkbox/Modal/SegmentedControl/Toast/Icon*均来自@deepseek-ai/dsh-client-ui-primitives(静态种子,无额外依赖)。 DSH 无进度条 / Textarea / Select 原语,这三处保留功能自有实现并对齐 Input 的几何(32px 高、0.5px 描边、--dsw-radius-md)。 - CSS Modules:
client/Dbd.module.css经 esbuildlocal-css作用域化, 构建脚本把它按 DSH 约定注入为<style data-plugin data-plugin-css>—— 客户端模块系统claimStyles()认领、卸载时removeOwnedStyles()清理。 - 只用设计令牌:圆角走
--dsw-radius-{sm,md,lg},描边 0.5px--dsw-alias-border-l4,文案色阶label-primary/secondary/tertiary/caption, 交互底--dsw-alias-interactive-bg-hover,焦点--dsw-focus-ring-*。 - 页面骨架对齐 shipped 页面:960px 内容宽、
clamp(24px,4vw,48px)留白、 页首h120px/500/28px、控件高度 28/32/36。 - 文案 i18n:
ctx.locale.register(NS, { zh, en }),两处注册都声明locale: NS(渲染框架据此注入t),侧栏label用 thunk 以便切语言跟随。 - 无障碍:破坏性操作走
Modal(不用window.confirm);图标按钮带aria-label;进度条带role="progressbar";筛选带role="tablist"; 加载/空态带role="status"、错误带role="alert";尊重prefers-reduced-motion。
结构
package.json 双面包声明(main = 宿主半,exports["./client"] = 浏览器半)
lib/store.js 纯数据层:读写、校验、派生指标
lib/mutations.js 变更操作(读-改-写 + NOT_FOUND 哨兵)
lib/index.js 宿主半:webServer 路由
client/index.tsx 浏览器半:侧栏入口 + 看板 + 详情 + 结果提示(JSX + primitives)
client/Dbd.module.css CSS Modules:只用 --dsw-* 令牌,经 esbuild local-css 作用域化
dist/client.js 构建产物(__ModuleLoader__ 包裹,CSS 随 bundle 注入)
scripts/build-client.mjs esbuild 构建(JSX automatic + CSS local-css + style 注入)
scripts/verify-bundle.mjs 契约/规范校验(纯度、CSS 令牌、槽位一致性)
test/ store / routes / plugin-load / bundle / render / packaging
pnpm run verify 会在发布前把上面的规范断言跑一遍(模块纯度、CSS 令牌、
无硬编码颜色、无 window.confirm、侧栏 id 与 main key 一致等)。