Slow local models often cannot complete these sub-tasks within the
hardcoded 60-second limit, causing timeouts that the user-provided
--timeout flag cannot override. Raise both to 180s in task_template.json
and scan_template.json to give local models sufficient time.
* fix: ensure current file path is always injected for code_comment and improve line number tracking in resolver
* test: Cover blank-line matching in resolveFromFileContent fallback
Add a regression test for snippets that omit blank lines while the
source file retains them, and document that consecutive matching skips
blank lines on both sides.
* test: Add tests for resolving line numbers with blank lines and CRLF
* feat: add tool_calls field to JSON output for tool usage statistics
Track per-tool invocation counts in llmloop.Runner and expose them
through the ResultProvider interface so both review and scan modes
report tool call statistics in --format json output.
* fix: correct tool_calls counting and ensure stable JSON schema
Move recordToolCall after lookupTool nil check so only actually-executed
tool calls are counted. Always emit tool_calls field in JSON output for
a consistent schema, initializing by_tool to empty map when nil.
* fix: remove omitempty from tool_calls to ensure stable JSON schema
Drop omitempty from the tool_calls struct tag and initialize ToolCalls
in outputJSONNoFiles so the field is always present in JSON output
regardless of execution path.
Commit 18797f8 added the ocr scan feature but only updated the English
README. This syncs all six categories of changes (intro paragraph, quick
start examples, commands table, --exclude flag, ocr scan flags section,
and scan usage examples) to zh-CN, ja-JP, ko-KR, and ru-RU.
* feat: add ocr scan for full-file code review
Introduce a new top-level subcommand `ocr scan` (alias `s`) that reviews
whole files instead of git diffs. Use cases include reviewing unfamiliar
codebases, pre-migration audits, and ad-hoc per-directory reviews.
Architecture splits scan and diff review at the package level so the two
pipelines can evolve independently:
- internal/scan/ new package: file enumeration via `git ls-files`,
full-scan agent, FULL_SCAN_TASK rendering, preview
- internal/llmloop/ new package: shared LLM tool-use loop, three-zone
memory compression, CommentWorkerPool, AgentWarning.
Both internal/agent and internal/scan delegate to
llmloop.Runner; agent and scan never import each other
- internal/agent/ slimmed: LLM loop / compression / token aggregation
moved to llmloop; review-only orchestration remains
- internal/model/ new ScanItem (full-file payload) + Preview /
PreviewEntry / ExcludeReason shared by both modes
- internal/diff/ new gitignore.go exporting helpers reused by scan
- cmd/opencodereview/ new scan_cmd.go; shared.go consolidates startup
(loadCommonContext / loadLLMRuntime), output
(emitRunResult, ResultProvider) and stdout silencing
(quietHandle); review_cmd.go follows the same shape
Template additions:
- FULL_SCAN_TASK: dedicated prompt with Tool-call discipline guidance to
reduce gratuitous tool calls per file
- FULL_SCAN_MAX_TOOL_REQUEST_TIMES (default 60): scan-only per-file budget,
raised over diff's 30 to fit multi-finding files; --max-tools still
composes (only raise, never lower)
In scan mode, file_read_diff is filtered out of MainToolDefs since it has
no useful semantics without a diff.
Tests cover provider enumeration (with temp git repo), template rendering,
filter passes, dependency budget, flag validation, and excludeToolDef.
* feat(scan): v2 — exclude / non-git / split template / plan / batch / dedup / project-summary
Address design-review feedback by evolving `ocr scan` along seven axes
while keeping `ocr review` behavior unchanged:
1. File size cap is now configurable (ScanTemplate.MaxFileSizeBytes,
default 2 MiB; previously a hard-coded 5 MiB). The cap exists only to
bound memory reading; the real review-feasibility gate is the per-file
token budget downstream.
2. Drop the `--all` flag. Bare `ocr scan` now scans the whole repo;
`--path` narrows. Less ceremony, fewer redundant flags.
3. New `--exclude` flag on both review and scan. Comma-separated
gitignore-style patterns; merged with rule.json's exclude layer via
the new shared.applyCLIExcludes helper.
4. Scan supports non-git directories. internal/scan.Provider chooses
between `git ls-files` (full .gitignore semantics) and a
filepath.WalkDir fallback (root .gitignore + ExcludedDirs blocklist)
per isGitRepo probe. loadCommonContext takes a requireGit bool; review
keeps the hard requirement, scan relaxes it.
5. Scan configuration lives in its own file. internal/config/template:
- new ScanTemplate type with LoadScanDefault/ApplyLanguage/Validate
- new embedded scan_template.json
- Template loses the FULL_SCAN_* fields (review template unaffected)
scan.Agent.Args.Template now holds a ScanTemplate; toLoopTemplate
adapts it for llmloop.Runner.
6. New scan phases — each nil-able in the template and toggleable via a
CLI flag, so users can revert to v1 behavior trivially:
* PLAN_TASK (--no-plan): per-file pre-pass that outputs a JSON
summary + checkpoints, embedded into MAIN_TASK as {{plan_guidance}}.
formatPlanGuidance renders to markdown; malformed JSON falls back
to raw text. PLAN_TASK failure never blocks the main loop.
* BATCH_STRATEGY (--batch): files are grouped before dispatch.
"none" preserves v1, "by-language" (default) groups by extension,
"by-directory" groups by first-level subdir. BatchSize caps natural
groups so a single language with 500 files doesn't form one giant
batch. Batches are processed sequentially; files within a batch
remain concurrent up to MaxConcurrency.
* DEDUP_TASK (--no-dedup): per-batch postprocess that asks the LLM
to cluster near-duplicate comments. Output is a `groups` JSON;
every input id must appear exactly once or the result is rejected
and originals are kept (safety: never silently lose comments).
CommentCollector grows Snapshot/Since/ReplaceSince for this.
* PROJECT_SUMMARY_TASK (--no-summary): once-per-run cross-file
summary appended to text output and surfaced as `project_summary`
in JSON output. ResultProvider grows ProjectSummary(); agent.Agent
returns "" (review mode has no project summary).
All four new LLM steps record token usage via runner.RecordUsage so
aggregate counters stay accurate.
7. Tests cover the new pure code paths:
- batch_test.go: 3 strategies, BatchSize cap, language-key edge cases
- dedup_test.go: groups parser, malformed shapes, fence stripping,
payload field selection
- agent_test.go: formatPlanGuidance variants, buildSummaryCommentsList
truncation, maybeRunPlan skip paths
- provider_test.go: non-git directory walker fallback
- template_test.go: ScanTemplate loads / ApplyLanguage / review
template no longer contains scan fields
The seven phases can be reverted independently by toggling flags or
clearing the corresponding optional template fields; nothing forces the
new behavior on existing review users.
* fix(scan): three real bugs surfaced by SCAN_PLAN_TASK self-review
A v2 end-to-end test (ocr scan --path internal/scan/preview.go) had the
PLAN_TASK phase flag three concrete bugs in the scan package itself.
This commit fixes them and adds regression tests.
1. Preview() mutated a.items as a side-effect.
Both Preview and Run wrote to a.items. Calling Preview before Run
silently primed Run with the preview's enumeration instead of
triggering a fresh listFiles. Preview is documented as a read-only
dry-run; uphold that. Local variable now; a.items stays nil after
Preview returns.
2. Preview.result.Entries was nil when there were no items.
With no items at all the loop never ran, so Entries remained nil and
JSON marshalling produced "files":null. Pre-allocate to a non-nil
empty slice so the JSON contract stays "files":[] regardless.
3. Provider.Enumerate and listFilesViaWalk never checked ctx.Done().
On a large repo a cancelled context would still complete the full
walk before the caller saw an error (every iteration costs a stat or
ReadFile syscall). Add the check at the top of each iteration in
both the git-ls-files path and the walker fallback path; the walker
returns ctx.Err() so filepath.WalkDir propagates the cancellation.
Three new regression tests pin the contracts:
- TestPreview_DoesNotMutateAgentItems
- TestPreview_EmptyResultEntriesIsNonNilSlice
- TestProvider_Enumerate_RespectsContextCancellation
* feat(scan): cost estimate + token budget cap; fix file_find on non-git dirs
Two cost-control features and one robustness fix, all surfaced by running
the scanner against a real ~870K-token repository.
Cost estimate (internal/scan/estimate.go):
- Before dispatch, Run prints an order-of-magnitude projection of token
usage (input/output/total), derived from per-file content size × an
assumed round count, plus the optional plan/dedup/summary phases.
- Deliberately reports tokens only, not dollars — pricing varies per
provider/model and a precise figure would mislead. Actual usage is still
reported from the API after the run.
Token budget cap (--max-tokens-budget / ScanTemplate.MaxTokensBudget):
- Caps total token usage for one scan. The gate is checked per file inside
dispatchBatch, right before acquiring a concurrency slot: if tokens
already spent plus a look-ahead estimate of the next file would exceed
the budget, that file and all remaining files are skipped and a
token_budget_reached warning is recorded.
- An earlier batch-level gate was too coarse: with the default by-language
batching, a Go-heavy repo puts most files in one batch, so the gate only
fired between batches and overran the budget ~2.4×. The per-file gate
bounds overrun to roughly one in-flight file per worker (~1.3× at
concurrency=1 in testing).
- 0 = unlimited (unchanged default behavior).
Phase-gate helpers (planEnabled/dedupEnabled/summaryEnabled) consolidate
the "template defines it AND --no-* flag not set" checks so the cost
estimate and the dispatch path agree on which phases will actually run.
file_find non-git fallback (internal/tool/file_find.go):
- `git ls-files` exits 128 in a non-git directory, which spammed failures
when scanning plain directories (scan already supports non-git repos via
the provider's walker, but the file_find tool did not). Now falls back
to filepath.WalkDir honoring the root .gitignore and the default
excluded-dir blocklist when git fails and no specific ref is requested.
Tests:
- estimate_test.go: humanTokens formatting, per-file vs aggregate estimate
consistency, phase scaling, phase-gate tri-state.
- budget_test.go: fake LLM client drives the gate deterministically —
verifies dispatch stops before exceeding budget and that 0 = unlimited.
- file_find_test.go: non-git directory fallback finds files, honors
.gitignore / blocklist, and returns the not-found sentinel correctly.
* docs(readme): document ocr scan subcommand and flags
ocr scan existed but was undiscoverable from the README. Add it to the
intro blurb, Quick Start, the Commands table, Examples, and a dedicated
flags table (path / exclude / preview / max-tokens-budget / no-plan /
no-dedup / no-summary / batch / format / concurrency / rule / repo).
Note non-git support and the pre-run cost estimate. Also backfill the
--exclude flag in the ocr review flags table (added during the v1.3 merge
but never documented).
Flag names and defaults verified against `ocr scan -h`.
* fix(scan): code_search works in non-git directories via git grep --no-index
code_search relied on `git grep`, which exits 128 in a non-git directory —
so `ocr scan` on a plain directory (already supported by file enumeration and
file_find) silently returned errors instead of search results. Detect that
failure and retry with `git grep --no-index --exclude-standard`, which searches
the working tree directly while still honoring .gitignore. Reuses all existing
grep flag/parsing logic; ref-based search still requires a real repo.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* fix(scan): preserve context on compression failure; fix NUL parsing in gitLs
Address three real bugs from the PR #93 automated review that regressed when
compression moved into internal/llmloop:
- Sync compression failure / empty summary now return the original messages
instead of truncating to the frozen zone, which discarded the whole
per-file conversation context.
- Async compression now abandons the job on error instead of applying a
truncated snapshot, and re-applies messages appended while it ran
(snapshotLen), so concurrent tool results are no longer lost.
- scan Provider.gitLs uses cmd.Output() instead of CombinedOutput() so
stderr can't corrupt the NUL-delimited (-z) filename parsing.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
* feat(llm): update provider model lists
Sync built-in model presets with latest vendor offerings.
* docs: update providers screenshot
Reflect the latest provider list in the config provider TUI.
PR #161 refactored matchProjectRule into matchProjectRuleEntry but
removed the empty-rule guard, causing entries with rule:"" to match
and return an empty string instead of falling through to the next
layer or system rule. This restores the skip-on-empty semantics while
honoring merge_system_rule:true with empty rule as "lock system rule".
Commit 9d2800f added `ocr config unset custom_providers.<name>`
documentation to README.md but missed the four localized copies.
Add the command table row and usage example to zh-CN, ja-JP, ko-KR,
and ru-RU READMEs.
* feat: add ability to delete custom providers from configuration
Implements GitHub issue #136.
CLI: add 'ocr config unset custom_providers.<name>' command to delete
a custom provider from config. If the deleted provider is the active
one, clears 'provider' and 'model' fields and prompts the user.
TUI: press 'd' on Custom tab to delete a provider with y/n confirmation.
Shows warning when deleting the active provider. Deletions are persisted
even if the user cancels provider selection afterward.
- Add runConfigUnset() with key validation and active-provider handling
- Add 'unset' case to parseConfigArgs() and printConfigUsage()
- Add delete confirmation state machine to providerTUIModel
- Add applyProviderDeletions() helper in provider_cmd.go
- Add 10 new tests covering CLI parsing, deletion logic, and TUI flows
- Update README with unset command documentation
* fix: address PR review feedback
- Add defensive bounds check for deleteTargetIdx before deletion
- Use explicit slice copy to avoid retaining references (memory leak)
- Update subCmd comment to reflect 'set' and 'unset' values
* refactor: extract shared deleteCustomProvider and improve test coverage
Address PR review feedback from lizhengfeng101:
- Extract deleteCustomProvider() as a pure function shared by both
runConfigUnset (CLI) and applyProviderDeletions (TUI)
- Extract unsetCustomProvider() accepting configPath for testability
- Add existence check in applyProviderDeletions (skip non-existent providers)
- Rewrite 3 tests to call actual functions instead of inlining logic
- Remove unused strings import from config_cmd_test.go
* style: use [ocr] WARNING prefix for active provider deletion messages
Align with project convention (output.go, flags.go): warnings use
'[ocr] WARNING' prefix and write to stderr instead of stdout.
* fix: address second round of PR review feedback
- Fix test state pollution in TestUnsetInvalidKey: use t.Run sub-tests
with independent config files per case (#7)
- Log warning instead of silently swallowing errors in
applyProviderDeletions (#9)
- Add comment explaining existingCfg snapshot assumption in
viewCustomTab (#10)
- Simplify runConfigUnset error message to single line for consistency
with project style (#11)
* ci(workflow): add rate-limit-aware retry for PR review comment posting
Add GitHub REST API rate-limit handling to the ocr-review workflow:
- Implement computeRetryDelayMs() following GitHub's documented strategy:
* Honor retry-after header (seconds or HTTP-date)
* Wait until x-ratelimit-reset when primary limit is exhausted (remaining=0)
* Exponential backoff (>=60s base) for secondary limits without a header
* Backoff for transient 5xx/408 errors
- Add per-comment retry loop with configurable attempts and delays
- Add logRateLimitQuota() to log and proactively throttle on low remaining quota
- Honor batch createReview rate-limit headers before per-comment retry
- Cap all waits (including header-derived) to avoid stalling the CI job
- Expose tuning via OCR_* env vars (retries, delays, thresholds)
- Update example workflow docs with retry/delay configuration reference
* fix(workflow): use shorter transient backoff base and dedupe header lookup
- Transient server errors (5xx/408) now use a 2s base delay instead of
the 60s rate-limit base, matching the comment's stated intent and
avoiding unnecessary CI stalls on short-lived server hiccups.
- Extract a shared getHeader() helper for case-insensitive header
lookup, reused by both computeRetryDelayMs and logRateLimitQuota to
eliminate duplicated logic and ensure consistent robustness.
* doc: revert example doc
The release job uses ubuntu:24.04 which lacks git. After adding
commit-based release notes generation, git commands (config/describe/log)
fail with "git: not found". Install git before checkout so the full
history is available for release notes.
Replace GitHub releases download with `npm i -g` so platform package
installations also get auto-updates. On permission failure, write a hint
file that bin/ocr.js reads to prompt the user to update manually.
* feat: add install.sh for one-line release install
Add a POSIX install script that detects OS/arch, resolves the latest
release (override with OCR_VERSION), verifies the SHA-256 checksum
fail-closed, and installs the ocr binary to /usr/local/bin (override
with OCR_INSTALL_DIR, sudo fallback when needed).
README now leads with a single curl | sh command and keeps the manual
per-platform downloads in a collapsible section for Windows and offline
use.
* fix: harden install.sh shell robustness
- replace word-split $SHA_CMD invocation with a sha256() wrapper function
- capture github api response and fail explicitly on curl error instead of
masking it through the tag-parsing pipeline under set -eu
* fix: harden install.sh from local ocr review
- trap INT/TERM in addition to EXIT so the temp dir is cleaned on signals
- install binary with install(1) so sudo installs are root-owned in system dirs
- make sha256() self-contained (errors if no checksum tool) and drop the now
redundant up-front guard
* docs(i18n): sync install one-liner to localized READMEs
Apply the same GitHub Release install-section change as README.md to the
zh-CN/ja-JP/ko-KR/ru-RU translations: lead with the curl|sh one-liner plus
OCR_INSTALL_DIR/OCR_VERSION override example, and move the per-platform
manual downloads into a <details> block.
Use "Proportion" (EN) and "Доля" (RU) instead of the bare "%" symbol
for consistency with the Chinese, Japanese, and Korean translations
which already use their respective words for "proportion".
The generic YAML rule only checked spelling in keys, which is insufficient
for CI/CD workflow files. Add layered rules with security, correctness,
reliability checks for .github/workflows/ and structure validation for
other .github/ config files (issue templates, release config).
Add continuous integration pipeline that runs go vet, tests with
race detection, and a build check on every push to main and PR.
Satisfies the OpenSSF Best Practices test_continuous_integration criterion.
Satisfy the OpenSSF Best Practices "release_notes" criterion by parsing
commits between tags and categorizing them into Features, Bug Fixes,
Refactoring, and Documentation sections.
- Switch logo from logo.svg to logo-core.svg with smaller size
- Replace <p> wrapper with <div> and add <h1> title
- Remove redundant tagline and separator
- Add DeepWiki badge to all README variants
- Sync changes across all i18n README files (zh-CN, ja-JP, ko-KR, ru-RU)
* ci: add rate limit handling and version verification to GitHub Actions workflow
- Add version check after OCR installation to verify successful setup
- Implement exponential backoff retry logic for GitHub API rate limits
- Add delays between individual comment posts to avoid secondary rate limits
- GitHub enforces ~80 content-generating requests per minute; spacing calls
helps stay under that threshold with 2-second base delay and up to 3 retries
* ci: refine rate limit handling in GitHub Actions workflow
- Add `|| true` to ocr version check for error isolation
- Narrow rate limit detection to 429 and 403 with rate-limit
message matching, avoiding retries on permission/auth failures
- Extract hardcoded delay constants into env-configurable
variables (OCR_RETRY_BASE_DELAY, OCR_MAX_RETRIES,
OCR_SUCCESS_DELAY, OCR_FAILURE_DELAY) with sensible defaults
- Document optional environment variables in workflow header
* docs: add environment variable configuration guide for retry and delay settings
* ci: add rate-limit resilience and version check to GitLab CI pipeline
- Add `ocr version || true` after install for diagnostic logging
- Add `api_request_with_retry` function with exponential backoff
for 429 and 403 (rate-limit message matching) errors
- Respect GitLab `Retry-After` header when present
- Extract delay constants into CI/CD-configurable variables
(OCR_RETRY_BASE_DELAY, OCR_MAX_RETRIES,
OCR_SUCCESS_DELAY, OCR_FAILURE_DELAY) with defaults
- Add pacing delays between successful/failed discussion posts
- Document optional CI/CD variables in pipeline header comments
* docs: add retry/delay settings section to GitLab CI README
* ci: fix rate-limit retry delay exhaustion handling in CI workflows
- GitHub Actions: distinguish exhausted rate-limit retries from other errors, apply SUCCESS_DELAY (2s) instead of FAILURE_DELAY (1s) when retries exhausted
- GitLab CI: return structured result from api_request_with_retry to differentiate failure types, apply context-aware delays based on rate-limit exhaustion status
- Both: prevent perpetuating rate-limit failures by using longer delays after retry exhaustion
* ci: align GitHub Actions rate-limit retry with header-based strategy
Derive wait durations from response headers (retry-after, x-ratelimit-reset)
instead of fixed exponential backoff, add proactive throttle when remaining
quota is low, honor batch-level rate limits before per-comment retry, and add
support for transient 5xx/408 errors.
* feat(gitlab-ci): enhance rate-limit handling with jitter, max retry delay, and proactive throttling
- Add ±25% jitter on retry delays to avoid thundering herd problems
- Add OCR_MAX_RETRY_DELAY (default 60s) to cap per-retry wait time
- Add OCR_RATE_LIMIT_THRESHOLD (default 10) for proactive throttling
based on GitLab RateLimit-Remaining response header
- Parse Retry-After header properly (handle non-numeric values)
- Apply retry logic to all API requests (notes, versions, discussions)
- Parse and log RateLimit-Remaining/Limit headers for observability
- Double pacing delay when remaining quota drops below threshold
- Update README with new configuration variables and behavior docs
* fix(examples): sync rate-limit docs with script defaults and add missing variables
- GitHub Actions README: fix OCR_RETRY_BASE_DELAY default from 2000 to 60000
(matching script code and header comments)
- GitHub Actions README: add missing OCR_RETRY_MAX_DELAY, OCR_LOW_REMAINING_THRESHOLD,
OCR_LOW_REMAINING_SPACING variables
- GitHub Actions README: add GitHub Rate Limits doc reference link
- GitHub Actions yml header: add OCR_LLM_USE_ANTHROPIC and llm.extra_body notes
- GitLab CI yml header: add llm.extra_body note
- GitLab CI README: add GitLab Rate Limits doc reference link
* ci(examples): unify header lookup and add transient retry backoff
- GitHub Actions: extract inline header closure into a reusable getHeader
helper; use it in both computeRetryDelayMs and logRateLimitQuota for
consistent case-insensitive header access.
- GitHub Actions: use a 2s transientBase for 5xx/408 exponential backoff
instead of the 60s rate-limit base, since server hiccups are typically
short-lived and the longer base stalled CI jobs unnecessarily.
- GitLab CI: add a _get_header helper and route all header access
(Retry-After, RateLimit-*) through it, matching the GitHub Actions
approach.
- GitLab CI: add transient retry logic for 5xx/408 errors with a 2s
base delay, so server errors no longer fail immediately.
Add Codex GPT-5.5 benchmark data: F1 8.36%, Precision 27.82% (74/266),
Recall 4.92% (74/1505), avg time 2m58s, avg token 525K.
Update legend to show Codex version and /review command.
Regenerate benchmark screenshots for en and zh.
Extract utility functions (stripEmptyPlanBlock, stripMarkdownFences,
buildMessageXML, copyMessages, countMessagesTokens, reviewModeString,
detectGitBranch) into util.go and all compression logic into compression.go
to improve readability (agent.go: 1489 → 1114 lines).
Fix pre-existing compression bugs from commit 14adf6f:
- Return unmodified messages on compression failure instead of truncating
to frozen zone (which discarded all conversation context)
- Check error in async compression goroutine to avoid applying failed results
- Track snapshot length to append post-snapshot messages when applying async
compression, preventing silent message loss
- Strip old <previous_review_summary> before appending new one to prevent
cumulative frozen zone bloat across multiple compressions
- Guard pendingJob cleanup to only clear when it matches the completed job,
preventing accidental clearing of a newly scheduled job
- Add context.Context and 5s timeout to detectGitBranch
- Deep copy ToolCalls in copyMessages to match session/history.go
- Reuse finalCount in addNextMessage to avoid redundant token counting
Move all LLM prompt content from inline JSON strings in task_template.json
to individual Markdown files under prompts/, following the same embed.FS
pattern used by internal/config/rules/. This improves maintainability by
enabling native syntax highlighting, cleaner diffs, and separation of
prompt content from runtime configuration.
Also removes two dead config fields (TOOL_REQUEST_WAIT_TIME_MS,
MAX_SUBTASK_EXECUTION_TIME_MINUTES) that had no runtime consumers.
Add benchmark comparison data (metrics table, key conclusion, and
screenshot) to EN, ZH-CN, JA-JP, KO-KR, and RU-RU READMEs.
Non-Chinese languages use the English screenshot.
Update Claude Code benchmark results for Claude-4.8-Opus and GLM-5.1,
refresh token cost ratio (1/5 → 1/9) and F1 score (26.1% → 25.1%) to
reflect latest data. Add clickable sort headers for F1/Precision/Recall
columns with visual indicators. Centralize hardcoded stats into i18n
and use semantic i18n keys for benchmark subtitle.
Add preset provider list (Anthropic, OpenAI, DashScope, DeepSeek, Z.AI)
and custom endpoint support details to the multi-model protocol feature
description in both en.ts and zh.ts.
The main npm package included all 6 platform binaries (~243MB) because
.npmignore did not exclude the opencodereview-* artifacts downloaded
during CI. Adding a files whitelist reduces the package from ~243MB
to ~1.4MB.