把长任务拆成步骤,逐步在独立会话中执行并校验结果
29.9/100
综合分
0
GitHub 星标
—
npm 周下载
—/5
用户评分
数据截至 2026/10/27 · 周下载取自 npm 全网(含 CI / 镜像),非本站安装数;综合分由星标、活跃度与兼容性检查合成。
安装命令 · 需先装 dsh CLI 引擎
dsh plugin --profile web add MathieuPortmann/dsh-plan-runner该包不可直接 npm 安装,改从 GitHub 源安装(明细见下方安装检查)
状态速览
判定依据:实装验证 · 静态安装检查 · 自动扫描 · 仓库维护状态信任档位:仅索引
是什么
dsh 原生插件 · chat
装得上吗
本站尚未做安装检查
安全吗
本站尚未对该插件做风险分级
暂未覆盖,不等同于无风险
还在维护吗
活跃:最近一次提交在 6 天前
档位由哪些信号合成
本站实装验证(真实安装 L4 覆盖全站;L5 为运行时冒烟或实机截图,覆盖范围小于 L4) · 验证所用 dsh 版本 · 静态安装检查 · 风险分级 · 仓库维护状态。 下方各区块是它的证据明细。
社区实装还没有人打卡 · 装过的第一个就是你
安全扫描自动 · 静态分析源码v2.7.0🔵 扫描:含敏感能力尚无人工评估展开查看扫描说明与证据 ↓
安全扫描自动 · 静态分析源码
v2.7.0静态扫描发现插件具备触达本地系统的能力:执行外部命令、读写/删除本地文件、读取剪贴板或密钥类环境变量(至少其一)。这是能力清单,不是危险判定——具体能力项与证据见下方,安装前请自行判断是否需要。
可执行外部命令读写/删除本地文件发起外部网络请求
查看扫描证据(共 28 处,展示前 28 条)
- 读取本地文件index.js:48
for (const d of (() => { try { return readdirSync(root); } catch { return []; } })()) { - 读取本地文件index.js:49
const read = f => { try { return readFileSync(join(root, d, f), 'utf8').trim(); } catch { return ''; } }; - 发起网络请求index.js:155
const r = await fetch(`${cfg.ollamaUrl}/api/tags`, { signal: AbortSignal.timeout(4000) }); - 删除本地文件index.js:173
if (out) { try { unlinkSync(resolve(state.cwd, out)); } catch { } } - 读取本地文件index.js:225
if (!(p in state.preexisting)) state.preexisting[p] = existsSync(abs); - 读取本地文件index.js:227
if (rel.startsWith('..') || !existsSync(abs) || !statSync(abs).isFile()) continue; - 读取本地文件index.js:227
if (rel.startsWith('..') || !existsSync(abs) || !statSync(abs).isFile()) continue; - 写入本地文件index.js:228
try { mkdirSync(dirname(join(dest, rel)), { recursive: true }); copyFileSync(abs, join(dest, rel)); } catch { continue; } - 写入本地文件index.js:228
try { mkdirSync(dirname(join(dest, rel)), { recursive: true }); copyFileSync(abs, join(dest, rel)); } catch { continue; } - 删除本地文件index.js:232
if (!step.forEach && state.preexisting?.[p] === false && !inputs.has(p) && !keptByDoneStep) { try { unlinkSync(abs); } catch { } } - 读取本地文件index.js:238
unchanged: (cwd, paths, since) => paths.filter(p => { try { return statSync(resolve(cwd, p)).mtimeMs < since - 1000; } catch { return false; } }), - 读取本地文件lib/plan-tools.js:71
if (!session || !cwd || !existsSync(cwd)) return 'REFUSED: this conversation has no working folder.'; - 读取本地文件lib/plan-file.js:36
if (typeof plan === 'string' && plan.trim() && cwd && existsSync(cwd)) { - 写入本地文件lib/plan-file.js:37
try { writeFileSync(join(cwd, `PLAN-${planSlug(plan)}.md`), plan.endsWith('\n') ? plan : `${plan}\n`); } - 读取本地文件lib/checks.js:83
try { return readdirSync(dir, { withFileTypes: true }); } catch { return []; } - 读取本地文件lib/checks.js:86
const isFile = f => { try { return statSync(f).isFile(); } catch { return false; } }; - 读取本地文件lib/checks.js:108
try { statSync(next); } catch { return; } - 执行外部命令固定命令lib/checks.js:162
child = spawn('sh', ['-c', command], { cwd, stdio: ['ignore', 'pipe', 'pipe'], detached: process.platform !== 'win32' }); - 读取本地文件lib/checks.js:193
try { const st = statSync(abs); size = st.isFile() ? st.size : undefined; } catch { } - 读取本地文件lib/checks.js:197
try { text = readFileSync(abs).toString('utf8'); } catch { } - 读取本地文件lib/checks.js:234
try { const st = statSync(abs); return st.isFile() ? st.size : undefined; } catch { return undefined; } - 写入本地文件lib/store.js:22
mkdirSync(dirname(file), { recursive: true }); - 写入本地文件lib/store.js:24
writeFileSync(tmp, content); - 写入本地文件lib/store.js:25
renameSync(tmp, file); - 读取本地文件lib/store.js:36
const s = JSON.parse(new TextDecoder('utf-8', { fatal: true, ignoreBOM: true }).decode(readFileSync(String(file)))); - 读取本地文件lib/store.js:45
const parsed = JSON.parse(readFileSync(join(dataDir(), 'index.json'), 'utf8')); - 读取本地文件lib/store.js:64
return list.filter(f => typeof f === 'string' && existsSync(f)).map(loadState).filter(Boolean); - 读取本地文件lib/store.js:68
return Object.values(readIndex()).flatMap(l => (Array.isArray(l) ? l : [])).filter(f => typeof f === 'string' && existsSync(f));
扫描于 2026/11/1(0 天前) · 范围 入口闭包 + 发布文件清单 · 来源 GitHub 仓库
静态扫描只反映源码中出现的调用,不构成安全背书;人工评估与自动扫描相互独立、互不覆盖。
依赖的 DSH / Cordis 模块
@deepseek-ai/dsh-llm@deepseek-ai/dsh-tools给这个插件打分还没有人投票↓
用户评分
还没有人投票,来当第一个
为 DeepSeek Harness(DSH)逐步执行计划的运行器,专为小型本地模型打造:每一步都开全新子会话,做机械校验,可选审查者。
README
由 DeepSeek 最新模型翻译生成dsh-plan-runner
为 DeepSeek Harness(DSH)打造的分步计划执行器,专为本地小模型设计——这类模型在长任务中容易跑偏。Plan 智能体负责写步骤;执行器随后在全新的子会话里逐步执行,每个子会话只能看到目标、自己的指令、前面步骤的简短摘要和需要用到的文件,并用 harness 自己运行的检查项验证结果。
维护状态: 尽力而为。issue 可能无人回复;欢迎 fork。
工作原理
1. 选择 Plan 预设。智能体先做只读探索,然后用 plan_begin、plan_add_step(每步一次调用)和 plan_show 记录步骤。某一步如果超过其模型上下文窗口的 60 %,会被拒绝,必须拆分。计划同时保存为 PLAN-<name>.md。
2. 批准计划,然后按 Run step by step(计划审核卡片,或输入框上方的条带)。每一步都在自己的会话里运行(原生 DSH 子代理),带有:
- 自己的模型(见「配置」),
- 自己的访问级别:read、read-shell(仅只读 shell 命令)、write(写文件,限于该步骤声明的输出)或 full,
- 一个 worker 人设和固定的最终报告(Summary / Files / Decisions / Open questions)。
展开完整文档(README 剩余 1 节)
dsh-plan-runner
为 DeepSeek Harness(DSH)打造的分步计划执行器,专为本地小模型设计——这类模型在长任务中容易跑偏。Plan 智能体负责写步骤;执行器随后在全新的子会话里逐步执行,每个子会话只能看到目标、自己的指令、前面步骤的简短摘要和需要用到的文件,并用 harness 自己运行的检查项验证结果。
维护状态: 尽力而为。issue 可能无人回复;欢迎 fork。
工作原理
1. 选择 Plan 预设。智能体先做只读探索,然后用 plan_begin、plan_add_step(每步一次调用)和 plan_show 记录步骤。某一步如果超过其模型上下文窗口的 60 %,会被拒绝,必须拆分。计划同时保存为 PLAN-<name>.md。
2. 批准计划,然后按 Run step by step(计划审核卡片,或输入框上方的条带)。每一步都在自己的会话里运行(原生 DSH 子代理),带有:
- 自己的模型(见「配置」),
- 自己的访问级别:read、read-shell(仅只读 shell 命令)、write(写文件,限于该步骤声明的输出)或 full,
- 一个 worker 人设和固定的最终报告(Summary / Files / Decisions / Open questions)。
3. 每步结束后,harness 运行该步骤的检查项:exists: <path>、contains: <path> :: <text>、words: <path> >= <n>、count: <glob> >= <n>、command: <shell command>(退出码 0 即通过)。重要步骤还会配一个只读审核者,以 VERDICT: OK 或 VERDICT: PROBLEMS - ... 结尾。
4. 失败的步骤会重试一次,附带失败原因和一条经验教训;第二次失败后,会提议更细的拆分,在你接受之前不做任何改动。
5. for_each 步骤按文件或条目逐个运行,每个都在简短会话里执行,并为每个条目写一个结果文件。标记为 stop 的步骤会暂停运行,方便你检查结果。
6. 循环(同一工具调用反复出现)会中止该步骤;因重启而中断的计划会暂停,并从当前步骤继续。
状态保存在 <working folder>/.plan-<name>/state.json(人类可读),每个会话的计划索引保存在 <DSH_HOME>/plan-runner/index.json。步骤覆盖的文件会备份到 .plan-<name>/backups/ 下。
步骤无法请求批准(DSH 会拒绝子代理中的批准请求):会话的权限模式不允许免询问执行的操作会被拒绝,该步骤随之失败。对于要写文件的步骤,请把会话设为自动模式或 workspace-write 模式。
安装
dsh plugin --profile web add dsh-plan-runner
or straight from GitHub:
dsh plugin --profile web add github:MathieuPortmann/dsh-plan-runner
之后重启配置档。该 bundle 自带 Plan 预设(id 为 plan);不要与其他定义了相同 id 预设的 bundle 一起使用。
配置
plan-runner 这一行写在你的配置档的 cordis.patch.yml 里;每个键都是可选的。
- id: plan-runner
config:
models: # models a step may use; empty = the plan conversation's own model
my-local-model:
provider: ollama
window: 32768 # context window in tokens
description: good reasoning, slow # shown to the Plan agent
defaultModel: my-local-model
splitModel: my-local-model # proposes the finer split after two failures
auditModel: '' # reviewer of important steps ('' = the step's own model)
pauseOnBattery: false # pause the run on battery power
ollamaUrl: http://127.0.0.1:11434
commandTimeoutMs: 120000 # timeout of command: checks
loopRepeats: 3 # identical tool calls in a step that count as a loop
当某个模型的服务商是 ollama 时,只要 ollamaUrl 不再响应,运行就会暂停。token 预算由 basePromptTokens、outputReserve、unknownFileTokens、itemOutputTokens 和 summaryTokens 控制(默认值按 32k 窗口调校)。
兼容性
| 组件 | 支持范围 |
| Node.js | ^22.19.0 \|\| >=24.0.0(engines.node) |
| DSH | >=0.2.0-rc.2 <0.3.0;以可选 peerDependencies 的形式声明在 @deepseek-ai/dsh-llm 和 @deepseek-ai/dsh-tools 上,这也是插件唯一导入的两个 DSH 包 |
| 平台 | Linux(已测试);纯 JavaScript,不含原生扩展。command: 检查需要 POSIX sh |
已在 Node 22.23 上配合 DSH 0.2.0-rc.2 测试(见验证)。
权限与外部服务
插件能触及的一切,以及失败时的表现:
| 能力 | 位置 | 用途 | 失败时 |
| 文件(读) | lib/checks.js、index.js | exists / contains / words / count 检查、用于 token 预算的文件大小、/sys/class/power_supply(仅在开启 pauseOnBattery 时);每个路径都在工作目录内解析 | 检查失败,或该文件按缺失处理 |
| 文件(写) | lib/store.js、lib/plan-file.js、index.js | <cwd>/.plan-<slug>/state.json 和 backups/、<DSH_HOME>/plan-runner/index.json、工作目录里的 PLAN-<name>.md;步骤自己的结果文件由该步骤的子会话写入,且限于它声明的 outputs | 计划保持之前的状态 |
| 命令 | lib/checks.js(spawn('sh', ['-c', …])) | command: 检查,由你或 Plan 智能体编写,在工作目录中运行并带超时(commandTimeoutMs);Plan 智能体会被告知保持它们只读 | 超时会杀掉命令及其子进程;检查失败 |
| 网络 | index.js(fetch) | 仅当某步骤使用 ollama 模型时,发起 GET <ollamaUrl>/api/tags | 服务器不可达时暂停运行 |
| 动态模块加载 | index.js、lib/plan-tools.js | 从运行插件的 DSH 安装中加载 @deepseek-ai/dsh-llm 和 @deepseek-ai/dsh-tools(在 Node 22 上,对 ES 模块做同步 require 会失败);不下载任何内容,也不从文本中求值任何代码 | 两者都是必需的:缺少任何一个,插件都无法加载 |
| 子代理 | index.js(ctx.subagents) | 每个步骤一个子会话,按访问级别(read、read-shell、write、full)配置工具过滤器 | 该步骤失败,并按重试规则处理 |
计划状态是 .plan-<slug>/ 下的纯 JSON;删除该文件夹即可忘记一个计划。
验证
在一次性配置档上验证过(DSH_HOME 指向临时文件夹,配置档用 dsh <name> --from-default-profile web 克隆,因此真实配置档从未被触碰):
npm pack
dsh plugin --profile t add file:$PWD/dsh-plan-runner-0.1.1.tgz # install
dsh --profile t --no-open --port 3095 # start: plugin loads, no error
npm test 运行 42 个独立测试(状态、解析、检查、存储、运行器、作用域守卫、只读 shell、配置),无需安装 DSH。用 9B 本地模型做了一次真实运行,通过 plan_begin / plan_add_step 创建计划,在子会话中运行其步骤,并用 words: 检查验证了结果。
开发
npm test
许可证
MIT预览分享卡片长什么样 ↓
分享 · DeepSeek Harness Hub
MathieuPortmann/dsh-plan-runner
把长任务拆成步骤,逐步在独立会话中执行并校验结果
相关插件 · 对话 / 记忆
上下文中枢oceanbase/powercontext
上下文跟着工作走 —— 跨会话、跨智能体、跨人。
★ 1,462已汉化DSH
73
智能体记忆库plastic-labs/honcho
Honcho 是记忆基础设施,用来构建有状态的智能体。这些智能体能理解不断变化的人、智能体、群组、项目和想法。
★ 7,848已汉化DSH
71.7
长程智能体控制面loopx-project/loopx
给 Agent 一个目标,让工作持续向前。
★ 6,358已汉化DSH
71.3
智能体上下文数据库volcengine/OpenViking
给 AI 智能体用的上下文数据库
★ 41,246已汉化DSH
71.3
长效机器人团队Fei2411/DS-Bot
DS Bot 是一个基于 DeepSeek Harness简称 dsh的 bot 插件,插件将 dsh 改造为 bot…
★ 4,717已汉化DSH
71.1
可携带记忆层EverMind-AI/EverOS
为什么选择 EverOS
★ 13,711已汉化DSH
71.1