* docs: clarify --from/--to uses merge-base (three-dot) semantics
Fixes#579. internal/diff/git.go's ModeRange computes the range via
the two refs' merge-base, matching the CLI --help text (flags.go:206,
'merge-base mode'). The three Quickstart locales incorrectly described
this as a..b (two-dot) comparison; README.md was ambiguous. All four
now describe the actual merge-base behavior in plain language rather
than relying on git dot-notation.
* docs: sync merge-base wording to remaining locale READMEs
Addresses review feedback on #613 — zh-CN, ja-JP, ko-KR, ru-RU README
comments still described the old (incorrect) two-dot comparison.
The project reached OpenSSF Best Practices Gold level, so update the
static status badge in all localized READMEs accordingly. The label
changes from Silver to Gold and the color to metallic gold (D4AF37).
Wire ru into the docs site language switcher and i18n strings, add
quickstart/installation translations, README Russian screenshots, and
include ru in the docs translation-sync guard. Remaining docs pages
fall back to English.
Reduce the large content overlap between the README files and the docs
site (pages/src/content/docs). Add a Documentation section linking to
open-codereview.ai/docs, and collapse the Commands, Review Rules, and
Configuration Reference sections into one-line summaries plus links.
This makes the docs site the single source of truth for reference
content and cuts the multi-language maintenance burden.
Applied consistently across all five localized READMEs (en/zh/ja/ko/ru).
* feat(examples): add Gerrit CI integration for publishing review results
Adds examples/gerrit_ci following the gitflic_ci CI-glue pattern (#316):
a stdlib-only post_review.py that reads 'ocr review --format json' and
publishes summary, inline comments, suggestion blocks, and file-level
findings in ONE batched POST /a/changes/{change}/revisions/{rev}/review,
tagged autogenerated:opencodereview with notify=OWNER and
omit_duplicate_comments.
Decisions (validated against a live Gerrit 3.14 in Docker):
- Plain comments, bare line = end_line, no CommentRange: the range form
{start,0,end,0} renders lines start..end-1 in the UI (end_character 0
excludes the final line), so correct ranges would need file contents
in CI. Verified via UI screenshots during E2E.
- Preemptive HTTP Basic auth (urllib's handler does not preempt),
XSSI )]}' stripping, HTML-200 detected as config error, 400 batch
fold-retry, 409 change-closed tolerated (defensive on modern Gerrit:
label-free reviews post fine on closed changes), password scrubbed
from all error output.
- Jenkins Gerrit Trigger as the reference integration; the script is
trigger-agnostic via flags/env (Zuul/hook recipes in the README).
Jenkinsfile always passes the injected patchset SHA (revision race).
45 table-driven stdlib-unittest tests, red-to-green TDD; E2E against
gerritcodereview/gerrit covering live post, unicode round-trip, dedup
re-run, and failure paths (401 exit 2 with scrubbed password).
* fix(examples/gerrit_ci): harden post_review.py per review findings
- Send Authorization via add_unredirected_header so Basic credentials
cannot follow a redirect to another host (urllib forwards ordinary
headers cross-host).
- Reject non-object JSON input cleanly instead of an AttributeError
traceback; validate --timeout > 0 at argparse time.
- Warn on stderr when the 400-fallback folded summary is truncated, and
report the fold accurately instead of claiming N inline comments.
- Pin drafts=KEEP in ReviewInput (depot_tools convention; old servers
defaulted to deleting the caller's drafts).
- Jenkinsfile: fetch with an explicit dest refspec so
origin/$GERRIT_BRANCH materializes under narrow-refspec clones;
comment out extra_body thinking (OpenAI rejects unknown fields).
- Gitflic parity: optional positional input arg; single-sourced
'current' revision default; scrub() skips sub-4-char passwords.
- README: document exit 1 and the defensive 409 branch; add gerrit_ci
row to all five root READMEs (parity with the GitFlic example).
- Tests: 44 -> 55, covering stdin input, flag-over-env precedence,
fold-retry failure, fold truncation, GERRIT_CHANGE_URL wiring,
non-dict JSON, timeout validation, positional input.
* fix(examples/gerrit_ci): address OCR bot review on #401
- Jenkinsfile: resolve the LLM endpoint from the OCR_LLM_URL/TOKEN/MODEL
env triple instead of `ocr config set`, so the auth token stays
env-only and is never written to ~/.opencodereview/config.json on a
shared agent (OCR_CONFIG_PATH is deliberately ignored by write paths,
so it can't redirect the leak). Pin the npm install to a validated
version. Document the config-file fallback (and its cleanup) for
extra_body, which has no env equivalent.
- post_review.py: scrub the base64(user:password) Authorization value
from error output too, not just the raw password — a proxy echoing the
request header would otherwise leak decodable credentials. +1 test.
* feat(examples/gerrit_ci): scoped retry + robustness polish
Post-review hardening from an OSS-precedent study (depot_tools, kudu,
Gerrit REST docs):
- Bounded retry (3 attempts, exp backoff) in make_poster, scoped to the
provably-safe failures only: HTTP 5xx and pre-response connection
errors (refused/reset/DNS). Read-timeouts are deliberately NOT retried
— a timeout is ambiguous (the server may have applied the review) and
omit_duplicate_comments dedupes only inline comments, not the summary
message, so a blind retry could post a duplicate change message. 4xx
(400/401/404/409) propagate unchanged so main() classifies them as
before.
- Document why plain comments are used, not robot_comments: the latter
is deprecated since Gerrit 3.6, disabled-by-default in 3.12, and
slated for removal; the tag already marks bot origin.
- Fold fallback: strip the '; N posted as inline comment(s).' clause
from the reused summary so the folded message doesn't claim inline
comments were posted and then explain they couldn't be placed.
- README: document the retry scoping and note fix_suggestions / label
voting as intentional future options.
Tests: 56 -> 61 (5 retry cases: 5xx-then-ok, conn-err-then-ok,
5xx-exhaust, read-timeout-not-retried, 4xx/409-not-retried).
* feat: add install.ps1 for Windows one-line install
Give Windows users the same checksum-verified one-liner experience as
install.sh, and document it next to the curl instructions.
Signed-off-by: shaurya2k06 <shaurya2k06@gmail.com>
* fix(install): harden arch detection and document pipe-to-shell risk
Clarify unsupported/empty architecture errors in install.ps1, and recommend
download-and-inspect as a safer alternative to curl|sh and irm|iex.
Signed-off-by: shaurya2k06 <shaurya2k06@gmail.com>
* fix(install.ps1): fail closed when PROCESSOR_ARCHITECTURE is empty
Do not assume AMD64 from Is64BitOperatingSystem — that is also true on
ARM64 Windows and would silently install the wrong binary.
Signed-off-by: shaurya2k06 <shaurya2k06@gmail.com>
---------
Signed-off-by: shaurya2k06 <shaurya2k06@gmail.com>
* feat(delegate): add delegation mode for host-agent driven code review
Add `ocr delegate` subcommand that provides deterministic file selection
and rule resolution without calling any LLM. This enables AI coding agents
to perform reviews themselves using OCR only for engineering scaffolding
(preview which files to review, resolve grouped rules by path).
Includes:
- `ocr delegate preview` — outputs reviewable file list with mode/ref metadata
- `ocr delegate rule <path...>` — outputs review rules grouped by content
- Claude Code plugin command (delegate-review.md)
- Skill definitions for Claude Code, Codex, and Cursor
- Unit tests for internal/delegate package
- README documentation synced across all 5 locales
* fix(delegate): group rules by source, pattern and text
GroupRules keyed groups on rule text alone, so files sharing identical
rule text but resolved from different sources or matched by different
patterns were merged into one group that kept only the first file's
Source/Pattern metadata. Use a composite (source, pattern, text) key so
each group's provenance is accurate for every file it contains.
* feat(llm): add OpenAI Responses API support
Add `openai-responses` as a third LLM protocol alongside `anthropic` and
`openai-chat-completions`, enabling code review via the OpenAI Responses
API (/v1/responses) for GPT-5.x / o-series models.
Protocol naming refactor (backward-compatible):
- Canonicalize "openai" -> "openai-chat-completions" (alias still accepted)
- Add NormalizeProtocol / ValidateProtocol / IsAnthropicProtocol helpers
- Registry uses canonical constants; resolver normalizes everywhere
New OpenAIResponsesClient (stateless replay, per DESIGN_STATE_CACHE_PHASE.md):
- system messages -> Instructions; tool calls -> function_call items keyed
by CallID so the agent loop pairs results correctly
- store=false (privacy); prompt_cache_key = sha256(instructions)[:32]
- Phase fields (commentary/final_answer) dropped with TODO for gpt-5.3-codex+
Config plumbing:
- llm.protocol field + OCR_LLM_PROTOCOL env (priority over use_anthropic /
OCR_USE_ANTHROPIC); TUI exposes all three protocols in Custom & Manual
- anthropic-vertex rejected with friendly "not yet implemented" message
Docs: protocol reference, config examples, env var table, and Responses API
notes (store=false caching caveat, cache key derivation, Phase TODO) updated
across en/zh-CN/ko-KR/ja-JP/ru-RU READMEs.
* refactor(llm): switch PromptCacheKey to precomputed scheme via ChatRequest.CacheKey
Replace per-turn sha256 computation inside buildResponsesParams with a
precomputed cache key that callers compute once per session and pass
through ChatRequest.CacheKey (json:"-"). The key now incorporates the
first user message alongside instructions, so different files under
review land in distinct cache buckets — the previous instructions-only
key was identical across all files.
Changes:
- ChatRequest gains CacheKey string field (json:"-", zero impact on
Chat Completions / Anthropic clients which never read it)
- New llm.ComputeCacheKey helper: sha256(instructions + "\x00" +
firstUser)[:32]
- responses_client.go: reads req.CacheKey directly, removes promptCacheKey
function and first-user-message scanning
- loop.go: RunPerFile computes cacheKey once before the loop, reuses
every turn
- All 8 remaining call sites (agent, scan, relocation, compression,
llm_cmd) compute once at request construction
- Update PLAN_RESPONSES_SUPPORT.md and DESIGN_STATE_CACHE_PHASE.md to
reflect the precomputed scheme
- Update tests: passthrough tests for client, dedicated TestComputeCacheKey
* refactor(llm): use canonical protocol name "openai" and UUID-based session ID for cache key
Two changes to maximize backward compatibility and simplify the design:
1. Protocol naming: revert ProtocolOpenAIChatCompletions value from
"openai-chat-completions" back to "openai". Old config files with
protocol: "openai" are now identical to what new configs write —
zero behavioral difference. The alias direction in NormalizeProtocol
is reversed: "openai-chat-completions" -> "openai" (for configs
written during this branch's testing phase only).
2. Cache key: replace content-based sha256 hash (ComputeCacheKey) with a
random UUID session ID. The agent loop generates one UUID per file in
RunPerFile and passes it via ChatRequest.SessionID; the Responses
client uses it as prompt_cache_key. Single-turn call sites no longer
set a cache key (no multi-turn caching benefit). This removes the
need to scan messages or compute hashes, and eliminates collision
risk between files with similar content.
ChatRequest.CacheKey is renamed to SessionID to reflect its actual
semantic — a per-session identifier that the Responses client
repurposes as prompt_cache_key.
Also updates PLAN_RESPONSES_SUPPORT.md, all 5 README translations,
test expectations, and promotes google/uuid to a direct dependency.
* refactor(llm): remove IsAnthropicProtocol helper and anthropic-vertex special case
* refactor(llm): remove openai-chat-completions branch-internal alias
* docs: remove DESIGN_STATE_CACHE_PHASE and PLAN_RESPONSES_SUPPORT design notes
* fix(llm): address code review findings on Responses API support
- provider_cmd: clear stale use_anthropic when switching to openai-responses
- resolver: validate preset protocol with ValidateProtocol for consistency
- responses_client: swap usage mapping to resolveUsage-first (matches OpenAIClient)
- responses_client: map failed/cancelled statuses to 'error' finish reason
- usage_resolver: add Responses API field paths (input_tokens, output_tokens,
input_tokens_details.cached_tokens)
- add tests for all four fixes
* fix(llm): mirror use_anthropic when setting llm.protocol
- config_cmd: 'ocr config set llm.protocol' now mirrors use_anthropic
(anthropic -> true, OpenAI family -> false) for backward compat with
older binaries that predate llm.protocol
- provider_cmd: openai-responses now sets use_anthropic=false instead of
nil, so older binaries fall back to the OpenAI family rather than
wrongly defaulting to anthropic
- update tests for both write paths
* fix(llm): mirror protocol when setting llm.use_anthropic
- config_cmd: 'ocr config set llm.use_anthropic' now mirrors protocol
(true -> anthropic, false -> openai) so the two fields never disagree,
matching the reverse llm.protocol mirroring added previously
- without this, setting use_anthropic=true while protocol=openai-responses
left a contradictory config that misled older binaries into using the
anthropic protocol against an OpenAI endpoint
- extend tests to cover both values and stale-protocol overwrite
* docs(llm): fix NormalizeProtocol comment to match lowercasing behavior
The comment claimed unknown values are 'returned unchanged', but the
default branch lowercases and trims them (corroborated by the
'gRPC -> grpc' test). Update the wording to describe the actual
behavior so callers aren't misled about round-trip fidelity.
* docs(llm): drop OpenAI Responses API implementation notes from READMEs
* fix(llm): address code review findings on Responses API support
- config: preserve openai-responses when setting llm.use_anthropic=false
(only mirror to openai when protocol is unset or a legacy anthropic/openai)
- config: add Protocol values guidance to unknown-key error message
- protocol: extract normalized local var in NormalizeProtocol
- responses_client: align SDK base URL trimming with NewOpenAIClient
- responses_client: drop unused test-only sdkBaseURL method
* fix(llm): use protocol constants consistently
- providers: edenai now uses ProtocolOpenAIChatCompletions like the rest
of the registry instead of the "openai" string literal
- provider_cmd: print the normalized protocol variable (what is actually
saved) instead of the raw TUI value
* fix(llm): drop stream key and surface non-completed status in Responses client
Address two PR review comments on OpenAI Responses API support:
1. extra_body.stream=true was forwarded to Responses.New, making the API
return SSE while the SDK expects JSON and breaking every call. Skip the
'stream' key (like OpenAIClient treats it as a non-forwarded key) while
still forwarding other extra_body entries.
2. The Responses API returns HTTP 200 even for failed/cancelled (terminal)
and queued/in_progress (background) states, so the SDK reports nil error.
Surface these as real errors so callers branching on err != nil (ocr llm
test, review loop) fail instead of treating a dead response as success.
Add table-driven tests covering both fixes.
* feat(action): extract reusable OpenCodeReview PR review GitHub Action
Consolidate the reusable-action work into one commit:
- Add composite action (action.yml at repo root for GitHub Marketplace;
helper at scripts/github-actions/post-review-comments.js) porting the
sticky summary, incremental posting, and retry idempotency logic.
- Add unit tests covering the ported idempotency behavior.
- Switch the in-repo CI workflow to use the reusable action.
- Add and refine example reusable workflows for consumers.
* ci(workflow): point ocr-review at root action.yml and quote boolean inputs
- Fix uses: to ./ now that action.yml lives at the repo root.
- Quote sticky_summary/incremental/upload_artifacts as strings to
match action.yml's input declarations (composite-action inputs are
always strings) and silence actionlint.
- Enable upload_artifacts for this workflow.
* docs(examples): point reusable demo at root action.yml
The example workflow referenced alibaba/open-code-review/action@v1,
but action.yml now lives at the repo root, so the /action subpath no
longer resolves. Use alibaba/open-code-review@v1 and update the stale
action/README.md comment to point at the root action.yml.
* docs(examples): sync README to root action.yml references
The example README still pointed at the relocated/deleted locations:
action.yml is now at the repo root, so update all 11
alibaba/open-code-review/action@v1 references to
alibaba/open-code-review@v1, and repoint the action/ directory and
action/README.md links to the root action.yml.
* fix(examples): prevent unrelated PR comments from canceling ocr-review
GitHub Actions evaluates concurrency before the job-level if-condition.
The flat group mapped every issue_comment event on a PR into the review's
group, so any comment (even a skipped conversation reply) canceled any
in-progress review.
Match the reusable demo's conditional group: PR events and human-authored
/open-code-review/@open-code-review comments share a per-PR group, while
non-matching comments fall back to a unique noop-<run_id> group that can
never collide with a real review.
* fix(action): address code-review findings across reusable PR review
- post-review-comments: parse retry delays via parseNonNegInt (0/negative fix);
paginate findExistingSummaryComment through readAllPages; remove dead
rangeOf and hasIssueCommentWithId (plus duplicated comment block)
- action.yml: move ${{ }} interpolations into env: (resolve refs, PR_NUM,
ocr_version); fail fast on PR head fetch instead of swallowing errors
- workflows: add timeout-minutes: 30; gate issue_comment on
author_association; tighten pr-context if to == 'issue_comment'
* fix(action): harden review posting after code review
- pass incremental_overlap_threshold via env to avoid github-script injection
- capture ocr review exit code directly instead of &&/|| chain
- drop redundant SUMMARY_MARKER prepend in postSummary (callers already add it)
- align example job if-condition bot check with its concurrency group
* fix(action): always upload review artifacts and capture ocr exit code
* fix(action): merge posting statistics into the summary header
The PR summary issue comment used to present two overlapping breakdowns:
a leading "posted as inline / posted as summary" header and a trailing
"📊 Posting Statistics" block. Their definitions overlapped (the header's
"summary" count included failures the trailer also listed as failed), and
when incremental filtering skipped comments the header counts no longer
summed to the total, making the summary hard to interpret.
Merge them into a single header whose four counts (inline / summary /
skipped / failed) are mutually exclusive and sum to the total, and drop
the trailing Posting Statistics section. buildSummaryBody now takes an
options object.
* fix(action): support local action resolution in container/self-hosted setups
- Checkout trusted base + mark workspace safe for pull_request_target so
the local `uses: ./` action can be resolved and loaded
- Check for git/Node.js and install git when missing, making the
composite action resilient across runner images
- Move Setup Node.js earlier and make it conditional on availability
- Resolve post-review-comments helper at runtime via
GITHUB_ACTION_PATH falling back to GITHUB_WORKSPACE, fixing helper
lookup for local actions where the action path is a host path
invisible inside containers
* refactor(examples): consolidate github_actions demo to reusable action
Drop the inline-script full-control demo; the renamed ocr-review.yml
(from ocr-review-reusable.yml) is now the single demo, invoking
alibaba/open-code-review@main.
Sync the README to the current implementation:
- normalize action refs to @main; point self-hosted-runner users to the
repo's own workflow (noting uses: ./ is internal-only)
- document config via action inputs (posting modes: sticky/incremental)
- update the comment-trigger if with defensive bot/author_association
guards and the concurrency mirror
- fix Example Output to cover the summary comment + inline comments
- replace the non-existent OCR_DEBUG debugging with
artifacts/outputs/ACTIONS_STEP_DEBUG
- use --replace-all for safe.directory
* fix(action): harden withRetry against silent undefined return
withRetry's for loop had no terminal return/throw after the loop body.
Although the current loop invariant (last attempt always throws, and
parseNonNegInt guards against negative MAX_RETRIES) makes fall-through
unreachable, an async function that falls through resolves to undefined,
which would surface as a confusing downstream TypeError for the read-API
callers that rely on it.
Capture lastErr in the loop and add an explicit terminal throw so any
future break of the invariant fails loudly instead of silently returning
undefined.
* docs(readme): document the reusable GitHub Action in CI/CD section
* fix(action): restore language config via a language input
The old inline workflow ran `ocr config set language English`, but the
composite action's Configure OCR step only set llm.extra_body, with no
language input. Add a language input (default English) and write it via
`ocr config set language` so review output language is no longer left
to the tool's default.
Addresses #337 (discussion_r3550069843).
* fix(action): warn when incremental comment listing hits page cap
listExistingReviewComments silently dropped comments beyond its 10-page
cap, unlike readAllPages which logs when truncation occurs. Add the
same max-page-limit warning after the loop so a partial walk during
incremental dedup is visible in the logs.
Addresses #337 (discussion_r3550069871).
* docs(readme): sync GitHub Action section to localized READMEs
GitHub restricted the stargazers API (July 2026) to a repository's own
admins and collaborators, so the embedded star-history.com SVG can no
longer render for anonymous README viewers. Remove the Star History
section from README.md and all localized versions.
Go Report Card has been sunset by its maintainers; the badge endpoint now
returns "go report: retired" and the report page redirects to a farewell
notice, so the badge can never render a grade. Remove it from README.md and
all localized versions (zh-CN, ja-JP, ko-KR, ru-RU).
* feat(telemetry): add OTLP HTTP exporter and print TraceID
- Add HTTP/protobuf exporter support alongside existing gRPC exporter
- Route based on OTEL_EXPORTER_OTLP_PROTOCOL config (http/protobuf vs grpc)
- Print TraceID to stderr when telemetry is enabled for easier correlation
- Add corresponding unit tests
* feat(telemetry): add span coverage for LLM calls, tool execution, plan/filter phases
- Add StartLLMSpan / RecordLLMResult helpers (span.go), symmetric with
existing StartToolSpan / RecordToolResult
- Wrap LLM completion calls in llmloop.RunPerFile with llm.request spans
- Wrap all three tool execution paths in executeToolCall with
tool.execute.* spans (dynamic tools, code_comment sync/async, other tools)
- Add plan.execute span around executePlanPhase
- Add main.loop span around RunPerFile call in executeSubtask
- Add review_filter.execute span around executeReviewFilter, with
comments.before / comments.filtered attributes
- Record llm.error attribute on LLM failures for diagnosability
- Record review.repo / review.from / review.to / review.model on the
top-level review.run span
- Metrics (RecordLLMRequest / RecordToolCall) are preserved alongside
the new spans — they serve different purposes (aggregate dashboards
vs per-run diagnosis)
Verified end-to-end against Sunfire (OTLP HTTP gateway): full span tree
observed for review.run -> subtask.execute -> plan.execute/main.loop/
review_filter.execute -> llm.request/tool.execute.*
* fix(telemetry): address CR findings — span error handling, async span lifecycle, protocol robustness
- Add span.RecordError(err) to RecordLLMResult and RecordToolResult for
consistency with EndSpan
- Use OTel standard pattern (span.SetStatus + span.RecordError) in error
paths of review.run, plan.execute, main.loop, review_filter.execute
- Move async code_comment span end into pool.Submit callback so span
duration reflects actual execution time
- Unify time.Since(startTime) in code_comment error path to a single dur
- Remove http/json from supported OTLP protocols (not actually implemented)
- Add stderr warning when unknown OTLP protocol falls back to gRPC
* feat(telemetry): include trace_id in JSON output, restrict stderr to text format
- Add trace_id as top-level field in jsonOutput struct (omitempty)
- JSON format: trace_id in structured response for programmatic extraction
- Text format: TraceID printed to stderr for human debugging
- Telemetry disabled: trace_id field omitted entirely
* fix: address PR review findings
- loop.go: wrap async span lifecycle in defer to prevent leak on panic
- exporter.go: update parseOTLPEndpoint comment to reflect gRPC+HTTP usage
- scan_cmd.go: align traceID extraction and OTel error handling with review_cmd
- output.go/shared.go: propagate traceID to outputJSONNoFiles for consistency
- agent.go: move comments.filtered attribute before early return so 0 is
distinguishable from not-executed
* feat(telemetry): address PR review — http/json routing, LLM span coverage, trace_id tests
- Route http/json to HTTP exporter (Go OTel SDK HTTP transport only
supports protobuf serialization; users need HTTP transport, not JSON encoding)
- Add llm.request spans to executePlanPhase, executeReviewFilter, and
ReLocateComment with Usage nil-safety consistent with loop.go
- Add trace_id assertions to output helper tests and emitRunResult
end-to-end tests using real TracerProvider
* docs: add OTLP protocol selection and endpoint format to telemetry section
Sync across all 5 README language versions (en, zh-CN, ja-JP, ko-KR, ru-RU).
* fix: unify time.Since in async code_comment defer to single dur variable
Add two structured fields, category and severity, to every review finding
so CI integrations can sort, group, filter, or gate builds without
re-parsing natural-language comment text.
- Tool schema (tools.json): add category/severity as enum-constrained,
required properties of code_comment. severity is limited to
critical/high/medium/low (info dropped, since LLMs struggle to
distinguish low from info).
- System prompt (task_template.json) is intentionally left untouched to
avoid the review-quality regression observed on the benchmark suite;
the tool schema alone drives field population.
- JSON output: category/severity are flat siblings of content/start_line,
omitted entirely when empty (backward compatible).
- CLI output: render an inline [category - severity] badge before the
comment, colored by severity.
- Sync docs across all five README locales.
Bump the Git prerequisite version hint from >= 2.38 to >= 2.41, and add
the Prerequisites section to the ja/ko/ru localized READMEs which were
missing it.
* docs(examples): add GitFlic CI auto-review example
Add examples/gitflic_ci/, a CI-layer integration that reviews GitFlic
merge requests with OpenCodeReview and posts the findings as MR
discussions. Like the GitHub and GitLab examples, the posting glue lives
outside the core binary.
post_review.py (standard library only) reads `ocr review --format json`
and posts inline discussions plus a fallback note and a summary. GitFlic's
Discussions API requires an old-side line for inline comments, which the
new-side-only review output lacks, so the script recomputes it from the
same merge-base diff the review ran on. Ships with a stdlib unittest suite
whose line-mapping cases are ported from the review's diff logic.
* docs(readme): list the GitFlic CI example in the localized READMEs
* fix(examples): address GitFlic CI review feedback from PR #201
Apply the five review comments left on the PR:
- gitflic-ci.yaml: guard `ocr config set llm.model` behind a non-empty
check so the documented-optional OCR_LLM_MODEL no longer breaks the
config step when it is unset
- gitflic-ci.yaml: skip posting when `ocr review` produced no output
(the step ends with `|| true`) instead of feeding empty/partial JSON
to post_review.py
- post_review.py: redact the token from HTTP error snippets so it cannot
leak into CI logs if GitFlic echoes the request back in an error body
- post_review.py: read the review-result file via a `with` block so the
handle is closed explicitly
- examples/README.md: add the missing trailing newline
* feat(mcp): add Model Context Protocol server support
Add MCP client and provider packages that allow integrating external
MCP tool servers into the review loop. Includes config commands for
managing MCP servers, stdio subprocess integration tests, and
comprehensive test coverage.
* refactor(mcp): rename loop variable in contentToText to avoid shadowing Client receiver
* fix(mcp): use platform-specific shell for setup command
The MCP server setup command was hardcoded to use `sh -c`, which
fails on Windows. Extract a `shellCommand` helper behind build tags
to use `cmd /c` on Windows and `sh -c` elsewhere.
* docs(mcp): add MCP server documentation to all README locales
Add official website URL to the "What is Open Code Review?" section
across all localized READMEs. Update highlights and benchmark
screenshots for en/zh, add Japanese versions (highlights-ja.png,
benchmark-ja.png), and add id="highlights" to HighlightsSection
for screenshot tool targeting.
* feat: support inline content and file path resolution for rule field
- rule field auto-detects: .md/.txt/.markdown ending = file path, otherwise inline
- file paths: project-relative first, then as absolute path
- safety: stat before read (512KB cap), extension whitelist, symlink resolution
- tightened heuristic: values with spaces treated as inline to avoid false positives
- guard against empty repoDir to avoid CWD-relative resolution
- 5-language README docs updated with file path usage and first-match-wins behavior
- 15 new unit tests covering all resolution branches
Closes#67
Supersedes #87
* update readme
* feat: update rule resolution logic to clear rules for missing or invalid files
* feat: update rule field description to clarify file path detection criteria
* feat: enhance rule file resolution to block path traversal and improve validation
* fix: clean up tryReadRuleFile and add missing blank line
- Add blank line between matchProjectRuleEntry and allowedRuleExts (Issue 1)
- Remove dead code '|| repoDir == ' in tryReadRuleFile (Issue 2)
- Remove unnecessary warning when repoDir is empty but path is absolute (Issue 3)
Add .cursor-plugin/plugin.json manifest alongside existing Claude Code
and Codex plugin integrations, reusing the shared SKILL.md. Update all
README versions (EN, zh-CN, ja-JP, ko-KR, ru-RU) with Cursor badge and
installation instructions.
Replace the legacy manual `llm.*` configuration with the modern provider
system across all README localizations (en, zh-CN, ja-JP, ko-KR, ru-RU).
The new structure introduces interactive setup for humans and CLI-based
`ocr config set` commands for CI/CD, covering both built-in and custom
providers.
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.
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 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".
- 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)
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.
ApplyLanguage was only called when the config file existed, so without
~/.opencodereview/config.json no language instruction was injected and
the LLM picked its own language. Now ApplyLanguage is called
unconditionally, defaulting to English via resolveLang("").
Update all README translations to reflect the corrected default
(English) and clarify that any language name is accepted.