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

递归双插件 HeliosLz/harness2-recursion

DeepSeek Harness
HeliosLz12 天前有提交已提供中文文档扫描:含敏感能力

用任务探针与经验库让插件自我迭代改进

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

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

安装命令 · 需先装 dsh CLI 引擎
dsh plugin --profile web add HeliosLz/harness2-recursion
该包不可直接 npm 安装,改从 GitHub 源安装(明细见下方安装检查)

状态速览

判定依据:实装验证 · 静态安装检查 · 自动扫描 · 仓库维护状态
信任档位:已验证
是什么
dsh 原生插件 · dev
装得上吗
本站已在 dsh 0.2.1-rc.2 下真实安装成功
非静态推断
L4 · 真实安装等级说明 →
安全吗
本站尚未对该插件做风险分级
暂未覆盖,不等同于无风险
还在维护吗
活跃:最近一次提交在 12 天前
档位由哪些信号合成

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

验证判据与等级说明 →
社区实装还没有人打卡 · 装过的第一个就是你
安全扫描自动 · 静态分析源码
v2.7.0
🔵 扫描:含敏感能力尚无人工评估
展开查看扫描说明与证据 ↓

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

可执行外部命令读写/删除本地文件
查看扫描证据(共 118 处,展示前 102 条)
  • 写入本地文件
    e2e/fake-model-server.mjs:22
    mkdirSync(dirname(LOG), { recursive: true })
  • 写入本地文件
    e2e/fake-model-server.mjs:106
    appendFileSync(LOG, `${JSON.stringify({ url: req.url, body: parsed })}\n`)
  • 写入本地文件
    e2e/round6-spike/fake-openai.mjs:14
    if (LOG) mkdirSync(dirname(LOG), { recursive: true })
  • 写入本地文件
    e2e/round6-spike/fake-openai.mjs:41
    if (LOG) appendFileSync(LOG, `${JSON.stringify({ at: new Date().toISOString(), body: parsed })}\n`)
  • 读取本地文件
    e2e/round6-spike/gate-replay.mjs:183
    const records = (await readFile(LEDGER, 'utf8')).trim().split('\n').filter(Boolean).map((line) => JSON.parse(line))
  • 读取本地文件
    e2e/round6-spike/gate-replay.mjs:228
    const experienceText = await readFile(EXPERIENCE, 'utf8').catch(() => '')
  • 读取本地文件
    e2e/round6-spike/gate-replay.mjs:229
    const freshStage0ExperienceText = await readFile(STAGE0_EXPERIENCE, 'utf8').catch(() => '')
  • 写入本地文件
    e2e/round6-spike/gate-replay.mjs:348
    await mkdir(path.dirname(OUT), { recursive: true })
  • 写入本地文件
    e2e/round6-spike/gate-replay.mjs:349
    await writeFile(OUT, `${JSON.stringify(verdict, null, 2)}\n`, 'utf8')
  • 执行外部命令固定命令
    e2e/round6-spike/run-spike.mjs:34
    const run = spawnSync('git', ['status', '--porcelain'], { cwd: REPO, encoding: 'utf8' })
  • 读取本地文件
    e2e/round6-spike/run-spike.mjs:45
    const fileHash = async (file) => `sha256:${sha256(await readFile(file, 'utf8'))}`
  • 执行外部命令来自配置/变量
    e2e/round6-spike/run-spike.mjs:49
    const run = spawnSync(process.execPath, [CLI, ...args], {
  • 写入本地文件
    e2e/round6-spike/run-spike.mjs:62
    try { writeFileSync(fd, text, 'utf8'); fsyncSync(fd) } finally { closeSync(fd) }
  • 读取本地文件
    e2e/round6-spike/run-spike.mjs:113
    try { return (await readFile(LOG, 'utf8')).trim().split('\n').filter(Boolean).length } catch { return 0 }
  • 执行外部命令来自配置/变量
    e2e/round6-spike/run-spike.mjs:118
    const server = spawn(process.execPath, [path.join(HERE, 'fake-openai.mjs')], {
  • 执行外部命令来自配置/变量
    e2e/round6-spike/run-spike.mjs:128
    const run = spawnSync(process.execPath, [CLI, '--profile', PROFILE, task], {
  • 读取本地文件
    e2e/round6-spike/run-spike.mjs:134
    const lines = (await readFile(LOG, 'utf8')).trim().split('\n').filter(Boolean).slice(before)
  • 删除本地文件递归
    e2e/round6-spike/run-spike.mjs:144
    await rm(path.join(ART, 'home'), { recursive: true, force: true })
  • 删除本地文件
    e2e/round6-spike/run-spike.mjs:145
    await rm(LOG, { force: true })
  • 写入本地文件
    e2e/round6-spike/run-spike.mjs:146
    await mkdir(ART, { recursive: true })
  • 写入本地文件
    e2e/round6-spike/run-spike.mjs:158
    await writeFile(PATCH, patchA, 'utf8')
  • 写入本地文件
    e2e/round6-spike/run-spike.mjs:159
    await copyFile(PATCH, BACKUP)
  • 写入本地文件
    e2e/round6-spike/run-spike.mjs:161
    await mkdir(path.join(ART, 'revisions', 'rev-A', 'backup'), { recursive: true })
  • 写入本地文件
    e2e/round6-spike/run-spike.mjs:162
    await copyFile(PATCH, path.join(ART, 'revisions', 'rev-A', 'backup', 'cordis.patch.yml'))
  • 读取本地文件
    e2e/round6-spike/run-spike.mjs:182
    const backupBytes = await readFile(path.join(ART, 'revisions', 'rev-A', 'backup', 'cordis.patch.yml'), 'utf8')
  • 执行外部命令来自配置/变量
    e2e/run.mjs:35
    const result = spawnSync(process.execPath, [cli, ...args], {
  • 读取本地文件
    e2e/run.mjs:50
    if (!existsSync(cli)) {
  • 删除本地文件递归
    e2e/run.mjs:55
    await rm(dshHome, { recursive: true, force: true })
  • 删除本地文件递归
    e2e/run.mjs:56
    await rm(artifacts, { recursive: true, force: true })
  • 写入本地文件
    e2e/run.mjs:57
    await mkdir(artifacts, { recursive: true })
  • 写入本地文件
    e2e/run.mjs:58
    await mkdir(dshHome, { recursive: true })
  • 读取本地文件
    e2e/run.mjs:65
    const profilePackage = JSON.parse(await readFile(path.join(profileDir, 'package.json'), 'utf8'))
  • 写入本地文件
    e2e/run.mjs:71
    await writeFile(path.join(profileDir, 'cordis.patch.yml'), `# Generated by e2e/run.mjs
  • 执行外部命令来自配置/变量
    e2e/run.mjs:142
    const server = spawn(process.execPath, [path.join(repoRoot, 'e2e', 'fake-model-server.mjs')], {
  • 执行外部命令来自配置/变量
    e2e/run.mjs:161
    const result = spawnSync(
  • 读取本地文件
    e2e/run.mjs:180
    const ledgerLines = (await readFile(ledgersPath, 'utf8')).trim().split('\n').filter(Boolean)
  • 读取本地文件
    e2e/run.mjs:207
    const experienceText = await readFile(experiencePath, 'utf8').catch(() => '')
  • 写入本地文件
    e2e/run.mjs:229
    await writeFile(path.join(artifacts, 'RESULTS.md'), summary.join('\n'), 'utf8')
  • 写入本地文件
    e2e/stage0/fake-model-server.mjs:37
    mkdirSync(dirname(LOG), { recursive: true })
  • 写入本地文件
    e2e/stage0/fake-model-server.mjs:179
    appendFileSync(LOG, `${JSON.stringify({
  • 读取本地文件
    e2e/stage0/stage0.mjs:70
    const text = await readFile(file, 'utf8')
  • 读取本地文件
    e2e/stage0/stage0.mjs:84
    const text = await readFile(file, 'utf8')
  • 执行外部命令来自配置/变量
    e2e/stage0/stage0.mjs:93
    const result = spawnSync(process.execPath, [CLI, ...args], {
  • 执行外部命令固定命令
    e2e/stage0/stage0.mjs:164
    const result = spawnSync('git', ['-C', REPO, 'status', '--porcelain'], { encoding: 'utf8' })
  • 读取本地文件
    e2e/stage0/stage0.mjs:175
    if (!existsSync(CLI)) {
  • 读取本地文件
    e2e/stage0/stage0.mjs:179
    if (!existsSync(path.join(REPO, 'packages', packageName, 'lib', 'index.js'))) {
  • 读取本地文件
    e2e/stage0/stage0.mjs:189
    text = await readFile(EXPERIENCE, 'utf8')
  • 写入本地文件
    e2e/stage0/stage0.mjs:209
    await mkdir(HOME, { recursive: true })
  • 删除本地文件递归
    e2e/stage0/stage0.mjs:210
    await rm(PROFILE_DIR, { recursive: true, force: true })
  • 写入本地文件
    e2e/stage0/stage0.mjs:212
    await writeFile(
  • 写入本地文件
    e2e/stage0/stage0.mjs:242
    await writeFile(PROFILE_PATCH, patchYaml(), 'utf8')
  • 写入本地文件
    e2e/stage0/stage0.mjs:245
    await writeFile(path.join(DIR, 'profile-dump-final.txt'), dumpText, 'utf8')
  • 读取本地文件
    e2e/stage0/stage0.mjs:265
    const deps = JSON.parse(await readFile(path.join(PROFILE_DIR, 'package.json'), 'utf8')).dependencies ?? {}
  • 写入本地文件
    e2e/stage0/stage0.mjs:272
    await writeFile(
  • 删除本地文件
    e2e/stage0/stage0.mjs:326
    await rm(REQUESTS, { force: true })
  • 执行外部命令来自配置/变量
    e2e/stage0/stage0.mjs:328
    const child = spawn(process.execPath, [path.join(SCRIPT_DIR, 'fake-model-server.mjs')], {
  • 写入本地文件
    e2e/stage0/stage0.mjs:384
    await writeFile(SERVER_LOG, `${stdout}${stderr}`, 'utf8')
  • 删除本地文件
    e2e/stage0/stage0.mjs:1318
    await rm(LEDGER, { force: true })
  • 删除本地文件
    e2e/stage0/stage0.mjs:1319
    await rm(EXPERIENCE, { force: true })
  • 删除本地文件
    e2e/stage0/stage0.mjs:1320
    await rm(REQUESTS, { force: true })
  • 执行外部命令来自配置/变量
    e2e/stage0-r6/run.mjs:50
    const result = spawnSync(process.execPath, [CLI, ...args], {
  • 读取本地文件
    e2e/stage0-r6/run.mjs:61
    const text = await readFile(file, 'utf8')
  • 读取本地文件
    e2e/stage0-r6/run.mjs:70
    const text = await readFile(file, 'utf8')
  • 执行外部命令固定命令
    e2e/stage0-r6/run.mjs:136
    assert(spawnSync('test', ['-f', CLI]).status === 0, `dsh CLI not found at ${CLI}`)
  • 执行外部命令固定命令
    e2e/stage0-r6/run.mjs:137
    assert(spawnSync('test', ['-f', FAKE_SERVER]).status === 0, 'stage0 fake server missing')
  • 执行外部命令固定命令
    e2e/stage0-r6/run.mjs:139
    assert(spawnSync('test', ['-f', path.join(REPO, 'packages', dirName, 'lib', 'index.js')]).status === 0,
  • 删除本地文件递归
    e2e/stage0-r6/run.mjs:142
    await rm(HOME, { recursive: true, force: true })
  • 写入本地文件
    e2e/stage0-r6/run.mjs:143
    await mkdir(ART, { recursive: true })
  • 写入本地文件
    e2e/stage0-r6/run.mjs:144
    await mkdir(HOME, { recursive: true })
  • 删除本地文件递归
    e2e/stage0-r6/run.mjs:145
    await rm(EDITS_DIR, { recursive: true, force: true })
  • 删除本地文件
    e2e/stage0-r6/run.mjs:146
    await rm(LEDGER, { force: true })
  • 删除本地文件
    e2e/stage0-r6/run.mjs:147
    await rm(EXPERIENCE, { force: true })
  • 删除本地文件
    e2e/stage0-r6/run.mjs:148
    await rm(REQUESTS, { force: true })
  • 写入本地文件
    e2e/stage0-r6/run.mjs:160
    await writeFile(path.join(PROFILE_DIR, 'cordis.patch.yml'), patchYaml(), 'utf8')
  • 执行外部命令来自配置/变量
    e2e/stage0-r6/run.mjs:169
    server = spawn(process.execPath, [FAKE_SERVER], {
  • 写入本地文件
    e2e/stage0-r6/run.mjs:201
    await writeFile(CLIENT_LOG, `${sessions.map((item) => JSON.stringify(item)).join('\n')}\n`, 'utf8')
  • 读取本地文件
    e2e/stage0-r6/run.mjs:207
    const bodyEntries = await readdir(EDITS_DIR).catch(() => [])
  • 读取本地文件
    e2e/stage0-r6/run.mjs:212
    const body = JSON.parse(await readFile(path.join(EDITS_DIR, entry), 'utf8'))
  • 写入本地文件
    e2e/stage0-r6/run.mjs:360
    await writeFile(RESULTS, `${JSON.stringify({ summary, checks, sessions }, null, 2)}\n`, 'utf8')
  • 写入本地文件
    e2e/stage0-r6/run.mjs:361
    if (passed) await writeFile(REPORT, report, 'utf8')
  • 读取本地文件
    packages/harness2-meta-recursion/src/index.ts:1270
    text = await readFile(this.experiencePath, 'utf8')
  • 读取本地文件
    packages/harness2-meta-recursion/src/index.ts:1322
    const text = await readFile(this.applyStatePath, 'utf8')
  • 读取本地文件
    packages/harness2-meta-recursion/src/index.ts:1339
    const journal = await readFile(journalPath, 'utf8').catch(() => '')
  • 读取本地文件
    packages/harness2-meta-recursion/src/index.ts:1362
    try { text = await readFile(this.evaluationsPath, 'utf8') } catch (error) {
  • 读取本地文件
    packages/harness2-meta-recursion/src/index.ts:1381
    try { report = JSON.parse(await readFile(reportPath, 'utf8')) } catch (error) {
  • 写入本地文件
    packages/harness2-meta-recursion/src/index.ts:1447
    await copyFile(this.experiencePath, backupPath)
  • 写入本地文件
    packages/harness2-meta-recursion/src/index.ts:1460
    await mkdir(directory, { recursive: true })
  • 写入本地文件
    packages/harness2-meta-recursion/src/index.ts:1462
    await writeFile(temporary, serializeExperience(snapshot), 'utf8')
  • 写入本地文件
    packages/harness2-meta-recursion/src/index.ts:1463
    await rename(temporary, this.experiencePath)
  • 写入本地文件
    packages/harness2-task-recursion/src/edit-store.ts:225
    await mkdir(directory, { recursive: true })
  • 写入本地文件
    packages/harness2-task-recursion/src/edit-store.ts:234
    await rename(temporary, file)
  • 读取本地文件
    packages/harness2-task-recursion/src/edit-store.ts:265
    await stat(file)
  • 读取本地文件
    packages/harness2-task-recursion/src/edit-store.ts:266
    const existing = await readFile(file, 'utf8')
  • 读取本地文件
    packages/harness2-task-recursion/src/edit-store.ts:304
    text = await readFile(file, 'utf8')
  • 读取本地文件
    packages/harness2-task-recursion/src/edit-store.ts:421
    const ledger = await readFile(options.ledgerPath, 'utf8')
  • 读取本地文件
    packages/harness2-task-recursion/src/edit-store.ts:432
    entries = await readdir(options.editsDir)
  • 读取本地文件
    packages/harness2-task-recursion/src/edit-store.ts:451
    const info = await stat(path.join(options.editsDir, entry))
  • 删除本地文件
    packages/harness2-task-recursion/src/edit-store.ts:456
    await rm(path.join(options.editsDir, entry))
  • 写入本地文件
    packages/harness2-task-recursion/src/index.ts:897
    await mkdir(path.dirname(absolute), { recursive: true })
  • 写入本地文件
    packages/harness2-task-recursion/src/index.ts:898
    await appendFile(absolute, `${JSON.stringify(record)}\n`, 'utf8')
  • 读取本地文件
    packages/harness2-task-recursion/src/index.ts:939
    text = await readFile(resolveStoragePath(ledgerPath), 'utf8')
  • 读取本地文件
    packages/harness2-task-recursion/src/index.ts:978
    text = await readFile(resolveStoragePath(ledgerPath), 'utf8')
扫描于 2026/11/1(0 天前) · 范围 全包扫描 · 来源 GitHub 仓库

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

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

Harness² 递归:两个可审计的 dsh 插件——任务级探针/组合证据闭环 + 驾驭级经验库(冻结契约 v4,34/34 测试通过,真实会话端到端验证)

README

由 DeepSeek 最新模型翻译生成
harness2-recursion Harness² 递归方案 —— 两个互相独立、可分别加载的 dsh 插件(第四轮冻结契约版本)。 | 包 | 职责 | | packages/harness2-task-recursion | 任务级递归:Propose → Probe → probe/completed → 确定性 Compose 门禁 → 账本 v3 → compose/applied/compose/rejected → 下一个 pre-step 应用 pendingPatch | | packages/harness2-meta-recursion | Harnessing 级递归:消费三事件 → 事后归因(edit 只取事实)→ 经验库 → 冻结只读门面 harness2Experience | 两个包的 src/index.ts 互不 import;src/constants.ts 逐字节相同。契约见 CONTRACT.md,验收见 SELF-CHECK.md。
展开完整文档(README 剩余 1 节)
harness2-recursion

Harness² 递归方案 —— 两个互相独立、可分别加载的 dsh 插件(第四轮冻结契约版本)。

| 包 | 职责 |
| packages/harness2-task-recursion | 任务级递归:Propose → Probe → probe/completed → 确定性 Compose 门禁 → 账本 v3 → compose/applied/compose/rejected → 下一个 pre-step 应用 pendingPatch |
| packages/harness2-meta-recursion | Harnessing 级递归:消费三事件 → 事后归因(edit 只取事实)→ 经验库 → 冻结只读门面 harness2Experience |

两个包的 src/index.ts 互不 import;src/constants.ts 逐字节相同。契约见 CONTRACT.md,验收见 SELF-CHECK.md。

目录

harness2-recursion/
├── CONTRACT.md # 第三轮冻结契约 ├── SELF-CHECK.md # 第三轮 13 项验收清单逐项证据 ├── README.md ├── package.json / tsconfig.base.json ├── test/loader-smoke.mjs # 真实 Cordis 装载/事件/卸载 smoke ├── e2e/ # 真实 headless 会话 E2E(安装/账本/applyMode/经验) ├── docs/ # 社区 Discussion 提案 + 发布清单 ├── LICENSE · .gitignore └── packages/ ├── harness2-task-recursion/ │ ├── src/{index.ts, constants.ts} │ ├── lib/ # tsc 产物(构建生成,不入库) │ ├── cordis.patch.yml · locale/ · icon.svg │ └── test/verify.mjs # 15 项契约自检 └── harness2-meta-recursion/ # 同上(13 项自检)

社区讨论

- 生态提案 Discussion(dsh 社区 Show Your Plugins!):https://github.com/deepseek-ai/deepseek-harness/discussions/10324
- 本仓库:https://github.com/HeliosLz/harness2-recursion

验证

要求 Node ≥ 24(node --test 直接 import src/index.ts,依赖类型剥离)。

npm install
npm run build # lib/index.js + lib/index.d.ts + lib/constants.js
npm run typecheck
npm run verify # task 15 + meta 14 + loader smoke 5 = 34 项

本次结果(2026-10-19):npm run verify 34/34 pass;typecheck/build exit 0;npm pack --dry-run 清单齐全;真实会话 E2E 通过(见下)。

第三轮新增(相对第二轮)

1. 事件 schema:TrialRecord 三个候选元数据字段必填(Q1);ProbeMetrics.tokenCostSource(Q4);ComposeAppliedPayload.appliedEdits(R3-1);ComposeRejectedPayload.rejectedCandidateIds(Q3)。
2. 账本 v3:{version,id,previousSnapshotRef,ledgerEntryId,event,payload,recordedAt};只写 v3,readLedgerTail 接受 v2|v3 并做内存映射、不重写 v2 文件(Q7)。
3. 归因规则:反射必须带 edit.candidateId,且与来源事实严格一致;写入的 edit 字段永远取自来源载荷(R3-3/Q2);不一致 → onError('reflection-edit-mismatch') 且拒绝写入。
4. confidence v3:base(0.6/0.5) × (0.5+0.5·min(1,trials/3)) × repeat(≤1.4) × sourcePenalty(estimated 0.9);trials=0 → 0 且不写入(Q4/Q5)。
5. 双注入阈值:positive 用 minConfidenceToInject,negative 用 minNegativeConfidenceToInject(默认 0.3,Q6)。
6. 组件表:COMPONENT_NAMES 八类冻结;7 项旧名迁移映射 + migratedFrom 审计;未知组件跳过并 onError('unknown-component');移除 workflow-control 回退(R3-7)。
7. token 计量:Propose 用 usage chunk;Probe/baseline 用可选 tokenMeter;否则字符数/4 估算;同一 metrics 单一来源。
8. 第四轮增量:新增终态事件 propose/failed(R4-1,与 Probe/Compose 互斥、append→emit、账本 revision 探测跳过它);rejectedCandidateIds 只取 trials 中出现的 id(R4-2 正式契约);outcome.tokenCostSource/migratedFrom 正式纳入 entry schema(R4-3)。

第三轮如实偏差(详见 CONTRACT §9 / SELF-CHECK §三)

- 无逻辑偏差:第三轮 Q3 冲突已由 propose/failed 独立终态解决(原 TODO(ROUND3_PROPOSE_FAILURE) 移除);预算早停的 rejected ids 与 entry 增量字段已追溯为正式契约。
- 环境依赖继续留 TODO/不验收:pre-step-patch 运行时 API(dsh 0.2.1 无)、Probe 工具沙箱、profile 安装(第四轮执行)。

第五轮:真实环境验证 + 社区材料

真实会话 E2E(已通过)

需要 dsh 0.2.1-rc.2 CLI 运行时(提取方式见 e2e/README.md)
E2E_CLI="<dsh-0.2.1-runtime>/dsh/node_modules/@deepseek-ai/dsh/lib/bin.js" node e2e/run.mjs

隔离 profile 内通过官方 dsh plugin add 安装两包,跑两次真实 headless 会话(假 provider:前 3 次主模型 500 → 触发 request-error 路径,随后延迟成功)。实测结果:

Ledger: 4 v3 records (2 probe/completed + 2 compose/applied)
applyMode: run1=noop-todo, run2=next-task-ledger
Revision anchor chain: null -> led-… -> led-… -> led-…
EXPERIENCE.md entries: 1 (confidence 0.50, measured tokens)
Sessions: 2 (exit 0)

- 首次 noop-todo 是冻结语义(插件激活时尚无账本可读);第二次会话由 readRevisionAnchor 升级为 next-task-ledger。
- 完整证据与复现步骤:e2e/README.md、e2e/artifacts/RESULTS.md。
- 卸载残留:loader smoke 第 5 项验证真实 Cordis dispose 后 7 个监听器全部释放、不再写账本/经验文件。

社区材料

- docs/discussion-proposal.md:Discussion 提案底稿(双插件契约、propose/failed 独立终态、元知识只改进编辑器三个差异点 + 34/34 证据 + 缺口 + 讨论问题)。
- docs/publishing.md:Phase 1 原型仓库/npm/Plugin Directory 发布清单。
- LICENSE(MIT)、.gitignore 已就绪;两包 keywords 含 dsh-plugin(发布前移除 private 并改用可发布包名)。

安装(第四轮/第五轮)

cd harness2-recursion && npm install && npm run build

然后在 Harness Web 的 Plugins 页分别安装两个本地 bundle(target 指向各包目录)。默认 observeOnly: true:只取证、不应用 Compose。
预览分享卡片长什么样 ↓HeliosLz/harness2-recursion
分享 · DeepSeek Harness Hub
HeliosLz/harness2-recursion

用任务探针与经验库让插件自我迭代改进

回到顶部