Commit graph

465 commits

Author SHA1 Message Date
kite
c2312f9744 fix(npm): improve binary staging for zero-downtime auto-upgrade
Replace the simple binary cache with a proper staged binary mechanism:

- Add version.json metadata tracking (version, timestamp, platform)
- Add platform validation to prevent cross-platform misuse
- Add file integrity checks (exists, non-empty) in resolveStagedBinary()
- Notify users via dim stderr message when running from staged binary
- Refresh staged binary after successful upgrade for next-time protection
- Reuse STATE_DIR from platform.js to eliminate path duplication
- Always write version.json to avoid orphan binaries on disk

Resolution priority: platform package > staged binary > legacy path.
2026-08-04 16:58:21 +08:00
kite
730f2243f6 fix(npm): prevent binary unavailability during auto-upgrade (#703)
Add a binary cache fallback mechanism to ensure ocr remains available
while the background auto-upgrade is running npm i -g.

Before the upgrade, the current binary is copied to
~/.opencodereview/bin/ as a safety net. resolveNativeBinary() now
checks this cache path as a last resort before returning null.

This fixes:
- Unix: the gap window where binary is deleted before new one installs
- Windows: broken installs when npm i -g fails due to file locks
2026-08-03 21:30:41 +08:00
Nikolay
f4f2eb8b38
feat(cli): support per-run LLM provider and model overrides (#687)
Some checks are pending
CI / cross-compile (arm64, windows) (push) Waiting to run
CI / test (push) Waiting to run
CI / cross-compile (amd64, darwin) (push) Waiting to run
CI / cross-compile (amd64, windows) (push) Waiting to run
CI / cross-compile (arm64, darwin) (push) Waiting to run
CI / cross-compile (arm64, linux) (push) Waiting to run
Deploy Pages / build (push) Waiting to run
Deploy Pages / deploy (push) Blocked by required conditions
* feat(llm): support per-run provider overrides

* fix(llm): preserve provider credential fallback

* feat(llm): prefer environment configuration

* feat(cli): add per-run provider selection

* feat(output): include resolved LLM identity

* docs: document per-run LLM overrides

* fix(llm): clear stale model on provider switch

* docs: move LLM overrides to CLI reference

* fix(llm): preserve config-first resolution
2026-08-03 21:13:33 +08:00
祈愿Qiii
02fd55b46a
docs(ru): add Russian translation for core documentation pages (#696)
* docs(ru): add Russian core documentation pages

* docs(ru): address architecture review feedback
2026-08-03 21:06:21 +08:00
Abdul Moiz Hussain
8fce4c20a7
refactor(cli): use Cobra validation for parent commands (#694)
* refactor(cli): use Cobra validation for parent commands

* Update cmd/opencodereview/delegate_cmd.go

Fixing inconsistent indentation

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>

* Update cmd/opencodereview/config_cmd.go

Fix inconsistent indentation

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>

---------

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2026-08-03 20:13:49 +08:00
Seonggwan Ahn
e75601d2e6
feat(examples/gitlab): add fail-open category/severity publication controls (#685)
* feat(examples/gitlab): add fail-open category/severity publication controls

Port the GitHub Action publication policy (#478/#529) to the GitLab CI
example so MRs can badge findings and optionally route low-signal
categories/severities to summary notes without dropping them.

Co-authored-by: Cursor <cursoragent@cursor.com>

* fix(examples/gitlab): sanitize metadata in route_comment

Align routing with build_badge so control characters in LLM
category/severity values do not desync badge labels from policy matching.

---------

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-08-03 19:52:44 +08:00
Ayush Pandey
50bc9b1b20
feat(scan): add resumable full-file scans (#677)
* feat(scan): add resumable full-file scans

* Address scan resume review feedback
2026-08-03 19:44:52 +08:00
wxwxwxw_orange
27fab9546f
feat(llm): add Claude Opus 5, Sonnet 5, Kimi K3, and Qwen 3.8 models (#693)
* feat(llm): add Claude Opus 5, Sonnet 5, Kimi K3, and Qwen 3.8 models

* test(llm): update anthropic model order expectation for Opus 5 and Sonnet 5
2026-08-03 17:30:49 +08:00
Abdul Moiz Hussain
df95361392
feat(llm): add GPT-5.6 models to OpenAI provider (#666) 2026-08-03 16:46:00 +08:00
A
ffebbf4f4b
fix(cli): return error on unknown subcommands for parent commands (#660)
Parent commands (session, config, delegate, llm, rules) were defined
without a RunE function. In Cobra, when a parent command has no RunE
and receives an unrecognized subcommand, it falls back to displaying
help and returns nil (exit 0). This is inconsistent with the root
command and leaf commands, which correctly return exit code 1 with an
error message.

Add RunE: func(cmd *cobra.Command, args []string) error { return cmd.Help() }
to all five parent commands so Cobra properly reports "unknown command"
errors instead of silently succeeding.

Includes tests verifying:
- unknown subcommands produce a non-nil error containing "unknown command"
- known subcommands still route correctly
- bare parent commands (no args) still print help and return nil

Closes #641
2026-08-03 16:23:02 +08:00
Soner
1b193db358
feat(cli): add 'ocr session comments' to display saved review comments (#505) (#646)
Some checks are pending
CI / cross-compile (arm64, linux) (push) Waiting to run
CI / cross-compile (arm64, windows) (push) Waiting to run
CI / cross-compile (arm64, darwin) (push) Waiting to run
CI / test (push) Waiting to run
CI / cross-compile (amd64, darwin) (push) Waiting to run
CI / cross-compile (amd64, windows) (push) Waiting to run
Deploy Pages / build (push) Waiting to run
Deploy Pages / deploy (push) Blocked by required conditions
Adds a new 'ocr session comments <session-id>' subcommand that prints the
review comments persisted in a session, rendered in the same style as
'ocr review' terminal output (path, line range, severity badge, suggestion
diff). Supports --json for machine-readable output and --severity/--category
comma-separated filters.

Comments are read from the review_item_done / review_item_reused checkpoint
records via a new session.LoadComments, mirroring resume replay semantics:
a later checkpoint for the same fingerprint supersedes the earlier one and a
subsequent failure drops it.

Also adds shell tab completion for session ids (session show, session
comments, and review --resume) and for the --severity/--category values.

Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
2026-08-03 11:49:48 +08:00
kite
3b9c5e7c21
feat(allowlist): exclude snapshots, testdata, fixtures, and generated code from review (#683)
These file categories pass through all existing filters but provide
little review value: auto-generated protobuf/codegen output and
test fixture data that is never manually authored.

New patterns: __snapshots__/**, *.snap, testdata/**, fixtures/**,
*.generated.*, *.gen.go, *.pb.go, *.pb.cc, *.pb.h
2026-08-03 10:19:17 +08:00
chongli jin
4c9dc2a7b1
refactor(test): replace custom string helpers with strings.Contains in resume_test.go (#681)
Some checks are pending
CI / test (push) Waiting to run
CI / cross-compile (amd64, darwin) (push) Waiting to run
CI / cross-compile (amd64, windows) (push) Waiting to run
CI / cross-compile (arm64, darwin) (push) Waiting to run
CI / cross-compile (arm64, linux) (push) Waiting to run
CI / cross-compile (arm64, windows) (push) Waiting to run
2026-08-02 22:58:21 +08:00
Matt Van Horn
490b52346b
fix(llm): retry once when a chat completion is truncated (#670)
Closes #664
2026-08-02 21:55:37 +08:00
Fabiano Arruda
5829539379
fix(telemetry): honour a base path in the OTLP HTTP endpoint (#667)
Some checks failed
Deploy Pages / build (push) Has been cancelled
Deploy Pages / deploy (push) Has been cancelled
CI / test (push) Has been cancelled
CI / cross-compile (amd64, darwin) (push) Has been cancelled
CI / cross-compile (amd64, windows) (push) Has been cancelled
CI / cross-compile (arm64, darwin) (push) Has been cancelled
CI / cross-compile (arm64, linux) (push) Has been cancelled
CI / cross-compile (arm64, windows) (push) Has been cancelled
2026-08-01 18:09:50 +08:00
Ray
42de431de9
refactor(test): remove config migration comments (#665) 2026-08-01 17:02:27 +08:00
Gongyl01
0ce730a3c8
feat(manifest): run manifest coverage contract for review (#367) (#520)
* feat(session): add run manifest coverage data model and builder

First slice of issue #367 (run manifest coverage contract): the data
model and state machine only. Not yet wired into the agent or CLI, so
existing review/scan output is unchanged.

Introduce the versioned, immutable RunManifest (schema ocr.run-manifest/v1)
and a concurrency-safe ManifestBuilder that tracks per-file coverage
(selected/completed/reused/failed/waived) and freezes into a terminal
state.

- terminal state derived solely from coverage sets, never comments/warnings
  (complete/partial/failed/skipped)
- Finalize sweeps any undecided selected item to failed/unknown so no item
  is silently dropped
- single-mutex builder: first terminal state wins, frozen after Finalize,
  nil-receiver safe
- fixed failure classification enum with an unknown catch-all
- redaction floor on failure/waive reasons (strip secrets, cap length) as a
  single write entry so callers cannot bypass it
- 22 unit tests, race-clean

Refs: issue #367
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

* fix(session): harden run manifest per adversarial review

Address findings from the concurrency / JSON-contract / PR#306-coupling
adversarial review of the manifest data model (still slice 1; not wired to
agent or CLI).

- SetSweepClass: Finalize can classify undispatched items as cancelled/budget
  instead of a blanket unknown (the one real model gap the review found)
- ItemID(fingerprint)=SHA-256 canonical mint helper; an item_id is never a raw
  fingerprint, keeping the resume cross-reference explicit and mix-ups caught
- sanitizeReason: strip control/ANSI chars, coerce valid UTF-8, redact quoted
  secret values, guarantee single line
- Finalize returns deep-copied coverage slices so the frozen snapshot is never
  aliased across the two outlets
- RegisterSelected: nil-safe (lazy-init map) + documents that only the
  post-deletion/post-filter dispatchable set may be registered

+7 unit tests (29 total), race-clean.

Refs: issue #367
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

* feat(manifest): wire input identity, config hashes and run-level failure (shard ②d)

- Freeze per-mode input identity (mode + resolved_base/head + exact_range +
  source_artifact_sha256) via diff.ResolveInput/commitParents, and repository
  identity via RemoteIdentity/canonicalRemote (credential-free).
- Add rule_config_sha256 and runtime_config_sha256 over an allowlist of
  non-secret fields using a length-prefixed SHA-256 framework (no tokens/URLs).
- Replace SetRunLevelFailure(bool) with structured SetRunFailure(class, reason)
  and set ManifestInput.mode; fill execution.* (ocr version, provider, model,
  concurrency, config hashes).
- Thread error returns through Finalize/WriteSessionEnd (main review path
  surfaces them; skip/all-failed/scan paths hardened in follow-up).
- Tests: manifest_hash, canonical_config, git_resolve.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

* fix(manifest): propagate persistence errors and harden remote/error classification

Merged review themes A/B/E from the 07-22 consolidated assessment.

Theme A — Finalize / session_end delivery errors no longer swallowed:
- agent.go no-files path returns the Finalize error instead of nil (A1)
- agent.go loadDiffs failure joins the Finalize error via errors.Join (A2)
- session.Finalize uses sync.Once + cached finalizeErr: written exactly
  once, concurrency-safe, and every caller replays the same result so a
  retry cannot falsely report success (A3)
- scan/agent.go wires both Finalize call sites to surface the error (A4)

Theme B — canonicalRemote rewritten (internal/diff/git.go):
- keep the port (u.Host, not u.Hostname) so endpoints differing only by
  port stay distinct (B1)
- split scp syntax on the first ':' so an '@' inside the path survives (B2)
- recognize local/file/Windows/UNC remotes and omit identity rather than
  misparsing a path as a host (B3; local-remote policy still open)

Theme E — main_task-empty is now a sentinel (errMainTaskEmpty) classified
via errors.Is instead of matching error text.

Theme D (TOCTOU) deferred to shard 4 per issue #367 open-issues OI-12.

Tests: go build ./... + go vet + go test ./... all green (23 pkgs).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

* fix(manifest): report both dispatch and persistence errors on the normal path

The success-path Finalize wiring used `ferr != nil && err == nil`, so when the
review (or scan) failed AND session_end also failed to persist, the persistence
error was dropped and only the dispatch error surfaced — the caller never
learned the session/manifest was not saved.

Join both with errors.Join when both occur (matching the loadDiffs path), so a
persistence failure is always reported even alongside a dispatch failure. This
closes the last gap in the OI-10 contract.

- internal/agent/agent.go: review normal path
- internal/scan/agent.go: scan normal path (+ errors import)

Tests: go build ./... + go vet + go test ./... all green (23 pkgs).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

* feat(manifest): 接入 CLI 与 viewer 并补齐验收用例

- 使用冻结 manifest 统一 review JSON、文本与退出状态\n- session CLI 和 viewer 展示五集合覆盖并兼容 legacy/aborted\n- 补充本地 mock、跨出口一致性及安全验收用例

* test(manifest): 补齐验收矩阵缺口并修复审核发现的缺陷

验收用例:configuration 分类(run 级 sweep + item 级映射)、budget/timeout/panic 混合 partial 隔离、跨出口一致性改为规范化原始字节比对、flag 校验失败无产物断言。

代码修复:sanitizeReason 先剥控制字符再脱敏(堵控制字节绕过)、失败项异分类二次标记报冲突错误、source_artifact_sha256 按 item_id 去重并稳定排序、sortItems 改 SliceStable 对齐设计用词。

全仓 go test 23 包通过。

* test(manifest): 补充 provider transition resume 测试用例

覆盖 issue #367 验收标准 provider transition:resume 时 provider/model 改变后,子 manifest 记录当前值而非继承父运行,并经 parent_run_id 链接父会话以支持审计。用 mock client,不依赖真实 provider key。

* fix(manifest): 对齐预算终态与持久化语义

统一聚合预算停止时的 coverage、status 与退出码。传播 session writer 初始化错误,并补齐 merge first-parent 输入身份及回归测试。移除代码注释中的外部设计文档引用。

---------

Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
Co-authored-by: kite <254839944+lizhengfeng101@users.noreply.github.com>
2026-08-01 16:50:21 +08:00
A
f29659bbc0
fix(vscode): use shell mode for spawn on Windows to detect npm correctly (#653)
Some checks are pending
CI / test (push) Waiting to run
CI / cross-compile (amd64, darwin) (push) Waiting to run
CI / cross-compile (amd64, windows) (push) Waiting to run
CI / cross-compile (arm64, darwin) (push) Waiting to run
CI / cross-compile (arm64, linux) (push) Waiting to run
CI / cross-compile (arm64, windows) (push) Waiting to run
On Windows, child_process.spawn cannot find npm.cmd / npx.cmd without
shell: true, causing the VS Code extension to falsely report 'npm not
detected' and disable CLI features.

probeCommand now hardcodes ['--version'] and adds shell: true only on
win32. runRaw is intentionally left unchanged — it receives user-controlled
args and must not use shell: true for security.

Fixes #453
2026-08-01 11:29:13 +08:00
c
dfc9340b38
fix(cli): refocus previous input on esc in manual provider form (#630) 2026-08-01 11:28:39 +08:00
Do Tuan Anh
230c6e7878
refactor(config): extract supported config keys into a single source of truth (#655)
The supported top-level config keys lived both in the switch/case in setConfigValue and, hardcoded again, in the unknown-key error message, so adding a key meant updating two places. Move them into a supportedConfigKeys slice and generate the error message from it. The message content is unchanged.

Closes #637
2026-08-01 11:26:59 +08:00
Do Tuan Anh
575dfee97e
refactor(test): unify config compat helpers to use cobra subcommand tree (#656)
runConfig manually dispatched config subcommands and parseConfigArgs did manual arg slicing, duplicating the routing the production config command already defines with cobra. Rebuild runConfig as a fresh cobra tree mirroring production (matching the runSession pattern), and drop parseConfigArgs, configAction, and configParseError, which are no longer used. Dispatch behavior is unchanged and stays covered by the existing runConfig/config_dispatch tests.

Closes #638
2026-08-01 11:22:15 +08:00
Lei Zhang
e78474478f
fix(llm): drop extra_body.stream from non-streaming requests (#647) (#657)
Forwarding extra_body.stream to the non-streaming Chat Completions and
Anthropic Messages APIs made the server return text/event-stream (SSE)
while the SDK's non-streaming New() expects a JSON body, causing every
call to fail with "expected destination type of 'string' or '[]byte'
for responses with content-type 'text/event-stream;charset=utf-8' that
is not 'application/json'".

The OpenAIResponsesClient already had this fix (it drops the stream key
in CompletionsWithCtx). Apply the same pattern to OpenAIClient and
AnthropicClient so the three non-streaming clients behave consistently.
For OpenAIClient the streaming decision is preserved: only boolean
true triggers NewStreaming (which sets stream=true itself); other value
types (string "true", bool false) now have the key dropped from the
wire body so the server returns JSON instead of SSE.
2026-08-01 11:16:27 +08:00
Luis Rodriguez
6ab7e0f206
fix(diff): honor .gitignore negation patterns (#651)
* fix(diff): honor .gitignore negation patterns

Patterns were resolved with a first-match-wins scan that discarded any
`!` line outright ("negation patterns are not needed for exclusion
purposes"). That holds for a blocklist .gitignore, but inverts the result
for the allow-list idiom github/gitignore ships per language: `*` to
ignore everything, then `!` lines to re-include. Because a bare `*`
basename-matches every file, every path in such a repository resolved as
excluded.

The failure is silent. `ocr review` reports "0 reviewable / 0 total" and
`--preview` prints "No files changed", both of which read as a clean
review of a repository that was never looked at. It reaches `ocr scan`
and the agent's file_find tool too, since both filter through the same
matcher.

Resolve patterns the way git does — in file order, last match wins, `!`
inverting that pattern's verdict — and while in here support the two
constructs the allow-list idiom needs: a leading `/` anchoring a pattern
to the repository root, and `**`, routed through doublestar (already a
dependency) since filepath.Match cannot express it.

Two deliberate asymmetries:

  - The hardcoded directory blocklist (.git/, node_modules/, vendor/…)
    still short-circuits, so a negation cannot re-admit those.
  - A negated directory-only pattern is inert. Git uses `!*/` to keep
    descending into subdirectories, not to re-admit the files inside
    them; honouring it against file paths would readmit everything below
    the root. Positive directory-only patterns now also match on
    directory components only, so `vendor/` no longer matches a file
    named `vendor`.

MatchGitignorePattern keeps its existing contract: a negated pattern
reports false, so callers testing one pattern in isolation still read it
as "does this exclude the path". Ordered resolution, where negations
carry meaning, lives in isPathExcluded.

Verified against a repository using Go.AllowList.gitignore: file
discovery goes from 0 reviewable / 0 total to 9 reviewable / 18 total,
with the ignore file untouched.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

* fix(diff): anchor the path-suffix match on a component boundary

The suffix fallback compared raw strings, so a pattern containing "/" also
matched a path whose directory merely ends in the pattern's first component:
"src/main.go" excluded "othersrc/main.go", which git never matches — a
pattern with a "/" is anchored to the repository root.

Requiring the suffix to start at "/" keeps the intentionally loose
"generated/api.go" matches "src/generated/api.go" behaviour while dropping
the partial-component case. Two cases added to TestMatchGitignorePattern.

Pre-existing rather than introduced here; the line is in this diff because
of the anchored-pattern guard, and the fix is a one-liner, so it is folded
in rather than deferred.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-01 11:12:02 +08:00
Matthew Betancourt
12406a35f3
fix(action): group 422 fallback inline comments into a single review (#661)
GitHub rejects an entire createReview batch with HTTP 422 when any one
inline comment points at a line outside the PR diff. The previous fallback
degraded to N separate per-comment reviews, producing N timeline entries
for what is logically one review — the churn described in #624.

The batch path now filters out the comments it can PROVE are unresolvable
against the PR diff and re-sends the survivors as a single review. Dropped
comments are reported in the summary with their original span.

Correctness constraints, each of which can make things worse if relaxed:

- Classification is tri-state (valid/invalid/unknown), not boolean.
  "invalid" is a claim that must be proven, because it permanently routes
  a finding to the summary without ever attempting to post it. Missing
  diff metadata — a patchless binary or oversized file, a truncated file
  walk — is "unknown", not "invalid". Treating absent metadata as proof
  of out-of-diff would silently void an entire batch with zero posting
  attempts, which is strictly worse than the pre-existing behavior.
  Only "valid" comments are re-batched; "unknown" keeps the per-comment path.

- The 422 gate is conservative. GitHub documents 422 on this endpoint as
  "Validation failed, OR the endpoint has been spammed", so the status
  code alone is not evidence of a line-resolution problem. The fallback
  activates only on a confirmed line/diff validation error; anything else,
  including spam/abuse detection, falls through to the per-comment loop.

- Both the primary and the secondary batch run the same cooldown and
  idempotency reconciliation (cooldownAndReconcile). A secondary batch
  that fails with a 5xx or network error may still have LANDED with its
  response lost; retrying it blindly would repost every comment and
  recreate the exact duplication this change removes.

- Diff hunks are parsed as {start,end} ranges, one per hunk, so a
  multi-line span must satisfy start_line <= line within a SINGLE hunk.
  A flat per-file line set would accept cross-hunk and reversed spans,
  which GitHub then rejects with another 422.

The diff inventory is fetched once per run and paginated through the
existing readWithPacing helper, so it shares the repo's read retry and
pacing discipline rather than bypassing it.

Verified against live GitHub, not only against mocks. Driving the real
runPostReviewComments at a real PR with two in-diff and two out-of-diff
comments produced: one 422 on the initial batch, one listFiles read, one
successful secondary batch, and EXACTLY ONE review timeline entry holding
the two surviving comments, with the two unresolvable ones reported in the
summary. The observed 422 body is

  { "message": "Unprocessable Entity",
    "errors": ["Line could not be resolved and Line could not be resolved"],
    "status": "422" }

which pins two things the implementation silently depended on. First, this
endpoint returns errors[] as plain STRINGS, so the structured entry.field
branch is unreachable here (kept as defensive cover for other endpoints,
now annotated as such). Second, the decisive wording reaches us only through
Octokit's composed error.message; response.data.message alone is
"Unprocessable Entity" and matches no pattern, so narrowing the gate to the
structured field would disable the fallback while leaving every test green.
That footgun is now documented at the call site and pinned by a regression
test built from the verbatim live payload.

Known limitations:

- The 422 gate matches known line-resolution wordings. Live probing found
  "Line could not be resolved" (line outside a hunk, past EOF, negative,
  LEFT side, or a span straddling hunks), "Start position could not be
  resolved" (inverted span) and "Path could not be resolved" (path not in
  the PR), all covered by /could not be resolved/i. A future wording
  outside these patterns would fall through to the per-comment loop:
  never worse than the pre-existing behavior, but it would quietly
  disable the grouping.
- Only RIGHT-side comments are modeled. A LEFT-side comment classifies
  as "unknown" and takes the per-comment path. The producer emits
  RIGHT-side comments today.

npm run test:github-actions passes, covering secondary landed-then-5xx
reconciliation (fully and partially landed), secondary 429 cooldown
followed by the per-comment retry, non-line 422s, patchless files,
cross-hunk and reversed spans, listFiles truncation, and inventory caching.

Refs: #624
2026-08-01 11:03:09 +08:00
kite
80a5794667
refactor(cli): migrate to Cobra framework for shell completion support (#625)
Some checks are pending
CI / test (push) Waiting to run
CI / cross-compile (amd64, darwin) (push) Waiting to run
CI / cross-compile (amd64, windows) (push) Waiting to run
CI / cross-compile (arm64, darwin) (push) Waiting to run
CI / cross-compile (arm64, linux) (push) Waiting to run
CI / cross-compile (arm64, windows) (push) Waiting to run
Deploy Pages / build (push) Waiting to run
Deploy Pages / deploy (push) Blocked by required conditions
* refactor(cli): migrate to Cobra framework for shell completion support

Replace the hand-rolled ocrFlagSet + switch dispatch with spf13/cobra,
enabling native bash/zsh/fish/powershell completion via `ocr completion`.

Key changes:
- Add root.go (rootCmd definition, version flag with -V shorthand)
- Add completion.go (ocr completion [bash|zsh|fish|powershell])
- Add shared_flags.go (reusable flag registration helpers + validation)
- Rewrite all *_cmd.go to use cobra.Command with RunE
- Delete flags.go (ocrFlagSet, expandShortFlags, parseXxxFlags)
- Add compat_test.go (test compatibility wrappers for existing tests)
- Promote github.com/spf13/cobra from indirect to direct dependency

Behavioral improvements over the previous implementation:
- Shell completion for all commands, flags, and enum values
- "Did you mean?" suggestions for misspelled commands
- cobra.NoArgs on review/scan prevents silent positional arg ignoring
- Cleaner error messages on unknown flags (no full flag dump)
- Consistent help output format across all subcommands

Closes #576

* fix(cli): add Args: cobra.NoArgs to viewerCmd

Prevents `ocr viewer localhost:3000` from silently ignoring the
positional argument and starting on the default address.
Consistent with reviewCmd and scanCmd.

* feat(cli): add "Did you mean?" suggestions for misspelled flags

Cobra only suggests corrections for unknown subcommands, not flags.
Add a levenshtein-distance based suggestion that fires when cobra
returns an "unknown flag" error, matching the same UX pattern.

Examples:
  --hel     → Did you mean this? --help
  --audienc → Did you mean this? --audience
  --comit   → Did you mean this? --commit

* fix(deps): promote spf13/pflag to direct dependency

After the Cobra migration, pflag is directly imported but was still
marked as indirect in go.mod, causing CI's go-mod-tidy check to fail.

* refactor(cli): use idiomatic cobra patterns for args validation and flag errors

Replace hand-rolled argument validation in configSetCmd/configUnsetCmd
with cobra.ExactArgs, and move flag typo suggestions from post-hoc error
string parsing into SetFlagErrorFunc where cobra provides the command
context directly.
2026-07-31 16:56:07 +08:00
kite
c8dd936672
feat(viewer): add review comments display to session detail page (#627)
Parse review_item_done/review_item_reused JSONL records to extract
LLM-generated review comments. Display them in the session detail page
grouped by file, with severity/category badges, line ranges, and
side-by-side code diff panels (existing vs suggested). Also add a
comment count column to the sessions list page.
2026-07-31 16:27:06 +08:00
nolanchic
fbfa94561c
test(rules): add integrity checks for system_rules ↔ rule_docs (#620) (#629)
Add TestSystemRulesIntegrity covering four invariants between the
embedded system_rules.json and rule_docs/:

- every referenced rule file (default_rule + path_rule_map values)
  exists in the embedded rule_docs/
- every path_rule_map glob is a valid doublestar pattern, validated
  post brace-expansion to match Resolve()'s runtime semantics
- every embedded rule_docs/*.md is referenced (no orphan files)
- no duplicate pattern keys in path_rule_map, caught via the ordered
  streaming decode in SystemRule.UnmarshalJSON

Closes #620.
2026-07-31 16:26:50 +08:00
时勇勇
c3918923a6
fix: honor per-file review terminal states (#582)
Treat FAILED and missing completion as review failures, and retry
invalid task_done states instead of accepting them as success.

Keep partial scan output and session history aligned with those states.

Co-authored-by: 4-1-1 <4401981+4-1-1@users.noreply.github.com>
Co-authored-by: kite <254839944+lizhengfeng101@users.noreply.github.com>
2026-07-31 14:32:30 +08:00
FenjuFu
75589cfcd8
docs(configuration): note url accepts base URL or full /responses endpoint (#623)
Follow-up to #562 (which documented the openai-responses protocol). Adds
the one clarification #562 lacked: for openai-responses, the `url` field
accepts either the API base URL or the full `/responses` endpoint, since
ensureResponsesEndpoint normalizes both forms. Added in en/zh/ja.

Signed-off-by: FenjuFu <92919259+FenjuFu@users.noreply.github.com>
2026-07-31 13:14:25 +08:00
Polly Labs
35227dfb0f
docs: fix po catalog descriptions (#619) 2026-07-31 12:59:11 +08:00
c
7038072e04
docs: remove stale Java-implementation references from code comments (#621)
The Java implementation referenced by these comments
(processTargetLineCode, TaskCheckPoint, subtaskExecutor, the Java-side
LlmConversation) does not exist in this repository, so the
cross-references cannot be verified. Trim or reword each comment to keep
the behavioral explanation without the stale Java reference.
Comment-only change; no behavior is affected.
2026-07-31 12:57:57 +08:00
Kevin
8dac23e0fe
fix(vscode): force-kill unresponsive reviews (#489) 2026-07-31 12:05:28 +08:00
kite
86482ade24 chore(gitignore): ignore local claude command files
Some checks are pending
CI / test (push) Waiting to run
CI / cross-compile (amd64, darwin) (push) Waiting to run
CI / cross-compile (amd64, windows) (push) Waiting to run
CI / cross-compile (arm64, darwin) (push) Waiting to run
CI / cross-compile (arm64, linux) (push) Waiting to run
CI / cross-compile (arm64, windows) (push) Waiting to run
Deploy Pages / build (push) Waiting to run
Deploy Pages / deploy (push) Blocked by required conditions
2026-07-31 11:27:35 +08:00
kite
e55974e6be
feat(viewer): modernize web UI design (#616)
Redesign the OCR viewer interface with a modern developer-tool aesthetic:
- New color system with layered surfaces and indigo accents
- Dark mode with deeper tones and refined contrast
- Branded navigation with official OCR logo (inline SVG)
- Improved card, table, and accordion components
- Subtle animations with prefers-reduced-motion support
- System font stack (no external dependencies)
- color-mix() with proper fallbacks for older browsers
- Responsive layout improvements
2026-07-31 11:10:51 +08:00
nolanchic
b21cee0843
docs(pages): sync review-rules table with system_rules.json and add ru locale (#612)
The "Rule resolution per file" table in en/ja/zh was missing 11 entries
(go, astro, python, protobuf, po, pot, graphql, prisma, julia, terraform,
bicep) that exist in internal/config/rules/system_rules.json. Rows are now
ordered to match the declaration order in system_rules.json.

Also adds pages/src/content/docs/ru/review-rules.md, translating the full
page to Russian (the ru locale only had installation.md and quickstart.md
so far) and registers it in the docs index so the ru site shows the
translated page instead of the English fallback.

Closes #608
2026-07-31 10:58:04 +08:00
Abdul Moiz Hussain
d55f5e5940
refactor(diff): strip index headers from review prompts (#609)
Some checks are pending
CI / test (push) Waiting to run
CI / cross-compile (amd64, darwin) (push) Waiting to run
CI / cross-compile (amd64, windows) (push) Waiting to run
CI / cross-compile (arm64, darwin) (push) Waiting to run
CI / cross-compile (arm64, linux) (push) Waiting to run
CI / cross-compile (arm64, windows) (push) Waiting to run
Deploy Pages / build (push) Waiting to run
Deploy Pages / deploy (push) Blocked by required conditions
2026-07-30 17:27:13 +08:00
Abdul Moiz Hussain
5a7a25dbac
fix(config): warn when active provider shadows llm settings (#588)
* fix(config): warn when active provider shadows llm settings

* fix(config): suggest correct path for custom provider settings

* fix(config): refine shadow warning and unset help
2026-07-30 17:10:05 +08:00
chethanuk
74afd9c89c
feat(allowlist): add Protocol Buffers (.proto) support (#473)
Allow .proto files through the extension allowlist and map them to a
dedicated protobuf review rule focused on wire compatibility.

Part of #470.
2026-07-30 17:01:11 +08:00
mikkeldanielsen
1e43d37b6c
feat(rules): add PHP and Composer rules (#603) 2026-07-30 16:34:26 +08:00
kite
be5e79c1a7
ci: upgrade low-risk GitHub Actions dependencies (#468)
Upgrade actions with minimal breaking-change surface:
- actions/checkout v4 → v7
- actions/setup-node v4 → v7
- actions/cache v4 → v6
- actions/github-script v7 → v9
- actions/upload-pages-artifact v3 → v5
- actions/deploy-pages v4 → v5
- softprops/action-gh-release v2 → v3
- actions/attest-build-provenance v2 → v4

Deliberately keeps upload-artifact and download-artifact at v4
to avoid the artifact format and hash-enforcement breaking changes
in v7/v8 that could disrupt the release pipeline.

Verified: self-hosted runner is v2.335.1, exceeds the v2.329.0
requirement for checkout v6+ credential persistence in containers.
2026-07-30 15:54:59 +08:00
Stephen Jarso
a47dfb2737
test(session): (#590)
add comprehensive test coverage for resume.go

Add 34 focused tests for session/resume.go, which previously had no
dedicated test file. Tests cover every exported and unexported function:

- SessionFilePath: empty ID rejection, valid path construction
- CompletedCount: nil state, empty items, populated items
- Item: nil state, missing key, found key, defensive copy verification
- ValidateOptions: nil/workspace/empty/missing mode rejection, mode
  mismatch, range match/mismatch, commit match/mismatch, unsupported mode
- applyResumeLine: session_start, review_item_done (with NewPath
  fallback and empty fingerprint skip), review_item_reused,
  review_item_failed (removal + empty fingerprint), unknown type,
  invalid JSON
- applySessionStart: RepoDir preservation/override, SessionID
  preservation, all fields set
- copyLlmComments: nil input, empty slice, deep copy with mutation
  isolation
- LoadResumeState: nonexistent file, empty file, multiple records
  round-trip, invalid JSON, fail-then-redo replay sequencing
2026-07-30 14:52:08 +08:00
dependabot[bot]
0dafc3022a
chore(deps-dev): bump the vscode-dependencies group (#592)
Bumps the vscode-dependencies group in /extensions/vscode with 2 updates: [webpack](https://github.com/webpack/webpack) and [webpack-cli](https://github.com/webpack/webpack-cli).


Updates `webpack` from 5.108.4 to 5.109.2
- [Release notes](https://github.com/webpack/webpack/releases)
- [Changelog](https://github.com/webpack/webpack/blob/main/CHANGELOG.md)
- [Commits](https://github.com/webpack/webpack/compare/v5.108.4...v5.109.2)

Updates `webpack-cli` from 7.2.1 to 7.2.2
- [Release notes](https://github.com/webpack/webpack-cli/releases)
- [Changelog](https://github.com/webpack/webpack-cli/blob/main/CHANGELOG.md)
- [Commits](https://github.com/webpack/webpack-cli/compare/webpack-cli@7.2.1...webpack-cli@7.2.2)

---
updated-dependencies:
- dependency-name: webpack
  dependency-version: 5.109.2
  dependency-type: direct:development
  update-type: version-update:semver-minor
  dependency-group: vscode-dependencies
- dependency-name: webpack-cli
  dependency-version: 7.2.2
  dependency-type: direct:development
  update-type: version-update:semver-patch
  dependency-group: vscode-dependencies
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-07-30 14:44:57 +08:00
seescer
1948b42b2f
i18n(pages): add Russian (ru) locale (#596)
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.
2026-07-30 14:40:06 +08:00
Nitish Agarwal
2640f5830c
feat(agent): add token-cost budget guardrails to the review path (#508)
Some checks are pending
CI / test (push) Waiting to run
CI / cross-compile (amd64, darwin) (push) Waiting to run
CI / cross-compile (amd64, windows) (push) Waiting to run
CI / cross-compile (arm64, darwin) (push) Waiting to run
CI / cross-compile (arm64, linux) (push) Waiting to run
CI / cross-compile (arm64, windows) (push) Waiting to run
Add a runtime token-budget guardrail to the diff-review path so a large MR
stops itself before runaway cost (issue #409: ~90.4M tokens in one failed
attempt), instead of timing out and losing all structured output.

New `ocr review` flag (mirror scan's proven --max-tokens-budget):
- --max-tokens-budget N : cap aggregate token usage; dispatch stops once the
  running total + a per-file look-ahead would exceed it (0 = unlimited).

Mechanism mirrors scan/agent.go's dispatchBatch gate exactly: read the
existing atomic Runner counters (no duplicate counter — a second one would be
a drift bug) before acquiring the semaphore, and break the dispatch loop on
exceed. In-flight workers are allowed to finish (overrun bounded by the
in-flight count, <= concurrency), matching scan's documented contract.

Budget exhaustion returns the partial comments already produced with a nil
error (not a Go error — the failure path suppresses output), and signals
budget-exceeded out-of-band so the output layer sets a typed `budget_exceeded`
status distinct from success / completed_with_warnings / completed_with_errors.

Additional changes tied to the invariants:
- Pre-review scale warning (files, diff tokens, configured budget) printed
  before any model spend; non-blocking, warn-only.
- Structured usage emitted on the failure path (stderr) so the cost of a
  failed attempt is never lost. Carries only token/tool tallies — no
  credentials or prompts. Reports the agent's actual BudgetExceeded() state so
  the residual budget-trip + all-dispatched-fail edge can never contradict the
  typed status.
- summary.budget_exceeded JSON field (additive, omitempty) so old parsers are
  unaffected; default 0/unlimited restores prior behavior.

Internal/scan gains only the BudgetExceeded() accessor (returns false) so the
shared ResultProvider interface compiles; scan keeps its own token budget and
its JSON output is unchanged.

Tests mirror internal/scan/budget_test.go: token-budget gate stops dispatch
early and sets BudgetExceeded(); unlimited default runs all files; estimate
helpers project sane values (with a humanTokens parity table so the two copies
cannot diverge); JSON output asserts the typed status and the failure-path
usage record. Full `make test` (-race) green.
2026-07-30 10:49:13 +08:00
Nitish Agarwal
20db3d7d12
feat(action): add fail-open category/severity publication controls (#478) (#529)
Some checks are pending
CI / test (push) Waiting to run
CI / cross-compile (amd64, darwin) (push) Waiting to run
CI / cross-compile (amd64, windows) (push) Waiting to run
CI / cross-compile (arm64, darwin) (push) Waiting to run
CI / cross-compile (arm64, linux) (push) Waiting to run
CI / cross-compile (arm64, windows) (push) Waiting to run
Add category/severity-aware, fail-open publication controls to the reusable
GitHub Action: render a CLI-consistent `[category · severity]` badge on every
comment, and add one opt-in routing destination that moves low-severity or
selected-category findings from inline comments to the PR summary.

No finding is ever silently dropped: unknown/malformed metadata on a finding
never matches the policy (routes to its normal inline destination), and a
malformed policy itself degrades to no-routing. A new `routed` accounting
bucket is disjoint from summary/skipped/failed, so destination counts still
sum to the raw input total.

- buildBadge: byte-matches the CLI's buildBadge degeneration
  ([cat · sev] / [cat] / [sev] / ""), with control-char sanitization that is
  intentionally stricter than the CLI (strips \t/\n to defend Markdown layout).
- buildPolicy / routeComment: pure fail-open policy decision. A finding matches
  when its severity is at-or-below the threshold OR its category is in the list;
  unknown metadata never matches.
- Partition loop: routing is a placement decision (route OUT of reviewComments),
  so routed findings never enter any createReview write path (no double-post on
  retry) and carry no idempotency id.
- Accounting: new comments_routed output and summary bullet; render order is
  counts -> no-line -> routed -> failed.
- action.yml: opt-in route_severity_below and route_categories string inputs
  (empty defaults = today's behavior) plus the comments_routed output.

With no routing input set, behavior is byte-equivalent to today except for the
additive badge prefix on comments that carry category/severity metadata.
2026-07-29 22:45:03 +08:00
Abdul Moiz Hussain
e0eb10774f
feat(allowlist): add Prisma schema review support (#572) 2026-07-29 22:40:22 +08:00
Ritvik K
dc1e346316
Add CodeUp CI integration (#570)
* Add CodeUp CI integration (issue #517)

Adds examples/codeup_ci with:
- post_review.py: runs ocr review --format json and posts a
  GLOBAL_COMMENT summary via CodeUp's CreateChangeRequestComment API
- post_review_test.py: unit tests (27 passing)
- codeup-flow.yml: example Yunxiao Flow pipeline
- README.md: setup docs and known limitations (v1 = summary
  comment only, inline comments as a follow-up)

* chore: ignore Python cache files

* Add actual file contents for CodeUp CI integration

* Use generic placeholder for OCR_LLM_MODEL example

* Address review: remove local .gitignore, add trailing newlines, simplify testing docs
2026-07-29 22:37:29 +08:00
svector
ea5056979f
fix(vscode): patch brace-expansion DoS via minimatch 10.2.6 (CVE-2026-14257) (#561)
extensions/vscode's resolutions pinned minimatch to ^9.0.7, which yarn
resolves to 9.0.9 -- still pulling brace-expansion@2.1.2, inside the
vulnerable range of GHSA-mh99-v99m-4gvg / CVE-2026-14257 (unbounded brace
expansion can OOM the process; expand() bounds result count but not
result length). The resolutions block also explicitly caps brace-expansion
below 3.0 (">=2.1.2 <3"), which was likely intentional: minimatch 9.0.9
calls brace-expansion via __importDefault(...).default, a shape
brace-expansion's 5.0.8 CJS build (named `expand` export only, no
module.exports = expand, no __esModule marker) doesn't satisfy -- a
straight override to 5.0.8 would throw TypeError at runtime.

minimatch@10.2.6 calls brace-expansion via the compatible named-export
form (const { expand } = require('brace-expansion'); expand(pattern,
...)), so bumping minimatch itself -- not just overriding brace-expansion
in isolation -- is the actual fix. No application code imports minimatch
directly (grep confirmed); it's purely a transitive dependency of
typescript-eslint/eslint tooling here, which lowers the risk of the major
version bump surfacing elsewhere.

Verified: yarn install clean, `yarn lint` 0 errors (1 pre-existing
unrelated warning), `yarn build` all three webpack bundles compile
successfully, `yarn test` 11/11 suites and 96/96 tests pass.
2026-07-29 21:13:30 +08:00
Abdul Moiz Hussain
0613abd257
ci(test): add binary smoke test (#566)
* ci(test): add binary smoke test

* ci: strengthen CLI smoke test coverage and clean up binary
2026-07-29 19:45:21 +08:00
c
be2985317b
docs(agent): correct MaxConcurrency doc comment to match actual default (#577) 2026-07-29 19:38:40 +08:00