@alibaba-group/open-code-review 1.1.8 → 1.1.10

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,225 @@
1
+ # OpenCodeReview - GitLab CI Merge Request Auto-Review Demo
2
+ #
3
+ # This pipeline automatically reviews Merge Requests using OpenCodeReview
4
+ # and posts review comments (discussions) directly on the MR diff.
5
+ #
6
+ # Required CI/CD Variables (Settings → CI/CD → Variables):
7
+ # OCR_LLM_URL - LLM API endpoint (e.g., https://api.openai.com/v1/chat/completions)
8
+ # OCR_LLM_AUTH_TOKEN - Authentication token for the LLM API (mark as "Masked")
9
+ # GITLAB_API_TOKEN - GitLab Personal/Project Access Token with "api" scope
10
+ #
11
+ # Optional CI/CD Variables:
12
+ # OCR_LLM_MODEL - Model name (default: gpt-4o)
13
+
14
+ stages:
15
+ - review
16
+
17
+ code-review:
18
+ stage: review
19
+ image: node:20
20
+ only:
21
+ - merge_requests
22
+ variables:
23
+ GIT_DEPTH: 0 # Full history needed for merge-base diff
24
+ script:
25
+ # Install OpenCodeReview
26
+ - npm install -g @alibaba-group/open-code-review
27
+
28
+ # Configure OCR
29
+ - mkdir -p ~/.open-code-review
30
+ # Gitlab CI/CD does not support confuring variables with value length less than 8, so you can't set use_anthropic as a CI variable
31
+ - |
32
+ ocr config set llm.url $OCR_LLM_URL
33
+ ocr config set llm.auth_token $OCR_LLM_AUTH_TOKEN
34
+ ocr config set llm.model $OCR_LLM_MODEL
35
+ ocr config set llm.use_anthropic false
36
+ ocr config set llm.extra_body '{"thinking": {"type": "disabled"}}'
37
+
38
+ # Run OCR review
39
+ - |
40
+ echo "Reviewing MR: ${CI_MERGE_REQUEST_SOURCE_BRANCH_NAME} against ${CI_MERGE_REQUEST_TARGET_BRANCH_NAME}"
41
+ ocr review \
42
+ --from "origin/${CI_MERGE_REQUEST_TARGET_BRANCH_NAME}" \
43
+ --to "origin/${CI_MERGE_REQUEST_SOURCE_BRANCH_NAME}" \
44
+ --format json \
45
+ --audience agent \
46
+ > /tmp/ocr-result.json 2>/tmp/ocr-stderr.log || true
47
+ echo "OCR review completed."
48
+ cat /tmp/ocr-result.json
49
+
50
+ # Post review comments to MR
51
+ - |
52
+ python3 << 'PYTHON_SCRIPT'
53
+ import json
54
+ import os
55
+ import sys
56
+ import urllib.request
57
+ import urllib.error
58
+
59
+ GITLAB_URL = os.environ.get("CI_SERVER_URL", "https://gitlab.com")
60
+ PROJECT_ID = os.environ["CI_PROJECT_ID"]
61
+ MR_IID = os.environ["CI_MERGE_REQUEST_IID"]
62
+ API_TOKEN = os.environ["GITLAB_API_TOKEN"]
63
+ SOURCE_BRANCH = os.environ["CI_MERGE_REQUEST_SOURCE_BRANCH_NAME"]
64
+ TARGET_BRANCH = os.environ["CI_MERGE_REQUEST_TARGET_BRANCH_NAME"]
65
+ COMMIT_SHA = os.environ["CI_COMMIT_SHA"]
66
+
67
+ API_BASE = f"{GITLAB_URL}/api/v4/projects/{PROJECT_ID}/merge_requests/{MR_IID}"
68
+
69
+ def api_request(endpoint, data=None, method="POST"):
70
+ """Make a GitLab API request."""
71
+ url = f"{API_BASE}{endpoint}"
72
+ headers = {
73
+ "PRIVATE-TOKEN": API_TOKEN,
74
+ "Content-Type": "application/json"
75
+ }
76
+ body = json.dumps(data).encode("utf-8") if data else None
77
+ req = urllib.request.Request(url, data=body, headers=headers, method=method)
78
+ try:
79
+ with urllib.request.urlopen(req) as resp:
80
+ return json.loads(resp.read().decode("utf-8"))
81
+ except urllib.error.HTTPError as e:
82
+ print(f"API error {e.code}: {e.read().decode('utf-8')}", file=sys.stderr)
83
+ return None
84
+
85
+ def post_note(body):
86
+ """Post a general note/comment on the MR."""
87
+ return api_request("/notes", {"body": body})
88
+
89
+ def post_discussion(path, line, body, base_sha=None, start_sha=None, head_sha=None):
90
+ """Post an inline discussion on a specific file/line in the MR diff."""
91
+ position = {
92
+ "position_type": "text",
93
+ "new_path": path,
94
+ "old_path": path,
95
+ "new_line": line,
96
+ "base_sha": base_sha or TARGET_BRANCH,
97
+ "start_sha": start_sha or TARGET_BRANCH,
98
+ "head_sha": head_sha or COMMIT_SHA,
99
+ }
100
+ data = {
101
+ "body": body,
102
+ "position": position
103
+ }
104
+ return api_request("/discussions", data)
105
+
106
+ def format_comment(comment):
107
+ """Format a single review comment as markdown."""
108
+ body = comment.get("content", "")
109
+
110
+ existing = comment.get("existing_code", "")
111
+ suggestion = comment.get("suggestion_code", "")
112
+ if suggestion and existing:
113
+ body += "\n\n**Suggestion:**\n"
114
+ body += f"```suggestion:-0+0\n{suggestion}\n```"
115
+
116
+ return body
117
+
118
+ def format_comment_fallback(comment):
119
+ """Format a comment for fallback (non-inline) display."""
120
+ path = comment.get("path", "unknown")
121
+ start_line = comment.get("start_line", 0)
122
+ end_line = comment.get("end_line", 0)
123
+ content = comment.get("content", "")
124
+
125
+ md = f"### 📄 `{path}`"
126
+ if start_line and end_line:
127
+ md += f" (L{start_line}-L{end_line})"
128
+ md += f"\n\n{content}"
129
+
130
+ existing = comment.get("existing_code", "")
131
+ suggestion = comment.get("suggestion_code", "")
132
+ if suggestion and existing:
133
+ md += "\n\n<details><summary>💡 Suggested Change</summary>\n\n"
134
+ md += f"**Before:**\n```\n{existing}\n```\n\n"
135
+ md += f"**After:**\n```\n{suggestion}\n```\n\n"
136
+ md += "</details>"
137
+
138
+ return md
139
+
140
+ # --- Main ---
141
+
142
+ # Read OCR result (skip first line which is summary, not JSON)
143
+ try:
144
+ with open("/tmp/ocr-result.json", "r") as f:
145
+ next(f) # Skip first line
146
+ result = json.load(f)
147
+ except (FileNotFoundError, json.JSONDecodeError) as e:
148
+ print(f"Failed to parse OCR output: {e}", file=sys.stderr)
149
+ stderr_content = ""
150
+ try:
151
+ with open("/tmp/ocr-stderr.log", "r") as f:
152
+ stderr_content = f.read().strip()
153
+ except FileNotFoundError:
154
+ pass
155
+ if stderr_content:
156
+ post_note(f"⚠️ **OpenCodeReview** encountered an error:\n```\n{stderr_content}\n```")
157
+ sys.exit(0)
158
+
159
+ comments = result.get("comments", [])
160
+ warnings = result.get("warnings", [])
161
+
162
+ # No comments - post summary
163
+ if not comments:
164
+ message = result.get("message", "No comments generated. Looks good to me.")
165
+ post_note(f"✅ **OpenCodeReview**: {message}")
166
+ print("No review comments to post.")
167
+ sys.exit(0)
168
+
169
+ # Get MR diff metadata for position calculation
170
+ diff_refs = None
171
+ try:
172
+ versions_url = f"{API_BASE}/versions"
173
+ req = urllib.request.Request(versions_url, headers={"PRIVATE-TOKEN": API_TOKEN})
174
+ with urllib.request.urlopen(req) as resp:
175
+ versions = json.loads(resp.read().decode("utf-8"))
176
+ if versions:
177
+ latest = versions[0]
178
+ diff_refs = {
179
+ "base_sha": latest.get("base_commit_sha", ""),
180
+ "start_sha": latest.get("start_commit_sha", ""),
181
+ "head_sha": latest.get("head_commit_sha", ""),
182
+ }
183
+ except Exception as e:
184
+ print(f"Warning: Could not fetch MR versions: {e}", file=sys.stderr)
185
+
186
+ # Post inline discussions for each comment
187
+ success_count = 0
188
+ failed_comments = []
189
+
190
+ for comment in comments:
191
+ path = comment.get("path", "")
192
+ end_line = comment.get("end_line", 0)
193
+ start_line = comment.get("start_line", end_line)
194
+ body = format_comment(comment)
195
+
196
+ if not path or not end_line:
197
+ failed_comments.append(comment)
198
+ continue
199
+
200
+ kwargs = {}
201
+ if diff_refs:
202
+ kwargs = diff_refs
203
+
204
+ result_resp = post_discussion(path, end_line, body, **kwargs)
205
+ if result_resp:
206
+ success_count += 1
207
+ else:
208
+ failed_comments.append(comment)
209
+
210
+ print(f"Successfully posted {success_count}/{len(comments)} inline comments.")
211
+
212
+ # Post fallback for any failed inline comments
213
+ if failed_comments:
214
+ fallback_body = f"🔍 **OpenCodeReview** found issues that could not be posted inline:\n\n---\n\n"
215
+ for comment in failed_comments:
216
+ fallback_body += format_comment_fallback(comment) + "\n\n---\n\n"
217
+ post_note(fallback_body)
218
+
219
+ # Post summary
220
+ summary = f"🔍 **OpenCodeReview** found **{len(comments)}** issue(s) in this MR."
221
+ if warnings:
222
+ summary += f"\n\n⚠️ {len(warnings)} warning(s) occurred during review."
223
+ post_note(summary)
224
+
225
+ PYTHON_SCRIPT
@@ -0,0 +1,268 @@
1
+ # OpenCodeReview - GitLab CI Demo
2
+
3
+ This demo shows how to integrate OpenCodeReview into your GitLab CI/CD pipeline to automatically review Merge Requests and post review comments as inline discussions.
4
+
5
+ ## How It Works
6
+
7
+ ```
8
+ MR Created/Updated → GitLab Pipeline Triggered → OCR Reviews Diff → Discussions Posted on MR
9
+ ```
10
+
11
+ 1. When a Merge Request is opened or updated, the pipeline triggers
12
+ 2. It installs OCR via npm in a `node:20` Docker image
13
+ 3. Runs `ocr review --from origin/<target> --to origin/<source> --format json` to analyze the diff
14
+ 4. Parses the JSON output and posts inline discussions on the MR using GitLab's Discussions API
15
+
16
+ ## Setup
17
+
18
+ ### 1. Copy the pipeline file
19
+
20
+ Copy `.gitlab-ci.yml` to your repository root (or include it via `include:`):
21
+
22
+ ```bash
23
+ cp .gitlab-ci.yml /path/to/your/repo/.gitlab-ci.yml
24
+ ```
25
+
26
+ Or use GitLab's `include` feature in your existing `.gitlab-ci.yml`:
27
+
28
+ ```yaml
29
+ include:
30
+ - local: 'ci_demo/gitlab_ci/.gitlab-ci.yml'
31
+ ```
32
+
33
+ ### 2. Configure CI/CD Variables
34
+
35
+ Go to your project's **Settings → CI/CD → Variables** and add:
36
+
37
+ | Variable | Required | Masked | Description |
38
+ |----------|----------|--------|-------------|
39
+ | `OCR_LLM_URL` | Yes | No | LLM API endpoint URL (e.g., `https://api.openai.com/v1/chat/completions`) |
40
+ | `OCR_LLM_AUTH_TOKEN` | Yes | Yes | API authentication token |
41
+ | `OCR_LLM_MODEL` | No | No | Model name (defaults to `gpt-4o`) |
42
+ | `GITLAB_API_TOKEN` | Yes | Yes | GitLab access token with `api` scope |
43
+
44
+ > **Note:** GitLab CI/CD does not support variables with values shorter than 8 characters, so `use_anthropic` cannot be set as a CI variable. The pipeline sets it to `false` by default. If you need to use Anthropic Claude models, you'll need to modify the `.gitlab-ci.yml` script directly.
45
+ >
46
+ > The pipeline also configures `llm.extra_body` to disable thinking mode for compatibility with various LLM providers.
47
+
48
+ ### 3. Create a GitLab Access Token
49
+
50
+ You need a token with `api` scope to post discussions on MRs. Options:
51
+
52
+ - **Project Access Token** (recommended): Settings → Access Tokens → Create with `api` scope
53
+ - **Personal Access Token**: User Settings → Access Tokens → Create with `api` scope
54
+ - **Group Access Token**: For organization-wide usage
55
+
56
+ > **Note:** The built-in `CI_JOB_TOKEN` does NOT have sufficient permissions to create MR discussions, which is why a separate token is needed.
57
+ >
58
+ > **Tip:** For Project Access Tokens and Group Access Tokens, the token name determines the bot name shown in MR discussions. For example, naming your token `OpenCodeReview Bot` will make review comments appear as posted by `OpenCodeReview Bot`.
59
+
60
+ ## Example Output
61
+
62
+ When an MR is reviewed, comments appear as:
63
+
64
+ - **Inline discussions**: Directly on the changed lines in the MR diff view
65
+ - **Summary note**: A final note summarizing the total number of issues found
66
+ - **Fallback notes**: If inline posting fails for specific comments, they appear as regular MR notes with file/line references
67
+
68
+ ### Inline Discussion Example
69
+
70
+ Comments are posted using GitLab's Discussion API with position data, so they appear directly next to the relevant code in the "Changes" tab.
71
+
72
+ ## Supported LLM Providers
73
+
74
+ OCR supports both OpenAI and Anthropic API formats:
75
+
76
+ - **OpenAI-compatible APIs** (default):
77
+ - OpenAI (GPT-4o, GPT-4, etc.)
78
+ - Azure OpenAI
79
+ - Self-hosted models (vLLM, Ollama, etc.)
80
+ - **Anthropic APIs** (modify `.gitlab-ci.yml` to set `use_anthropic: true`):
81
+ - Anthropic Claude models
82
+
83
+ ## Customization
84
+
85
+ ### Use a specific OCR version
86
+
87
+ ```yaml
88
+ script:
89
+ - npm install -g @alibaba-group/open-code-review@1.0.0
90
+ ```
91
+
92
+ ### Add custom review rules
93
+
94
+ Use the `--rule` flag to pass a custom rules JSON file:
95
+
96
+ ```yaml
97
+ script:
98
+ - ocr review --rule ./my-rules.json --from origin/$CI_MERGE_REQUEST_TARGET_BRANCH_NAME --to origin/$CI_MERGE_REQUEST_SOURCE_BRANCH_NAME
99
+ ```
100
+
101
+ ### Limit concurrency
102
+
103
+ Adjust the `--concurrency` flag for large MRs to control the number of concurrent LLM requests:
104
+
105
+ ```yaml
106
+ script:
107
+ - ocr review --concurrency 5 --from origin/$CI_MERGE_REQUEST_TARGET_BRANCH_NAME --to origin/$CI_MERGE_REQUEST_SOURCE_BRANCH_NAME
108
+ ```
109
+
110
+ ### Provide background context
111
+
112
+ Use the `--background` flag to pass additional context that helps OCR better understand the purpose of the changes:
113
+
114
+ ```yaml
115
+ script:
116
+ - ocr review --background "$CI_MERGE_REQUEST_TITLE" --from origin/$CI_MERGE_REQUEST_TARGET_BRANCH_NAME --to origin/$CI_MERGE_REQUEST_SOURCE_BRANCH_NAME
117
+ ```
118
+
119
+ This is particularly useful when your MR titles follow semantic conventions (e.g., `feat(auth): add OAuth2 support`) that clearly summarize what the MR implements. The background information helps OCR provide more relevant and context-aware review comments.
120
+
121
+ ### Change the trigger events
122
+
123
+ By default, the pipeline uses `only: [merge_requests]`, which triggers on **all** MR events (creation, updates, reopen). GitLab CI does not natively support fine-grained control to trigger **only on MR creation**.
124
+
125
+ To avoid re-reviewing on every push to an existing MR (and wasting LLM API tokens), you can check for existing OCR reviews **before** running `ocr review`. Use a wrapper script that skips the review step if OCR comments already exist:
126
+
127
+ ```yaml
128
+ script:
129
+ # Install OpenCodeReview
130
+ - npm install -g @alibaba-group/open-code-review
131
+
132
+ # Configure OCR
133
+ - mkdir -p ~/.open-code-review
134
+ - |
135
+ ocr config set llm.url $OCR_LLM_URL
136
+ ocr config set llm.auth_token $OCR_LLM_AUTH_TOKEN
137
+ ocr config set llm.model $OCR_LLM_MODEL
138
+ ocr config set llm.use_anthropic false
139
+ ocr config set llm.extra_body '{"thinking": {"type": "disabled"}}'
140
+
141
+ # Check for existing OCR reviews and run review only if not found
142
+ - |
143
+ python3 << 'WRAPPER_SCRIPT'
144
+ import json
145
+ import os
146
+ import subprocess
147
+ import sys
148
+ import urllib.request
149
+
150
+ GITLAB_URL = os.environ.get("CI_SERVER_URL", "https://gitlab.com")
151
+ PROJECT_ID = os.environ["CI_PROJECT_ID"]
152
+ MR_IID = os.environ["CI_MERGE_REQUEST_IID"]
153
+ API_TOKEN = os.environ["GITLAB_API_TOKEN"]
154
+ SOURCE_BRANCH = os.environ["CI_MERGE_REQUEST_SOURCE_BRANCH_NAME"]
155
+ TARGET_BRANCH = os.environ["CI_MERGE_REQUEST_TARGET_BRANCH_NAME"]
156
+
157
+ # Check for existing OCR reviews
158
+ url = f"{GITLAB_URL}/api/v4/projects/{PROJECT_ID}/merge_requests/{MR_IID}/notes?per_page=100"
159
+ req = urllib.request.Request(url, headers={"PRIVATE-TOKEN": API_TOKEN})
160
+ with urllib.request.urlopen(req) as resp:
161
+ notes = json.loads(resp.read().decode("utf-8"))
162
+
163
+ for note in notes:
164
+ if "OpenCodeReview" in note.get("body", ""):
165
+ print("⏭️ OCR has already reviewed this MR. Skipping to save tokens.")
166
+ print("Delete previous OCR comments to re-trigger review.")
167
+ sys.exit(0)
168
+
169
+ # No existing review found - run OCR
170
+ print("🔍 No existing OCR review found. Running review...")
171
+ result = subprocess.run([
172
+ "ocr", "review",
173
+ "--from", f"origin/{TARGET_BRANCH}",
174
+ "--to", f"origin/{SOURCE_BRANCH}",
175
+ "--format", "json",
176
+ "--audience", "agent"
177
+ ], capture_output=True, text=True)
178
+
179
+ # Save output for the posting script
180
+ with open("/tmp/ocr-result.json", "w") as f:
181
+ f.write(result.stdout)
182
+ with open("/tmp/ocr-stderr.log", "w") as f:
183
+ f.write(result.stderr)
184
+
185
+ print("OCR review completed.")
186
+ WRAPPER_SCRIPT
187
+
188
+ # Post review comments to MR
189
+ - |
190
+ python3 << 'PYTHON_SCRIPT'
191
+ ...existing post script...
192
+ PYTHON_SCRIPT
193
+ ```
194
+
195
+ The key logic: the Python wrapper checks for existing OCR comments before running `ocr review`. If found, it exits early with `sys.exit(0)` before consuming any LLM tokens. To re-trigger a review, users can manually delete the previous OCR comments.
196
+
197
+ ### Self-hosted GitLab
198
+
199
+ The script automatically uses `CI_SERVER_URL` to determine the GitLab API base URL, so it works with self-hosted GitLab instances out of the box.
200
+
201
+ ### Use a Service Account as Review Bot
202
+
203
+ By default, review comments are posted using the user who owns the access token configured in `GITLAB_API_TOKEN`. You can create a dedicated service account bot to post reviews with a custom identity, making it easier to distinguish automated reviews from human comments.
204
+
205
+ For more details about GitLab service accounts, see the [GitLab Service Accounts documentation](https://docs.gitlab.com/ee/user/profile/service_accounts.html).
206
+
207
+ #### Step 1: Create a Service Account
208
+
209
+ Create a service account in your project:
210
+
211
+ 1. Go to your **Project → Settings → Service Accounts**
212
+ 2. Click **New service account**
213
+ 3. Fill in the following:
214
+ - **Name**: e.g., `OpenCodeReview Bot` (this will be the bot name shown in MR discussions)
215
+ - **Username**: Will be auto-generated based on the name
216
+ 4. Click **Create service account**
217
+
218
+ #### Step 2: Invite the Service Account to Your Project
219
+
220
+ After the service account is created, invite it to your project with appropriate permissions:
221
+
222
+ 1. Go to your **Project → Settings → Members**
223
+ 2. Click **Invite member**
224
+ 3. Search for the service account by name (e.g., `OpenCodeReview Bot`)
225
+ 4. Select the service account and assign a role (`Developer` or `Maintainer` required for posting discussions)
226
+ 5. Click **Invite**
227
+
228
+ #### Step 3: Create an Access Token
229
+
230
+ Generate an access token for the service account:
231
+
232
+ 1. Go to your **Project → Settings → Service Accounts**
233
+ 2. Click on the service account to view its details
234
+ 3. Click **Add new token**
235
+ 4. Configure the token:
236
+ - **Name**: e.g., `ocr-review-token`
237
+ - **Expiration**: As needed
238
+ - **Scope**: Select `api` (required for Discussions API)
239
+ 5. Click **Create token** and copy the token value
240
+
241
+ #### Step 4: Update CI/CD Variables
242
+
243
+ Update the `GITLAB_API_TOKEN` variable in your project's CI/CD settings:
244
+
245
+ Go to **Settings → CI/CD → Variables** and update `GITLAB_API_TOKEN` with the service account's token.
246
+
247
+ Now review comments will be posted with your service account identity (e.g., `OpenCodeReview Bot`), providing a clear and professional appearance for automated code reviews.
248
+
249
+ ## Troubleshooting
250
+
251
+ ### Common Issues
252
+
253
+ 1. **"API error 403"**: The `GITLAB_API_TOKEN` lacks `api` scope or doesn't have access to the project
254
+ 2. **"Failed to parse OCR output"**: Check that `OCR_LLM_URL` and `OCR_LLM_AUTH_TOKEN` variables are correctly set
255
+ 3. **"Cannot find merge-base"**: Ensure `GIT_DEPTH: 0` is set (full clone)
256
+ 4. **Inline comments on wrong lines**: GitLab requires exact SHA matching; the script fetches MR version metadata to get correct diff refs
257
+
258
+ ### Debugging
259
+
260
+ Add verbose output to the review step:
261
+
262
+ ```yaml
263
+ script:
264
+ - cat /tmp/ocr-result.json
265
+ - cat /tmp/ocr-stderr.log
266
+ ```
267
+
268
+
package/package.json CHANGED
@@ -1,14 +1,12 @@
1
1
  {
2
2
  "name": "@alibaba-group/open-code-review",
3
- "version": "1.1.8",
3
+ "version": "1.1.10",
4
4
  "description": "OpenCodeReview CLI — AI-powered code review tool",
5
5
  "bin": {
6
6
  "ocr": "bin/ocr.js"
7
7
  },
8
8
  "scripts": {
9
- "postinstall": "node scripts/install.js",
10
- "prepublishOnly": "cp NPM-README.md README.md",
11
- "postpublish": "git checkout README.md"
9
+ "postinstall": "node scripts/install.js"
12
10
  },
13
11
  "repository": {
14
12
  "type": "git",
package/NPM-README.md DELETED
@@ -1,95 +0,0 @@
1
- # OpenCodeReview CLI
2
-
3
- AI-powered code review tool that reads Git diffs, sends changed files to a configurable LLM via OpenAI-compatible API, and generates structured review comments. It goes beyond surface-level analysis — the Agent can read project context for deep reviews.
4
-
5
- ## Install
6
-
7
- ```bash
8
- npm install -g @alibaba-group/open-code-review
9
- ```
10
-
11
- After installation, the `ocr` command is available globally.
12
-
13
- ### Version Control
14
-
15
- ```bash
16
- # Install specific version
17
- OCR_VERSION=v1.0.0 npm install -g @alibaba-group/open-code-review
18
- ```
19
-
20
- ## Prerequisites
21
-
22
- **You must configure an LLM provider before using `ocr`.** The tool requires access to an OpenAI-compatible API endpoint (OpenAI, Claude, local models, etc.).
23
-
24
- ```bash
25
- ocr config set llm.url https://api.anthropic.com/v1/messages \
26
- && ocr config set llm.auth_token {{your-api-key}} \
27
- && ocr config set llm.model claude-opus-4-6 \
28
- && ocr config set llm.use_anthropic true \
29
- && ocr config set language Chinese
30
- ```
31
-
32
- Config is stored in `~/.opencodereview/config.json`.
33
-
34
- Or via environment variables:
35
-
36
- ```bash
37
- export OCR_LLM_URL=https://api.anthropic.com/v1/messages
38
- export OCR_LLM_TOKEN=your-api-key
39
- export OCR_LLM_MODEL=claude-opus-4-6
40
- ```
41
-
42
- ### Test Connectivity
43
-
44
- ```bash
45
- ocr llm test
46
- ```
47
-
48
- ## Quick Start
49
-
50
- Navigate to any Git repository and run:
51
-
52
- ```bash
53
- # Review all workspace changes
54
- ocr review
55
-
56
- # Review diff between two branches
57
- ocr review --from main --to feature-branch
58
-
59
- # Review a single commit
60
- ocr review --commit abc123
61
- ```
62
-
63
- ## Commands
64
-
65
- | Command | Description |
66
- |---------|-------------|
67
- | `ocr review` / `ocr r` | Start code review |
68
- | `ocr config set <key> <value>` | Manage configuration |
69
- | `ocr llm test` | Test LLM connectivity |
70
- | `ocr viewer` | Start WebUI session viewer |
71
- | `ocr version` | Show version info |
72
-
73
- ## Common Options
74
-
75
- | Flag | Shorthand | Default | Description |
76
- |------|-----------|---------|-------------|
77
- | `--repo` | | current dir | Git repository root |
78
- | `--from` | | | Source ref (e.g., `main`) |
79
- | `--to` | | | Target ref (e.g., `feature-branch`) |
80
- | `--commit` | `-c` | | Review a single commit |
81
- | `--format` | `-f` | `text` | Output format: `text` or `json` |
82
- | `--concurrency` | | `4` | Max concurrent file reviews |
83
- | `--timeout` | | `10` | Per-file timeout (minutes) |
84
-
85
- ## Features
86
-
87
- - **Three review modes**: workspace changes, branch range, single commit
88
- - **Context-aware**: Agent reads arbitrary files, searches code via `git grep`, inspects diffs
89
- - **Plan phase**: Large changes (>50 lines) get risk analysis first
90
- - **Any LLM**: Works with OpenAI, Claude-compatible endpoints, local models
91
- - **Concurrent**: Files reviewed in parallel (configurable workers)
92
-
93
- ## License
94
-
95
- Apache-2.0