dsh-model-switch 0.4.40 → 0.4.42
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 +22 -0
- package/README.md +3 -1
- package/README.zh.md +4 -2
- package/cordis.patch.yml +7 -0
- package/lib/{auto-review-BDx3LjVL.js → auto-review-QDEFUjT2.js} +2 -332
- package/lib/auto-review.js +1 -1
- package/lib/automode-compat.js +266 -0
- package/lib/client.js +23 -1
- package/lib/index.js +5 -2
- package/lib/tool-allowlist-DlzB5GlQ.js +332 -0
- package/lib/types/automode-compat.d.ts +152 -0
- package/lib/types/capabilities-rpc.d.ts +8 -0
- package/lib/types/client/locales.d.ts +3 -0
- package/lib/types/client-contract.d.ts +7 -0
- package/package.json +7 -2
- package/lib/session-route-BCQFzqRP.js +0 -172
- package/lib/session-route-BjNPlliu.js +0 -172
package/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,25 @@
|
|
|
1
|
+
## v0.4.42
|
|
2
|
+
|
|
3
|
+
与第三方自动模式插件 `@log.li/dsh-automode` 的插件层适配:**不改用户配置、不新增依赖、不安装任何东西**——本插件在自己的 loader 行里,把「自动审查路由」与「纯读名单」注入到 `@log.li/dsh-automode` 行的**内存配置**,让它的 `auto-mode` 档位沿用我们的路由与豁免。
|
|
4
|
+
|
|
5
|
+
- **新行 `model-switch-automode-compat`**(`dsh-model-switch/automode-compat`):`inject = ['loader','modelSwitch']`,在 `loader/patch-context` 里于该行挂载前改写 `entry.options.config`;行不存在时整行空转。可在插件管理器里单独停用,不影响审查闸门。
|
|
6
|
+
- **路由**:仅当 automode 的 `classifier.provider` / `classifier.model` **都为空**时填入我们的 `autoReviewProvider/Model`;任一字段已有值即视为用户意图,绝不覆盖(状态里标 `user-set`);我们将自己上次写入的值记为可重写,设置变更时能跟随更新。
|
|
7
|
+
- **纯读豁免**:把我们的名单(默认 58 条)并入它的 `readOnlyTools`,并在「纯读工具免审查」开关关闭时**不注入**。它用精确匹配,所以 `sessions_list__*` 这类通配条目会跳过并在卡片上计数(默认名单里是 1 条)。注入后的工具仍会先过它自己的 deny 正则——不会削弱它的硬底线。
|
|
8
|
+
- **不落盘**:只改运行时 `entry.options`,从不调用 `Entry.update()`;启动前后 profile 的 `cordis.patch.yml` 不变,重启自动重放。
|
|
9
|
+
- **可见性**:「审查豁免」卡片新增一行 `Auto mode 已接入:审查路由 <provider>/<model>,直通 +N 个纯读工具(M 条通配未同步)`,未安装时不显示;`tools` RPC 的 `status.automode` 提供同数字段。
|
|
10
|
+
- **rc.3 lab 实测**(3083 / `~/.dsh-lab3`,automode `0.17.0` + 本插件 0.4.42):automode 的 `boot` 审计行出现;在 `auto-mode` 会话的工具调用里,它的闸门实际读到 `preset="auto-mode"`、`classifier={"provider":"apigoto","model":"mimo-v2.6-flash",…}`、`readOnlyTools=58`、`preExecuteGate=true`(即注入生效);启动前后 profile `cordis.patch.yml` 的 sha256 一致(未落盘);卡片显示「Auto mode 已接入:审查路由 apigoto/mimo-v2.6-flash,直通 +53 个纯读工具(2 条通配未同步)」。注:automode 的逐调用审计行本次未出现,是因为它对未升级的 workspace-write 调用按设计静默放行,与兼容性无关。
|
|
11
|
+
- **边界**:它的分类器只有一个静态路由,逐步 provider 分组无法映射过去(取顶层自动审查路由);它的 `readOnlyTools` 精确匹配,通配条目转不过去;这些都在文案与文档里写明。
|
|
12
|
+
|
|
13
|
+
## v0.4.41
|
|
14
|
+
|
|
15
|
+
DSH `0.2.1-rc.3`(2026-10-23 发布,当前在 `next` 通道)兼容性更新:**插件本体零改动**,本轮做的是实证与声明;旧线(`0.1.7-alpha.2` … `0.2.1-rc.2`)的声明与依赖下界原样保留。
|
|
16
|
+
|
|
17
|
+
- **rc.3 是纯客户端加法**(compare `dsh-v0.2.1-rc.2...dsh-v0.2.1-rc.3`,300 个文件):`ui-conversation` 只新增 `conversation.session.header.views.actions` 槽位与 header 的 `entryPins`/`entryActions`/`setPinned`(`conversation.composer` 链与 `ComposerChainProps` 一字未改);输入侧新增 `whenDraftExists`,`clearPreviousDraft` 语义保持兼容(本插件从不调用 `requestDraftInitialization`);`ui-user-questions`、`ui-primitives` 只加不改;`experimental-auto-review`、`dsh-tools`、`dsh-session`、`dsh-subagent` 与 `api/*` 源码未变(只有版本号)。
|
|
18
|
+
- **rc.3 lab 实测**(独立 home `~/.dsh-lab3`、端口 3083、`@deepseek-ai/dsh@0.2.1-rc.3`):挂载无 `best-effort on unverified runtime` 告警;「审查豁免」卡片正常,「恢复默认名单」得到 **58 条**;自动审查预设下 `read`+`glob`+`read` 让跳过计数到 **3**,随后 `write` 让计数保持 **3**(写操作仍走审查);计划卡「去聊天里说」使回合以 **`aborted`** 结束、输入框回来、显示「已停止」;草稿跨会话切换保留(rc.3 的修复点)。
|
|
19
|
+
- **rc.2 回归**(3082,同一份 0.4.41 产物):挂载正常、卡片正常、`glob`+`read` 跳过计数 **2**,与 0.4.40 行为一致。
|
|
20
|
+
- **声明**:`package.json#dsh.compatibility.dshReleases` 增加 `0.2.1-rc.3`;`README.md`、`README.zh.md` 与 `docs/dsh-compat-watch.md` 同步(含「rc.3 走 `next` 通道」与本次「用户显式要求、先于 `latest` 触发」的例外记录)。
|
|
21
|
+
- **测试**:`tests/compatibility.spec.ts` 新增两例——真实 `package.json` 必须同时保留旧线与 rc.3 的声明;rc.3 分类为 verified(不产生告警),未知版本仍 fail-open。
|
|
22
|
+
|
|
1
23
|
## v0.4.40
|
|
2
24
|
|
|
3
25
|
按你的点名,默认豁免名单从 47 条扩到 **58 条**:新增 11 个工具,全部在「设置 → 模型切换 → 审查豁免」里可查、可删、可恢复默认。
|
package/README.md
CHANGED
|
@@ -158,7 +158,7 @@ A packed tarball installs the same build without a registry:
|
|
|
158
158
|
dsh plugin --profile web add --force ./dsh-model-switch-0.4.26.tgz
|
|
159
159
|
```
|
|
160
160
|
|
|
161
|
-
Then install only the provider adapters you use. This release was checked against official DeepSeek Harness `0.1.7-rc.2` and verified on `0.2.0-rc.2` and `0.2.1-rc.
|
|
161
|
+
Then install only the provider adapters you use. This release was checked against official DeepSeek Harness `0.1.7-rc.2` and verified on `0.2.0-rc.2`, `0.2.1-rc.2` and `0.2.1-rc.3` (rc.3 currently ships on the `next` dist-tag):
|
|
162
162
|
|
|
163
163
|
```sh
|
|
164
164
|
dsh plugin --profile web add --force \
|
|
@@ -193,6 +193,8 @@ Verified releases: `0.1.7-alpha.2`, `0.1.7-rc.1`, `0.1.7-rc.2`, `0.2.0-rc.2`. Th
|
|
|
193
193
|
|
|
194
194
|
The verified releases in `package.json#dsh.compatibility.dshReleases` are evidence, not an allowlist. Review public API changes and test new Host releases before adding a verification claim.
|
|
195
195
|
|
|
196
|
+
**Third-party auto modes.** When [`@log.li/dsh-automode`](https://github.com/log-li/dsh-automode) is installed, the `model-switch-automode-compat` row injects this plugin's Auto-review route and pure-read list into that row's **in-memory** config — no profile write, nothing to configure by hand. Its `auto-mode` preset then reviews with your configured route and passes your allowlisted tools, while the `auto` preset keeps using this plugin's own gate. Explicit `classifier.provider/model` values in that row always win, pattern-shaped allowlist entries cannot transfer (its check is exact-match), and its hard-deny bands still run first.
|
|
197
|
+
|
|
196
198
|
## Development
|
|
197
199
|
|
|
198
200
|
Requires Node 22.19+ and pnpm.
|
package/README.zh.md
CHANGED
|
@@ -156,7 +156,7 @@ dsh plugin --profile web add --force dsh-model-switch
|
|
|
156
156
|
dsh plugin --profile web add --force ./dsh-model-switch-0.4.17.tgz
|
|
157
157
|
```
|
|
158
158
|
|
|
159
|
-
然后只安装实际使用的 Provider Adapter。此版本已在官方 DeepSeek Harness `0.1.7-rc.2` 上检查,并在 `0.2.0-rc.2`
|
|
159
|
+
然后只安装实际使用的 Provider Adapter。此版本已在官方 DeepSeek Harness `0.1.7-rc.2` 上检查,并在 `0.2.0-rc.2`、`0.2.1-rc.2` 与 `0.2.1-rc.3`(rc.3 目前走 `next` 通道)上验证:
|
|
160
160
|
|
|
161
161
|
```sh
|
|
162
162
|
dsh plugin --profile web add --force \
|
|
@@ -187,10 +187,12 @@ DeepSeek 薄适配器调用官方公开 `DeepSeekSearchProvider`,复用用户
|
|
|
187
187
|
|
|
188
188
|
DSH Host peer 和开发依赖接受 `>=0.1.7-alpha.2`,包括 rc.1 和后续版本。开发锁文件解析到 rc.2。Cordis 接受 `>=4.0.4 <5.0.0`。
|
|
189
189
|
|
|
190
|
-
已验证版本:`0.1.7-alpha.2`、`0.1.7-rc.1`、`0.1.7-rc.2`、`0.2.0-rc.2`、`0.2.1-rc.2`。0.2.0 的声明覆盖三处差异:Host 改名的提问撤下动词(`cancel()` → `dismiss()`)、`session.selectModel` 不 await 的部署默认值写入、以返回值报出的 `ModelDirectory.select` 拒绝;三者均已在 lab(3082/3085)与真实桌面会话中逐一验证。0.2.1 的声明覆盖两处被替换的 seam:共享命名调用改为 provider 自备提示词与解析的 `executeSessionTitleLlm`(本插件按安装行在运行时适配,并镜像官方 0.2.1 的提示词、取最低 reasoning effort 与 `currentTitle` 锚定);Subagent 运行时以 `startActivation` 取代 `start()`/`startContinuable()`,本插件同时识别两条已发布线,并为激活入口覆写 `spec.request.agentOptions`(显式路由仍优先、非 agentOptions 能力的外部适配器不改写),路由语义与旧线一致(0.4.28,记录于 `docs/seam-gap.md`);0.2.1 还新增了自动审查门禁对 `ctx.workingDirectory` 的读取,旧实现因在自己的 fiber 里直调 `official.apply` 而需要手工镜像门禁的 `inject`,于是每个工具调用都被拒(`cannot get property "workingDirectory" without inject`),0.4.28 改为把官方门禁以插件方式挂载、由官方 `inject` 解析依赖,本行只声明自身需要的服务。0.4.28 的真实包证据:0.2.1 上旧形态精确复现该注入错误、新形态到达 `workingDirectory.ensure` 且成功注册门禁、激活入口的路由改写与 spec 透传通过;0.2.0 上无需 `workingDirectory` 服务即可注册门禁,`start()` 路由改写与父身份保持不变。0.2.1 的 lab 证据为:npm 安装的 0.2.1 运行时 + 打包后的 0.4.26 组合 `exit 0`、命名/压缩/自动审查/子代理四行均来自本插件、Web Host 在 3082 启动并服务需要鉴权的页面;该次未经浏览器调用 3082 能力 RPC,真实桌面的 0.2.1 命名差分在应用升级后复验。0.2.1 还暴露出一处预设层面的差异(0.2.1 校验提示词变量、只有 `provider`/`model`,且把 `time-context`/`tool-schedule` 移进预设):0.4.26 的静态预设副本因此让每一轮都报 `unknown prompt variable "{{cwd}}"`,0.4.27 删除副本改为启动期运行时桥接,并在 lab 的 0.2.1 headless 真实回合中验证通过(展开见 CHANGELOG 0.4.27)。
|
|
190
|
+
已验证版本:`0.1.7-alpha.2`、`0.1.7-rc.1`、`0.1.7-rc.2`、`0.2.0-rc.2`、`0.2.1-rc.2`、`0.2.1-rc.3`。0.2.0 的声明覆盖三处差异:Host 改名的提问撤下动词(`cancel()` → `dismiss()`)、`session.selectModel` 不 await 的部署默认值写入、以返回值报出的 `ModelDirectory.select` 拒绝;三者均已在 lab(3082/3085)与真实桌面会话中逐一验证。0.2.1 的声明覆盖两处被替换的 seam:共享命名调用改为 provider 自备提示词与解析的 `executeSessionTitleLlm`(本插件按安装行在运行时适配,并镜像官方 0.2.1 的提示词、取最低 reasoning effort 与 `currentTitle` 锚定);Subagent 运行时以 `startActivation` 取代 `start()`/`startContinuable()`,本插件同时识别两条已发布线,并为激活入口覆写 `spec.request.agentOptions`(显式路由仍优先、非 agentOptions 能力的外部适配器不改写),路由语义与旧线一致(0.4.28,记录于 `docs/seam-gap.md`);0.2.1 还新增了自动审查门禁对 `ctx.workingDirectory` 的读取,旧实现因在自己的 fiber 里直调 `official.apply` 而需要手工镜像门禁的 `inject`,于是每个工具调用都被拒(`cannot get property "workingDirectory" without inject`),0.4.28 改为把官方门禁以插件方式挂载、由官方 `inject` 解析依赖,本行只声明自身需要的服务。0.4.28 的真实包证据:0.2.1 上旧形态精确复现该注入错误、新形态到达 `workingDirectory.ensure` 且成功注册门禁、激活入口的路由改写与 spec 透传通过;0.2.0 上无需 `workingDirectory` 服务即可注册门禁,`start()` 路由改写与父身份保持不变。0.2.1 的 lab 证据为:npm 安装的 0.2.1 运行时 + 打包后的 0.4.26 组合 `exit 0`、命名/压缩/自动审查/子代理四行均来自本插件、Web Host 在 3082 启动并服务需要鉴权的页面;该次未经浏览器调用 3082 能力 RPC,真实桌面的 0.2.1 命名差分在应用升级后复验。0.2.1 还暴露出一处预设层面的差异(0.2.1 校验提示词变量、只有 `provider`/`model`,且把 `time-context`/`tool-schedule` 移进预设):0.4.26 的静态预设副本因此让每一轮都报 `unknown prompt variable "{{cwd}}"`,0.4.27 删除副本改为启动期运行时桥接,并在 lab 的 0.2.1 headless 真实回合中验证通过(展开见 CHANGELOG 0.4.27)。0.2.1-rc.3 是纯客户端改动:本品读到的三个包都是加法——`ui-conversation` 新增 `conversation.session.header.views.actions` 槽位与 header 的 `entryPins`/`entryActions`/`setPinned`(`conversation.composer` 链与 `ComposerChainProps` 一字未改)、`ui-primitives` 新增 `IconAppsAddOutline*` 图标、`ui-user-questions` 只有版本号;`experimental-auto-review`、`dsh-tools`、`dsh-session`、`dsh-subagent` 与 `api/*` 在 rc.3 中源码未变(后者只有版本号)。插件本体零改动,在 rc.3 lab(3083,`@deepseek-ai/dsh@0.2.1-rc.3`)复验:挂载无 unverified 告警、58 条默认名单、纯读跳过计数、写操作仍审查、计划卡「去聊天里说」回合以 `aborted` 结束、草稿跨会话保留;再用同一产物在 rc.2 lab(3082)回归通过(展开见 CHANGELOG 0.4.41)。
|
|
191
191
|
|
|
192
192
|
`package.json#dsh.compatibility.dshReleases` 中的已验证版本是证据,不是允许列表。新增验证声明前要审查公开 API 变化并测试新 Host 版本。
|
|
193
193
|
|
|
194
|
+
**第三方自动模式。** 安装 [`@log.li/dsh-automode`](https://github.com/log-li/dsh-automode) 后,`model-switch-automode-compat` 行会把本插件的自动审查路由与纯读名单注入到该行的**内存配置**里——不写 profile、不需要手工配置。它的 `auto-mode` 档位会用你配置的路由审查、并按你的名单直通纯读工具;`auto` 档位仍然走本插件自己的闸门。该行里显式写过的 `classifier.provider/model` 永远优先,带通配的名单条目无法转过去(它是精确匹配),它的硬 deny 正则也照旧先跑。
|
|
195
|
+
|
|
194
196
|
## 开发
|
|
195
197
|
|
|
196
198
|
需要 Node 22.19+ 和 pnpm。
|
package/cordis.patch.yml
CHANGED
|
@@ -73,3 +73,10 @@
|
|
|
73
73
|
# The official naming provider under the configurable naming route.
|
|
74
74
|
- id: model-switch-session-title
|
|
75
75
|
name: 'dsh-model-switch/session-title'
|
|
76
|
+
|
|
77
|
+
# Inject this plugin's Auto-review route and pure-read list into the
|
|
78
|
+
# third-party @log.li/dsh-automode row's in-memory config (no profile write,
|
|
79
|
+
# no-op when that plugin is not installed). Kept as its own row so it can be
|
|
80
|
+
# disabled without touching the reviewer gate.
|
|
81
|
+
- id: model-switch-automode-compat
|
|
82
|
+
name: 'dsh-model-switch/automode-compat'
|
|
@@ -1,339 +1,9 @@
|
|
|
1
1
|
import { i as sessionProviderOf, r as resolveCapabilityRoute } from "./session-route-D1zoZgf3.js";
|
|
2
|
+
import { n as isAllowedByList } from "./tool-allowlist-DlzB5GlQ.js";
|
|
2
3
|
import { AsyncLocalStorage } from "node:async_hooks";
|
|
3
4
|
import { mkdirSync, readFileSync, rmSync, writeFileSync } from "node:fs";
|
|
4
5
|
import { homedir } from "node:os";
|
|
5
6
|
import { dirname, join } from "node:path";
|
|
6
|
-
/** Catalog lookup by id. */
|
|
7
|
-
const SOURCE_BY_ID = new Map([
|
|
8
|
-
{
|
|
9
|
-
id: "core",
|
|
10
|
-
kind: "core",
|
|
11
|
-
label: "DSH 核心",
|
|
12
|
-
repo: "https://github.com/deepseek-ai/deepseek-harness"
|
|
13
|
-
},
|
|
14
|
-
{
|
|
15
|
-
id: "dsh-ops",
|
|
16
|
-
kind: "plugin",
|
|
17
|
-
label: "插件 · dsh-ops",
|
|
18
|
-
repo: "https://github.com/T-Auto/dsh-ops"
|
|
19
|
-
},
|
|
20
|
-
{
|
|
21
|
-
id: "dsh-browser-cdp",
|
|
22
|
-
kind: "plugin",
|
|
23
|
-
label: "插件 · dsh-browser-cdp",
|
|
24
|
-
repo: "https://github.com/drscrewdriver/dsh-browser-cdp"
|
|
25
|
-
},
|
|
26
|
-
{
|
|
27
|
-
id: "dsh-auto-memory",
|
|
28
|
-
kind: "plugin",
|
|
29
|
-
label: "插件 · dsh-auto-memory",
|
|
30
|
-
repo: "https://github.com/AskTheWay/dsh-auto-memory"
|
|
31
|
-
},
|
|
32
|
-
{
|
|
33
|
-
id: "dsh-model-switch",
|
|
34
|
-
kind: "plugin",
|
|
35
|
-
label: "插件 · dsh-model-switch",
|
|
36
|
-
repo: "https://github.com/vandoor7-droid/dsh-model-switch"
|
|
37
|
-
},
|
|
38
|
-
{
|
|
39
|
-
id: "mcp:wincu",
|
|
40
|
-
kind: "mcp",
|
|
41
|
-
label: "MCP · wincu(dsh-computer-use-win)",
|
|
42
|
-
repo: "https://github.com/Yu-tao-Li/dsh-computer-use-win"
|
|
43
|
-
},
|
|
44
|
-
{
|
|
45
|
-
id: "qqbot-extension",
|
|
46
|
-
kind: "extension",
|
|
47
|
-
label: "QQ 机器人扩展(框架 @zaofan/dsh-qqbot)",
|
|
48
|
-
repo: "https://github.com/zaofan-make/dsh-qqbot"
|
|
49
|
-
}
|
|
50
|
-
].map((entry) => [entry.id, entry]));
|
|
51
|
-
/**
|
|
52
|
-
* Tool names the released Host owns, calibrated against dsh 0.2.1-rc.2.
|
|
53
|
-
*
|
|
54
|
-
* A name outside the catalog would otherwise be reported as core, which is the
|
|
55
|
-
* one guess a reader could act on wrongly; it resolves to `unknown` instead.
|
|
56
|
-
*/
|
|
57
|
-
const CORE_TOOLS = /* @__PURE__ */ new Set([
|
|
58
|
-
"ask_user_question",
|
|
59
|
-
"create_goal",
|
|
60
|
-
"create_skill",
|
|
61
|
-
"create_worktree",
|
|
62
|
-
"edit",
|
|
63
|
-
"exit_plan_mode",
|
|
64
|
-
"get_goal",
|
|
65
|
-
"glob",
|
|
66
|
-
"grep",
|
|
67
|
-
"interrupt_agent",
|
|
68
|
-
"job_kill",
|
|
69
|
-
"job_list",
|
|
70
|
-
"job_output",
|
|
71
|
-
"list_agents",
|
|
72
|
-
"list_mcp_resource_templates",
|
|
73
|
-
"list_mcp_resources",
|
|
74
|
-
"load_workspace_dependencies",
|
|
75
|
-
"present",
|
|
76
|
-
"pwsh",
|
|
77
|
-
"ralph",
|
|
78
|
-
"read",
|
|
79
|
-
"read_image",
|
|
80
|
-
"read_mcp_resource",
|
|
81
|
-
"schedule_create",
|
|
82
|
-
"schedule_delete",
|
|
83
|
-
"schedule_list",
|
|
84
|
-
"schedule_update",
|
|
85
|
-
"send_message",
|
|
86
|
-
"session_event_read",
|
|
87
|
-
"session_event_search",
|
|
88
|
-
"session_event_trace",
|
|
89
|
-
"session_search",
|
|
90
|
-
"session_trace",
|
|
91
|
-
"sidebar_open",
|
|
92
|
-
"skill",
|
|
93
|
-
"spawn_teammate",
|
|
94
|
-
"subagent",
|
|
95
|
-
"subagent_fork",
|
|
96
|
-
"team_task_create",
|
|
97
|
-
"team_task_get",
|
|
98
|
-
"team_task_list",
|
|
99
|
-
"team_task_update",
|
|
100
|
-
"terminal_close",
|
|
101
|
-
"terminal_list",
|
|
102
|
-
"terminal_open",
|
|
103
|
-
"terminal_read",
|
|
104
|
-
"terminal_send",
|
|
105
|
-
"terminal_signal",
|
|
106
|
-
"todo_write",
|
|
107
|
-
"update_goal",
|
|
108
|
-
"wait_agent",
|
|
109
|
-
"web_fetch",
|
|
110
|
-
"web_search",
|
|
111
|
-
"web_search_pro",
|
|
112
|
-
"workflow",
|
|
113
|
-
"working_directory",
|
|
114
|
-
"write"
|
|
115
|
-
]);
|
|
116
|
-
/** MCP server name → catalog id, for the servers this allowlist knows. */
|
|
117
|
-
const MCP_SERVERS = /* @__PURE__ */ new Map([["wincu", "mcp:wincu"]]);
|
|
118
|
-
/** Plugin identity by tool-name prefix (checked before the core catalog). */
|
|
119
|
-
const PLUGIN_PREFIXES = [
|
|
120
|
-
["bcdp_", "dsh-browser-cdp"],
|
|
121
|
-
["browser_window_", "dsh-browser-cdp"],
|
|
122
|
-
["ops_", "dsh-ops"],
|
|
123
|
-
["memory_", "dsh-auto-memory"]
|
|
124
|
-
];
|
|
125
|
-
/** Single plugin tools that carry no prefix. */
|
|
126
|
-
const PLUGIN_TOOLS = /* @__PURE__ */ new Map([["generate_image", "dsh-model-switch"]]);
|
|
127
|
-
/** `<base>__<owner>` — the extension-tool naming the QQ bot framework uses. */
|
|
128
|
-
const EXTENSION_TOOL = /^([A-Za-z0-9_-]+)__(.+)$/;
|
|
129
|
-
/**
|
|
130
|
-
* Default allowlist: every pure-read tool this deployment exposes plus the
|
|
131
|
-
* no-side-effect and autonomy entries the user explicitly released, calibrated
|
|
132
|
-
* on a live desktop profile (105 tools) at dsh 0.2.1-rc.2.
|
|
133
|
-
*
|
|
134
|
-
* Grouped by origin so a reader can trace each entry through {@link SOURCE_CATALOG}.
|
|
135
|
-
* Entries ending in `*` are patterns: the QQ bot extension suffixes its tools with
|
|
136
|
-
* the bot's own name, so `sessions_list__*` keeps working when the persona is
|
|
137
|
-
* renamed.
|
|
138
|
-
*
|
|
139
|
-
* Everything here follows one rule: releasing it must not let a side effect escape
|
|
140
|
-
* the reviewer. Calls that merely dispatch, ask, present, wait or navigate qualify
|
|
141
|
-
* because the work they trigger still runs under the same auto preset. Delegation
|
|
142
|
-
* tools (`subagent`, `subagent_fork`, `spawn_teammate`) deliberately stay out: a
|
|
143
|
-
* child session seeds its preset from `permissionPresets.current(parent.session)`,
|
|
144
|
-
* and this bypass answers `'custom'` for an allowlisted call in flight — releasing
|
|
145
|
-
* them would hand the child no `auto` preset at all, i.e. no review.
|
|
146
|
-
*/
|
|
147
|
-
const DEFAULT_READ_ONLY_TOOLS = [
|
|
148
|
-
"read",
|
|
149
|
-
"grep",
|
|
150
|
-
"glob",
|
|
151
|
-
"read_image",
|
|
152
|
-
"skill",
|
|
153
|
-
"web_search",
|
|
154
|
-
"web_search_pro",
|
|
155
|
-
"web_fetch",
|
|
156
|
-
"load_workspace_dependencies",
|
|
157
|
-
"ask_user_question",
|
|
158
|
-
"present",
|
|
159
|
-
"sidebar_open",
|
|
160
|
-
"exit_plan_mode",
|
|
161
|
-
"job_list",
|
|
162
|
-
"job_output",
|
|
163
|
-
"terminal_list",
|
|
164
|
-
"terminal_read",
|
|
165
|
-
"list_agents",
|
|
166
|
-
"team_task_list",
|
|
167
|
-
"team_task_get",
|
|
168
|
-
"get_goal",
|
|
169
|
-
"schedule_list",
|
|
170
|
-
"wait_agent",
|
|
171
|
-
"send_message",
|
|
172
|
-
"team_task_create",
|
|
173
|
-
"list_mcp_resources",
|
|
174
|
-
"list_mcp_resource_templates",
|
|
175
|
-
"read_mcp_resource",
|
|
176
|
-
"session_search",
|
|
177
|
-
"session_event_search",
|
|
178
|
-
"session_event_read",
|
|
179
|
-
"session_event_trace",
|
|
180
|
-
"session_trace",
|
|
181
|
-
"create_goal",
|
|
182
|
-
"schedule_create",
|
|
183
|
-
"terminal_open",
|
|
184
|
-
"ops_read_files",
|
|
185
|
-
"ops_discover_tools",
|
|
186
|
-
"bcdp_status",
|
|
187
|
-
"bcdp_help",
|
|
188
|
-
"bcdp_doctor",
|
|
189
|
-
"bcdp_snapshot",
|
|
190
|
-
"browser_window_status",
|
|
191
|
-
"memory_list",
|
|
192
|
-
"memory_read",
|
|
193
|
-
"mcp__wincu__windows_computer_use_accessibility_tree",
|
|
194
|
-
"mcp__wincu__windows_computer_use_element_info",
|
|
195
|
-
"mcp__wincu__windows_computer_use_find",
|
|
196
|
-
"mcp__wincu__windows_computer_use_health",
|
|
197
|
-
"mcp__wincu__windows_computer_use_list_windows",
|
|
198
|
-
"mcp__wincu__windows_computer_use_ocr",
|
|
199
|
-
"mcp__wincu__windows_computer_use_screenshot",
|
|
200
|
-
"mcp__wincu__windows_computer_use_snapshot",
|
|
201
|
-
"mcp__wincu__windows_computer_use_tools",
|
|
202
|
-
"mcp__wincu__windows_computer_use_wait",
|
|
203
|
-
"mcp__wincu__windows_computer_use_wait_for",
|
|
204
|
-
"sessions_list__*",
|
|
205
|
-
"bing_search__*"
|
|
206
|
-
];
|
|
207
|
-
/**
|
|
208
|
-
* Validate one allowlist entry.
|
|
209
|
-
*
|
|
210
|
-
* `*` is a suffix wildcard: the entry must keep at least one literal leading
|
|
211
|
-
* character, so a stray `*` can never turn the list into "allow everything".
|
|
212
|
-
*
|
|
213
|
-
* @param entry - the raw entry as typed in settings.
|
|
214
|
-
* @returns `ok`, or the specific problem.
|
|
215
|
-
*/
|
|
216
|
-
function validateAllowEntry(entry) {
|
|
217
|
-
const trimmed = entry.trim();
|
|
218
|
-
if (trimmed === "") return "empty";
|
|
219
|
-
if (/^\*+$/.test(trimmed)) return "bare-wildcard";
|
|
220
|
-
if (trimmed.startsWith("*")) return "leading-wildcard";
|
|
221
|
-
return "ok";
|
|
222
|
-
}
|
|
223
|
-
/**
|
|
224
|
-
* Whether a tool name matches one allowlist entry.
|
|
225
|
-
*
|
|
226
|
-
* Exact names match exactly; an entry may end in `*`, which matches any
|
|
227
|
-
* remaining characters (including none). Invalid entries never match.
|
|
228
|
-
*
|
|
229
|
-
* @param name - the tool name from `exec.name`.
|
|
230
|
-
* @param entry - one allowlist entry.
|
|
231
|
-
* @returns true when the call may skip review.
|
|
232
|
-
*/
|
|
233
|
-
function matchesAllowPattern(name, entry) {
|
|
234
|
-
if (name === "" || validateAllowEntry(entry) !== "ok") return false;
|
|
235
|
-
const trimmed = entry.trim();
|
|
236
|
-
const star = trimmed.indexOf("*");
|
|
237
|
-
if (star === -1) return name === trimmed;
|
|
238
|
-
const prefix = trimmed.slice(0, star);
|
|
239
|
-
const suffix = trimmed.slice(star + 1);
|
|
240
|
-
if (!name.startsWith(prefix) || !name.endsWith(suffix)) return false;
|
|
241
|
-
return name.length >= prefix.length + suffix.length;
|
|
242
|
-
}
|
|
243
|
-
/**
|
|
244
|
-
* Whether a tool name is covered by an allowlist.
|
|
245
|
-
* @param name - the tool name under review.
|
|
246
|
-
* @param allowlist - configured entries, patterns included.
|
|
247
|
-
* @returns true when at least one entry matches.
|
|
248
|
-
*/
|
|
249
|
-
function isAllowedByList(name, allowlist) {
|
|
250
|
-
return allowlist.some((entry) => matchesAllowPattern(name, entry));
|
|
251
|
-
}
|
|
252
|
-
/**
|
|
253
|
-
* Resolve the origin of one tool name for display.
|
|
254
|
-
*
|
|
255
|
-
* Resolution order: MCP bridge → `<tool>__<owner>` extension → plugin prefix →
|
|
256
|
-
* plugin table → core catalog → unknown. Only the first two are structural; the
|
|
257
|
-
* rest are calibrated names, so an unlisted tool is reported as unknown rather
|
|
258
|
-
* than guessed into a package.
|
|
259
|
-
*
|
|
260
|
-
* @param name - the tool name.
|
|
261
|
-
* @returns The origin, with its repository when known.
|
|
262
|
-
*/
|
|
263
|
-
function resolveToolSource(name) {
|
|
264
|
-
const trimmed = name.trim().replace(/\*+$/, "");
|
|
265
|
-
const mcp = /^mcp__([A-Za-z0-9_-]+)__/.exec(trimmed);
|
|
266
|
-
if (mcp !== null) {
|
|
267
|
-
const server = mcp[1];
|
|
268
|
-
const entry = SOURCE_BY_ID.get(MCP_SERVERS.get(server) ?? "");
|
|
269
|
-
if (entry !== void 0) return {
|
|
270
|
-
kind: "mcp",
|
|
271
|
-
label: entry.label,
|
|
272
|
-
repo: entry.repo,
|
|
273
|
-
owner: server
|
|
274
|
-
};
|
|
275
|
-
return {
|
|
276
|
-
kind: "mcp",
|
|
277
|
-
label: `MCP · ${server}`,
|
|
278
|
-
owner: server
|
|
279
|
-
};
|
|
280
|
-
}
|
|
281
|
-
const extension = EXTENSION_TOOL.exec(trimmed);
|
|
282
|
-
if (extension !== null && !trimmed.startsWith("mcp__")) {
|
|
283
|
-
const entry = SOURCE_BY_ID.get("qqbot-extension");
|
|
284
|
-
const base = extension[1];
|
|
285
|
-
const owner = extension[2];
|
|
286
|
-
return {
|
|
287
|
-
kind: "extension",
|
|
288
|
-
label: `扩展 · ${base}__${owner}`,
|
|
289
|
-
...entry === void 0 ? {} : { repo: entry.repo },
|
|
290
|
-
owner
|
|
291
|
-
};
|
|
292
|
-
}
|
|
293
|
-
if (trimmed.endsWith("__")) {
|
|
294
|
-
const entry = SOURCE_BY_ID.get("qqbot-extension");
|
|
295
|
-
return {
|
|
296
|
-
kind: "extension",
|
|
297
|
-
label: `扩展 · ${trimmed.slice(0, -2)}__*`,
|
|
298
|
-
...entry === void 0 ? {} : { repo: entry.repo },
|
|
299
|
-
owner: "*"
|
|
300
|
-
};
|
|
301
|
-
}
|
|
302
|
-
for (const [prefix, id] of PLUGIN_PREFIXES) {
|
|
303
|
-
if (!trimmed.startsWith(prefix)) continue;
|
|
304
|
-
const entry = SOURCE_BY_ID.get(id);
|
|
305
|
-
if (entry !== void 0) return {
|
|
306
|
-
kind: "plugin",
|
|
307
|
-
label: entry.label,
|
|
308
|
-
repo: entry.repo,
|
|
309
|
-
owner: id
|
|
310
|
-
};
|
|
311
|
-
}
|
|
312
|
-
const plugin = PLUGIN_TOOLS.get(trimmed);
|
|
313
|
-
if (plugin !== void 0) {
|
|
314
|
-
const entry = SOURCE_BY_ID.get(plugin);
|
|
315
|
-
if (entry !== void 0) return {
|
|
316
|
-
kind: "plugin",
|
|
317
|
-
label: entry.label,
|
|
318
|
-
repo: entry.repo,
|
|
319
|
-
owner: plugin
|
|
320
|
-
};
|
|
321
|
-
}
|
|
322
|
-
if (CORE_TOOLS.has(trimmed)) {
|
|
323
|
-
const entry = SOURCE_BY_ID.get("core");
|
|
324
|
-
return {
|
|
325
|
-
kind: "core",
|
|
326
|
-
label: entry?.label ?? "DSH 核心",
|
|
327
|
-
...entry === void 0 ? {} : { repo: entry.repo },
|
|
328
|
-
owner: "core"
|
|
329
|
-
};
|
|
330
|
-
}
|
|
331
|
-
return {
|
|
332
|
-
kind: "unknown",
|
|
333
|
-
label: "未知来源"
|
|
334
|
-
};
|
|
335
|
-
}
|
|
336
|
-
//#endregion
|
|
337
7
|
//#region lib/types/auto-sessions-state.js
|
|
338
8
|
/**
|
|
339
9
|
* Durable snapshot of the sessions that were on the Auto preset when this row
|
|
@@ -1394,4 +1064,4 @@ async function apply(ctx) {
|
|
|
1394
1064
|
}, "model-switch: release the Auto registration before anything else");
|
|
1395
1065
|
}
|
|
1396
1066
|
//#endregion
|
|
1397
|
-
export { bindAutoReviewSessionCorrelation as a, installToolCallSafetyNet as c, resolveSessionAutoReviewRoute as d, reviewLlm as f,
|
|
1067
|
+
export { bindAutoReviewSessionCorrelation as a, installToolCallSafetyNet as c, resolveSessionAutoReviewRoute as d, reviewLlm as f, autoReviewStatus as i, isReviewerInfrastructureFailure as l, autoReviewGate as n, defensivePermissionPresets as o, reviewScope as p, autoReviewRouteOf as r, inject as s, apply as t, name as u };
|
package/lib/auto-review.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { a as bindAutoReviewSessionCorrelation, c as installToolCallSafetyNet, d as resolveSessionAutoReviewRoute, f as reviewLlm, i as autoReviewStatus, l as isReviewerInfrastructureFailure, n as autoReviewGate, o as defensivePermissionPresets, p as reviewScope, r as autoReviewRouteOf, s as inject, t as apply, u as name } from "./auto-review-
|
|
1
|
+
import { a as bindAutoReviewSessionCorrelation, c as installToolCallSafetyNet, d as resolveSessionAutoReviewRoute, f as reviewLlm, i as autoReviewStatus, l as isReviewerInfrastructureFailure, n as autoReviewGate, o as defensivePermissionPresets, p as reviewScope, r as autoReviewRouteOf, s as inject, t as apply, u as name } from "./auto-review-QDEFUjT2.js";
|
|
2
2
|
export { apply, autoReviewGate, autoReviewRouteOf, autoReviewStatus, bindAutoReviewSessionCorrelation, defensivePermissionPresets, inject, installToolCallSafetyNet, isReviewerInfrastructureFailure, name, resolveSessionAutoReviewRoute, reviewLlm, reviewScope };
|