dsh-ohna
Verifieddsh-ohna · v0.1.4 · MIT · Web UI
Multi-tool development toolkit for the agent runtime: ohna_devline_run (parallel, context-isolated dev pipeline) + ohna_bug_record / ohna_bug_fixed (workspace bug log) + a Web GUI bug table. The orchestrating tool named by the one-click fix prompt is conf
Install
dsh plugin add dsh-ohna 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
Creators
Readme
dsh-ohna
开发闭环工具包:并行隔离开发流水线 + 工作区 bug 记录 + Web GUI 表格,一个插件跑通 「用户报 bug → 一键修复 → 编排修复流程 → 标记完成」。
- 包名:
dsh-ohna· 版本:0.1.4·private: false(可发布) - 对外暴露 3 个模型可调用工具,共用一份 host 依赖、一个前端入口、一份
cordis.patch.yml
用户报 bug ┌────────────────── 本插件 ─────────────────┐
│ │ │
▼ ▼ │
ohna_bug_record ──► <workspace>/tmp/dsh-repo-bug.json │
│ │ │
│ GUI「一键修复」 ▼ │
└────────────────► ohna_devline_run ──► 并行 coder → reviewer → 原 coder 修复
│
ohna_bug_fixed ◄── 每修完一条回写 fixed ───┘
1. 三个工具(名称固定,不可配置)
| 工具 | 作用 | 原归属 |
|---|---|---|
ohna_devline_run |
并行、上下文隔离的开发流水线:coders → reviewer → 原 coder 修复,直到 pass 或 maxFixRounds |
原 dsh-dev-line |
ohna_bug_record |
把用户在提示词里明确表述的 bug / 问题追加写入工作区 bug JSON | 原 dsh-repo-dashboard |
ohna_bug_fixed |
翻转记录上的 fixed 标志(GUI 据此渲染) |
原 dsh-repo-dashboard |
为什么这三个名字固定且带
ohna_前缀: 它们是本插件对外暴露的接口,应当稳定;而devline_run/repo_bug_record/mark_bug_fixed都是通用词,与其他市场插件重名概率不低 —— DSH 的tools.register对同一层内重名直接抛错 (tool "X" is already registered,不是覆盖、也不是后者赢),会让后加载的插件整个启动失败。 因此统一加ohna_前缀主动避让;注册时若仍冲突,本插件选择 fail-loud 清晰报错,不静默吞掉。唯一可配置的是
fixTool(见 §2),它只决定「一键修复」提示词第 3 步引用哪个编排工具, 不影响本插件自己注册的工具名。
2. 一键修复 与 fixTool
GUI 的「一键修复」会把修复指令填入输入框(不自动发送,用户确认后手动发送)。
提示词中只带日志文件路径,不含具体条目 —— 模型自行读文件筛选 fixed !== true,
因此提示词长度与 bug 条数无关。
请修复 <workspace>/tmp/dsh-repo-bug.json 中所有 fixed 不为 true 的 bug。
步骤:
1. 读取 <workspace>/tmp/dsh-repo-bug.json
2. 筛出所有 fixed !== true 的记录
3. 使用 {fixTool} 工具的开发流程逐条修复(该插件负责流程编排与冲突分析)
4. 每修复完一条,调用 ohna_bug_fixed 工具把该条标记为已修复
全部修完后,汇总说明每条 bug 的修复方式。
| 步骤 | 工具名 | 是否可配置 |
|---|---|---|
| 第 3 步(编排修复) | 由 fixTool 决定,默认 ohna_devline_run |
✅ 可改成任意第三方工具名 |
| 第 4 步(标记已修复) | 恒为 ohna_bug_fixed(常量 MARK_TOOL) |
❌ 固定,不可配置 |
为什么第 4 步不可配置
ohna_bug_fixed 写的是本插件自己的 bug JSON。第三方编排工具做不到这个写入动作,
所以无论 fixTool 配成什么,第 4 步都必须指向本插件的标记工具。
幽灵工具防线
用户配了第三方工具名但该工具实际未安装/未注册时,提示词会引用一个不存在的工具,主 agent 调用会得到
UNKNOWN_TOOL。因此 host 侧在只读路由返回 fixTool 前,会用 ctx.tools.get(name) 校验它确实已注册:
| 场景 | 行为 |
|---|---|
fixTool 未配置 / 为空 |
回退到默认 ohna_devline_run,仍然走注册校验 |
| 校验通过(工具已注册) | 第 3 步正常引用该工具名 |
| 校验失败(未注册) | 返回 null,GUI 把第 3 步降级为工具无关的通用指令:3. 逐条修复(按当前会话可用的工具自行组织开发流程) |
提示词组装逻辑是无副作用的纯函数
buildFixPrompt(logPath, fixTool),位于 fixprompt.js(gui.js是浏览器 bundle,无法被node --test导入, 因此与测试共用这一个数据源)。
3. ohna_devline_run —— 并行隔离开发流水线
由**主 agent(编排者)**调用,把任务拆解后一次性执行:
主 agent(编排者) 子 agent(上下文互相隔离)
───────────────────── ─────────────────────────────
分析任务 → 拆解 work items
(数量 = 可并行开发的数量)
│ 调用 ohna_devline_run
▼
并行 spawn N 个 coder/architect ──► 每个在全新隔离上下文中开发
│
spawn 1 个 reviewer ──► 审核全部 coder 输出(结构化结论)
│
┌─ 发现问题 → 续跑原 coder 会话(sendMessage 投递反馈)修复 ──► 重新审核
└─ 直到 pass 或 maxFixRounds
│
▼ 返回汇总报告
主 agent 独立完成完整测试 + 文档同步(在工具之外)
关键设计
- 上下文隔离:子 agent 统一由
spawn后端启动(inheritsParentContext: false), 每个 coder / reviewer 都是全新会话,只拿到自己的任务描述与共享文档,互不相通。 - 原 coder 修复:审核发现问题时,用
ctx.subagents.sendMessage把反馈直接投递给 原 coder 的同一个会话(continuable child:启动时预留childId)。修复消息只携带 审核反馈 + 语言提醒,不再重传 task / 共享上下文 / 上一轮报告 —— 这些本就在原 coder 的会话里, 因此每轮修复都不必重建上下文,省掉大量 token。 - 语言跟随:
language参数(zh/en/auto)决定子 agent 的思考与输出语言。 DSH 的界面语言是 client 端服务(ctx.locale),宿主插件所在的 host 端读不到, 因此由主 agent 通过参数把用户界面语言传下来;auto或缺省时按task+shared_context是否含汉字推断。语言约束同时锁住「思考」与「正文输出」,并显式要求代码、标识符、文件路径、 命令输出保持原样(永不翻译)。 - 主 agent 的职责:文档同步 + 最终完整测试由主 agent 自己在工具返回之后完成,工具只负责开发与审核。
工具参数
| 参数 | 必填 | 说明 |
|---|---|---|
task |
是 | 整体开发任务与验收标准,注入每个子 agent |
work_items |
是 | 并行工作项数组;数量即并行度。每项 { id, title, role, description },role 取 architect / senior_developer / developer(缺省 developer) |
parallelism |
否 | 最大并发 coder 数;缺省全部并行(上限 maxParallel) |
cwd |
否 | 子 agent 工作目录;缺省继承调用方目录 |
shared_context |
否 | 共享项目上下文(规格 / 架构 / 规范)注入每个子 agent |
max_fix_rounds |
否 | 审核→修复最大迭代次数;缺省取配置 maxFixRounds |
language |
否 | zh / en / auto(默认 auto)。请按用户界面语言传 zh 或 en |
返回值是一份 Markdown 汇总报告:状态 / 轮次、每个 work item 的摘要与修复次数、 reviewer 结论与遗留问题、交接给主 agent 的测试与文档待办。
4. ohna_bug_record / ohna_bug_fixed
记录原则
- 只记录用户在提示词里明确表述的 bug / 问题;
- agent 在 coding 过程中自己发现的编码问题不记录;
- 用户说「这个有点难用」这类没说 bug 的体验抱怨 → 记为
体验优化。
工具参数(ohna_bug_record)
| 参数 | 必填 | 说明 |
|---|---|---|
title |
是 | 简短摘要(≤ 80 字为宜) |
type |
是 | 类型,见下表;建议值不强制,可自由扩展 |
detail |
否 | 详细描述(用户的原话 + 上下文),软上限 detailMaxChars(默认 2000,超长截断并提示) |
note |
否 | 备注 |
fixed |
否 | 是否已修复,默认 false |
location |
否 | { file, symbol, line, snippet },初步(不可信)定位 |
locate |
否 | 为 true 时由插件 spawn 一个 subagent 帮忙定位代码;默认不 spawn |
工具参数(ohna_bug_fixed)
| 参数 | 必填 | 说明 |
|---|---|---|
ids |
是 | 要更新的编号数组,如 ["BUG-001","BUG-002"];["*"] 表示全部 |
fixed |
否 | 新状态,默认 true;传 false 表示重新打开(用户反馈仍存在) |
note |
否 | 可选备注,写入 fixed_note |
已是目标状态的记录不会被重复改写;修复完成后由主 agent 调用,回写 fixed / fixed_at。
建议类型(不强制)
| 类型 | 说明 |
|---|---|
阻断 |
阻塞主流程,无法继续 |
功能缺陷 |
功能不符合预期 / 结果错误 |
体验优化 |
能用但难用、别扭 |
代码规范 |
风格、命名、结构问题 |
文档对齐/冲突 |
文档与实现不一致或互相矛盾 |
性能问题 |
慢、资源占用高 |
安全问题 |
安全隐患 / 漏洞 |
5. 数据模型
<workspace>/tmp/dsh-repo-bug.json(相对路径按会话工作目录解析,见 §7):
{
"meta": { "version": 1, "updated_at": "..." },
"records": [
{
"id": "BUG-001",
"title": "简短摘要",
"type": "功能缺陷",
"fixed": false,
"note": "备注",
"detail": "详细描述",
"location": { "file": "src/a.js", "symbol": "foo", "line": 12, "snippet": "...", "line_volatile": true },
"recorded_at": "2026-10-22T00:00:00.000Z",
"git_sha": "abc1234",
"fixed_at": null
}
]
}
字段说明
| 字段 | 说明 |
|---|---|
id |
BUG-001 起,三位补零;超过 999 不截断(BUG-1000),由插件分配 |
title |
简短摘要 |
type |
类型(建议值见 §4,可自由扩展) |
fixed |
是否已修复,GUI 据此渲染 |
note |
备注(可选) |
detail |
详细描述(可选) |
location |
初步定位:file / symbol / snippet 是主要锚点,line 仅作记录时参考并标注 line_volatile: true;用 locate: true 时还会带 located_by: "subagent" |
recorded_at |
记录时间(ISO 8601) |
git_sha |
记录时的 git rev-parse --short HEAD,便于追溯 |
fixed_at |
标记修复的时间;未修复为 null |
fixed_note |
仅当 ohna_bug_fixed 传了 note 时写入 |
写入保证
- 只追加,从不整文件覆写;
- 原子写:同目录临时文件 +
rename;写入前重读防并发覆盖,id 冲突时重试; - 文件损坏:移到
<dataPath>.corrupt-<ts>备份后重建,不丢数据。
6. Web GUI
| slot | 位置 | 说明 |
|---|---|---|
conversation.view(order: 20) |
会话上方的 Bugs tab,与「对话」「轨迹」并列 | session 作用域,表格主体 |
conversation.input.left(order: 20) |
输入框工具行左侧(「切换模型」左边)的 Bug 记录 按钮 | 点击弹出浮层,复用同一表格 |
第二个入口在新建会话尚未发消息时同样可见 —— 此时 DSH 会隐藏整个 tab 栏(含「轨迹」) 与头部 utilities,只有 composer 工具行仍渲染,且它仍能拿到
inputActions, 所以「一键修复填输入框」在 blank 会话下依然可用。
表格能力:
- 列:编号 / 摘要 / 类型 / 已修复 / 备注 / 记录时间 / 操作;点击行展开详细描述与代码定位弹层;
- 一键修复:把未修复 bug 的修复指令写进输入框(不自动发送);
- 每行操作:一个按钮翻转该条
fixed(修好了标已修复;验证没修好改回未修复以便二次修复); - 不提供删除:新增由
ohna_bug_record完成,状态变更由ohna_bug_fixed或 GUI 操作完成; - 每个工作区只显示自己的
tmp/dsh-repo-bug.json,不串台(组件从当前 session 取cwd)。
7. HTTP 接口
GET {apiPrefix}/bugs?cwd=<会话工作目录> # 读取
POST {apiPrefix}/bugs?cwd=<会话工作目录> # 翻转 fixed
默认 apiPrefix = /api/dsh-repo-dashboard,即 /api/dsh-repo-dashboard/bugs。
GET 返回:
| 字段 | 说明 |
|---|---|
meta |
{ version, updated_at } |
records |
记录数组 |
workspace |
解析后的工作目录绝对路径 |
data_path |
bug JSON 的绝对路径 |
fix_tool |
经注册校验后的编排工具名;未配置或未注册时为 null(GUI 据此降级第 3 步) |
POST 接收 { ids, fixed },返回 { updated, total, data_path, workspace }。
非 GET/POST 方法返回 405;无法解析出绝对工作目录时返回 400。
8. 配置(cordis.patch.yml)
- insert:
- id: dsh-ohna
name: 'dsh-ohna'
config:
# —— 开发流水线(ohna_devline_run) ——
provider: spawn
maxParallel: 8
maxFixRounds: 3
insertionGraceMs: 1000
# —— bug 记录(ohna_bug_record / ohna_bug_fixed) ——
dataPath: tmp/dsh-repo-bug.json
detailMaxChars: 2000
apiPrefix: /api/dsh-repo-dashboard
locatorProvider: spawn
# —— 一键修复提示词:第 3 步引用的修复编排工具 ——
# 默认指向本插件自带的 ohna_devline_run;可改成任意第三方 tool 名。
# 第 4 步的标记工具恒为 ohna_bug_fixed,不可配置。
fixTool: ohna_devline_run
| 键 | 默认 | 说明 |
|---|---|---|
provider |
spawn |
子 agent 后端(spawn = 隔离上下文) |
maxParallel |
8 |
并发 coder 上限(夹取到 1–64) |
maxFixRounds |
3 |
审核→修复迭代上限(夹取到 0–10) |
insertionGraceMs |
1000 |
修复轮等待「本条反馈写入子会话日志(user/message)」的兜底上限:仅用于只上报 subagent/end 却从不上报该记录的宿主,避免修复轮卡死;正常宿主由后续 subagent/end 直接结算,不会触及 |
dataPath |
tmp/dsh-repo-bug.json |
记录文件路径;相对路径按会话工作目录解析,绝对路径原样使用 |
detailMaxChars |
2000 |
详细描述软上限(下限 200) |
apiPrefix |
/api/dsh-repo-dashboard |
HTTP 路由前缀 |
locatorProvider |
spawn |
locate: true 时定位 subagent 的后端 |
fixTool |
ohna_devline_run |
「一键修复」提示词第 3 步引用的编排工具,可换成任意第三方 tool 名 |
另有可选的
workspace:仅作为 GUI 请求未带?cwd=时的兜底工作目录, 不会被工具调用更新(该状态是跨会话共享的,若被改写会让每个会话的 tab 都指向同一个文件)。
服务依赖
inject = ["tools", "subagents"]。workingDirectory 与 webServer 不声明 ——
cordis 没有 optional-inject 形式,声明了会让缺该服务的 profile 永久 pending,
因此二者一律运行时用 ctx.get / ctx.inject 惰性获取。
9. 安装
方式一:npm 安装(推荐)
在 the agent runtime 的 Plugins 页(插件市场) 搜索安装本包,或用 install_bundle 安装。
安装后重载 profile(重启 DSH,或在插件市场重装本 entry),三个工具即对当前 profile 的 agent 可见。
也可以直接装进 profile:
npm install dsh-ohna
然后在 ~/.dsh/profiles/<profile>/package.json 把 dsh-ohna 加入 dsh.profile.bundles:
{
"dsh": {
"profile": {
"bundles": [
"@deepseek-ai/dsh-base",
"@deepseek-ai/dsh-web-app",
"dsh-ohna"
]
}
}
}
需要 Node >= 22(本插件使用了
Promise.withResolvers())。
方式二:本地 link(开发用)
把本地开发目录 link 进 profile,便于改代码即时验证:
{
"dependencies": {
"dsh-ohna": "link:/path/to/your/dsh-ohna"
},
"dsh": {
"profile": {
"bundles": [
"@deepseek-ai/dsh-base",
"@deepseek-ai/dsh-web-app",
"dsh-ohna"
]
}
}
}
把 /path/to/your/dsh-ohna 换成你的实际目录,然后重载 profile。
10. 从旧插件迁移
dsh-ohna 由两个插件合并而来,二者原本是「一个闭环被拆成两个包」:
| 原插件 | 原工具 | 现工具 |
|---|---|---|
dsh-dev-line |
devline_run |
ohna_devline_run |
dsh-repo-dashboard |
repo_bug_record |
ohna_bug_record |
dsh-repo-dashboard |
mark_bug_fixed |
ohna_bug_fixed |
迁移要点:
- 工具名统一加
ohna_前缀。DSH 的tools.register对同一层内重名直接抛错, 而devline_run/repo_bug_record/mark_bug_fixed都是通用词,与其他市场插件重名概率不低, 重名会让后加载的插件整个启动失败 —— 加前缀是主动避让冲突。调用方需改用新名字。 fixTool取代了写死的工具名。旧dsh-repo-dashboard的「一键修复」提示词里写死了devline_run+mark_bug_fixed;现在第 3 步由fixTool配置(默认ohna_devline_run), 第 4 步固定为ohna_bug_fixed。- 数据文件与 GUI 行为不变:仍是
<workspace>/tmp/dsh-repo-bug.json, API 前缀仍是/api/dsh-repo-dashboard/bugs,旧记录可直接沿用,无需迁移数据。 - 卸载旧插件:避免两个插件同时注册重复工具导致启动失败。
11. 目录结构与测试
dsh-ohna/
├── package.json # name: dsh-ohna, version 0.1.4, private: false
├── cordis.patch.yml # 合并后的一份 config
├── index.js # host 入口:注册 3 个工具
├── devline.js # ohna_devline_run(并行流水线)
├── buglog.js # ohna_bug_record / ohna_bug_fixed + HTTP 路由
├── storage.js # bug 存储:编号 / 原子写 / 损坏备份
├── fixprompt.js # 一键修复提示词(纯函数,无副作用)
├── gui.js # client 侧:tab + 浮层 + 一键修复
├── locale/{en,zh}.json
├── icon.svg
└── tests/ # node --test
npm test # node --test "tests/*.test.js" —— 63 个测试
测试覆盖:devline 的 fix 循环归属(FEEDBACK_MARKER + session/event + subagent/end
时序消歧)、三个工具名固定且互不相同、重复注册 fail-loud、路由 GET/POST 与 fix_tool
校验降级、提示词纯函数的第 3/4 步与降级分支、工作区隔离。
仅依赖 Node 内置模块,任何提供
tools/subagents服务的 profile 都能激活。
License
见 LICENSE。