JayYuen666/dsh-ocr-review ↗★ 0

@jayyuen66/dsh-ocr-review

dsh 工作区代码审查插件:把 open-code-review(ocr CLI)封装为 5 个模型工具 + 设置卡片(从 settings.yaml 选 provider/model 应用到 OCR 配置)。

套件
@jayyuen66/dsh-ocr-review
相容性
待驗證
版本
0.1.2
授權
MIT
最近更新
2026年10月1日

安裝

$npx -p @deepseek-ai/dsh dsh plugin --profile web add github:JayYuen666/dsh-ocr-review

@jayyuen66/dsh-ocr-review

English · 中文

What it does

  • Wraps the external ocr (open-code-review) CLI into 5 model tools plus 1 web settings card for dsh; the host validates tool arguments not at all, so every shape and type gate lives in this package.
  • The host half (host.ts) declares 6 .volatile() settings fields — as of 0.1.7 the namespace is implicit: the host projects the form from the profile entry id ocr-review and the plugin calls no settings.register.
  • It also registers 5 tools, one systemPrompt routing section (ocr-review-routing, order 1555) and 4 /_dsh/ocr-review/* endpoints.
  • The client half (src/client-entry.ts → client.js) is the settings card, taking provider/model from the llm-pi-ai namespace of the settings service.
  • It writes provider/model into the external ocr CLI's own ~/.opencodereview/config.json — as an api_key_cmd command, never as a plaintext key.

Prerequisites (external CLI)

  • This package imports no OCR library, it only spawns processes: ocr review / ocr scan / ocr delegate preview / ocr delegate rule / ocr session / ocr llm test.
  • Commands are built against the contract verified line-by-line on the v1.12.x source (header comments of lib/cli.ts and lib/parse.ts), shaped like ocr review --audience agent --format json --effort medium --output .
  • Multi-value --exclude/--path are merged into one comma-separated flag, and --format only accepts json/text/sarif.
  • Command resolution order: the launcher bundled with the package first - @alibaba-group/open-code-review (an optionalDependencies entry, whose own optionalDependencies pick the platform binary) resolved to the absolute path of its bin/ocr.js - and only when that does not resolve does it fall back to a bare ocr on PATH. Both installation shapes keep working, so installing this plugin is enough to get a working tool without a separate brew / npm i -g step. Resolution is lazy and memoized once per process (the same shape dsh core uses to resolve @vscode/ripgrep); a failed resolve never throws at load time, which would take the whole plugin offline over one optional binary.
  • With neither path available the child exits 127 and the tool reports "ocr command not found", offering brew install open-code-review or npm i -g @alibaba-group/open-code-review.
  • Platforms: macOS and Linux are the targets. Process reaping (the reaper guard around ocr_review / ocr_scan) depends on a POSIX toolchain - bash traps and job control plus the process-group semantics of ps / pgrep / kill. None of that exists on Windows, so the package runs the bare command there (guarded by process.platform): no reaping, but it still works. The cost is that a hard host exit can leave an orphaned OCR process.
  • The provider list and the key status come from the official host channels ctx.settings.describe() (the value.providers of the llm-pi-ai entry) and ctx.credentials.
  • When either is missing the card shows the degradation reason while tools and settings keep working.
  • The host must be >=0.2.0-rc.2: declared in peerDependencies (the host checks it on plugin install from 0.1.7-rc; alpha.1 has no such gate yet) and in engines.dsh (same value, read by nothing).

Installation

dsh plugin --profile web add @jayyuen66/dsh-ocr-review
  • The packages are on the public npm registry, so installation needs no credentials.
  • The published files are only host.js, client.js, cordis.patch.yml and scripts (prepack rebuilds both bundles); source repository: see repository.url in package.json.
  • Runtime value dependencies are @jayyuen66/dsh-plugin-shared, @deepseek-ai/schemastery (the host's fork of schemastery — only it implements the 0.1.7 .volatile() resolution) and js-yaml (the last one used only by scripts/get-cred.mjs).

pnpm blocks the dependency script on install (ERR_PNPM_IGNORED_BUILDS)

This package keeps @alibaba-group/open-code-review in optionalDependencies, and upstream ships a postinstall (scripts/install.js). pnpm 10+ does not run dependency build scripts unless allowlisted, so the install ends like this:

Error: ERR_PNPM_IGNORED_BUILDS
  × installing dependencies
  ╰─▶ Ignored build scripts: @alibaba-group/open-code-review@1.12.11

Allowlisting is a one-time step, and only this package triggers it — no other plugin in this family depends on anything with a build script.

The straightforward fix is to allowlist it in the profile's pnpm-workspace.yaml (under /profiles/ /):

allowBuilds:
  '@alibaba-group/open-code-review': true

Then re-run pnpm i. The approval persists in that profile under the exact package name and survives later failed installs.

The host also ships an approval flow of its own: a failed install surfaces "allow these scripts and retry" on the web plugin page, and an Agent can grant it for you through install_bundle's approvedBuilds once you have said so in the conversation. The host validates only the pending package names, not the conversational consent, so you must approve it explicitly.

About that postinstall: on the normal path it does nothing. The platform binary comes from upstream's optionalDependencies (@alibaba-group/ocr--, each carrying os / cpu fields so pnpm installs only the one matching your platform); install.js detects that, prints Binary provided by platform package, skipping download. and returns. Measured, ocr runs identically whether or not the script executes — the only difference is whether that code runs during install, and it only downloads when the platform package is missing, which under pnpm never happens.

If you would rather run nothing at install time, write '@alibaba-group/open-code-review': false instead: ocr still works (the launcher reads the binary straight out of the platform package directory), but the host's readPendingBuilds() only recognises entries whose value is set this to true or false, so once it is false the approval flow can no longer grant it and you maintain that entry by hand.

Enabling it in dsh

  • The in-package cordis.patch.yml declares - id: ocr-review / name: "@jayyuen66/dsh-ocr-review" and is pointed at by dsh.bundle.patch in package.json.
  • dsh plugin --profile web add/remove registers and removes it, then restart dsh.
  • The card needs a web profile (dsh.client.platform: web, immediately: true).
  • The four /_dsh/ocr-review/* endpoints hang off an inject(["webServer"]) child fiber: with no webServer (a TUI host) the child never activates, so the endpoints simply do not exist while tools and settings stay available.
    • On the real host webServer arrives about a second after this entry, which is why it has to be a dependency rather than a one-off ctx.get in apply.
  • Deployment defaults can go on the profile's config: line (cordis validates and fills defaults through the exported Config schema); precedence: runtime settings value > line config > built-in default.

Tools exposed to the model

ToolArguments and constraints
ocr_reviewrepo (absolute path, default = current session workspace), scope workspace/commit/branch (branch needs both from+to and is mutually exclusive with commit), effort, background, exclude (at most 50 entries), provider/model/resume (resume only with commit/branch — workspace reviews cannot be resumed), wait
Numeric group (arguments of ocr_review)concurrency/timeoutMinutes/maxTools/maxTokens/maxTokensBudget (mapped to --concurrency --timeout --max-tools --max-tokens --max-tokens-budget; non-integers or values below the floor are rejected; note that --max-tools values 1-49 are raised to 50 by OCR — its help text says min 50)
ocr_scanrepo, path (at most 100 entries), exclude (50), batch none/by-language/by-directory, provider/model (native shared flags of scan_cmd, matching review), the same numeric group, wait; no git diff required
ocr_delegate_preview / ocr_delegate_ruleThe former: repo, scope/commit/from/to, exclude 50, background. The latter: repo, paths required, 1–200 entries, positional arguments after --, each escaped. Zero LLM cost on the OCR side, they return only the file list and the rule groups
ocr_sessionrepo, action list/show/comments (whitelist, anything else errors), id, limit (clamped to 1–100, default 10); show/comments without an id falls back to list
Background and reaperwait: false (background start, no host deadline, reclaimed by a 2-hour backstop, no --output, poll results with ocr_session) and the host reaper guard apply only to these two minute-scale commands, review and scan - that subprocess is also an official job (see the job-surface section below); that change left the tool's JSON untouched (a later output-contract rework switched it to the direct canonical object, see below)

Settings

FieldValues, defaults and use
effortlow/medium/high, built-in default medium; used when ocr_review is called without an explicit effort
language中文/English, default 中文; written as the top-level language key of the OCR config when a selection is applied
autoVerifydefault true; when true, a successful /select also runs ocr llm test --color never (capped at 90 seconds)
maxCommentsdefault 12, the number of comments kept in the summary; 0 = no truncation, non-integers and negatives fall back to 12
timeoutMinutesdefault 0 = request the host cap (the host clamps to min(request, shell.maxTimeoutMs)), >0 is a number of minutes
ocrConfigPathwhere the external ocr CLI config lives; left empty it derives os.homedir()/.opencodereview/config.json, ~ and ~/ prefixes are accepted, relative paths error out. A custom value must follow the /.opencodereview/config.json layout: OCR has no file-level path override (it only ever looks at /.opencodereview/config.json, config_cmd.go:92-99), so the plugin makes it effective by injecting HOME= into the ocr subprocess (config and sessions are redirected together, and api_key_cmd carries the host-resolved data directory as get-cred's explicit first-tier locator); any path outside that layout is rejected outright at the setting layer rather than silently mismatching (the HOME injection is a POSIX assignment prefix; Windows has no such channel, so custom paths only take effect on macOS/Linux)

Three deployment-level tuning keys are deliberately not on the settings card — they are plain (non-volatile) fields of the exported Config, settable only on the profile's config: line and taking effect on restart:

KeyDefaultUse
llmTestTimeoutMs90000Wall clock for ocr llm test (shared by autoVerify and the card's "test connection"); raise it on slow machines
ocrBackgroundMaxMs7200000The 2-hour backstop window for background reviews (jobs.wait to the deadline, then kill)
stdoutMaxBytes400000Executor stdout buffer cap, shared by foreground and background runs

Credentials and config files

AspectFact