@jayyuen66/dsh-ocr-review 0.1.7 → 0.1.9
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 +325 -0
- package/LICENSE +1 -1
- package/README.md +204 -168
- package/README.zh-CN.md +209 -174
- package/THIRD_PARTY_NOTICES.md +11 -7
- package/client.js +1259 -543
- package/cordis.patch.yml +5 -3
- package/docs/DETAIL.md +28 -0
- package/docs/DETAIL.zh.md +28 -0
- package/host.js +2355 -632
- package/locale/en.json +7 -0
- package/locale/zh.json +7 -0
- package/package.json +59 -51
- package/scripts/get-cred.mjs +151 -55
package/README.zh-CN.md
CHANGED
|
@@ -1,206 +1,241 @@
|
|
|
1
|
-
|
|
1
|
+
<p align="center">
|
|
2
|
+
<img src="https://cdn.jsdelivr.net/gh/JayYuen666/dsh-ocr-review@main/icon.svg" width="96" height="96" alt="dsh-ocr-review logo" />
|
|
3
|
+
</p>
|
|
4
|
+
|
|
5
|
+
<h1 align="center">dsh-ocr-review</h1>
|
|
6
|
+
|
|
7
|
+
<p align="center"><em>把外部 `ocr`(open-code-review)CLI 封装成 dsh 的七个模型工具与一张设置卡片——CLI 由你自己装,插件只发现、核对并驱动它。</em></p>
|
|
8
|
+
|
|
9
|
+
<p align="center">
|
|
10
|
+
<a href="https://www.npmjs.com/package/@jayyuen66/dsh-ocr-review"><img src="https://img.shields.io/npm/v/@jayyuen66/dsh-ocr-review?style=flat-square&logo=npm&logoColor=white" alt="npm version" /></a>
|
|
11
|
+
<a href="https://www.npmjs.com/package/@jayyuen66/dsh-ocr-review"><img src="https://img.shields.io/npm/d18m/@jayyuen66/dsh-ocr-review?style=flat-square" alt="npm downloads (total)" /></a>
|
|
12
|
+
<a href="https://github.com/JayYuen666/dsh-ocr-review/actions/workflows/ci.yml"><img src="https://img.shields.io/github/actions/workflow/status/JayYuen666/dsh-ocr-review/ci.yml?branch=main&style=flat-square&label=ci" alt="ci" /></a>
|
|
13
|
+
<img src="https://img.shields.io/badge/license-MIT-4c1?style=flat-square" alt="MIT" />
|
|
14
|
+
<img src="https://img.shields.io/badge/node-%3E%3D22.12-4c1?style=flat-square&logo=nodedotjs&logoColor=white" alt="node" />
|
|
15
|
+
<img src="https://img.shields.io/badge/dsh-%5E0.2.1--rc.3-658EFF?style=flat-square" alt="dsh" />
|
|
16
|
+
<a href="https://github.com/deepseek-ai/deepseek-harness"><img src="https://img.shields.io/badge/powered_by_dsh-4D6BFE?style=flat-square&logo=deepseek&logoColor=white" alt="powered by dsh" /></a>
|
|
17
|
+
</p>
|
|
18
|
+
|
|
19
|
+
<p align="center">
|
|
20
|
+
<img src="https://skillicons.dev/icons?i=typescript,nodejs,react,vitest,githubactions" alt="tech stack" />
|
|
21
|
+
</p>
|
|
22
|
+
|
|
23
|
+
<p align="center">
|
|
24
|
+
<a href="https://github.com/JayYuen666"><img src="https://img.shields.io/badge/GitHub-JayYuen666-181717?style=flat-square&logo=github&logoColor=white" alt="GitHub" /></a>
|
|
25
|
+
<a href="mailto:cqwkkj@gmail.com"><img src="https://img.shields.io/badge/Email-cqwkkj@gmail.com-EA4335?style=flat-square&logo=gmail&logoColor=white" alt="Email" /></a>
|
|
26
|
+
<a href="https://twitter.com/JayYuen666"><img src="https://img.shields.io/badge/Twitter-X%2FJayYuen666-000000?style=flat-square&logo=x&logoColor=white" alt="Twitter/X" /></a>
|
|
27
|
+
<a href="./README.md"><img src="https://img.shields.io/badge/lang-English-658EFF?style=flat-square" alt="English" /></a>
|
|
28
|
+
</p>
|
|
29
|
+
|
|
30
|
+
**一个 [dsh](https://github.com/deepseek-ai/deepseek-harness) 代码审查桥:七个模型工具(`ocr_review`、`ocr_scan`、delegate preview 与 rule、`ocr_session`、`ocr_rules_check`、`ocr_llm`)加一张设置卡片,把宿主的 provider/model 选择落到外部 CLI 自己的配置里——写进去的是运行期命令,绝不是明文 key。**
|
|
31
|
+
|
|
32
|
+
## <img src="https://api.iconify.design/lucide/file-text.svg?color=%23658EFF&height=22" height="22" width="22" align="absmiddle" alt="" /> 目录
|
|
33
|
+
|
|
34
|
+
- [它做什么](#它做什么)
|
|
35
|
+
- [安装](#安装)
|
|
36
|
+
- [外部 CLI](#外部-cli)
|
|
37
|
+
- [确认它真的在工作](#确认它真的在工作)
|
|
38
|
+
- [它不提供什么](#它不提供什么)
|
|
39
|
+
- [在 dsh 里启用](#在-dsh-里启用)
|
|
40
|
+
- [提供给模型的工具](#提供给模型的工具)
|
|
41
|
+
- [设置项](#设置项)
|
|
42
|
+
- [对外接口](#对外接口)
|
|
43
|
+
- [凭据与 OCR 配置文件](#凭据与-ocr-配置文件)
|
|
44
|
+
- [后台运行与官方作业](#后台运行与官方作业)
|
|
45
|
+
- [数据与隐私](#数据与隐私)
|
|
46
|
+
- [已知边界](#已知边界)
|
|
47
|
+
- [常见问题](#常见问题)
|
|
48
|
+
- [开发](#开发)
|
|
49
|
+
- [许可](#许可)
|
|
50
|
+
|
|
51
|
+
## <img src="https://api.iconify.design/lucide/shield.svg?color=%23658EFF&height=22" height="22" width="22" align="absmiddle" alt="" /> 它做什么
|
|
52
|
+
|
|
53
|
+
- **设置卡还承载两块管理面**:可校验的 MCP servers JSON 编辑器(保存只改 `mcp_servers`),以及报告 `ocr auth` 登录态并切换 OCR provider/model 的 ChatGPT 区。两块都由人操作,不是模型工具(stdio MCP server 会执行命令,OAuth 登录需要浏览器与本地回调)。
|
|
54
|
+
- **把外部 `ocr`(open-code-review)CLI 封装成七个模型工具。** 宿主对工具入参零校验,形状、类型与枚举闸全在本包内:用户可控字符串一律单引号转义,枚举一律白名单钳制,错类型直接报错——绝不静默收窄或放宽审查范围。
|
|
55
|
+
- **一张设置卡片**(client 半)从宿主自己的 `llm-pi-ai` 设置条目取 provider/model 清单、从宿主凭据服务取 key 状态。两个服务缺席时卡片显示降级原因,工具与设置照常可用。
|
|
56
|
+
- **应用一次选择写的是 CLI 自己的 `~/.opencodereview/config.json`**——写进去的是 `api_key_cmd` 命令,OCR 运行期经它读宿主凭据 ref;任何地方都不落明文 key。
|
|
57
|
+
- **评审结果是一份结构化摘要,字段分两套口径**:OCR 审出了什么(`status`/`aggregation`/`topComments`/`warnings`),以及这一场有没有真把选中的文件审完(`coverage`/`budgetExceeded`/`toolCalls`)。CLI 以 `--audience agent` 被调用,进度输出被它压掉——后一套口径只能从这些字段里读。
|
|
58
|
+
- **CLI 可得性只有一份判据**(`lib/cli.ts` 的 `resolveOcrAvailability`):纯读文件系统、绝不起进程、每次调用现读。设置卡状态行、插件详情页徽标与启用指引渲染的都是这同一份答案,「用的是哪一份」不许有三套说法。
|
|
59
|
+
- **后台运行(`wait: false`)是官方宿主作业**:`job_list` / `job_output` / `job_kill` 看得见、读得到、也停得掉一场超出工具调用生命周期的评审。
|
|
60
|
+
|
|
61
|
+
## <img src="https://api.iconify.design/lucide/package.svg?color=%23658EFF&height=22" height="22" width="22" align="absmiddle" alt="" /> 安装
|
|
2
62
|
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
- 把外部 `ocr`(open-code-review)CLI 封装成 dsh 的 5 个模型工具 + 1 张 web 设置卡片;宿主对工具入参零校验,形状与类型闸全在本包内做。
|
|
8
|
-
- Host 半(`host.ts`)声明 6 个 `.volatile()` 设置项(命名空间是隐式的:宿主按 profile 条目 id `ocr-review` 投影表单,插件不调 `settings.register`)。
|
|
9
|
-
- 同时注册 5 个模型工具、一段 systemPrompt 路由(`ocr-review-routing`,order 1555)与 `ocrReview` 命名空间下的 5 个方法。
|
|
10
|
-
- Client 半(`src/client-entry.ts` → `client.js`)是设置卡片,provider/model 取自设置服务的 `llm-pi-ai` 命名空间;此外还贡献三处只读显示:插件详情页标题旁的徽标、页面内容之下的区块,以及启用本包那一刻的指引——三处说的都是「这台机器上的外部 CLI 是什么状态」。
|
|
11
|
-
- 卡片把 provider/model 落盘到外部 ocr CLI 自己的 `~/.opencodereview/config.json`,写进去的是 `api_key_cmd` 命令而非明文 key。
|
|
12
|
-
- 评审结果回给模型的是一份结构化摘要,字段分两套口径:OCR 审出了什么(`status`/`aggregation`/`topComments`/`warnings`),以及这一场有没有真把选中的文件审完(`coverage`/`budgetExceeded`/`toolCalls`)。`--audience agent` 下 CLI 把进度行写进 `io.Discard`,后一套口径只能从这些字段里读。
|
|
13
|
-
|
|
14
|
-
## 前置条件(外部 CLI)
|
|
15
|
-
|
|
16
|
-
- 本包不 import 任何 OCR 库,只起进程:`ocr review` / `ocr scan` / `ocr delegate preview` / `ocr delegate rule` / `ocr session` / `ocr llm test`。
|
|
17
|
-
- 命令按 **1.13.0** 源码逐一核对(`lib/cli.ts`、`lib/parse.ts` 头注释),形如 `ocr review --audience agent --format json --effort medium --output <临时文件>`。这一版号只写在 package.json 的 `ocrCliVersion` 一处,`lib/cli.ts` 里的 `EXPECTED_OCR_CLI_VERSION` 是它在本包代码里的唯一镜像:`test/publish-manifest.test.ts` 断言两处逐字相等,`test/readme-parity.test.ts` 断言这一句写的也是它。「README 教用户装 A、代码却按 B 核对」这种两边各自自洽的错,只有并排断言才拦得住。
|
|
18
|
-
- 多值 `--exclude`/`--path` 合并成一个逗号分隔 flag,`--format` 只认 json/text/sarif。
|
|
19
|
-
- **CLI 由你自己装。** 本包刻意不带 `optionalDependencies`:把 `@alibaba-group/open-code-review` 列成依赖,一是让「装一个插件」顺带改了用户的全局工具链,二是那条绝对路径解析得比 PATH 上用户自装那份更靠前——用户在终端升了级,插件仍在跑随包那一份旧版,卡片报的版本与他实际跑的永远对不上,而且没有任何线索指向「机器上有两份」。
|
|
20
|
-
- 于是命令词的解析顺序是:PATH 上第一个能命中的 `ocr`(取它的绝对路径),其次才是本包依赖树里那一份兜底,两处都没有候选时才是裸 `ocr`(也就是下面那条拒绝要处理的情形)。设置页状态行、五个工具的前置短路、真正下发的那条命令词都读这同一份判据,「用的是哪一份」不许有三套说法。Windows 上随包兜底整体跳过(`bin/ocr.js` 是 shebang 脚本,pwsh/cmd 无法直执行),命令词也保持裸 `ocr`——带反斜杠的绝对路径在 `cmd` 里不靠单引号成对。
|
|
21
|
-
- 装法两条任选,npm 那条带得上核对版本,brew 那条带不上:
|
|
22
|
-
|
|
23
|
-
```sh
|
|
24
|
-
brew install open-code-review # formula 只跟上游最新版
|
|
25
|
-
npm i -g @alibaba-group/open-code-review@1.13.0 # 钉在本包核对的那一版
|
|
26
|
-
```
|
|
63
|
+
```sh
|
|
64
|
+
dsh plugin --profile web add @jayyuen66/dsh-ocr-review
|
|
65
|
+
```
|
|
27
66
|
|
|
28
|
-
|
|
29
|
-
- 两条路都没有候选时,工具在起进程之前就拒绝,并把带版本的装法一起交给模型;如果判据拿到候选、子进程那边却执行不了(exit 127),工具报「ocr 命令不存在」并指到卡片上外部 CLI 那一行。
|
|
30
|
-
- 平台:目标平台是 macOS / Linux。进程收割(`ocr_review` / `ocr_scan` 的 reaper 守护)依赖 POSIX 工具链——bash 的 trap 与作业控制,加上 `ps` / `pgrep` / `kill` 的进程组语义;自定义 `ocrConfigPath` 背后的 `HOME=` 赋值前缀同样是 POSIX 专属。Windows 上这层整体缺席:本包按 `process.platform` 直接放行裸命令(不收割但能跑),并跳过随包 launcher(Windows 需 PATH 上的全局 `ocr`);`api_key_cmd` 在 Windows 按双引号转义写出(ocr 在那边经 `cmd.exe` 跑凭据命令)。代价是宿主硬退出后 OCR 可能留下孤儿进程。
|
|
31
|
-
- provider 清单与 key 状态走宿主官方通道 `ctx.settings.describe()`(`llm-pi-ai` 那条的 `value.providers`)与 `ctx.credentials`。
|
|
32
|
-
- 两者缺席时卡片显示降级原因,工具与设置照常可用。
|
|
33
|
-
- 宿主版本要求 `>= 0.2.1-rc.2`:这条写在 `engines.dsh`,属于文档性声明,装载器与安装器都不读它。真正拦安装的是那四枚 peer 的精确钉:宿主拿运行时版本逐条比对 peer 范围(预发布号参与比对),不合就以 `incompatible-version` 拒装。跑 dsh 0.2.1-rc.2 的机器要先升 dsh,或在 profile 的 `compatibility.json` 里给本包登记豁免(`dsh plugin --profile <profile> allow-version <name@version> --dsh-version <运行时版本> --accept-risk`)。本包也不从 `@deepseek-ai/dsh` 主包导入任何符号(服务面全部来自 `@deepseek-ai/dsh-*` 子包),所以它在任何一张依赖表里都不出现。
|
|
67
|
+
卸载用 `dsh plugin --profile web remove @jayyuen66/dsh-ocr-review`。包在公共 npm 上,安装不需要凭据。
|
|
34
68
|
|
|
35
|
-
|
|
69
|
+
- **升级已装的那一份要「先 remove 再 add」。** profile 跑着 HMR(出厂那几个都跑)时,`add` 一个 profile 已经依赖着的包会在 pnpm 动手之前就被拒(`already-installed`)——先 `remove` 再 `add` 目标版本,新版不必重启就起跑。没跑 HMR 时同一个 `add` 照样走 pnpm,报 `restart-required`。
|
|
70
|
+
- **要求 Node.js `>= 22.12`,宿主 dsh 在 `0.2.1-rc.3` 线上。** 宿主只读 `engines.dsh`(`^0.2.1-rc.3`)并独立裁决,预发布号参与比较。不合的宿主要显式登记风险豁免:`dsh plugin --profile <p> allow-version @jayyuen66/dsh-ocr-review@<版本> --dsh-version <确切运行版本> --accept-risk`。支持窗口是滚动的:本包在发布时最近的三个已发布宿主版本上逐版取证,窗口滚动后重新取证,不把这一句里的版本号当长期承诺。
|
|
71
|
+
- **`dependencies` 里不放任何 `@deepseek-ai/*`,这是契约**(`test/publish-manifest.test.ts` 钉着)。消费方 profile 用 `nodeLinker: hoisted` 与 `autoInstallPeers: false` 安装,宿主包进了那张表就会落成真实目录,与宿主进程已加载的那份并存。`@deepseek-ai/dsh-tools` 的调度器键是普通 `Symbol`(不是 `Symbol.for`),符号身份按实例计算——那个 profile 里**每一次原生工具调用都抛**,而本包的构建、类型检查与覆盖率门在此前一路绿。
|
|
72
|
+
- **`host.js` 以值导入的五枚宿主包是非 optional 的 peer**:`@deepseek-ai/schemastery`(宿主 fork——`.volatile()` 的解析只在它有实现)、`@deepseek-ai/dsh-credentials`、`@deepseek-ai/dsh-home-paths`、`@deepseek-ai/dsh-atomic-write` 与 `@deepseek-ai/dsh-typert-protocol`(Remote 的 Service 基类)。五枚同时以同一钉版另列进 `devDependencies`,本仓自己的类型检查才解析得到;构建对 manifest 三张表一律外部化,产物里保持裸说明符。
|
|
73
|
+
- **发布面**:`host.js`、`client.js`、`cordis.patch.yml`、`scripts/`、`icon.svg`、`CHANGELOG.md` 与 `THIRD_PARTY_NOTICES.md`。`prepack` 重建两个 bundle,发出去的永远是当前源码的产物。
|
|
36
74
|
|
|
37
|
-
|
|
75
|
+
### <img src="https://api.iconify.design/lucide/arrow-down-to-line.svg?color=%23658EFF&height=22" height="22" width="22" align="absmiddle" alt="" /> shared 的版本下限
|
|
38
76
|
|
|
39
|
-
|
|
40
|
-
| ------ | -------------------- |
|
|
41
|
-
| 五个工具 | 起任何进程之前先现读一次。两条路都没有候选就直接拒绝,模型看到的是「两条路都没找到 + 这么装(命令里带着核对版本)」,而不是子进程 exit 127 之后反推出来的那句「命令不存在」。每次调用现读、不按进程缓存:装完 CLI 直接重试即可,不必重启 dsh |
|
|
42
|
-
| 设置卡片 | provider 表单**之外**的一行状态(「这台机器有没有 ocr」与「宿主能不能列出 provider」是两件事,缺 CLI 的机器必须连原因都看得见):用的是哪一份、什么装法、本插件按哪一版核对、最近一次实测是哪一版,没装时再附一句装法;外加一枚「检测版本」按钮 |
|
|
43
|
-
| 插件详情页 | 标题旁一只徽标 + 页面自身内容之下一个区块;页面说的不是本包、或状态还没回来时两处都渲染 null。实测过且与核对版本不一致时,徽标改口说「版本不一致」,来源那一档让位 |
|
|
44
|
-
| 启用之后 | 启用指引只在判据为 `none` 时说话,说的就是带版本的装法——那是第三方 bundle 能渲染的最外侧位置 |
|
|
77
|
+
如果你的 profile 用 pnpm `overrides` 把 `@jayyuen66/dsh-plugin-shared` 钉在某个版本,那个钉住的值必须不低于本包声明的版本。钉得更低就会装到一份缺少本包运行期所导入的名字的产物,宿主起来时报 `N entries did not activate` 加 `does not provide an export named ...`——包装得上、永远不生效,而各仓单仓 CI 看不见这一类。
|
|
45
78
|
|
|
46
|
-
|
|
47
|
-
- 三处显示面读的都是 `providers()` 里同一个 `ocrBinary` 字段,且都不在本地自己算可得性、判装法、写装法命令:判据算三份就会分叉,命令写两处就会漂成「卡片教的版本与插件核对的版本不是一版」。
|
|
48
|
-
- **版本号不是白来的**:取版本要 spawn `ocr version`。跑它的时机有两处——按下卡片上的「检测版本」,以及 `startupVerify` 开着时装载期那一次(管它的是同一条开关,因为那条设置的判据就是「装载期允不允许起进程」)。页面渲染时绝不起进程:`providers()` 只交最近一次实测到的那个值,没测过就是 `null`,卡片于是只说「本插件按 1.13.0 核对」,不替你编一个本机版本。
|
|
49
|
-
- **版本对不上既显示也说出口**:回执那一行把两个数字并列,徽标改口,`ocr_review` / `ocr_scan` 的摘要 `hint` 尾部多一句「这份结果不是按核对版本跑出来的」,让模型也读到。它从不当成硬失败——新版 CLI 通常照样能用——本包也不替你执行升级:给的那条命令按那份 CLI 自己的来源说(formula 说 `brew upgrade open-code-review`,全局包说 `npm i -g …@<核对版本>`),来源判不出时按部署偏好说,并且始终把「brew 钉不住版本」那句一并说了。
|
|
50
|
-
- 回执在版本行之下附上 CLI 自己的输出,并剥掉终端控制序列(上游 launcher 那句「有新版本」的颜色码是硬编码的,而且打在 JS 包装层,`--color never` 管不到它)——要给人复制的那行是 `npm i -g …`,复制时不该拖着转义字节。一次来回走完后卡片会重读载荷,让状态行与刚取到的版本描述的是同一时刻(页面开着的时候装上 CLI,那一行也不会再跟回执自相矛盾)。本包刻意不提供更新动作,也不接剪贴板 API(非安全上下文会静默失败,看上去像按钮没反应)。
|
|
51
|
-
- **上游会自己升级**:`ocr` 的 npm 包装层会在调用过程中自行跑 `scripts/update.js`(默认 18 分钟冷却 + pid 锁),而那个脚本执行的是 `npm i -g @alibaba-group/open-code-review@<latest>`。部署项 `ocrNoAutoUpdate` 置真时,本包起的每一条 `ocr` 命令都带 `OCR_NO_UPDATE=1`,于是一场评审不会中途改动你的全局 npm;默认为假,即保持上游行为。版本探测无论这个开关怎么设都会带上该变量——读状态不该有写侧副作用。launcher 那句「有新版本」提示写在 `OCR_NO_UPDATE` 那道闸**之前**,所以它照样会出现在回执文本里。
|
|
79
|
+
## <img src="https://api.iconify.design/lucide/terminal.svg?color=%23658EFF&height=22" height="22" width="22" align="absmiddle" alt="" /> 外部 CLI
|
|
52
80
|
|
|
53
|
-
|
|
81
|
+
本包只 spawn `ocr`,从不安装或升级它。命令契约按 **1.13.3** 核对(`lib/cli.ts` 的 `EXPECTED_OCR_CLI_VERSION`,版本号只在 package.json 的 `ocrCliVersion` 声明一次——测试把 manifest、代码常量与两侧 README 钉成同一个串)。
|
|
54
82
|
|
|
55
83
|
```sh
|
|
56
|
-
|
|
84
|
+
brew install open-code-review # formula 只跟上游最新版
|
|
85
|
+
npm i -g @alibaba-group/open-code-review@1.13.3 # 钉在本包核对的那一版
|
|
57
86
|
```
|
|
58
87
|
|
|
59
|
-
-
|
|
60
|
-
-
|
|
61
|
-
-
|
|
88
|
+
- **brew 钉不住版本。** `homebrew/core` 里只有一份 stable formula、没有版本化变体,`brew install` / `brew upgrade` 拿到的永远是上游最新。带得上核对版本的只有 npm 那条。
|
|
89
|
+
- **PATH 优先,拒绝也说人话。** 命令词解析先取 PATH 上第一个 `ocr`,其次本包依赖树里那份兜底(Windows 整体跳过——shebang 脚本 pwsh/cmd 执行不了);两处都没有时,工具在起进程之前就拒绝,并把带版本的装法交给模型。「怎么装上的」看 bin 软链真正指向的文件:落在 `node_modules` 下是 npm 一类,落在 `Cellar` / `Homebrew` 下是 formula,都不是就报「未识别」而不猜。
|
|
90
|
+
- **版本是量出来的,不是猜出来的。** 读版本要 spawn 一次 `ocr version`(15 秒墙钟,恒定带 `OCR_NO_UPDATE=1`)——两处会跑:卡片上的「检测版本」按钮,以及 `startupVerify` 开着时装载期那一次。页面渲染绝不起进程:卡片只显示最近一次测量,没测过就不显示。版本对不上时两个数字并列、徽标改口、摘要 `hint` 加一句说明;从不当成硬失败,本包也不执行任何安装动作。
|
|
91
|
+
- **上游会自己升级。** npm 包装层会在调用过程中自行执行 `npm i -g @alibaba-group/open-code-review@<latest>`。版本探测恒定拦住这条路;`ocrNoAutoUpdate` 再把拦截扩到本包起的每一条命令(见「设置项」)。
|
|
92
|
+
- **从随包分发过 CLI 的版本升上来**(`optionalDependencies`,0.1.5-rc 及更早):什么都不必做——现在 PATH 优先,旧的那份不再遮蔽你自装的。想清掉 profile 依赖树里那份,在该 profile 目录下移除该包,并删掉当初写在它 `pnpm-workspace.yaml` 里的 `allowBuilds` 条目。
|
|
93
|
+
- **平台。** 目标是 macOS 与 Linux:进程收割与自定义 `ocrConfigPath` 背后的 `HOME=` 注入都是 POSIX 专属。Windows 按裸命令执行、不收割(宿主硬退出可能留下孤儿 OCR 进程),且要求 PATH 上有全局 `ocr`。
|
|
62
94
|
|
|
95
|
+
## <img src="https://api.iconify.design/lucide/circle-check.svg?color=%23658EFF&height=22" height="22" width="22" align="absmiddle" alt="" /> 确认它真的在工作
|
|
63
96
|
|
|
64
|
-
|
|
97
|
+
1. **层已挂载**:`dsh --profile web --dump-config` 末尾有本包的层行(`# == @jayyuen66/dsh-ocr-review`)。
|
|
98
|
+
- 这条命令是唯一被认的「层进了栈」判据,而且它**不是只读的**——会把该 profile 的根装配文件重写一遍。层行从 stdout 读、stderr 另行检查:未匹配的 patch 目标只出现在 stderr,光看退出码什么也证明不了。`# == <层>` 与 `# == <层>, patched by <路径>` 两种形态都要认。
|
|
99
|
+
2. **卡片渲染**:设置页出现本包卡片,外部 CLI 那一行写明用的是哪一份、什么装法、本插件按哪一版核对。
|
|
100
|
+
3. **检测版本可用**:按下后跑一次 `ocr version`,把实测版本填进那一行——失败时点名是哪一档(找不到命令词、非零退出、超时、读不出版本号)。
|
|
101
|
+
4. **没有 CLI 时工具答得诚实**:机器上没有 `ocr` 时,`ocr_review` 在起进程之前就拒绝,并返回带核对版本的装法命令——而不是让模型去反推一个 exit 127。
|
|
65
102
|
|
|
66
|
-
|
|
103
|
+
## <img src="https://api.iconify.design/lucide/circle-slash.svg?color=%23658EFF&height=22" height="22" width="22" align="absmiddle" alt="" /> 它不提供什么
|
|
67
104
|
|
|
68
|
-
|
|
105
|
+
- **它不安装、不升级 CLI。** brew/npm 命令只展示、不执行;没有更新动作,也不接剪贴板 API(非安全上下文会静默失败,看上去像按钮没反应)。
|
|
106
|
+
- **没有自己的 HTTP 路由。** 数据面是一枚官方 Typert Remote 命名空间(`ocrReview`),经宿主 `/api` 网关到达;认证、Host / DNS 重绑定 / Origin 判据与请求体上限都是网关的。本包没有 CSRF token、没有 body 上限,也没有路由释放器。
|
|
107
|
+
- **没有 CLI 子命令。** 不存在 `dsh ocr …`。
|
|
108
|
+
- **不读以下范围之外的文件**:CLI 配置路径、自己创建的临时文件、以及宿主交给它的设置 / 凭据服务。
|
|
109
|
+
- 它*确实*消费的:宿主 `settings` 与 `credentials` 服务(provider 清单、key 状态)、`shell`(每一条 `ocr` 子进程)、`jobs`(后台运行)与 `systemPrompt`(一段路由)。settings 或 credentials 缺席只降级卡片——工具照常可用。
|
|
69
110
|
|
|
70
|
-
|
|
111
|
+
## <img src="https://api.iconify.design/lucide/plug.svg?color=%23658EFF&height=22" height="22" width="22" align="absmiddle" alt="" /> 在 dsh 里启用
|
|
71
112
|
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
113
|
+
- `package.json` 的 `dsh.bundle.patch` 指向 `cordis.patch.yml`,其唯一注册行是 `- id: ocr-review`、`name` 为裸包名——宿主只按裸包名扫描 client 半。
|
|
114
|
+
- 卡片要 web profile(`dsh.client.platform: web`、`immediately: true`)。九个 `ocrReview` 方法由 apply fiber 无条件注册,宿主的 web 层从不起(如 TUI)时工具与设置照常在。
|
|
115
|
+
- 网关只把方法暴露给本 profile 的客户端;本包不在它前面再加一层。
|
|
116
|
+
- 部署默认写在注册行的 `config:` 上(cordis 按导出的 `Config` schema 校验);优先级:设置卡运行时值 > 行 config > 内置默认。
|
|
76
117
|
|
|
77
|
-
|
|
78
|
-
- **本包不执行任何一条。** 版本探测恒定带 `OCR_NO_UPDATE=1`,读状态不许顺带装东西;`ocrNoAutoUpdate` 再把这条覆盖到本包起的每一条命令。
|
|
79
|
-
- **换版命令按那份 CLI 自己的来源给**:formula 给 `brew upgrade open-code-review`,全局包给 `npm i -g @alibaba-group/open-code-review@<核对版本>`。来源判不出来(手工 `cp` 到 `~/bin`、`npx`、别的前缀)就按部署项 `ocrInstallHint` 说,不猜。
|
|
80
|
-
- **从随包分发过 CLI 的版本升上来**(`optionalDependencies` 那几版,0.1.5-rc 及更早):什么都不必做——现在 PATH 上的那份优先,那份旧的不再遮蔽它。想把 profile 依赖树里那份清掉,在该 profile 目录(`<dsh 数据目录>` 下的 `profiles/<profile>/`)执行 `pnpm remove @alibaba-group/open-code-review`,或重装这个 profile;当初为它写的 `allowBuilds: {'@alibaba-group/open-code-review': true}` 也可以一并删掉。
|
|
81
|
-
- **`ERR_PNPM_IGNORED_BUILDS` 不再来自本包。** 之前会撞上,是因为上游包装层带一个 `postinstall`(`scripts/install.js`),而 pnpm 10+ 默认不执行依赖的构建脚本。本包现在没有需要跑脚本的依赖,这条报错只可能来自别的包——那种情况下宿主的审批流程照旧可用(Web 插件页的「允许这些脚本并重试」,或在对话里明确同意后由 Agent 经 `install_bundle` 的 `approvedBuilds` 代为授权;宿主只校验待决定的包名,不核实对话里的批准,所以仍需你明确同意)。
|
|
82
|
-
- `dependencies` 里不放任何 `@deepseek-ai/*`,这不是风格偏好。本包的消费方是 dsh 插件,被装进 profile(`nodeLinker: hoisted`、`autoInstallPeers: false`),只要宿主包出现在 `dependencies`,pnpm 就会把它在那颗 profile 里落成**真实目录**,与宿主进程已经加载的那份并存。而 `@deepseek-ai/dsh-tools` 的 `TOOL_RUNTIME_SCHEDULER` 是普通 `Symbol`(不是 `Symbol.for`),符号身份按模块实例计算——宿主 `dsh-agent-loop` 拿自己那份的 Symbol 去读由副本挂载出来的 `ToolRuntime`,得到 `undefined`,于是**每一次原生工具调用都抛** `Cannot read properties of undefined (reading 'prepare')`,整个 profile 的工具一起失效。本包的构建、类型检查与测试在这之前全部照绿,所以判据只能由 `test/publish-manifest.test.ts` 落在 manifest 面。
|
|
83
|
-
- 产物里以**值**导入的四枚宿主包是非 optional 的 `peerDependencies`:`@deepseek-ai/schemastery`(宿主 fork 的 schemastery,`.volatile()` 的解析只在它有实现)、`@deepseek-ai/dsh-credentials`、`@deepseek-ai/dsh-home-paths`、`@deepseek-ai/dsh-atomic-write`。运行期由宿主在场提供,而 profile 不装 peer,所以不产生副本;`build-host.mjs` 对 `dependencies`、`peerDependencies` 与 `optionalDependencies` 三张表一律外部化,`host.js` 里的裸说明符因此一字不变。
|
|
84
|
-
- 这四枚同时另列一份进 `devDependencies`——那才是本包自己的 typecheck、build、test 解析得到它们的方式。其余 `@deepseek-ai/*` 全是 type-only(构建即擦除,`host.js` 里不留说明符),只留在 `devDependencies`。
|
|
85
|
-
- `dependencies` 剩下的确实是本包自己的运行期代码:`@jayyuen66/dsh-plugin-shared` 与 `js-yaml`(后者只被 `scripts/get-cred.mjs` 用)。
|
|
86
|
-
|
|
87
|
-
## 在 dsh 里启用
|
|
88
|
-
|
|
89
|
-
- 包内 `cordis.patch.yml` 声明 `- id: ocr-review` / `name: "@jayyuen66/dsh-ocr-review"`,由 `package.json` 的 `dsh.bundle.patch` 指向。
|
|
90
|
-
- `dsh plugin --profile web add/remove` 负责登记与摘除,改完重启 dsh。
|
|
91
|
-
- 卡片要 web profile(`dsh.client.platform: web`、`immediately: true`)。
|
|
92
|
-
- 五个 `ocrReview` 方法由 `installOcrRemote` 注册在 apply fiber 上(无条件):它们不依赖任何可选宿主服务,所以宿主没有 web 层(如 TUI)时这五个方法照样在,工具与设置面照常可用。
|
|
93
|
-
- 网关只把方法暴露给**本 profile 的客户端**,来源校验与鉴权是它自己的事,本包因此没有 CSRF token、没有 body 上限,也不再自带路由释放器。
|
|
94
|
-
- 部署默认可写在 profile 注册行的 `config:` 上(cordis 按导出的 `Config` schema 校验并填默认),优先级:设置卡运行时值 > 行 config > 内置默认。
|
|
95
|
-
|
|
96
|
-
## 提供给模型的工具
|
|
97
|
-
|
|
98
|
-
| 工具 | 入参与约束 |
|
|
99
|
-
| -------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
100
|
-
| `ocr_review` | repo(绝对路径,缺省=当前会话工作区)、scope workspace/commit/branch(branch 需同时给 from+to,且与 commit 互斥)、effort、background、exclude(最多 50 条)、provider/model/resume(resume 仅 commit/branch,workspace 不支持恢复)、wait |
|
|
101
|
-
| 数值参数组(`ocr_review` 的入参) | concurrency/timeoutMinutes/maxTools/maxTokens/maxTokensBudget,落 `--concurrency` `--timeout` `--max-tools` `--max-tokens` `--max-tokens-budget`,非整数或小于下限即报错(注意 `--max-tools` 的 1-49 会被 OCR 抬到 50,其帮助文本写明 min 50) |
|
|
102
|
-
| `ocr_scan` | repo、path(最多 100 条)、exclude(50)、batch none/by-language/by-directory、provider/model(scan_cmd 原生共享 flags,与 review 对齐)、同一组数值参数、wait;无需 git diff |
|
|
103
|
-
| `ocr_delegate_preview` / `ocr_delegate_rule` | 前者:repo、scope/commit/from/to、exclude 50、background;后者:repo、paths 必填 1–200 条,经 `--` 分隔的位置参数逐条转义。OCR 端零 LLM 消耗,只回文件清单与规则分组 |
|
|
104
|
-
| `ocr_session` | repo、action list/show/comments(白名单,越界即报错)、id、limit(钳到 1–100,缺省 10);show/comments 缺 id 时回落 list |
|
|
105
|
-
| 后台与回收 | `wait: false`(后台启动、不挂宿主 deadline、默认不设时限、不写 `--output`,结果用 `ocr_session` 轮询)与宿主回收守护只作用于 review/scan 这两条分钟级命令。**那次子进程同时是一枚官方作业**(见下面的「后台作业面」一节),工具回执那份 JSON 在换装那次一字未改(输出契约后来另改为 canonical 对象直返,见下节) |
|
|
106
|
-
|
|
107
|
-
## 设置项
|
|
108
|
-
|
|
109
|
-
| 字段 | 取值、默认与用途 |
|
|
110
|
-
| ---------------- | ------------------------------------------------------------------------------------------------------------------------ |
|
|
111
|
-
| `effort` | low/medium/high,内置默认 medium;`ocr_review` 未显式传 effort 时用它 |
|
|
112
|
-
| `language` | 中文/English,默认 中文;应用选择时作为顶层 `language` 键写进 OCR config |
|
|
113
|
-
| `autoVerify` | 默认 true;true 时 `/select` 成功后自动跑一次 `ocr llm test --color never`(90 秒上限) |
|
|
114
|
-
| `maxComments` | 默认 12,即摘要保留条数;0 = 不截断,非整数或负数回退 12 |
|
|
115
|
-
| `timeoutMinutes` | 默认 0 = 请求宿主上限(宿主按 min(请求, shell.maxTimeoutMs) 收口),>0 为分钟数 |
|
|
116
|
-
| `ocrConfigPath` | 外部 ocr CLI 配置的位置;留空按 `os.homedir()/.opencodereview/config.json` 派生,接受 `~` 与 `~/` 前缀,相对路径直接报错。**自定义值必须是 `<X>/.opencodereview/config.json` 布局**:OCR 端没有配置文件级的路径覆盖(只认 `<HOME>/.opencodereview/config.json`,`config_cmd.go:92-99`),插件通过给 ocr 子进程注入 `HOME=<X>` 让它生效(config 与 sessions 一并重定向,`api_key_cmd` 会带上宿主侧解析出的数据目录作 get-cred 的显式定位档);布局外的任何路径在设置层直接报错,绝不静默失配(HOME 注入是 POSIX 赋值前缀形态,Windows 无此通道,自定义路径仅在 macOS/Linux 生效) |
|
|
117
|
-
|
|
118
|
-
另有三枚**部署级**调优值,刻意不进设置卡——它们是导出 `Config` 上的普通(非 volatile)字段,只能写在 profile 注册行的 `config:` 上,改值随重启生效:
|
|
119
|
-
|
|
120
|
-
| 键 | 默认 | 用途 |
|
|
121
|
-
| -------------------- | --------- | ---------------------------------------------------------------------------------------- |
|
|
122
|
-
| `llmTestTimeoutMs` | `90000` | `ocr llm test` 的墙钟(autoVerify 与卡片「测试连接」共用);评审机慢就调大 |
|
|
123
|
-
| `ocrBackgroundMaxMs` | `0` | 后台评审的兜底回收窗口(`jobs.wait` 等到 deadline 即经注册表 `kill`);0 = 不设窗口,只有宿主退出、会话停止、插件卸载或显式 `job_kill` 才结束 |
|
|
124
|
-
| `stdoutMaxBytes` | `400000` | shell 执行器的 stdout 缓冲上限,前台与后台共用同一字段 |
|
|
125
|
-
|
|
126
|
-
第四枚非 volatile 字段是**部署决策**而不是调优值,理由与上面同一类(它改变一场运行对这台机器能做什么,不该放在一张用户可以在审查中途随手翻动的卡片上):
|
|
127
|
-
|
|
128
|
-
| 键 | 默认 | 用途 |
|
|
129
|
-
| ----------------- | ------- | ---------------------------------------------------------------------------------------------------------------------- |
|
|
130
|
-
| `ocrNoAutoUpdate` | `false` | 置真时本包起的每条 `ocr` 命令都带 `OCR_NO_UPDATE=1`,拦住上游 npm 包装层在评审中途执行 `npm i -g @alibaba-group/open-code-review@<latest>`;置假保持上游行为(18 分钟冷却 + pid 锁)。版本探测不受本开关影响,恒定带上该变量 |
|
|
131
|
-
|
|
132
|
-
第五枚管的是「给用户看哪条装法命令」,同一个理由让它也不上卡片(一个统一用 brew 或统一用 npm 的部署,不该让每台机器各自在页面上发现这件事):
|
|
133
|
-
|
|
134
|
-
| 键 | 默认 | 用途 |
|
|
135
|
-
| ---------------- | ------ | ---------------------------------------------------------------------------------------------------------------------- |
|
|
136
|
-
| `ocrInstallHint` | `both` | 还没装时,工具拒绝、卡片状态行与启用指引先推哪条命令:`both`(两条都给)/ `brew` / `npm`。它只是兜底而非覆盖——机器上已有一份候选时按那份自己的来源说,因为要给的是「替换他手上那一份」的命令:对着 brew 装的用户端出 `npm i -g`,机器上会多出第二份 ocr,而 PATH 上那条还是旧的。npm 那条恒带核对版本,brew 那条恒带不了 |
|
|
137
|
-
|
|
138
|
-
## 凭据与配置文件
|
|
139
|
-
|
|
140
|
-
| 面 | 事实 |
|
|
141
|
-
| ---------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
142
|
-
| config 里的凭据形态 | 写进去的是命令不是明文:POSIX 上 `api_key_cmd` = `node '<本包 scripts/get-cred.mjs 的路径>' '<REF>' '<dsh 数据目录>'`(三段都过单引号转义);Windows 上按双引号转义(ocr 在那边经 `cmd.exe` 跑凭据命令,单引号是普通字符)。第三段是宿主此刻 `resolveDshHome()` 的解析值,HOME 重定向或非 env 指定 dsh home 时 get-cred 的兜底层才不会跑偏;REF 名必须匹配 `^[A-Z0-9_]+$`,否则拒绝构造 |
|
|
143
|
-
| 取值层序 | get-cred 三层的先后**照抄**官方 credentials-local:`$DSH_HOME/.credentials.yaml` 的 `refs.<REF>` > 继承来的进程环境 > `$DSH_HOME/.env`。排错一位不会报错:宿主认「托管文件里那一份才是有效的」,脚本若先交环境里那份,OCR 就打的是另一个 key,而卡片与 OCR 两边都显示成功。dsh 0.2.1-rc.2 把环境层从最高降到了托管文件之后,本包的脚本与 `test/get-cred.test.ts` 同步跟上 |
|
|
144
|
-
| 可达性闸 | `/select` 与 `/migrate` 会拒绝「OCR 运行时取不到」的 key:dsh 起 shell 会剥掉名字命中 `KEY`/`PASSWORD`/`SECRET`/`TOKEN` 或 `DSH_` 前缀的环境变量(`scrubbedParentEnv`),get-cred 也刻意不读被审查仓库的 `.env`——只存在于 dsh 进程环境或工作区 `.env` 的 key 在宿主侧解析得到、OCR 运行时却取不到,旧行为是「select 成功 → OCR 401」的假绿。`file`(`$DSH_HOME/.credentials.yaml`)与 `user-env`(`$DSH_HOME/.env`)两层放行;`env` 仅当 ref 名不被净化模式命中才放行;`project-env` 一律不放行。拒绝发生在写盘之前,错误文本写明补救方式(把 key 存入托管凭据或 `$DSH_HOME/.env`) |
|
|
145
|
-
| 写入方式 | 只走原子替换(交官方 `@deepseek-ai/dsh-atomic-write`):同目录随机后缀 `.<hex>.tmp` → rename,新文件权限 0600 由新 inode 携带、父目录 0700;备份 `.bak` 由本包在 rename **之前**复制并 chmod 0600;整段「读→判→写」由官方 `withFileLock` 串行化,RMW 期间同目录会短暂出现 `config.json.lock`(正常路径下 `finally` 删除,持锁进程崩溃时按 pid 探活接管);现有 config 是坏 JSON 或顶层非对象时中止写入,绝不「按空配置覆盖」。**已知不一致**:并发争用超过官方默认 2s 等待上限时,写会以 `atomic-write: timed out waiting for the writer lock at …` 抛出并回 400 JSON,这条文本来自官方件、不走 `lib/messages.ts`(本包其余用户可见错误都在消息表里);换装前 RMW 同处一个 tick、没有超时这条路,是异步化换来的新失败模式,映射它需要给锁等待时间加注入缝并为 2s 超时写测试,本包选择记录而不是静默扩面 |
|
|
146
|
-
| `migrate()` | 把 custom provider 条目里的明文 `api_key` 换成 `api_key_cmd` 并删除明文;key 所在层在 OCR 运行时不可达(与 `select` 同一道闸)或 settings 里查不到 `apiKeyEnv` 的条目原样不动、列进 `skippedUnknown`;一条都没迁移成功时不写盘 |
|
|
147
|
-
| `scripts/get-cred.mjs` | 由外部 ocr CLI 自己起进程调用,是本包唯一还在读宿主凭据文件的地方。数据目录按「命令行第三参数 > `$DSH_HOME` > `~/.dsh`」定位,取值层序就是上面「取值层序」那一行(托管文档 > 继承环境 > `.env`)——注意「继承环境」这一层对凭据 ref 实际常为空:dsh 起 shell 会剥掉名字含 `KEY`/`PASSWORD`/`SECRET`/`TOKEN` 或 `DSH_` 前缀的变量。刻意不读被审查仓库的项目 `.env`;三层全落空即非零退出,并把查过的位置一并报出 |
|
|
148
|
-
|
|
149
|
-
## 对外接口
|
|
150
|
-
|
|
151
|
-
设置卡的契约面是一枚官方 Typert Remote 命名空间 `ocrReview`(`lib/remote-shape.ts` 的 `OCR_REMOTE_NAMESPACE`),五个方法用程序化方式打标记(`host.ts` 的 `markRemote`)。不再有 `/_dsh/*` 路由:认证、Host / DNS 重绑定 / Origin 判据与请求体上限都由宿主 `/api` 网关承担,本包因此没有 CSRF token、没有自己的 body 上限、没有 405 那一档,也没有路由释放器。
|
|
118
|
+
## <img src="https://api.iconify.design/lucide/hammer.svg?color=%23658EFF&height=22" height="22" width="22" align="absmiddle" alt="" /> 提供给模型的工具
|
|
152
119
|
|
|
153
|
-
|
|
|
154
|
-
| --- | --- |
|
|
155
|
-
| `
|
|
156
|
-
|
|
|
157
|
-
| `
|
|
158
|
-
| `
|
|
159
|
-
| `
|
|
160
|
-
|
|
|
120
|
+
| 工具 | 入参与约束 |
|
|
121
|
+
| --- | --- |
|
|
122
|
+
| `ocr_review` | repo(绝对路径,缺省=当前会话工作区)、scope workspace/commit/branch(branch 需同时给 from+to,且与 commit 互斥)、effort、background、exclude、provider/model/resume——resume 仅限 commit/branch,workspace 不支持恢复。preview(只做文件选择)、noFilter、maxGitProcs、rule/backgroundFile(仅 repo 根内文件)、wait |
|
|
123
|
+
| 数值参数组(review 与 scan) | concurrency / timeoutMinutes / maxTools / maxTokens / maxTokensBudget,落 `--concurrency` `--timeout` `--max-tools` `--max-tokens` `--max-tokens-budget`。取值忠实透传;下限 concurrency 为 1、其余为 0,非整数或低于下限直接报错,不钳制 |
|
|
124
|
+
| `ocr_scan` | repo、path、exclude、batch none/by-language/by-directory、provider/model(CLI 原生共享旗标)、同一组数值参数、preview、noPlan/noDedup/noSummary、resume、maxGitProcs、rule(repo 根内文件)、wait。整仓扫描,无需 git diff |
|
|
125
|
+
| `ocr_delegate_preview` / `ocr_delegate_rule` | preview:repo、scope/commit/from/to、exclude、background、backgroundFile/rule/maxGitProcs。rule:repo 加 paths——必填、最多 200 条、经 `--` 分隔作位置参数、逐条转义——外加 rule。OCR 端零 LLM 消耗:只回文件清单与规则分组 |
|
|
126
|
+
| `ocr_session` | repo、action list/show/comments/compare/export、id、before/after(compare)、severity/category(comments 过滤)、limit——缺省 10;显式给出必须是 1–100 的整数,越界报错而不是钳制。compare 返回四桶,export 返回 HTML 路径 |
|
|
127
|
+
| `ocr_rules_check` | repo、path(必填)、rule(repo 根内文件):打印命中的规则层、glob 与正文;不调 LLM |
|
|
128
|
+
| `ocr_llm` | action providers/models:只读查询 LLM 清单;不评审、不测连通性 |
|
|
129
|
+
| 清单上限 | exclude 与 path 各收 2000 条;超限直接拒绝整次调用。条目绝不静默丢弃——「比清单少审了几份」不许以成功的口径上报 |
|
|
130
|
+
|
|
131
|
+
`wait: false` 起后台运行、不挂宿主 deadline(用 `ocr_session` 轮询;该子进程同时是一枚官方作业,见[后台运行与官方作业](#后台运行与官方作业));dsh 以任何方式退出时,收割守护把 OCR 进程树收走。取消工具调用即终止对应的后台进程。
|
|
161
132
|
|
|
162
|
-
|
|
133
|
+
## <img src="https://api.iconify.design/lucide/sliders-horizontal.svg?color=%23658EFF&height=22" height="22" width="22" align="absmiddle" alt="" /> 设置项
|
|
163
134
|
|
|
164
|
-
|
|
135
|
+
命名空间是条目 id `ocr-review`;卡片上的字段是 `.volatile()` 的那几枚。
|
|
165
136
|
|
|
166
|
-
|
|
137
|
+
| 字段 | 取值、默认与用途 |
|
|
138
|
+
| --- | --- |
|
|
139
|
+
| `effort` | auto/low/medium/high,内置默认 auto;`auto` 不传 `--effort`,让 OCR 自己的配置生效。`ocr_review` 未显式传 effort 时用它 |
|
|
140
|
+
| `language` | 中文/English,默认 中文;应用选择时作为顶层 `language` 键写进 CLI config |
|
|
141
|
+
| `autoVerify` | 默认 true;select 成功后自动跑一次 `ocr llm test`(上限由 `llmTestTimeoutMs` 管) |
|
|
142
|
+
| `maxComments` | 默认 12,即摘要保留条数;0 = 不截断,非整数或负数回退 12 |
|
|
143
|
+
| `timeoutMinutes` | 默认 0 = 请求宿主上限(宿主按 min(请求, shell.maxTimeoutMs) 收口);大于 0 为分钟数 |
|
|
144
|
+
| `ocrConfigPath` | CLI 配置的位置;留空按 `<home>/.opencodereview/config.json` 派生,接受 `~` 与 `~/` 前缀,相对路径直接报错。自定义值必须是 `<X>/.opencodereview/config.json` 布局——CLI 没有配置文件级的路径覆盖,插件靠给子进程注入 `HOME=<X>` 让它生效(config 与 sessions 一并重定向);布局外的路径在设置层就拒绝。仅 POSIX:Windows 无此通道 |
|
|
167
145
|
|
|
168
|
-
|
|
169
|
-
| ---------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
170
|
-
| 模型的观察面 | 多了三位:官方 `job_list` 列得出这次评审、`job_output` 读得到它的 stdout/stderr(注册表按自己的节奏从 `proc.observed` 拉,非消费式,与 `readOutput()` 游标互不争夺 — 官方 d.ts 明写 "without stealing bytes from `readOutput`")、`job_kill` 停得掉它。评审结果本身仍以 `ocr_session` 会话记录为准;工具回执的内容自换装起未变,其后随输出契约改造改为 canonical 对象直返(不再把回执 stringify 进 `{ text }` 双重编码) |
|
|
171
|
-
| 坏掉的执行器读者 | 官方泵对"源抛错"的答法是只往宿主日志写一行、此后这一路读作空(实测)⇒ 本包额外写**一条**"这段不完整"进环,只写一次、也不再去敲坏掉的读者 |
|
|
172
|
-
| controller 寿命 | 只挂在 `start` 那一瞬:官方件在"没有 controller 服务这个 owner"时拒绝 `start`,而 web 面宿主的 `tool-jobs` 在各 preset realm 内(宿主平面那一行被 disabled)⇒ 未拥有作业必须自己挂一枚。挂完立刻摘(实测:摘掉即恢复拒绝、后续 read/kill/落定都不依赖它)——常驻等于在"宿主故意没装 job 工具"的组成里替全宿主开着那道闸门 |
|
|
173
|
-
| 三条回收路径 | 可选的兜底窗口、插件卸载、会话 dispose 都是 `jobs.kill(id, undefined, reason)` 而不是绕过它杀进程 ⇒ 记录推到 `stopping`、reason 落进 `detail`(实测绕过那一层,名册里这条会永远停在 `running`)。三条可以叠加(实测对 `stopping` 再 kill 仍回 `requested`、`proc.kill()` 幂等)。reason 是模型可见文本 ⇒ 取双语字典 |
|
|
174
|
-
| 取消链里不许抛 | 宿主事件处理器里抛出的错误由 Node 以 `process.nextTick` 重抛 ⇒ 未捕获异常 ⇒ **整个宿主进程退出**(本机实跑复现:`Error: unknown job ...` + `EXIT=1`)。官方件也不替生产者兜:`killJob` 裸调 `job.cancel()`(dsh-jobs-local 的 `killJob`,只有 teardown 那一臂逐条 try/catch),注册表被重载/关掉时对陌生 id 抛(同文件 `expect` 那一处 throw)。于是两层各兜一次:`cancel` 经 `killProc` 吞掉"进程早就不在了"那一类,`stop` 兜住注册表那一臂,兜不住时退化成直接杀我们自己的进程(各有一条用例,删掉任一层那条就红) |
|
|
175
|
-
| 可选兜底窗口 | 本包仍不给外部 CLI 套宿主 `timeoutMs`(长评审会被误砍),但"完全没有终点"在换装后有了新受害者:未拥有的 10 格桶是**全宿主共用**的(实测 `running` 与 `stopping` 都计数、满员直接拒绝新 `start`)⇒ 一条挂死的 CLI 会永久占一格。收法用注册表自己的 `wait(id, ms)` + `kill`,不用宿主 timer 也不裸 `setTimeout` |
|
|
176
|
-
| 未拥有的暴露面 | 官方件按 owner 隔离,未拥有作业任何 caller 都能 `list`/`read`/`kill`。这是本波已知并接受的暴露面(受有作业要 `dsh-agent` 注册表,实测不可得);回滚这次换装是唯一的收回方式 |
|
|
177
|
-
| 落定记录窗口 | 注册表不会自行回收已落定的记录,而它随宿主活着、不随本插件卸载而死 ⇒ 本包在每次登记前剪掉 `ocr-review` 这一 kind 最老的已落定记录,剪到 9 条再起新的 ⇒ 在册任何时刻都不超过 10 条(每条最多带一只 256 KiB 的环)。卸载时两件事都做:活着的经注册表 kill,已落定的 remove —— 用户直接禁用本包就没有"下一次 apply"来剪窗口了。在跑与正在收的一条都不被剪 —— 官方件对超额的答法是**拒绝新 start**(实测未拥有桶 10),不是替我们杀评审 |
|
|
178
|
-
| 没注册表没后台 | 宿主没装 `dsh-jobs-local` 时,`wait: false` 直接抛出点名缺件的错误,**不会**先把子进程起在没人看得见的地方。前台(`wait: true`)不受影响 |
|
|
146
|
+
下面这些**部署键**刻意不进设置卡——它们是导出 `Config` 上的普通(非 volatile)字段,只能写在 profile 注册行的 `config:` 上,改值随重启生效:
|
|
179
147
|
|
|
180
|
-
|
|
148
|
+
| 键 | 默认 | 用途 |
|
|
149
|
+
| --- | --- | --- |
|
|
150
|
+
| `llmTestTimeoutMs` | `90000` | `ocr llm test` 的墙钟,autoVerify 与卡片「测试连接」共用;评审机慢就调大 |
|
|
151
|
+
| `startupVerify` | `true` | 装载期跑一次端点自检(顺带量一次版本)。两条归同一开关,因为判据同是「装载期允不允许起进程」;要求装载零进程的部署关掉它 |
|
|
152
|
+
| `ocrBackgroundMaxMs` | `0` | 后台评审的兜底回收窗口(注册表等到 deadline 即 kill);0 = 不设窗口——有主作业还会在所属会话停止时结束,无主作业则只在宿主退出、插件卸载或作业被杀时结束 |
|
|
153
|
+
| `stdoutMaxBytes` | `400000` | shell 执行器的 stdout 缓冲上限,前台与后台共用(评审结果走 `--output` 临时文件,正是为了绕开它) |
|
|
154
|
+
| `ocrNoAutoUpdate` | `false` | 置真时本包起的每条命令都带 `OCR_NO_UPDATE=1`,拦住上游在评审中途把新版 `npm i -g` 装上;置假保持上游行为。版本探测不受本开关影响,恒定带上该变量 |
|
|
155
|
+
| `ocrInstallHint` | `both` | 还没装时先推哪条装法:`both` / `brew` / `npm`。只是兜底而非覆盖——机器上已有一份时按那份自己的来源说,因为对着 brew 用户端出 `npm i -g` 会多出第二份、PATH 上还是旧的。npm 那条恒带核对版本,brew 那条恒带不了 |
|
|
181
156
|
|
|
182
|
-
|
|
183
|
-
| ------------ | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
184
|
-
| 进程边界 | 被审查仓库的路径与 diff 内容进 `ocr` 子进程,OCR 再把它发给自己在 config.json 里配置的 LLM 端点;这条外发是审查功能本身,不经 dsh 宿主。明文 key 不进工具返回、也不进 `ocrReview` 的应答,宿主侧 `resolve()` 拿到的值只用于确认「现在解析得到」,当场丢弃 |
|
|
185
|
-
| 原始输出脱敏 | OCR 的原始 stdout/stderr(失败详情、llm test、解析失败回显、session 透传)出宿主前统一过 `redactKeyMaterial()`:Bearer 与赋值形态从严抹除,独立 key 形态额外要求随机串特征,以免把要交给模型的文件路径一起抹掉 |
|
|
186
|
-
| 写盘范围 | 本包写盘只有两处:外部 ocr CLI 的 `config.json`(含同目录随机后缀 `.tmp`、备份 `.bak`,以及 RMW 期间短暂存在、正常路径下即删的 `config.json.lock`)与系统临时目录下的 `ocr-review-*`/`ocr-scan-*`(读完即删)。迁移前的明文可能仍留在同一次写入产生的 `.bak` 里(权限 0600),要彻底清掉需自行删除该备份。这两处之外仍可能被改动的是 **CLI 自己那层 npm 包装**:`ocrNoAutoUpdate` 没置真时,一次 `ocr` 调用会触发上游把新版全局 `npm i -g` 装上。本包自己从不执行安装动作,版本探测那条恒定拦住这条路 |
|
|
157
|
+
## <img src="https://api.iconify.design/lucide/network.svg?color=%23658EFF&height=22" height="22" width="22" align="absmiddle" alt="" /> 对外接口
|
|
187
158
|
|
|
188
|
-
|
|
159
|
+
一枚官方 Typert Remote 命名空间 `ocrReview`(`lib/remote-shape.ts` 的 `OCR_REMOTE_NAMESPACE`),九个方法在 `host.ts` 里以程序化方式打标记。服务在构造时注册、随所属 fiber 撤回,热重载留不下没人撤的旧命名空间。
|
|
189
160
|
|
|
190
|
-
|
|
|
191
|
-
|
|
|
192
|
-
|
|
|
193
|
-
|
|
|
194
|
-
|
|
|
161
|
+
| 方法 | 入参 | 成功回执 |
|
|
162
|
+
| --- | --- | --- |
|
|
163
|
+
| `providers()` | — | `{providers(每条附 hasKey 布尔), current, getCredReady, source, endpointVerify, ocrBinary}`,不含任何明文 key。`ocrBinary` 是那份纯文件系统的可得性判定再补上版本上下文(`source`、`channel`、`expectedVersion`、`measuredVersion: string \| null`、`installHint`);读这个方法不起进程 |
|
|
164
|
+
| `select(request)` | `{provider, model}`,两者必须命中 `describe()` 给的清单 | `{ok, applied, llmTest}`(`autoVerify` 关闭时 `llmTest` 为 null) |
|
|
165
|
+
| `migrate()` | — | `{ok, migrated, skippedUnknown}` |
|
|
166
|
+
| `test()` | — | `{ok, output}`——`ok` 是**测试结论**,不是这次调用成没成;output 先脱敏再截 8000 字符 |
|
|
167
|
+
| `probe()` | — | `{ok, version, expectedVersion, consistent, output, reason, changeText}`——15 秒墙钟内跑一次 `ocr version`,恒定带 `OCR_NO_UPDATE=1`。`consistent` 是三态(`null` = 没量到,此时宣称「不一致」就是把没证据的事说成结论);`reason` 点名失败那一档;`changeText` 只在真有一条该给的命令时非空 |
|
|
168
|
+
| `mcp()` | — | `{ok, json}`——只回 `mcp_servers` 对象(pretty JSON),不含 providers/keys |
|
|
169
|
+
| `saveMcp(request)` | `{json}`——原始 JSON 文本,上限 64 KiB;stdio/remote 条目逐字段校验 | `{ok, count}`——只写 `mcp_servers`,其他配置原样保留 |
|
|
170
|
+
| `auth()` | — | `{ok, output, loginCommand}`——只读 `ocr auth status --provider chatgpt`;登录本身要浏览器与本地回调,仍留在终端执行 |
|
|
171
|
+
| `chatGpt(request)` | `{model}` | `{ok, model}`——写 `provider: "chatgpt"` 与 `providers.chatgpt.model`,不写 key |
|
|
172
|
+
|
|
173
|
+
被拒时答 `{ok: false, error, status}`,其中 `status` 是**保留下来的语义码、不是 HTTP 状态**(选择为空或不在清单上是 400,写失败或凭据脚本缺失是 500)——那个数字的作用是让测试钉住是哪条判据拦的,客户端只渲染 `error`。这些调用刻意不带客户端墙钟:超时归网关管,卡片再设一枚就是「写得慢的那次被判成丢了,而它其实落了」。
|
|
174
|
+
|
|
175
|
+
## <img src="https://api.iconify.design/lucide/key-round.svg?color=%23658EFF&height=22" height="22" width="22" align="absmiddle" alt="" /> 凭据与 OCR 配置文件
|
|
176
|
+
|
|
177
|
+
| 面 | 事实 |
|
|
178
|
+
| --- | --- |
|
|
179
|
+
| 写进 config 的是什么 | 命令不是明文:`api_key_cmd` = `node '<本包 scripts/get-cred.mjs 的路径>' '<REF>' '<dsh 数据目录>'`——POSIX 单引号转义,Windows 双引号转义(CLI 在那边经 `cmd.exe` 跑凭据命令)。数据目录是宿主此刻解析出的 home,HOME 被重定向时 get-cred 的兜底层不会跑偏;REF 名必须满足官方 ref 名规则,否则拒绝构造 |
|
|
180
|
+
| 取值层序 | get-cred 三层的先后照抄官方 credentials-local:托管凭据文件里的 `refs.<REF>` 优先,其次继承来的进程环境,再次 `$DSH_HOME/.env`。宿主认「托管文件里那一份才是有效的」,排错一位不会报错——OCR 打的是另一个 key,而卡片与 OCR 两边都显示成功 |
|
|
181
|
+
| 可达性闸 | select 与 migrate 拒绝「CLI 运行时取不到」的 key:dsh 起 shell 会剥掉名字含 `KEY`/`PASSWORD`/`SECRET`/`TOKEN` 或 `DSH_` 前缀的变量,被审查仓库的 `.env` 也刻意不读。只存在于 dsh 进程环境或工作区 `.env` 的 key 在宿主侧解析得到、CLI 运行时却取不到——旧行为是「select 成功、OCR 401」的假绿。拒绝发生在写盘之前,错误文本写明补救方式 |
|
|
182
|
+
| 写入方式 | 走官方原子替换:同目录随机后缀临时文件 → rename,新 inode 携带 0600;`.bak` 备份由本包在 rename 之前复制。整段「读→判→写」由官方文件锁串行化——`config.json.lock` 短暂出现、`finally` 里删除。现有 config 是坏 JSON 或顶层非对象时中止写入,绝不「按空配置覆盖」 |
|
|
183
|
+
| `migrate()` | 把 custom provider 条目里的明文 `api_key` 换成 `api_key_cmd` 并删除明文;key 所在层在 CLI 运行时不可达(与 select 同一道闸)或 settings 里查不到 `apiKeyEnv` 的条目原样不动、列进 `skippedUnknown`;一条都没迁移成功时不写盘 |
|
|
184
|
+
| `scripts/get-cred.mjs` | 由 CLI 自己起进程调用,是本包唯一还在读宿主凭据文件的地方。三层全落空时非零退出,并把查过的位置一并报出 |
|
|
185
|
+
|
|
186
|
+
## <img src="https://api.iconify.design/lucide/hourglass.svg?color=%23658EFF&height=22" height="22" width="22" align="absmiddle" alt="" /> 后台运行与官方作业
|
|
187
|
+
|
|
188
|
+
| 面 | 事实 |
|
|
189
|
+
| --- | --- |
|
|
190
|
+
| 模型多看到的 | `job_list` 列得出这场评审、`job_output` 读得到它的 stdout/stderr(非消费式——不会从会话读取器那里抢字节)、`job_kill` 停得掉它。评审结果仍以 `ocr_session` 会话记录为准 |
|
|
191
|
+
| 没注册表就没后台 | 宿主没有 jobs 服务时,`wait: false` 直接抛错点名缺件,而不是起一个没人看得见的子进程;前台运行不受影响 |
|
|
192
|
+
| 归属 | 调用方能解析到活会话时,作业以该会话为 `owner` 登记;此后只有那个会话能经 `job_list` / `job_output` / `job_kill` 碰到它。解析不到活 Agent 的调用起的是无主作业 |
|
|
193
|
+
| 容量桶 | 有主作业计入各自 owner 的桶;无主作业共用全宿主的未拥有桶。满员都直接拒绝新 start,一条挂死的 CLI 会占住一格——`ocrBackgroundMaxMs` 那个可选兜底窗口就是为它设的,用注册表自己的 wait + kill,不用宿主 timer |
|
|
194
|
+
| 清理 | 每次登记前,把该 caller 可见面(无主桶 + 自己的)里本 kind 的已落定记录剪到固定窗口;在跑与正在收的一条不剪(注册表对超额的答法是拒绝,不是替人杀评审)。会话销毁只回收该会话的作业;卸载时统一回收全部,有主作业的 id 靠一份最小的「id → owner」台账枚举,因为注册表对别的 owner 隐藏它们 |
|
|
195
|
+
| 暴露面 | 有主作业只对所属会话可见、也只由它可 kill。无主作业仍对所有 caller 可见——这是残留暴露面,只发生在解析不到活 Agent 的时候 |
|
|
196
|
+
| 取消链里不许抛 | 宿主事件处理器里抛出的错误会把整个宿主进程带下来,官方件也不替生产者兜——取消链在两层各兜一次,每层各有一条用例钉着 |
|
|
197
|
+
|
|
198
|
+
## <img src="https://api.iconify.design/lucide/lock.svg?color=%23658EFF&height=22" height="22" width="22" align="absmiddle" alt="" /> 数据与隐私
|
|
199
|
+
|
|
200
|
+
| 面 | 事实 |
|
|
201
|
+
| --- | --- |
|
|
202
|
+
| 进程边界 | 被审查仓库的路径与 diff 内容进 `ocr` 子进程,CLI 再把它们发给自己在 config.json 里配置的 LLM 端点——这条外发是审查功能本身,不经 dsh 宿主。明文 key 不进工具返回、也不进 Remote 应答;宿主侧解析到的值只用于确认「现在解析得到」,当场丢弃 |
|
|
203
|
+
| 原始输出脱敏 | 本包出去的 CLI 原始 stdout/stderr(失败详情、llm test、解析失败回显、session 透传)统一过 `redactKeyMaterial()`:Bearer 与赋值形态从严抹除,独立 key 形态额外要求随机串特征,免得把要交给模型的文件路径一起抹掉 |
|
|
204
|
+
| 写盘范围 | 只有两处:CLI 的 `config.json`(含临时文件、`.bak` 备份与短暂的锁)与系统临时目录下的 `ocr-review-*` / `ocr-scan-*`(读完即删)。迁移前的明文可能留在那次写入产生的 `.bak` 里(权限 0600)——要彻底清掉需自行删除该备份。这两处之外,`ocrNoAutoUpdate` 没置真时唯一的写者就是 CLI 自己那层 npm 包装 |
|
|
205
|
+
|
|
206
|
+
## <img src="https://api.iconify.design/lucide/triangle-alert.svg?color=%23658EFF&height=22" height="22" width="22" align="absmiddle" alt="" /> 已知边界
|
|
207
|
+
|
|
208
|
+
- **Windows 没有收割、也没有自定义配置路径。** 两者都立在 POSIX 工具链上(bash trap、进程组语义、`HOME=` 赋值前缀);Windows 上本包按裸命令执行、不收割,宿主硬退出可能留下孤儿 OCR 进程。
|
|
209
|
+
- **版本对不上从不当硬失败。** 新版 CLI 通常照样能用;两个数字并列显示、徽标改口、摘要 `hint` 加一句。本包从不执行安装动作。
|
|
210
|
+
- **读版本要起一次进程**,页面渲染绝不触发;卡片只显示最近一次测量或什么都不显示——渲染一页装不了、更不了、也探不了任何东西。
|
|
211
|
+
- **原子写的锁超时以英文出现。** 争用超过官方等待上限时抛的是官方件自己的超时文本——这是本包唯一一条绕过双语消息表的用户可见错误。
|
|
212
|
+
- **`partial` 是终态里的成功档。** 部分文件失败但覆盖仍成立、评论仍有效;既不被抬成成功,也不被折进失败。
|
|
213
|
+
- **无主的后台作业对所有会话可见**(见「后台运行与官方作业」)。解析不到活 Agent 的调用会起这种作业;有主作业则被围栏在自己的会话里。
|
|
214
|
+
|
|
215
|
+
## <img src="https://api.iconify.design/lucide/circle-help.svg?color=%23658EFF&height=22" height="22" width="22" align="absmiddle" alt="" /> 常见问题
|
|
216
|
+
|
|
217
|
+
| 现象 / 问题 | 结论 |
|
|
218
|
+
| --- | --- |
|
|
219
|
+
| 把 exit 0 当成评审成功 | exit 0 不等于成功:`status` 不在 success / complete / partial / completed_with_warnings / completed_with_errors / skipped 白名单内即按失败报。`partial` 指部分文件失败、但覆盖与评论仍有效。解析失败时回显脱敏后原文的前 500 个 UTF-16 码元 |
|
|
220
|
+
| 摘要有没有覆盖全部产出? | 两件不同的事,不能互相替代。`droppedCount` / `invalidCommentCount` 只说明**本摘要**有没有列全评论(调大 `maxComments` 或置 0 再复核)。**这一场**有没有把选中的文件审完看 `coverage`(`selected` 是分母,`failedItems` 给出文件名与原因)、`budgetExceeded` 与 `toolCalls` |
|
|
221
|
+
| `add` 被拒,报 `already-installed` | HMR profile 对已装包的 `add` 在 pnpm 动手之前就拒——先 `remove` 再 `add` 目标版本(见「安装」) |
|
|
222
|
+
| dsh 退出时后台进程怎么办? | 收割守护在任何宿主退出方式下(含 kill -9 后被收养)以 TERM→1s→KILL 收走 review/scan 的进程树;取消工具调用即终止对应的后台进程 |
|
|
223
|
+
| 明文 key 还可能留在哪? | 本包写盘的地方没有它。迁移前配置里的明文可能留在迁移后第一次写入产生的 `.bak` 里(权限 0600);删掉那份备份即彻底清除 |
|
|
224
|
+
|
|
225
|
+
## <img src="https://api.iconify.design/lucide/wrench.svg?color=%23658EFF&height=22" height="22" width="22" align="absmiddle" alt="" /> 开发
|
|
195
226
|
|
|
196
|
-
|
|
227
|
+
```sh
|
|
228
|
+
pnpm install
|
|
229
|
+
pnpm run check # typecheck(两侧)→ lint → client 构建 → host 构建 → 带 coverage 的测试 → 格式检查
|
|
230
|
+
```
|
|
197
231
|
|
|
198
|
-
-
|
|
199
|
-
-
|
|
200
|
-
-
|
|
201
|
-
- 插件源码是
|
|
232
|
+
- 覆盖率阈值**四项 100%**,分母是 `vitest.config.ts` 里 `coverageInclude` 选定的那一面(`host.ts` + `lib/**`);两块刻意在分母外:客户端半(`src/**`)经 bundle 与设置卡用例覆盖,`scripts/get-cred.mjs` 由进程级用例另起进程驱动(v8 覆盖率看不到子进程),它的行为门禁在 `test/get-cred.test.ts`。
|
|
233
|
+
- 往 profile 加本包的**本地目录**(`pnpm add <路径>`)需要 pnpm ≥ 12.3.0:更早的 pnpm 12 把无别名的本地路径当 registry 包名解析(上游 #14437,12.3.0 修复)。从 registry 装不受影响。
|
|
234
|
+
- 产物新鲜度由 `test/build-host.test.ts` 钉着:`host.js` / `client.js` 落后于源码就红。发布物不手改;`prepack` 重建。
|
|
235
|
+
- 插件源码是 TypeScript,由宿主的 cordis Loader 直接加载(Node ≥ 22.18 类型剥离);bundle 只为 npm 发布面存在。
|
|
202
236
|
|
|
203
|
-
##
|
|
237
|
+
## <img src="https://api.iconify.design/lucide/scale.svg?color=%23658EFF&height=22" height="22" width="22" align="absmiddle" alt="" /> 许可
|
|
204
238
|
|
|
205
|
-
MIT
|
|
239
|
+
MIT,源码在 [github.com/JayYuen666/dsh-ocr-review](https://github.com/JayYuen666/dsh-ocr-review),问题提该仓的 tracker。
|
|
206
240
|
|
|
241
|
+
运行时依赖各有自己的许可证;[`THIRD_PARTY_NOTICES.md`](./THIRD_PARTY_NOTICES.md) 记录这一产物边界与复核方法。
|
package/THIRD_PARTY_NOTICES.md
CHANGED
|
@@ -30,16 +30,19 @@
|
|
|
30
30
|
- 上游项目:`open-code-review`
|
|
31
31
|
- 上游仓库:https://github.com/alibaba/open-code-review
|
|
32
32
|
- 上游许可:Apache-2.0,Copyright 2026 Alibaba
|
|
33
|
-
- 验证版本:1.13.
|
|
33
|
+
- 验证版本:1.13.3(声明在 package.json 的 `ocrCliVersion`,代码里的镜像常量与两侧 README 由门禁对齐同一枚数字)
|
|
34
34
|
|
|
35
35
|
本包**使用**而非**包含**以下接口(`host.ts` / `lib/cli.ts` 的头注释按该版本源码逐条核对):
|
|
36
36
|
|
|
37
37
|
| 接口 | 用途 |
|
|
38
38
|
| --- | --- |
|
|
39
|
-
| `ocr review` / `ocr scan` | diff 审查与全文件扫描(`--audience agent --format json --output`
|
|
40
|
-
| `ocr delegate preview` / `ocr delegate rule` | 委托模式脚手架(文件清单 + 规则分组,OCR 端零 LLM
|
|
41
|
-
| `ocr session list/show/comments` |
|
|
42
|
-
| `ocr
|
|
39
|
+
| `ocr review` / `ocr scan` | diff 审查与全文件扫描(`--audience agent --format json --output` 机器可读面;`--preview`、`--no-filter`、scan 的 `--no-plan/--no-dedup/--no-summary/--resume`、`--max-git-procs`、`--rule`、`--background-file`) |
|
|
40
|
+
| `ocr delegate preview` / `ocr delegate rule` | 委托模式脚手架(文件清单 + 规则分组,OCR 端零 LLM 消耗;含 `--rule`/`--background-file`/`--max-git-procs`) |
|
|
41
|
+
| `ocr session list/show/comments/compare/export` | 会话查询、四桶比较与 HTML 导出(含 `--resume` 恢复) |
|
|
42
|
+
| `ocr rules check` | 单文件规则层/glob/正文诊断 |
|
|
43
|
+
| `ocr llm test` / `providers` / `models` | select 后的连通性验证与 LLM 清单查询 |
|
|
44
|
+
| `ocr auth status` | 设置卡查询 ChatGPT 登录态;登录/登出仍由用户在终端执行 |
|
|
45
|
+
| `config.json` 的 `mcp_servers` 与 `providers.chatgpt.model` | MCP 管理面与 ChatGPT provider 选择;只改对应分支,不写 key |
|
|
43
46
|
| `config.json` 的 `custom_providers.<name>.{url,protocol,model,api_key_cmd}` | provider/model 应用面;key 经 `api_key_cmd` 动态读取,绝不落明文 |
|
|
44
47
|
|
|
45
48
|
这些都是 CLI 的外层面,但不是任何文档承诺过的稳定 API——本包把契约钉在上面那一版正是为了
|
|
@@ -52,7 +55,8 @@
|
|
|
52
55
|
|
|
53
56
|
| 依赖 | 版本 | 许可 | 引入方 |
|
|
54
57
|
| --- | --- | --- | --- |
|
|
55
|
-
| `@alibaba-group/open-code-review` | 1.13.
|
|
58
|
+
| `@alibaba-group/open-code-review` | 1.13.3(核对版本,非依赖) | Apache-2.0(Alibaba) | **不在依赖表里**:用户自选 `brew install open-code-review` 或 `npm i -g @alibaba-group/open-code-review@<版本>`,本包只 spawn 它 |
|
|
56
59
|
| `js-yaml` | ^5.4.3 | MIT | `scripts/get-cred.mjs` 读 dsh 托管凭据文档 |
|
|
60
|
+
| `zod` | catalog(伞根 4.6.7) | MIT | 设置卡 `src/remote.ts` 的 strict codec 形状校验;client 产物由宿主 `PLATFORM_MODULES` 提供 |
|
|
57
61
|
|
|
58
|
-
dsh 宿主侧的包分两档:产物里以**值**导入、且列在 `peerDependencies`
|
|
62
|
+
dsh 宿主侧的包分两档:产物里以**值**导入、且列在 `peerDependencies` 的五枚(`@deepseek-ai/schemastery` 宿主 fork、`@deepseek-ai/dsh-credentials`、`@deepseek-ai/dsh-home-paths`、`@deepseek-ai/dsh-atomic-write` 与 `@deepseek-ai/dsh-typert-protocol`)由宿主在场提供、不随本包分发;其余 `@deepseek-ai/dsh-*` 与 `@deepseek-ai/cordis` 只在 `devDependencies` 里,用途是把类型绑到官方声明上(type-only 绑定),产物里不留说明符。本包按 dsh `0.2.2-alpha.2` 逐条核对过(同版的 cordis `4.0.6-alpha.1` 与 schemastery `3.18.6-alpha.1` fork 一并核对)。
|