revu-ai 0.1.2 → 0.2.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/CHANGELOG.md +39 -0
- package/README.md +75 -12
- package/dist/cache/cross-reference.d.ts +37 -0
- package/dist/cache/cross-reference.js +94 -0
- package/dist/cache/cross-reference.js.map +1 -0
- package/dist/cli.js +106 -12
- package/dist/cli.js.map +1 -1
- package/dist/config.d.ts +3 -1
- package/dist/config.js +9 -10
- package/dist/config.js.map +1 -1
- package/dist/discovery.js +8 -1
- package/dist/discovery.js.map +1 -1
- package/dist/findings.d.ts +18 -0
- package/dist/findings.js +22 -0
- package/dist/findings.js.map +1 -0
- package/dist/forges/dedup.d.ts +17 -0
- package/dist/forges/dedup.js +42 -0
- package/dist/forges/dedup.js.map +1 -0
- package/dist/forges/diff-lines.d.ts +12 -0
- package/dist/forges/diff-lines.js +93 -0
- package/dist/forges/diff-lines.js.map +1 -0
- package/dist/forges/github/api.d.ts +70 -0
- package/dist/forges/github/api.js +102 -0
- package/dist/forges/github/api.js.map +1 -0
- package/dist/forges/github/index.d.ts +10 -0
- package/dist/forges/github/index.js +292 -0
- package/dist/forges/github/index.js.map +1 -0
- package/dist/forges/gitlab/index.d.ts +7 -0
- package/dist/forges/gitlab/index.js +13 -0
- package/dist/forges/gitlab/index.js.map +1 -0
- package/dist/forges/post-cmd.d.ts +20 -0
- package/dist/forges/post-cmd.js +54 -0
- package/dist/forges/post-cmd.js.map +1 -0
- package/dist/forges/registry.d.ts +5 -0
- package/dist/forges/registry.js +24 -0
- package/dist/forges/registry.js.map +1 -0
- package/dist/forges/render.d.ts +18 -0
- package/dist/forges/render.js +59 -0
- package/dist/forges/render.js.map +1 -0
- package/dist/forges/types.d.ts +65 -0
- package/dist/forges/types.js +2 -0
- package/dist/forges/types.js.map +1 -0
- package/dist/index.d.ts +2 -2
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/dist/init.d.ts +3 -1
- package/dist/init.js +6 -3
- package/dist/init.js.map +1 -1
- package/dist/mcp/aggregator.d.ts +9 -1
- package/dist/mcp/aggregator.js +39 -3
- package/dist/mcp/aggregator.js.map +1 -1
- package/dist/mcp/server.d.ts +8 -0
- package/dist/mcp/server.js +60 -5
- package/dist/mcp/server.js.map +1 -1
- package/dist/mcp/tools.d.ts +38 -2
- package/dist/mcp/tools.js +36 -1
- package/dist/mcp/tools.js.map +1 -1
- package/dist/output/github.d.ts +1 -1
- package/dist/output/github.js +3 -7
- package/dist/output/github.js.map +1 -1
- package/dist/output/json.d.ts +3 -1
- package/dist/output/json.js +4 -7
- package/dist/output/json.js.map +1 -1
- package/dist/output/pretty.d.ts +1 -1
- package/dist/output/pretty.js +2 -8
- package/dist/output/pretty.js.map +1 -1
- package/dist/prompts/review-system.d.ts +3 -1
- package/dist/prompts/review-system.js +47 -2
- package/dist/prompts/review-system.js.map +1 -1
- package/dist/providers/claude-code.d.ts +7 -5
- package/dist/providers/claude-code.js +77 -15
- package/dist/providers/claude-code.js.map +1 -1
- package/dist/providers/opencode.d.ts +6 -0
- package/dist/providers/opencode.js +653 -0
- package/dist/providers/opencode.js.map +1 -0
- package/dist/providers/registry.d.ts +7 -7
- package/dist/providers/registry.js +29 -21
- package/dist/providers/registry.js.map +1 -1
- package/dist/providers/types.d.ts +8 -1
- package/dist/runner.d.ts +6 -1
- package/dist/runner.js +71 -26
- package/dist/runner.js.map +1 -1
- package/dist/scaffold-paths.d.ts +10 -0
- package/dist/scaffold-paths.js +25 -0
- package/dist/scaffold-paths.js.map +1 -0
- package/dist/types.d.ts +38 -3
- package/dist/types.js +4 -7
- package/dist/types.js.map +1 -1
- package/examples/github-workflow.yml +51 -10
- package/package.json +16 -10
package/dist/config.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"config.js","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AACnD,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;
|
|
1
|
+
{"version":3,"file":"config.js","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"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"}
|
package/dist/discovery.js
CHANGED
|
@@ -63,7 +63,14 @@ function listFromGit(repoRoot, pattern) {
|
|
|
63
63
|
`:(glob)${pattern}`,
|
|
64
64
|
...GIT_EXCLUDE_PATHSPECS,
|
|
65
65
|
], { cwd: repoRoot, encoding: "utf8", maxBuffer: 256 * 1024 * 1024 });
|
|
66
|
-
|
|
66
|
+
// `git ls-files -c` lists tracked-but-deleted-from-working-tree paths
|
|
67
|
+
// (rule file deleted locally without committing the deletion). Skip those —
|
|
68
|
+
// discovery's contract is "give me rule files I can read right now."
|
|
69
|
+
return out
|
|
70
|
+
.split("\0")
|
|
71
|
+
.filter(Boolean)
|
|
72
|
+
.filter((rel) => existsSync(resolve(repoRoot, rel)))
|
|
73
|
+
.sort();
|
|
67
74
|
}
|
|
68
75
|
async function listFromFs(repoRoot, pattern) {
|
|
69
76
|
const ig = ignore();
|
package/dist/discovery.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"discovery.js","sourceRoot":"","sources":["../src/discovery.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAClD,OAAO,EAAE,YAAY,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AACnD,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,GAAG,EAAE,MAAM,WAAW,CAAC;AAC/C,OAAO,EAAE,MAAM,WAAW,CAAC;AAC3B,OAAO,YAAY,MAAM,QAAQ,CAAC;AAGlC,yFAAyF;AACzF,MAAM,MAAM,GAAI,YAA6D,CAAC,OAAO,IAAI,YAAY,CAAC;AAEtG,kFAAkF;AAClF,sEAAsE;AACtE,MAAM,mBAAmB,GAAG,CAAC,cAAc,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,CAAC,CAAC;AAEtE,wFAAwF;AACxF,wFAAwF;AACxF,sEAAsE;AACtE,MAAM,gBAAgB,GAAG,mBAAmB,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC;AAEnE,mFAAmF;AACnF,uFAAuF;AACvF,mEAAmE;AACnE,MAAM,qBAAqB,GAAG,mBAAmB,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,qBAAqB,CAAC,KAAK,CAAC,CAAC;AAE1F,MAAM,CAAC,KAAK,UAAU,aAAa,CAAC,QAAgB,EAAE,OAAe;IACnE,MAAM,OAAO,GAAG,SAAS,CAAC,QAAQ,CAAC;QACjC,CAAC,CAAC,WAAW,CAAC,QAAQ,EAAE,OAAO,CAAC;QAChC,CAAC,CAAC,MAAM,UAAU,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAC;IAExC,OAAO,OAAO,CAAC,GAAG,CAAC,CAAC,GAAG,EAAY,EAAE;QACnC,MAAM,GAAG,GAAG,OAAO,CAAC,QAAQ,EAAE,GAAG,CAAC,CAAC;QACnC,OAAO;YACL,MAAM,EAAE,YAAY,CAAC,GAAG,CAAC;YACzB,OAAO,EAAE,GAAG;YACZ,OAAO,EAAE,GAAG;YACZ,OAAO,EAAE,YAAY,CAAC,GAAG,EAAE,MAAM,CAAC;SACnC,CAAC;IACJ,CAAC,CAAC,CAAC;AACL,CAAC;AAED,SAAS,SAAS,CAAC,QAAgB;IACjC,IAAI,CAAC;QACH,YAAY,CAAC,KAAK,EAAE,CAAC,WAAW,EAAE,WAAW,CAAC,EAAE;YAC9C,GAAG,EAAE,QAAQ;YACb,KAAK,EAAE,CAAC,QAAQ,EAAE,QAAQ,EAAE,QAAQ,CAAC;SACtC,CAAC,CAAC;QACH,OAAO,IAAI,CAAC;IACd,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,KAAK,CAAC;IACf,CAAC;AACH,CAAC;AAED,gFAAgF;AAChF,mFAAmF;AACnF,iFAAiF;AACjF,kFAAkF;AAClF,8DAA8D;AAC9D,EAAE;AACF,8CAA8C;AAC9C,4DAA4D;AAC5D,+EAA+E;AAC/E,kFAAkF;AAClF,oEAAoE;AACpE,SAAS,WAAW,CAAC,QAAgB,EAAE,OAAe;IACpD,MAAM,GAAG,GAAG,YAAY,CACtB,KAAK,EACL;QACE,UAAU;QACV,KAAK;QACL,oBAAoB;QACpB,IAAI;QACJ,IAAI;QACJ,UAAU,OAAO,EAAE;QACnB,GAAG,qBAAqB;KACzB,EACD,EAAE,GAAG,EAAE,QAAQ,EAAE,QAAQ,EAAE,MAAM,EAAE,SAAS,EAAE,GAAG,GAAG,IAAI,GAAG,IAAI,EAAE,CAClE,CAAC;IACF,OAAO,GAAG,
|
|
1
|
+
{"version":3,"file":"discovery.js","sourceRoot":"","sources":["../src/discovery.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import type { Finding } from "./types.js";
|
|
2
|
+
/**
|
|
3
|
+
* Stable 12-char hash that identifies a finding across runs.
|
|
4
|
+
* Computed from (ruleId, path, line, message) so that the same logical
|
|
5
|
+
* issue at the same logical place always hashes to the same value.
|
|
6
|
+
*/
|
|
7
|
+
export declare function computeFingerprint(input: {
|
|
8
|
+
ruleId: string;
|
|
9
|
+
path: string;
|
|
10
|
+
line?: number;
|
|
11
|
+
message: string;
|
|
12
|
+
}): string;
|
|
13
|
+
/** Return a Finding with its `fingerprint` populated, computing it if missing. */
|
|
14
|
+
export declare function ensureFingerprint<T extends Omit<Finding, "fingerprint"> & {
|
|
15
|
+
fingerprint?: string;
|
|
16
|
+
}>(f: T): T & {
|
|
17
|
+
fingerprint: string;
|
|
18
|
+
};
|
package/dist/findings.js
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { createHash } from "node:crypto";
|
|
2
|
+
/**
|
|
3
|
+
* Stable 12-char hash that identifies a finding across runs.
|
|
4
|
+
* Computed from (ruleId, path, line, message) so that the same logical
|
|
5
|
+
* issue at the same logical place always hashes to the same value.
|
|
6
|
+
*/
|
|
7
|
+
export function computeFingerprint(input) {
|
|
8
|
+
const h = createHash("sha256");
|
|
9
|
+
h.update(input.ruleId);
|
|
10
|
+
h.update("\0");
|
|
11
|
+
h.update(input.path);
|
|
12
|
+
h.update("\0");
|
|
13
|
+
h.update(input.line === undefined ? "" : String(input.line));
|
|
14
|
+
h.update("\0");
|
|
15
|
+
h.update(input.message);
|
|
16
|
+
return h.digest("hex").slice(0, 12);
|
|
17
|
+
}
|
|
18
|
+
/** Return a Finding with its `fingerprint` populated, computing it if missing. */
|
|
19
|
+
export function ensureFingerprint(f) {
|
|
20
|
+
return { ...f, fingerprint: f.fingerprint ?? computeFingerprint(f) };
|
|
21
|
+
}
|
|
22
|
+
//# sourceMappingURL=findings.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"findings.js","sourceRoot":"","sources":["../src/findings.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAGzC;;;;GAIG;AACH,MAAM,UAAU,kBAAkB,CAAC,KAKlC;IACC,MAAM,CAAC,GAAG,UAAU,CAAC,QAAQ,CAAC,CAAC;IAC/B,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC;IACvB,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;IACf,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;IACrB,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;IACf,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,IAAI,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC;IAC7D,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;IACf,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;IACxB,OAAO,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;AACtC,CAAC;AAED,kFAAkF;AAClF,MAAM,UAAU,iBAAiB,CAC/B,CAAI;IAEJ,OAAO,EAAE,GAAG,CAAC,EAAE,WAAW,EAAE,CAAC,CAAC,WAAW,IAAI,kBAAkB,CAAC,CAAC,CAAC,EAAE,CAAC;AACvE,CAAC"}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import type { Finding } from "../types.js";
|
|
2
|
+
/** Stable 12-char hash of a finding's identity. Prefer reading `finding.fingerprint` directly
|
|
3
|
+
* on `Finding` objects coming from the runtime; this helper is for cases where the field
|
|
4
|
+
* may be absent (e.g. test fixtures, ad-hoc finding-shaped objects). */
|
|
5
|
+
export declare function fingerprint(finding: Pick<Finding, "ruleId" | "path" | "line" | "message"> & {
|
|
6
|
+
fingerprint?: string;
|
|
7
|
+
}): string;
|
|
8
|
+
/** Stable 12-char hash of the *set* of fingerprints in a single run's body, used to short-circuit identical re-posts. */
|
|
9
|
+
export declare function bodyFingerprint(fingerprints: Iterable<string>): string;
|
|
10
|
+
/** Append a hidden HTML comment marker to a comment body. */
|
|
11
|
+
export declare function withMarker(body: string, fp: string): string;
|
|
12
|
+
/** Append a hidden HTML body-level marker to the top-level review body. */
|
|
13
|
+
export declare function withBodyMarker(body: string, bodyFp: string): string;
|
|
14
|
+
/** Extract every revu-ai:fp marker from a comment body. */
|
|
15
|
+
export declare function extractMarkers(body: string): string[];
|
|
16
|
+
/** Extract a body-level marker, if present. */
|
|
17
|
+
export declare function extractBodyMarker(body: string): string | undefined;
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import { createHash } from "node:crypto";
|
|
2
|
+
import { computeFingerprint } from "../findings.js";
|
|
3
|
+
const MARKER_PREFIX = "revu-ai:fp=";
|
|
4
|
+
const MARKER_RE = /<!--\s*revu-ai:fp=([0-9a-f]{12})\s*-->/g;
|
|
5
|
+
const BODY_MARKER_PREFIX = "revu-ai:body-fp=";
|
|
6
|
+
const BODY_MARKER_RE = /<!--\s*revu-ai:body-fp=([0-9a-f]{12})\s*-->/;
|
|
7
|
+
/** Stable 12-char hash of a finding's identity. Prefer reading `finding.fingerprint` directly
|
|
8
|
+
* on `Finding` objects coming from the runtime; this helper is for cases where the field
|
|
9
|
+
* may be absent (e.g. test fixtures, ad-hoc finding-shaped objects). */
|
|
10
|
+
export function fingerprint(finding) {
|
|
11
|
+
return finding.fingerprint ?? computeFingerprint(finding);
|
|
12
|
+
}
|
|
13
|
+
/** Stable 12-char hash of the *set* of fingerprints in a single run's body, used to short-circuit identical re-posts. */
|
|
14
|
+
export function bodyFingerprint(fingerprints) {
|
|
15
|
+
const sorted = [...fingerprints].sort();
|
|
16
|
+
const h = createHash("sha256");
|
|
17
|
+
h.update(sorted.join("|"));
|
|
18
|
+
return h.digest("hex").slice(0, 12);
|
|
19
|
+
}
|
|
20
|
+
/** Append a hidden HTML comment marker to a comment body. */
|
|
21
|
+
export function withMarker(body, fp) {
|
|
22
|
+
return `${body.replace(/\s+$/u, "")}\n\n<!-- ${MARKER_PREFIX}${fp} -->`;
|
|
23
|
+
}
|
|
24
|
+
/** Append a hidden HTML body-level marker to the top-level review body. */
|
|
25
|
+
export function withBodyMarker(body, bodyFp) {
|
|
26
|
+
return `${body.replace(/\s+$/u, "")}\n\n<!-- ${BODY_MARKER_PREFIX}${bodyFp} -->`;
|
|
27
|
+
}
|
|
28
|
+
/** Extract every revu-ai:fp marker from a comment body. */
|
|
29
|
+
export function extractMarkers(body) {
|
|
30
|
+
const out = [];
|
|
31
|
+
for (const m of body.matchAll(MARKER_RE)) {
|
|
32
|
+
if (m[1])
|
|
33
|
+
out.push(m[1]);
|
|
34
|
+
}
|
|
35
|
+
return out;
|
|
36
|
+
}
|
|
37
|
+
/** Extract a body-level marker, if present. */
|
|
38
|
+
export function extractBodyMarker(body) {
|
|
39
|
+
const m = body.match(BODY_MARKER_RE);
|
|
40
|
+
return m?.[1];
|
|
41
|
+
}
|
|
42
|
+
//# sourceMappingURL=dedup.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"dedup.js","sourceRoot":"","sources":["../../src/forges/dedup.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAEzC,OAAO,EAAE,kBAAkB,EAAE,MAAM,gBAAgB,CAAC;AAEpD,MAAM,aAAa,GAAG,aAAa,CAAC;AACpC,MAAM,SAAS,GAAG,yCAAyC,CAAC;AAC5D,MAAM,kBAAkB,GAAG,kBAAkB,CAAC;AAC9C,MAAM,cAAc,GAAG,6CAA6C,CAAC;AAErE;;yEAEyE;AACzE,MAAM,UAAU,WAAW,CAAC,OAAyF;IACnH,OAAO,OAAO,CAAC,WAAW,IAAI,kBAAkB,CAAC,OAAO,CAAC,CAAC;AAC5D,CAAC;AAED,yHAAyH;AACzH,MAAM,UAAU,eAAe,CAAC,YAA8B;IAC5D,MAAM,MAAM,GAAG,CAAC,GAAG,YAAY,CAAC,CAAC,IAAI,EAAE,CAAC;IACxC,MAAM,CAAC,GAAG,UAAU,CAAC,QAAQ,CAAC,CAAC;IAC/B,CAAC,CAAC,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC;IAC3B,OAAO,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;AACtC,CAAC;AAED,6DAA6D;AAC7D,MAAM,UAAU,UAAU,CAAC,IAAY,EAAE,EAAU;IACjD,OAAO,GAAG,IAAI,CAAC,OAAO,CAAC,OAAO,EAAE,EAAE,CAAC,YAAY,aAAa,GAAG,EAAE,MAAM,CAAC;AAC1E,CAAC;AAED,2EAA2E;AAC3E,MAAM,UAAU,cAAc,CAAC,IAAY,EAAE,MAAc;IACzD,OAAO,GAAG,IAAI,CAAC,OAAO,CAAC,OAAO,EAAE,EAAE,CAAC,YAAY,kBAAkB,GAAG,MAAM,MAAM,CAAC;AACnF,CAAC;AAED,2DAA2D;AAC3D,MAAM,UAAU,cAAc,CAAC,IAAY;IACzC,MAAM,GAAG,GAAa,EAAE,CAAC;IACzB,KAAK,MAAM,CAAC,IAAI,IAAI,CAAC,QAAQ,CAAC,SAAS,CAAC,EAAE,CAAC;QACzC,IAAI,CAAC,CAAC,CAAC,CAAC;YAAE,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;IAC3B,CAAC;IACD,OAAO,GAAG,CAAC;AACb,CAAC;AAED,+CAA+C;AAC/C,MAAM,UAAU,iBAAiB,CAAC,IAAY;IAC5C,MAAM,CAAC,GAAG,IAAI,CAAC,KAAK,CAAC,cAAc,CAAC,CAAC;IACrC,OAAO,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;AAChB,CAAC"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Parse a unified diff produced by `git diff` (or GitHub's
|
|
3
|
+
* `application/vnd.github.v3.diff` representation) into a map of
|
|
4
|
+
* `<path> → Set<post-image line numbers>` containing every "added" line.
|
|
5
|
+
*
|
|
6
|
+
* Inline review comments on most forges can only be posted on lines that
|
|
7
|
+
* were added or modified in the diff. Context lines and removed lines are
|
|
8
|
+
* not commentable. We only track post-image (RIGHT-side) line numbers.
|
|
9
|
+
*/
|
|
10
|
+
export declare function parseUnifiedDiff(diff: string): Map<string, Set<number>>;
|
|
11
|
+
/** Convenience: is `(path, line)` postable as an inline comment based on the parsed diff? */
|
|
12
|
+
export declare function isInlineable(map: Map<string, Set<number>>, path: string, line: number): boolean;
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Parse a unified diff produced by `git diff` (or GitHub's
|
|
3
|
+
* `application/vnd.github.v3.diff` representation) into a map of
|
|
4
|
+
* `<path> → Set<post-image line numbers>` containing every "added" line.
|
|
5
|
+
*
|
|
6
|
+
* Inline review comments on most forges can only be posted on lines that
|
|
7
|
+
* were added or modified in the diff. Context lines and removed lines are
|
|
8
|
+
* not commentable. We only track post-image (RIGHT-side) line numbers.
|
|
9
|
+
*/
|
|
10
|
+
export function parseUnifiedDiff(diff) {
|
|
11
|
+
const result = new Map();
|
|
12
|
+
if (!diff)
|
|
13
|
+
return result;
|
|
14
|
+
const lines = diff.split(/\r?\n/);
|
|
15
|
+
let currentPath;
|
|
16
|
+
let currentSet;
|
|
17
|
+
let newLineNo = 0;
|
|
18
|
+
let inHunk = false;
|
|
19
|
+
let isBinary = false;
|
|
20
|
+
for (const raw of lines) {
|
|
21
|
+
if (raw.startsWith("diff --git ")) {
|
|
22
|
+
currentPath = undefined;
|
|
23
|
+
currentSet = undefined;
|
|
24
|
+
newLineNo = 0;
|
|
25
|
+
inHunk = false;
|
|
26
|
+
isBinary = false;
|
|
27
|
+
continue;
|
|
28
|
+
}
|
|
29
|
+
if (raw.startsWith("Binary files ") || raw.startsWith("GIT binary patch")) {
|
|
30
|
+
isBinary = true;
|
|
31
|
+
continue;
|
|
32
|
+
}
|
|
33
|
+
if (raw.startsWith("+++ ")) {
|
|
34
|
+
// "+++ b/path/to/file" or "+++ /dev/null"
|
|
35
|
+
const tail = raw.slice(4);
|
|
36
|
+
if (tail === "/dev/null") {
|
|
37
|
+
currentPath = undefined;
|
|
38
|
+
}
|
|
39
|
+
else {
|
|
40
|
+
currentPath = tail.startsWith("b/") ? tail.slice(2) : tail;
|
|
41
|
+
if (!isBinary) {
|
|
42
|
+
currentSet = result.get(currentPath) ?? new Set();
|
|
43
|
+
result.set(currentPath, currentSet);
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
inHunk = false;
|
|
47
|
+
continue;
|
|
48
|
+
}
|
|
49
|
+
if (raw.startsWith("@@")) {
|
|
50
|
+
// @@ -oldStart,oldLen +newStart,newLen @@ optional context
|
|
51
|
+
const m = raw.match(/^@@ -\d+(?:,\d+)? \+(\d+)(?:,(\d+))? @@/);
|
|
52
|
+
if (m && m[1]) {
|
|
53
|
+
newLineNo = Number.parseInt(m[1], 10);
|
|
54
|
+
inHunk = true;
|
|
55
|
+
}
|
|
56
|
+
else {
|
|
57
|
+
inHunk = false;
|
|
58
|
+
}
|
|
59
|
+
continue;
|
|
60
|
+
}
|
|
61
|
+
if (!inHunk || !currentSet || isBinary)
|
|
62
|
+
continue;
|
|
63
|
+
const first = raw.charAt(0);
|
|
64
|
+
if (first === "+") {
|
|
65
|
+
// Added line — commentable.
|
|
66
|
+
currentSet.add(newLineNo);
|
|
67
|
+
newLineNo++;
|
|
68
|
+
}
|
|
69
|
+
else if (first === " ") {
|
|
70
|
+
// Context line — advances the new-side counter but not commentable.
|
|
71
|
+
newLineNo++;
|
|
72
|
+
}
|
|
73
|
+
else if (first === "-") {
|
|
74
|
+
// Removed line — does not advance the new-side counter.
|
|
75
|
+
}
|
|
76
|
+
else if (first === "\\") {
|
|
77
|
+
// "" — skip.
|
|
78
|
+
}
|
|
79
|
+
else if (raw.length === 0) {
|
|
80
|
+
// Blank trailing line; skip.
|
|
81
|
+
}
|
|
82
|
+
else {
|
|
83
|
+
// Unexpected line shape; bail out of the hunk.
|
|
84
|
+
inHunk = false;
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
return result;
|
|
88
|
+
}
|
|
89
|
+
/** Convenience: is `(path, line)` postable as an inline comment based on the parsed diff? */
|
|
90
|
+
export function isInlineable(map, path, line) {
|
|
91
|
+
return map.get(path)?.has(line) ?? false;
|
|
92
|
+
}
|
|
93
|
+
//# sourceMappingURL=diff-lines.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"diff-lines.js","sourceRoot":"","sources":["../../src/forges/diff-lines.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Thin `fetch`-based GitHub REST API client. Exposes only the four endpoints
|
|
3
|
+
* the forge adapter uses; not a general-purpose SDK.
|
|
4
|
+
*/
|
|
5
|
+
export interface GhPullRequest {
|
|
6
|
+
number: number;
|
|
7
|
+
head: {
|
|
8
|
+
sha: string;
|
|
9
|
+
ref: string;
|
|
10
|
+
};
|
|
11
|
+
base: {
|
|
12
|
+
sha: string;
|
|
13
|
+
ref: string;
|
|
14
|
+
};
|
|
15
|
+
}
|
|
16
|
+
export interface GhComment {
|
|
17
|
+
id: number;
|
|
18
|
+
body: string;
|
|
19
|
+
user: {
|
|
20
|
+
login: string;
|
|
21
|
+
type: string;
|
|
22
|
+
} | null;
|
|
23
|
+
path?: string;
|
|
24
|
+
line?: number;
|
|
25
|
+
}
|
|
26
|
+
export interface GhPostReviewBody {
|
|
27
|
+
commit_id: string;
|
|
28
|
+
event: "COMMENT" | "REQUEST_CHANGES" | "APPROVE";
|
|
29
|
+
body: string;
|
|
30
|
+
comments: Array<{
|
|
31
|
+
path: string;
|
|
32
|
+
line: number;
|
|
33
|
+
side: "LEFT" | "RIGHT";
|
|
34
|
+
body: string;
|
|
35
|
+
start_line?: number;
|
|
36
|
+
start_side?: "LEFT" | "RIGHT";
|
|
37
|
+
}>;
|
|
38
|
+
}
|
|
39
|
+
export interface GhCreatedReview {
|
|
40
|
+
id: number;
|
|
41
|
+
html_url: string;
|
|
42
|
+
state: string;
|
|
43
|
+
}
|
|
44
|
+
export declare class GitHubApiError extends Error {
|
|
45
|
+
readonly status: number;
|
|
46
|
+
readonly url: string;
|
|
47
|
+
readonly responseBody: string;
|
|
48
|
+
constructor(status: number, url: string, responseBody: string);
|
|
49
|
+
}
|
|
50
|
+
export declare class GitHubClient {
|
|
51
|
+
private readonly token;
|
|
52
|
+
private readonly fetchImpl;
|
|
53
|
+
constructor(token: string, fetchImpl?: typeof fetch);
|
|
54
|
+
getPullRequest(owner: string, repo: string, number: number): Promise<GhPullRequest>;
|
|
55
|
+
getPullRequestDiff(owner: string, repo: string, number: number): Promise<string>;
|
|
56
|
+
/** Paged fetch of PR review comments (the inline ones). */
|
|
57
|
+
listReviewComments(owner: string, repo: string, number: number): Promise<GhComment[]>;
|
|
58
|
+
/** Paged fetch of the comments that belong to a single PR review (created together). */
|
|
59
|
+
listReviewCommentsForReview(owner: string, repo: string, number: number, reviewId: number): Promise<GhComment[]>;
|
|
60
|
+
/** Paged fetch of issue comments — used to find a prior top-level body marker. */
|
|
61
|
+
listIssueComments(owner: string, repo: string, number: number): Promise<GhComment[]>;
|
|
62
|
+
createReview(owner: string, repo: string, number: number, body: GhPostReviewBody): Promise<GhCreatedReview>;
|
|
63
|
+
/** Edit an existing PR review comment's body and/or line. */
|
|
64
|
+
patchReviewComment(owner: string, repo: string, commentId: number, body: {
|
|
65
|
+
body: string;
|
|
66
|
+
}): Promise<GhComment>;
|
|
67
|
+
private listAll;
|
|
68
|
+
private request;
|
|
69
|
+
private requestText;
|
|
70
|
+
}
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Thin `fetch`-based GitHub REST API client. Exposes only the four endpoints
|
|
3
|
+
* the forge adapter uses; not a general-purpose SDK.
|
|
4
|
+
*/
|
|
5
|
+
const BASE = "https://api.github.com";
|
|
6
|
+
const ACCEPT_JSON = "application/vnd.github+json";
|
|
7
|
+
const ACCEPT_DIFF = "application/vnd.github.v3.diff";
|
|
8
|
+
const API_VERSION = "2022-11-28";
|
|
9
|
+
export class GitHubApiError extends Error {
|
|
10
|
+
status;
|
|
11
|
+
url;
|
|
12
|
+
responseBody;
|
|
13
|
+
constructor(status, url, responseBody) {
|
|
14
|
+
super(`GitHub API ${status} for ${url}: ${responseBody.slice(0, 400)}`);
|
|
15
|
+
this.status = status;
|
|
16
|
+
this.url = url;
|
|
17
|
+
this.responseBody = responseBody;
|
|
18
|
+
this.name = "GitHubApiError";
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
export class GitHubClient {
|
|
22
|
+
token;
|
|
23
|
+
fetchImpl;
|
|
24
|
+
constructor(token, fetchImpl = fetch) {
|
|
25
|
+
this.token = token;
|
|
26
|
+
this.fetchImpl = fetchImpl;
|
|
27
|
+
}
|
|
28
|
+
async getPullRequest(owner, repo, number) {
|
|
29
|
+
return this.request(`/repos/${owner}/${repo}/pulls/${number}`);
|
|
30
|
+
}
|
|
31
|
+
async getPullRequestDiff(owner, repo, number) {
|
|
32
|
+
return this.requestText(`/repos/${owner}/${repo}/pulls/${number}`, { accept: ACCEPT_DIFF });
|
|
33
|
+
}
|
|
34
|
+
/** Paged fetch of PR review comments (the inline ones). */
|
|
35
|
+
async listReviewComments(owner, repo, number) {
|
|
36
|
+
return this.listAll(`/repos/${owner}/${repo}/pulls/${number}/comments`);
|
|
37
|
+
}
|
|
38
|
+
/** Paged fetch of the comments that belong to a single PR review (created together). */
|
|
39
|
+
async listReviewCommentsForReview(owner, repo, number, reviewId) {
|
|
40
|
+
return this.listAll(`/repos/${owner}/${repo}/pulls/${number}/reviews/${reviewId}/comments`);
|
|
41
|
+
}
|
|
42
|
+
/** Paged fetch of issue comments — used to find a prior top-level body marker. */
|
|
43
|
+
async listIssueComments(owner, repo, number) {
|
|
44
|
+
return this.listAll(`/repos/${owner}/${repo}/issues/${number}/comments`);
|
|
45
|
+
}
|
|
46
|
+
async createReview(owner, repo, number, body) {
|
|
47
|
+
return this.request(`/repos/${owner}/${repo}/pulls/${number}/reviews`, {
|
|
48
|
+
method: "POST",
|
|
49
|
+
body,
|
|
50
|
+
});
|
|
51
|
+
}
|
|
52
|
+
/** Edit an existing PR review comment's body and/or line. */
|
|
53
|
+
async patchReviewComment(owner, repo, commentId, body) {
|
|
54
|
+
return this.request(`/repos/${owner}/${repo}/pulls/comments/${commentId}`, {
|
|
55
|
+
method: "PATCH",
|
|
56
|
+
body,
|
|
57
|
+
});
|
|
58
|
+
}
|
|
59
|
+
async listAll(path) {
|
|
60
|
+
const out = [];
|
|
61
|
+
const perPage = 100;
|
|
62
|
+
let page = 1;
|
|
63
|
+
// GitHub paginates via Link header; fewer-than-per-page is a reliable end-of-list signal.
|
|
64
|
+
for (;;) {
|
|
65
|
+
const sep = path.includes("?") ? "&" : "?";
|
|
66
|
+
const batch = await this.request(`${path}${sep}per_page=${perPage}&page=${page}`);
|
|
67
|
+
out.push(...batch);
|
|
68
|
+
if (batch.length < perPage)
|
|
69
|
+
break;
|
|
70
|
+
page++;
|
|
71
|
+
if (page > 100)
|
|
72
|
+
break; // hard safety cap
|
|
73
|
+
}
|
|
74
|
+
return out;
|
|
75
|
+
}
|
|
76
|
+
async request(path, opts = {}) {
|
|
77
|
+
const text = await this.requestText(path, opts);
|
|
78
|
+
return JSON.parse(text);
|
|
79
|
+
}
|
|
80
|
+
async requestText(path, opts = {}) {
|
|
81
|
+
const url = path.startsWith("http") ? path : `${BASE}${path}`;
|
|
82
|
+
const headers = {
|
|
83
|
+
Accept: opts.accept ?? ACCEPT_JSON,
|
|
84
|
+
Authorization: `Bearer ${this.token}`,
|
|
85
|
+
"X-GitHub-Api-Version": API_VERSION,
|
|
86
|
+
"User-Agent": "revu-ai",
|
|
87
|
+
};
|
|
88
|
+
const init = { method: opts.method ?? "GET", headers };
|
|
89
|
+
if (opts.body !== undefined) {
|
|
90
|
+
headers["Content-Type"] = "application/json";
|
|
91
|
+
init.body = JSON.stringify(opts.body);
|
|
92
|
+
}
|
|
93
|
+
const fetchFn = opts.fetchImpl ?? this.fetchImpl;
|
|
94
|
+
const res = await fetchFn(url, init);
|
|
95
|
+
const body = await res.text();
|
|
96
|
+
if (!res.ok) {
|
|
97
|
+
throw new GitHubApiError(res.status, url, body);
|
|
98
|
+
}
|
|
99
|
+
return body;
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
//# sourceMappingURL=api.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"api.js","sourceRoot":"","sources":["../../../src/forges/github/api.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type { ForgeAdapter, ForgeAdapterFactory, ForgeContext, PostOptions, PostResult, ResolveContextFlags } from "../types.js";
|
|
2
|
+
export declare const githubForgeFactory: ForgeAdapterFactory;
|
|
3
|
+
export declare class GitHubForgeAdapter implements ForgeAdapter {
|
|
4
|
+
private readonly fetchImpl?;
|
|
5
|
+
readonly name = "github";
|
|
6
|
+
/** Allow tests to inject a custom `fetch`. */
|
|
7
|
+
constructor(fetchImpl?: typeof fetch | undefined);
|
|
8
|
+
resolveContext(env: NodeJS.ProcessEnv, flags: ResolveContextFlags): Promise<ForgeContext>;
|
|
9
|
+
post(options: PostOptions): Promise<PostResult>;
|
|
10
|
+
}
|