@cnbmtech/dsh-zentao-session
DeepSeek Harness 的禅道(ZenTao)会话式集成插件:11 个模型工具 + 一个「我的工作」面板(BUG / 任务 / 需求),可把条目一键送进对话。
走禅道的会话式接口(
/my-*.json+ 表单页),不依赖 REST API v1/v2 —— 因此在那些api.php被网关改造、官方 REST 不可用的禅道实例上照样能用。
能力
面板(左侧栏「更多」菜单 → 「禅道」;同一行右边的「侧边栏 + 眼睛」可让它常驻左侧栏,见「侧栏入口」)
-
三个页签:我的 BUG / 我的任务 / 我的需求,每个页签自带浏览范围下拉(指派给我 / 由我创建 / 由我解决|完成 / 我评审 / 由我关闭 …,与禅道「我的地盘」的 tab 逐一对应)
-
列表头只留刷新,条数与分页在卡片页脚(整组靠右):页脚从右往左是分页(
‹ 当前页 / 总页数 ›+ 每页 20 / 50 / 100)与条数(共 N 条), 分页只此一处(早期条数写成「7 / 7 条」与页码「1 / 1」并排,会被读成两处分页;后来挤进头部,面板一窄就整组掉行、看着像错位,故下沉到页脚并整体贴右);刷新按当前范围 + 当前页重新取数,不会把第 2 页打回第 1 页; 筛选/搜索激活时刷新改走query通道强制重拉(force=1,连行集/计数缓存一起绕过),既保持筛选口径也拿到新数据(2026-10-30 修复:此前刷新会把未过滤口径覆盖回筛选视图) -
条数口径统一为服务端总数:无筛选时,页脚条数、页签上的数字、统计卡主卡三处都用服务端返回的总数(recTotal),不再各说各话; 统计卡的子卡(未确认 / 已确认 / 已解决 …)是全范围计数:禅道的「我的」接口不给分状态总数(
pager里只有 recTotal / pageTotal,且任何查询参数都被忽略), 所以由宿主侧把当前范围整批取回后本地按状态 / 确认度聚合(每页 200 条并发拉,最多 40 页),结果带 60 秒缓存,浏览器端只收几十字节; 子卡文案写明「全范围 …」,聚合不全时(超出页数上限或部分页失败)自动退回本页口径并标「本页 …」 -
列表按所属产品 / 所属项目分组(2026-10-30):列表默认分组展示,组头是一行吸顶的「所属产品:<名称> (N)」(任务页签是「所属项目:<名称> (N)」), 组头本身是纯标签:置灰、不可点,不额外缩进(只留一个空格不贴边),只用来标出下面这组条目属于谁; 同组条目按列表原顺序排在一起;BUG 与需求按产品(对齐禅道 BUG/需求列表的「所属产品」维度),任务按项目(对齐任务列表的「所属项目」列), 无归属或取不到名称的条目归到末尾「未关联产品 / 未关联项目」。BUG 行 JSON 只有 product / project 两个数字 id(实测 56 个字段里没有名称), 宿主借
/product-all.json(实测 30 个产品)、/project-all.json(约 311 个项目)的 id→名称表补productTitle/projectName(10 分钟缓存;任务行自带项目名时不发这次请求),筛选/搜索通道同样补,所以筛选后组头不会掉成「未关联」; 补名逻辑在宿主侧(Node),改了要重启宿主才生效;若宿主还是旧版(行里只有 product / project 数字 id), 面板会自动拉一次targets列表(与新建弹窗同一份)把 id 译成名称再分组,不会整页落到「未关联」; 列表头的「按产品分组 / 按项目分组」按钮可切回平铺列表,偏好记在localStorage(dsh-zentao-group)。 组头括号里数是当前页该组的条数——禅道一页 20 条,同一产品跨页时每页各出一组,想一屏看全某个产品就把每页条数调到 50 / 100 或直接用筛选 -
列表行右侧显示处理时长(2026-10-30):每行右上角一个红色「N 天」+ 其下一条细胶囊进度条, 一眼看出这条挂了多久、相对承诺天数消耗到哪了。口径三条: ① 起点取创建时间(
openedDate),终点取解决 / 完成时间(BUG 用resolvedDate、任务用finishedDate), 没走解决就直接关闭的条目才回落到closedDate,都为空表示仍在处理、算到今天——所以「关闭」不会把处理时间虚增成验收时间; ② 只比日期不比时刻(0 点对齐),与禅道网页的「N 天」一致,不会把 7 天 20 小时显示成 8 天; ③ 承诺天数优先取该条目的deadline(创建 → 截止),没人填截止日期时按优先级兜底 P1=3 / P2=7 / P3=15 / P4=30 天 (实测禅道行的deadline大量是0000-00-00,只认它会让进度条永远按 0 算)。 进度条宽度 = 已用 / 承诺,超期时铺满并加深字重;悬停给出「创建 … · 仍在处理/解决 … · 已用 N 天 / 承诺 M 天(来源)」,超期还写明超了几天。 没有创建时间的行不显示这个标识(宁可不显示也不编一个天数)。任务行原本不带创建/完成时间,宿主侧已一并补齐。 布局:左栏(标题 + 元数据)可收缩、右栏固定 78px 靠右;宿主侧栏只给到 ~300px 时按行自身宽度换行到标题下方(不用视口宽度判断,侧栏变窄时视口往往仍然很宽)。 七套皮肤各有一条--dur令牌(深色皮肤把红提亮、波普压深一档),轨道统一用半透明色——固定浅灰在选中行的浅蓝底上会整个隐形 -
筛选/搜索是全量的,不是本页的(2026-10-29):点统计卡筛选、点工具栏状态签、输搜索词(防抖 300ms),当前页签列表走宿主
query通道—— 宿主复用 counts 聚合时的整范围行集(同一份缓存,零额外请求)按状态/确认度/关键词过滤后本地分页, 页脚与分页器切成筛选集自己的口径(如「已解决」= 共 81 条、1 / 5 页),与统计卡子卡数字天然一致,取消筛选即回到服务端总数; 行集被 40 页上限截断时,状态筛选走排序聚类走查兜底(关闭条目的 assignedTo='closed'、未关闭是真账号,按 assignedTo/status 排序目标簇聚在两端, 每方向最多走 40 页、遇簇边界即停)——此法不适用 confirmed 维度与搜索(无对应排序列),截断场景下它们仍按「本页」口径降级 -
切换浏览范围,列表与数字一起刷新(2026-10-29 修复):筛选/搜索激活时,列表走
query通道、统计卡走counts通道, 两条通道各自按「kind:范围」取数。此前query的 effect 依赖里漏了scopes,于是选中卡片后再切范围下拉会出现 「统计卡数字变了、列表还是旧范围的行」。现在依赖补齐;同时主卡数字改为优先读counts.total(与子卡同源), 不再依赖loadLists的state.*Total——筛选态下loadLists会跳过当前页签,那个字段本来就不会更新 -
搜索框可一键清空(2026-10-29):有搜索词时右侧出现
×,点击或按Esc清空并回到第 1 页;清空只清搜索词、不动状态筛选。 -
写操作后的联动刷新(2026-10-30):确认/解决/加备注后,当前页签的全量计数强制重拉(此前统计卡要等切页签/换范围才更新); 翻页、改范围只重发有变化的页签,未变化的两类不再陪跑重拉;点主卡(本来就没有筛选时)是纯 no-op,不再把页码打回第 1 页; 退出登录会清掉统计卡计数与新建权限探测,换账号不残留上一账号的数字。 输入框外层由
label改成div——label会把内部按钮的点击转发成输入框聚焦,清空按钮会被吞掉 -
列表行显示真名(2026-10-29):禅道列表行 JSON 只有裸账号(实测 56 个字段无真名),宿主借 view 详情 JSON 内嵌的全量 users 表 (实测约 747 项,变化慢,缓存 10 分钟;详情接口顺手收割刷新)给行内账号附加
*Name字段,列表指派列与详情相关人字段均显示真名; 关闭态占位账号closed按禅道网页写法显示「Closed」 -
HTML 实体统一还原:禅道按
htmlspecialchars下发(&→&、'→'),标题/名称/产品名/模块路径/相关人真名/备注都解码, 且不限于&——命名实体(< > " — … × © …,共 80 余个)、十进制'、十六进制😀都认, 只解一层(&amp;仍是&)。富文本字段(重现步骤/描述/备注 HTML)保持原样,解码交给渲染层 -
新建:工具栏「+ 新建BUG / 新建任务 / 新建需求」——弹出禅道自己的创建表单(字段、选项、默认值、联动条件都来自创建页), 先选创建目标(BUG/需求 → 产品;任务 → 项目,下拉可搜索),提交后回读新建对象的详情页确认真的建成,并直接跳到它的详情
-
没权限就不显示「新建」:切页签时探一次该类型有没有创建权限(禅道没权限也返回 200,只是创建页里没有表单),没有就把按钮换成一行说明(含原因与探测地址),不再点进去撞红条
-
新建表单按禅道复刻:控件类型(下拉/多选/复选/单选组/日期/文件)、必填标记、帮助说明、隐藏域默认值都照创建页渲染; 同名单选项合并成一组(禅道「添加之后」是 3 个同名 radio —— 旧实现渲染成 3 个文本框,提交值还会后写覆盖前写); 下拉与正文里的 HTML 实体(
<p>等)还原成原文;整行带class='hide'/'hidden'的按禅道显隐(有联动条件的交给条件,其余整行隐藏); 核心内容栏是可粘图编辑器——在里面按 Ctrl+V 粘贴截图会先上传到禅道(/file-ajaxPasteImage-<uid>.html,带本次表单令牌 kuid), 再把返回的<img src="/file-read-N.png">插到光标处就地预览(经本机代理,不裸取外域); 「附件」字段支持多选上传(单个 ≤ 8MB,base64 交给宿主后按multipart/form-data提交),超过 8MB 会在本地直接拦下; 选择器(下拉)展开是浮层:坐标按锚点实测、下方放不下就向上翻,不占行内位置,所以同一行的其它控件不会被挤走(点外部或 ESC 关闭); 同一行的控件保持一行(与创建页一致):日期范围(日程规划 预计开始 ~ 截止日期)并排等宽、不拆成两行, 第 2..N 个控件(操作系统 / 浏览器 / 严重程度 / 优先级 / 预计工时)跟在主控件后面用行内小标签补名,不另起一行被缩进一个标签列; 标题/名称独占一行(BUG标题、任务名称、需求名称铺满控件列,挤在同一行会把标题压窄、长标题看不全), 它的附加控件(严重程度 / 优先级 / 预计工时)另起一行、与控件列左对齐; 单选组与左侧字段名在同一行、垂直居中 -
统计卡点击筛选、标题/编号搜索、列表与详情双栏、详情全屏(面板内铺满)(隐藏顶栏/页签/统计卡/搜索工具栏,详情卡贴边铺满面板,右上角刷新 + 退出;ESC 或再点退出)
-
工具栏右侧「新建 / 角色 / 状态筛选」是一个操作组:同 32px 基线、组内 8px 间距(原来 35/30/35px 高、9-13px 间距,三个控件看着互不相干)
-
详情里:富文本重现步骤/描述(图片走本机代理并可点击放大、左右切换)、基本信息、处理信息、关联对象、操作历史
-
BUG 可直接在面板里走禅道原生表单:确认 / 解决 / 关闭 / 激活 / 指派(提交前拉取真实表单字段,提交后回读证实)
-
添加备注(三段式模板:问题原因/解决方案/解决时间),发错了可以直接改:
zentao_bug_comment_edit按 actionId / 内容片段 / 最近一条定位后重写(实测禅道只给条目页最新一条备注渲染编辑表单,改旧备注会报错并告知最新那条的编号) -
「解决」模型也能直接做:
zentao_bug_resolve走禅道自己的解决表单(解决方案 / 解决版本 / 解决日期 / 三段式备注),默认解决方案=已解决(solve)、解决版本=主干(trunk),提交后回读status=resolved才算成功;只发备注的zentao_bug_comment不会改状态 -
「在禅道中打开」链接附带会话参数,免登录直达
-
拖拽 / 复制为 Markdown 引用:把条目拖到聊天输入框,或点「复制」后粘贴——引用只有三行:标题行、读全文行(该调哪个工具、截图怎么拿)、免登录原地址
-
按角色处理:选好职位(开发/测试/产品/管理)→ 点「按【开发】处理」→ 在当前项目新建对话并自动发送「身份开场白 + 条目引用 + 角色任务书」;任务书排在最后(模型读到最后的才是要它做的事),且是纯文本聊天口吻——不用 Markdown 标题/加粗,只有条目引用那两行带「- 」引导符。开发那套是四步处理流程:查沉淀(只说「用这条记录的标题自己提炼业务词」,不写死任何示例)→ 给分析 → 我确认后再改码 → 回写;末步文案按条目类型替换(BUG 先给
zentao_bug_resolve:三段式写进 comment、默认 solution=solve(已解决)/ build=trunk(主干),提交后回读确认已解决;只补备注才用zentao_bug_comment,并提醒「发错了不用补发更正,用zentao_bug_comment_edit改那条」;任务/需求没有回写通道,直接说明「文案交我,我在禅道里填」) -
提示词不回抄详情:禅道详情页里能看到的东西(状态、优先级、正文、步骤、截图清单、信息缺口)一概不复制进对话——写进上下文只会又碎又容易失真;提示词只给
【禅道BUG #201030】标题、- 读全文:zentao_bug_view({ id: '201030' });截图按详情链接自行取回(带 zentaosid),取不到就明说,不要脑补;不要凭标题猜内容。、- 禅道原地址:https://…/bug-view-201030.html?zentaosid=…这几行 -
截图靠模型自己取,取不到就明说:条目里的图地址都带会话票据(
?zentaosid=…,实测不带 cookie 也能取),「读全文」那行已写明截图要自行取回、取不到就明说别脑补;工具回包里的<img src>同样改写成绝对地址,模型直接复制就能取回来看 -
七套皮肤随时切换:顶栏右侧的下拉选 原生(跟随宿主明暗)/ 极光 / 波普 / 棱彩 / 青海波 / 记分牌 / 碳纤红。 切换即时生效并记在
localStorage的dsh-zentao-theme,刷新后保持;七套皮肤共用同一套 DOM,只有配色与少量外观修饰不同, 所以分页唯一、页脚末位、浮层 portal 等结构行为在所有皮肤下完全一致。 各皮肤的浮层(选择器菜单、图片画廊)也跟随皮肤,不会掉回原生配色。皮肤 明暗 主色 记忆点 原生 跟随宿主 禅道蓝 与宿主浑然一体 极光 暗 蓝紫渐变 流体光斑 + 玻璃卡 波普 浅 红黄蓝三原色 波点底 + 粗描边 + 硬阴影 棱彩 暗 紫/天蓝/青柠 马赛克彩窗虚化 + 磨砂卡 青海波 浅 藍染靛 + 朱印红 青海波纹样 + 明朝体标题 记分牌 暗 荧光绿 + 琥珀 数码管数字 + 等宽字 碳纤红 暗 碳灰 + 赛车红 碳纤编织纹 + 切角按钮 实现方式是「根节点挂
zts-theme-<id>,只换 CSS 令牌 + 少量外观修饰」,新增一套皮肤只需加一条SKINS项和一段令牌定义。 注意两条硬约束:同一个颜色变量不能同时当「前景文字色」和「按钮底色」(例:碳纤红的--blue是暗底上的红字、--btn-primary是托白字的深红); 浮层挂在 body 上,皮肤 class 必须一起带过去,否则下拉菜单会掉回原生配色。 -
面板动效可关(2026-11-02):顶栏的动效开关默认开,关掉只是根节点摘掉
.zts-motion,DOM 结构与布局完全不变; 开着时换皮肤走 260ms 颜色交叉渐变,极光 / 棱彩的氛围光跟同一个开关,偏好记在localStorage的dsh-zentao-motion。 系统的「减少动态效果」不再单独压掉面板动画——默认开是选定的默认,想静止就关顶栏这个开关
模型工具
| 工具 | 用途 |
|---|---|
zentao_ping | 连通性与凭据自检 |
zentao_my_bugs / zentao_my_tasks / zentao_my_stories | 三类条目列表,type 指定浏览范围 |
zentao_bug_view / zentao_story_view / zentao_task_view | 单条完整详情(正文、截图地址、相关人、操作历史) |
zentao_bug_confirm | 确认 BUG(只置「已确认」,状态仍是激活) |
zentao_bug_resolve | 解决 BUG:提交禅道解决表单(解决方案 / 解决版本 / 解决日期 / 三段式备注),默认 solve(已解决)/ trunk(主干),提交后回读确认 status=resolved(写操作) |
zentao_bug_comment | 追加备注(只加备注,不改状态) |
zentao_bug_comment_edit | 修改已发出的备注(写操作;只能改最新一条,见「已知限制」) |
zentao_plugin_status | 注册诊断(取数失败时排障用) |
插件还会注册一段系统提示,告诉模型这些工具何时用、未登录该怎么办。
⚠️ 「解决」和「备注」是两条不同的写入路径:禅道里只发备注不会把 BUG 变成「已解决」。要「回复三段式并把 BUG 解决」,必须用
zentao_bug_resolve(comment放三段式文案,resolution默认solve、resolvedBuild默认trunk),它会回读status证实;zentao_bug_comment只用于补备注。
安装
前置:DeepSeek Harness 0.1.0-rc.2 ~ 0.2.x(已在 0.2.0-rc.2、0.2.1-rc.1、0.2.1-rc.2 上实机验证;0.2.1-rc.3 上已验证工具调用与槽位注册;0.2.1-rc.5 上已验证 12 个工具注册、系统提示/HTTP 路由/凭据三个槽位、面板取数与禅道真实连通,并逐项比对过 @deepseek-ai/dsh-tools 的导出面(0.2.0-rc.2 → 0.2.1-rc.5 无增删、defineTool 行为未变))、Node ^22.19 || >=24。
ℹ️ 版本声明:
package.json的engines.dsh写的是>=0.1.0-rc.2 <0.3.0。DSH0.2.1起,第三方插件的兼容性优先按engines.dsh判断(未声明时才回落到旧的 peer 规则),声明不覆盖当前宿主就会被跳过并给出告警。宿主升到0.3.x时记得同步放宽这个区间。
方式一:DSH 桌面端插件管理器(推荐)
设置 → 插件 → 「添加插件」,输入三者之一:
- 包名:
@cnbmtech/dsh-zentao-session(npm 或公司私服) - Git 仓库地址:内网 Git / GitHub 地址
- 本地目录路径:例如
D:\dsh-plugins\dsh-zentao-session
⚠️ 选「本地目录」时务必先在该目录里执行过一次
npm install。包管理器只做目录链接,不会替你安装被链接包自己的依赖;目录里没有node_modules时插件会因为找不到@deepseek-ai/dsh-tools而起不来。宿主自带的
@deepseek-ai/*按生态惯例只声明在peerDependencies(本地开发用devDependencies装进插件自己的目录)——不写成dependencies:那样会把钉死的版本塞进 DSH 的共享依赖树、与宿主自己的版本互相干扰(插件清单会告警)。从包名安装时这些包由 DSH 提供,无需额外处理。
方式二:CLI
# 包名
dsh plugin --profile web add @cnbmtech/dsh-zentao-session
# 本地目录(同样记得先 npm install)
dsh plugin --profile web add D:\dsh-plugins\dsh-zentao-session
安装后完全重启 DSH(客户端 bundle 只在启动时加载,关开插件不会刷新)。
ℹ️ 装到旧版本了?(pnpm 11.7 实测)
pnpm 默认带
minimumReleaseAge(24 小时供应链策略),但显式指定版本安装时它会自动把该版本写进pnpm-workspace.yaml的minimumReleaseAgeExclude,无需手动放行。刚发布几分钟内,不带版本号(或
@latest)可能因 pnpm 的 registry 元数据缓存而拿到上一个版本。想要立刻拿到新版就把版本号写全:dsh plugin --profile web add '@cnbmtech/[email protected]'插件管理器里同理,填
@cnbmtech/[email protected];或者等几分钟缓存过期后重装。只有 profile 设了
minimumReleaseAgeStrict: true(策略变成"必须人工确认")时,才需要手动加minimumReleaseAgeExclude条目。
登录与配置
打开侧边栏「禅道」面板,填禅道地址 / 账号 / 密码,点「登录并保存」——凭据写入 DSH 凭据库 ~/.dsh/.credentials.yaml(refs:ZENTAO_BASE_URL / ZENTAO_ACCOUNT / ZENTAO_PASSWORD),之后免登录,且可随时「退出登录」清除密码。
也可以在 profile 的 cordis.patch.yml 里配置 id: zentao-session 的 config(优先级:config > 凭证库 > 环境变量):
| 字段 | 默认 | 说明 |
|---|---|---|
baseUrl | 空 | 禅道地址(不含末尾 /);为空时读凭据 ZENTAO_BASE_URL |
account / password | 空 | 同上,建议放凭据库,不要写进配置文件 |
timeoutMs | 30000 | 单次请求超时 |
defaultLimit | 20 | 列表工具默认返回条数 |
未配置地址时插件不休眠:照常注册工具与路由,只在你真正取数时提示"请先在面板登录"。
侧栏入口:栏上图标 or「更多」
图标默认显示在左侧栏(低版本 DSH 没有「更多」按钮,菜单默认会让面板无门——默认上栏是向下兼容的一部分);高版本 DSH 里点「更多」→ 点那一行的 「禅道」 也能开面板。
「更多」里禅道只占一行:左边「禅道」(点开面板),右边同一行是「侧边栏」三个字 + 一颗眼睛,控制这个入口要不要常驻左侧栏—— 睁眼=图标在左侧栏上,划掉=收在「更多」里(悬停有提示;写「侧边栏」是为了说清眼睛动的是哪儿)。
- 点这个开关当刻生效(不用重启,也不用重载插件):放出 = 立刻补注册侧栏条目,收起 = 注销那条注册(同时把宿主的入口 pin 一并置为未固定,双保险)
- 那一行是插件自绘的,不 require 宿主的 client 包——宿主文档明确不要加载
@deepseek-ai/dsh-client-ui-primitives一类的内部包,组件抛错会让整条槽位条目白屏 - 那一行全部用内联样式(颜色只取宿主
--dsw-alias-*令牌并带 fallback):菜单挂在宿主浮层里,插件样式表在这个位置实测不生效,用类名会退化成浏览器默认按钮 - 选择记在浏览器
localStorage的dsh-zentao-sidebar-entry(rail= 栏上常驻,more= 收进「更多」,默认即rail,2026-11-05 起),换浏览器 / 清缓存后回到默认;低版本 DSH 没有「更多」按钮,图标强制显示在栏上(此时开关不存在) - 收起后**「更多」里那行「禅道」一定还在**——宿主的「更多」本身不列面板条目(官方入口定制只把面板条目渲染给会话视图与右栏),这一行是收进去之后唯一的入口
- 客户端插件拿不到宿主 YAML 里的
config(客户端apply的第二个参数在运行时是undefined),所以这项偏好不走cordis.patch.yml
图标用的是禅道官方 logo(官网上那颗蓝色漩涡标,60×60 透明 PNG,从 zentao.net 页头的 logo 图里裁出来;官方没提供矢量版),以 data URI 内联进 client.js,所以插件不额外带资源文件。换浏览器主题时它跟官方一致、不跟着文字变色。禅道与 ZENTAO 是禅道软件的商标,这里仅用于标识本插件连接的是禅道。
安全边界
- 面板数据接口
/api/dsh-zentao-session/*:所有 action(含读)都要求自定义请求头x-dsh-zentao-session: 1,且 Host 必须是回环字面量(防 DNS rebinding) - 截图代理
/api/dsh-zentao-session-file?path=…:只放行禅道/file-(read|download)-数字路径,只回位图/PDF(排除 SVG,避免同源脚本执行面),单文件 8 MB 上限;请求带Sec-Fetch-Site且不是 same-origin/none 的一律 403(跨站<img>借宿主会话探测附件的路子封掉,老内核不发该头则保持放行) - 表单写入:令牌
kuid取不到就硬失败,绝不带空令牌出网;非幂等 POST 从不自动重试(避免重复备注——该版本禅道没有删除备注的入口,只能再编辑一次) - 贴图与附件写入同样受上一条约束:粘贴图上传(
/file-ajaxPasteImage-<uid>.html)与带附件的创建提交都要求令牌,请求体上限 32MB,非幂等且不重试 posted: true只代表"禅道没报错";确认/追加备注/改备注都会回读证实后才报成功- 仓库内不含任何禅道地址、账号或密码
排障
| 现象 | 处理 |
|---|---|
| 面板空白 / 页签缺失 | 客户端 bundle 没重新加载 → 完全重启 DSH(不是关开插件),再刷新页面 |
| 左侧栏找不到禅道图标 | 默认就在左侧栏;若之前用「更多」里的开关收起过:点左侧栏的「更多」→ 点同一行的眼睛放出。低版本 DSH(没有「更多」按钮)图标强制在栏上 |
| 工具报「请在面板登录」 | 打开侧边栏「禅道」面板登录一次 |
| 取数失败 | 让模型调用 zentao_plugin_status,它会打出路由/RPC 注册结果与真实错误 |
| 列表比预期少 | 禅道「我的地盘」一页只回 20 条;面板会标注"服务端共 N 条",用范围/筛选收窄,或让模型用工具的 limit |
启动日志出现 skipping profile bundle "@cnbmtech/dsh-zentao-session"(面板/工具全都不在) | 宿主判定版本不兼容:engines.dsh 没覆盖当前 DSH 版本。升级插件到覆盖该版本的发行;确知无碍时可用 dsh plugin allow-version 或插件管理器加"精确版本豁免",再重启 |
已知限制
-
创建权限按目标探测:探前 3 个产品/项目(第一个有创建页表单即视为可创建),不逐个探完;权限都在别的目标上时会误显示成"没有创建权限"
-
新建写的是真实禅道:提交即创建(不可撤销,请在禅道里核对或删除);附件走禅道自己的
files[]字段,扩展名/大小最终仍由禅道侧规则决定(被拒时弹窗里会显示禅道原话) -
创建表单的联动是服务端初始态:切换产品/项目会重新拉取该目标的表单;页面内 JS 联动(如「新建版本」勾选后展开的子字段)以禅道渲染结果为准
-
目录/链接安装时依赖需自备(见上)
-
列表按禅道分页(服务端一页 20 条);面板列表页脚可翻页、可改每页条数(20 / 50 / 100,页码与总页数取自服务端 pager),模型工具默认取一页再按
limit截断 -
分组是「当前页内」的(同一条限制的延伸):组头括号里是本页该组的条数,不是该产品/项目的全量条数;同一产品跨页时会在每页各出一个组头。要按产品整体看,用筛选/搜索,或把每页条数调到 50 / 100
-
需求的详情接口不返回产品名(只有产品 id),面板会回落到列表行;列表能拿到就没问题
-
表单操作只覆盖 BUG(确认/解决/关闭/激活/指派);任务与需求为只读 + 复制/拖拽/送对话
-
需要禅道账号本身有对应权限;插件不做越权尝试
更新日志
从 0.6.6 起,每个发布版本都在这里写清「这个版本改了什么」(发版前先写,再 npm publish)。更早的版本当时没留说明,只回填了能核实的里程碑。
0.6.8 — 2026-11-02
新功能:列表按「所属产品 / 所属项目」分组、行内显示处理时长,另加面板动效开关(0.6.7 未单独发布,分组一并合入本版)。
- 列表分组:组头吸顶一行「所属产品:<名称> (N)」(任务页签为「所属项目:<名称> (N)」),置灰不可点、一个前导不换行空格让它不贴边;BUG 与需求按所属产品、任务按所属项目,无归属的归到末尾「未关联产品 / 未关联项目」
- 列表头「按产品分组 / 按项目分组」开关可切回平铺列表,偏好记在
localStorage(dsh-zentao-group);分组作用在当前页的行上,组头括号里是本页该组的条数 - BUG 行补产品名:BUG 列表 JSON 只有 product / project 数字 id(实测 56 个字段没有名称),宿主借
/product-all.json、/project-all.json的 id→名称表补productTitle/projectName(10 分钟缓存;任务行自带名称时不发这次请求),筛选/搜索通道同样补;旧版宿主下由面板自己拉targets译名兜底 - 行内处理时长:右上红色「N 天」+ 其下细进度条,天数 = 创建 → 解决/完成(没走解决直接关闭的回落到关闭时间,未结束的算到今天,只比日期);承诺天数优先取
deadline,没填按 P1=3 / P2=7 / P3=15 / P4=30 兜底;超期铺满并加深字重,悬停写明创建/结束时间、承诺天数来源与超期天数;没有创建时间的行不显示这个标识 - 宿主侧补齐行字段:BUG 行补
assignedDate / resolvedDate / closedDate / deadline,任务行补openedDate / assignedDate / realStarted / finishedDate / closedDate(此前任务行连创建时间都没有,无从算时长) - 面板动效开关(顶栏,默认开,记在
dsh-zentao-motion):关掉只是根节点摘掉.zts-motion,DOM 结构与布局不变;开着时换皮肤走 260ms 颜色交叉渐变,极光 / 棱彩的氛围光跟同一个开关 - 样式热更新:面板是在同一个页面里反复开关的,旧实现只在
apply()里注入一次<style>,插件更新后样式会冻在旧版本;现在挂载时比对内容并原地替换,关掉再打开面板即可吃到新样式 - 行为变更:详情全屏改为面板内铺满,不再调用浏览器 Fullscreen API(ESC 仍可退出);顺手修正碳纤红分组开关按下态对比度(4.35 → 5.1)
- 测试:新增
node test-grouping.mjs(宿主补名缓存与零额外请求、分组开关、样式热更新、旧宿主兜底),node test-client.mjs增加处理时长用例
0.6.6 — 2026-10-30
**兼容性发布:适配 DeepSeek Harness 0.2.1-rc.5,插件代码零改动。**同时把此前一直没发到 npm 的 0.6.5 内容一并带上(0.6.4 之后安装的用户会一次拿到)。
兼容性复核(全部实测通过):
engines.dsh声明>=0.1.0-rc.2 <0.3.0本身就覆盖新宿主,不会被启动时跳过- 12 个工具注册、系统提示、HTTP 前缀路由(面板取数)、凭据库三个槽位、禅道真实连通全部正常;唯一
[FAIL]的rpc.register-failed :: cannot get property "webServer" without inject是长期已知项,面板走 HTTP 路由不受影响 - 逐项比对
@deepseek-ai/dsh-tools导出面:0.2.0-rc.2→0.2.1-rc.5无增删(23 个),defineTool行为未变;宿主本版唯一的改动只影响 PTC 嵌套调用的presentationMeta,本插件不使用
随包内容(原 0.6.5,此前未发布):
- 七套面板皮肤:原生(跟随宿主明暗)/ 极光 / 波普 / 棱彩 / 青海波 / 记分牌 / 碳纤红,切换即时生效并记忆在
localStorage - 「按角色处理」:开发 / 测试 / 产品 / 管理四套任务书,一键在项目里新建对话并发送「身份开场白 + 条目引用 + 任务书」(开发那套是四步流程,含
zentao_bug_resolve三段式回写) - 详情全屏:贴边铺满,退出后列表/筛选/滚动位置复原
- 工具栏操作组:新建 / 角色 / 状态筛选同 32px 基线、组内 8px 间距
- 搜索与筛选口径统一:筛选态走 query 通道,页脚分页、页签计数、统计卡与主卡口径一致
- 面板不再定时自动刷新(0.6.4 的「自动刷新」下拉已移除),改为操作后与手动刷新
本地开发:
devDependencies对齐宿主:@deepseek-ai/dsh-tools0.2.1-rc.5、@deepseek-ai/schemastery3.18.5(只影响目录 /link:安装的本地开发,npm 使用者用宿主自带那份)
历史里程碑(回填,日期为 npm 发布时间)
| 版本 | 日期 | 内容 |
|---|---|---|
| 0.2.0 | 2026-10-15 | 首发:9 个工具(我的 BUG / 任务 / 需求、BUG 与需求详情、BUG 确认 / 备注、注册诊断)+ 侧栏面板(页签切换、拖拽与复制、送对话、详情全屏、图片画廊、搜索) |
| 0.3.0 | 2026-10-15 | 面板加「新建」表单与列表分页(页码/每页条数取自服务端 pager) |
| 0.4.1 | 2026-10-17 | 新增 zentao_task_view、zentao_bug_comment_edit(工具 9 → 11);新建表单支持富文本贴图与附件 |
| 0.5.1 | 2026-10-19 | 新增 zentao_bug_resolve(工具 11 → 12):三段式备注 + 解决表单一次提交并回读状态 |
| 0.6.4 | 2026-10-26 | 侧栏入口收进左侧栏「更多」菜单(同行开关可切回栏上) |
| 0.6.6 | 2026-10-30 | 适配 DSH 0.2.1-rc.5,并补发 0.6.5 的面板内容(见上) |
| 0.6.8 | 2026-11-02 | 列表按所属产品 / 所属项目分组、行内处理时长、面板动效开关(0.6.7 未单独发布,已合入本版) |
同一阶段内的补丁版本(0.2.1–0.2.3、0.3.1–0.3.5、0.4.2、0.5.3–0.5.6)当时没留说明,只保留了包本身,不再逐条回填。
开发与自测
npm install
node test-client.mjs # 面板全链路(最小 React hooks 模拟宿主)
node test-tools.mjs # 11 个工具的渲染 + lossless JSON
node test-form-encoding.mjs # 写路径铁律(多选重复键 / 302 不重发 / 缺 kuid 不出网)
node test-real-render.mjs # 真实 React SSR 首跳
node test-real-browser.mjs # jsdom + 真实 React 全交互链
node test-sidebar-entry.mjs # 侧栏入口:默认上栏(低版本兼容)、开关收放当刻生效 + 低版本回退
node test-skins-and-fixes.mjs # 六套换色皮肤(+ 原生 = 七项)+ 切范围同步刷新 + 搜索清空
node test-grouping.mjs # 列表分组:宿主补产品名/项目名(缓存/零多余请求)+ 面板按产品/项目分组与开关
node test-client.mjs # 同一份里含「列表行处理时长」用例:8 天/15 天=53%、超期铺满、无日期不渲染
面板皮肤(全部七套)另有一套像素级验收脚本,放在仓库工作区的 ui-mocks/ 下
(SKINS=popart,ukiyo node panel-shot.mjs 可只跑指定皮肤,不传则全跑):
panel-harness.html(浏览器内加载真实 client.js + 真实 React 18 + 真实禅道数据)、
panel-shot.mjs(无头 Chrome 出图 + 真实像素对比度 + 布局体检)、
panel-clip-probe.mjs(窄栏裁剪/滚动可达性定点探针)、
panel-verify-3fix.mjs(顶栏/工具栏/页签/统计卡口径的行为断言)、
verify-interactive.mjs(真浏览器:CDP 真实鼠标点搜索清空 ×、Esc 清空、切范围后 query/counts 都带新范围且主卡/子卡/页脚口径一致、皮肤切换即时生效与记忆、× 在 7 套皮肤下常规态与悬停态的对比度)、
verify-fullscreen.mjs(真浏览器 × 7 套皮肤:全屏后顶栏/页签/统计卡/工具栏必须全部消失、详情卡贴边铺满 1440×950、有退出入口、退出后四层复原;以及工具栏四控件 32px 同基线/圆角/组内 8px 间距)。
目录结构:index.js(宿主:工具 + HTTP/RPC 路由 + 系统提示)、src/client.js(宿主侧禅道客户端:登录/列表/详情/表单)、client.js(浏览器面板 bundle)、cordis.patch.yml(bundle 安装层)。
发布与迭代(维护者)
# 0. 先在 README「更新日志」最上面写这次改了什么(下面的模板),再发版
npm login # 首次:需要 npm 账号,且对 @cnbmtech 组织有发布权
npm version patch # 0.2.0 → 0.2.1(或 minor/major)
npm publish --registry=https://registry.npmjs.org # 本机默认 registry 是 npmmirror 镜像,发不上去
npm view @cnbmtech/dsh-zentao-session version --registry=https://registry.npmjs.org # 确认 latest 已更新(大约 1 分钟)
更新日志模板(README.md 的「更新日志」节,新版本写在最上面):
### <版本> — <YYYY-MM-DD>
**<一句话:这个版本为什么发(兼容性 / 新功能 / 修复)>**
- <用户能感知的变化,一条一句;兼容性发布要写清核对过什么、有没有改代码>
- <已知问题 / 行为变更(比如移除了哪个开关)也要写,别只说新增>
- 首次发布前需要在 npm 上创建组织
cnbmtech(免费组织只能发公开包),或用公司私有源:npm publish --registry https://私服地址(并让同事的插件管理器指向该源)。 - 本机开发不必发布:profile 里以
link:指向源码目录,改完代码重启 DSH 即生效;只有同事需要走 npm。 - 同事升级:插件管理器里重新添加同名包(或
dsh plugin --profile web update @cnbmtech/dsh-zentao-session),再完全重启 DSH。 - 发布物只含 10 个文件(
package.json的files白名单),不含node_modules、测试脚本与任何凭据——发布前可用npm pack --dry-run复核。
许可
MIT