Skip to content

Releases: denceee/dsh-compat-adapter

v0.5.0 — 真实能力补齐(102 精确 / 10 近似)

Choose a tag to compare

@denceee denceee released this 18 Oct 04:45

v0.5.0 — 为缺失能力补齐真实实现

核心变化

四条路由,能力分级不变(DIRECT / ADAPTED / CARRY / UNSUPPORTED)

路由 事件数 说明
official-bridge 17 复用 DSH 官方已发布的 hook 桥
native-translate 80 直接翻译到 DSH 原生 seam
native-seam 5 只读观测(observe-only)
builtin-bridge 10 本插件自建桥(无官方桥的厂商)

总计:112 个厂商事件,0 个拒收,29 个原生翻译点。

其中 102 个为真实/精确映射,10 个在自己的 degradations 里明确写着 Approximate。
这 10 个分布在四家 vendor 上,而不是集中在某一家的边角:

vendor 近似事件
claude MessageDisplay、StopFailure
codex Interrupt
workbuddy Elicitation、ElicitationResult
opencode installation.updated、server.connected、session.deleted、session.updated、tui.toast.show

修正说明: 本条 release 的初版正文写的是"107 个真实 / 5 个近似"。那是错的 —— 它按"只有 5 个 native-seam 只读事件"来推算,而没有去读每个事件自己的 degradations 文本。按代码重新统计后是 102 / 10。这个偏差已被 test/doc-counts.test.js 覆盖:它从代码反推 badge、汇总表、流程图、翻译点数、用例数与 package.json 描述,任何一处比代码多宣称一分能力都会让 npm test 失败;初版数字 107 被按名拒收。

本轮补齐的真实能力

  • WorktreeCreate / WorktreeRemove — 真实执行 git worktree list --porcelain 轮询(porcelain stanza 解析:worktree/HEAD/branch/detached/locked/prunable),配合 looksLikeRepository() 与 diffWorktrees() 做增删差分。
  • opencode lsp.* — 真实调用 ctx.lsp.query(变更文件后触发),LSP_QUERY_FILE_LIMIT=10。
  • Elicitation — user-questions/request 瀑布真实作答(elicitationAnswerFrom),不再只是观测。
  • PreModelSwitch / PostModelSwitch — request/header 对 EpochHeader.config 做差分;首个 header 只作基线,不触发回调。
  • 工具批边界 — 以 step/end 作为真实边界(DSH 中一步 = 一次模型调用及其工具执行),当该步未请求任何工具时保持静默。
  • Copilot 自建桥 — builtin-bridge 路由 + kind:'builtin',与官方桥明确区分;check-surface 断言 @deepseek-ai/dsh-hooks-copilot 不存在,若 DSH 未来发布则测试响亮失败。

阻塞契约

只用 stdout 的 hookSpecificOutput.permissionDecision(deny/ask)+ exit 0;
不依赖 exit 2。Copilot 方言的决策位于顶层(permissionDecision),
matcher 为锚定正则 ^(?:PATTERN)$,stop 用 decision:"block",另有 8 次失控保护。

验证(本机实测)

npm run check-surface   # OK — 缺失元素会响亮命名报错
npm test                # 141 pass / 0 fail
node scripts/verify-live.mjs        # PASS — 真实 profile 启动
node scripts/verify-installed.mjs --profile <已装 profile>   # PASS — 已装 profile 真的生效

verify-live matrix:
  claude     hooks=33 supported /  0 refused   rules=CARRY
  codex      hooks=12 supported /  0 refused   rules=CARRY
  workbuddy  hooks=24 supported /  0 refused   rules=CARRY
  opencode   hooks=29 supported /  0 refused   rules=CARRY
  copilot    hooks=14 supported /  0 refused   rules=CARRY

verify-live 断言:Copilot 顶层 deny 能到达 DSH、锚定 matcher(bash vs edit)生效、1 次拒收路径成立。

兼容性

  • DSH 0.2.0-rc.2(peerDependencies 已固定)
  • Cordis 4.x、@deepseek-ai/schemastery
  • 零静态 @deepseek-ai/* 导入(src/peer.js 延迟加载),因此在 profile link: 目录下也能解析

另有本次修正:verify-installed 的四个假失败

scripts/verify-installed.mjs 回答的是使用者最关心的那个问题——"装到我自己的 profile 里,
它到底活没活"。它此前会在真实 profile 上给出错误结论,本次一并修掉:

  1. 没有握住 stdin —— profile 挂载的 SDK app 注册了 exitOnStdinEnd,stdin 一到 EOF 就卸载整个组合,
    下一次调用抛 ADAPTER_DISPOSED,被误报为插件故障。改为父进程持有管道再 re-exec。
  2. 伪造的 agent 没有 session —— DSH 自己的 GoalService 在 agent/created 里做
    WeakMap.set(agent.session, ...),直接抛 Invalid value used as weak map key。
  3. 用 ctx.waterfall 手动派发 agent/created —— DSH 实际是经 AgentService.announce()
    以 ctx.serial 在 agent 的 scope carrier 上派发;手动派发会在挂了 scope 插件的 profile 上
    假报 "0 injected",而真实产品路径注入正常。改为走真实的 ctx.agents.register()。
  4. 立刻读注入计数 —— 规则注入惰性解析消息构造器,需要等微任务落地。

并加了失败归因:deny 脚本现在无条件写 trace,于是"命令根本没跑"(环境限制,例如
沙箱受限执行器 + 本机无沙箱后端)与"跑了但裁决被忽略"(插件 bug)被区分开。

本机实测:真实 dsh-base profile 在 DSH_PERMISSION_MODE=danger-full-access 下
verify-installed: PASS;非危险模式下给出带归因的失败,而不是误导性的 allow。
新增 test/verify-scripts.test.js(5 例)把这些不变量钉住。

v0.4.0 — 自建 Copilot 桥 + 真实文件监听

Choose a tag to compare

@denceee denceee released this 18 Oct 03:53

DSH 没有官方 Copilot 桥 —— 这个版本自己造了一条,并补齐了此前只能近似的 seam。

自建 Copilot 桥(新)

与官方桥同一契约,可像官方桥一样挂载:

ctx.plugin(copilotBridge, { configPath: './hooks.json' })
  • 导出 name / inject / Config / apply,与 dsh-hooks-claude-code 一致
  • 复用 @deepseek-ai/dsh-hook-protocol 做匹配、执行、解码,不重造协议
  • 写耐久审计事件 hook/invoked / hook/result,Copilot hook 与 Claude/Codex 一样可审计
  • 解析 Copilot 自己的配置信封 {version:1, hooks:{...}} 与 bash/powershell/command/exec 字段
  • 自己实现 Copilot 方言:顶层 permissionDecision 解码、锚定正则 matcher、8 次续跑守卫

Copilot 的 10 个事件因此从「内联翻译」改为「走桥」。

真实文件监听(消除 FileChanged 的损失)

ctx.fs.watch 武装真正的文件系统监听 —— 外部编辑器改文件也会触发,这是「工具调用后近似」永远做不到的。测试用测试进程自己写文件来证明这一点。

新增 5 个真实 seam(共 25 个翻译点)

seam 效果
fs/watch 真实文件监听
user-questions/request Elicitation 真实拦截(可回答结构化问题)
command/run 拿到真实命令名与参数
agent/instructions-loaded 真实指令文件发现
agent/inbox/inserted 真实消息到达

造桥过程中暴露并修复的 6 个真实缺陷

  1. 桥内异步 mount 让监听器注册落在 inactive fiber(INACTIVE_EFFECT)→ 所有监听器静默失效
  2. 桥未解码顶层 permissionDecision → 每个 Copilot deny 都会被当作放行
  3. mergeHookOutputs 把 context 合并成数组,注入被判非字符串而丢失
  4. mergeHookOutputs 把 decision:"block" 归一为 deny → 续跑判断永不命中
  5. 桥用 ctx.agents 属性访问未声明的 inject → Cordis 抛错
  6. 桥漏了 Copilot 的 8 次 runaway guard

测试不再不稳定

「固定 sleep 后读文件」是竞态:文件已创建但内容未写完,高负载下必然失败。
已全部改为轮询可观测结果(含 parseable 判定)—— 修复前 15 轮有 1~2 轮失败,现在 10 轮 0 失败。

验证

npm test           # 115 tests passing
npm run check-surface   # OK
npm run verify-live     # PASS

事件总数仍为 112,0 拒绝,0 个 DIRECT:每条适配仍在矩阵里逐项列出损失。

v0.3.1 — 用精确 seam 减少适配损失

Choose a tag to compare

@denceee denceee released this 18 Oct 03:02

事件数保持 112,但把能精确化的近似映射换成了真实 seam —— 这一步只减少损失,不增加数量。

用精确 seam 替换的近似

事件 原来 现在
FileChanged(claude / workbuddy) 任何可能改文件的工具调用后触发 workspace/changes + workspaceChanges.summary(),拿到该 turn 真实的变更文件列表(paths / total / added / deleted)
file.edited / file.watcher.updated / session.diff(opencode) 同上 同上
InstructionsLoaded(claude / workbuddy) session/created 近似,文件列表恒为 null 调用 dsh-agent-instructions 导出的 discoverBaselineInstructionFiles,报告真实发现的指令文件
message.updated 等 4 个(opencode) 整个 session 事件流近似 agent/inbox/inserted,携带真实 UserMessage(id + 文本)

新增 3 个原生翻译点(共 22 个)

  • workspace/changes — 真实变更文件摘要
  • agent/instructions-loaded — 真实指令文件发现
  • agent/inbox/inserted — 真实消息到达

同时修复一个真实接线 bug(出现过两次)

workspace/changes 与 agent/instructions-loaded 曾只加了 service 分支、却没加入 NATIVE_TRANSLATIONS,导致这些 point 永远解析不到(vendor 表找不到映射,注册会失败)。

现在有两个双向守卫测试:每个已声明 point 必须有 service 分支;每个 service 分支必须对应已声明的 point;且每个 native-translate 事件的 point 必须存在。

确认无法精确化的(保持近似并如实标注)

  • LSP:DSH 既无 lsp 包、也无 lsp 事件
  • PostToolBatch:工具库没有批次 seam
  • worktree / TUI / 通知 / 服务器连接等 DSH 本就没有的生命周期

验证

npm test           # 102 tests passing
npm run check-surface   # OK
npm run verify-live     # PASS

v0.3.0 — 厂商文档事件全覆盖(112 个事件)

Choose a tag to compare

@denceee denceee released this 18 Oct 02:41

逐一对照 4 家 vendor 的官方文档做差集,补上此前会抛 UNKNOWN_EVENT 的事件:85 → 112 个。

总数

Vendor 事件 变化
claude 33 +1(PostCompact)
codex 12 —(核对无缺口)
workbuddy 24 —
opencode 29 +24(补全事件总线)
copilot 14 +2(preCompact / userPromptTransformed)
合计 112 +27

值得一提的两处

  • Copilot userPromptTransformed 是真实改写:它能替换发给模型的内容。DSH 的 agent/pre-step 支持返回替换后的消息列表,因此这不是观察,而是真的生效。
  • OpenCode permission.asked 是真实拦截:走 DSH 的 approval/request waterfall,hook 能决定放行或拒绝。

新增 3 个原生翻译点

  • compaction/start、compaction/end:压缩前后观察(摘要取自前置的 compaction/summary 事件)
  • agent/pre-step/transform:模型可见 prompt 的真实改写

验证

npm test           # 96 tests passing
npm run check-surface   # OK
npm run verify-live     # PASS

仍然是 0 拒绝、0 个 DIRECT:112 条全部是 ADAPTED,每条在矩阵里逐项列出损失(OpenCode 事件总线观察多为近似映射)。

v0.2.0 — Copilot 适配器与 85 事件全覆盖

Choose a tag to compare

@denceee denceee released this 18 Oct 02:19

DSH 前置/基座适配插件首个功能完整版本:5 家 vendor、85 个 hook 事件全部可执行。

支持矩阵

Vendor 事件 官方桥 本插件翻译 rules
claude 32 7 25 CARRY
codex 12 5 7 CARRY
workbuddy 24 5 19 CARRY
opencode 5 — 5 CARRY
copilot 12 — 12 CARRY

亮点

  • GitHub Copilot:DSH 无官方 Copilot 桥,12 个事件全部由本插件翻译。Copilot 把 deny 写在顶层 permissionDecision,而 DSH 协议只读 hookSpecificOutput —— 直接复用会让每一个 deny 被当成「没有决定」而放行。本插件自带解析层修正这一点。
  • 真拦截而非旁观:preToolUse 的 deny 真的拦工具;agentStop 的 decision:"block" 真的让 turn 继续(含 8 次 runaway guard);approval/request 上的 PermissionRequest 真的决定放行/拒绝;subagentStart 的上下文真的注入子 agent。
  • 损失逐项列出:85 条全部是 ADAPTED,没有一条声称 DIRECT。近似映射(文件变更、worktree、通知类)在矩阵每一行最后一列写明。

安装

dsh plugin --profile <profile> add github:denceee/dsh-compat-adapter

验证

npm test           # 87 tests passing
npm run check-surface   # OK
npm run verify-live     # PASS(真实启动 profile)

注意:全局覆盖不等于语义等价。OpenCode 的 TS 回调只映射「名字」不携带「体」;WorkBuddy 桌面端无公开 hook API。细节见 README 的「已知限制」。