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,364 @@
1
+ // SPEC §1.8.1 doc-file renderer for `docs/reviews/PR-<n>.md`.
2
+ //
3
+ // This is the PURE rendering half of the App's `lib/review-writeback.ts`.
4
+ // The Octokit-side WRITEBACK (branch detection, idempotent rewrite,
5
+ // Contents-API commit) stays App-side — that surface depends on Octokit
6
+ // which we don't want to pull into core.
7
+ //
8
+ // Renamed from the App's `renderReview` to `renderReviewFile` to avoid
9
+ // colliding with the CLI's existing `renderReview` (which renders the
10
+ // summary-PR-comment shape, not the doc-file). Both renderers coexist:
11
+ // - `renderReview` (./render-review.ts) → `## 🐛 Clud Bug review` PR comment
12
+ // - `renderReviewFile` (this module) → `# clud-bug review — PR #N` doc file
13
+ //
14
+ // SPEC pins honored here:
15
+ // - `<!-- protocol-version: 0.1.0 -->` — SPEC version.
16
+ // - `<!-- written-by: clud-bug[bot] -->` — App identity, not Action.
17
+ // - `<!-- review-sha: <40-char-head-sha> -->` — pinned to review-time HEAD.
18
+ // - Severity bucket order: red → yellow → purple.
19
+ // - Empty buckets omitted entirely (no empty headers).
20
+ // - "Resolved this round:" and "Still open:" blocks omitted when empty
21
+ // (D.2.0 always omits — multi-pass is D.2.5).
22
+ // - Trailing `---\n[Link to PR](<url>)` line preserved verbatim.
23
+ // - Emoji codepoints: U+1F534, U+1F7E1, U+1F7E3, NFC-normalized.
24
+ import { deriveSkillsReferenced, deriveSummaryCounts, flattenFindings, } from './review-schema-zod.js';
25
+ /** Protocol version this implementation emits. */
26
+ export const PROTOCOL_VERSION = '0.1.0';
27
+ /** "Written by" tag for the App writeback (SPEC §6.1). */
28
+ export const WRITTEN_BY = 'clud-bug[bot]';
29
+ // Severity emoji per SPEC §1.8.1. We define them by codepoint so a stray
30
+ // editor that switches encoding can't silently break byte-equality with
31
+ // the Action-runner output. Same constants as render-review.ts but kept
32
+ // local so this module is independent of the CLI renderer.
33
+ export const SEVERITY_EMOJI = {
34
+ critical: '\u{1F534}', // U+1F534 RED CIRCLE
35
+ minor: '\u{1F7E1}', // U+1F7E1 YELLOW CIRCLE
36
+ preexisting: '\u{1F7E3}', // U+1F7E3 PURPLE CIRCLE
37
+ };
38
+ /**
39
+ * Renders the review object to the SPEC §1.8.1 markdown template.
40
+ *
41
+ * Pure: no I/O, no time-of-day, no provider info — fixture-stable.
42
+ *
43
+ * NB: This produces the doc-file shape (`# clud-bug review — PR #N` H1).
44
+ * The CLI's `renderReview` produces the PR-comment shape (`## 🐛 Clud Bug
45
+ * review` H2). Both are valid review outputs; SPEC §6.2 says they share
46
+ * the underlying finding data but differ in container.
47
+ */
48
+ export function renderReviewFile(input) {
49
+ const { review, prNumber, headSha, prUrl, resolvedFindings, stillOpenFindings, cacheStats, } = input;
50
+ // Wire-shape Review carries findings in 3 severity arrays. Flatten to
51
+ // internal `Finding[]` so the renderer's bucketing, count-derivation,
52
+ // and per-skill aggregation can work uniformly.
53
+ const findings = flattenFindings(review);
54
+ // Always derive these from findings to guarantee they match what we
55
+ // actually render. The model can drift on counts; we don't trust it.
56
+ const counts = deriveSummaryCounts(findings);
57
+ const skillsReferenced = deriveSkillsReferenced(findings);
58
+ const lines = [];
59
+ lines.push(`# clud-bug review — PR #${prNumber}`);
60
+ lines.push(`<!-- protocol-version: ${PROTOCOL_VERSION} -->`);
61
+ lines.push(`<!-- written-by: ${WRITTEN_BY} -->`);
62
+ lines.push(`<!-- review-sha: ${headSha} -->`);
63
+ // SPEC §6.7.3: cache telemetry comment goes immediately below the
64
+ // review-sha so a single grep can pull review-sha + cache stats out
65
+ // of a doc-file without re-parsing the whole block. Omitted entirely
66
+ // when cacheStats is undefined.
67
+ if (cacheStats !== undefined) {
68
+ lines.push(`<!-- cache: ${cacheStats.cachedInputTokens} read · ${cacheStats.cacheCreationInputTokens} created -->`);
69
+ }
70
+ lines.push('');
71
+ // Summary line — SPEC §1.8.1 wording.
72
+ lines.push(`**Summary:** ${counts.critical} critical · ${counts.minor} minor · ${counts.preexisting} preexisting · ${counts.resolved_from_prior} resolved-from-prior · ${counts.still_open} still-open`);
73
+ lines.push('');
74
+ // Skills cited block — group findings per skill for citation counts.
75
+ lines.push('**Skills cited:**');
76
+ if (skillsReferenced.length === 0) {
77
+ lines.push('- _(none — see summary above)_');
78
+ }
79
+ else {
80
+ for (const slug of skillsReferenced) {
81
+ const count = findings.filter((f) => f.skill === slug).length;
82
+ lines.push(`- ${slug} (${count} finding${count === 1 ? '' : 's'})`);
83
+ }
84
+ }
85
+ lines.push('');
86
+ lines.push('**Findings:**');
87
+ lines.push('');
88
+ // Severity buckets in SPEC order; empty buckets are omitted entirely.
89
+ const bucketed = bucketBySeverity(findings);
90
+ if (bucketed.critical.length > 0) {
91
+ lines.push(`### ${SEVERITY_EMOJI.critical} Critical`);
92
+ for (const f of bucketed.critical)
93
+ lines.push(renderFinding(f, true));
94
+ lines.push('');
95
+ }
96
+ if (bucketed.minor.length > 0) {
97
+ lines.push(`### ${SEVERITY_EMOJI.minor} Minor`);
98
+ for (const f of bucketed.minor)
99
+ lines.push(renderFinding(f, false));
100
+ lines.push('');
101
+ }
102
+ if (bucketed.preexisting.length > 0) {
103
+ lines.push(`### ${SEVERITY_EMOJI.preexisting} Preexisting (informational)`);
104
+ for (const f of bucketed.preexisting)
105
+ lines.push(renderFinding(f, false));
106
+ lines.push('');
107
+ }
108
+ // SPEC §1.8.1 Resolved this round / Still open blocks. Omitted
109
+ // entirely when the corresponding input list is empty/undefined.
110
+ //
111
+ // Bullet shape (one finding per line):
112
+ // - `path/file.ts:42` — `critical-issues-only`: null-deref ... (was 🔴 Critical)
113
+ //
114
+ // The `(was <emoji> <Severity>)` suffix carries the SEVERITY at the
115
+ // time the finding was last seen so a downgrade across rounds is
116
+ // visible without diffing the two doc files. Note: backticks around
117
+ // file and skill render in markdown viewers as inline-code, which
118
+ // makes the file path scannable in the GitHub UI.
119
+ if (resolvedFindings !== undefined && resolvedFindings.length > 0) {
120
+ lines.push('**Resolved this round:**');
121
+ for (const f of resolvedFindings) {
122
+ lines.push(renderDiffFinding(f));
123
+ }
124
+ lines.push('');
125
+ }
126
+ if (stillOpenFindings !== undefined && stillOpenFindings.length > 0) {
127
+ lines.push('**Still open:**');
128
+ for (const f of stillOpenFindings) {
129
+ lines.push(renderDiffFinding(f));
130
+ }
131
+ lines.push('');
132
+ }
133
+ lines.push('---');
134
+ lines.push('');
135
+ lines.push(`[Link to PR](${prUrl})`);
136
+ // Final NFC normalization — guarantees the emoji codepoints stay
137
+ // composed even if a future renderer step decomposes them.
138
+ return lines.join('\n').normalize('NFC') + '\n';
139
+ }
140
+ function bucketBySeverity(findings) {
141
+ return {
142
+ critical: findings.filter((f) => f.severity === 'critical'),
143
+ minor: findings.filter((f) => f.severity === 'minor'),
144
+ preexisting: findings.filter((f) => f.severity === 'preexisting'),
145
+ };
146
+ }
147
+ /**
148
+ * Renders one finding for the SPEC §1.8.1 Resolved / Still-open blocks.
149
+ * Output shape:
150
+ *
151
+ * - `path/file.ts:42` — `critical-issues-only`: null-deref ... (was 🔴 Critical)
152
+ *
153
+ * Line `0` is treated as "no anchor" (cross-cutting / missing) and the
154
+ * `:N` suffix is omitted. The severity label uses the SPEC §1.8.1
155
+ * emoji + label so a reader can see at a glance whether the finding
156
+ * was downgraded (different severity in current round) or merely
157
+ * resolved.
158
+ */
159
+ function renderDiffFinding(f) {
160
+ const location = f.line > 0 ? `${f.file}:${f.line}` : f.file;
161
+ const label = f.severity === 'critical'
162
+ ? 'Critical'
163
+ : f.severity === 'minor'
164
+ ? 'Minor'
165
+ : 'Preexisting';
166
+ const emoji = SEVERITY_EMOJI[f.severity];
167
+ return `- \`${location}\` — \`${f.skillName}\`: ${f.summary} (was ${emoji} ${label})`;
168
+ }
169
+ function renderFinding(f, includeReasoning) {
170
+ // findingItemSchema.file is z.string().optional() — the model is
171
+ // instructed to always provide it, but Zod doesn't enforce. Without
172
+ // the fallback an absent file would emit literal "undefined" in the
173
+ // committed SPEC §1.8.1 doc file. clud-bug-review #158 flagged this.
174
+ const fileLabel = f.file ?? '(unknown file)';
175
+ const location = f.line ? `${fileLabel}:${f.line}` : fileLabel;
176
+ // Per SPEC §1.8.1: "**<file>:<line>** — <skill-name>: <one-line summary>".
177
+ const head = `- **${location}** — ${f.skill}: ${f.summary}`;
178
+ // Reasoning line is documented for the Critical bucket; we follow the
179
+ // SPEC template strictly. For Minor/Preexisting, no reasoning line.
180
+ if (includeReasoning && f.reasoning) {
181
+ return `${head}\n Reasoning: ${f.reasoning}`;
182
+ }
183
+ return head;
184
+ }
185
+ /**
186
+ * Renders a multi-pass review with per-pass attribution lines.
187
+ *
188
+ * Output layout (SPEC §1.8.5):
189
+ *
190
+ * # clud-bug review — PR #N (M passes · mode)
191
+ * <!-- protocol-version: ... -->
192
+ * <!-- written-by: clud-bug[bot] -->
193
+ * <!-- review-sha: ... -->
194
+ * <!-- passes: M -->
195
+ * <!-- mode: cross-check|consensus|independent -->
196
+ *
197
+ * **Summary:** ... · **Verdict:** request_changes / review_only / clean
198
+ *
199
+ * **Reviewers:**
200
+ * - Pass 1 — Beetle · anthropic/claude-sonnet-4.6
201
+ * - Pass 2 — Wasp · anthropic/claude-opus-4.7
202
+ *
203
+ * **Skills cited:** ...
204
+ *
205
+ * **Findings:**
206
+ *
207
+ * ### (red) Critical
208
+ * - [Pass 1 — Beetle · Sonnet 4.6] auth.ts:42 — race-conditions: Race condition
209
+ * Reasoning: ...
210
+ * [Pass 2 — Wasp · Opus 4.7]: (check) AGREED — same finding identified independently.
211
+ *
212
+ * ...
213
+ *
214
+ * ---
215
+ * [Link to PR](...)
216
+ *
217
+ * Pure: no I/O, no time-of-day, fixture-stable.
218
+ */
219
+ export function renderMultiPassMarkdown(input) {
220
+ const { review, prNumber, headSha, prUrl } = input;
221
+ const lines = [];
222
+ lines.push(`# clud-bug review — PR #${prNumber} (${review.passCount} ${review.passCount === 1 ? 'pass' : 'passes'} · ${review.mode})`);
223
+ lines.push(`<!-- protocol-version: ${PROTOCOL_VERSION} -->`);
224
+ lines.push(`<!-- written-by: ${WRITTEN_BY} -->`);
225
+ lines.push(`<!-- review-sha: ${headSha} -->`);
226
+ lines.push(`<!-- passes: ${review.passCount} -->`);
227
+ lines.push(`<!-- mode: ${review.mode} -->`);
228
+ lines.push('');
229
+ const counts = review.summary_counts;
230
+ lines.push(`**Summary:** ${counts.critical} critical · ${counts.minor} minor · ${counts.preexisting} preexisting · ${counts.resolved_from_prior} resolved-from-prior · ${counts.still_open} still-open · **Verdict:** ${review.verdict}`);
231
+ lines.push('');
232
+ lines.push('**Reviewers:**');
233
+ for (const r of review.roles) {
234
+ lines.push(`- Pass ${r.passNumber} — ${r.roleName} · ${r.model}`);
235
+ }
236
+ lines.push('');
237
+ lines.push('**Skills cited:**');
238
+ if (review.skills_referenced.length === 0) {
239
+ lines.push('- _(none — see summary above)_');
240
+ }
241
+ else {
242
+ for (const slug of review.skills_referenced) {
243
+ const count = review.findings.filter((f) => f.skill === slug).length;
244
+ lines.push(`- ${slug} (${count} finding${count === 1 ? '' : 's'})`);
245
+ }
246
+ }
247
+ lines.push('');
248
+ lines.push('**Findings:**');
249
+ lines.push('');
250
+ // Severity buckets in SPEC order; empty buckets are omitted entirely.
251
+ const bucketed = bucketUnifiedBySeverity(review.findings);
252
+ if (bucketed.critical.length > 0) {
253
+ lines.push(`### ${SEVERITY_EMOJI.critical} Critical`);
254
+ for (const f of bucketed.critical)
255
+ lines.push(renderUnifiedFinding(f, /* includeReasoning */ true));
256
+ lines.push('');
257
+ }
258
+ if (bucketed.minor.length > 0) {
259
+ lines.push(`### ${SEVERITY_EMOJI.minor} Minor`);
260
+ for (const f of bucketed.minor)
261
+ lines.push(renderUnifiedFinding(f, false));
262
+ lines.push('');
263
+ }
264
+ if (bucketed.preexisting.length > 0) {
265
+ lines.push(`### ${SEVERITY_EMOJI.preexisting} Preexisting (informational)`);
266
+ for (const f of bucketed.preexisting)
267
+ lines.push(renderUnifiedFinding(f, false));
268
+ lines.push('');
269
+ }
270
+ lines.push('---');
271
+ lines.push('');
272
+ lines.push(`[Link to PR](${prUrl})`);
273
+ return lines.join('\n').normalize('NFC') + '\n';
274
+ }
275
+ function bucketUnifiedBySeverity(findings) {
276
+ return {
277
+ critical: findings.filter((f) => f.severity === 'critical'),
278
+ minor: findings.filter((f) => f.severity === 'minor'),
279
+ preexisting: findings.filter((f) => f.severity === 'preexisting'),
280
+ };
281
+ }
282
+ /**
283
+ * Renders one finding with inline per-pass attribution. The headline carries
284
+ * the FIRST attribution (whichever pass raised the issue); subsequent
285
+ * attributions appear on indented sub-lines:
286
+ *
287
+ * - [Pass 1 — Beetle · sonnet] auth.ts:42 — race: Race condition
288
+ * Reasoning: ...
289
+ * [Pass 2 — Wasp · opus]: (check) AGREED — confirmed by independent review.
290
+ * [Pass 3 — Mantis · opus]: (x) DISAGREED — guarded by the surrounding lock.
291
+ *
292
+ * The headline always tracks the FIRST attribution to preserve the SPEC
293
+ * §1.8.1 grep pattern (`**<file>:<line>** — <skill>: <summary>`).
294
+ */
295
+ function renderUnifiedFinding(f, includeReasoning) {
296
+ // Same guard as renderFinding — findingItemSchema.file is optional.
297
+ const fileLabel = f.file ?? '(unknown file)';
298
+ const location = f.line ? `${fileLabel}:${f.line}` : fileLabel;
299
+ const head = f.attributions[0];
300
+ if (!head) {
301
+ // Defensive — shouldn't happen; the aggregator guarantees ≥1 attribution.
302
+ return `- **${location}** — ${f.skill}: ${f.summary}`;
303
+ }
304
+ const headLabel = formatAttributionLabel(head);
305
+ const lines = [];
306
+ lines.push(`- ${headLabel} **${location}** — ${f.skill}: ${f.summary}`);
307
+ if (includeReasoning && f.reasoning) {
308
+ lines.push(` Reasoning: ${f.reasoning}`);
309
+ }
310
+ for (let i = 1; i < f.attributions.length; i++) {
311
+ const a = f.attributions[i];
312
+ if (!a)
313
+ continue;
314
+ lines.push(` ${formatFollowupAttribution(a)}`);
315
+ }
316
+ return lines.join('\n');
317
+ }
318
+ /**
319
+ * The leading bracket on the head line. Example:
320
+ *
321
+ * [Pass 1 — Beetle · anthropic/claude-sonnet-4.6]
322
+ * [Pass 2 — Wasp · anthropic/claude-opus-4.7 — found independently]
323
+ *
324
+ * "found independently" only fires when the head attribution is NOT
325
+ * `source: 'first'` — i.e. when a later pass surfaced this finding without
326
+ * Pass 1 raising it.
327
+ */
328
+ function formatAttributionLabel(a) {
329
+ const independent = a.source === 'independent' && a.passNumber > 1
330
+ ? ' — found independently'
331
+ : '';
332
+ return `[Pass ${a.passNumber} — ${a.roleName} · ${a.model}${independent}]`;
333
+ }
334
+ /**
335
+ * Subsequent-line attribution. Example:
336
+ *
337
+ * [Pass 2 — Wasp · opus]: ✅ AGREED — confirmed.
338
+ * [Pass 3 — Mantis · opus]: ❌ DISAGREED — guarded by surrounding lock.
339
+ */
340
+ function formatFollowupAttribution(a) {
341
+ const verdictSymbol = a.source === 'agreed'
342
+ ? '✅ AGREED' // U+2705 WHITE HEAVY CHECK MARK
343
+ : a.source === 'disagreed'
344
+ ? '❌ DISAGREED' // U+274C CROSS MARK
345
+ : a.source === 'independent'
346
+ ? 'INDEPENDENTLY FLAGGED'
347
+ : 'NOTED';
348
+ const note = a.note ? ` — ${a.note}` : '';
349
+ const disputed = a.source === 'disagreed' ? ' (Disputed — human decides.)' : '';
350
+ return `[Pass ${a.passNumber} — ${a.roleName} · ${a.model}]: ${verdictSymbol}${note}${disputed}`;
351
+ }
352
+ /** SPEC §6.1 / §1.8 path. The App's Octokit writeback uses this. */
353
+ export function reviewFilePath(prNumber) {
354
+ return `docs/reviews/PR-${prNumber}.md`;
355
+ }
356
+ /**
357
+ * SPEC §6.1 commit message: exactly `[skip-logmind] clud-bug review: PR #<n>`.
358
+ * The `[skip-logmind]` prefix tells `check-decisions.yml` to ignore this
359
+ * commit (SPEC §6.4). The App's Octokit writeback uses this.
360
+ */
361
+ export function reviewCommitMessage(prNumber) {
362
+ return `[skip-logmind] clud-bug review: PR #${prNumber}`;
363
+ }
364
+ //# sourceMappingURL=review-writeback.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"review-writeback.js","sourceRoot":"","sources":["../../src/core/review-writeback.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,147 @@
1
+ export declare const API_BASE = "https://skills.sh/api/v1";
2
+ export declare const MAX_SKILLS = 8;
3
+ export interface SkillDescriptor {
4
+ source: string;
5
+ name: string;
6
+ description: string;
7
+ installs: number;
8
+ kind?: string;
9
+ content?: string;
10
+ }
11
+ type RawSkillItem = {
12
+ source?: string;
13
+ repo?: string;
14
+ name?: string;
15
+ slug?: string;
16
+ description?: string;
17
+ summary?: string;
18
+ installs?: number;
19
+ installCount?: number;
20
+ };
21
+ type RawSkillListResponse = RawSkillItem[] | {
22
+ skills?: RawSkillItem[];
23
+ results?: RawSkillItem[];
24
+ } | unknown;
25
+ export declare function normalizeList(data: RawSkillListResponse): SkillDescriptor[];
26
+ interface SkillsClientOptions {
27
+ fetch?: typeof globalThis.fetch;
28
+ base?: string;
29
+ userAgent?: string;
30
+ }
31
+ export declare class SkillsClient {
32
+ #private;
33
+ private readonly fetch;
34
+ private readonly base;
35
+ private readonly userAgent;
36
+ constructor({ fetch, base, userAgent }?: SkillsClientOptions);
37
+ search(terms: string[]): Promise<SkillDescriptor[]>;
38
+ curated(): Promise<SkillDescriptor[]>;
39
+ getContent(source: string, name: string): Promise<string>;
40
+ }
41
+ export interface RankableSkill extends SkillDescriptor {
42
+ kind?: string;
43
+ }
44
+ export declare function rankAndCap(curated: RankableSkill[], searched: RankableSkill[], baseline: RankableSkill[], cap?: number): RankableSkill[];
45
+ export declare function readReviewMode(skillContent: unknown): 'shared' | 'dedicated';
46
+ export interface AppliesToRule {
47
+ paths: string[];
48
+ extensions: string[];
49
+ }
50
+ export declare function readAppliesTo(skillContent: unknown): AppliesToRule | null;
51
+ export declare function appliesToPr(skillContent: unknown, prPaths: unknown): boolean;
52
+ export declare function appliesToAuthor(skillContent: unknown, prAuthor: unknown): boolean;
53
+ export interface SkillWithOptionalContent {
54
+ content?: unknown;
55
+ [key: string]: unknown;
56
+ }
57
+ export declare function partitionByReviewMode<T extends SkillWithOptionalContent>(skills: T[]): {
58
+ shared: T[];
59
+ dedicated: T[];
60
+ };
61
+ export declare function extractPerSkillLine(comment: unknown, skillName: unknown): string | null;
62
+ export interface PrComment {
63
+ body?: unknown;
64
+ user?: {
65
+ login?: unknown;
66
+ };
67
+ created_at?: unknown;
68
+ }
69
+ export declare function selectReviewHeader(comments: unknown, botLogin: unknown): string | null;
70
+ export declare function extractFirstReviewHeaderLine(body: unknown): string | null;
71
+ export declare function selectReviewBody(comments: unknown, botLogin: unknown): string | null;
72
+ export interface ReviewStatsHeader {
73
+ important: number;
74
+ nit: number;
75
+ preExisting: number;
76
+ }
77
+ export declare function extractStatsHeader(comment: unknown): ReviewStatsHeader | null;
78
+ export declare function isCriticalReviewHeader(headerLine: unknown): boolean;
79
+ export declare function classifyPerSkillOutcome(outcomeLine: unknown): 'failure' | 'success';
80
+ /** Source provenance for an installed skill (see SPEC §1.10). */
81
+ export type SkillSource = 'manual' | 'logmind-derived' | 'skills-sh' | 'clud-bug-baseline';
82
+ export type SkillReviewMode = 'shared' | 'dedicated';
83
+ /**
84
+ * Parsed SKILL.md frontmatter. The App uses this shape (see
85
+ * `clud-bug-app/lib/skills-loader.ts:40`); the prompt builder's
86
+ * `PromptSkillFrontmatter` is a narrower subset (name + description +
87
+ * applies_to) so we keep the full shape here.
88
+ */
89
+ export type SkillKind = 'rule' | 'voice';
90
+ export type VoiceScope = 'personal' | 'team' | 'org' | 'community';
91
+ export interface SkillFrontmatter {
92
+ name: string;
93
+ description: string;
94
+ source: SkillSource | string;
95
+ review_mode: SkillReviewMode;
96
+ /**
97
+ * SPEC §1.10.1 v0.5.0+ skill classification. OPTIONAL — absent =
98
+ * `kind: rule` (the v0.4.0 default). Surfaced on the parsed
99
+ * frontmatter (v0.7.0-rc.6+) so consumers can route on the field;
100
+ * v0.7.0-rc.5 and earlier silently dropped it.
101
+ */
102
+ kind?: SkillKind;
103
+ /**
104
+ * SPEC §1.10.1 v0.5.0+ voice scope. REQUIRED when `kind: voice`,
105
+ * absent otherwise. Surfaced on the parsed frontmatter (v0.7.0-rc.6+).
106
+ */
107
+ voice_scope?: VoiceScope;
108
+ applies_to?: {
109
+ paths?: string[];
110
+ extensions?: string[];
111
+ /**
112
+ * SPEC §1.10.1 v0.5.1+ — single GitHub login string (no `@`
113
+ * prefix, no list). When present, the skill MUST only load when
114
+ * `pull_request.user.login === author`. Filters via strict AND
115
+ * with the sibling `paths` + `extensions` filters when all are
116
+ * present. v0.7.0-rc.5 and earlier silently dropped this field
117
+ * (treated skills as if it were absent — load unconditionally);
118
+ * v0.7.0-rc.6+ enforces the filter via `appliesToAuthor`.
119
+ */
120
+ author?: string;
121
+ };
122
+ }
123
+ /**
124
+ * Minimal YAML frontmatter parser. Handles:
125
+ * - `key: value` (scalar)
126
+ * - `key: [a, b, c]` (inline list)
127
+ * - `key:\n subkey: value` (one-level nesting — applies_to)
128
+ *
129
+ * Throws on malformed input; the App's `loadSkillsFromBaseRef` catches
130
+ * and skips the skill (a bad SKILL.md doesn't take down the whole review).
131
+ *
132
+ * Deliberately NOT a general-purpose YAML parser — SPEC §1.10 fixes the
133
+ * frontmatter schema to a handful of fields. If the schema grows beyond
134
+ * what this hand-rolled parser handles, swap to `js-yaml` — the boundary
135
+ * is this function.
136
+ */
137
+ export declare function parseFrontmatter(raw: string): SkillFrontmatter;
138
+ /**
139
+ * Strip the leading `---\n...\n---\n` from a SKILL.md file. Returns the
140
+ * markdown body (the part the LLM actually reads).
141
+ *
142
+ * Ported from `clud-bug-app/lib/skills-loader.ts:269` so callers don't have
143
+ * to re-implement the regex.
144
+ */
145
+ export declare function stripFrontmatter(raw: string): string;
146
+ export {};
147
+ //# sourceMappingURL=skills.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"skills.d.ts","sourceRoot":"","sources":["../../src/core/skills.ts"],"names":[],"mappings":"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"}