DeepSeek Harness 插件

dsh-neoforge

NeoForge-style standard API layer for DeepSeek Harness plugins: runtime mixins with snapshot/restore + a Cordis-native event bus(英文原文)

跳到安装方式

来源信息

GitHub 仓库
r05En1cU/dsh-neoforge
最近更新
2026年8月16日
分类
工具与能力
GitHub stars
3
载体类型
plugin
目录证据
上游声明已找到 dsh.bundle
证据路径
package.json#dsh.bundle
核对版本
0.1.0-rc.8
上游核对日期
2026-08-20

该证据由上游目录提供。本站没有安装、运行或安全审核这个插件。

安装

默认先复制一段 Prompt,让 Agent 读 GitHub 仓库和源码;需要自己装时再切到命令。

复制这段 Prompt,发给 DSH、Codex 或其他 Agent,让它先读 GitHub 仓库和源码。

请先不要安装或执行任何命令。阅读这个插件的 GitHub 仓库、README 和关键源码,然后用清楚、直接的方式回答以下问题,帮助我判断它是否适合我的需求:

1. 这个插件是什么,解决什么问题;
2. 适合哪些用户和典型使用场景;
3. 安装后如何使用,并给出一个最小使用示例;
4. 有哪些已知限制,以及隐私、安全、兼容性或维护风险;
5. 给出“推荐 / 有条件推荐 / 不推荐”的明确建议和理由。

请区分仓库明确说明、根据源码推断和未知信息。证据不足时请明确说明,不要猜测或照抄 README。

GitHub:https://github.com/r05En1cU/dsh-neoforge
插件名:dsh-neoforge
作者:r05En1cU

检查来源文件

安装前先看这个插件目录里的 README 和其他文件。

文件资源管理器3 个文件
README.md来源说明 · 只读预览

dsh-neoforge

面向 DeepSeek Harness(DSH)插件开发的类 NeoForge 标准 API 层

  • 语义化 source,先 seam 后 mixin:catalog 作者声明 event / service / view / mixin,后端自动选择;官方已有事件或服务方法时零补丁。
  • Mixin 是可选子层dsh-neoforge/mixin 通过 createMixinLayer() 挂载;运行期解析目标、保留旧快照、执行修改后的包装,卸载时恢复旧快照。
  • 运行期目标全局独占:同一目标被多个第三方包 patch 时直接 loud error,不做隐式链式叠加。
  • 事件总线复用官方 HMRctx.on('vendor/action', handler) / ctx.neoforge.on(...) 就是官方 Cordis 事件注册,fiber 卸载自动回收 listener。
语义 source
  ├─ event     → 官方事件别名(零补丁)
  ├─ service   → internal/service + 原型快照/恢复
  ├─ view      → internal/get 消费方视图
  ├─ mixin     → 运行期 resolve → descriptor 快照 → wrapper → 恢复
                    │
                    ▼
            {id}/before (ctx.bail) + {id} (ctx.emit)
                    │
                    ▼
        社区插件 ctx.on('vendor/action', …)

dsh plugin add 相容

dsh-neoforge 现在同时是库和 bundle carrier:

dsh plugin --profile web add github:r05En1cU/dsh-neoforge
  • 安装后注入一个默认禁用的 dsh-neoforge 行;
  • 默认不 mount,不会作为 plugin 启动;
  • 其他插件可以直接 import from 'dsh-neoforge'
  • 如果宿主想挂载基础服务,可在 profile overlay 启用:
- id: dsh-neoforge
  disabled: false

启用后根入口作为标准 function plugin 执行,等价于调用一次 getNeoForge(ctx),挂载 ctx.neoforge

快速开始

1. catalog 作者:语义 source + 稳定事件

import { defineCatalog, defineEventPoint } from 'dsh-neoforge'
import type { NeoForgeEvent } from 'dsh-neoforge'

declare module '@deepseek-ai/cordis' {
  interface Events {
    'agent-preset/switch'(event: NeoForgeEvent<{ to: string }>): void
    'agent-preset/switch/before'(event: NeoForgeEvent<{ to: string }>): void
  }
}

export default defineCatalog({
  plugin: '@deepseek-ai/dsh-agent',
  versionRange: '>=0.0.0-0',          // DSH 全系 rc:不能用 '^x'(不匹配预发布)
  points: [
    defineEventPoint({
      id: 'agent-preset/switch',
      requires: 'mutate',
      source: {
        kind: 'mixin',
        target: {
          module: '@deepseek-ai/dsh-agent',
          versionRange: '>=0.0.0-0',
          filePath: 'lib/index.js',
          functionQuery: { className: 'AgentPresets', methodName: 'recompose', kind: 'Method' },
        },
        operation: 'around',
      },
      map: {
        toEvent: (args) => ({ to: args[0] }),
        applyEvent: (payload, args) => { args[0] = payload.to },
      },
    }),
  ],
})

2. 装配 catalog

import { createNeoForge } from 'dsh-neoforge'
import { createMixinLayer } from 'dsh-neoforge/mixin'
import agentCatalog from './catalogs/agent.ts'

// catalog 含 source.kind === 'mixin' 时,必须先挂可选 mixin 层
ctx.plugin(createMixinLayer())
ctx.plugin(createNeoForge(agentCatalog))

3. 社区插件:零 mixin 概念

export const name = 'my-preset-logger'

export function apply(ctx) {
  ctx.on('agent-preset/switch/before', (event) => {
    event.payload.to = 'code'
  })
  ctx.on('agent-preset/switch', (event) => {
    console.log('switched to', event.result)
  })
}

运行期 Mixin:快照 → 修改后运行 → 恢复

每个 runtime-mixin 注册都执行:

1. Object.getOwnPropertyDescriptor(holder, key) 保存精确旧快照; 2. Object.defineProperty(holder, key, { ...snapshot, value: wrapper }); 3. 调用经 wrapper 执行 Advice 语义; 4. fiber 卸载时恢复旧快照 descriptor。

冲突策略:目标 (holder, key) 运行期全局独占。第二个第三方包尝试 patch 同一目标时注册直接抛错:

neoforge: runtime mixin "b" conflicts with "a" on Object.helper —
a runtime patch target is exclusive

同一 mixin id 的同 owner 重注册视为 HMR/重放,卸载后目标恢复可再次注册。

运行期 Mixin 能做什么

目标支持机制
CJS exports.helper / 对象属性函数保存 descriptor,替换为 wrapper
class 实例方法 ChatService.prototype._sendclassName + methodName 定位 prototype,现有实例立即生效
ESM class export 的实例方法namespace 绑定只读,但 class.prototype 可变
尚未加载模块里的 class 方法监听官方 internal/service,服务注册时补丁
ESM named export 模块级函数unavailablenamespace 绑定运行期不可写
#private、闭包、astQueryunavailable运行期原理性不可达

不可达目标不会静默假装成功:ctx.neoforge.status() 明确报告 bound / pending / missing / unavailable / stale

Advice:唯一拦截原语

before / after / around / replace 全部编译为同一个 around 形态:

type OperationPhases = {
  before?(call): void
  after?(call): unknown
  around?(call, proceed): unknown
}

事件后端和裸 ctx.mixinLayer.register 后端共享这一个操作分发器,因此 async settle、host policy、payload 映射只实现一次。

事件语义

织入 operation{id}/beforectx.bail{id}ctx.emit
before可改 event.args
afterevent.result 可改并回流
around可改参;event.veto = true 跳过原方法settle 后携带 event.result
replace完全接管;event.invoke() 才执行原方法

source: { kind: 'event' } 是纯观察别名,只有 {id},没有写回能力。

破坏性更新影响最小化

  • 稳定事件面:事件名是 catalog 的公共契约,官方方法改名/改签名只改 catalog。
  • 版本治理target.versionRange + 自动读取目标包 package.json(或注入 readVersion)。
  • 契约测试contractSuite(catalog, harness) —— 一次安装、一次调用、断言事件恰好一次。
  • 默认观察、显式写入requires: 'mutate' | 'replace' 是 review-listed 能力;宿主可 ctx.intercept('neoforge', { allowMutate: false }) 降级为只读。

模块级函数 mixin:自定义事件层

functionName / expressionName 类型的 mixin source 会自动路由到 module-mixin 后端,它专门消费以下标准 Cordis 事件:

事件语义
neoforge/module/load模块 handle 首次可用 → 解析并 patch
neoforge/module/reload重新求值产生新 exports holder → 退役旧快照、patch 新 holder
neoforge/module/unload模块句柄失效 → 恢复当前快照,回到 pending

宿主 / loader / bundle 刷新器只需发布:

import { trackModule, reloadModule, untrackModule } from 'dsh-neoforge'

trackModule(ctx, {
  id: '@pkg/lib/index.js',      // 与 mixin target 的 module/filePath 对应
  module: '@pkg',
  filePath: 'lib/index.js',
  exports: cjsExports,          // 可变 exports holder
  version: '1.2.0',
})

// HMR/重导入后
reloadModule(ctx, { ...same, exports: freshExports })

// 卸载
untrackModule(ctx, '@pkg/lib/index.js')

事件派发是同步的,因此 reload 完成后旧 holder 已恢复、新 holder 已 patch。该层只对运行期可写的 CJS exports / class prototype 有效;ESM named export 绑定应改用官方事件或 service seam。

HMR 语义

  • 下游监听器:官方 ctx.on,loader 卸载旧 fiber 时自动回收。
  • catalog/neoforge 插件自身:注册是 ctx.effect;卸载恢复快照,重载重新注册。
  • service 类目标:完整代际 HMR。internal/service 同步通知,新类 prototype 在同一窗口内完成 retire(old) → attach(new)
  • 模块级 CJS 目标:无官方“模块被重新求值”事件,运行期无法自动感知;getNeoForgeStatus(ctx) / status() 会重新解析已绑定目标,发现新 exports holder 后自动退役旧快照、补丁新 holder。
  • ESM named export / #private / 闭包:运行期不可达;dsh-neoforge 不再内置加载期桥,请改用官方事件、service seam,或让目标模块暴露可变句柄。

服务与治理

NeoForgeService 是标准 Cordis 服务(ctx.neoforge):

ctx.intercept('neoforge', { deny: ['vendor/unsafe-point'] })
ctx.intercept('neoforge', { allowMutate: false })

ctx.neoforge.register(catalog)         // fiber-scoped 注册
ctx.mixinLayer.register(mixin, h)      // 裸 mixin 运行期注册
ctx.neoforge.status()                  // 每个注入点的 source/后端/绑定/漂移诊断
ctx.neoforge.on(name, listener)        // = ctx.on,官方 HMR 事件路径

旧 catalog 的 tier/runtime/mixin 字段会 normalize 为语义 source,现有声明无需迁移。

统一 UI 服务:page → layer → slot → component

dsh-neoforge/ui 是一个纯 Cordis、无 Node builtin 的渲染无关 UI 层。插件只需 inject: ['ui']

const store = ctx.ui.state({
  id: 'feed',
  init: () => ({ items: [] }),
  actions: {
    push(draft, item) { draft.items.push(item) },
  },
})

ctx.ui.page({ id: 'workspace', title: 'Workspace' })
ctx.ui.layer({ id: 'webui', kind: 'react-dom' })

ctx.ui.slot({ id: 'workspace.sidebar', page: 'workspace' })
ctx.ui.component({
  id: 'feed-panel',
  slot: 'workspace.sidebar',
  title: 'Feed',
  state: store,
  render: (h) => h('view', { direction: 'column' }, [
    h('text', { value: `items: ${store.getSnapshot().items.length}` }),
    h('button', { label: 'Refresh' }),
  ]),
})
  • component:返回统一 vnode,不直接依赖 React/Ink/RN;
  • stategetSnapshot / subscribe / select / actions,adapter 各自绑定框架;
  • adapter:webui adapter 把 vnode 转成 React 组件并注册到 ctx.slots;tui adapter 把 vnode 投影成文本 panel;
  • 组件注册、store、layer/slot 都是 fiber effect,HMR 自动回收。

内置 adapter:

import { createUiKit, webuiSlotsAdapter, tuiAdapter } from 'dsh-neoforge/ui'

ctx.plugin(createUiKit({
  adapters: [
    webuiSlotsAdapter({ createElement: React.createElement }),
    tuiAdapter(),
  ],
}))
  • tuiPanelAdapter():注册到 CodeWhale 风格的 registerPanel surface;
  • tuiOverlayAdapter():注册到官方 dsh/cc-tui 的 openOverlay surface;
  • tuiAdapter() / codewhaleTuiAdapter:自动选择上述两种 TUI surface。

dsh-neoforge/ui 同时内置了迁移自 CodeWhale 的 TUI 表面:

import { createTui } from 'dsh-neoforge/ui'

ctx.plugin(createTui({ placement: 'top', panel: 'tasks' }))

ctx.tui.registerPanel({
  id: 'neoforge.status',
  title: 'neoforge',
  lines: () => ctx.neoforge.status().map((row) => `${row.id}: ${row.mounted.join(',')}`),
})

ctx.tui.setWorkSurface({
  panel: 'tasks',
  placement: 'top',
  rows: [
    { id: 'patch', label: 'runtime mixin', status: 'done', tone: 'success' },
    { id: 'tui', label: 'migrate CodeWhale TUI', status: 'running', tone: 'live' },
  ],
})

ctx.tui.render({ width: 80, height: 24 }) // 确定性文本快照

createTui 是幂等插件;ctx.tui 支持 registerPanel / openOverlay / setChrome / render,panel/overlay 都随调用 fiber 自动回收。createCodewhaleTui 是迁移别名。

Node 侧零依赖 ANSI host:

import { createTuiHost } from 'dsh-neoforge/tui-host'

ctx.plugin(createUiKit({ adapters: [tuiAdapter()] }))
ctx.plugin(createTui())
ctx.plugin(createTuiHost())
// q / ctrl+c 发出 'tui/host/exit-requested',launcher 负责 shutdown

GUI/React Native 可以用同一套 SurfaceAdapter 约定接自己的 service。

WebUI / TUI:事件跨树

  • TUI(cc-tui):Node 同树场景直接 ctx.on,无需额外层;组件注入仅在目标运行期可达时使用 mixin
  • WebUI:浏览器是另一棵 Cordis 树,使用两个新入口:
// host 侧:把最新事件发布到官方 webserver exact route
import { createNeoForgeRelay } from 'dsh-neoforge'

ctx.plugin(createNeoForgeRelay({
  path: '/neoforge/snapshot',
  points: ['agent-preset/switch'],
}))
// browser 侧:dsh-neoforge/client 轮询 relay 并 re-emit 同名 neoforge 事件
import { createNeoForgeClient } from 'dsh-neoforge/client'

ctx.plugin(createNeoForgeClient({
  route: '/neoforge/snapshot',
  points: ['agent-preset/switch'],
  interval: 1500,
}))

createNeoForgeClient 是浏览器安全入口,不 import 任何 Node builtin;事件到达浏览器树后,UI 注册仍走官方 ctx.slots / ctx.command,neoforge 只负责事件语义跨树。

开发

pnpm install         # 同时执行 prepare 构建 dist/
pnpm run typecheck   # tsc strict
pnpm test            # 64 项:Advice + source + runtime/module mixin + WebUI relay/client + ctx.ui + CodeWhale TUI + HMR + policy
pnpm run build       # dist/ ESM + d.ts

要求 Node ≥ 22.19;ESM class 运行期补丁依赖当前 Node 的同步 require(esm)(Node 24 默认启用)。架构决策见 [docs/architecture.md](docs/architecture.md),完整调用文档见 [docs/usage.md](docs/usage.md),迁移技能见 [skills/dsh-neoforge-migrate/SKILL.md](skills/dsh-neoforge-migrate/SKILL.md)。