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
Enhance the embedded viewer stylesheet per #304:
- Add automatic dark mode via `prefers-color-scheme` (no JS/toggle).
The full colour palette — surfaces, text, borders, accents, task/badge
brand colours — lives in `:root` custom properties, with a single dark
block overriding the values. Light-mode colours are unchanged.
- Declare `color-scheme: light dark` so native scrollbars and form
controls follow the active theme.
- Use the system monospace stack (`ui-monospace, ...`) via a `--mono`
variable, replacing the hardcoded font stacks.
- Dark tokens chosen to clear WCAG AA (>=4.5:1) for small text, and dim
brand colours (task-main, task-default) lifted for the dark surface.
Verified by rendering all three viewer pages in light and dark with a
headless browser: computed colours, contrast ratios, resolved theme
variables, and `color-scheme` asserted programmatically.
* fix(tool): resolve file_read paths against git top-level in monorepos
ocr review from a monorepo subdirectory failed with "file not found" (#287):
git reports diff and `git show HEAD:<path>` paths relative to the repo root,
but RepoDir was scoped to the invocation subdirectory, producing a double
prefix. resolveWorkingDir now anchors RepoDir at `git rev-parse
--show-toplevel` on the review path (requireGit=true); scan keeps the CWD so
its `git ls-files` walk stays scoped.
The top-level lookup uses a stdout-only git helper so stderr notices can't
pollute the path, and fails loudly if --show-toplevel errors or is empty
(e.g. a bare repo) instead of silently reusing the subdirectory. Adds
regression tests for the subdir hoist, the scan-path scoping, git-show
resolution of root-relative paths, and the bare-repo failure.
* docs(rules): document repo-root rule.json resolution in monorepos
Since #287 anchored RepoDir at the git top-level, ocr review from a
monorepo subdirectory loads the repo-root .opencodereview/rule.json
rather than a subdir-local one. Call out this user-visible behavior at
loadProjectRule so the scope change isn't a surprise (review feedback).
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.
* fix(tui): persist official-tab models and refine saved secret hint
Persist user-added models to providers.<name>.models on the official tab.
When an API key or auth token is already saved, show a replace hint with a
prefix/suffix fingerprint (skipped for short keys), use a fixed mask placeholder,
and ensure typing or paste replaces the saved value instead of re-saving it.
* fix(tui): model add/delete UX and config wizard hardening
- Add model add/delete in config provider and config model (official + custom)
- Show d Delete only on model rows; green highlight when selected
- Improve Esc cancel text; track savedInSession to avoid misleading messages
- Reload config on save failure; read registry models fresh after reload
- Export llm.ModelListContains; fix config model persist using registry-only check
* fix(tui): defer provider config until confirm and harden API key UX
Only persist provider/model on wizard confirm; keep in-session picks via
sessionModelPick. Validate API key before quit, clear saved keys when emptied,
and improve official env-var hints and custom edit clear behavior.
* feat(tui): show active model suffix on official provider list
Align Official tab with Custom: display (model) next to the active preset
when cfg.Provider matches and a global model is configured.
- Increase section height to prevent terminal bottom from being clipped by overflow:hidden
- Adjust terminal body bottom padding to 8px for better spacing
* fix(pages): address CodeQL XSS alerts in markdown rendering
Alert #4 (headingId.ts): replace the unreliable single-pass regex used to
strip HTML tags (incomplete multi-character sanitization) with DOMPurify.
This also fixes a pre-existing mismatch where headings containing HTML
entities produced different anchor ids on the TOC vs renderer sides.
Alert #5 (MarkdownRenderer.tsx): mermaid runs with securityLevel:'strict'
and already sanitizes its own SVG output, so re-running DOMPurify over the
whole SVG broke rendering (namespaces, inline <style>, foreignObject
labels). Make securityLevel explicit and inject mermaid's trusted output
directly, annotated with a codeql suppression comment.
* docs(pages): clarify CodeQL XSS suppression justification in MarkdownRenderer
The suppression comment claimed the mermaid SVG is 'not raw user input',
which understates the trust boundary. The SVG is in fact derived from
user-controlled mermaid code; safety relies on mermaid's securityLevel:
'strict' sanitizing the output via DOMPurify. Update the comment to state
this accurately and flag that the boundary depends on that setting.
Each docs chapter previously lived at the single /docs route driven by
component state, so chapters had no shareable URL and browser back/forward
did not work. Add a /docs/:slug route and derive activeSlug from the URL
param (falling back to quickstart), navigating via the router on switch.
Also add a dev-time invariant that throws when two sidebar entries share a
slug, since each slug now maps to exactly one URL.
Sync the reorganized zh/mcp.md into the English and Japanese versions:
remove the MCP client-side paragraph and the How it works section,
split Configuration into Adding/Removing subsections, drop the manual
JSON edit example, move env to the end of the code block and table, and
align dash spacing. Also fix a double-space typo in the zh version.
Add an MCP tutorial page (en/zh/ja) covering how OCR acts as an MCP
client that pulls tools from external MCP servers into a review:
configuration via mcp_servers, the config fields, CLI usage, tool
filtering, name conflicts, the setup command, and troubleshooting.
Wire the new page into the docs system (index.ts, DocsPage sidebar,
i18n en/zh/ja) and cross-link from the integrations page to clarify the
client vs server distinction.
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.
Translate all 17 docs pages from zh to ja under content/docs/ja/,
translate frontmatter titles, and wire ja into content/docs/index.ts
(replacing the previous English fallback). Sidebar i18n keys already
existed in i18n/ja.ts, so navigation renders Japanese automatically.
* feat(pages): add Docs page with search, markdown rendering, and i18n support
- Add DocsPage with full-text search modal (⌘K trigger)
- Add MarkdownRenderer with DOMPurify sanitization
- Add bilingual docs content (en/zh) for all sections
- Add shared headingId utility for consistent TOC anchors
- Add search keyboard hints with i18n support
- Update Navbar with Docs navigation link
- Add icon-search.svg asset
- Configure webpack for markdown imports
* fix(pages): address PR #273 code review feedback
- Replace marked.setOptions() with new Marked instance (no global mutation)
- Escape heading ID attribute value to prevent XSS
- Use crypto.randomUUID() for mermaid diagram IDs (no collisions)
- Add cancellation flag for async mermaid renders on unmount
- Move inline <pre> styles to CSS class (only dynamic align-items inline)
- Move @types/dompurify to devDependencies
- Remove @ts-nocheck from docs/index.ts
- Extract getRawContent helper to reduce duplication
- Fix searchDocs fallback consistency (add enDocs fallback)
- Fix heading ID mismatch by stripping markdown links before ID generation
- Separate sidebar chevron (expand) from label (navigate)
- Guard ⌘K shortcut against input/textarea focus interception
* fix(telemetry): support http:// scheme in otlp_endpoint for insecure gRPC
Parse the otlp_endpoint scheme before creating the OTLP gRPC exporters:
- http://host:port -> strip scheme, call WithInsecure() (plaintext gRPC)
- https://host:port -> strip scheme, keep default TLS
- host:port -> unchanged, keep default TLS (backward compatible)
Scheme matching is case-insensitive. Applies to both the trace and
metric exporters in initOTLPProviders.
Fixes#268
* fix(telemetry): trim trailing slash from otlp_endpoint after scheme strip
Addresses review feedback: a URL-style endpoint with a trailing slash
(e.g. "http://localhost:4317/") left the trailing "/" in the address
passed to WithEndpoint(), which expects a bare host:port with no path
and could cause connection failures.
* feat(llm): add z-ai-coding provider for GLM Coding Plan endpoint
Z.AI (智谱) subscribers to the GLM Coding Plan must route requests through
the dedicated coding endpoint (https://open.bigmodel.cn/api/coding/paas/v4)
for them to be billed against the subscription quota. The existing z-ai
provider points at the generic pay-as-you-go endpoint
(https://open.bigmodel.cn/api/paas/v4), so Coding Plan keys silently drain
the wallet balance instead of consuming the plan quota, surfacing as a
spurious "1113 余额不足" error even when the plan is barely used.
Add a dedicated z-ai-coding provider following the existing *-tokenplan
pattern (dashscope/dashscope-tokenplan, tencent-tokenhub/hy-tokenplan).
It reuses Z_AI_API_KEY — the same key authenticates against both endpoints,
so selecting this provider is all that's needed to activate the plan. The
model list is restricted to the models officially supported by the Coding
Plan to avoid selecting a non-plan model that falls back to wallet billing.
- internal/llm/providers.go: register z-ai-coding preset
- extensions/vscode/src/shared/providers.ts: mirror the preset (kept in
sync with the Go registry per the file header)
- internal/llm/providers_test.go: update the sorted provider list assertion
Co-Authored-By: Oz <oz-agent@warp.dev>
* docs(pages): add Z.AI GLM Coding Plan config tip to docs page
Subscribers to the Z.AI (Zhipu) GLM Coding Plan must route requests through
the dedicated coding endpoint (https://open.bigmodel.cn/api/coding/paas/v4)
to bill against the plan quota. The default z-ai preset points at the generic
pay-as-you-go endpoint, so coding-plan keys silently drain the wallet and
surface a spurious "1113 余额不足" error — a recurring trap for new users.
Add a provider-specific callout at the end of the Docs config section showing
the one-line fix that works today on any released version:
ocr config set providers.z-ai.url https://open.bigmodel.cn/api/coding/paas/v4
This complements the z-ai-coding provider added in the previous commit: the
provider gives a native first-class option going forward, while this doc tip
rescues users already running released builds. Copy/localized for zh/en/ja.
Co-Authored-By: Oz <oz-agent@warp.dev>
* fix(llm): address review feedback for z-ai-coding provider
- Switch z-ai-coding to a dedicated Z_AI_CODING_API_KEY env var instead
of reusing Z_AI_API_KEY, matching the tokenplan-provider convention so
pay-as-you-go and Coding Plan keys can be configured independently
- Remove comment blocks from the z-ai-coding presets (Go and TS) to keep
the registry as plain data consistent with the other entries
- Revert pages/ changes (i18n + DocsPage.tsx); provider docs are out of
scope for a provider-registration PR
Co-Authored-By: Oz <oz-agent@warp.dev>
---------
Co-authored-by: mountainwu <mountainwu@kuainiugroup.com>
Co-authored-by: Oz <oz-agent@warp.dev>
Move the 5-minute timeout note from the standalone mcpNote paragraph
into the setup field description in the MCP Server table, so users
see the timeout constraint directly alongside the field definition.
* 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
A panic in a single file's review goroutine (dispatchSubtasks) or in a CommentWorkerPool task previously crashed the whole ocr process. Recover in both: the per-file panic is isolated like an error return (counted in subtaskFailed + recorded as a subtask_error warning with stack trace + telemetry, using the parent ctx since fileCtx is already cancelled on unwind), and a panicking comment-pool task is contained so healthy tasks still complete.
Rebased onto current main: the pool moved to internal/llmloop, so the pool-side recover + the panic-isolation test now live in internal/llmloop/pool.go and pool_test.go; the per-file recover stays in internal/agent/agent.go. Also documents CommentWorkerPool.Await's concurrency contract (Submit must not race Await).
Update documentation strings across en/ja/zh to reflect the new
provider-based configuration: add full scan review mode, list built-in
providers (Anthropic, OpenAI, DashScope, DeepSeek, Z.AI), and replace
legacy config keys with provider-scoped keys including extraHeaders.
* fix(ci): add idempotency check to prevent duplicate review posts on retry
When the batch createReview fails with a 5xx/408/network error, the
request may still have landed on the server. Before retrying per-comment,
the workflow now:
- Tags each review/comment/summary with a per-run HTML comment ID derived
from runId + runAttempt + content hash.
- Queries existing reviews and review comments to detect whether the batch
actually landed, and only retries the comments that are missing.
- Before retrying an individual comment whose request may have reached
GitHub, cools down (honoring rate-limit headers) then checks whether the
comment already exists, treating it as success instead of posting a
duplicate.
- Skips posting the summary comment when one with the same run tag already
exists.
- Adds read-API retry/pacing helpers (withRetry/readWithPacing/readAllPages)
with shorter spacing than writes (OCR_READ_SUCCESS_DELAY /
OCR_READ_LOW_REMAINING_SPACING) since reads are cheaper but still consume
the primary rate limit.
Degrades gracefully to the original fallback (accepting duplicate risk)
when the idempotency read calls themselves fail.
* fix(ci): harden idempotency checks in ocr-review workflow
Address code review findings on the GitHub Actions PR auto-review
workflow (applied to both .github/workflows and examples copies):
- readAllPages: cap pagination at maxPages=50 (default) to prevent
unbounded loops, and validate the argument is a positive integer.
- getPostedCommentIds: anchor the ID regex to the HTML comment wrapper
(<!-- ocr-... -->) with a capture group to avoid false positives from
user-generated content.
- isCommentAlreadyPosted: return null (unknown) instead of false when
the read API fails, so callers do not silently risk duplicates; accept
a postedIdsCache to reuse a single paginated walk across retries.
- hasIssueCommentWithId: return null (unknown) on read API failure, and
match the summary tag with an anchored regex for consistency.
- Call sites: handle null by skipping retry/posting to avoid duplicates
while surfacing the failure in the summary.
* fix(ci): validate env config and document intentional behaviors
Address code review findings on the ocr-review workflow (applied to
both .github/workflows and examples copies):
- parseNonNegInt: add a validation helper for env-var parsing so
negative or non-numeric values (e.g. OCR_MAX_RETRIES=-5) fall back to
defaults instead of bypassing the `|| default` guard (a negative
parseInt result is truthy). All seven retry/pacing config values now
use it.
- readAllPages: document that the 50-page cap is an intentional safety
valve against unbounded loops, not a normal mode; callers that depend
on completeness already degrade safely to null (unknown), so a
truncated walk does not silently produce duplicates.
- commentId: document that the 12-hex-char (48-bit) hash collision
scope is a single PR (listReviewComments is PR-scoped) and a single
run produces only tens to hundreds of comments, making the
birthday-bound collision probability negligible (~1e-7 at 10k).
* docs(github_actions): sync README with retry/idempotency features in ocr-review.yml
- Add OCR_READ_SUCCESS_DELAY and OCR_READ_LOW_REMAINING_SPACING variables
for read API pacing used by the idempotency check
- Document the three GitHub rate-limit retry strategies (primary reset,
retry-after header, secondary no-header backoff)
- Add 'Idempotency: avoiding duplicate review comments' section describing
how the workflow detects already-landed comments via per-run HTML tags
and skips retrying when the read API is unavailable
* fix(ci): use full sha256 hash for review comment idempotency IDs
Drop the .slice(0, 12) truncation in commentId() and use the full 64-char
(256-bit) sha256 hex digest. The truncated 12-char hash carried a tiny but
nonzero collision risk whose failure mode was a silently dropped inline
comment (the idempotency check would mistake two distinct comments for
duplicates). The full hash makes the collision probability effectively
zero with no meaningful downside; the ID regex already used [a-f0-9]+ so
it accepts the longer IDs unchanged.
* fix(ci): use random per-comment IDs and defer body assembly in review workflow
Replace the content-derived commentId() (sha256 of path/line/content) with
a random per-comment ID (crypto.randomBytes) and restructure the inline-
comment flow around an item struct that carries { comment, id, lines }.
This fixes two issues in the idempotency check:
1. ID was recomputed on every failure check. Each inline comment is now
assigned one random ID up front and carried on the item struct, so the
retry/idempotency logic reads item.id directly. The comment body (which
embeds the ID) is assembled only at API-call time in toReviewPayload(),
eliminating repeated hash computation.
2. Content-derived IDs collided for distinct comments sharing the same
path/line/content. A random ID guarantees two such comments get
different IDs, so the idempotency check no longer mistakes the second
for a duplicate of the first and silently drops it on retry.
formatComment/commentId are removed (no callers remain) and replaced with
newCommentId/resolveLines/toReviewPayload/buildBody. The matching regex
already used [a-f0-9]+ so it accepts the new random tokens unchanged.
README ID-format placeholder updated from <hash> to <token>.
* docs(ci): correct misleading readAllPages truncation comment
The comment claimed 'a truncated walk does not silently produce
duplicates' because callers 'degrade safely by returning null on read
failures.' That reasoning only holds when the read API THROWS (rate
limit, 5xx): isCommentAlreadyPosted/hasIssueCommentWithId then return
null (unknown) and the caller skips retrying. A truncated walk does not
throw — it returns a partial set silently, so isCommentAlreadyPosted
returns false (definitively 'not posted') for comments beyond the cap,
and the retry loop reposts them, producing duplicates.
Rewrite the comment to state the cap is an intentional safety valve and
to explicitly distinguish truncation (partial data, can duplicate) from
thrown read failures (null/unknown, safe). No behavior change.
* fix(ci): drop stale postedIdsCache to prevent duplicate inline comments
isCommentAlreadyPosted reused a single listReviewComments snapshot
(postedIdsCache) across all per-comment retries. As comments landed
during the loop, the snapshot went stale; a 5xx-landed comment checked
against the stale snapshot would be reported as 'not posted' and
retried, posting a duplicate.
Remove the cache and walk fresh on every check. The extra reads are
paced via readAllPages/readWithPacing (with retry honoring retry-after
and x-ratelimit-reset) and degrade to null — skip retry — if the read
API ultimately fails, so they cannot produce duplicates. The cache
provided no real benefit in this path: checked comments are either
genuine misses (correctly false) or just-landed (a fresh walk catches
them), so hits essentially never occurred.
* 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
Merge the redundant scan --preview standalone section into its existing
card with richer copy, and add a matching Dry-Run Preview card to the
ocr review advanced usage section. Updates en/zh/ja i18n files.
* docs(pages): add ocr scan documentation page
Adds a dedicated Scan page covering when to use ocr scan vs ocr
review, basic usage, --preview dry-run, batching strategies,
--no-plan/--no-dedup/--no-summary toggles, --max-tokens-budget,
and the full flag reference — cross-checked against
cmd/opencodereview/scan_cmd.go. Wires the /scan route into App.tsx,
adds a Scan nav link, and adds scan.* i18n keys for en/zh/ja.
Closes#242
* refactor(pages): move ocr scan docs into the Docs page
Folds the ocr scan documentation into a new section within
DocsPage.tsx instead of a standalone /scan page, matching how
ocr review is structured. Removes ScanPage.tsx, the /scan route,
and the Scan nav link.
Also addresses the automated review findings: reuses DocsPage's
existing Toast/CodeBlock/IconBox (no more duplication), adds alt=""
to IconBox, i18n-izes the 'ocr review'/'ocr scan' comparison labels,
and adds a console.warn when clipboard copy fails.
i18n keys renamed from scan.* to docs.scan* to match the existing
docs.review* naming convention.
Prevent make test from polluting ~/.opencodereview/sessions/ with
thousands of var-folders-* directories by redirecting test session
writes to ~/.opencodereview/test-sessions/.
Introduce a package-level sessionSubDir variable (default "sessions")
and an exported UseTestSessions() function that switches it to
"test-sessions". Each test package that creates sessions calls
UseTestSessions() from init() in an init_test.go file.
* fix: add configurable HTTP timeout for LLM API calls
The LLM HTTP client had no user-configurable request timeout. When the
LLM API becomes unresponsive (e.g., rate limiting, network issues), the
ocr process hangs indefinitely with 0% CPU, holding an ESTABLISHED TCP
connection that never completes.
Changes:
- Add Timeout field to ResolvedEndpoint struct
- Add OCR_LLM_TIMEOUT environment variable (value in seconds)
- Add timeout_sec field to config.json llm and provider sections
- Pass timeout from ResolvedEndpoint to ClientConfig in NewLLMClient
The default timeout remains 5 minutes when not explicitly configured.
Users can now set a shorter timeout via:
- Environment: OCR_LLM_TIMEOUT=120
- Config file: {"llm": {"timeout_sec": 120}}
Fixes#237
* fix: address Copilot review feedback
- Make OCR_LLM_TIMEOUT a global override (works with any endpoint strategy)
- Add proper overflow detection for timeout values (check before multiply)
- Add validateTimeoutSec helper with negative/overflow guards
- Add comprehensive tests for timeout parsing, validation, and forwarding
- Reject negative timeout_sec in config files with explicit error
* fix: address review feedback for timeout configuration
- parseTimeoutEnv now returns errors instead of silent fallback for invalid values (negative, non-integer, overflow)
- Reuse validateTimeoutSec in parseTimeoutEnv to eliminate duplicated validation logic
- Remove redundant comment in tryOCREnv
- Add missing tests:
- TestResolveEndpoint_ProviderConfigTimeoutSec
- TestResolveEndpoint_ProviderConfigNegativeTimeoutSec
- TestResolveEndpoint_EnvTimeoutOverridesConfigTimeout
- TestResolveEndpoint_EnvTimeoutOverridesProviderTimeout
- TestResolveEndpoint_InvalidEnvTimeoutWithConfig
- TestResolveEndpoint_NegativeEnvTimeoutWithConfig
- Reorder terminal lines: move Summary above the separator line
- Change command from range mode (--from/--to) to workspace mode (ocr review)
- Apply semantic color scheme: brand, command, path, success, action, dim
- Remove unused terminal prompt icon and hasIcon field
- Add blinking cursor animation for the last terminal line
- Reduce line number container width after icon removal
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.
Use navigator.languages to detect the user's preferred language and
automatically select the matching locale (zh/ja/en) on first visit,
falling back to English when no match is found.
The ocr viewer command is a session history viewer, not a results browser.
Updated the description in all three locales (en, zh, ja) to accurately
reflect its purpose.