dsh-yolo-mode 0.4.1 → 0.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -1,62 +1,103 @@
1
- # Changelog
2
-
3
- 本项目遵循 [Semantic Versioning](https://semver.org/)。
4
-
5
- ## [0.4.0] - 2026-08-14
6
-
7
- ### 新增
8
-
9
- - **模型下拉选择**:设置页的 judge `provider` / `model` 改为下拉框,选项来自 Harness 模型配置(`connection.api.llm`),切换 provider 联动清空 model。
10
- - **每预设默认裁判提示词**:`defaultJudgePromptFor(preset)` 为六预设提供默认裁判提示词(strict 最保守、balanced 通用、permissive 宽松、custom 按层级表),`judge.systemPrompt` 留空时自动选用。
11
- - **预设预填充**:切换预设时自动把该预设的默认提示词与层级表填入 `systemPrompt` / `levels`(选 `custom` 留空);`statusView` 返回 `presetDefaults`。
12
-
13
- ## [0.3.0] - 2026-08-14
14
-
15
- ### 变更(UI 重做,对齐 dsh-plugin-subagent-director 参考架构)
16
-
17
- - **独立桥接条目**:新增 `./bridge` 入口(`lib/bridge-entry.js`,`inject: ['webServer','settings']`),自发布 `/yolo-mode` 前缀路由。修复 v0.2.0 根因——宿主 `webServer` 只能经 `inject` 取得,树外插件 `ctx.get('webServer')` 永远拿不到(参考项目已实测)。
18
- - **RPC 信封桥**:`/yolo-mode` 上实现 `settingsView` / `settingsMutate` / `statusView` 三端点,语义镜像 connection RPC 通道(loopback 围栏、乐观 revision 冲突、redacted 视图、路径 op)。
19
- - **settings 规范布线**:改用 `installSettingsSection`(`@deepseek-ai/dsh-settings`),行 config 作为 `base` 层;`effectiveConfig() = normalizeConfig(resolved)`;移除手写 mergeConfig。
20
- - **客户端 rolldown 构建**:`src/client/*.js` → `scripts/build-client.mjs`(rolldown,external react/@deepseek-ai)→ `lib/client/index.js`;客户端 `inject: ['slots','locale','connection','remote']`,locale 双语字典、`bindSnapshotSelector` 快照 store、`connection.rpc.call` 走桥、revision 冲突机。
21
- - **主条目 inject**:`export const inject = ['llm','settings']`(命名导出插件,非 default 函数)。
22
-
23
- ## [0.2.0] - 2026-08-14
24
-
25
- ### 新增
26
-
27
- - **客户端 UI(双面包)**:`dsh-yolo-mode` 声明 `dsh.client` 并导出 `lib/client.js`(手写 ModuleLoader 工厂,零构建),提供三处界面:
28
- - 输入栏左侧状态 chip(`conversation.input.left`,显示 `YOLO <preset>`,点击开关弹窗);
29
- - 全局面板(`shell.overlay`):运行统计(总审批/放行/拒绝/转人工)+ 最近 20 条决策表 + 刷新;
30
- - 设置页(`settings.section`,'YOLO 审批'):预设/生效模式/judge 参数/levels JSON 的在线编辑与保存。
31
- - **HTTP API**:`GET /plugins/yolo-mode/status`(状态与统计)、`POST /plugins/yolo-mode/config`(配置校验后持久化),由宿主 webServer 路由提供。
32
- - **settings 集成**:settings 命名空间 `yolo-mode`(自由 JSON 分区,落盘 settings.yaml);`effectiveConfig()` 每次裁决将插件行 config 与 settings 分区合并规范化,配置改动即时生效(无需重启)。
33
- - **内存统计**:每次裁决累计 total/allowed/rejected/delegated 与最近 20 条决策环形缓冲。
34
- - **judge 实例缓存**:按 judge 配置键缓存裁判实例,配置变化自动重建。
35
-
36
- ### 变更
37
-
38
- - package.json:version 0.2.0;exports 增加 `./client`;peerDependencies 增加 `react`、`@deepseek-ai/dsh-client-runtime`、`@deepseek-ai/dsh-client-ui-slots`、`@deepseek-ai/schemastery`。
39
-
40
- ### 已知限制
41
-
42
- - 已挂载插件行的**模块代码**更新需要重启 DSH 才能重新导入(patch 热重载只覆盖新行挂载与 config 变更);v0.1.0 → v0.2.0 升级后请重启 DSH 并刷新浏览器。
43
-
44
- ## [0.1.0] - 2026-08-14
45
-
46
- ### 新增
47
-
48
- - **宿主侧审批应答插件**:作为 `approval/request` seam 的应答者,在会话处于可写沙箱模式且审批策略为 `ask` 时,用 LLM 自动裁决沙箱升权申请。
49
- - **抢占注册**:以 `ctx.on('approval/request', handler, { prepend: true })` 抢占监听列表头,抢在人工应答者之前裁决。
50
- - **前置门槛**:按 `ctx.sandboxPolicy.resolve({session})` 校验当前有效模式,仅处理位于 `modes` 列表(默认 `['workspace-write']`)内的会话。
51
- - **内置预设**:`off` / `strict` / `balanced`(默认)/ `permissive` / `yolo` / `custom`,各含 `workspace-write` 与 `danger-full-access` 的处置策略与失败 / 不确定回退。
52
- - **自定义层级**:`levels` 支持目标模式、`error` / `unsure` 回退、以及逐工具 `tools.<toolName>` 覆盖,`custom` 预设全字段开放。
53
- - **LLM 裁判封装**:基于 `@deepseek-ai/dsh-llm`(`BlockAssembler` / `createUserMessage` / `llm.stream`)与 `@deepseek-ai/dsh-timeout`(`deadline`)实现,含并发信号量上限与超时。
54
- - **裁决策略映射**:`allow → allowed-once`、`deny → rejected`、`delegate → next()`、`judge → 裁判`;失败 / 不确定按预设 fail-closed 回退。
55
- - **JSONL 审计**:`ctx.logger` + 文件(默认 `%TEMP%/dsh-yolo/judge.log`)记录每次裁决的明细。
56
- - **纯函数策略层** `lib/policy.js`(零依赖,可单测)与单元测试 `test/policy.test.mjs`、`test/judge.test.mjs`。
57
-
58
- ### 安全
59
-
60
- - fail-closed:任何错误、超时、非法输出、工具块、并发溢出路径均不放行。
61
- - 裁判 prompt 与 agent 上下文隔离,防审批回环自批准。
62
- - 默认预设为 `balanced`(不确定 → 转人工),不默认启用 `permissive` / `yolo`。
1
+ # Changelog
2
+
3
+ 本项目遵循 [Semantic Versioning](https://semver.org/)。
4
+
5
+ ## [0.5.0] - 2026-09-04
6
+
7
+ ### 兼容:DSH 0.1.2-alpha.4
8
+
9
+ - **peerDependencies 升级**:`dsh-llm` / `dsh-timeout` / `dsh-settings` /
10
+ `dsh-client-connection` / `dsh-client-ui-slots` / `dsh-client-locale` →
11
+ `^0.1.2-alpha.4`;`dsh-client-runtime` / `dsh-host-apiproxy` →
12
+ `^0.1.1-rc.2`(alpha 期未重发,最高仅到 `0.1.1-rc.2`);`@deepseek-ai/schemastery`
13
+ 保持 `^3.18.1`。旧 `^0.1.0-rc.6` 预发布区间按 semver 预发布元组规则不会匹配
14
+ `0.1.2-alpha.4`,会把插件钉死在 rc.8。
15
+ - **settings 类服务迁移(lib/settings.js + lib/remote.js)**:alpha.4 删除
16
+ `installSettingsSection` / `settingsNamespace` 函数导出,`ctx.settings` 变为
17
+ `SettingsProvider` 类服务(默认导出)。命名空间改为纯 kebab-case 字符串字面量
18
+ `yolo-mode`(原品牌函数 `settingsNamespace('yolo-mode')` 的产物即同字符串);
19
+ 分区接线改为 `settings.installSection(ctx, ns, schema, entry, hooks)`,
20
+ 钩子(`setSource` / `onChange` / `validate`)语义不变。`SettingsConflictError`、
21
+ `settings.mutate` / `describe` / `writable` 均保留,桥接层仅去除品牌调用。
22
+ - **真实-Cordis 探针**:新增 `test/probe.test.mjs`,在真实
23
+ `@deepseek-ai/cordis` Context 上挂载插件本体(内存 `SettingsProvider` +
24
+ 假 llm + sandboxPolicy stub),覆盖:激活与命名空间注册、取消、透明委托
25
+ (非升权 / 沙箱模式门 / includeSubagents)、`yolo` 预设确定性放行、裁判
26
+ allow(真实 dsh-llm 组装)、settings 用户层更新即时生效。
27
+ - **devDependencies**:新增 `@deepseek-ai/cordis ^4.0.2`、`dsh-llm` /
28
+ `dsh-timeout` / `dsh-settings`(alpha.4)、`@deepseek-ai/schemastery`,
29
+ 供 `npm test`(`node --test`)直接运行。
30
+
31
+ ## [0.5.0] - 2026-08-28
32
+
33
+ ### 新增
34
+
35
+ - **决策表翻页**:状态弹窗的最近决策表改为分页展示(每页 5 条,倒序),新增「上一页 / 下一页」+ 页码指示(多页时显示);刷新导致列表长度跨页边界时自动回到第一页。
36
+ - **打开审计日志**:弹窗新增「打开日志」按钮,客户端经新 RPC 端点 `openLogFile` 请求宿主,用 OS 默认应用打开审计 JSONL(macOS `open` / Windows `cmd start` / Linux `xdg-open`);文件尚不存在返回 `log-not-found`,UI 显示友好提示(含解析出的日志路径)。
37
+ - **statusView 携带 auditFile**:生效审计日志路径随 statusView 返回(与主条目 `audit()` 同一解析规则),弹窗展示路径(按钮 title + 说明行)。
38
+ - **lib/audit.js 新模块**:审计日志路径解析(`resolveAuditFile` / `defaultAuditFile` / `auditFileExists`)与 OS 打开(`openFileWithDefaultApp` / `openerCommandFor`)抽为独立宿主模块;主条目 `audit()` 与桥接 `openLogFile` 端点共用同一解析规则,杜绝路径不一致。
39
+
40
+ ### 测试
41
+
42
+ - 新增 `test/audit.test.mjs`(路径解析 / 存在性 / 三平台打开命令)与 `test/state.test.mjs`(statusView 载荷装配含 auditFile)。
43
+ - `test/remote-bridge.test.mjs` 增 `openLogFile` 端点用例:文件存在 → 注入 openFile 收到解析路径;不存在 → `log-not-found` 且不调用 openFile;端点常量。
44
+ - `test/client.test.mjs` 增 `YoloStore.openLogFile` 转发用例与 Popup 分页渲染用例(20 条 → 5 条/页、翻页器、打开日志按钮与成功提示)。
45
+
46
+ ## [0.4.0] - 2026-08-14
47
+
48
+ ### 新增
49
+
50
+ - **模型下拉选择**:设置页的 judge `provider` / `model` 改为下拉框,选项来自 Harness 模型配置(`connection.api.llm`),切换 provider 联动清空 model。
51
+ - **每预设默认裁判提示词**:`defaultJudgePromptFor(preset)` 为六预设提供默认裁判提示词(strict 最保守、balanced 通用、permissive 宽松、custom 按层级表),`judge.systemPrompt` 留空时自动选用。
52
+ - **预设预填充**:切换预设时自动把该预设的默认提示词与层级表填入 `systemPrompt` / `levels`(选 `custom` 留空);`statusView` 返回 `presetDefaults`。
53
+
54
+ ## [0.3.0] - 2026-08-14
55
+
56
+ ### 变更(UI 重做,对齐 dsh-plugin-subagent-director 参考架构)
57
+
58
+ - **独立桥接条目**:新增 `./bridge` 入口(`lib/bridge-entry.js`,`inject: ['webServer','settings']`),自发布 `/yolo-mode` 前缀路由。修复 v0.2.0 根因——宿主 `webServer` 只能经 `inject` 取得,树外插件 `ctx.get('webServer')` 永远拿不到(参考项目已实测)。
59
+ - **RPC 信封桥**:`/yolo-mode` 上实现 `settingsView` / `settingsMutate` / `statusView` 三端点,语义镜像 connection RPC 通道(loopback 围栏、乐观 revision 冲突、redacted 视图、路径 op)。
60
+ - **settings 规范布线**:改用 `installSettingsSection`(`@deepseek-ai/dsh-settings`),行 config 作为 `base` 层;`effectiveConfig() = normalizeConfig(resolved)`;移除手写 mergeConfig。
61
+ - **客户端 rolldown 构建**:`src/client/*.js` → `scripts/build-client.mjs`(rolldown,external react/@deepseek-ai)→ `lib/client/index.js`;客户端 `inject: ['slots','locale','connection','remote']`,locale 双语字典、`bindSnapshotSelector` 快照 store、`connection.rpc.call` 走桥、revision 冲突机。
62
+ - **主条目 inject**:`export const inject = ['llm','settings']`(命名导出插件,非 default 函数)。
63
+
64
+ ## [0.2.0] - 2026-08-14
65
+
66
+ ### 新增
67
+
68
+ - **客户端 UI(双面包)**:`dsh-yolo-mode` 声明 `dsh.client` 并导出 `lib/client.js`(手写 ModuleLoader 工厂,零构建),提供三处界面:
69
+ - 输入栏左侧状态 chip(`conversation.input.left`,显示 `YOLO <preset>`,点击开关弹窗);
70
+ - 全局面板(`shell.overlay`):运行统计(总审批/放行/拒绝/转人工)+ 最近 20 条决策表 + 刷新;
71
+ - 设置页(`settings.section`,'YOLO 审批'):预设/生效模式/judge 参数/levels JSON 的在线编辑与保存。
72
+ - **HTTP API**:`GET /plugins/yolo-mode/status`(状态与统计)、`POST /plugins/yolo-mode/config`(配置校验后持久化),由宿主 webServer 路由提供。
73
+ - **settings 集成**:settings 命名空间 `yolo-mode`(自由 JSON 分区,落盘 settings.yaml);`effectiveConfig()` 每次裁决将插件行 config 与 settings 分区合并规范化,配置改动即时生效(无需重启)。
74
+ - **内存统计**:每次裁决累计 total/allowed/rejected/delegated 与最近 20 条决策环形缓冲。
75
+ - **judge 实例缓存**:按 judge 配置键缓存裁判实例,配置变化自动重建。
76
+
77
+ ### 变更
78
+
79
+ - package.json:version 0.2.0;exports 增加 `./client`;peerDependencies 增加 `react`、`@deepseek-ai/dsh-client-runtime`、`@deepseek-ai/dsh-client-ui-slots`、`@deepseek-ai/schemastery`。
80
+
81
+ ### 已知限制
82
+
83
+ - 已挂载插件行的**模块代码**更新需要重启 DSH 才能重新导入(patch 热重载只覆盖新行挂载与 config 变更);v0.1.0 → v0.2.0 升级后请重启 DSH 并刷新浏览器。
84
+
85
+ ## [0.1.0] - 2026-08-14
86
+
87
+ ### 新增
88
+
89
+ - **宿主侧审批应答插件**:作为 `approval/request` seam 的应答者,在会话处于可写沙箱模式且审批策略为 `ask` 时,用 LLM 自动裁决沙箱升权申请。
90
+ - **抢占注册**:以 `ctx.on('approval/request', handler, { prepend: true })` 抢占监听列表头,抢在人工应答者之前裁决。
91
+ - **前置门槛**:按 `ctx.sandboxPolicy.resolve({session})` 校验当前有效模式,仅处理位于 `modes` 列表(默认 `['workspace-write']`)内的会话。
92
+ - **内置预设**:`off` / `strict` / `balanced`(默认)/ `permissive` / `yolo` / `custom`,各含 `workspace-write` 与 `danger-full-access` 的处置策略与失败 / 不确定回退。
93
+ - **自定义层级**:`levels` 支持目标模式、`error` / `unsure` 回退、以及逐工具 `tools.<toolName>` 覆盖,`custom` 预设全字段开放。
94
+ - **LLM 裁判封装**:基于 `@deepseek-ai/dsh-llm`(`BlockAssembler` / `createUserMessage` / `llm.stream`)与 `@deepseek-ai/dsh-timeout`(`deadline`)实现,含并发信号量上限与超时。
95
+ - **裁决策略映射**:`allow → allowed-once`、`deny → rejected`、`delegate → next()`、`judge → 裁判`;失败 / 不确定按预设 fail-closed 回退。
96
+ - **JSONL 审计**:`ctx.logger` + 文件(默认 `%TEMP%/dsh-yolo/judge.log`)记录每次裁决的明细。
97
+ - **纯函数策略层** `lib/policy.js`(零依赖,可单测)与单元测试 `test/policy.test.mjs`、`test/judge.test.mjs`。
98
+
99
+ ### 安全
100
+
101
+ - fail-closed:任何错误、超时、非法输出、工具块、并发溢出路径均不放行。
102
+ - 裁判 prompt 与 agent 上下文隔离,防审批回环自批准。
103
+ - 默认预设为 `balanced`(不确定 → 转人工),不默认启用 `permissive` / `yolo`。
package/LICENSE CHANGED
@@ -1,21 +1,21 @@
1
- MIT License
2
-
3
- Copyright (c) 2026 dsh-yolo-mode contributors
4
-
5
- Permission is hereby granted, free of charge, to any person obtaining a copy
6
- of this software and associated documentation files (the "Software"), to deal
7
- in the Software without restriction, including without limitation the rights
8
- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
- copies of the Software, and to permit persons to whom the Software is
10
- furnished to do so, subject to the following conditions:
11
-
12
- The above copyright notice and this permission notice shall be included in all
13
- copies or substantial portions of the Software.
14
-
15
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
- SOFTWARE.
1
+ MIT License
2
+
3
+ Copyright (c) 2026 dsh-yolo-mode contributors
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md CHANGED
@@ -1,36 +1,40 @@
1
- # dsh-yolo-mode
2
-
3
- > DeepSeek Harness 插件:用大模型自动裁决沙箱**升权申请**(LLM-powered auto-approval)。
4
-
5
- 当会话处于可写沙箱模式、审批策略为 `ask` 时,`dsh-yolo-mode` 拦截 `escalate sandbox to ...` 升权申请,按你选择的**预设**或**自定义权限层级**由大模型裁决「放行 / 拒绝 / 转人工」。任何不确定或失败路径都不会放行(**fail-closed**)。
6
-
7
- [![npm version](https://img.shields.io/npm/v/dsh-yolo-mode)](https://www.npmjs.com/package/dsh-yolo-mode)
8
- [![license](https://img.shields.io/badge/license-MIT-blue.svg)](LICENSE)
9
-
10
- ---
11
-
12
- ## 功能特性
13
-
14
- - **LLM 自动裁决**:在 `workspace-write` 会话中,对 `danger-full-access` / `workspace-write` 升权申请调用大模型分级(`allow / deny / unsure`),确定时免去人工弹窗。
15
- - **内置预设**:`off` / `strict` / `balanced`(默认)/ `permissive` / `yolo` / `custom`,覆盖从「全部转人工」到「确定性全放行」的完整光谱。
16
- - **自定义层级**:`levels` 支持逐目标模式、逐工具(`tools.<toolName>`)的 `allow / judge / delegate / deny` 策略,及 `error` / `unsure` 回退。
17
- - **每预设默认提示词**:`judge.systemPrompt` 留空时按预设自动选用对应裁判提示词(strict 最保守、permissive 宽松、custom 按层级表)。
18
- - **图形化配置**:设置面板「YOLO 审批」页在线修改预设 / 生效模式 / 裁判模型(下拉选择)/ 层级表,保存即生效;输入栏状态 chip + 决策统计面板。
19
- - **完整审计**:每次裁决落 JSONL 日志,含工具、目标模式、当前模式、理由、决策与结果。
20
- - **fail-closed**:超时、非法输出、模型不可用、并发溢出等一切异常路径都回退为「拒绝」或「转人工」。
21
-
22
- ## 安装
23
-
24
- ### 1. 安装插件包
25
-
26
- ```bash
27
- # 从 npm
28
- dsh plugin --profile web add dsh-yolo-mode
29
-
30
- # 或从本地路径
31
- dsh plugin --profile web add <项目绝对路径>
32
- ```
33
-
1
+ # dsh-yolo-mode
2
+
3
+ > DeepSeek Harness 插件:用大模型自动裁决沙箱**升权申请**(LLM-powered auto-approval)。
4
+
5
+ 当会话处于可写沙箱模式、审批策略为 `ask` 时,`dsh-yolo-mode` 拦截 `escalate sandbox to ...` 升权申请,按你选择的**预设**或**自定义权限层级**由大模型裁决「放行 / 拒绝 / 转人工」。任何不确定或失败路径都不会放行(**fail-closed**)。
6
+
7
+ [![npm version](https://img.shields.io/npm/v/dsh-yolo-mode)](https://www.npmjs.com/package/dsh-yolo-mode)
8
+ [![license](https://img.shields.io/badge/license-MIT-blue.svg)](LICENSE)
9
+ [![DeepSeek Harness](https://img.shields.io/badge/DeepSeek%20Harness-0.1.2--alpha.4-blue)](https://github.com/deepseek-ai/deepseek-harness)
10
+ [![Awesome DSH Plugin](https://awesome-dsh-plugin.com/badge.svg)](https://awesome-dsh-plugin.com)
11
+
12
+ > **兼容性**:v0.5.0 支持 DSH **0.1.2-alpha.4+**(真实-Cordis 探针 125/125 通过;settings 已迁移至 alpha.4 的 `SettingsProvider` 类服务)。旧版 DSH(0.1.0-rc.6 / rc.8)请使用最后兼容的 npm 版本 **0.4.1**。
13
+
14
+ ---
15
+
16
+ ## 功能特性
17
+
18
+ - **LLM 自动裁决**:在 `workspace-write` 会话中,对 `danger-full-access` / `workspace-write` 升权申请调用大模型分级(`allow / deny / unsure`),确定时免去人工弹窗。
19
+ - **内置预设**:`off` / `strict` / `balanced`(默认)/ `permissive` / `yolo` / `custom`,覆盖从「全部转人工」到「确定性全放行」的完整光谱。
20
+ - **自定义层级**:`levels` 支持逐目标模式、逐工具(`tools.<toolName>`)的 `allow / judge / delegate / deny` 策略,及 `error` / `unsure` 回退。
21
+ - **每预设默认提示词**:`judge.systemPrompt` 留空时按预设自动选用对应裁判提示词(strict 最保守、permissive 宽松、custom 按层级表)。
22
+ - **图形化配置**:设置面板「YOLO 审批」页在线修改预设 / 生效模式 / 裁判模型(下拉选择)/ 层级表,保存即生效;输入栏状态 chip + 决策统计面板。
23
+ - **完整审计**:每次裁决落 JSONL 日志,含工具、目标模式、当前模式、理由、决策与结果;状态弹窗一键「打开日志」用系统默认应用查看。
24
+ - **fail-closed**:超时、非法输出、模型不可用、并发溢出等一切异常路径都回退为「拒绝」或「转人工」。
25
+
26
+ ## 安装
27
+
28
+ ### 1. 安装插件包
29
+
30
+ ```bash
31
+ # 从 npm
32
+ dsh plugin --profile web add dsh-yolo-mode
33
+
34
+ # 或从本地路径
35
+ dsh plugin --profile web add <项目绝对路径>
36
+ ```
37
+
34
38
  ### 2.(可选)覆盖插件配置
35
39
 
36
40
  `dsh plugin add` 会通过插件包自带的 `cordis.patch.yml` 自动挂载 `yolo-mode` 与
@@ -61,79 +65,80 @@ dsh plugin --profile web add <项目绝对路径>
61
65
  `ERR_MODULE_NOT_FOUND`。
62
66
 
63
67
  ## 配置
64
-
65
- 插件行 `config` 全字段可选,未填按默认值:
66
-
67
- | 字段 | 类型 | 默认值 | 说明 |
68
- |---|---|---|---|
69
- | `preset` | `off\|strict\|balanced\|permissive\|yolo\|custom` | `balanced` | 使用的预设;`custom` 时以 `levels` 为准 |
70
- | `modes` | `string[]` | `['workspace-write']` | 会话有效沙箱模式 ∈ 此列表时才介入(`read-only` / `workspace-write` / `danger-full-access`) |
71
- | `levels` | `object` | `{}` | 权限层级表;`levels.tools.<toolName>` 对任意预设逐工具覆盖 |
72
- | `judge.provider` | `string` | `''` | 裁判模型 provider;空 = 未配置(judge 决策按错误回退) |
73
- | `judge.model` | `string` | `''` | 裁判模型;与 provider 同非空才启用裁判 |
74
- | `judge.systemPrompt` | `string` | `''` | 裁判 system prompt;空 = 按预设取默认 |
75
- | `judge.timeoutMs` | `number` | `20000` | 单次裁判超时(毫秒) |
76
- | `judge.maxTokens` | `number` | `256` | 裁判输出最大 token 数 |
77
- | `judge.concurrency` | `number` | `2` | 并发裁判上限,溢出按错误回退 |
78
- | `includeSubagents` | `boolean` | `true` | 子代理会话是否同样裁决 |
79
- | `auditFile` | `string` | `''` | 审计日志路径;空 = `%TEMP%/dsh-yolo/judge.log` |
80
-
81
- ### 权限层级(`levels`)
82
-
83
- ```yaml
84
- levels:
85
- workspace-write: judge # 目标模式 → 策略
86
- danger-full-access: judge
87
- error: delegate # 裁判错误回退
88
- unsure: delegate # 裁判不确定回退
89
- tools:
90
- pwsh: delegate # 逐工具覆盖,优先级最高
91
- write: allow
92
- ```
93
-
94
- 策略取值 `allow | judge | delegate | deny`;优先级:`levels.tools[toolName]` → 基础行(`custom` 时为 `levels[targetMode]`,其余预设为内置表)。
95
-
96
- ## 预设
97
-
98
- | 预设 | `workspace-write` | `danger-full-access` | 失败回退 | 不确定回退 | 说明 |
99
- |---|---|---|---|---|---|
100
- | `off` | delegate | delegate | delegate | delegate | 不介入,全部转人工 |
101
- | `strict` 严格 | judge | delegate | rejected | delegate | 仅裁决 `workspace-write`;`danger-full-access` 恒转人工 |
102
- | `balanced` 均衡(默认) | judge | judge | delegate | delegate | 裁决全部升级目标;失败 / 不确定转人工 |
103
- | `permissive` 宽松 | judge | judge | delegate | **allowed-once** | 裁决全部目标;不确定视为允许(慎用) |
104
- | `yolo` | allow | allow | — | — | 确定性全放行,零 LLM 调用 |
105
- | `custom` | 依 `levels` | 依 `levels` | 依 `levels.error` | 依 `levels.unsure` | 全字段开放 |
106
-
107
- 每预设默认裁判提示词(`judge.systemPrompt` 留空时自动选用):
108
-
109
- | 预设 | 默认裁判立场 |
110
- |---|---|
111
- | `off` / `yolo` | 不调用裁判 |
112
- | `strict` | 最保守:`danger-full-access` 一律拒绝;仅最小范围 `workspace-write` 且理由极充分才允许 |
113
- | `balanced` | 通用审计:只依据事实、防回环、存疑即 deny/unsure |
114
- | `permissive` | 宽松:理由合理且范围可接受即倾向允许,仅明显破坏性 / 供应链风险拒绝 |
115
- | `custom` | 按 `levels` 层级表裁决,存疑按 `levels.error` / `levels.unsure` 回退 |
116
-
117
- ## 界面
118
-
119
- - **输入栏 chip**:显示 `YOLO <preset>`,点击弹出统计面板(总审批 / 放行 / 拒绝 / 转人工 + 最近 20 条决策)。
120
- - **设置页**:「YOLO 审批」页在线修改预设、生效沙箱模式、裁判模型(provider / model 下拉,取自 Harness 模型配置)、层级表(JSON);切换预设时自动预填充该预设的默认提示词与层级表。
121
-
122
- ## 安全
123
-
124
- - **fail-closed**:只有明确得到 `allow` 才返回一次性 `allowed-once`;其余一切路径拒绝或转人工。
125
- - **防回环**:裁判 prompt 与 agent 上下文隔离,防止模型借 Web 审批回环自批准 `danger-full-access`。
126
- - **不改写策略**:仅在 `ask` 策略下作为应答者,不改变 DSH 的沙箱 / 审批词汇。
127
- - **默认保守**:默认预设 `balanced`(不确定转人工),不默认启用 `permissive` / `yolo`。
128
- - **审计**:每次裁决落一行 JSONL,含 `{time, sessionId, origin, toolName, callId?, targetMode, currentMode, justification, decision, outcome, reason?}`。
129
-
130
- ## 开发
131
-
132
- ```bash
133
- npm test # node --test 全量测试
134
- npm run build # 构建客户端 bundle(rolldown)
135
- ```
136
-
137
- ## 许可
138
-
139
- [MIT](LICENSE)
68
+
69
+ 插件行 `config` 全字段可选,未填按默认值:
70
+
71
+ | 字段 | 类型 | 默认值 | 说明 |
72
+ |---|---|---|---|
73
+ | `preset` | `off\|strict\|balanced\|permissive\|yolo\|custom` | `balanced` | 使用的预设;`custom` 时以 `levels` 为准 |
74
+ | `modes` | `string[]` | `['workspace-write']` | 会话有效沙箱模式 ∈ 此列表时才介入(`read-only` / `workspace-write` / `danger-full-access`) |
75
+ | `levels` | `object` | `{}` | 权限层级表;`levels.tools.<toolName>` 对任意预设逐工具覆盖 |
76
+ | `judge.provider` | `string` | `''` | 裁判模型 provider;空 = 未配置(judge 决策按错误回退) |
77
+ | `judge.model` | `string` | `''` | 裁判模型;与 provider 同非空才启用裁判 |
78
+ | `judge.systemPrompt` | `string` | `''` | 裁判 system prompt;空 = 按预设取默认 |
79
+ | `judge.timeoutMs` | `number` | `20000` | 单次裁判超时(毫秒) |
80
+ | `judge.maxTokens` | `number` | `256` | 裁判输出最大 token 数 |
81
+ | `judge.concurrency` | `number` | `2` | 并发裁判上限,溢出按错误回退 |
82
+ | `includeSubagents` | `boolean` | `true` | 子代理会话是否同样裁决 |
83
+ | `auditFile` | `string` | `''` | 审计日志路径;空 = `%TEMP%/dsh-yolo/judge.log` |
84
+
85
+ ### 权限层级(`levels`)
86
+
87
+ ```yaml
88
+ levels:
89
+ workspace-write: judge # 目标模式 → 策略
90
+ danger-full-access: judge
91
+ error: delegate # 裁判错误回退
92
+ unsure: delegate # 裁判不确定回退
93
+ tools:
94
+ pwsh: delegate # 逐工具覆盖,优先级最高
95
+ write: allow
96
+ ```
97
+
98
+ 策略取值 `allow | judge | delegate | deny`;优先级:`levels.tools[toolName]` → 基础行(`custom` 时为 `levels[targetMode]`,其余预设为内置表)。
99
+
100
+ ## 预设
101
+
102
+ | 预设 | `workspace-write` | `danger-full-access` | 失败回退 | 不确定回退 | 说明 |
103
+ |---|---|---|---|---|---|
104
+ | `off` | delegate | delegate | delegate | delegate | 不介入,全部转人工 |
105
+ | `strict` 严格 | judge | delegate | rejected | delegate | 仅裁决 `workspace-write`;`danger-full-access` 恒转人工 |
106
+ | `balanced` 均衡(默认) | judge | judge | delegate | delegate | 裁决全部升级目标;失败 / 不确定转人工 |
107
+ | `permissive` 宽松 | judge | judge | delegate | **allowed-once** | 裁决全部目标;不确定视为允许(慎用) |
108
+ | `yolo` | allow | allow | — | — | 确定性全放行,零 LLM 调用 |
109
+ | `custom` | 依 `levels` | 依 `levels` | 依 `levels.error` | 依 `levels.unsure` | 全字段开放 |
110
+
111
+ 每预设默认裁判提示词(`judge.systemPrompt` 留空时自动选用):
112
+
113
+ | 预设 | 默认裁判立场 |
114
+ |---|---|
115
+ | `off` / `yolo` | 不调用裁判 |
116
+ | `strict` | 最保守:`danger-full-access` 一律拒绝;仅最小范围 `workspace-write` 且理由极充分才允许 |
117
+ | `balanced` | 通用审计:只依据事实、防回环、存疑即 deny/unsure |
118
+ | `permissive` | 宽松:理由合理且范围可接受即倾向允许,仅明显破坏性 / 供应链风险拒绝 |
119
+ | `custom` | 按 `levels` 层级表裁决,存疑按 `levels.error` / `levels.unsure` 回退 |
120
+
121
+ ## 界面
122
+
123
+ - **输入栏 chip**:显示 `YOLO <preset>`,点击弹出统计面板(总审批 / 放行 / 拒绝 / 转人工 + 最近决策表,每页 5 条,带上一页 / 下一页翻页)。
124
+ - **打开日志**:弹窗右上「打开日志」按钮用系统默认应用打开审计 JSONL(`auditFile` 配置或默认 `%TEMP%/dsh-yolo/judge.log`);文件尚不存在时提示暂无记录。
125
+ - **设置页**:「YOLO 审批」页在线修改预设、生效沙箱模式、裁判模型(provider / model 下拉,取自 Harness 模型配置)、层级表(JSON);切换预设时自动预填充该预设的默认提示词与层级表。
126
+
127
+ ## 安全
128
+
129
+ - **fail-closed**:只有明确得到 `allow` 才返回一次性 `allowed-once`;其余一切路径拒绝或转人工。
130
+ - **防回环**:裁判 prompt 与 agent 上下文隔离,防止模型借 Web 审批回环自批准 `danger-full-access`。
131
+ - **不改写策略**:仅在 `ask` 策略下作为应答者,不改变 DSH 的沙箱 / 审批词汇。
132
+ - **默认保守**:默认预设 `balanced`(不确定转人工),不默认启用 `permissive` / `yolo`。
133
+ - **审计**:每次裁决落一行 JSONL,含 `{time, sessionId, origin, toolName, callId?, targetMode, currentMode, justification, decision, outcome, reason?}`。
134
+
135
+ ## 开发
136
+
137
+ ```bash
138
+ npm test # node --test 全量测试
139
+ npm run build # 构建客户端 bundle(rolldown)
140
+ ```
141
+
142
+ ## 许可
143
+
144
+ [MIT](LICENSE)
package/cordis.patch.yml CHANGED
@@ -1,12 +1,12 @@
1
- # dsh-yolo-mode bundle patch.
2
- #
3
- # Adds the plugin's two entries: the main entry and the settings bridge that
4
- # exposes the `yolo-mode` settings namespace to the Web UI.
5
- # Install: dsh plugin --profile <name> add dsh-yolo-mode
6
- # Restart `dsh --profile <name>` after installing.
7
- - insert:
8
- - id: yolo-mode
9
- name: dsh-yolo-mode
10
- - insert:
11
- - id: yolo-mode-bridge
1
+ # dsh-yolo-mode bundle patch.
2
+ #
3
+ # Adds the plugin's two entries: the main entry and the settings bridge that
4
+ # exposes the `yolo-mode` settings namespace to the Web UI.
5
+ # Install: dsh plugin --profile <name> add dsh-yolo-mode
6
+ # Restart `dsh --profile <name>` after installing.
7
+ - insert:
8
+ - id: yolo-mode
9
+ name: dsh-yolo-mode
10
+ - insert:
11
+ - id: yolo-mode-bridge
12
12
  name: dsh-yolo-mode/bridge
package/lib/audit.js ADDED
@@ -0,0 +1,116 @@
1
+ /**
2
+ * dsh-yolo-mode —— 审计日志文件解析与打开(lib/audit.js)
3
+ *
4
+ * 审计 JSONL 路径的唯一解析来源:主条目(lib/index.js 的 audit())与桥接条目
5
+ * (openLogFile 端点)都必须落到同一个文件,否则「打开日志」会指向错误位置。
6
+ * 规则(design.md §8/§11.1,README 配置表 auditFile):
7
+ * - 配置显式给出非空 `auditFile` → 用配置值;
8
+ * - 否则回落默认 `%TEMP%/dsh-yolo/judge.log`(os.tmpdir(),宿主真实临时目录)。
9
+ *
10
+ * `openFileWithDefaultApp` 用 OS 默认应用打开文件(fire-and-forget):
11
+ * - darwin → `open <file>`
12
+ * - win32 → `cmd /c start "" "<file>"`(引号包实参,兼容含空格路径)
13
+ * - 其余 → `xdg-open <file>`
14
+ * 启动失败(如 xdg-open 缺失)经 child 'error' 事件返回 { ok:false },
15
+ * 绝不抛出(打开失败不致命,UI 只提示)。
16
+ *
17
+ * 纯函数层(resolveAuditFile / auditFileExists / openerCommandFor)无副作用,
18
+ * 可在普通 node 环境单测。
19
+ *
20
+ * @module lib/audit.js
21
+ */
22
+ import os from 'node:os';
23
+ import path from 'node:path';
24
+ import fs from 'node:fs';
25
+ import { spawn } from 'node:child_process';
26
+
27
+ /** 默认审计日志路径:`%TEMP%/dsh-yolo/judge.log`(design.md §8;每次调用取当前 tmpdir)。 */
28
+ export function defaultAuditFile() {
29
+ return path.join(os.tmpdir(), 'dsh-yolo', 'judge.log');
30
+ }
31
+
32
+ /**
33
+ * 解析生效的审计日志路径:显式非空 `auditFile` 优先(返回值去除首尾空白),
34
+ * 否则回落默认。
35
+ * @param {object|undefined} cfg 配置字形(view.value / effectiveConfig)
36
+ * @returns {string} 绝对或配置给定的审计日志路径
37
+ */
38
+ export function resolveAuditFile(cfg) {
39
+ const configured =
40
+ cfg && typeof cfg === 'object' && typeof cfg.auditFile === 'string' ? cfg.auditFile.trim() : '';
41
+ return configured !== '' ? configured : defaultAuditFile();
42
+ }
43
+
44
+ /**
45
+ * 审计日志文件是否已存在(尚无裁决时不创建、不弹错误对话框)。
46
+ * @param {string} file
47
+ * @returns {boolean}
48
+ */
49
+ export function auditFileExists(file) {
50
+ try {
51
+ return fs.existsSync(file);
52
+ } catch {
53
+ return false;
54
+ }
55
+ }
56
+
57
+ /**
58
+ * 按平台挑选「默认应用打开」命令(纯函数,可注入 platform 单测)。
59
+ * @param {string} file 目标文件路径
60
+ * @param {string} [platform] process.platform 值;缺省取当前进程
61
+ * @returns {{command: string, args: string[]}}
62
+ */
63
+ export function openerCommandFor(file, platform = process.platform) {
64
+ const target = String(file);
65
+ if (platform === 'darwin') return { command: 'open', args: [target] };
66
+ if (platform === 'win32') {
67
+ // cmd 的 start 把首个带引号实参当作窗口标题;用 "" 占位,文件实参整体包引号。
68
+ return { command: 'cmd', args: ['/c', 'start', '""', '"' + target.replace(/"/g, '\\"') + '"'] };
69
+ }
70
+ return { command: 'xdg-open', args: [target] };
71
+ }
72
+
73
+ /**
74
+ * 用 OS 默认应用打开文件(detached + unref 的 fire-and-forget)。
75
+ * @param {string} file
76
+ * @returns {Promise<{ok:true, value:{path:string}} | {ok:false, error:{code:string, message:string, details:object}}>}
77
+ */
78
+ export function openFileWithDefaultApp(file) {
79
+ return new Promise((resolve) => {
80
+ const { command, args } = openerCommandFor(file);
81
+ let settled = false;
82
+ const settle = (result) => {
83
+ if (settled) return;
84
+ settled = true;
85
+ resolve(result);
86
+ };
87
+ let child;
88
+ try {
89
+ child = spawn(command, args, { detached: true, stdio: 'ignore' });
90
+ } catch (err) {
91
+ settle({
92
+ ok: false,
93
+ error: {
94
+ code: 'open-failed',
95
+ message: 'failed to launch ' + command + ': ' + String(err && err.message ? err.message : err),
96
+ details: { path: file },
97
+ },
98
+ });
99
+ return;
100
+ }
101
+ child.once('error', (err) => {
102
+ settle({
103
+ ok: false,
104
+ error: {
105
+ code: 'open-failed',
106
+ message: 'failed to launch ' + command + ': ' + (err && err.message ? err.message : String(err)),
107
+ details: { path: file },
108
+ },
109
+ });
110
+ });
111
+ child.once('spawn', () => {
112
+ child.unref();
113
+ settle({ ok: true, value: { path: file } });
114
+ });
115
+ });
116
+ }