xinyangGL/dsh-open-code-review ↗★ 0
dsh-open-code-review
把阿里 OpenCodeReview(ocr) 接进 DSH:模型可调用的 ocr_review/ocr_status 工具、/ocr-review 命令、按需评审(回合尾部的「启动代码审核」按钮 + 运行时 skill,出厂默认不自动评审)、评审先于测试(preTest=remind/gate 把评审接进「跑测试之前」)、三档引擎(ocr 流水线 / delegate 委派 / 独立的只读评审子 agent),结果按文件逐条列出「文件:行 [严重程度] 问题」,每次评审都有实时进度(Jobs 面板 + 会话内进度行、可停止)。 适合需要在测试前自动或手动进行代码质量审查、逐行输出问题的开发任务。
Other repositories with this package name
Install
npx -p @deepseek-ai/dsh dsh plugin --profile web add github:xinyangGL/dsh-open-code-reviewREADME
Read the full README ↗Configuration
Settings page
Two entries lead to the same form:
- Settings → Code review — the plugin’s own settings page (the nav title is 「代码评审」).
- Settings → Plugins → dsh-open-code-review — the plugin card shows a read-only summary plus a pointer to the settings page; values are edited on the settings page, not on the card.
Layout of the page:
- Basics — 6 rows, expanded:
enabled(master switch),engine,autoReview,reviewerAgent,llmMode,llmModel. - Dependent rows appear with their parent:
reviewerProvider/reviewerModel/reviewerRoundswhenreviewerAgent = spawn;llmBaseUrl/llmProtocol/llmApiKeyRefwhenllmMode = endpoint;llmProvider(an advanced row) only indshmode. - 「Advanced settings」— 13 items, folded by default. Tuning:
autoScope,autoMaxPerSession,autoMinReviewableFiles,autoMinIntervalMs,autoSkipSubagents,autoIncludeDiff,preTest. Runtime & diagnostics:audience,ocrPath,timeoutMinutes,progress,llmProvider,verbose. The fold title reads 「高级设置(13 项)」; if it holds edited-but-unsaved rows it also shows 「N 项待保存」. autoMinIntervalMsis a preset dropdown (30 seconds / 1 minute / 5 minutes / 10 minutes / Custom…) but is stored in milliseconds — pick 「自定义…」 to type a millisecond value (default60000).- Rows the settings page has touched carry a 「设置页已改」 badge.
- Values are stored per profile (they do not follow you to another profile or machine).
ocr_statusshows where each key actually came from.


Real screenshots (DSH on Windows, sidebar cropped out): the basics group, and the advanced section after expanding it.
Config sources
resolveConfigFile() (lib/config.js) reads one file — the first that exists:
- the path in
DSH_OPEN_CODE_REVIEW_CONFIG; /dsh-open-code-review.json— recommended (DSH_HOMEdefaults to~/.dsh);/config.json— only meaningful for a source / local checkout: a GitHub (git) install lives undernode_modulesand is overwritten on upgrade.
That file layer holds the keys the settings page does not have (ocrCandidates, extraArgs, env, llm.apiKey, a larger maxTimeoutMinutes, …). Precedence is settings page > config file > factory defaults, and ocr_status.fileValues lists the keys the file actually provided.
ocr’s own configuration (~/.opencodereview/config.json) is separate; ocr_status.ocrHomeConfig reports what was found there.
Key reference
Where says which settings-page row exposes the key (or file only). Defaults are the factory values in lib/config.js.
| Key | Default | Where | Notes |
|---|---|---|---|
enabled | true | Basics | Master switch. false stops automatic review and makes ocr_review / /ocr-review refuse to run (ocr_status still works). |
engine | "auto" | Basics | Default engine: auto / ocr / delegate. A tool call can override it. |
auto | "off" | Basics (autoReview) | Settings-page key autoReview writes here. off (the default since 0.5.0) / adaptive / inject / followup. |
onDemand | true | Basics (onDemand) | On-demand review: a Start code review button at the end of every completed turn, plus the runtime skill ocr-on-demand-review (so the model itself can start a review when you ask it to verify something). |
reviewer.agent | "off" | Basics (reviewerAgent) | off / spawn — run reviews through an independent read-only reviewer subagent. |
llm.mode | "dsh" | Basics (llmMode) | dsh / endpoint — see LLM routing. |
llm.model | "" | Basics (llmModel) | → OCR_LLM_MODEL; empty = follow DSH’s default model. |
reviewer.provider | "spawn" | dependent (spawn) | Subagent provider. A wrong name fails with OCR_REVIEWER_UNAVAILABLE and lists the available ones. |
reviewer.model | "" | dependent (spawn) | Empty = that provider’s default model. |
reviewer.rounds | 3 | dependent (spawn) | 1–10 round trips before automatic re-review stops. |
llm.baseUrl | "https://api.commandcode.ai/provider/v1" | dependent (endpoint) | → OCR_LLM_URL. |
llm.protocol | "openai" | dependent (endpoint) | openai / anthropic → OCR_LLM_PROTOCOL. |
llm.apiKeyRef | "COMMANDCODE_API_KEY" | dependent (endpoint) | → OCR_LLM_TOKEN, resolved from the DSH credential store (no plaintext on disk). |
autoScope | "workspace" | Advanced · tuning | Scope used by automatic reviews: workspace / range / commit / scan. |
autoMaxPerSession | 3 | Advanced · tuning | Max automatic reviews per session (0 = none; manual reviews still work). |
autoMinReviewableFiles | 1 | Advanced · tuning | Skip the automatic review when fewer files are reviewable. |
autoMinIntervalMs | 60000 | Advanced · tuning | Cooldown between two automatic reviews, in ms. |
autoSkipSubagents | true | Advanced · tuning | Turns of subagents (delegationDepth > 0) do not trigger automatic review. |
autoIncludeDiff | true | Advanced · tuning | Include the unified diff when an automatic review falls back to delegate. |
preTest | "off" | Advanced · tuning | Review before tests: off / remind / gate — see Review before tests. |
audience | "agent" | Advanced · runtime | → ocr --audience; agent = summary only, human = the fuller report. |
ocrPath | "" | Advanced · runtime | Absolute path to the real ocr executable; empty = auto-discovery. |
timeoutMinutes | 15 | Advanced · runtime | → ocr --timeout and the plugin-side hard timeout. The settings page caps it at the factory 60. |
progress | true | Advanced · runtime | Register each review as a background job (Jobs panel) and show the in-session progress row. |
llm.provider | "" | Advanced · runtime (dsh) | Provider id the bridge forwards to; empty = follow DSH’s default model. |
verbose | false | Advanced · runtime | Log the ocr command line, env and timings to the DSH log. |
autoEngine | "" | file only | Engine used by automatic reviews; empty = follow engine. |
ocrCandidates | [] | file only | Extra candidate paths tried after ocrPath ([] clears the layer). |
extraArgs | [] | file only | Raw extra arguments appended to the ocr command line. |
env | {} | file only | Extra environment variables for the ocr child process ("" deletes one). |
includeDiffMaxBytes | 120000 | file only | Cap (characters) on the diff embedded in the generated spec. |
maxIssuesInText | 40 | file only | Max issues listed in the text summary (the full data stays in issues / rawJson). |
maxTimeoutMinutes | 60 | file only | Hard upper bound for timeoutMinutes; itself clamped to 24 h (1440 min) in code. |
llm.apiKey | "" | file only | Literal key for the endpoint route. Prefer llm.apiKeyRef: a literal ends up on disk in a config file — and keep that file out of any repository (this repo ships only config.example.json). |
reviewer.persona | "" | file only | Extra persona / instructions for the reviewer subagent. |
Choosing an engine
The spec always comes from ocr, so all three engines review against the same rules; you can switch per call.
| Engine | What actually runs | Cost | Pick it when |
|---|---|---|---|
ocr | ocr’s own pipeline: deterministic engineering + its LLM reviewer, parsed back into issues | Needs an LLM for ocr — with llm.mode = dsh that is DSH’s model, key and quota | You want the most hands-off setup and OCR’s own review pipeline. |
delegate | No LLM call inside ocr: the plugin returns the ocr-parsed rules + file list + unified diff, and the current model reviews by those rules | Uses the current session’s model/quota only | You have no LLM key/quota to spare, or ocr’s LLM is not configured. engine = auto falls back to this automatically. |
reviewer.agent = spawn | Each round spawns an independent read-only subagent (own context + model, tools limited to read/grep/glob) that returns structured findings; the coding agent fixes them or explains why not, then the next round starts automatically until clean or the round limit | The most expensive, and the closest to a human review | High-risk changes where “the author reviews their own work” is not enough. |
Which one? Start with ocr (or delegate if you want reviews without spending anything extra), and switch on reviewer.agent = spawn for the changes that really matter.
LLM routing
| Mode | Behaviour |
|---|---|
dsh (default, recommended) | ocr is a separate subprocess and cannot reach cordis, so the plugin starts a small OpenAI-compatible bridge on 127.0.0.1 that accepts only a random per-run token and forwards requests to DSH’s ctx.llm.stream. Models, provider, keys, account rotation and quota stay inside DSH — nothing to configure beyond optionally pinning llm.provider / llm.model. |
endpoint | ocr talks straight to a static endpoint: llm.baseUrl + llm.protocol (openai / anthropic) + a key — llm.apiKeyRef names a DSH credential (recommended), or llm.apiKey holds a literal key in the config file. |
The plugin maps these onto the environment ocr understands: OCR_LLM_URL, OCR_LLM_PROTOCOL, OCR_LLM_TOKEN, OCR_LLM_MODEL (config.env can override or add more).
ocr_status.bridge shows the dsh bridge live: url, the masked token, requests, failed, retries, retrySkips + retrySkipReason (why a request was not retried automatically), cumulative tokens (prompt_tokens, completion_tokens, total_tokens, cache_read_tokens, cache_write_tokens, partial), lastError, lastProvider, lastModel, inflight and uptimeMs. If the host has no llm service, the plugin still works and the dsh route falls back to the static endpoint.
Usage
Tool ocr_review
| Parameter | Type | Meaning |
|---|---|---|
scope | workspace | range | commit | scan | workspace (default) = uncommitted changes, equivalent to ocr review; range uses from/to; commit uses commit; scan scans paths and needs no diff. |
from / to | string | Start / end ref of scope = range, e.g. main, feature-x (to omitted = up to the working tree). |
commit | string | Commit hash or tag for scope = commit. |
paths | string[] | Files/directories to scan for scope = scan; also filters the git diff in delegate mode. |
engine | auto | ocr | delegate | Defaults to the configured engine. auto = try ocr, fall back to delegate when ocr has no LLM. |
reviewer | boolean | true = force the independent reviewer subagent (fails with OCR_REVIEWER_UNAVAILABLE instead of falling back); false = force ocr/delegate; omitted = follow reviewer.agent. |
preview | boolean | Only list the files that would be reviewed and the exclusions; no LLM call (like ocr review -p). |
effort | low | medium | high | Review effort preset (ocr’s --effort). |
model / provider | string | Override the model / provider for this run. |
exclude | string[] | gitignore-style exclusion patterns (joined with commas for --exclude). |
rulePath | string | Path to a custom system-rule JSON file (ocr’s --rule). |
timeoutMinutes | number | Timeout for this run; defaults to the plugin config. |
repo | string | Git repository root; defaults to the session working directory. |
includeDiff | boolean | delegate mode only: embed the unified diff in the spec (default true). |
extraArgs | string[] | Raw extra arguments for ocr (advanced). |
Unknown parameters are rejected (additionalProperties: false), so a typo fails loudly instead of silently doing nothing.
The result carries: ok, code (empty on success), engine (the one that actually ran: ocr / delegate / agent), reviewer (provider, model, round, rounds, childId, stopReason, verdict = clean / issues / uncertain), scope, repository, command (the ocr command line that ran), exitCode, durationMs, reviewableFiles[] (path, status, insertions, deletions), excludedFiles[], issues[] (file, line, severity, message), summary, reviewSpec (the delegate payload), configHint, notes[], rawJson (ocr’s stdout, up to 100 000 characters), stderr, lostOutput, spillPath, llmMissing, usage (prompt_tokens, completion_tokens, total_tokens, cache_read_tokens, cache_write_tokens, partial, requests — accumulated through the bridge on the dsh route), timedOut, aborted.
Tool ocr_status
Diagnostics for one call: resolved executable + version, configPath / configSource / fileValues[], installHint, settingsPage, the effective enabled / engine / auto / llmMode / llmRoute / llmEndpoint, the bridge counters (above), reviewer availability (providers[], ready, error), credentialRef / credentialSource, ocrHomeConfig, llmEnv[], a minimal llmTest, and notes[]. Start here whenever a review fails.
Command /ocr-review
Runs a review from the input box: it injects a follow-up instruction into the current session, which then calls ocr_review (default scope = workspace) and works through the findings one by one. It accepts optional free text after the command — extra requirements such as “only review changes under src/, focus on concurrency and error handling”. If the plugin is switched off (enabled = false), the command returns an error pointing at the settings page; ocr_status still works.
On-demand review (the default since 0.5.0)
Nothing runs on its own. Two ways to start a review when you decide the change is ready:
- The button at the end of a turn. Every completed turn gets a Start code review button in the conversation tail. One click runs the same thing as
/ocr-reviewfor that session; while a review for that session is running the button turns into Reviewing… and is disabled (so double-clicking cannot stack two reviews), and a failure shows the reason inline and can be retried. It is rendered bylib/client.js(conversation.chat.turnTail); if the host does not expose the remote-command service the button simply is not there, and everything else keeps working. - The runtime skill
ocr-on-demand-review. WithonDemand = truethe plugin registers it with the host, so when you say “review this”, “verify the change” or “跑一次评审” the model can callocr_reviewitself and report file-by-file findings.ocr_statusreportsonDemandandskill.registered, which is how you confirm the registration.
The button and a typed /ocr-review both execute the same slash command on the host, so ocr_status also reports command: { name: "ocr-review", registered, reason } (added in 0.5.4). If registered is false the host refused the registration — the button and the command cannot work, and the status note says so instead of failing silently.
Turn both off (onDemand = false, or enabled = false) and the plugin is reduced to the tools plus the /ocr-review command — nothing is ever injected or auto-started. onDemand = false also removes the skill registration; the tail button disappears with it.
Review before tests (preTest, since 0.5.7)
“Can the review be wired into the standard flow — start it before the agent runs unit tests?”
Yes, and it is off by default. Three modes (preTest, settings page → Advanced → Tuning →
Review before tests, or preTest in the config file):
| Mode | What happens when a shell tool looks like a test command |
|---|---|
off (default) | Nothing. Test commands are untouched. |
remind | T |