@motivation-labs/crosscheck 0.1.0
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/LICENSE +21 -0
- package/README.md +92 -0
- package/crosscheck.config.example.yml +75 -0
- package/dist/cli.d.ts +3 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +40 -0
- package/dist/cli.js.map +1 -0
- package/dist/commands/init.d.ts +2 -0
- package/dist/commands/init.d.ts.map +1 -0
- package/dist/commands/init.js +75 -0
- package/dist/commands/init.js.map +1 -0
- package/dist/commands/review.d.ts +2 -0
- package/dist/commands/review.d.ts.map +1 -0
- package/dist/commands/review.js +69 -0
- package/dist/commands/review.js.map +1 -0
- package/dist/commands/serve.d.ts +2 -0
- package/dist/commands/serve.d.ts.map +1 -0
- package/dist/commands/serve.js +92 -0
- package/dist/commands/serve.js.map +1 -0
- package/dist/commands/status.d.ts +2 -0
- package/dist/commands/status.d.ts.map +1 -0
- package/dist/commands/status.js +57 -0
- package/dist/commands/status.js.map +1 -0
- package/dist/commands/watch.d.ts +2 -0
- package/dist/commands/watch.d.ts.map +1 -0
- package/dist/commands/watch.js +177 -0
- package/dist/commands/watch.js.map +1 -0
- package/dist/config/loader.d.ts +5 -0
- package/dist/config/loader.d.ts.map +1 -0
- package/dist/config/loader.js +34 -0
- package/dist/config/loader.js.map +1 -0
- package/dist/config/schema.d.ts +267 -0
- package/dist/config/schema.d.ts.map +1 -0
- package/dist/config/schema.js +47 -0
- package/dist/config/schema.js.map +1 -0
- package/dist/github/client.d.ts +16 -0
- package/dist/github/client.d.ts.map +1 -0
- package/dist/github/client.js +89 -0
- package/dist/github/client.js.map +1 -0
- package/dist/github/detector.d.ts +6 -0
- package/dist/github/detector.d.ts.map +1 -0
- package/dist/github/detector.js +35 -0
- package/dist/github/detector.js.map +1 -0
- package/dist/github/webhook.d.ts +27 -0
- package/dist/github/webhook.d.ts.map +1 -0
- package/dist/github/webhook.js +48 -0
- package/dist/github/webhook.js.map +1 -0
- package/dist/reviewers/claude.d.ts +7 -0
- package/dist/reviewers/claude.d.ts.map +1 -0
- package/dist/reviewers/claude.js +66 -0
- package/dist/reviewers/claude.js.map +1 -0
- package/dist/reviewers/codex.d.ts +7 -0
- package/dist/reviewers/codex.d.ts.map +1 -0
- package/dist/reviewers/codex.js +59 -0
- package/dist/reviewers/codex.js.map +1 -0
- package/package.json +60 -0
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
import { Octokit } from 'octokit';
|
|
2
|
+
import { createHmac, timingSafeEqual } from 'crypto';
|
|
3
|
+
export function createGithubClient(token) {
|
|
4
|
+
return new Octokit({ auth: token });
|
|
5
|
+
}
|
|
6
|
+
export function verifyWebhookSignature(payload, signature, secret) {
|
|
7
|
+
const expected = `sha256=${createHmac('sha256', secret).update(payload).digest('hex')}`;
|
|
8
|
+
try {
|
|
9
|
+
return timingSafeEqual(Buffer.from(signature), Buffer.from(expected));
|
|
10
|
+
}
|
|
11
|
+
catch {
|
|
12
|
+
return false;
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
export async function getPRDiff(octokit, owner, repo, pullNumber) {
|
|
16
|
+
const { data } = await octokit.rest.pulls.get({
|
|
17
|
+
owner,
|
|
18
|
+
repo,
|
|
19
|
+
pull_number: pullNumber,
|
|
20
|
+
mediaType: { format: 'diff' },
|
|
21
|
+
});
|
|
22
|
+
return data;
|
|
23
|
+
}
|
|
24
|
+
export async function registerRepoWebhook(owner, repo, webhookUrl, secret, token) {
|
|
25
|
+
const res = await fetch(`https://api.github.com/repos/${owner}/${repo}/hooks`, {
|
|
26
|
+
method: 'POST',
|
|
27
|
+
headers: {
|
|
28
|
+
Authorization: `Bearer ${token}`,
|
|
29
|
+
Accept: 'application/vnd.github+json',
|
|
30
|
+
'Content-Type': 'application/json',
|
|
31
|
+
},
|
|
32
|
+
body: JSON.stringify({
|
|
33
|
+
name: 'web',
|
|
34
|
+
active: true,
|
|
35
|
+
events: ['pull_request'],
|
|
36
|
+
config: { url: webhookUrl, content_type: 'json', secret },
|
|
37
|
+
}),
|
|
38
|
+
});
|
|
39
|
+
if (!res.ok) {
|
|
40
|
+
const err = await res.json();
|
|
41
|
+
throw new Error(`Failed to register webhook: ${err.message ?? res.status}`);
|
|
42
|
+
}
|
|
43
|
+
const data = await res.json();
|
|
44
|
+
return data.id;
|
|
45
|
+
}
|
|
46
|
+
export async function deleteRepoWebhook(owner, repo, hookId, token) {
|
|
47
|
+
await fetch(`https://api.github.com/repos/${owner}/${repo}/hooks/${hookId}`, {
|
|
48
|
+
method: 'DELETE',
|
|
49
|
+
headers: { Authorization: `Bearer ${token}`, Accept: 'application/vnd.github+json' },
|
|
50
|
+
});
|
|
51
|
+
}
|
|
52
|
+
export async function registerOrgWebhook(org, webhookUrl, secret, token) {
|
|
53
|
+
const res = await fetch(`https://api.github.com/orgs/${org}/hooks`, {
|
|
54
|
+
method: 'POST',
|
|
55
|
+
headers: {
|
|
56
|
+
Authorization: `Bearer ${token}`,
|
|
57
|
+
Accept: 'application/vnd.github+json',
|
|
58
|
+
'Content-Type': 'application/json',
|
|
59
|
+
},
|
|
60
|
+
body: JSON.stringify({
|
|
61
|
+
name: 'web',
|
|
62
|
+
active: true,
|
|
63
|
+
events: ['pull_request'],
|
|
64
|
+
config: { url: webhookUrl, content_type: 'json', secret },
|
|
65
|
+
}),
|
|
66
|
+
});
|
|
67
|
+
if (!res.ok) {
|
|
68
|
+
const err = await res.json();
|
|
69
|
+
throw new Error(`Failed to register org webhook: ${err.message ?? res.status}`);
|
|
70
|
+
}
|
|
71
|
+
const data = await res.json();
|
|
72
|
+
return data.id;
|
|
73
|
+
}
|
|
74
|
+
export async function deleteOrgWebhook(org, hookId, token) {
|
|
75
|
+
await fetch(`https://api.github.com/orgs/${org}/hooks/${hookId}`, {
|
|
76
|
+
method: 'DELETE',
|
|
77
|
+
headers: { Authorization: `Bearer ${token}`, Accept: 'application/vnd.github+json' },
|
|
78
|
+
});
|
|
79
|
+
}
|
|
80
|
+
export async function postReviewComment(octokit, owner, repo, pullNumber, body, reviewer) {
|
|
81
|
+
const header = `### Code Review by ${reviewer === 'claude' ? '🤖 Claude Code' : '⚡ Codex'}\n\n`;
|
|
82
|
+
await octokit.rest.issues.createComment({
|
|
83
|
+
owner,
|
|
84
|
+
repo,
|
|
85
|
+
issue_number: pullNumber,
|
|
86
|
+
body: header + body,
|
|
87
|
+
});
|
|
88
|
+
}
|
|
89
|
+
//# sourceMappingURL=client.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"client.js","sourceRoot":"","sources":["../../src/github/client.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import type { Config } from '../config/schema.js';
|
|
2
|
+
export type PROrigin = 'claude' | 'codex' | 'human';
|
|
3
|
+
export declare function detectPROrigin(prBody: string, config: Config): PROrigin;
|
|
4
|
+
export declare function shouldReview(origin: PROrigin, config: Config): boolean;
|
|
5
|
+
export declare function assignReviewer(origin: PROrigin, config: Config): 'claude' | 'codex' | null;
|
|
6
|
+
//# sourceMappingURL=detector.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"detector.d.ts","sourceRoot":"","sources":["../../src/github/detector.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,qBAAqB,CAAA;AAEjD,MAAM,MAAM,QAAQ,GAAG,QAAQ,GAAG,OAAO,GAAG,OAAO,CAAA;AAEnD,wBAAgB,cAAc,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,QAAQ,CAYvE;AAED,wBAAgB,YAAY,CAAC,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CAKtE;AAED,wBAAgB,cAAc,CAAC,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,MAAM,GAAG,QAAQ,GAAG,OAAO,GAAG,IAAI,CAY1F"}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
export function detectPROrigin(prBody, config) {
|
|
2
|
+
const body = prBody ?? '';
|
|
3
|
+
for (const pattern of config.routing.codex_reviews_patterns) {
|
|
4
|
+
if (new RegExp(pattern, 'i').test(body))
|
|
5
|
+
return 'claude';
|
|
6
|
+
}
|
|
7
|
+
for (const pattern of config.routing.claude_reviews_patterns) {
|
|
8
|
+
if (new RegExp(pattern, 'i').test(body))
|
|
9
|
+
return 'codex';
|
|
10
|
+
}
|
|
11
|
+
return 'human';
|
|
12
|
+
}
|
|
13
|
+
export function shouldReview(origin, config) {
|
|
14
|
+
if (config.mode === 'single-vendor')
|
|
15
|
+
return true;
|
|
16
|
+
// cross-vendor: only review PRs from the other AI
|
|
17
|
+
return origin === 'claude' || origin === 'codex';
|
|
18
|
+
}
|
|
19
|
+
export function assignReviewer(origin, config) {
|
|
20
|
+
if (config.mode === 'single-vendor') {
|
|
21
|
+
// use whichever vendor is enabled
|
|
22
|
+
if (config.vendors.codex.enabled)
|
|
23
|
+
return 'codex';
|
|
24
|
+
if (config.vendors.claude.enabled)
|
|
25
|
+
return 'claude';
|
|
26
|
+
return null;
|
|
27
|
+
}
|
|
28
|
+
// cross-vendor: opposite vendor reviews
|
|
29
|
+
if (origin === 'claude' && config.vendors.codex.enabled)
|
|
30
|
+
return 'codex';
|
|
31
|
+
if (origin === 'codex' && config.vendors.claude.enabled)
|
|
32
|
+
return 'claude';
|
|
33
|
+
return null;
|
|
34
|
+
}
|
|
35
|
+
//# sourceMappingURL=detector.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"detector.js","sourceRoot":"","sources":["../../src/github/detector.ts"],"names":[],"mappings":"AAIA,MAAM,UAAU,cAAc,CAAC,MAAc,EAAE,MAAc;IAC3D,MAAM,IAAI,GAAG,MAAM,IAAI,EAAE,CAAA;IAEzB,KAAK,MAAM,OAAO,IAAI,MAAM,CAAC,OAAO,CAAC,sBAAsB,EAAE,CAAC;QAC5D,IAAI,IAAI,MAAM,CAAC,OAAO,EAAE,GAAG,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC;YAAE,OAAO,QAAQ,CAAA;IAC1D,CAAC;IAED,KAAK,MAAM,OAAO,IAAI,MAAM,CAAC,OAAO,CAAC,uBAAuB,EAAE,CAAC;QAC7D,IAAI,IAAI,MAAM,CAAC,OAAO,EAAE,GAAG,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC;YAAE,OAAO,OAAO,CAAA;IACzD,CAAC;IAED,OAAO,OAAO,CAAA;AAChB,CAAC;AAED,MAAM,UAAU,YAAY,CAAC,MAAgB,EAAE,MAAc;IAC3D,IAAI,MAAM,CAAC,IAAI,KAAK,eAAe;QAAE,OAAO,IAAI,CAAA;IAEhD,kDAAkD;IAClD,OAAO,MAAM,KAAK,QAAQ,IAAI,MAAM,KAAK,OAAO,CAAA;AAClD,CAAC;AAED,MAAM,UAAU,cAAc,CAAC,MAAgB,EAAE,MAAc;IAC7D,IAAI,MAAM,CAAC,IAAI,KAAK,eAAe,EAAE,CAAC;QACpC,kCAAkC;QAClC,IAAI,MAAM,CAAC,OAAO,CAAC,KAAK,CAAC,OAAO;YAAE,OAAO,OAAO,CAAA;QAChD,IAAI,MAAM,CAAC,OAAO,CAAC,MAAM,CAAC,OAAO;YAAE,OAAO,QAAQ,CAAA;QAClD,OAAO,IAAI,CAAA;IACb,CAAC;IAED,wCAAwC;IACxC,IAAI,MAAM,KAAK,QAAQ,IAAI,MAAM,CAAC,OAAO,CAAC,KAAK,CAAC,OAAO;QAAE,OAAO,OAAO,CAAA;IACvE,IAAI,MAAM,KAAK,OAAO,IAAI,MAAM,CAAC,OAAO,CAAC,MAAM,CAAC,OAAO;QAAE,OAAO,QAAQ,CAAA;IACxE,OAAO,IAAI,CAAA;AACb,CAAC"}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { type IncomingMessage, type ServerResponse } from 'http';
|
|
2
|
+
import type { Config } from '../config/schema.js';
|
|
3
|
+
export interface PREvent {
|
|
4
|
+
action: string;
|
|
5
|
+
number: number;
|
|
6
|
+
pull_request: {
|
|
7
|
+
title: string;
|
|
8
|
+
body: string;
|
|
9
|
+
head: {
|
|
10
|
+
ref: string;
|
|
11
|
+
sha: string;
|
|
12
|
+
};
|
|
13
|
+
base: {
|
|
14
|
+
ref: string;
|
|
15
|
+
};
|
|
16
|
+
html_url: string;
|
|
17
|
+
};
|
|
18
|
+
repository: {
|
|
19
|
+
name: string;
|
|
20
|
+
owner: {
|
|
21
|
+
login: string;
|
|
22
|
+
};
|
|
23
|
+
clone_url: string;
|
|
24
|
+
};
|
|
25
|
+
}
|
|
26
|
+
export declare function createWebhookServer(config: Config, webhookSecret: string, onPR: (event: PREvent) => void, onLog: (msg: string) => void): import("http").Server<typeof IncomingMessage, typeof ServerResponse>;
|
|
27
|
+
//# sourceMappingURL=webhook.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"webhook.d.ts","sourceRoot":"","sources":["../../src/github/webhook.ts"],"names":[],"mappings":"AAAA,OAAO,EAAgB,KAAK,eAAe,EAAE,KAAK,cAAc,EAAE,MAAM,MAAM,CAAA;AAC9E,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,qBAAqB,CAAA;AAGjD,MAAM,WAAW,OAAO;IACtB,MAAM,EAAE,MAAM,CAAA;IACd,MAAM,EAAE,MAAM,CAAA;IACd,YAAY,EAAE;QACZ,KAAK,EAAE,MAAM,CAAA;QACb,IAAI,EAAE,MAAM,CAAA;QACZ,IAAI,EAAE;YAAE,GAAG,EAAE,MAAM,CAAC;YAAC,GAAG,EAAE,MAAM,CAAA;SAAE,CAAA;QAClC,IAAI,EAAE;YAAE,GAAG,EAAE,MAAM,CAAA;SAAE,CAAA;QACrB,QAAQ,EAAE,MAAM,CAAA;KACjB,CAAA;IACD,UAAU,EAAE;QACV,IAAI,EAAE,MAAM,CAAA;QACZ,KAAK,EAAE;YAAE,KAAK,EAAE,MAAM,CAAA;SAAE,CAAA;QACxB,SAAS,EAAE,MAAM,CAAA;KAClB,CAAA;CACF;AAED,wBAAgB,mBAAmB,CACjC,MAAM,EAAE,MAAM,EACd,aAAa,EAAE,MAAM,EACrB,IAAI,EAAE,CAAC,KAAK,EAAE,OAAO,KAAK,IAAI,EAC9B,KAAK,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,IAAI,wEAkD7B"}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import { createServer } from 'http';
|
|
2
|
+
import { verifyWebhookSignature } from './client.js';
|
|
3
|
+
export function createWebhookServer(config, webhookSecret, onPR, onLog) {
|
|
4
|
+
const server = createServer(async (req, res) => {
|
|
5
|
+
const { pathname } = new URL(req.url ?? '/', `http://localhost`);
|
|
6
|
+
if (pathname !== config.server.webhook_path) {
|
|
7
|
+
res.writeHead(404).end();
|
|
8
|
+
return;
|
|
9
|
+
}
|
|
10
|
+
if (req.method !== 'POST') {
|
|
11
|
+
res.writeHead(405).end();
|
|
12
|
+
return;
|
|
13
|
+
}
|
|
14
|
+
const chunks = [];
|
|
15
|
+
for await (const chunk of req)
|
|
16
|
+
chunks.push(chunk);
|
|
17
|
+
const rawBody = Buffer.concat(chunks).toString('utf8');
|
|
18
|
+
const signature = req.headers['x-hub-signature-256'] ?? '';
|
|
19
|
+
if (!verifyWebhookSignature(rawBody, signature, webhookSecret)) {
|
|
20
|
+
onLog('⚠ Rejected request with invalid webhook signature');
|
|
21
|
+
res.writeHead(401).end();
|
|
22
|
+
return;
|
|
23
|
+
}
|
|
24
|
+
const event = req.headers['x-github-event'];
|
|
25
|
+
if (event !== 'pull_request') {
|
|
26
|
+
res.writeHead(200).end('ok');
|
|
27
|
+
return;
|
|
28
|
+
}
|
|
29
|
+
let body;
|
|
30
|
+
try {
|
|
31
|
+
body = JSON.parse(rawBody);
|
|
32
|
+
}
|
|
33
|
+
catch {
|
|
34
|
+
res.writeHead(400).end();
|
|
35
|
+
return;
|
|
36
|
+
}
|
|
37
|
+
if (body.action === 'opened' || body.action === 'synchronize') {
|
|
38
|
+
res.writeHead(200).end('ok');
|
|
39
|
+
// async — don't block the webhook response
|
|
40
|
+
setImmediate(() => onPR(body));
|
|
41
|
+
}
|
|
42
|
+
else {
|
|
43
|
+
res.writeHead(200).end('ok');
|
|
44
|
+
}
|
|
45
|
+
});
|
|
46
|
+
return server;
|
|
47
|
+
}
|
|
48
|
+
//# sourceMappingURL=webhook.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"webhook.js","sourceRoot":"","sources":["../../src/github/webhook.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAA6C,MAAM,MAAM,CAAA;AAE9E,OAAO,EAAE,sBAAsB,EAAE,MAAM,aAAa,CAAA;AAmBpD,MAAM,UAAU,mBAAmB,CACjC,MAAc,EACd,aAAqB,EACrB,IAA8B,EAC9B,KAA4B;IAE5B,MAAM,MAAM,GAAG,YAAY,CAAC,KAAK,EAAE,GAAoB,EAAE,GAAmB,EAAE,EAAE;QAC9E,MAAM,EAAE,QAAQ,EAAE,GAAG,IAAI,GAAG,CAAC,GAAG,CAAC,GAAG,IAAI,GAAG,EAAE,kBAAkB,CAAC,CAAA;QAEhE,IAAI,QAAQ,KAAK,MAAM,CAAC,MAAM,CAAC,YAAY,EAAE,CAAC;YAC5C,GAAG,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,CAAA;YACxB,OAAM;QACR,CAAC;QAED,IAAI,GAAG,CAAC,MAAM,KAAK,MAAM,EAAE,CAAC;YAC1B,GAAG,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,CAAA;YACxB,OAAM;QACR,CAAC;QAED,MAAM,MAAM,GAAa,EAAE,CAAA;QAC3B,IAAI,KAAK,EAAE,MAAM,KAAK,IAAI,GAAG;YAAE,MAAM,CAAC,IAAI,CAAC,KAAe,CAAC,CAAA;QAC3D,MAAM,OAAO,GAAG,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAA;QAEtD,MAAM,SAAS,GAAG,GAAG,CAAC,OAAO,CAAC,qBAAqB,CAAW,IAAI,EAAE,CAAA;QACpE,IAAI,CAAC,sBAAsB,CAAC,OAAO,EAAE,SAAS,EAAE,aAAa,CAAC,EAAE,CAAC;YAC/D,KAAK,CAAC,oDAAoD,CAAC,CAAA;YAC3D,GAAG,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,CAAA;YACxB,OAAM;QACR,CAAC;QAED,MAAM,KAAK,GAAG,GAAG,CAAC,OAAO,CAAC,gBAAgB,CAAW,CAAA;QACrD,IAAI,KAAK,KAAK,cAAc,EAAE,CAAC;YAC7B,GAAG,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,IAAI,CAAC,CAAA;YAC5B,OAAM;QACR,CAAC;QAED,IAAI,IAAa,CAAA;QACjB,IAAI,CAAC;YACH,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,OAAO,CAAY,CAAA;QACvC,CAAC;QAAC,MAAM,CAAC;YACP,GAAG,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,CAAA;YACxB,OAAM;QACR,CAAC;QAED,IAAI,IAAI,CAAC,MAAM,KAAK,QAAQ,IAAI,IAAI,CAAC,MAAM,KAAK,aAAa,EAAE,CAAC;YAC9D,GAAG,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,IAAI,CAAC,CAAA;YAC5B,2CAA2C;YAC3C,YAAY,CAAC,GAAG,EAAE,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAA;QAChC,CAAC;aAAM,CAAC;YACN,GAAG,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,IAAI,CAAC,CAAA;QAC9B,CAAC;IACH,CAAC,CAAC,CAAA;IAEF,OAAO,MAAM,CAAA;AACf,CAAC"}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import type { QualityConfig, VendorConfig } from '../config/schema.js';
|
|
2
|
+
export declare function runClaudeReview(repoDir: string, baseBranch: string, prTitle: string, quality: QualityConfig, vendor: VendorConfig, perReviewBudget: number, onLog?: (msg: string) => void): Promise<string>;
|
|
3
|
+
export declare function checkClaudeAuth(): Promise<{
|
|
4
|
+
ok: boolean;
|
|
5
|
+
detail: string;
|
|
6
|
+
}>;
|
|
7
|
+
//# sourceMappingURL=claude.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"claude.d.ts","sourceRoot":"","sources":["../../src/reviewers/claude.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,aAAa,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAA;AAetE,wBAAsB,eAAe,CACnC,OAAO,EAAE,MAAM,EACf,UAAU,EAAE,MAAM,EAClB,OAAO,EAAE,MAAM,EACf,OAAO,EAAE,aAAa,EACtB,MAAM,EAAE,YAAY,EACpB,eAAe,EAAE,MAAM,EACvB,KAAK,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,IAAI,GAC5B,OAAO,CAAC,MAAM,CAAC,CA2CjB;AAED,wBAAsB,eAAe,IAAI,OAAO,CAAC;IAAE,EAAE,EAAE,OAAO,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,CAAC,CAQhF"}
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
import { execa } from 'execa';
|
|
2
|
+
import { readFileSync, mkdtempSync } from 'fs';
|
|
3
|
+
import { tmpdir } from 'os';
|
|
4
|
+
import { join } from 'path';
|
|
5
|
+
const TIER_MODELS = {
|
|
6
|
+
fast: 'claude-haiku-4-5-20251001',
|
|
7
|
+
balanced: 'claude-sonnet-4-6',
|
|
8
|
+
thorough: 'claude-opus-4-7',
|
|
9
|
+
};
|
|
10
|
+
const EFFORT_MAP = {
|
|
11
|
+
low: 'low',
|
|
12
|
+
medium: 'medium',
|
|
13
|
+
high: 'high',
|
|
14
|
+
max: 'max',
|
|
15
|
+
};
|
|
16
|
+
export async function runClaudeReview(repoDir, baseBranch, prTitle, quality, vendor, perReviewBudget, onLog) {
|
|
17
|
+
const model = TIER_MODELS[quality.tier] ?? 'claude-sonnet-4-6';
|
|
18
|
+
const effort = EFFORT_MAP[vendor.effort] ?? 'medium';
|
|
19
|
+
const focusLine = quality.focus.length > 0
|
|
20
|
+
? `Focus areas: ${quality.focus.join(', ')}.`
|
|
21
|
+
: '';
|
|
22
|
+
const customLine = quality.custom_prompt ?? '';
|
|
23
|
+
const prompt = [
|
|
24
|
+
`You are reviewing a pull request titled: "${prTitle}".`,
|
|
25
|
+
`The branch \`${baseBranch}\` is the base. Review only the changes introduced in this PR.`,
|
|
26
|
+
focusLine,
|
|
27
|
+
customLine,
|
|
28
|
+
'Structure your output as: ## Summary, ## Critical Issues, ## Warnings, ## Suggestions.',
|
|
29
|
+
'Be concise. Skip praise.',
|
|
30
|
+
].filter(Boolean).join('\n');
|
|
31
|
+
const outputFile = join(mkdtempSync(join(tmpdir(), 'crosscheck-')), 'review.md');
|
|
32
|
+
const args = [
|
|
33
|
+
'--print',
|
|
34
|
+
'--bare',
|
|
35
|
+
'--model', model,
|
|
36
|
+
'--effort', effort,
|
|
37
|
+
'--max-budget-usd', String(perReviewBudget),
|
|
38
|
+
'--output-last-message', outputFile,
|
|
39
|
+
'--allowedTools', 'Bash(git diff),Bash(git log)',
|
|
40
|
+
prompt,
|
|
41
|
+
];
|
|
42
|
+
onLog?.(` running: claude --print --model ${model} --effort ${effort}`);
|
|
43
|
+
try {
|
|
44
|
+
await execa('claude', args, {
|
|
45
|
+
cwd: repoDir,
|
|
46
|
+
timeout: 180_000,
|
|
47
|
+
env: { ...process.env },
|
|
48
|
+
});
|
|
49
|
+
return readFileSync(outputFile, 'utf8').trim();
|
|
50
|
+
}
|
|
51
|
+
catch (err) {
|
|
52
|
+
const error = err;
|
|
53
|
+
throw new Error(`claude review failed: ${error.stderr ?? error.message ?? 'unknown error'}`);
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
export async function checkClaudeAuth() {
|
|
57
|
+
try {
|
|
58
|
+
const { stdout } = await execa('claude', ['--version'], { timeout: 10_000 });
|
|
59
|
+
return { ok: true, detail: stdout.trim() };
|
|
60
|
+
}
|
|
61
|
+
catch (err) {
|
|
62
|
+
const error = err;
|
|
63
|
+
return { ok: false, detail: error.stderr ?? error.message ?? 'not found' };
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
//# sourceMappingURL=claude.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"claude.js","sourceRoot":"","sources":["../../src/reviewers/claude.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import type { QualityConfig } from '../config/schema.js';
|
|
2
|
+
export declare function runCodexReview(repoDir: string, baseBranch: string, prTitle: string, quality: QualityConfig, overrideModel?: string, authMode?: 'subscription' | 'api-key', onLog?: (msg: string) => void): Promise<string>;
|
|
3
|
+
export declare function checkCodexAuth(): Promise<{
|
|
4
|
+
ok: boolean;
|
|
5
|
+
detail: string;
|
|
6
|
+
}>;
|
|
7
|
+
//# sourceMappingURL=codex.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"codex.d.ts","sourceRoot":"","sources":["../../src/reviewers/codex.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAA;AASxD,wBAAsB,cAAc,CAClC,OAAO,EAAE,MAAM,EACf,UAAU,EAAE,MAAM,EAClB,OAAO,EAAE,MAAM,EACf,OAAO,EAAE,aAAa,EACtB,aAAa,CAAC,EAAE,MAAM,EACtB,QAAQ,GAAE,cAAc,GAAG,SAA0B,EACrD,KAAK,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,IAAI,GAC5B,OAAO,CAAC,MAAM,CAAC,CAwCjB;AAED,wBAAsB,cAAc,IAAI,OAAO,CAAC;IAAE,EAAE,EAAE,OAAO,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,CAAC,CAQ/E"}
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import { execa } from 'execa';
|
|
2
|
+
import { mkdtempSync, mkdirSync, writeFileSync, rmSync } from 'fs';
|
|
3
|
+
import { tmpdir } from 'os';
|
|
4
|
+
import { join } from 'path';
|
|
5
|
+
// Models for API-key auth. When using ChatGPT subscription auth, omit model override.
|
|
6
|
+
const TIER_MODELS_API = {
|
|
7
|
+
fast: 'gpt-4o-mini',
|
|
8
|
+
balanced: 'o4-mini',
|
|
9
|
+
thorough: 'o3',
|
|
10
|
+
};
|
|
11
|
+
export async function runCodexReview(repoDir, baseBranch, prTitle, quality, overrideModel, authMode = 'subscription', onLog) {
|
|
12
|
+
// subscription auth has a fixed model set by ChatGPT plan; only override for api-key
|
|
13
|
+
const model = authMode === 'api-key'
|
|
14
|
+
? (overrideModel ?? TIER_MODELS_API[quality.tier] ?? 'o4-mini')
|
|
15
|
+
: undefined;
|
|
16
|
+
const tmpFile = join(mkdtempSync(join(tmpdir(), 'crosscheck-')), 'review.md');
|
|
17
|
+
// --base and [PROMPT] are mutually exclusive in codex review;
|
|
18
|
+
// inject focus instructions via a .codex/instructions file instead
|
|
19
|
+
const focusNote = quality.focus.length > 0
|
|
20
|
+
? `Focus areas: ${quality.focus.join(', ')}. `
|
|
21
|
+
: '';
|
|
22
|
+
const customNote = quality.custom_prompt ?? '';
|
|
23
|
+
const instructionsNote = [focusNote, customNote].filter(Boolean).join('');
|
|
24
|
+
if (instructionsNote) {
|
|
25
|
+
mkdirSync(`${repoDir}/.codex`, { recursive: true });
|
|
26
|
+
writeFileSync(`${repoDir}/.codex/instructions`, instructionsNote);
|
|
27
|
+
}
|
|
28
|
+
try {
|
|
29
|
+
const modelArgs = model ? ['-c', `model="${model}"`] : [];
|
|
30
|
+
onLog?.(` running: codex review --base ${baseBranch}${model ? ` -c model="${model}"` : ''}`);
|
|
31
|
+
const result = await execa('codex', ['review', '--base', baseBranch, '--title', prTitle, ...modelArgs], {
|
|
32
|
+
cwd: repoDir,
|
|
33
|
+
timeout: 120_000,
|
|
34
|
+
env: { ...process.env },
|
|
35
|
+
});
|
|
36
|
+
return result.stdout.trim() || result.stderr.trim();
|
|
37
|
+
}
|
|
38
|
+
catch (err) {
|
|
39
|
+
const error = err;
|
|
40
|
+
throw new Error(`codex review failed: ${error.stderr ?? error.message ?? 'unknown error'}`);
|
|
41
|
+
}
|
|
42
|
+
finally {
|
|
43
|
+
try {
|
|
44
|
+
rmSync(tmpFile, { force: true, recursive: true });
|
|
45
|
+
}
|
|
46
|
+
catch { /* ignore */ }
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
export async function checkCodexAuth() {
|
|
50
|
+
try {
|
|
51
|
+
const { stdout } = await execa('codex', ['login', 'status'], { timeout: 10_000 });
|
|
52
|
+
return { ok: true, detail: stdout.trim() };
|
|
53
|
+
}
|
|
54
|
+
catch (err) {
|
|
55
|
+
const error = err;
|
|
56
|
+
return { ok: false, detail: error.stderr ?? error.message ?? 'not authenticated' };
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
//# sourceMappingURL=codex.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"codex.js","sourceRoot":"","sources":["../../src/reviewers/codex.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,MAAM,OAAO,CAAA;AAC7B,OAAO,EAAE,WAAW,EAAE,SAAS,EAAE,aAAa,EAAE,MAAM,EAAE,MAAM,IAAI,CAAA;AAClE,OAAO,EAAE,MAAM,EAAE,MAAM,IAAI,CAAA;AAC3B,OAAO,EAAE,IAAI,EAAE,MAAM,MAAM,CAAA;AAG3B,sFAAsF;AACtF,MAAM,eAAe,GAA2B;IAC9C,IAAI,EAAE,aAAa;IACnB,QAAQ,EAAE,SAAS;IACnB,QAAQ,EAAE,IAAI;CACf,CAAA;AAED,MAAM,CAAC,KAAK,UAAU,cAAc,CAClC,OAAe,EACf,UAAkB,EAClB,OAAe,EACf,OAAsB,EACtB,aAAsB,EACtB,WAAuC,cAAc,EACrD,KAA6B;IAE7B,qFAAqF;IACrF,MAAM,KAAK,GAAG,QAAQ,KAAK,SAAS;QAClC,CAAC,CAAC,CAAC,aAAa,IAAI,eAAe,CAAC,OAAO,CAAC,IAAI,CAAC,IAAI,SAAS,CAAC;QAC/D,CAAC,CAAC,SAAS,CAAA;IACb,MAAM,OAAO,GAAG,IAAI,CAAC,WAAW,CAAC,IAAI,CAAC,MAAM,EAAE,EAAE,aAAa,CAAC,CAAC,EAAE,WAAW,CAAC,CAAA;IAE7E,8DAA8D;IAC9D,mEAAmE;IACnE,MAAM,SAAS,GAAG,OAAO,CAAC,KAAK,CAAC,MAAM,GAAG,CAAC;QACxC,CAAC,CAAC,gBAAgB,OAAO,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI;QAC9C,CAAC,CAAC,EAAE,CAAA;IACN,MAAM,UAAU,GAAG,OAAO,CAAC,aAAa,IAAI,EAAE,CAAA;IAC9C,MAAM,gBAAgB,GAAG,CAAC,SAAS,EAAE,UAAU,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,CAAA;IACzE,IAAI,gBAAgB,EAAE,CAAC;QACrB,SAAS,CAAC,GAAG,OAAO,SAAS,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAA;QACnD,aAAa,CAAC,GAAG,OAAO,sBAAsB,EAAE,gBAAgB,CAAC,CAAA;IACnE,CAAC;IAED,IAAI,CAAC;QACH,MAAM,SAAS,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,UAAU,KAAK,GAAG,CAAC,CAAC,CAAC,CAAC,EAAE,CAAA;QACzD,KAAK,EAAE,CAAC,kCAAkC,UAAU,GAAG,KAAK,CAAC,CAAC,CAAC,cAAc,KAAK,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAA;QAE7F,MAAM,MAAM,GAAG,MAAM,KAAK,CACxB,OAAO,EACP,CAAC,QAAQ,EAAE,QAAQ,EAAE,UAAU,EAAE,SAAS,EAAE,OAAO,EAAE,GAAG,SAAS,CAAC,EAClE;YACE,GAAG,EAAE,OAAO;YACZ,OAAO,EAAE,OAAO;YAChB,GAAG,EAAE,EAAE,GAAG,OAAO,CAAC,GAAG,EAAE;SACxB,CACF,CAAA;QAED,OAAO,MAAM,CAAC,MAAM,CAAC,IAAI,EAAE,IAAI,MAAM,CAAC,MAAM,CAAC,IAAI,EAAE,CAAA;IACrD,CAAC;IAAC,OAAO,GAAY,EAAE,CAAC;QACtB,MAAM,KAAK,GAAG,GAA6D,CAAA;QAC3E,MAAM,IAAI,KAAK,CAAC,wBAAwB,KAAK,CAAC,MAAM,IAAI,KAAK,CAAC,OAAO,IAAI,eAAe,EAAE,CAAC,CAAA;IAC7F,CAAC;YAAS,CAAC;QACT,IAAI,CAAC;YAAC,MAAM,CAAC,OAAO,EAAE,EAAE,KAAK,EAAE,IAAI,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAA;QAAC,CAAC;QAAC,MAAM,CAAC,CAAC,YAAY,CAAC,CAAC;IAClF,CAAC;AACH,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,cAAc;IAClC,IAAI,CAAC;QACH,MAAM,EAAE,MAAM,EAAE,GAAG,MAAM,KAAK,CAAC,OAAO,EAAE,CAAC,OAAO,EAAE,QAAQ,CAAC,EAAE,EAAE,OAAO,EAAE,MAAM,EAAE,CAAC,CAAA;QACjF,OAAO,EAAE,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,MAAM,CAAC,IAAI,EAAE,EAAE,CAAA;IAC5C,CAAC;IAAC,OAAO,GAAY,EAAE,CAAC;QACtB,MAAM,KAAK,GAAG,GAA4C,CAAA;QAC1D,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,KAAK,CAAC,MAAM,IAAI,KAAK,CAAC,OAAO,IAAI,mBAAmB,EAAE,CAAA;IACpF,CAAC;AACH,CAAC"}
|
package/package.json
ADDED
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@motivation-labs/crosscheck",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Cross-vendor AI code review orchestrator — Claude Code ↔ Codex",
|
|
5
|
+
"bin": {
|
|
6
|
+
"crosscheck": "dist/cli.js"
|
|
7
|
+
},
|
|
8
|
+
"type": "module",
|
|
9
|
+
"files": [
|
|
10
|
+
"dist",
|
|
11
|
+
"crosscheck.config.example.yml",
|
|
12
|
+
"README.md"
|
|
13
|
+
],
|
|
14
|
+
"engines": {
|
|
15
|
+
"node": ">=18"
|
|
16
|
+
},
|
|
17
|
+
"scripts": {
|
|
18
|
+
"build": "tsc && chmod +x dist/cli.js",
|
|
19
|
+
"dev": "tsx src/cli.ts",
|
|
20
|
+
"typecheck": "tsc --noEmit",
|
|
21
|
+
"lint": "eslint src --ext .ts",
|
|
22
|
+
"prepublishOnly": "npm run typecheck && npm run build"
|
|
23
|
+
},
|
|
24
|
+
"dependencies": {
|
|
25
|
+
"chalk": "^5.3.0",
|
|
26
|
+
"commander": "^12.1.0",
|
|
27
|
+
"execa": "^9.3.0",
|
|
28
|
+
"js-yaml": "^4.1.0",
|
|
29
|
+
"octokit": "^4.0.2",
|
|
30
|
+
"ora": "^8.1.0",
|
|
31
|
+
"zod": "^3.23.8",
|
|
32
|
+
"smee-client": "^2.0.2"
|
|
33
|
+
},
|
|
34
|
+
"devDependencies": {
|
|
35
|
+
"@types/js-yaml": "^4.0.9",
|
|
36
|
+
"@types/node": "^22.0.0",
|
|
37
|
+
"tsx": "^4.16.0",
|
|
38
|
+
"typescript": "^5.5.0"
|
|
39
|
+
},
|
|
40
|
+
"keywords": [
|
|
41
|
+
"code-review",
|
|
42
|
+
"ai",
|
|
43
|
+
"claude",
|
|
44
|
+
"codex",
|
|
45
|
+
"github",
|
|
46
|
+
"pull-request",
|
|
47
|
+
"automation",
|
|
48
|
+
"cli"
|
|
49
|
+
],
|
|
50
|
+
"homepage": "https://github.com/Motivation-Labs/crosscheck",
|
|
51
|
+
"repository": {
|
|
52
|
+
"type": "git",
|
|
53
|
+
"url": "git+https://github.com/Motivation-Labs/crosscheck.git"
|
|
54
|
+
},
|
|
55
|
+
"bugs": {
|
|
56
|
+
"url": "https://github.com/Motivation-Labs/crosscheck/issues"
|
|
57
|
+
},
|
|
58
|
+
"author": "Motivation Labs",
|
|
59
|
+
"license": "MIT"
|
|
60
|
+
}
|