clud-bug 0.6.34 → 0.7.0-rc.11

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.
Files changed (153) hide show
  1. package/README.md +20 -0
  2. package/bin/clud-bug.js +10 -1353
  3. package/data/canonical-v1.json +37 -0
  4. package/dist/cli/agents-md.d.ts +16 -0
  5. package/dist/cli/agents-md.d.ts.map +1 -0
  6. package/dist/cli/agents-md.js +226 -0
  7. package/dist/cli/agents-md.js.map +1 -0
  8. package/dist/cli/audit.d.ts +13 -0
  9. package/dist/cli/audit.d.ts.map +1 -0
  10. package/dist/cli/audit.js +90 -0
  11. package/dist/cli/audit.js.map +1 -0
  12. package/dist/cli/branch-protection.d.ts +57 -0
  13. package/dist/cli/branch-protection.d.ts.map +1 -0
  14. package/dist/cli/branch-protection.js +118 -0
  15. package/dist/cli/branch-protection.js.map +1 -0
  16. package/dist/cli/configure-github.d.ts +58 -0
  17. package/dist/cli/configure-github.d.ts.map +1 -0
  18. package/dist/cli/configure-github.js +242 -0
  19. package/dist/cli/configure-github.js.map +1 -0
  20. package/dist/cli/edit-workflow.d.ts +18 -0
  21. package/dist/cli/edit-workflow.d.ts.map +1 -0
  22. package/dist/cli/edit-workflow.js +43 -0
  23. package/dist/cli/edit-workflow.js.map +1 -0
  24. package/dist/cli/index.d.ts +9 -0
  25. package/dist/cli/index.d.ts.map +1 -0
  26. package/dist/cli/index.js +19 -0
  27. package/dist/cli/index.js.map +1 -0
  28. package/dist/cli/main.d.ts +3 -0
  29. package/dist/cli/main.d.ts.map +1 -0
  30. package/dist/cli/main.js +2067 -0
  31. package/dist/cli/main.js.map +1 -0
  32. package/dist/cli/skill-usage.d.ts +109 -0
  33. package/dist/cli/skill-usage.d.ts.map +1 -0
  34. package/dist/cli/skill-usage.js +380 -0
  35. package/dist/cli/skill-usage.js.map +1 -0
  36. package/dist/cli/skills.d.ts +56 -0
  37. package/dist/cli/skills.d.ts.map +1 -0
  38. package/dist/cli/skills.js +292 -0
  39. package/dist/cli/skills.js.map +1 -0
  40. package/dist/cli/update.d.ts +29 -0
  41. package/dist/cli/update.d.ts.map +1 -0
  42. package/dist/cli/update.js +205 -0
  43. package/dist/cli/update.js.map +1 -0
  44. package/dist/cli/usage.d.ts +142 -0
  45. package/dist/cli/usage.d.ts.map +1 -0
  46. package/dist/cli/usage.js +348 -0
  47. package/dist/cli/usage.js.map +1 -0
  48. package/dist/core/audit.d.ts +8 -0
  49. package/dist/core/audit.d.ts.map +1 -0
  50. package/dist/core/audit.js +47 -0
  51. package/dist/core/audit.js.map +1 -0
  52. package/dist/core/auto-resolve.d.ts +235 -0
  53. package/dist/core/auto-resolve.d.ts.map +1 -0
  54. package/dist/core/auto-resolve.js +293 -0
  55. package/dist/core/auto-resolve.js.map +1 -0
  56. package/dist/core/configure-github.d.ts +179 -0
  57. package/dist/core/configure-github.d.ts.map +1 -0
  58. package/dist/core/configure-github.js +289 -0
  59. package/dist/core/configure-github.js.map +1 -0
  60. package/dist/core/detect.d.ts +77 -0
  61. package/dist/core/detect.d.ts.map +1 -0
  62. package/dist/core/detect.js +262 -0
  63. package/dist/core/detect.js.map +1 -0
  64. package/dist/core/diff-findings.d.ts +96 -0
  65. package/dist/core/diff-findings.d.ts.map +1 -0
  66. package/dist/core/diff-findings.js +261 -0
  67. package/dist/core/diff-findings.js.map +1 -0
  68. package/dist/core/formal-review.d.ts +79 -0
  69. package/dist/core/formal-review.d.ts.map +1 -0
  70. package/dist/core/formal-review.js +71 -0
  71. package/dist/core/formal-review.js.map +1 -0
  72. package/dist/core/index.d.ts +17 -0
  73. package/dist/core/index.d.ts.map +1 -0
  74. package/dist/core/index.js +66 -0
  75. package/dist/core/index.js.map +1 -0
  76. package/dist/core/inline-threads.d.ts +160 -0
  77. package/dist/core/inline-threads.d.ts.map +1 -0
  78. package/dist/core/inline-threads.js +369 -0
  79. package/dist/core/inline-threads.js.map +1 -0
  80. package/dist/core/prompt-builder.d.ts +164 -0
  81. package/dist/core/prompt-builder.d.ts.map +1 -0
  82. package/dist/core/prompt-builder.js +419 -0
  83. package/dist/core/prompt-builder.js.map +1 -0
  84. package/dist/core/prompts.d.ts +9 -0
  85. package/dist/core/prompts.d.ts.map +1 -0
  86. package/dist/core/prompts.js +401 -0
  87. package/dist/core/prompts.js.map +1 -0
  88. package/dist/core/render-review.d.ts +6 -0
  89. package/dist/core/render-review.d.ts.map +1 -0
  90. package/dist/core/render-review.js +219 -0
  91. package/dist/core/render-review.js.map +1 -0
  92. package/dist/core/render.d.ts +13 -0
  93. package/dist/core/render.d.ts.map +1 -0
  94. package/dist/core/render.js +62 -0
  95. package/dist/core/render.js.map +1 -0
  96. package/dist/core/resolve-verifier.d.ts +46 -0
  97. package/dist/core/resolve-verifier.d.ts.map +1 -0
  98. package/dist/core/resolve-verifier.js +187 -0
  99. package/dist/core/resolve-verifier.js.map +1 -0
  100. package/dist/core/review-schema-zod.d.ts +240 -0
  101. package/dist/core/review-schema-zod.d.ts.map +1 -0
  102. package/dist/core/review-schema-zod.js +218 -0
  103. package/dist/core/review-schema-zod.js.map +1 -0
  104. package/dist/core/review-schema.d.ts +42 -0
  105. package/dist/core/review-schema.d.ts.map +1 -0
  106. package/dist/core/review-schema.js +156 -0
  107. package/dist/core/review-schema.js.map +1 -0
  108. package/dist/core/review-writeback.d.ts +193 -0
  109. package/dist/core/review-writeback.d.ts.map +1 -0
  110. package/dist/core/review-writeback.js +364 -0
  111. package/dist/core/review-writeback.js.map +1 -0
  112. package/dist/core/skills.d.ts +147 -0
  113. package/dist/core/skills.d.ts.map +1 -0
  114. package/dist/core/skills.js +726 -0
  115. package/dist/core/skills.js.map +1 -0
  116. package/dist/core/version.d.ts +2 -0
  117. package/dist/core/version.d.ts.map +1 -0
  118. package/dist/core/version.js +4 -0
  119. package/dist/core/version.js.map +1 -0
  120. package/package.json +37 -5
  121. package/{lib/agents-md.js → src/cli/agents-md.ts} +25 -14
  122. package/{lib/audit.js → src/cli/audit.ts} +37 -44
  123. package/{lib/branch-protection.js → src/cli/branch-protection.ts} +75 -11
  124. package/src/cli/configure-github.ts +329 -0
  125. package/{lib/edit-workflow.js → src/cli/edit-workflow.ts} +32 -11
  126. package/src/cli/index.ts +107 -0
  127. package/src/cli/main.ts +2204 -0
  128. package/{lib/skill-usage.js → src/cli/skill-usage.ts} +168 -94
  129. package/src/cli/skills.ts +386 -0
  130. package/{lib/update.js → src/cli/update.ts} +87 -27
  131. package/{lib/usage.js → src/cli/usage.ts} +167 -76
  132. package/src/core/audit.ts +53 -0
  133. package/src/core/auto-resolve.ts +488 -0
  134. package/src/core/configure-github.ts +497 -0
  135. package/{lib/detect.js → src/core/detect.ts} +100 -47
  136. package/src/core/diff-findings.ts +323 -0
  137. package/src/core/formal-review.ts +168 -0
  138. package/src/core/index.ts +250 -0
  139. package/src/core/inline-threads.ts +471 -0
  140. package/src/core/prompt-builder.ts +561 -0
  141. package/{lib/prompts.js → src/core/prompts.ts} +16 -2
  142. package/{lib/render-review.js → src/core/render-review.ts} +57 -25
  143. package/{lib/render.js → src/core/render.ts} +37 -17
  144. package/src/core/resolve-verifier.ts +228 -0
  145. package/src/core/review-schema-zod.ts +262 -0
  146. package/{lib/review-schema.js → src/core/review-schema.ts} +68 -5
  147. package/src/core/review-writeback.ts +565 -0
  148. package/{lib/skills.js → src/core/skills.ts} +456 -342
  149. package/src/core/version.ts +3 -0
  150. package/templates/clud-bug-review.md.tmpl +115 -0
  151. package/templates/workflow-py.yml.tmpl +80 -3
  152. package/templates/workflow-ts.yml.tmpl +80 -3
  153. package/templates/workflow.yml.tmpl +175 -8
@@ -0,0 +1,369 @@
1
+ // Wave 5a — D.2.X inline review threads (npm workflow parity, OSS port).
2
+ //
3
+ // This module holds the pure helpers + GraphQL operation strings that BOTH
4
+ // the npm workflow path and the hosted clud-bug-app use to attach a
5
+ // per-finding inline review thread to the PR (replacing the legacy
6
+ // "one big summary comment listing every finding" UX).
7
+ //
8
+ // The split between npm and app:
9
+ // - npm path (this package's CLI verb `post-inline-threads`) is stateless:
10
+ // it shells out to `gh api` for the REST createReview + `gh api graphql`
11
+ // for the GraphQL thread-id lookup, then EXITS. No persistent record —
12
+ // Wave 5b's auto-resolve re-queries GitHub on the next push and re-derives
13
+ // finding IDs from the comment-body markers we embed here.
14
+ // - app path keeps its Redis-backed persistence for performance (cross-
15
+ // push thread correlation without re-querying GraphQL every time). The
16
+ // pure helpers below are designed so a future Wave 5c swap can have the
17
+ // App import from this module + drop its local duplicates.
18
+ //
19
+ // Designed to share `findingId` semantics with clud-bug-app's
20
+ // `lib/inline-threads.ts:findingId` (SHA-256 of the canonical 5-tuple,
21
+ // truncated to 16 hex chars) so threads posted by one consumer stay
22
+ // matchable by the other after the App migrates.
23
+ import { createHash } from 'node:crypto';
24
+ // ---------------------------------------------------------------------------
25
+ // Stable finding id — SHA-256 of the canonical 5-tuple, truncated to 16 hex.
26
+ // ---------------------------------------------------------------------------
27
+ /**
28
+ * Hashes the canonical `${file}:${line}:${severity}:${skill}:${summary[:100]}`
29
+ * tuple to 16 hex characters. Stable across consumers — the App computes
30
+ * the same hash for the same finding, so threads posted by one consumer
31
+ * stay matchable by the other.
32
+ *
33
+ * Summary is truncated to 100 chars BEFORE hashing so small wording tweaks
34
+ * on subsequent review passes don't generate a fresh id and orphan the
35
+ * prior thread.
36
+ *
37
+ * Distinct from `findingIdentity` in `./diff-findings` (which returns the
38
+ * plain unhashed string — used by the Resolved/Still-open block matcher).
39
+ * Both helpers coexist on purpose: the unhashed string is human-readable
40
+ * for in-prose matching; the hash is short + collision-safe for embedding
41
+ * in `<!-- finding-id: ... -->` comment-body markers.
42
+ */
43
+ export function findingId(finding) {
44
+ const file = finding.file ?? '<no-file>';
45
+ const line = finding.line ?? 0;
46
+ const summary = finding.summary.slice(0, 100);
47
+ const payload = `${file}:${line}:${finding.severity}:${finding.skill}:${summary}`;
48
+ return createHash('sha256').update(payload).digest('hex').slice(0, 16);
49
+ }
50
+ // ---------------------------------------------------------------------------
51
+ // Diff anchor detection
52
+ // ---------------------------------------------------------------------------
53
+ /**
54
+ * Returns the set of 1-indexed HEAD-side line numbers a unified-diff patch
55
+ * touches (added + context lines). GitHub only accepts inline review
56
+ * comments on lines that appear in the diff, so this gates whether a
57
+ * finding's `line` can become a thread.
58
+ *
59
+ * "Touched" = appears on the RIGHT side of the unified diff: added (`+`)
60
+ * lines OR unchanged context (` `) lines inside any hunk. Removed (`-`)
61
+ * lines are LEFT-side only and can't anchor inline comments.
62
+ *
63
+ * If `patch` is undefined (binary file, GitHub truncation) returns an empty
64
+ * set — the caller falls back to the summary comment for those findings.
65
+ */
66
+ export function parseHeadLines(patch) {
67
+ const lines = new Set();
68
+ if (!patch)
69
+ return lines;
70
+ // Hunk header: @@ -oldStart,oldLines +newStart,newLines @@
71
+ // newLines defaults to 1 when omitted.
72
+ const hunkHeaderRe = /^@@\s+-\d+(?:,\d+)?\s+\+(\d+)(?:,(\d+))?\s+@@/;
73
+ let newLine = 0;
74
+ let inHunk = false;
75
+ for (const rawLine of patch.split('\n')) {
76
+ const m = rawLine.match(hunkHeaderRe);
77
+ if (m) {
78
+ newLine = Number.parseInt(m[1], 10);
79
+ inHunk = true;
80
+ continue;
81
+ }
82
+ if (!inHunk)
83
+ continue;
84
+ if (rawLine.startsWith('+') && !rawLine.startsWith('+++')) {
85
+ lines.add(newLine);
86
+ newLine++;
87
+ }
88
+ else if (rawLine.startsWith('-') && !rawLine.startsWith('---')) {
89
+ // LEFT-side only — does not advance the newLine counter.
90
+ }
91
+ else if (rawLine.startsWith('\\')) {
92
+ // "" — doesn't advance.
93
+ }
94
+ else {
95
+ // Context line — counts as a HEAD-side line.
96
+ lines.add(newLine);
97
+ newLine++;
98
+ }
99
+ }
100
+ return lines;
101
+ }
102
+ /**
103
+ * Returns true when the finding's `(file, line)` can be anchored as an
104
+ * inline comment on the current diff. `diffFiles` is the per-file diff
105
+ * (as returned by `gh api repos/.../pulls/.../files`).
106
+ */
107
+ export function findingAnchorable(finding, diffFiles) {
108
+ if (!finding.file || !finding.line)
109
+ return false;
110
+ const file = diffFiles.find((f) => f.filename === finding.file);
111
+ if (!file)
112
+ return false;
113
+ return parseHeadLines(file.patch).has(finding.line);
114
+ }
115
+ // ---------------------------------------------------------------------------
116
+ // Context extraction for the verifier (consumed in Wave 5b)
117
+ // ---------------------------------------------------------------------------
118
+ /**
119
+ * Builds the `{codeBefore, codeAfter, diffAtAnchor?}` triple Wave 5b's
120
+ * auto-resolve verifier consumes for a single finding, pulled out of the
121
+ * unified-diff hunk that touches the finding's line.
122
+ *
123
+ * Works entirely from the in-hand patch — no fresh API calls. The patch
124
+ * already encodes BEFORE (lines with `-` or context) and AFTER (lines with
125
+ * `+` or context) for every hunk the PR touches.
126
+ *
127
+ * Returns empty strings for `codeBefore`/`codeAfter` when the finding's
128
+ * file isn't in the diff at all. The verifier sees "unchanged" and
129
+ * typically returns NOT_ADDRESSED / UNCERTAIN, which is the correct
130
+ * behavior — an unchanged file isn't a fix.
131
+ */
132
+ export function extractAnchorContext(finding, diffFiles) {
133
+ if (!finding.file || !finding.line) {
134
+ return { codeBefore: '', codeAfter: '' };
135
+ }
136
+ const file = diffFiles.find((f) => f.filename === finding.file);
137
+ if (!file || !file.patch) {
138
+ return { codeBefore: '', codeAfter: '' };
139
+ }
140
+ // Locate the hunk whose new-side range contains finding.line.
141
+ const hunkHeaderRe = /^@@\s+-(\d+)(?:,(\d+))?\s+\+(\d+)(?:,(\d+))?\s+@@/;
142
+ const patchLines = file.patch.split('\n');
143
+ let currentHunkStart = -1;
144
+ for (let i = 0; i < patchLines.length; i++) {
145
+ const m = patchLines[i].match(hunkHeaderRe);
146
+ if (!m)
147
+ continue;
148
+ const newStart = Number.parseInt(m[3], 10);
149
+ const newLen = m[4] !== undefined ? Number.parseInt(m[4], 10) : 1;
150
+ if (finding.line >= newStart &&
151
+ finding.line < newStart + Math.max(newLen, 1)) {
152
+ currentHunkStart = i;
153
+ break;
154
+ }
155
+ }
156
+ if (currentHunkStart < 0) {
157
+ return { codeBefore: '', codeAfter: '' };
158
+ }
159
+ const before = [];
160
+ const after = [];
161
+ const hunkBody = [patchLines[currentHunkStart]];
162
+ for (let i = currentHunkStart + 1; i < patchLines.length; i++) {
163
+ const line = patchLines[i];
164
+ if (line.match(hunkHeaderRe))
165
+ break;
166
+ hunkBody.push(line);
167
+ if (line.startsWith('+') && !line.startsWith('+++')) {
168
+ after.push(line.slice(1));
169
+ }
170
+ else if (line.startsWith('-') && !line.startsWith('---')) {
171
+ before.push(line.slice(1));
172
+ }
173
+ else if (line.startsWith('\\')) {
174
+ // No-newline marker — skip.
175
+ }
176
+ else if (line.length > 0) {
177
+ // Context line — appears on both sides.
178
+ const stripped = line.startsWith(' ') ? line.slice(1) : line;
179
+ before.push(stripped);
180
+ after.push(stripped);
181
+ }
182
+ }
183
+ return {
184
+ codeBefore: before.join('\n'),
185
+ codeAfter: after.join('\n'),
186
+ diffAtAnchor: hunkBody.join('\n'),
187
+ };
188
+ }
189
+ // ---------------------------------------------------------------------------
190
+ // Comment body rendering
191
+ // ---------------------------------------------------------------------------
192
+ /**
193
+ * Body for a single inline-thread comment. Includes a hidden HTML marker
194
+ * carrying `findingId` so Wave 5b's auto-resolve can recover the canonical
195
+ * id from the thread's first comment body without persisting state.
196
+ */
197
+ export function renderThreadBody(finding) {
198
+ const id = findingId(finding);
199
+ const severityBadge = finding.severity === 'critical' ? '🔴' : '🟡';
200
+ const header = `${severityBadge} \`${finding.skill}\``;
201
+ const body = finding.summary.trim();
202
+ const reasoning = finding.reasoning ? `\n\n${finding.reasoning.trim()}` : '';
203
+ return `<!-- finding-id: ${id} -->\n${header}\n\n${body}${reasoning}`;
204
+ }
205
+ /**
206
+ * Extracts the hashed `findingId` from a thread comment body that was
207
+ * rendered by `renderThreadBody`. Returns null when the marker is absent
208
+ * (a manual reply, or a comment posted by a different tool).
209
+ *
210
+ * Used by Wave 5b's auto-resolve to re-derive finding ids from existing
211
+ * GitHub threads on a stateless re-run.
212
+ */
213
+ export function extractFindingIdFromBody(body) {
214
+ // Anchor to start-of-string so a user reply that quotes the marker can't be
215
+ // misattributed as bot-authored. `renderThreadBody` always places the marker
216
+ // on line 1 — anything else is suspect input.
217
+ const m = body.match(/^<!--\s*finding-id:\s*([a-f0-9]{16})\s*-->/);
218
+ return m ? m[1] : null;
219
+ }
220
+ /**
221
+ * Wave 5b — invert `renderThreadBody` to recover the original finding
222
+ * tuple from a bot-authored thread comment. The fix-push auto-resolve
223
+ * CLI verb uses this to reconstruct `PriorFinding` from the GraphQL
224
+ * `reviewThreads` response without persistent state.
225
+ *
226
+ * Returns null when the body doesn't match the canonical shape
227
+ * `<!-- finding-id: XX -->\n🔴|🟡 \`skill\`\n\nsummary[\n\nreasoning]`.
228
+ * Same start-anchored posture as `extractFindingIdFromBody` for anti-
229
+ * injection: a user reply that quotes the marker mid-body won't be
230
+ * misattributed as bot-authored.
231
+ */
232
+ export function parseThreadBody(body) {
233
+ // Marker (line 1), header (line 2: badge + backticked skill), blank,
234
+ // summary, optional blank + reasoning. The header line shape:
235
+ // `🔴 \`critical-issues-only\`` or `🟡 \`magic-numbers\``
236
+ const re = /^<!--\s*finding-id:\s*([a-f0-9]{16})\s*-->\n(🔴|🟡)\s+`([^`]+)`\n\n([\s\S]+?)(?:\n\n([\s\S]+))?$/;
237
+ const m = body.match(re);
238
+ if (!m)
239
+ return null;
240
+ const [, findingId, badge, skill, summary, reasoning] = m;
241
+ const severity = badge === '🔴' ? 'critical' : 'minor';
242
+ const out = {
243
+ findingId: findingId,
244
+ severity,
245
+ skill: skill,
246
+ summary: summary.trim(),
247
+ };
248
+ if (reasoning && reasoning.trim())
249
+ out.reasoning = reasoning.trim();
250
+ return out;
251
+ }
252
+ /**
253
+ * Partitions a flat findings list into the `comments[]` body for
254
+ * `POST /repos/:owner/:repo/pulls/:n/reviews` + the findings the caller
255
+ * should surface elsewhere (summary comment for `skipped`; never for
256
+ * `preexisting`).
257
+ *
258
+ * Pure function — no I/O. The CLI verb uses this to compute the API body;
259
+ * the App can use it after Wave 5c migration to share the same partitioning.
260
+ */
261
+ export function planInlineThreads(findings, diffFiles) {
262
+ const comments = [];
263
+ const skipped = [];
264
+ const preexisting = [];
265
+ for (const f of findings) {
266
+ if (f.severity === 'preexisting') {
267
+ preexisting.push(f);
268
+ continue;
269
+ }
270
+ if (!findingAnchorable(f, diffFiles)) {
271
+ skipped.push(f);
272
+ continue;
273
+ }
274
+ comments.push({
275
+ path: f.file,
276
+ line: f.line,
277
+ side: 'RIGHT',
278
+ body: renderThreadBody(f),
279
+ });
280
+ }
281
+ return { comments, skipped, preexisting };
282
+ }
283
+ // ---------------------------------------------------------------------------
284
+ // GraphQL operations — pinned to module scope so callers (and tests) can
285
+ // reference the same query strings as the App.
286
+ // ---------------------------------------------------------------------------
287
+ // Wave 5b update — `author { login }` added so the resolve-threads CLI
288
+ // verb can filter to bot-authored threads. Without this, the bot-filter
289
+ // reads `comments[0].author?.login` as undefined and accepts everything,
290
+ // which would feed user-authored threads (that happen to start with the
291
+ // marker) into the verifier. Additive change — Wave 5a consumers
292
+ // (post-inline-threads) didn't read `author` so they're unaffected.
293
+ export const REVIEW_THREADS_QUERY = `
294
+ query ReviewThreads($owner: String!, $repo: String!, $pr: Int!) {
295
+ repository(owner: $owner, name: $repo) {
296
+ pullRequest(number: $pr) {
297
+ reviewThreads(first: 100) {
298
+ nodes {
299
+ id
300
+ isResolved
301
+ comments(first: 100) {
302
+ nodes {
303
+ databaseId
304
+ path
305
+ line
306
+ originalLine
307
+ body
308
+ author {
309
+ login
310
+ }
311
+ }
312
+ }
313
+ }
314
+ }
315
+ }
316
+ }
317
+ }
318
+ `;
319
+ // Includes `body` (unlike the App's lighter state query, which omits it) so
320
+ // Wave 5b's auto-resolve can re-derive the `findingId` from the
321
+ // `<!-- finding-id: ... -->` marker on each thread's first comment WITHOUT
322
+ // persisting state between fix-pushes. The npm workflow is stateless; the
323
+ // body field is the substitute for Redis-backed thread-id correlation.
324
+ export const REVIEW_THREADS_STATE_QUERY = `
325
+ query ReviewThreadStates($owner: String!, $repo: String!, $pr: Int!) {
326
+ repository(owner: $owner, name: $repo) {
327
+ pullRequest(number: $pr) {
328
+ reviewThreads(first: 100) {
329
+ nodes {
330
+ id
331
+ isResolved
332
+ comments(first: 1) {
333
+ nodes {
334
+ databaseId
335
+ body
336
+ }
337
+ }
338
+ }
339
+ }
340
+ }
341
+ }
342
+ }
343
+ `;
344
+ export const RESOLVE_THREAD_MUTATION = `
345
+ mutation ResolveThread($threadId: ID!) {
346
+ resolveReviewThread(input: { threadId: $threadId }) {
347
+ thread {
348
+ isResolved
349
+ }
350
+ }
351
+ }
352
+ `;
353
+ // Wave 5b — post a reply on a review thread (used to attach the
354
+ // auto-resolve marker explaining the verifier's verdict) BEFORE
355
+ // calling `RESOLVE_THREAD_MUTATION`. The reply is visible in the PR
356
+ // timeline so reviewers can audit why the bot auto-resolved.
357
+ export const ADD_REPLY_MUTATION = `
358
+ mutation AddThreadReply($threadId: ID!, $body: String!) {
359
+ addPullRequestReviewThreadReply(
360
+ input: { pullRequestReviewThreadId: $threadId, body: $body }
361
+ ) {
362
+ comment {
363
+ id
364
+ body
365
+ }
366
+ }
367
+ }
368
+ `;
369
+ //# sourceMappingURL=inline-threads.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"inline-threads.js","sourceRoot":"","sources":["../../src/core/inline-threads.ts"],"names":[],"mappings":"AAAA,yEAAyE;AACzE,EAAE;AACF,2EAA2E;AAC3E,oEAAoE;AACpE,mEAAmE;AACnE,uDAAuD;AACvD,EAAE;AACF,iCAAiC;AACjC,6EAA6E;AAC7E,6EAA6E;AAC7E,2EAA2E;AAC3E,+EAA+E;AAC/E,+DAA+D;AAC/D,0EAA0E;AAC1E,2EAA2E;AAC3E,4EAA4E;AAC5E,+DAA+D;AAC/D,EAAE;AACF,8DAA8D;AAC9D,uEAAuE;AACvE,oEAAoE;AACpE,iDAAiD;AAEjD,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAkCzC,8EAA8E;AAC9E,6EAA6E;AAC7E,8EAA8E;AAE9E;;;;;;;;;;;;;;;GAeG;AACH,MAAM,UAAU,SAAS,CAAC,OAMzB;IACC,MAAM,IAAI,GAAG,OAAO,CAAC,IAAI,IAAI,WAAW,CAAC;IACzC,MAAM,IAAI,GAAG,OAAO,CAAC,IAAI,IAAI,CAAC,CAAC;IAC/B,MAAM,OAAO,GAAG,OAAO,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC;IAC9C,MAAM,OAAO,GAAG,GAAG,IAAI,IAAI,IAAI,IAAI,OAAO,CAAC,QAAQ,IAAI,OAAO,CAAC,KAAK,IAAI,OAAO,EAAE,CAAC;IAClF,OAAO,UAAU,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;AACzE,CAAC;AAED,8EAA8E;AAC9E,wBAAwB;AACxB,8EAA8E;AAE9E;;;;;;;;;;;;GAYG;AACH,MAAM,UAAU,cAAc,CAAC,KAAyB;IACtD,MAAM,KAAK,GAAG,IAAI,GAAG,EAAU,CAAC;IAChC,IAAI,CAAC,KAAK;QAAE,OAAO,KAAK,CAAC;IAEzB,2DAA2D;IAC3D,uCAAuC;IACvC,MAAM,YAAY,GAAG,+CAA+C,CAAC;IAErE,IAAI,OAAO,GAAG,CAAC,CAAC;IAChB,IAAI,MAAM,GAAG,KAAK,CAAC;IACnB,KAAK,MAAM,OAAO,IAAI,KAAK,CAAC,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC;QACxC,MAAM,CAAC,GAAG,OAAO,CAAC,KAAK,CAAC,YAAY,CAAC,CAAC;QACtC,IAAI,CAAC,EAAE,CAAC;YACN,OAAO,GAAG,MAAM,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAE,EAAE,EAAE,CAAC,CAAC;YACrC,MAAM,GAAG,IAAI,CAAC;YACd,SAAS;QACX,CAAC;QACD,IAAI,CAAC,MAAM;YAAE,SAAS;QAEtB,IAAI,OAAO,CAAC,UAAU,CAAC,GAAG,CAAC,IAAI,CAAC,OAAO,CAAC,UAAU,CAAC,KAAK,CAAC,EAAE,CAAC;YAC1D,KAAK,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC;YACnB,OAAO,EAAE,CAAC;QACZ,CAAC;aAAM,IAAI,OAAO,CAAC,UAAU,CAAC,GAAG,CAAC,IAAI,CAAC,OAAO,CAAC,UAAU,CAAC,KAAK,CAAC,EAAE,CAAC;YACjE,yDAAyD;QAC3D,CAAC;aAAM,IAAI,OAAO,CAAC,UAAU,CAAC,IAAI,CAAC,EAAE,CAAC;YACpC,mDAAmD;QACrD,CAAC;aAAM,CAAC;YACN,6CAA6C;YAC7C,KAAK,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC;YACnB,OAAO,EAAE,CAAC;QACZ,CAAC;IACH,CAAC;IAED,OAAO,KAAK,CAAC;AACf,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,iBAAiB,CAC/B,OAAyC,EACzC,SAAkC;IAElC,IAAI,CAAC,OAAO,CAAC,IAAI,IAAI,CAAC,OAAO,CAAC,IAAI;QAAE,OAAO,KAAK,CAAC;IACjD,MAAM,IAAI,GAAG,SAAS,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,QAAQ,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IAChE,IAAI,CAAC,IAAI;QAAE,OAAO,KAAK,CAAC;IACxB,OAAO,cAAc,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;AACtD,CAAC;AAED,8EAA8E;AAC9E,4DAA4D;AAC5D,8EAA8E;AAE9E;;;;;;;;;;;;;GAaG;AACH,MAAM,UAAU,oBAAoB,CAClC,OAAyC,EACzC,SAAkC;IAElC,IAAI,CAAC,OAAO,CAAC,IAAI,IAAI,CAAC,OAAO,CAAC,IAAI,EAAE,CAAC;QACnC,OAAO,EAAE,UAAU,EAAE,EAAE,EAAE,SAAS,EAAE,EAAE,EAAE,CAAC;IAC3C,CAAC;IACD,MAAM,IAAI,GAAG,SAAS,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,QAAQ,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IAChE,IAAI,CAAC,IAAI,IAAI,CAAC,IAAI,CAAC,KAAK,EAAE,CAAC;QACzB,OAAO,EAAE,UAAU,EAAE,EAAE,EAAE,SAAS,EAAE,EAAE,EAAE,CAAC;IAC3C,CAAC;IAED,8DAA8D;IAC9D,MAAM,YAAY,GAAG,mDAAmD,CAAC;IACzE,MAAM,UAAU,GAAG,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;IAC1C,IAAI,gBAAgB,GAAG,CAAC,CAAC,CAAC;IAE1B,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,UAAU,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;QAC3C,MAAM,CAAC,GAAG,UAAU,CAAC,CAAC,CAAE,CAAC,KAAK,CAAC,YAAY,CAAC,CAAC;QAC7C,IAAI,CAAC,CAAC;YAAE,SAAS;QACjB,MAAM,QAAQ,GAAG,MAAM,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAE,EAAE,EAAE,CAAC,CAAC;QAC5C,MAAM,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,KAAK,SAAS,CAAC,CAAC,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAE,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;QACnE,IACE,OAAO,CAAC,IAAI,IAAI,QAAQ;YACxB,OAAO,CAAC,IAAI,GAAG,QAAQ,GAAG,IAAI,CAAC,GAAG,CAAC,MAAM,EAAE,CAAC,CAAC,EAC7C,CAAC;YACD,gBAAgB,GAAG,CAAC,CAAC;YACrB,MAAM;QACR,CAAC;IACH,CAAC;IAED,IAAI,gBAAgB,GAAG,CAAC,EAAE,CAAC;QACzB,OAAO,EAAE,UAAU,EAAE,EAAE,EAAE,SAAS,EAAE,EAAE,EAAE,CAAC;IAC3C,CAAC;IAED,MAAM,MAAM,GAAa,EAAE,CAAC;IAC5B,MAAM,KAAK,GAAa,EAAE,CAAC;IAC3B,MAAM,QAAQ,GAAa,CAAC,UAAU,CAAC,gBAAgB,CAAE,CAAC,CAAC;IAE3D,KAAK,IAAI,CAAC,GAAG,gBAAgB,GAAG,CAAC,EAAE,CAAC,GAAG,UAAU,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;QAC9D,MAAM,IAAI,GAAG,UAAU,CAAC,CAAC,CAAE,CAAC;QAC5B,IAAI,IAAI,CAAC,KAAK,CAAC,YAAY,CAAC;YAAE,MAAM;QACpC,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QAEpB,IAAI,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,UAAU,CAAC,KAAK,CAAC,EAAE,CAAC;YACpD,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC;QAC5B,CAAC;aAAM,IAAI,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,UAAU,CAAC,KAAK,CAAC,EAAE,CAAC;YAC3D,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC;QAC7B,CAAC;aAAM,IAAI,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,EAAE,CAAC;YACjC,4BAA4B;QAC9B,CAAC;aAAM,IAAI,IAAI,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YAC3B,wCAAwC;YACxC,MAAM,QAAQ,GAAG,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC;YAC7D,MAAM,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;YACtB,KAAK,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;QACvB,CAAC;IACH,CAAC;IAED,OAAO;QACL,UAAU,EAAE,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC;QAC7B,SAAS,EAAE,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC;QAC3B,YAAY,EAAE,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC;KAClC,CAAC;AACJ,CAAC;AAED,8EAA8E;AAC9E,yBAAyB;AACzB,8EAA8E;AAE9E;;;;GAIG;AACH,MAAM,UAAU,gBAAgB,CAAC,OAAyB;IACxD,MAAM,EAAE,GAAG,SAAS,CAAC,OAAO,CAAC,CAAC;IAC9B,MAAM,aAAa,GAAG,OAAO,CAAC,QAAQ,KAAK,UAAU,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC;IACpE,MAAM,MAAM,GAAG,GAAG,aAAa,MAAM,OAAO,CAAC,KAAK,IAAI,CAAC;IACvD,MAAM,IAAI,GAAG,OAAO,CAAC,OAAO,CAAC,IAAI,EAAE,CAAC;IACpC,MAAM,SAAS,GAAG,OAAO,CAAC,SAAS,CAAC,CAAC,CAAC,OAAO,OAAO,CAAC,SAAS,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;IAC7E,OAAO,oBAAoB,EAAE,SAAS,MAAM,OAAO,IAAI,GAAG,SAAS,EAAE,CAAC;AACxE,CAAC;AAED;;;;;;;GAOG;AACH,MAAM,UAAU,wBAAwB,CAAC,IAAY;IACnD,4EAA4E;IAC5E,6EAA6E;IAC7E,8CAA8C;IAC9C,MAAM,CAAC,GAAG,IAAI,CAAC,KAAK,CAAC,4CAA4C,CAAC,CAAC;IACnE,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAE,CAAC,CAAC,CAAC,IAAI,CAAC;AAC1B,CAAC;AAED;;;;;;;;;;;GAWG;AACH,MAAM,UAAU,eAAe,CAAC,IAAY;IAO1C,qEAAqE;IACrE,8DAA8D;IAC9D,8DAA8D;IAC9D,MAAM,EAAE,GACN,kGAAkG,CAAC;IACrG,MAAM,CAAC,GAAG,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC;IACzB,IAAI,CAAC,CAAC;QAAE,OAAO,IAAI,CAAC;IACpB,MAAM,CAAC,EAAE,SAAS,EAAE,KAAK,EAAE,KAAK,EAAE,OAAO,EAAE,SAAS,CAAC,GAAG,CAAC,CAAC;IAC1D,MAAM,QAAQ,GAAa,KAAK,KAAK,IAAI,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,OAAO,CAAC;IACjE,MAAM,GAAG,GAML;QACF,SAAS,EAAE,SAAU;QACrB,QAAQ;QACR,KAAK,EAAE,KAAM;QACb,OAAO,EAAE,OAAQ,CAAC,IAAI,EAAE;KACzB,CAAC;IACF,IAAI,SAAS,IAAI,SAAS,CAAC,IAAI,EAAE;QAAE,GAAG,CAAC,SAAS,GAAG,SAAS,CAAC,IAAI,EAAE,CAAC;IACpE,OAAO,GAAG,CAAC;AACb,CAAC;AA0BD;;;;;;;;GAQG;AACH,MAAM,UAAU,iBAAiB,CAC/B,QAAyC,EACzC,SAAkC;IAElC,MAAM,QAAQ,GAAwB,EAAE,CAAC;IACzC,MAAM,OAAO,GAAuB,EAAE,CAAC;IACvC,MAAM,WAAW,GAAuB,EAAE,CAAC;IAE3C,KAAK,MAAM,CAAC,IAAI,QAAQ,EAAE,CAAC;QACzB,IAAI,CAAC,CAAC,QAAQ,KAAK,aAAa,EAAE,CAAC;YACjC,WAAW,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;YACpB,SAAS;QACX,CAAC;QACD,IAAI,CAAC,iBAAiB,CAAC,CAAC,EAAE,SAAS,CAAC,EAAE,CAAC;YACrC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;YAChB,SAAS;QACX,CAAC;QACD,QAAQ,CAAC,IAAI,CAAC;YACZ,IAAI,EAAE,CAAC,CAAC,IAAK;YACb,IAAI,EAAE,CAAC,CAAC,IAAK;YACb,IAAI,EAAE,OAAO;YACb,IAAI,EAAE,gBAAgB,CAAC,CAAC,CAAC;SAC1B,CAAC,CAAC;IACL,CAAC;IAED,OAAO,EAAE,QAAQ,EAAE,OAAO,EAAE,WAAW,EAAE,CAAC;AAC5C,CAAC;AAED,8EAA8E;AAC9E,yEAAyE;AACzE,+CAA+C;AAC/C,8EAA8E;AAE9E,uEAAuE;AACvE,wEAAwE;AACxE,yEAAyE;AACzE,wEAAwE;AACxE,iEAAiE;AACjE,oEAAoE;AACpE,MAAM,CAAC,MAAM,oBAAoB,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;CAyBnC,CAAC;AAEF,4EAA4E;AAC5E,gEAAgE;AAChE,2EAA2E;AAC3E,0EAA0E;AAC1E,uEAAuE;AACvE,MAAM,CAAC,MAAM,0BAA0B,GAAG;;;;;;;;;;;;;;;;;;;CAmBzC,CAAC;AAEF,MAAM,CAAC,MAAM,uBAAuB,GAAG;;;;;;;;CAQtC,CAAC;AAEF,gEAAgE;AAChE,gEAAgE;AAChE,oEAAoE;AACpE,6DAA6D;AAC7D,MAAM,CAAC,MAAM,kBAAkB,GAAG;;;;;;;;;;;CAWjC,CAAC"}
@@ -0,0 +1,164 @@
1
+ import type { Finding } from './review-schema-zod.js';
2
+ /** Max bytes of patch per file to include in the prompt. Beyond this we
3
+ * truncate with a `... (N bytes omitted)` marker so the model knows the
4
+ * file kept going.
5
+ */
6
+ export declare const MAX_PATCH_BYTES_PER_FILE: number;
7
+ /** Default skill-body byte cap when the caller doesn't supply one.
8
+ * Matches SPEC §1.10 ceiling + the App's `MAX_SKILL_BYTES` env default
9
+ * (see clud-bug-app/lib/env.ts).
10
+ */
11
+ export declare const DEFAULT_MAX_SKILL_BYTES = 8192;
12
+ /**
13
+ * Status taxonomy mirrors `PullRequestFile["status"]` from `@octokit/rest`.
14
+ * We accept the wider GitHub union so callers can pass octokit's raw status
15
+ * verbatim.
16
+ */
17
+ export type ChangedFileStatus = 'added' | 'modified' | 'removed' | 'renamed' | 'copied' | 'changed' | 'unchanged';
18
+ export interface ChangedFile {
19
+ /** Repo-relative POSIX path. */
20
+ path: string;
21
+ /** GitHub's per-file status. */
22
+ status: ChangedFileStatus;
23
+ /** Lines added. */
24
+ additions: number;
25
+ /** Lines deleted. */
26
+ deletions: number;
27
+ /**
28
+ * Unified-diff patch for this file. May be empty for binary files or
29
+ * very large diffs (GitHub omits the patch above ~3000 lines). The
30
+ * App orchestrator treats absent patch as "skip this file from review".
31
+ */
32
+ patch: string | undefined;
33
+ }
34
+ export interface PullRequestDiff {
35
+ files: ChangedFile[];
36
+ /** PR HEAD SHA (40-char). Pinned to `<!-- review-sha: ... -->`. */
37
+ headSha: string;
38
+ /** PR BASE SHA (40-char). Used as the ref for skills-loader. */
39
+ baseSha: string;
40
+ /** PR base branch name (e.g. `main`). Used for human-readable logs. */
41
+ baseRef: string;
42
+ /** PR head branch name. Used for the writeback commit. */
43
+ headRef: string;
44
+ /** Sum of `additions + deletions` across `files`. */
45
+ totalChanges: number;
46
+ /** Total bytes of `patch` content combined. Drives the 100KB skip rule. */
47
+ totalPatchBytes: number;
48
+ }
49
+ /** Minimal applies_to rule type — matches `SkillFrontmatter.applies_to`. */
50
+ export interface PromptAppliesToRule {
51
+ paths?: string[];
52
+ extensions?: string[];
53
+ }
54
+ /** Minimal frontmatter shape the prompt builder needs from each skill. */
55
+ export interface PromptSkillFrontmatter {
56
+ name: string;
57
+ description: string;
58
+ applies_to?: PromptAppliesToRule;
59
+ }
60
+ /** Minimal LoadedSkill shape — slug + parsed frontmatter + body. */
61
+ export interface PromptLoadedSkill {
62
+ slug: string;
63
+ frontmatter: PromptSkillFrontmatter;
64
+ body: string;
65
+ }
66
+ export interface BuildReviewPromptInput {
67
+ repo: {
68
+ owner: string;
69
+ name: string;
70
+ };
71
+ pr: {
72
+ number: number;
73
+ title?: string;
74
+ baseRef: string;
75
+ headRef: string;
76
+ };
77
+ diff: PullRequestDiff;
78
+ skills: PromptLoadedSkill[];
79
+ /**
80
+ * Per-skill body byte cap. Defaults to `DEFAULT_MAX_SKILL_BYTES` (8192)
81
+ * matching SPEC §1.10 + the App's `MAX_SKILL_BYTES` env. Callers running
82
+ * the App provide it from `getEnv().MAX_SKILL_BYTES`; callers outside
83
+ * the App may omit it.
84
+ */
85
+ maxSkillBytes?: number;
86
+ }
87
+ export interface BuiltPrompt {
88
+ system: string;
89
+ prompt: string;
90
+ /** Slugs actually included (used for skills_referenced fallback). */
91
+ includedSkillSlugs: string[];
92
+ /** Files skipped because their patch was empty (binary, too large). */
93
+ skippedFiles: string[];
94
+ }
95
+ /**
96
+ * Builds the system + user prompt pair for the review call.
97
+ */
98
+ export declare function buildReviewPrompt(input: BuildReviewPromptInput): BuiltPrompt;
99
+ /**
100
+ * Returns true when the diff includes at least one file matching the
101
+ * applies_to clause. Absent applies_to → matches everything.
102
+ */
103
+ export declare function skillMatchesDiff(appliesTo: PromptAppliesToRule | undefined, changedPaths: string[]): boolean;
104
+ /**
105
+ * Very small glob matcher supporting `**` (any path segment) and `*`
106
+ * (any chars within a segment). Sufficient for the SPEC §1.10 examples
107
+ * (`src/**`, `*.ts`). Not a drop-in replacement for `minimatch`; if we
108
+ * need negation / brace expansion later, swap to minimatch — but adding
109
+ * a dependency for two characters of syntax isn't worth it yet.
110
+ *
111
+ * Exported because the App's skill-routing code reuses it for an
112
+ * orchestrator-side pre-filter that runs before prompt construction.
113
+ */
114
+ export declare function globMatch(pattern: string, path: string): boolean;
115
+ /**
116
+ * Truncates a patch to `MAX_PATCH_BYTES_PER_FILE`, appending a marker so
117
+ * the model knows it didn't see the whole file.
118
+ *
119
+ * Cut via UTF-8 byte buffer (see sliceUtf8Bytes) so multi-byte content
120
+ * — emoji in commit-author lines, CJK identifiers — doesn't blow past
121
+ * the byte cap. clud-bug-review #158 flagged the original code-unit
122
+ * slice as a contract violation when content went non-ASCII.
123
+ */
124
+ export declare function truncatePatch(patch: string): string;
125
+ /**
126
+ * Slice a string to at most `maxBytes` UTF-8 bytes, trimming any trailing
127
+ * partial codepoint (so the output is always a valid UTF-8 string).
128
+ *
129
+ * Why we need this: `String.prototype.slice(0, N)` keeps N UTF-16 code
130
+ * units, not N bytes. A skill body of CJK characters at maxSkillBytes=8192
131
+ * would actually carry 3*8192 ≈ 24KiB of UTF-8 bytes — silently busting
132
+ * the cap the call site exists to enforce. Buffer-based slicing is
133
+ * authoritative; we then decode back as UTF-8 with `fatal: false` so a
134
+ * trailing partial codepoint becomes a single replacement character that
135
+ * we strip below.
136
+ *
137
+ * For pure-ASCII content (the dominant case for skill files + diffs), this
138
+ * is bit-equivalent to String.slice. The fix only kicks in on multibyte.
139
+ */
140
+ export declare function sliceUtf8Bytes(input: string, maxBytes: number): string;
141
+ export interface BuildCrossCheckPromptInput extends BuildReviewPromptInput {
142
+ /** Pass 1's findings — the cross-check pass annotates these. */
143
+ pass1Findings: Finding[];
144
+ }
145
+ /**
146
+ * Builds a cross-check prompt: Pass 2 sees Pass 1's findings as a numbered
147
+ * list + the same skills + the same diff.
148
+ *
149
+ * The prompt asks Pass 2 to:
150
+ * - emit a verdict per Pass-1 finding (referenced by 0-indexed number)
151
+ * - emit an independent findings list (issues Pass 1 missed)
152
+ *
153
+ * The aggregator turns the verdicts into per-finding attribution lines.
154
+ */
155
+ export declare function buildCrossCheckPrompt(input: BuildCrossCheckPromptInput): BuiltPrompt;
156
+ /**
157
+ * Builds a consensus prompt: Pass N runs fully independent of Pass 1. The
158
+ * orchestrator diffs their outputs and keeps the intersection.
159
+ *
160
+ * This is essentially `buildReviewPrompt` with a tweaked system prompt
161
+ * — the user message is identical so the model can't tell which pass it is.
162
+ */
163
+ export declare function buildConsensusPrompt(input: BuildReviewPromptInput): BuiltPrompt;
164
+ //# sourceMappingURL=prompt-builder.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"prompt-builder.d.ts","sourceRoot":"","sources":["../../src/core/prompt-builder.ts"],"names":[],"mappings":"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"}