@cat-factory/agents 0.68.3 → 0.69.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/dist/agents/kinds/pr-review-context.d.ts +103 -0
- package/dist/agents/kinds/pr-review-context.d.ts.map +1 -0
- package/dist/agents/kinds/pr-review-context.js +456 -0
- package/dist/agents/kinds/pr-review-context.js.map +1 -0
- package/dist/agents/kinds/pr-reviewer.d.ts +1 -35
- package/dist/agents/kinds/pr-reviewer.d.ts.map +1 -1
- package/dist/agents/kinds/pr-reviewer.js +108 -238
- package/dist/agents/kinds/pr-reviewer.js.map +1 -1
- package/dist/agents/kinds/registry.d.ts +22 -0
- package/dist/agents/kinds/registry.d.ts.map +1 -1
- package/dist/agents/kinds/registry.js +8 -0
- package/dist/agents/kinds/registry.js.map +1 -1
- package/dist/agents/prompts/shared.d.ts +1 -9
- package/dist/agents/prompts/shared.d.ts.map +1 -1
- package/dist/agents/prompts/shared.js +29 -10
- package/dist/agents/prompts/shared.js.map +1 -1
- package/dist/agents/runtime/executor.d.ts.map +1 -1
- package/dist/agents/runtime/executor.js +2 -2
- package/dist/agents/runtime/executor.js.map +1 -1
- package/dist/agents/runtime/fragments.d.ts +28 -1
- package/dist/agents/runtime/fragments.d.ts.map +1 -1
- package/dist/agents/runtime/fragments.js +28 -1
- package/dist/agents/runtime/fragments.js.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/package.json +5 -5
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
import type { GitHubChangedFile, GitHubReviewThread, RepoOp } from '@cat-factory/kernel';
|
|
2
|
+
import type { ComposableFragment } from '../runtime/fragments.js';
|
|
3
|
+
/** The injected context file (under `.cat-context/`) the diff preOp writes for the reviewer. */
|
|
4
|
+
export declare const PR_DIFF_CONTEXT_FILE = "pr-diff.md";
|
|
5
|
+
/** The injected context file listing the PR's already-posted review comments (for de-dup). */
|
|
6
|
+
export declare const PR_EXISTING_COMMENTS_CONTEXT_FILE = "pr-existing-comments.md";
|
|
7
|
+
/**
|
|
8
|
+
* Filename prefix for the per-standard context files the standards preOp writes. Re-exports the
|
|
9
|
+
* SHARED convention (`@cat-factory/agents` `fragments.ts`) so `standardsDeliveredAsFiles` — which
|
|
10
|
+
* decides whether to fold standards into the prompt as a fallback — recognises what this preOp
|
|
11
|
+
* writes without knowing anything pr-review-specific.
|
|
12
|
+
*/
|
|
13
|
+
export declare const PR_STANDARD_CONTEXT_PREFIX = "standard-";
|
|
14
|
+
/** Resolve the reviewed PR's number from the block's task-type fields (prefer `prNumber`). */
|
|
15
|
+
export declare function resolvePrNumber(fields: {
|
|
16
|
+
prNumber?: number;
|
|
17
|
+
prUrl?: string;
|
|
18
|
+
} | undefined): number | null;
|
|
19
|
+
/** One suggested review slice: a cohesive group of changed files, with its size. */
|
|
20
|
+
export interface SuggestedSlice {
|
|
21
|
+
/** Short name — the grouping path, or `assorted` / a `(part N)` suffix when split. */
|
|
22
|
+
title: string;
|
|
23
|
+
paths: string[];
|
|
24
|
+
changedLines: number;
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* Group the changed files into candidate review slices, deterministically and with no model
|
|
28
|
+
* turns. Files group by their leading path segments (the project / module / top-level area),
|
|
29
|
+
* one-off groups collapse into a shared `assorted` slice, and any group over
|
|
30
|
+
* {@link SLICE_MAX_FILES} / {@link SLICE_MAX_CHANGED_LINES} is split into numbered parts.
|
|
31
|
+
*
|
|
32
|
+
* This is a SUGGESTION the reviewer may regroup — path adjacency is a good proxy for
|
|
33
|
+
* "belongs together" but it cannot see that a refactor and its call sites live apart. Its
|
|
34
|
+
* value is that the reviewer starts from a usable grouping instead of probing the file list
|
|
35
|
+
* to build one, and that the size caps stop a single oversized slice forming: cost scales with
|
|
36
|
+
* turns × context, so one slice big enough to need 100+ turns costs more than three that
|
|
37
|
+
* replace it.
|
|
38
|
+
*/
|
|
39
|
+
export declare function planSlices(files: GitHubChangedFile[]): SuggestedSlice[];
|
|
40
|
+
/**
|
|
41
|
+
* Render the changed-file list, the change shape, a suggested slicing, and — only for a diff
|
|
42
|
+
* small enough to review in one pass — the patches, as the injected `.cat-context/pr-diff.md`.
|
|
43
|
+
* See the module header for why the patch budget is all-or-nothing.
|
|
44
|
+
*/
|
|
45
|
+
export declare function renderPrDiffContext(number: number, files: GitHubChangedFile[]): string;
|
|
46
|
+
/**
|
|
47
|
+
* Render the PR's existing review threads as `.cat-context/pr-existing-comments.md`, so the
|
|
48
|
+
* reviewer de-dups against findings already raised (prior rounds / humans / other bots).
|
|
49
|
+
*
|
|
50
|
+
* Threads are GROUPED BY FILE under a path index. De-dup is a per-slice concern, so a slice
|
|
51
|
+
* reviewer should grep out the handful of threads on its own paths; reading the whole file
|
|
52
|
+
* into the parent's context makes every remaining turn of the review pay for all of them.
|
|
53
|
+
*/
|
|
54
|
+
export declare function renderExistingReviewComments(number: number, threads: GitHubReviewThread[]): string;
|
|
55
|
+
/**
|
|
56
|
+
* The `.cat-context/` filename a resolved best-practice standard is written to. Non-portable
|
|
57
|
+
* characters are replaced with `-` so the name survives the harness's context-file sanitizer
|
|
58
|
+
* (it keeps only `[A-Za-z0-9._-]` and flattens any directory) unchanged — the name in the index
|
|
59
|
+
* is then the name on disk.
|
|
60
|
+
*
|
|
61
|
+
* When sanitizing ALTERS the id, two distinct ids can sanitize to the same slug (`org/team` and
|
|
62
|
+
* `org team` both → `org-team`); the harness drops the duplicate path, silently losing the second
|
|
63
|
+
* standard while the index still advertises it. So a short hash of the ORIGINAL id is appended
|
|
64
|
+
* whenever the slug differs from the id, making the filename unique per id. An already-safe id is
|
|
65
|
+
* left untouched (no suffix), so the common case stays readable.
|
|
66
|
+
*/
|
|
67
|
+
export declare function standardsContextFileName(fragmentId: string): string;
|
|
68
|
+
/** Render one standard as its own context file, with the title the reviewer cites it by. */
|
|
69
|
+
export declare function renderStandardContext(fragment: ComposableFragment): string;
|
|
70
|
+
/** Render the index that tells the reviewer which standards exist and where each one is. */
|
|
71
|
+
export declare function renderStandardsIndex(fragments: ComposableFragment[]): string;
|
|
72
|
+
/** The index file listing every injected standard (the shared `context-files` convention). */
|
|
73
|
+
export declare const PR_STANDARDS_INDEX_CONTEXT_FILE = "standards.md";
|
|
74
|
+
/**
|
|
75
|
+
* PreOp for the `pr-reviewer` kind: hand the reviewer the PR's changed-file list, change shape and
|
|
76
|
+
* a suggested slicing as `.cat-context/pr-diff.md` (plus the patches when the whole diff is small
|
|
77
|
+
* enough to review in one pass). Pass-through — injecting nothing, so the prompt's git fallback
|
|
78
|
+
* runs — when the PR number can't be resolved, the bound client can't list changed files
|
|
79
|
+
* (unwired / a VCS provider without the capability), or the PR reports no changed files.
|
|
80
|
+
*/
|
|
81
|
+
export declare const prReviewerDiffPreOp: RepoOp;
|
|
82
|
+
/**
|
|
83
|
+
* PreOp for the `pr-reviewer` kind: hand the reviewer the PR's EXISTING review threads up front as
|
|
84
|
+
* `.cat-context/pr-existing-comments.md`, grouped by file, so it de-dups against findings already
|
|
85
|
+
* raised instead of re-reporting them. Pass-through — injecting nothing — when the PR number can't
|
|
86
|
+
* be resolved, the bound client can't read review threads, or the PR has no review threads yet.
|
|
87
|
+
*/
|
|
88
|
+
export declare const prReviewerExistingCommentsPreOp: RepoOp;
|
|
89
|
+
/**
|
|
90
|
+
* PreOp for the `pr-reviewer` kind: write the task's selected best-practice standards as one
|
|
91
|
+
* `.cat-context/standard-<id>.md` file each, plus an index.
|
|
92
|
+
*
|
|
93
|
+
* The reviewer's own prompt does NOT carry the standards (the kind declares
|
|
94
|
+
* `standardsDelivery: 'context-files'`, so the engine skips the fold). Folding them in charged
|
|
95
|
+
* the parent for every standard on every turn — 145 KB across 5 standards on the measured run,
|
|
96
|
+
* ~3.7M tokens over 96 turns — while the agents that actually review the code, the parallel slice
|
|
97
|
+
* subagents, never received them and worked from the parent's one-line paraphrase instead. As
|
|
98
|
+
* files, each standard is read once by the slices it applies to, from the real text.
|
|
99
|
+
*
|
|
100
|
+
* Pass-through when the run resolved no fragments (a review task with none selected).
|
|
101
|
+
*/
|
|
102
|
+
export declare const prReviewerStandardsPreOp: RepoOp;
|
|
103
|
+
//# sourceMappingURL=pr-review-context.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"pr-review-context.d.ts","sourceRoot":"","sources":["../../../src/agents/kinds/pr-review-context.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,iBAAiB,EACjB,kBAAkB,EAClB,MAAM,EAGP,MAAM,qBAAqB,CAAA;AAC5B,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,yBAAyB,CAAA;AAmCjE,gGAAgG;AAChG,eAAO,MAAM,oBAAoB,eAAe,CAAA;AAEhD,8FAA8F;AAC9F,eAAO,MAAM,iCAAiC,4BAA4B,CAAA;AAE1E;;;;;GAKG;AACH,eAAO,MAAM,0BAA0B,cAAgC,CAAA;AAkCvE,8FAA8F;AAC9F,wBAAgB,eAAe,CAC7B,MAAM,EAAE;IAAE,QAAQ,CAAC,EAAE,MAAM,CAAC;IAAC,KAAK,CAAC,EAAE,MAAM,CAAA;CAAE,GAAG,SAAS,GACxD,MAAM,GAAG,IAAI,CAef;AAMD,oFAAoF;AACpF,MAAM,WAAW,cAAc;IAC7B,sFAAsF;IACtF,KAAK,EAAE,MAAM,CAAA;IACb,KAAK,EAAE,MAAM,EAAE,CAAA;IACf,YAAY,EAAE,MAAM,CAAA;CACrB;AAcD;;;;;;;;;;;;GAYG;AACH,wBAAgB,UAAU,CAAC,KAAK,EAAE,iBAAiB,EAAE,GAAG,cAAc,EAAE,CAiDvE;AAqDD;;;;GAIG;AACH,wBAAgB,mBAAmB,CAAC,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,iBAAiB,EAAE,GAAG,MAAM,CAyDtF;AAyBD;;;;;;;GAOG;AACH,wBAAgB,4BAA4B,CAC1C,MAAM,EAAE,MAAM,EACd,OAAO,EAAE,kBAAkB,EAAE,GAC5B,MAAM,CA2CR;AAgBD;;;;;;;;;;;GAWG;AACH,wBAAgB,wBAAwB,CAAC,UAAU,EAAE,MAAM,GAAG,MAAM,CAInE;AAED,4FAA4F;AAC5F,wBAAgB,qBAAqB,CAAC,QAAQ,EAAE,kBAAkB,GAAG,MAAM,CAS1E;AAED,4FAA4F;AAC5F,wBAAgB,oBAAoB,CAAC,SAAS,EAAE,kBAAkB,EAAE,GAAG,MAAM,CAgB5E;AAED,8FAA8F;AAC9F,eAAO,MAAM,+BAA+B,iBAA+B,CAAA;AAM3E;;;;;;GAMG;AACH,eAAO,MAAM,mBAAmB,EAAE,MAYjC,CAAA;AAED;;;;;GAKG;AACH,eAAO,MAAM,+BAA+B,EAAE,MAiB7C,CAAA;AAED;;;;;;;;;;;;GAYG;AACH,eAAO,MAAM,wBAAwB,EAAE,MActC,CAAA"}
|
|
@@ -0,0 +1,456 @@
|
|
|
1
|
+
import { STANDARDS_CONTEXT_FILE_PREFIX, STANDARDS_CONTEXT_INDEX_FILE, } from '../runtime/fragments.js';
|
|
2
|
+
// ---------------------------------------------------------------------------
|
|
3
|
+
// What the `pr-reviewer` is handed UP FRONT, as `.cat-context/*.md` files.
|
|
4
|
+
//
|
|
5
|
+
// The governing constraint is that an agentic loop re-sends its whole transcript on every
|
|
6
|
+
// turn, so ANYTHING placed in the reviewer's context is paid for again on each of the
|
|
7
|
+
// (hundreds of) turns that follow. A 10k-token file read early in a 400-turn review costs
|
|
8
|
+
// millions of tokens by the end. Everything here is therefore sized by "how many turns will
|
|
9
|
+
// carry this?", not by "does it fit?".
|
|
10
|
+
//
|
|
11
|
+
// Measured on a 437-turn review of a ~450-file PR, that produced three rules:
|
|
12
|
+
//
|
|
13
|
+
// 1. The reviewer slices from the changed-file LIST; its parallel slice subagents pull their
|
|
14
|
+
// own diffs from git. Pre-inlining a large diff pays for a map nobody reads — that run
|
|
15
|
+
// inlined 319 KB and the subagents referenced it once while running 141 `git diff`/`git
|
|
16
|
+
// show` calls. So patches are inlined ONLY when the WHOLE diff is small enough to review
|
|
17
|
+
// in one pass ({@link MAX_INLINE_DIFF_BYTES}); past that the file is a manifest and the
|
|
18
|
+
// diffs are read per slice. All-or-nothing, because a half-inlined file is the worst case:
|
|
19
|
+
// it is big AND the reviewer still has to probe it to find out what is missing.
|
|
20
|
+
// 2. A manifest the reviewer has to reverse-engineer costs more than one it can read. That
|
|
21
|
+
// run spent 21 `grep`/`awk`/`sed`/`wc` probes working out the injected file's own shape,
|
|
22
|
+
// each probe's output then carried for the rest of the review. So the manifest states the
|
|
23
|
+
// per-directory rollup and a SUGGESTED SLICING outright ({@link planSlices}) — grouping
|
|
24
|
+
// changed files is mechanical, and doing it here costs zero model turns.
|
|
25
|
+
// 3. Reference material is per-slice, so it must be readable per-slice. Existing review
|
|
26
|
+
// threads are grouped under a path index, and best-practice standards go to one file each,
|
|
27
|
+
// so a subagent greps or reads only its own — rather than the parent reading the whole lot
|
|
28
|
+
// into a context that then carries it for every remaining turn.
|
|
29
|
+
// ---------------------------------------------------------------------------
|
|
30
|
+
/** The injected context file (under `.cat-context/`) the diff preOp writes for the reviewer. */
|
|
31
|
+
export const PR_DIFF_CONTEXT_FILE = 'pr-diff.md';
|
|
32
|
+
/** The injected context file listing the PR's already-posted review comments (for de-dup). */
|
|
33
|
+
export const PR_EXISTING_COMMENTS_CONTEXT_FILE = 'pr-existing-comments.md';
|
|
34
|
+
/**
|
|
35
|
+
* Filename prefix for the per-standard context files the standards preOp writes. Re-exports the
|
|
36
|
+
* SHARED convention (`@cat-factory/agents` `fragments.ts`) so `standardsDeliveredAsFiles` — which
|
|
37
|
+
* decides whether to fold standards into the prompt as a fallback — recognises what this preOp
|
|
38
|
+
* writes without knowing anything pr-review-specific.
|
|
39
|
+
*/
|
|
40
|
+
export const PR_STANDARD_CONTEXT_PREFIX = STANDARDS_CONTEXT_FILE_PREFIX;
|
|
41
|
+
/**
|
|
42
|
+
* Total inlined-patch budget. Under it, the WHOLE diff is inlined and a small PR is reviewable
|
|
43
|
+
* in one pass with no git turns at all. Over it, no patch is inlined: the reviewer slices from
|
|
44
|
+
* the manifest and each slice reads only its own files from the checkout — which is what the
|
|
45
|
+
* parallel slice subagents do regardless, so inlining more only pays for the same bytes twice.
|
|
46
|
+
*/
|
|
47
|
+
const MAX_INLINE_DIFF_BYTES = 64 * 1024;
|
|
48
|
+
/** Per-file inline cap: one generated blob (a lockfile, a snapshot) never crowds out the rest. */
|
|
49
|
+
const MAX_SINGLE_PATCH_BYTES = 32 * 1024;
|
|
50
|
+
/**
|
|
51
|
+
* Byte budget for the injected existing-comments file. Review threads are short prose, so this is
|
|
52
|
+
* generous; past it, the remaining threads are summarised as a count so the file never dominates
|
|
53
|
+
* the context on a PR with a very long comment history.
|
|
54
|
+
*/
|
|
55
|
+
const MAX_EXISTING_COMMENTS_BYTES = 64 * 1024;
|
|
56
|
+
/** Path depth a suggested slice groups at — `src/Foo.Bar/Baz/x.cs` groups under `src/Foo.Bar`. */
|
|
57
|
+
const SLICE_GROUP_DEPTH = 2;
|
|
58
|
+
/** A suggested slice is split once it exceeds either budget, so no single slice dwarfs the rest. */
|
|
59
|
+
const SLICE_MAX_FILES = 20;
|
|
60
|
+
const SLICE_MAX_CHANGED_LINES = 2_500;
|
|
61
|
+
/** Groups smaller than this are merged into a shared "assorted" slice rather than standing alone. */
|
|
62
|
+
const SLICE_MIN_FILES = 2;
|
|
63
|
+
// ---------------------------------------------------------------------------
|
|
64
|
+
// PR number resolution
|
|
65
|
+
// ---------------------------------------------------------------------------
|
|
66
|
+
/** Resolve the reviewed PR's number from the block's task-type fields (prefer `prNumber`). */
|
|
67
|
+
export function resolvePrNumber(fields) {
|
|
68
|
+
if (!fields)
|
|
69
|
+
return null;
|
|
70
|
+
if (typeof fields.prNumber === 'number' &&
|
|
71
|
+
Number.isInteger(fields.prNumber) &&
|
|
72
|
+
fields.prNumber > 0)
|
|
73
|
+
return fields.prNumber;
|
|
74
|
+
const url = fields.prUrl?.trim();
|
|
75
|
+
if (!url)
|
|
76
|
+
return null;
|
|
77
|
+
// GitHub `/pull/<n>`, GitLab `/-/merge_requests/<n>`, or a trailing `#<n>` / `/<n>`.
|
|
78
|
+
const m = url.match(/(?:pull|pulls|merge_requests)\/(\d+)|[#/](\d+)\s*$/);
|
|
79
|
+
const raw = m?.[1] ?? m?.[2];
|
|
80
|
+
const n = raw ? Number(raw) : Number.NaN;
|
|
81
|
+
return Number.isInteger(n) && n > 0 ? n : null;
|
|
82
|
+
}
|
|
83
|
+
/** The directory a path groups under: its leading {@link SLICE_GROUP_DEPTH} segments. */
|
|
84
|
+
function groupKey(path) {
|
|
85
|
+
const segments = path.split('/');
|
|
86
|
+
segments.pop(); // the filename
|
|
87
|
+
if (segments.length === 0)
|
|
88
|
+
return '(repo root)';
|
|
89
|
+
return segments.slice(0, SLICE_GROUP_DEPTH).join('/');
|
|
90
|
+
}
|
|
91
|
+
function changedLinesOf(file) {
|
|
92
|
+
return file.additions + file.deletions;
|
|
93
|
+
}
|
|
94
|
+
/**
|
|
95
|
+
* Group the changed files into candidate review slices, deterministically and with no model
|
|
96
|
+
* turns. Files group by their leading path segments (the project / module / top-level area),
|
|
97
|
+
* one-off groups collapse into a shared `assorted` slice, and any group over
|
|
98
|
+
* {@link SLICE_MAX_FILES} / {@link SLICE_MAX_CHANGED_LINES} is split into numbered parts.
|
|
99
|
+
*
|
|
100
|
+
* This is a SUGGESTION the reviewer may regroup — path adjacency is a good proxy for
|
|
101
|
+
* "belongs together" but it cannot see that a refactor and its call sites live apart. Its
|
|
102
|
+
* value is that the reviewer starts from a usable grouping instead of probing the file list
|
|
103
|
+
* to build one, and that the size caps stop a single oversized slice forming: cost scales with
|
|
104
|
+
* turns × context, so one slice big enough to need 100+ turns costs more than three that
|
|
105
|
+
* replace it.
|
|
106
|
+
*/
|
|
107
|
+
export function planSlices(files) {
|
|
108
|
+
const groups = new Map();
|
|
109
|
+
for (const file of files) {
|
|
110
|
+
const key = groupKey(file.path);
|
|
111
|
+
const bucket = groups.get(key);
|
|
112
|
+
if (bucket)
|
|
113
|
+
bucket.push(file);
|
|
114
|
+
else
|
|
115
|
+
groups.set(key, [file]);
|
|
116
|
+
}
|
|
117
|
+
// Collapse one-off groups together: a slice per single changed file is pure overhead.
|
|
118
|
+
const assorted = [];
|
|
119
|
+
const named = [];
|
|
120
|
+
for (const [key, bucket] of groups) {
|
|
121
|
+
if (bucket.length < SLICE_MIN_FILES)
|
|
122
|
+
assorted.push(...bucket);
|
|
123
|
+
else
|
|
124
|
+
named.push([key, bucket]);
|
|
125
|
+
}
|
|
126
|
+
if (assorted.length)
|
|
127
|
+
named.push(['assorted', assorted]);
|
|
128
|
+
const slices = [];
|
|
129
|
+
for (const [key, bucket] of named) {
|
|
130
|
+
// Largest-first within a group, so a split keeps the heavy files spread across parts
|
|
131
|
+
// rather than stacking them all into part 1.
|
|
132
|
+
const sorted = [...bucket].sort((a, b) => changedLinesOf(b) - changedLinesOf(a));
|
|
133
|
+
const parts = [[]];
|
|
134
|
+
let lines = 0;
|
|
135
|
+
for (const file of sorted) {
|
|
136
|
+
const current = parts[parts.length - 1];
|
|
137
|
+
const wouldExceed = current.length >= SLICE_MAX_FILES ||
|
|
138
|
+
(current.length > 0 && lines + changedLinesOf(file) > SLICE_MAX_CHANGED_LINES);
|
|
139
|
+
if (wouldExceed) {
|
|
140
|
+
parts.push([file]);
|
|
141
|
+
lines = changedLinesOf(file);
|
|
142
|
+
}
|
|
143
|
+
else {
|
|
144
|
+
current.push(file);
|
|
145
|
+
lines += changedLinesOf(file);
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
for (const [index, part] of parts.entries()) {
|
|
149
|
+
if (part.length === 0)
|
|
150
|
+
continue;
|
|
151
|
+
slices.push({
|
|
152
|
+
title: parts.length > 1 ? `${key} (part ${index + 1})` : key,
|
|
153
|
+
// Back to path order within the slice, so the list reads like the repo.
|
|
154
|
+
paths: part.map((f) => f.path).sort(),
|
|
155
|
+
changedLines: part.reduce((sum, f) => sum + changedLinesOf(f), 0),
|
|
156
|
+
});
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
return slices.sort((a, b) => b.changedLines - a.changedLines);
|
|
160
|
+
}
|
|
161
|
+
// ---------------------------------------------------------------------------
|
|
162
|
+
// `.cat-context/pr-diff.md`
|
|
163
|
+
// ---------------------------------------------------------------------------
|
|
164
|
+
/** Per-directory rollup of the change, so the reviewer sees the shape without probing. */
|
|
165
|
+
function renderDirectoryRollup(files) {
|
|
166
|
+
const rollup = new Map();
|
|
167
|
+
for (const file of files) {
|
|
168
|
+
const key = groupKey(file.path);
|
|
169
|
+
const entry = rollup.get(key) ?? { files: 0, lines: 0 };
|
|
170
|
+
entry.files += 1;
|
|
171
|
+
entry.lines += changedLinesOf(file);
|
|
172
|
+
rollup.set(key, entry);
|
|
173
|
+
}
|
|
174
|
+
const rows = [...rollup.entries()].sort((a, b) => b[1].lines - a[1].lines);
|
|
175
|
+
return [
|
|
176
|
+
`\n## Change shape (${rows.length} areas)\n`,
|
|
177
|
+
...rows.map(([key, e]) => `- ${key} — ${e.files} file(s), ${e.lines} changed line(s)`),
|
|
178
|
+
];
|
|
179
|
+
}
|
|
180
|
+
function renderSuggestedSlices(slices) {
|
|
181
|
+
return [
|
|
182
|
+
`\n## Suggested slicing (${slices.length} slices)\n`,
|
|
183
|
+
'Grouped mechanically by path and capped by size, so you can start from it instead of',
|
|
184
|
+
'deriving one. REGROUP where you know better — a refactor and its call sites often live in',
|
|
185
|
+
'different areas — but do not exceed these sizes: an oversized slice costs more than the two',
|
|
186
|
+
'that would replace it, because every extra turn re-sends the whole slice context.\n',
|
|
187
|
+
...slices.map((s) => `- **${s.title}** (${s.paths.length} file(s), ${s.changedLines} changed line(s))\n` +
|
|
188
|
+
s.paths.map((p) => ` - ${p}`).join('\n')),
|
|
189
|
+
];
|
|
190
|
+
}
|
|
191
|
+
/** The header for the manifest-only (large PR) shape: how to read a slice's diffs from git. */
|
|
192
|
+
function largePrGuidance(files, bytes) {
|
|
193
|
+
return (`\n## Patches — NOT inlined (${files} files, ~${Math.ceil(bytes / 1024)} KiB of patch)\n\n` +
|
|
194
|
+
'This diff is too large to inline: it would sit in context for every turn of the review while ' +
|
|
195
|
+
'each slice needs only its own files. Read each slice’s diff when you review that slice:\n\n' +
|
|
196
|
+
'```sh\n' +
|
|
197
|
+
'git diff origin/<base>...origin/pr-head -- <path> # the head diff for one file\n' +
|
|
198
|
+
'git show origin/pr-head:<path> # a file’s full body at the PR head\n' +
|
|
199
|
+
'```\n\n' +
|
|
200
|
+
"Read a RANGE, not a whole large file (`| sed -n '<from>,<to>p'`), and never re-read something " +
|
|
201
|
+
'you already have — both stay in context for the rest of the review.\n');
|
|
202
|
+
}
|
|
203
|
+
/**
|
|
204
|
+
* Render the changed-file list, the change shape, a suggested slicing, and — only for a diff
|
|
205
|
+
* small enough to review in one pass — the patches, as the injected `.cat-context/pr-diff.md`.
|
|
206
|
+
* See the module header for why the patch budget is all-or-nothing.
|
|
207
|
+
*/
|
|
208
|
+
export function renderPrDiffContext(number, files) {
|
|
209
|
+
const enc = new TextEncoder();
|
|
210
|
+
// Oversized single patches never inline, and never count toward the inline decision — one
|
|
211
|
+
// generated blob must not push an otherwise-small PR onto the manifest-only path.
|
|
212
|
+
const inlinable = files.filter((f) => f.patch != null && enc.encode(f.patch).length <= MAX_SINGLE_PATCH_BYTES);
|
|
213
|
+
const inlineBytes = inlinable.reduce((sum, f) => sum + enc.encode(f.patch ?? '').length, 0);
|
|
214
|
+
const inlinePatches = inlineBytes <= MAX_INLINE_DIFF_BYTES;
|
|
215
|
+
// The manifest-only header reports the WHOLE patch size (incl. over-cap blobs), not just the
|
|
216
|
+
// inlinable slice, so the "~N KiB of patch" figure matches the diff the reviewer is told to
|
|
217
|
+
// read from git rather than understating it by the size of the excluded lockfile/snapshot.
|
|
218
|
+
const totalPatchBytes = files.reduce((sum, f) => sum + enc.encode(f.patch ?? '').length, 0);
|
|
219
|
+
const header = `# Pull request #${number} — changed files and diff\n\n` +
|
|
220
|
+
'Prepared from the API so you can plan your review slices WITHOUT reconstructing the diff ' +
|
|
221
|
+
'yourself. You have the full base checkout AND (usually) the PR head fetched as ' +
|
|
222
|
+
'`origin/pr-head`.\n';
|
|
223
|
+
const list = [
|
|
224
|
+
`\n## Changed files (${files.length})\n`,
|
|
225
|
+
...files.map((f) => {
|
|
226
|
+
const rename = f.previousPath ? ` (renamed from ${f.previousPath})` : '';
|
|
227
|
+
return `- ${f.status} ${f.path} (+${f.additions}/-${f.deletions})${rename}`;
|
|
228
|
+
}),
|
|
229
|
+
];
|
|
230
|
+
const sections = [
|
|
231
|
+
header,
|
|
232
|
+
list.join('\n'),
|
|
233
|
+
renderDirectoryRollup(files).join('\n'),
|
|
234
|
+
renderSuggestedSlices(planSlices(files)).join('\n'),
|
|
235
|
+
];
|
|
236
|
+
if (!inlinePatches) {
|
|
237
|
+
sections.push(largePrGuidance(files.length, totalPatchBytes));
|
|
238
|
+
return `${sections.join('\n')}\n`;
|
|
239
|
+
}
|
|
240
|
+
const patches = ['\n## Patches\n'];
|
|
241
|
+
for (const f of files) {
|
|
242
|
+
const heading = `\n### ${f.path} (${f.status}, +${f.additions}/-${f.deletions})\n`;
|
|
243
|
+
if (f.patch == null) {
|
|
244
|
+
patches.push(`${heading}(no patch — binary or too large; read the file from the checkout)\n`);
|
|
245
|
+
}
|
|
246
|
+
else if (enc.encode(f.patch).length > MAX_SINGLE_PATCH_BYTES) {
|
|
247
|
+
const kib = Math.ceil(enc.encode(f.patch).length / 1024);
|
|
248
|
+
patches.push(`${heading}(patch ~${kib} KiB — over the per-file inline budget; read it with ` +
|
|
249
|
+
'`git show origin/pr-head:<path>`)\n');
|
|
250
|
+
}
|
|
251
|
+
else {
|
|
252
|
+
patches.push(`${heading}\`\`\`diff\n${f.patch}\n\`\`\`\n`);
|
|
253
|
+
}
|
|
254
|
+
}
|
|
255
|
+
sections.push(patches.join(''));
|
|
256
|
+
return `${sections.join('\n')}\n`;
|
|
257
|
+
}
|
|
258
|
+
// ---------------------------------------------------------------------------
|
|
259
|
+
// `.cat-context/pr-existing-comments.md`
|
|
260
|
+
// ---------------------------------------------------------------------------
|
|
261
|
+
/** A single review-thread comment's body, trimmed + collapsed to a one-liner excerpt for the list. */
|
|
262
|
+
function commentExcerpt(body, max = 500) {
|
|
263
|
+
const flat = body.trim().replace(/\s+/g, ' ');
|
|
264
|
+
return flat.length > max ? `${flat.slice(0, max)}…` : flat;
|
|
265
|
+
}
|
|
266
|
+
function renderThread(thread) {
|
|
267
|
+
const anchor = thread.path
|
|
268
|
+
? `${thread.path}${thread.line != null ? `:${thread.line}` : ''}`
|
|
269
|
+
: 'general';
|
|
270
|
+
const state = thread.isResolved ? 'RESOLVED' : 'UNRESOLVED';
|
|
271
|
+
const first = thread.comments[0];
|
|
272
|
+
const author = first?.author ? `@${first.author}` : 'unknown';
|
|
273
|
+
const excerpt = first ? commentExcerpt(first.body) : '(no comment body)';
|
|
274
|
+
const extra = thread.comments.length - 1;
|
|
275
|
+
const replies = extra > 0 ? ` (+${extra} repl${extra === 1 ? 'y' : 'ies'})` : '';
|
|
276
|
+
return `\n### ${anchor} — ${state}\n${author}${replies}: ${excerpt}\n`;
|
|
277
|
+
}
|
|
278
|
+
/**
|
|
279
|
+
* Render the PR's existing review threads as `.cat-context/pr-existing-comments.md`, so the
|
|
280
|
+
* reviewer de-dups against findings already raised (prior rounds / humans / other bots).
|
|
281
|
+
*
|
|
282
|
+
* Threads are GROUPED BY FILE under a path index. De-dup is a per-slice concern, so a slice
|
|
283
|
+
* reviewer should grep out the handful of threads on its own paths; reading the whole file
|
|
284
|
+
* into the parent's context makes every remaining turn of the review pay for all of them.
|
|
285
|
+
*/
|
|
286
|
+
export function renderExistingReviewComments(number, threads) {
|
|
287
|
+
const header = `# Pull request #${number} — existing review comments\n\n` +
|
|
288
|
+
'These findings have ALREADY been raised on this PR (earlier rounds, human reviewers, or other ' +
|
|
289
|
+
'bots). Do NOT re-report an issue an existing comment already covers. Skip UNRESOLVED threads ' +
|
|
290
|
+
'(already awaiting action); re-raise a RESOLVED thread only if the change shows its fix is wrong ' +
|
|
291
|
+
'or incomplete.\n\n' +
|
|
292
|
+
'Threads are grouped by file below. When reviewing ONE slice, read only that slice’s files — ' +
|
|
293
|
+
'`grep -n -A2 "^### <path>" .cat-context/pr-existing-comments.md` — rather than the whole file.\n';
|
|
294
|
+
// Insertion-ordered by first appearance, so the index reads in the order the API returned.
|
|
295
|
+
const byPath = new Map();
|
|
296
|
+
for (const thread of threads) {
|
|
297
|
+
const key = thread.path ?? '(general)';
|
|
298
|
+
const bucket = byPath.get(key);
|
|
299
|
+
if (bucket)
|
|
300
|
+
bucket.push(thread);
|
|
301
|
+
else
|
|
302
|
+
byPath.set(key, [thread]);
|
|
303
|
+
}
|
|
304
|
+
const index = [
|
|
305
|
+
`\n## Files with existing threads (${byPath.size})\n`,
|
|
306
|
+
...[...byPath.entries()].map(([path, list]) => `- ${path} (${list.length} thread(s))`),
|
|
307
|
+
];
|
|
308
|
+
const enc = new TextEncoder();
|
|
309
|
+
let bytes = 0;
|
|
310
|
+
let omitted = 0;
|
|
311
|
+
const sections = [`\n## Threads (${threads.length})\n`];
|
|
312
|
+
for (const [path, list] of byPath) {
|
|
313
|
+
const block = `\n## ${path}\n${list.map(renderThread).join('')}`;
|
|
314
|
+
const size = enc.encode(block).length;
|
|
315
|
+
if (bytes + size > MAX_EXISTING_COMMENTS_BYTES) {
|
|
316
|
+
omitted += list.length;
|
|
317
|
+
continue;
|
|
318
|
+
}
|
|
319
|
+
bytes += size;
|
|
320
|
+
sections.push(block);
|
|
321
|
+
}
|
|
322
|
+
const footer = omitted > 0
|
|
323
|
+
? `\n_${omitted} more thread(s) omitted to stay within the injected-context budget._\n`
|
|
324
|
+
: '';
|
|
325
|
+
return `${header}${index.join('\n')}\n${sections.join('')}${footer}`;
|
|
326
|
+
}
|
|
327
|
+
// ---------------------------------------------------------------------------
|
|
328
|
+
// `.cat-context/standard-<id>.md`
|
|
329
|
+
// ---------------------------------------------------------------------------
|
|
330
|
+
/** A short, stable base36 hash of a string — enough to disambiguate a sanitized-name collision. */
|
|
331
|
+
function shortHash(value) {
|
|
332
|
+
let h = 2166136261; // FNV-1a
|
|
333
|
+
for (let i = 0; i < value.length; i++) {
|
|
334
|
+
h ^= value.charCodeAt(i);
|
|
335
|
+
h = Math.imul(h, 16777619);
|
|
336
|
+
}
|
|
337
|
+
return (h >>> 0).toString(36);
|
|
338
|
+
}
|
|
339
|
+
/**
|
|
340
|
+
* The `.cat-context/` filename a resolved best-practice standard is written to. Non-portable
|
|
341
|
+
* characters are replaced with `-` so the name survives the harness's context-file sanitizer
|
|
342
|
+
* (it keeps only `[A-Za-z0-9._-]` and flattens any directory) unchanged — the name in the index
|
|
343
|
+
* is then the name on disk.
|
|
344
|
+
*
|
|
345
|
+
* When sanitizing ALTERS the id, two distinct ids can sanitize to the same slug (`org/team` and
|
|
346
|
+
* `org team` both → `org-team`); the harness drops the duplicate path, silently losing the second
|
|
347
|
+
* standard while the index still advertises it. So a short hash of the ORIGINAL id is appended
|
|
348
|
+
* whenever the slug differs from the id, making the filename unique per id. An already-safe id is
|
|
349
|
+
* left untouched (no suffix), so the common case stays readable.
|
|
350
|
+
*/
|
|
351
|
+
export function standardsContextFileName(fragmentId) {
|
|
352
|
+
const slug = fragmentId.replace(/[^A-Za-z0-9._-]/g, '-').replace(/^[.-]+/, '') || 'unnamed';
|
|
353
|
+
const suffix = slug === fragmentId ? '' : `-${shortHash(fragmentId)}`;
|
|
354
|
+
return `${PR_STANDARD_CONTEXT_PREFIX}${slug}${suffix}.md`;
|
|
355
|
+
}
|
|
356
|
+
/** Render one standard as its own context file, with the title the reviewer cites it by. */
|
|
357
|
+
export function renderStandardContext(fragment) {
|
|
358
|
+
const title = fragment.title?.trim() || fragment.id;
|
|
359
|
+
return (`# ${title}\n\n` +
|
|
360
|
+
`Best-practice standard \`${fragment.id}\`, selected for this review task. Cite it by its ` +
|
|
361
|
+
'title in `fragmentAdherence`.\n\n' +
|
|
362
|
+
'---\n\n' +
|
|
363
|
+
`${fragment.body.trim()}\n`);
|
|
364
|
+
}
|
|
365
|
+
/** Render the index that tells the reviewer which standards exist and where each one is. */
|
|
366
|
+
export function renderStandardsIndex(fragments) {
|
|
367
|
+
return ('# Best-practice standards for this review\n\n' +
|
|
368
|
+
'These are the standards this review is judged against. Each is a SEPARATE file so a slice ' +
|
|
369
|
+
'reviewer reads only the ones its slice needs — do not read them all into one context.\n\n' +
|
|
370
|
+
'When you dispatch a slice reviewer, name the standards that apply to that slice and tell it ' +
|
|
371
|
+
'to READ those files itself. Do NOT paraphrase a standard into the subagent’s prompt: a ' +
|
|
372
|
+
'summary is not the standard, and `fragmentAdherence` ratings must come from the real text.\n\n' +
|
|
373
|
+
fragments
|
|
374
|
+
.map((f) => `- **${f.title?.trim() || f.id}** (\`${f.id}\`) — \`.cat-context/${standardsContextFileName(f.id)}\``)
|
|
375
|
+
.join('\n') +
|
|
376
|
+
'\n');
|
|
377
|
+
}
|
|
378
|
+
/** The index file listing every injected standard (the shared `context-files` convention). */
|
|
379
|
+
export const PR_STANDARDS_INDEX_CONTEXT_FILE = STANDARDS_CONTEXT_INDEX_FILE;
|
|
380
|
+
// ---------------------------------------------------------------------------
|
|
381
|
+
// PreOps
|
|
382
|
+
// ---------------------------------------------------------------------------
|
|
383
|
+
/**
|
|
384
|
+
* PreOp for the `pr-reviewer` kind: hand the reviewer the PR's changed-file list, change shape and
|
|
385
|
+
* a suggested slicing as `.cat-context/pr-diff.md` (plus the patches when the whole diff is small
|
|
386
|
+
* enough to review in one pass). Pass-through — injecting nothing, so the prompt's git fallback
|
|
387
|
+
* runs — when the PR number can't be resolved, the bound client can't list changed files
|
|
388
|
+
* (unwired / a VCS provider without the capability), or the PR reports no changed files.
|
|
389
|
+
*/
|
|
390
|
+
export const prReviewerDiffPreOp = async (ctx) => {
|
|
391
|
+
const listChangedFiles = ctx.repo.listChangedFiles;
|
|
392
|
+
if (!listChangedFiles)
|
|
393
|
+
return;
|
|
394
|
+
const number = resolvePrNumber(ctx.context.block.taskTypeFields);
|
|
395
|
+
if (number == null)
|
|
396
|
+
return;
|
|
397
|
+
const files = await listChangedFiles(number);
|
|
398
|
+
if (!files.length)
|
|
399
|
+
return;
|
|
400
|
+
return {
|
|
401
|
+
contextFiles: [{ path: PR_DIFF_CONTEXT_FILE, content: renderPrDiffContext(number, files) }],
|
|
402
|
+
};
|
|
403
|
+
};
|
|
404
|
+
/**
|
|
405
|
+
* PreOp for the `pr-reviewer` kind: hand the reviewer the PR's EXISTING review threads up front as
|
|
406
|
+
* `.cat-context/pr-existing-comments.md`, grouped by file, so it de-dups against findings already
|
|
407
|
+
* raised instead of re-reporting them. Pass-through — injecting nothing — when the PR number can't
|
|
408
|
+
* be resolved, the bound client can't read review threads, or the PR has no review threads yet.
|
|
409
|
+
*/
|
|
410
|
+
export const prReviewerExistingCommentsPreOp = async (ctx) => {
|
|
411
|
+
const listReviewThreads = ctx.repo.listReviewThreads;
|
|
412
|
+
if (!listReviewThreads)
|
|
413
|
+
return;
|
|
414
|
+
const number = resolvePrNumber(ctx.context.block.taskTypeFields);
|
|
415
|
+
if (number == null)
|
|
416
|
+
return;
|
|
417
|
+
const threads = await listReviewThreads(number);
|
|
418
|
+
if (!threads.length)
|
|
419
|
+
return;
|
|
420
|
+
return {
|
|
421
|
+
contextFiles: [
|
|
422
|
+
{
|
|
423
|
+
path: PR_EXISTING_COMMENTS_CONTEXT_FILE,
|
|
424
|
+
content: renderExistingReviewComments(number, threads),
|
|
425
|
+
},
|
|
426
|
+
],
|
|
427
|
+
};
|
|
428
|
+
};
|
|
429
|
+
/**
|
|
430
|
+
* PreOp for the `pr-reviewer` kind: write the task's selected best-practice standards as one
|
|
431
|
+
* `.cat-context/standard-<id>.md` file each, plus an index.
|
|
432
|
+
*
|
|
433
|
+
* The reviewer's own prompt does NOT carry the standards (the kind declares
|
|
434
|
+
* `standardsDelivery: 'context-files'`, so the engine skips the fold). Folding them in charged
|
|
435
|
+
* the parent for every standard on every turn — 145 KB across 5 standards on the measured run,
|
|
436
|
+
* ~3.7M tokens over 96 turns — while the agents that actually review the code, the parallel slice
|
|
437
|
+
* subagents, never received them and worked from the parent's one-line paraphrase instead. As
|
|
438
|
+
* files, each standard is read once by the slices it applies to, from the real text.
|
|
439
|
+
*
|
|
440
|
+
* Pass-through when the run resolved no fragments (a review task with none selected).
|
|
441
|
+
*/
|
|
442
|
+
export const prReviewerStandardsPreOp = async (ctx) => {
|
|
443
|
+
const fragments = ctx.context.block.resolvedFragments ?? [];
|
|
444
|
+
if (!fragments.length)
|
|
445
|
+
return;
|
|
446
|
+
return {
|
|
447
|
+
contextFiles: [
|
|
448
|
+
{ path: PR_STANDARDS_INDEX_CONTEXT_FILE, content: renderStandardsIndex(fragments) },
|
|
449
|
+
...fragments.map((fragment) => ({
|
|
450
|
+
path: standardsContextFileName(fragment.id),
|
|
451
|
+
content: renderStandardContext(fragment),
|
|
452
|
+
})),
|
|
453
|
+
],
|
|
454
|
+
};
|
|
455
|
+
};
|
|
456
|
+
//# sourceMappingURL=pr-review-context.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"pr-review-context.js","sourceRoot":"","sources":["../../../src/agents/kinds/pr-review-context.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import type { GitHubChangedFile, GitHubReviewThread, RepoOp } from '@cat-factory/kernel';
|
|
2
1
|
import type { AgentKindDefinition, AgentKindRegistry } from './registry.js';
|
|
3
2
|
export declare const PR_REVIEWER_KIND = "pr-reviewer";
|
|
4
3
|
/**
|
|
@@ -34,44 +33,11 @@ export declare const prReview: import("./structured-output.js").StructuredOutput
|
|
|
34
33
|
}>;
|
|
35
34
|
export type PrReviewOutput = ReturnType<typeof prReview.parse>;
|
|
36
35
|
export declare const PR_REVIEWER_SYSTEM_PROMPT: string;
|
|
37
|
-
/** The injected context file (under `.cat-context/`) the diff preOp writes for the reviewer. */
|
|
38
|
-
export declare const PR_DIFF_CONTEXT_FILE = "pr-diff.md";
|
|
39
|
-
/** The injected context file listing the PR's already-posted review comments (for de-dup). */
|
|
40
|
-
export declare const PR_EXISTING_COMMENTS_CONTEXT_FILE = "pr-existing-comments.md";
|
|
41
|
-
/** Resolve the reviewed PR's number from the block's task-type fields (prefer `prNumber`). */
|
|
42
|
-
export declare function resolvePrNumber(fields: {
|
|
43
|
-
prNumber?: number;
|
|
44
|
-
prUrl?: string;
|
|
45
|
-
} | undefined): number | null;
|
|
46
|
-
/** Render the changed-file list + budgeted patches as the injected `.cat-context/pr-diff.md`. */
|
|
47
|
-
export declare function renderPrDiffContext(number: number, files: GitHubChangedFile[]): string;
|
|
48
|
-
/**
|
|
49
|
-
* PreOp for the `pr-reviewer` kind: hand the reviewer the PR's changed-file list + diff UP FRONT
|
|
50
|
-
* as `.cat-context/pr-diff.md`, so the container agent skips the early `git fetch`/`git diff`/
|
|
51
|
-
* scratch-file reconstruction turns that dominate a long review's token burn (each agentic turn
|
|
52
|
-
* re-sends the whole growing transcript). Pass-through — injecting nothing, so the prompt's git
|
|
53
|
-
* fallback runs — when the PR number can't be resolved, the bound client can't list changed files
|
|
54
|
-
* (unwired / a VCS provider without the capability), or the PR reports no changed files.
|
|
55
|
-
*/
|
|
56
|
-
export declare const prReviewerDiffPreOp: RepoOp;
|
|
57
|
-
/**
|
|
58
|
-
* Render the PR's existing review threads as the injected `.cat-context/pr-existing-comments.md`, so
|
|
59
|
-
* the reviewer can de-dup against findings already raised (prior rounds / humans / other bots). Each
|
|
60
|
-
* thread shows its anchor (path:line, or "general"), resolved state and the opening comment's text.
|
|
61
|
-
*/
|
|
62
|
-
export declare function renderExistingReviewComments(number: number, threads: GitHubReviewThread[]): string;
|
|
63
|
-
/**
|
|
64
|
-
* PreOp for the `pr-reviewer` kind: hand the reviewer the PR's EXISTING review threads up front as
|
|
65
|
-
* `.cat-context/pr-existing-comments.md`, so it de-dups against findings already raised (prior
|
|
66
|
-
* review rounds, human reviewers, other bots) instead of re-reporting them. Pass-through — injecting
|
|
67
|
-
* nothing — when the PR number can't be resolved, the bound client can't read review threads
|
|
68
|
-
* (unwired / a VCS provider without the capability), or the PR has no review threads yet.
|
|
69
|
-
*/
|
|
70
|
-
export declare const prReviewerExistingCommentsPreOp: RepoOp;
|
|
71
36
|
export declare const PR_REVIEWER_AGENT_KINDS: AgentKindDefinition[];
|
|
72
37
|
/**
|
|
73
38
|
* Register the pr-reviewer kind on the given registry. Called by `defaultAgentKindRegistry()`;
|
|
74
39
|
* idempotent (the registry replaces by kind).
|
|
75
40
|
*/
|
|
76
41
|
export declare function registerPrReviewerAgent(registry: AgentKindRegistry): void;
|
|
42
|
+
export { PR_DIFF_CONTEXT_FILE, PR_EXISTING_COMMENTS_CONTEXT_FILE, PR_STANDARDS_INDEX_CONTEXT_FILE, planSlices, prReviewerDiffPreOp, prReviewerExistingCommentsPreOp, prReviewerStandardsPreOp, renderExistingReviewComments, renderPrDiffContext, renderStandardContext, renderStandardsIndex, resolvePrNumber, standardsContextFileName, type SuggestedSlice, } from './pr-review-context.js';
|
|
77
43
|
//# sourceMappingURL=pr-reviewer.d.ts.map
|