@humanbased/crosscheck 1.6.1-beta.10 → 1.7.0-beta.22
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.
- package/README.md +3 -1
- package/crosscheck.config.example.yml +20 -4
- package/dist/__tests__/detector.test.js +22 -0
- package/dist/__tests__/detector.test.js.map +1 -1
- package/dist/__tests__/onboard-preservation.test.js +27 -5
- package/dist/__tests__/onboard-preservation.test.js.map +1 -1
- package/dist/__tests__/optimize.test.js +18 -2
- package/dist/__tests__/optimize.test.js.map +1 -1
- package/dist/__tests__/review-models.test.js +5 -5
- package/dist/__tests__/review-models.test.js.map +1 -1
- package/dist/__tests__/review-strategy.test.js +10 -10
- package/dist/__tests__/review-strategy.test.js.map +1 -1
- package/dist/__tests__/runner.test.js +12 -2
- package/dist/__tests__/runner.test.js.map +1 -1
- package/dist/commands/init.d.ts.map +1 -1
- package/dist/commands/init.js +14 -1
- package/dist/commands/init.js.map +1 -1
- package/dist/commands/issue.d.ts.map +1 -1
- package/dist/commands/issue.js +40 -16
- package/dist/commands/issue.js.map +1 -1
- package/dist/commands/onboard.d.ts +5 -4
- package/dist/commands/onboard.d.ts.map +1 -1
- package/dist/commands/onboard.js +126 -48
- package/dist/commands/onboard.js.map +1 -1
- package/dist/commands/optimize.d.ts +1 -1
- package/dist/commands/optimize.d.ts.map +1 -1
- package/dist/commands/optimize.js +53 -13
- package/dist/commands/optimize.js.map +1 -1
- package/dist/commands/review.d.ts.map +1 -1
- package/dist/commands/review.js +9 -3
- package/dist/commands/review.js.map +1 -1
- package/dist/commands/run.d.ts +2 -2
- package/dist/commands/run.d.ts.map +1 -1
- package/dist/commands/run.js +1 -1
- package/dist/commands/run.js.map +1 -1
- package/dist/commands/status.d.ts.map +1 -1
- package/dist/commands/status.js +12 -1
- package/dist/commands/status.js.map +1 -1
- package/dist/commands/watch.d.ts.map +1 -1
- package/dist/commands/watch.js +6 -3
- package/dist/commands/watch.js.map +1 -1
- package/dist/config/review-model-tiers.json +9 -9
- package/dist/config/review-strategy.json +12 -12
- package/dist/config/schema.d.ts +102 -16
- package/dist/config/schema.d.ts.map +1 -1
- package/dist/config/schema.js +28 -3
- package/dist/config/schema.js.map +1 -1
- package/dist/github/client.js +1 -1
- package/dist/github/client.js.map +1 -1
- package/dist/github/detector.d.ts +2 -2
- package/dist/github/detector.d.ts.map +1 -1
- package/dist/github/detector.js +46 -11
- package/dist/github/detector.js.map +1 -1
- package/dist/lib/comment-bodies.d.ts.map +1 -1
- package/dist/lib/comment-bodies.js +4 -2
- package/dist/lib/comment-bodies.js.map +1 -1
- package/dist/lib/review-models.d.ts +4 -1
- package/dist/lib/review-models.d.ts.map +1 -1
- package/dist/lib/review-models.js +8 -0
- package/dist/lib/review-models.js.map +1 -1
- package/dist/lib/reviewer-error.d.ts.map +1 -1
- package/dist/lib/reviewer-error.js +12 -8
- package/dist/lib/reviewer-error.js.map +1 -1
- package/dist/lib/runner.d.ts +8 -7
- package/dist/lib/runner.d.ts.map +1 -1
- package/dist/lib/runner.js +71 -20
- package/dist/lib/runner.js.map +1 -1
- package/dist/lib/smart-switch.d.ts +7 -6
- package/dist/lib/smart-switch.d.ts.map +1 -1
- package/dist/lib/smart-switch.js +9 -2
- package/dist/lib/smart-switch.js.map +1 -1
- package/dist/lib/vendor.d.ts +2 -2
- package/dist/lib/vendor.d.ts.map +1 -1
- package/dist/lib/vendor.js +12 -2
- package/dist/lib/vendor.js.map +1 -1
- package/dist/lib/workflow.d.ts +8 -8
- package/dist/lib/workflow.js +1 -1
- package/dist/lib/workflow.js.map +1 -1
- package/dist/reviewers/fix.d.ts +6 -0
- package/dist/reviewers/fix.d.ts.map +1 -1
- package/dist/reviewers/fix.js +61 -0
- package/dist/reviewers/fix.js.map +1 -1
- package/dist/reviewers/opencode-env.d.ts +13 -0
- package/dist/reviewers/opencode-env.d.ts.map +1 -0
- package/dist/reviewers/opencode-env.js +52 -0
- package/dist/reviewers/opencode-env.js.map +1 -0
- package/dist/reviewers/opencode.d.ts +17 -0
- package/dist/reviewers/opencode.d.ts.map +1 -0
- package/dist/reviewers/opencode.js +293 -0
- package/dist/reviewers/opencode.js.map +1 -0
- package/get-started.md +38 -4
- package/package.json +1 -1
|
@@ -0,0 +1,293 @@
|
|
|
1
|
+
import { execa } from 'execa';
|
|
2
|
+
import { rmSync, mkdtempSync, renameSync, existsSync, writeFileSync } from 'fs';
|
|
3
|
+
import { join } from 'path';
|
|
4
|
+
import { tmpdir } from 'os';
|
|
5
|
+
import { DEFAULT_REVIEW_INSTRUCTIONS } from '../lib/workflow.js';
|
|
6
|
+
import { resolveOpenCodeModel } from '../lib/review-models.js';
|
|
7
|
+
import { withTimeoutRetry } from '../lib/with-timeout-retry.js';
|
|
8
|
+
import { vendorFailureSummary } from '../lib/vendor-error-summary.js';
|
|
9
|
+
import { tierTimeoutMs } from './tier-timeouts.js';
|
|
10
|
+
import { buildOpenCodeEnv } from './opencode-env.js';
|
|
11
|
+
import { loadRepositoryReviewGuidance } from '../lib/repository-guidance.js';
|
|
12
|
+
import { withCredentialFreeOrigin } from '../lib/clone.js';
|
|
13
|
+
// OpenCode's reasoning-effort ladder is the `#variant` suffix on
|
|
14
|
+
// `--model provider/model#variant`. Variants are provider-defined, not one
|
|
15
|
+
// global ladder like claude/codex: deepseek-v4-* (the opencode models
|
|
16
|
+
// crosscheck ships policy for) expose none / high / max, with no low/medium.
|
|
17
|
+
// Whitelist rather than translation — anything outside this vocabulary falls
|
|
18
|
+
// back to `high` instead of reaching the CLI as an unsupported variant.
|
|
19
|
+
const OPENCODE_EFFORT_MAP = {
|
|
20
|
+
none: 'none',
|
|
21
|
+
high: 'high',
|
|
22
|
+
max: 'max',
|
|
23
|
+
};
|
|
24
|
+
export function opencodeEffort(effort) {
|
|
25
|
+
return (effort && OPENCODE_EFFORT_MAP[effort]) ?? 'high';
|
|
26
|
+
}
|
|
27
|
+
export function parseOpenCodeOutput(raw) {
|
|
28
|
+
let review = '';
|
|
29
|
+
let inputTokens = 0;
|
|
30
|
+
let outputTokens = 0;
|
|
31
|
+
let reasoningTokens = 0;
|
|
32
|
+
let sawTokens = false;
|
|
33
|
+
for (const line of raw.split('\n')) {
|
|
34
|
+
if (!line.trim())
|
|
35
|
+
continue;
|
|
36
|
+
let event;
|
|
37
|
+
try {
|
|
38
|
+
event = JSON.parse(line);
|
|
39
|
+
}
|
|
40
|
+
catch {
|
|
41
|
+
// Non-JSON line (progress/log noise) — skip, never fail the whole parse.
|
|
42
|
+
continue;
|
|
43
|
+
}
|
|
44
|
+
if (event.type === 'text' && event.part?.text)
|
|
45
|
+
review += event.part.text;
|
|
46
|
+
if (event.type === 'step_finish' && event.part?.tokens) {
|
|
47
|
+
// Each model step emits its own payload; accumulate rather than overwrite,
|
|
48
|
+
// and include reasoning so a multi-step run is not undercounted.
|
|
49
|
+
const t = event.part.tokens;
|
|
50
|
+
if (typeof t.input === 'number')
|
|
51
|
+
inputTokens += t.input;
|
|
52
|
+
if (typeof t.output === 'number')
|
|
53
|
+
outputTokens += t.output;
|
|
54
|
+
if (typeof t.reasoning === 'number')
|
|
55
|
+
reasoningTokens += t.reasoning;
|
|
56
|
+
sawTokens = true;
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
const tokensUsed = sawTokens ? inputTokens + outputTokens + reasoningTokens : undefined;
|
|
60
|
+
return { review, tokensUsed };
|
|
61
|
+
}
|
|
62
|
+
// OpenCode follows the same VERDICT rule as claude/codex, so a well-behaved run
|
|
63
|
+
// ends with the line. Match it case-insensitively: a `Verdict: BLOCK` that the
|
|
64
|
+
// old exact-match check missed then received an appended APPROVE, which the
|
|
65
|
+
// parser read as the final verdict. When no verdict was stated at all, default
|
|
66
|
+
// to NEEDS WORK — never APPROVE, which would clear a PR on a verdict nobody
|
|
67
|
+
// gave (an empty or refusing body is caught earlier by detectInconclusiveReview).
|
|
68
|
+
export function inferVerdictFromOpenCodeOutput(text) {
|
|
69
|
+
return /\bVERDICT\s*:/i.test(text) ? text : `${text}\n\nVERDICT: NEEDS WORK`;
|
|
70
|
+
}
|
|
71
|
+
// Detect transient OpenCode errors that should be retried (rate limits, socket
|
|
72
|
+
// disconnects). OpenCode reports these through the same shapes as codex.
|
|
73
|
+
function isRetryableOpenCodeError(message) {
|
|
74
|
+
return /socket.*closed|429|rate limit|connection.*reset|econnreset/i.test(message);
|
|
75
|
+
}
|
|
76
|
+
const MAX_OPENCODE_RETRIES = 2;
|
|
77
|
+
const OPENCODE_RETRY_DELAY_MS = 5000;
|
|
78
|
+
// Scans stderr bottom-up for the first fatal/error line, skipping OpenCode
|
|
79
|
+
// header/log boilerplate.
|
|
80
|
+
function extractOpenCodeErrorSummary(stderr) {
|
|
81
|
+
const lines = stderr.split('\n').map(l => l.trim()).filter(Boolean);
|
|
82
|
+
for (let i = lines.length - 1; i >= 0; i--) {
|
|
83
|
+
const l = lines[i];
|
|
84
|
+
if (/^(fatal|error):/i.test(l))
|
|
85
|
+
return l;
|
|
86
|
+
}
|
|
87
|
+
return lines.filter(l => !l.startsWith('---') &&
|
|
88
|
+
!/^\d{4}-\d{2}-\d{2}T\d/.test(l) &&
|
|
89
|
+
!/ WARN /i.test(l)).at(-1);
|
|
90
|
+
}
|
|
91
|
+
// OpenCode auto-discovers a project's own opencode.json / .opencode directory
|
|
92
|
+
// from the working directory upward, and loads any plugin they register. In an
|
|
93
|
+
// untrusted checkout that is an arbitrary-code channel independent of the
|
|
94
|
+
// prompt, and OpenCode v2 has no `--pure` / config override flag to suppress it.
|
|
95
|
+
// Remove them before the run so only the operator's global config applies. The
|
|
96
|
+
// clone is a throwaway and a review reads the diff, not these files.
|
|
97
|
+
// A restrictive permission policy for the untrusted run. OpenCode v2 has no
|
|
98
|
+
// sandbox flag, so this is the tool-denial layer: a review inspects the diff by
|
|
99
|
+
// running read-only git, so allow exactly those shell commands and deny every
|
|
100
|
+
// other one. `--auto` auto-approves `ask` but cannot widen a `deny`.
|
|
101
|
+
// `allowEdit` is left for the fix step, which must write files.
|
|
102
|
+
export function opencodePolicy(allowEdit) {
|
|
103
|
+
return {
|
|
104
|
+
permissions: [
|
|
105
|
+
{ action: 'shell', resource: '*', effect: 'deny' },
|
|
106
|
+
{ action: 'shell', resource: 'git status *', effect: 'allow' },
|
|
107
|
+
{ action: 'shell', resource: 'git diff *', effect: 'allow' },
|
|
108
|
+
{ action: 'shell', resource: 'git log *', effect: 'allow' },
|
|
109
|
+
{ action: 'shell', resource: 'git show *', effect: 'allow' },
|
|
110
|
+
...(allowEdit ? [] : [{ action: 'edit', resource: '*', effect: 'deny' }]),
|
|
111
|
+
],
|
|
112
|
+
};
|
|
113
|
+
}
|
|
114
|
+
export function isolateCheckoutOpenCodeConfig(repoDir, allowEdit = false) {
|
|
115
|
+
const backupDir = mkdtempSync(join(tmpdir(), 'crosscheck-oc-config-'));
|
|
116
|
+
const moved = [];
|
|
117
|
+
for (const rel of ['opencode.json', 'opencode.jsonc', '.opencode']) {
|
|
118
|
+
const from = join(repoDir, rel);
|
|
119
|
+
if (!existsSync(from))
|
|
120
|
+
continue;
|
|
121
|
+
const to = join(backupDir, rel.replace(/[/\\]/g, '_'));
|
|
122
|
+
try {
|
|
123
|
+
renameSync(from, to);
|
|
124
|
+
moved.push({ from, to });
|
|
125
|
+
}
|
|
126
|
+
catch { /* best effort */ }
|
|
127
|
+
}
|
|
128
|
+
// Install the policy as the project config this run will load; remove it on
|
|
129
|
+
// restore so a later fix's `git add -A` cannot stage it.
|
|
130
|
+
let policyWritten = false;
|
|
131
|
+
try {
|
|
132
|
+
writeFileSync(join(repoDir, 'opencode.json'), JSON.stringify(opencodePolicy(allowEdit), null, 2));
|
|
133
|
+
policyWritten = true;
|
|
134
|
+
}
|
|
135
|
+
catch { /* best effort */ }
|
|
136
|
+
// Restore the checkout's own config so a later fix step does not stage these
|
|
137
|
+
// tracked deletions as changed files (git add -A would then commit and push).
|
|
138
|
+
return () => {
|
|
139
|
+
if (policyWritten) {
|
|
140
|
+
try {
|
|
141
|
+
rmSync(join(repoDir, 'opencode.json'), { force: true });
|
|
142
|
+
}
|
|
143
|
+
catch { /* best effort */ }
|
|
144
|
+
}
|
|
145
|
+
const failed = [];
|
|
146
|
+
for (const { from, to } of moved.reverse()) {
|
|
147
|
+
try {
|
|
148
|
+
renameSync(to, from);
|
|
149
|
+
}
|
|
150
|
+
catch {
|
|
151
|
+
failed.push(from);
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
// Delete the backup only when every path was restored. If the agent recreated
|
|
155
|
+
// a conflicting path, keep the backup and fail loudly so the original tracked
|
|
156
|
+
// configuration is never silently lost.
|
|
157
|
+
if (failed.length > 0) {
|
|
158
|
+
throw new Error(`could not restore OpenCode config: ${failed.join(', ')} (backup kept at ${backupDir})`);
|
|
159
|
+
}
|
|
160
|
+
try {
|
|
161
|
+
rmSync(backupDir, { recursive: true, force: true });
|
|
162
|
+
}
|
|
163
|
+
catch { /* best effort */ }
|
|
164
|
+
};
|
|
165
|
+
}
|
|
166
|
+
export async function runOpenCodeReview(repoDir, baseBranch, prTitle, quality, vendor, stepInstructions, onLog, timeoutMs, onRetry, issueContext, _skillSession) {
|
|
167
|
+
const model = resolveOpenCodeModel(quality, vendor);
|
|
168
|
+
const effort = opencodeEffort(vendor.effort);
|
|
169
|
+
const tierTimeout = tierTimeoutMs(quality.tier);
|
|
170
|
+
// timeoutMs: 0 → no cap (crazy/halfcrazy); undefined → tier-based default; positive → user-specified
|
|
171
|
+
const resolvedTimeout = timeoutMs === undefined ? tierTimeout : timeoutMs === 0 ? undefined : timeoutMs;
|
|
172
|
+
const focusLine = quality.focus.length > 0
|
|
173
|
+
? `Focus areas: ${quality.focus.join(', ')}.`
|
|
174
|
+
: '';
|
|
175
|
+
const customLine = quality.custom_prompt ?? '';
|
|
176
|
+
const behaviorInstructions = stepInstructions ?? DEFAULT_REVIEW_INSTRUCTIONS;
|
|
177
|
+
const repositoryGuidance = loadRepositoryReviewGuidance(repoDir, baseBranch);
|
|
178
|
+
// Same block order as runClaudeReview/runCodexReview, so the same PR gets the
|
|
179
|
+
// same brief whichever vendor draws it: behaviour block ends on the verdict
|
|
180
|
+
// rule, repository guidance after it (reference material, not a first step).
|
|
181
|
+
const prompt = [
|
|
182
|
+
`You are reviewing a pull request titled: "${prTitle}".`,
|
|
183
|
+
`The branch \`${baseBranch}\` is the base. Review only the changes introduced in this PR.`,
|
|
184
|
+
issueContext ?? '',
|
|
185
|
+
focusLine,
|
|
186
|
+
customLine,
|
|
187
|
+
behaviorInstructions,
|
|
188
|
+
repositoryGuidance,
|
|
189
|
+
].filter(Boolean).join('\n\n');
|
|
190
|
+
// OpenCode takes the prompt on stdin (like claude/codex): `opencode run` with
|
|
191
|
+
// no message argument reads stdin, and keeping the prompt out of argv stops
|
|
192
|
+
// repository guidance from reaching the process list. `--standalone` runs a
|
|
193
|
+
// private server, so a review of untrusted code never shares a session with
|
|
194
|
+
// the operator's interactive work. `--auto` is required even for a read-only
|
|
195
|
+
// review: a headless run auto-rejects permission requests otherwise, and
|
|
196
|
+
// reviewing a diff can trip `external_directory` (the clone lives outside the
|
|
197
|
+
// agent's workspace root) which is fatal without it. The env allowlist and
|
|
198
|
+
// the throwaway clone bound the blast radius of the widened permissions.
|
|
199
|
+
//
|
|
200
|
+
// OpenCode has no separate effort flag — reasoning effort is the `#variant`
|
|
201
|
+
// suffix on `--model provider/model#variant`. Without a pinned model there is
|
|
202
|
+
// nowhere to hang the suffix, so `vendors.opencode.effort` is honoured only
|
|
203
|
+
// when `vendors.opencode.model` is set; otherwise OpenCode's configured
|
|
204
|
+
// default model AND its default variant run, and `effort` is reported but
|
|
205
|
+
// not applied (it is not a claim the CLI was given).
|
|
206
|
+
const modelArgs = model ? ['--model', `${model}#${effort}`] : [];
|
|
207
|
+
const args = ['run', '--format', 'json', '--auto', '--standalone', ...modelArgs];
|
|
208
|
+
onLog?.(` running: opencode run --format json --auto --standalone${model ? ` --model ${model}#${effort}` : ''}`);
|
|
209
|
+
let lastErr = undefined;
|
|
210
|
+
for (let attempt = 1; attempt <= MAX_OPENCODE_RETRIES; attempt++) {
|
|
211
|
+
try {
|
|
212
|
+
const { result: { stdout }, retried } = await withCredentialFreeOrigin(repoDir, () => {
|
|
213
|
+
// Hide any OpenCode config the untrusted checkout carries while the agent
|
|
214
|
+
// runs; restore it after so a later fix step cannot stage the deletion.
|
|
215
|
+
const restoreConfig = isolateCheckoutOpenCodeConfig(repoDir);
|
|
216
|
+
return withTimeoutRetry(resolvedTimeout, (t) => execa('opencode', args, {
|
|
217
|
+
cwd: repoDir,
|
|
218
|
+
timeout: t,
|
|
219
|
+
input: prompt,
|
|
220
|
+
// extendEnv: false or execa merges process.env back in and the
|
|
221
|
+
// allowlist means nothing.
|
|
222
|
+
extendEnv: false,
|
|
223
|
+
// No `${repoDir}/node_modules/.bin` on PATH: the checkout is untrusted
|
|
224
|
+
// and a committed `node_modules/.bin/opencode` would shadow the real
|
|
225
|
+
// executable. A review only reads the diff, so repo-local tools are
|
|
226
|
+
// not needed the way codex.ts assumed they were.
|
|
227
|
+
env: buildOpenCodeEnv(),
|
|
228
|
+
}), {
|
|
229
|
+
onRetry: (effectiveMs, delayMs) => (onRetry ?? onLog)?.(` ⏱ opencode timed out at ${effectiveMs / 1000}s — waiting ${delayMs / 1000}s and retrying once`),
|
|
230
|
+
}).finally(restoreConfig);
|
|
231
|
+
});
|
|
232
|
+
const { review: parsedReview, tokensUsed } = parseOpenCodeOutput(stdout ?? '');
|
|
233
|
+
const rawReview = parsedReview.trim();
|
|
234
|
+
const review = inferVerdictFromOpenCodeOutput(rawReview);
|
|
235
|
+
// Report effort only when a pinned model actually carried the #variant;
|
|
236
|
+
// with no model there is no suffix, so claiming a level would be false.
|
|
237
|
+
return { review, tokensUsed, model: model ?? 'default', effort: model ? effort : undefined, retried };
|
|
238
|
+
}
|
|
239
|
+
catch (err) {
|
|
240
|
+
const execa = err;
|
|
241
|
+
const rawStderr = execa.stderr ?? '';
|
|
242
|
+
const fullMessage = rawStderr || execa.message || '';
|
|
243
|
+
if (isRetryableOpenCodeError(fullMessage) && attempt < MAX_OPENCODE_RETRIES) {
|
|
244
|
+
const delay = OPENCODE_RETRY_DELAY_MS * attempt; // 5s, 10s
|
|
245
|
+
onLog?.(` opencode: transient error (${fullMessage.slice(0, 80)}), retrying in ${delay / 1000}s (attempt ${attempt}/${MAX_OPENCODE_RETRIES})...`);
|
|
246
|
+
await new Promise(resolve => setTimeout(resolve, delay));
|
|
247
|
+
lastErr = err;
|
|
248
|
+
continue;
|
|
249
|
+
}
|
|
250
|
+
const effectiveMs = execa.effectiveTimeoutMs ?? resolvedTimeout;
|
|
251
|
+
const retryNote = execa.retryDelayMs !== undefined ? ' (retried once)' : '';
|
|
252
|
+
const summary = execa.timedOut
|
|
253
|
+
? `timed out after ${effectiveMs !== undefined ? effectiveMs / 1000 : '?'}s${retryNote} — PR diff may be too large (tier: ${quality.tier})`
|
|
254
|
+
: vendorFailureSummary(execa, extractOpenCodeErrorSummary);
|
|
255
|
+
const thrown = Object.assign(new Error(`opencode: ${summary}`), {
|
|
256
|
+
exitCode: execa.exitCode,
|
|
257
|
+
timedOut: execa.timedOut,
|
|
258
|
+
stderr: rawStderr,
|
|
259
|
+
effectiveTimeoutMs: effectiveMs,
|
|
260
|
+
retryDelayMs: execa.retryDelayMs,
|
|
261
|
+
});
|
|
262
|
+
throw thrown;
|
|
263
|
+
}
|
|
264
|
+
}
|
|
265
|
+
if (lastErr)
|
|
266
|
+
throw lastErr;
|
|
267
|
+
throw new Error('opencode: unexpected retry loop exit');
|
|
268
|
+
}
|
|
269
|
+
export async function checkOpenCodeAuth() {
|
|
270
|
+
try {
|
|
271
|
+
// `--format json` returns one record per provider, so human-readable headers
|
|
272
|
+
// and summaries can never be miscounted as authenticated providers the way
|
|
273
|
+
// the text form's line count could.
|
|
274
|
+
const { stdout } = await execa('opencode', ['auth', 'list', '--format', 'json'], { timeout: 10_000 });
|
|
275
|
+
let parsed;
|
|
276
|
+
try {
|
|
277
|
+
parsed = JSON.parse(stdout);
|
|
278
|
+
}
|
|
279
|
+
catch {
|
|
280
|
+
parsed = null;
|
|
281
|
+
}
|
|
282
|
+
const providers = Array.isArray(parsed) ? parsed : [];
|
|
283
|
+
if (providers.length === 0) {
|
|
284
|
+
return { ok: false, detail: 'no providers configured — run: opencode auth login' };
|
|
285
|
+
}
|
|
286
|
+
return { ok: true, detail: `${providers.length} provider(s) configured` };
|
|
287
|
+
}
|
|
288
|
+
catch (err) {
|
|
289
|
+
const error = err;
|
|
290
|
+
return { ok: false, detail: error.stderr ?? error.message ?? 'not found' };
|
|
291
|
+
}
|
|
292
|
+
}
|
|
293
|
+
//# sourceMappingURL=opencode.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"opencode.js","sourceRoot":"","sources":["../../src/reviewers/opencode.ts"],"names":[],"mappings":"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"}
|
package/get-started.md
CHANGED
|
@@ -37,7 +37,7 @@
|
|
|
37
37
|
|
|
38
38
|
## Prerequisites
|
|
39
39
|
|
|
40
|
-
You need GitHub CLI and at least one authenticated AI reviewer CLI before crosscheck can run a one-shot review. Install both Claude Code and Codex only if you want cross-vendor review routing.
|
|
40
|
+
You need GitHub CLI and at least one authenticated AI reviewer CLI before crosscheck can run a one-shot review. Install both Claude Code and Codex only if you want cross-vendor review routing. OpenCode is an optional third harness, disabled by default.
|
|
41
41
|
|
|
42
42
|
### Claude Code
|
|
43
43
|
|
|
@@ -65,6 +65,15 @@ printenv OPENAI_API_KEY | codex login --with-api-key
|
|
|
65
65
|
|
|
66
66
|
Then set `auth: api-key` in your config to enable model selection.
|
|
67
67
|
|
|
68
|
+
### OpenCode
|
|
69
|
+
|
|
70
|
+
```bash
|
|
71
|
+
npm install -g @opencode/cli
|
|
72
|
+
opencode auth login # sign in to a provider (e.g. DeepSeek, Anthropic, OpenAI)
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
OpenCode is **opt-in**: enable it with `vendors.opencode.enabled: true` (or `crosscheck onboard`). Its model and provider come from your OpenCode config (`opencode auth login` / `opencode.json`) — crosscheck pins no model by default, so reviews run against whichever model OpenCode is configured to use. Reasoning effort is carried as the `#variant` suffix on `--model provider/model#variant`, so `vendors.opencode.effort` (none | high | max) applies only when `vendors.opencode.model` is also set.
|
|
76
|
+
|
|
68
77
|
### GitHub CLI
|
|
69
78
|
|
|
70
79
|
```bash
|
|
@@ -794,6 +803,7 @@ crosscheck status
|
|
|
794
803
|
Auth
|
|
795
804
|
✓ codex authenticated
|
|
796
805
|
✓ claude 2.1.x (Claude Code)
|
|
806
|
+
✓ opencode v2.x
|
|
797
807
|
✓ GITHUB_TOKEN via gh auth login
|
|
798
808
|
✓ WEBHOOK_SECRET auto-managed at ~/.crosscheck/webhook-secret
|
|
799
809
|
|
|
@@ -804,6 +814,8 @@ crosscheck status
|
|
|
804
814
|
enabled skills code-review-skill (by @awesome-skills, MIT), diagnosing-bugs (by @mattpocock, MIT)
|
|
805
815
|
codex auth subscription
|
|
806
816
|
claude model sonnet
|
|
817
|
+
opencode enabled false
|
|
818
|
+
opencode model configured in opencode.json
|
|
807
819
|
per-review budget $2.00/review
|
|
808
820
|
|
|
809
821
|
Impact
|
|
@@ -817,6 +829,7 @@ crosscheck status
|
|
|
817
829
|
CLIs
|
|
818
830
|
codex codex-cli 0.128.0
|
|
819
831
|
claude 2.1.x (Claude Code)
|
|
832
|
+
opencode v2.x
|
|
820
833
|
```
|
|
821
834
|
|
|
822
835
|
| Flag | Description |
|
|
@@ -1192,8 +1205,8 @@ vendors:
|
|
|
1192
1205
|
codex:
|
|
1193
1206
|
enabled: true
|
|
1194
1207
|
auth: subscription # subscription | api-key
|
|
1195
|
-
model: gpt-
|
|
1196
|
-
effort: medium # low | medium | high | xhigh | max | ultra
|
|
1208
|
+
model: gpt-6.1-sol # pins the review model; unset = tier model (api-key) / CLI default (subscription)
|
|
1209
|
+
effort: medium # low | medium | high | xhigh | max | ultra
|
|
1197
1210
|
# timeout_sec: 1200 # max seconds per CLI call; unset = tier-based (300/600/1200)
|
|
1198
1211
|
|
|
1199
1212
|
claude:
|
|
@@ -1202,6 +1215,16 @@ vendors:
|
|
|
1202
1215
|
effort: medium # low | medium | high | max
|
|
1203
1216
|
# timeout_sec: 1200 # max seconds per CLI call; unset = tier-based (300/600/1200)
|
|
1204
1217
|
|
|
1218
|
+
# Opt-in third harness; disabled by default. Its model/provider come from
|
|
1219
|
+
# `opencode auth login` / opencode.json, not from a crosscheck catalog.
|
|
1220
|
+
# Reasoning effort rides the `--model provider/model#variant` suffix, so
|
|
1221
|
+
# `effort` applies only when `model` is also set.
|
|
1222
|
+
opencode:
|
|
1223
|
+
enabled: false
|
|
1224
|
+
# model: provider/model # e.g. alibaba-cn/deepseek-v4-pro; unset = opencode.json default
|
|
1225
|
+
effort: high # none | high | max
|
|
1226
|
+
# timeout_sec: 1200 # max seconds per CLI call; unset = tier-based (300/600/1200)
|
|
1227
|
+
|
|
1205
1228
|
# ── Quality ───────────────────────────────────────────────────────────────────
|
|
1206
1229
|
quality:
|
|
1207
1230
|
# Structured findings and incremental follow-ups; set false for legacy prose reviews.
|
|
@@ -1285,12 +1308,18 @@ routing:
|
|
|
1285
1308
|
claude_reviews_patterns:
|
|
1286
1309
|
- "Generated with \\[OpenAI Codex\\]" # Codex attribution footer
|
|
1287
1310
|
- "Co-Authored-By: codex" # commit trailer
|
|
1311
|
+
opencode_reviews_patterns:
|
|
1312
|
+
- "Generated with \\[OpenCode\\]" # OpenCode attribution footer
|
|
1313
|
+
- "Co-Authored-By: opencode" # commit trailer
|
|
1288
1314
|
|
|
1289
|
-
# Branch prefix detection (signal 3). Claude Code uses claude/, Codex uses
|
|
1315
|
+
# Branch prefix detection (signal 3). Claude Code uses claude/, Codex uses
|
|
1316
|
+
# codex/, OpenCode uses opencode/.
|
|
1290
1317
|
claude_branch_prefixes:
|
|
1291
1318
|
- "claude/"
|
|
1292
1319
|
codex_branch_prefixes:
|
|
1293
1320
|
- "codex/"
|
|
1321
|
+
opencode_branch_prefixes:
|
|
1322
|
+
- "opencode/"
|
|
1294
1323
|
|
|
1295
1324
|
# Restrict reviews to PRs opened by these GitHub logins.
|
|
1296
1325
|
# Auto-filled with your GitHub login by `crosscheck init` or first `crosscheck watch`.
|
|
@@ -1304,6 +1333,11 @@ routing:
|
|
|
1304
1333
|
author_routes:
|
|
1305
1334
|
your-github-login: claude # your PRs → treated as Claude-authored → Codex reviews
|
|
1306
1335
|
|
|
1336
|
+
# Reviewer for PRs crosscheck cannot attribute (origin: human). 'auto' = the
|
|
1337
|
+
# first authenticated vendor (codex, then claude, then opencode); an explicit
|
|
1338
|
+
# 'codex' | 'claude' | 'opencode' always uses that vendor; null = skip the PR.
|
|
1339
|
+
fallback_reviewer: auto
|
|
1340
|
+
|
|
1307
1341
|
# ── Tunnel (watch mode only) ──────────────────────────────────────────────────
|
|
1308
1342
|
# localhost.run (default) — SSH tunnel, zero install, URL changes on reconnect.
|
|
1309
1343
|
# smee — stable relay via smee.io; events queued while offline.
|