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

钩子审查台 matata2017/dsh-codex-hooks

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

审查并批准钩子脚本,按轮查看运行与拦截统计

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

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

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

状态速览

判定依据:实装验证 · 静态安装检查 · 自动扫描 · 仓库维护状态
信任档位:仅索引
是什么
dsh 原生插件 · chat
装得上吗
本站尚未做安装检查
安全吗
本站尚未对该插件做风险分级
暂未覆盖,不等同于无风险
还在维护吗
活跃:最近一次提交在 5 天前
档位由哪些信号合成

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

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

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

可执行外部命令读写/删除本地文件
查看扫描证据(共 25 处,展示前 22 条)
  • 读取本地文件
    lib/core.js:407
    if (!path || !existsSync(path)) return { version: STATE_FILE_VERSION, states: {} }
  • 读取本地文件
    lib/core.js:408
    return parseStateFile(readFileSync(path, 'utf8'))
  • 写入本地文件
    lib/core.js:416
    mkdirSync(dirname(path), { recursive: true })
  • 写入本地文件
    lib/core.js:423
    writeFileSync(temporary, `${JSON.stringify(payload, null, 2)}\n`, 'utf8')
  • 写入本地文件
    lib/core.js:424
    renameSync(temporary, path)
  • 读取本地文件
    lib/core.js:427
    if (existsSync(temporary)) rmSync(temporary, { force: true })
  • 删除本地文件
    lib/core.js:427
    if (existsSync(temporary)) rmSync(temporary, { force: true })
  • 读取本地文件
    lib/core.js:589
    const text = readFileSync(path, 'utf8')
  • 读取本地文件
    lib/core.js:598
    if (!existsSync(modulesDir)) return []
  • 读取本地文件
    lib/core.js:602
    if (existsSync(candidate)) found.push(candidate)
  • 执行外部命令固定命令
    lib/events.js:135
    spawn('taskkill', ['/pid', String(child.pid), '/T', '/F'], { windowsHide: true }).unref()
  • 写入本地文件
    lib/events.js:187
    writeFileSync(inPath, input, 'utf8')
  • 删除本地文件递归
    lib/events.js:197
    rmSync(dir, { recursive: true, force: true })
  • 执行外部命令来自配置/变量
    lib/events.js:208
    child = spawn(command, {
  • 读取本地文件
    lib/events.js:247
    stdout = readFileSync(outPath, 'utf8')
  • 读取本地文件
    lib/events.js:252
    stderr = readFileSync(errPath, 'utf8')
  • 删除本地文件递归
    lib/events.js:257
    rmSync(dir, { recursive: true, force: true })
  • 写入本地文件
    lib/events.js:266
    appendFileSync(errPath, String(error?.message ?? error), 'utf8')
  • 写入本地文件
    lib/events.js:276
    appendFileSync(errPath, note, 'utf8')
  • 执行外部命令来自配置/变量
    lib/events.js:312
    child = spawn(command, {
  • 写入本地文件
    lib/events.js:422
    mkdirSync(dir, { recursive: true })
  • 写入本地文件
    lib/events.js:425
    writeFileSync(file, content, 'utf8')
扫描于 2026/11/3(0 天前) · 范围 入口闭包 + 发布文件清单 · 来源 GitHub 仓库

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

给这个插件打分还没有人投票↓
用户评分
还没有人投票,来当第一个
展开完整介绍(128 字)↓

为 DeepSeek Harness 提供 Codex 风格的钩子管理:从配置、插件和项目读取 hooks.json,每个钩子绑定一个 sha256 指纹,你批准后才会运行;输入框里有审核对话框,还有 Hooks 设置页、/hooks 命令和每轮运行统计。

README

由 DeepSeek 最新模型翻译生成
dsh-codex-hooks 把 CODEX 的钩子管理方式移植到 DeepSeek Harness(dsh)。 CODEX 里每条钩子都有:一次审查、钉在指纹上的一次批准、设置页、/hooks 浏览器,还有运行统计。dsh 一样都没有——它只暴露拦截 seam,其余全空。这个插件把这一整套管理搬过来,于是 dsh 上的钩子也能按 CODEX 那套审查、批准、单独关掉、看运行情况。 配置文件是 dsh 自己的(hooks.json + dsh 事件名)——移植的是围绕钩子的那套行为,不是 CODEX 的文件格式。 English: README.md 截图 审查就发生在干活的地方:输入框工具栏一个钩子图标,有待审核时右上角一个红点: 输入框工具栏的钩子图标,待审核时红点 点开就是审查弹窗:一条钩子一行,带新建徽标,chevron 展开细节,底部以后再说 / 全部允许 / 允许所选项: 审查钩子弹窗 其余都在 设置 → Hooks 里管:按来源分组,每条带信任状态、启用开关、信任/撤销和一次性的测试: 设置页里的钩子列表、信任状态与操作 单次运行的明细在消息操作行后面。钩子统计弹窗只读一轮、标明是哪一轮,列出这一轮的执行,底部是本会话累计——没有轮次下拉,它只回答你点开它的那条消息。
展开完整文档(README 剩余 1 节)
dsh-codex-hooks

把 CODEX 的钩子管理方式移植到 DeepSeek Harness(dsh)。

CODEX 里每条钩子都有:一次审查、钉在指纹上的一次批准、设置页、/hooks 浏览器,还有运行统计。dsh 一样都没有——它只暴露拦截 seam,其余全空。这个插件把这一整套管理搬过来,于是 dsh 上的钩子也能按 CODEX 那套审查、批准、单独关掉、看运行情况。

配置文件是 dsh 自己的(hooks.json + dsh 事件名)——移植的是围绕钩子的那套行为,不是 CODEX 的文件格式。

English: README.md

截图

审查就发生在干活的地方:输入框工具栏一个钩子图标,有待审核时右上角一个红点:

输入框工具栏的钩子图标,待审核时红点

点开就是审查弹窗:一条钩子一行,带新建徽标,chevron 展开细节,底部以后再说 / 全部允许 / 允许所选项:

审查钩子弹窗

其余都在 设置 → Hooks 里管:按来源分组,每条带信任状态、启用开关、信任/撤销和一次性的测试:

设置页里的钩子列表、信任状态与操作

单次运行的明细在消息操作行后面。钩子统计弹窗只读一轮、标明是哪一轮,列出这一轮的执行,底部是本会话累计——没有轮次下拉,它只回答你点开它的那条消息。每次运行都归属于触发它的那一轮,和 CODEX 把运行绑在 turn id 上一样:匹配是精确的,日志里没有的那一轮——包括宿主重启前编号的那些——就显示 0 并给出提示,绝不拿别的轮的数字顶替。轮次只在当前会话里解析,别的会话的同名轮次不会顶替。轮次由你点的那条消息决定:收尾的那条消息精确对应它所属的那一轮,正在进行中的那一轮的消息就回答那一轮:

钩子统计弹窗:运行、拦截、失败与这一轮的执行历史

截图取自本地运行的 dsh,钩子就是 ~/.dsh/hooks.json 里那两条 echo-hook —— 和本仓库示例用的是同一份配置。

兼容性

| 插件版本 | 验证过的 dsh |
| 0.5.x | dsh 0.1.0-rc.6(开发与自测宿主,web 与 desktop) |

更新的 dsh 版本没有验证过:插件读的是 dsh 的插槽、命令与远程方法契约,宿主改掉其中任何一个,插件在跟进之前就会坏。

客户端这一半绑在四个 dsh 客户端包上 —— @deepseek-ai/dsh-client-locale、@deepseek-ai/dsh-client-ui-settings、@deepseek-ai/dsh-client-ui-commands、@deepseek-ai/dsh-client-ui-chat。前三个随 profile 一起装;dsh-client-ui-chat 提供 conversation.chat.turnTail 插槽,「点哪条消息就看哪一轮」靠的就是它,有些安装里它只存在于应用自带的 node_modules。如果消息上的钩子按钮不显示轮次,缺的就是这个包。

它到底做了什么

- 发现三个来源的 hooks.json,界面上分组显示:
- 来自配置 —— $DSH_HOME/hooks.json(默认 ~/.dsh/hooks.json)。
- 来自插件 —— 当前 profile 里自带 hooks.json 的每个包。
- 来自项目配置文件 —— 本会话碰过的 workspace 里的 <workspace>/.dsh/hooks.json(最多记 32 个)。
- 指纹:把钩子定义规范化成 JSON,再对它 UTF-8 字节做 sha256:。信任就钉在这个指纹上,所以改掉一条钩子的命令,它的信任会自动失效,不会悄悄跑新代码。
- 逐个审查信任:新钩子处于待审核;你在设置页批准当前指纹,状态存在 $DSH_HOME/hooks.state.json,同时每条钩子有独立的启用开关。
- 执行:只有既启用又可信的 command 处理器才会跑,带自己的超时、cwd、环境变量,以及 command/commandWindows 平台拆分。同一事件的同步钩子会并行启动,与 Codex 一致;结果和注入上下文仍按配置顺序合并。approval/request 钩子可以返回 {"decision":"allow"} 直接放行待审批的工具调用,或返回 deny;任何一条钩子 deny 都压过 allow。
- 注入上下文:处理器返回的 additionalContext 会追加到模型输入,适用于 agent/pre-step、tools/pre-execute、tools/post-execute、agent/created(默认上限 2500 字符)。
- 匹配:工具类 seam(tools/pre-execute、tools/post-execute、approval/request)支持 matcher:、精确名、A|B 多选或正则。

事件

| 事件 | 何时触发 | 可拦截 |
| agent/pre-step | 用户提交提示、步骤开始之前 | 可以 |
| agent/request | 模型请求发出之前 | 不可以 |
| tools/pre-execute | 工具调用执行之前 | 可以 |
| tools/post-execute | 工具调用结束之后 | 可以 |
| approval/request | 工具调用向用户申请权限之前 | 可以 |
| agent/created | 会话开始 | 不可以 |
| agent/turn-stopping | 本轮响应结束之前 | 不可以 |
| session/disposed | 会话销毁 | 不可以 |

默认超时 600 秒;session/disposed 例外(默认 1 秒,最多 3 秒),免得退出时卡住。

审查、运行记录与 /hooks

- 输入框工具栏的钩子图标 —— 输入框工具栏(权限/专家控件旁边)有一个钩子图标,待审核时右上角只有一个红点、不带数字(数字一被别处信任就会过期);点它打开审查钩子弹窗:每条钩子一行,带复选框、名称、新建徽标和 chevron,展开是来源 / Hook 类型 / 命令 / 超时;底部提示「你可以稍后在 设置 → 钩子 里更改此选项」(纯文字,dsh 没有给插件打开设置页的接口,所以不假装能跳);三个按钮是以后再说 / 全部允许 / 允许所选项。点工具图标就打开,不自动弹。批准即把当前指纹钉进 $DSH_HOME/hooks.state.json;其余情况到 设置 → Hooks 里逐个处理。
- /hooks 打开钩子浏览器 —— 第一页按事件列出 生效/已安装 计数,待审核的事件行尾带 !;第二页列出该事件的处理器,带信任状态、启用开关和信任/撤销按钮。它是标准的 dsh 斜杠命令(宿主组合了 commands 服务时注册),不会发给模型。
- 消息操作行的钩子图标 → 钩子统计弹窗 —— 助手消息的操作行有一个钩子图标,点开是统计弹窗。与 CODEX 一致,每次运行都归属触发它的那一轮,所以弹窗一次只看一轮(运行 / 拦截 / 失败,慢钩子运行中另有 运行中 计数),并标明是哪一轮,底部是本会话累计。没有轮次切换器:弹窗就回答你打开它的那条消息。运行历史列表只列这一轮的运行(形如 Completed agent/pre-step User);弹窗打开期间每 1.5 秒刷新一次。钩子输出不会打印进对话,模型只会看到处理器的 additionalContext。运行记录只放在内存里,不落盘——重载即清空,与 CODEX 相同(它的 HookStarted/HookCompleted 通知同样是瞬态的)。会话级视角看 /hooks。点某条消息就打开它所在的那一轮:DSH 给动作行插槽的只有 messageId,所以另在 conversation.chat.turnTail 上挂了一个不绘制的伴随渲染——它拿得到完整的 TurnLocation,且比同一轮的动作行先渲染——记下每条消息属于哪一轮,弹窗据此打开;认不出的消息回落到当前轮。与 CODEX 有一处刻意的差别:agent/pre-step 在 agent 循环的每一步之前触发({ turn, step }),不是每提交一次提示触发一次,所以一条 agent/pre-step 钩子在一轮里会随每次模型调用各跑一次——这就是一轮里能看到多次运行的原因;只想每轮跑一次的钩子设 firstStepOnly: true。
- 试跑 —— 设置页的测试*会用样例输入把一条钩子跑一次,报告 通过/拦截/失败 和耗时;未批准的钩子拒绝试跑。
- 浮层:所有面板都用 portal 渲到 document.body 上并固定定位,不会被输入框或消息列裁掉。

自动放行一次工具调用

approval/request 钩子可以自己决定待审批的那次调用:

{
"hooks": {
"approval/request": [{ "command": "node examples/approval-allow.mjs", "timeout": 10 }]
}
}

钩子打印 {"decision":"allow"} 就是放行这一次;打印 {"decision":"deny","reason":"…"} 是拒绝;什么都不打印就交回正常的审批提示。任一钩子 deny 压过别的钩子的 allow。
examples/approval-allow.mjs 只放行 APPROVAL_ALLOW_TOOL 指定的那个工具——把什么都放行的钩子,等于把你装钩子本来想收紧的那道提示给拆了。

安装

需要 dsh 0.1.0-rc.6 或更新版本,Node 20+。

从 GitHub
dsh plugin --profile desktop add github:matata2017/dsh-codex-hooks

或者本地开发目录,本项目就是这么用的
dsh plugin --profile desktop add /path/to/dsh-codex-hooks

装完重启 dsh 的 web/desktop 宿主,然后打开 设置 → Hooks。

配置

~/.dsh/hooks.json:

{
"version": 1,
"description": "my hooks",
"hooks": {
"agent/created": [
{
"command": "node ./examples/echo-hook.mjs agent/created",
"commandWindows": "node.exe ./examples/echo-hook.mjs agent/created",
"timeout": 15,
"statusMessage": "echo-hook: session started"
}
],
"tools/pre-execute": [
{
"matcher": "Bash",
"command": "node ./examples/echo-hook.mjs"
}
]
}
}

一条钩子一个对象:command(或 type: "mcp_tool" 加 server + tool),可选 matcher、timeout、statusMessage、additionalContextLimit、async、firstStepOnly。

firstStepOnly(仅 agent/pre-step):agent/pre-step 在一轮的每一步之前都会触发,设为 true 后这条钩子每轮只在第一步(带用户消息的那一步)运行,后续步骤连进程都不启动,统计弹窗里一轮也只记一次。适合只关心用户这条消息的钩子(记忆召回、提示改写等)。该字段计入信任哈希,加上之后要重新信任一次;不写或写 false 时哈希与以前相同。

处理器类型:只有 command 会被执行。mcp_tool、prompt、agent 可以解析、可以审查,但暂不派发——它们显示为“已安装”而不是“生效”,宁可说清楚,也不要让一条钩子静默地什么都不做。

验证状态

- node test/run-tests.mjs → 99 passed, 0 failed, 0 skipped。
- node selftest/host-e2e.mjs → 对着真实 profile 跑 20 passed, 0 failed。
- agent/pre-step 在真实 dsh 会话里跑通(前提是钩子已被信任):示例钩子每跑一步打印一行 echo-hook received event=…(它在 agent 循环的每一步之前触发,所以一次提示可能打印多行)。未信任的钩子不会执行,必须先在审查弹窗或「设置 → 钩子」里批准。

这里做不到的事

下面几条是 dsh 的边界,不是我们没写:需要一个宿主没开放的接缝。CODEX 有这些,dsh 没有,所以移植到这里为止。

- 上下文只能以 user 角色注入:agent/pre-step 收的是 UserMessage[],也没有对外的「追加 developer 消息」接口,所以 additionalContext 拿不到 developer 消息那种分量。
- 改不了工具入参:tools/pre-execute 只能 allow / deny / ask / cancel,dsh 明确排除入参改写(参数已经记日志并展示给用户)。
- 压缩、中断、模型请求这三类事件没有接缝,最接近「压缩后」的只有 agent/created 的 source: "compact"。
- mcp_tool、prompt、agent 处理器可以审查但不会执行,所以它们永远不会显示为生效。

安全

钩子以 dsh 进程的权限执行真实命令。所以信任钉在每条钩子的 sha256 指纹上:批准一条钩子=批准这一行具体的命令,任何改动都要重新批准。只启用你读过的钩子。

批准是稳的。信任状态先写临时文件再改名覆盖正式文件,写到一半被打断也不会留下半个文件让下一次读取失败;而那个会落到「刚刚替换掉它的按钮」上的点击会被忽略——刚给的信任不会在一秒后自己撤销。

License

MIT
预览分享卡片长什么样 ↓matata2017/dsh-codex-hooks
分享 · DeepSeek Harness Hub
matata2017/dsh-codex-hooks

审查并批准钩子脚本,按轮查看运行与拦截统计

这是你的仓库?认领条目

回到顶部