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,3 @@
1
+ // Generated by scripts/gen-version.mjs at build time. Do not edit.
2
+ // Regenerated automatically on every `npm run build` via "prebuild" hook.
3
+ export const PKG_VERSION = '0.7.0-rc.11';
@@ -0,0 +1,115 @@
1
+ ---
2
+ description: Review the current branch's open PR locally, in this Claude Code session
3
+ argument-hint: "[pr-number]"
4
+ ---
5
+
6
+ <!-- clud-bug-local-version: v1 -->
7
+
8
+ You are running **clud-bug** as a local code review — inside this Claude Code
9
+ session, using this session's own model tokens (Max or API, whatever you have).
10
+ No hosted App, no extra auth: you already have `gh`, `git`, and file access.
11
+
12
+ ## 1. Find the PR
13
+
14
+ PR number: `$ARGUMENTS`
15
+
16
+ If `$ARGUMENTS` is empty, detect the current branch's open PR:
17
+
18
+ ```bash
19
+ gh pr list --head "$(git branch --show-current)" --state open --json number --jq '.[0].number'
20
+ ```
21
+
22
+ If there is no open PR, stop and tell the user to open one (or pass a PR number).
23
+
24
+ ## 2. Load the review skills
25
+
26
+ Read the manifest and every referenced skill body from the checkout:
27
+
28
+ - `.claude/skills/.clud-bug.json` — which skills are installed, plus `strictMode`.
29
+ - For each installed skill, `.claude/skills/<name>/SKILL.md` — the discipline to apply.
30
+
31
+ Load skills **before** the diff. At minimum the baseline set applies:
32
+ **critical-issues-only** (flag only correctness / security / performance — skip
33
+ nits), **evidence-based-review** (quote the exact line you criticize — no
34
+ hand-waving), **respect-existing-conventions** (don't fight the codebase's
35
+ established patterns).
36
+
37
+ ## 3. Fetch the diff
38
+
39
+ ```bash
40
+ gh pr diff <PR_NUMBER>
41
+ ```
42
+
43
+ ## 4. Review
44
+
45
+ Review the diff against every loaded skill. For each finding record: `file`,
46
+ `line`, `severity` (`critical` | `minor` | `preexisting`), the `skill` that
47
+ motivated it, and a one-line `summary`. Apply the skills strictly — especially
48
+ critical-issues-only (no nits) and evidence-based-review (quote the code).
49
+
50
+ ## 5. Render the review comment
51
+
52
+ Build the body in clud-bug's standard shape (omit any empty findings section):
53
+
54
+ ```
55
+ ## 🐛 Clud Bug review — <clean | critical findings>
56
+
57
+ **This round:** N critical · N minor · N resolved from prior · N still open
58
+
59
+ Found: N 🔴 / N 🟡 / N 🟣
60
+
61
+ ### Per-skill scan
62
+ - [<skill>]: <one line on what it scanned + found>
63
+
64
+ ### Critical findings
65
+ 🔴 [<skill>]: <summary> (<file>:<line>).
66
+
67
+ ### Minor findings
68
+ 🟡 [<skill>]: <summary> (<file>:<line>).
69
+
70
+ ### Pre-existing findings
71
+ 🟣 [<skill>]: <summary> (<file>:<line>).
72
+
73
+ Skills referenced: [<skill>, <skill>]
74
+
75
+ <!-- written-by: @<your-gh-login> (clud-bug local-mode) -->
76
+ <!-- review-sha: <HEAD_SHA> -->
77
+ ```
78
+
79
+ Get your gh login with `gh api user --jq .login` and the head sha with
80
+ `git rev-parse HEAD`. The `written-by` marker **MUST** end with
81
+ `(clud-bug local-mode)` so the bot's auto-resolve never mistakes this for a
82
+ `clud-bug[bot]` comment.
83
+
84
+ ## 6. Post (or update) the comment
85
+
86
+ Look for an existing local-mode comment and edit it in place (one rolling review
87
+ comment), otherwise post a fresh one. Use the **REST** issues-comments endpoint
88
+ for the lookup — its `.id` is the **integer** comment id the PATCH endpoint needs.
89
+ (Do NOT use `gh pr view --json comments`; that returns GraphQL node IDs, which
90
+ 404 on the REST PATCH and cause duplicate comments.) `gh` fills `{owner}/{repo}`.
91
+
92
+ ```bash
93
+ # existing local-mode comment id (integer), if any:
94
+ EXISTING_ID=$(gh api --paginate "repos/{owner}/{repo}/issues/<PR_NUMBER>/comments" \
95
+ --jq '[.[] | select(.body | test("written-by: @.* \\(clud-bug local-mode\\)"))] | first | .id // empty')
96
+ ```
97
+
98
+ - `$EXISTING_ID` empty → `gh pr comment <PR_NUMBER> --body-file <body.md>`
99
+ - `$EXISTING_ID` set → `gh api "repos/{owner}/{repo}/issues/comments/$EXISTING_ID" -X PATCH -F body=@<body.md>`
100
+
101
+ ## 7. Summarize
102
+
103
+ Print one line:
104
+ `clud-bug local-review: N critical · N minor · N preexisting — <PASS | FAIL (strictMode) | advisory>`
105
+
106
+ If `.clud-bug.json` has `strictMode: true` and there are critical findings, say
107
+ **FAIL** and tell the user to fix them before merging.
108
+
109
+ ---
110
+
111
+ _Optional: if the `clud-bug-mcp` MCP server is connected, you may use its
112
+ structured tools (`load_skills_from_pr_base`, `fetch_pr_diff`,
113
+ `partition_findings_by_severity`, `emit_review_comment`) in place of the raw
114
+ `gh`/`git` calls above — same flow, with the base-ref skill read and the exact
115
+ review rendering done for you._
@@ -1,4 +1,4 @@
1
- # clud-bug-template-version: v12
1
+ # clud-bug-template-version: v14
2
2
  name: Clud Bug 🐛 Crawls Your Code
3
3
 
4
4
  on:
@@ -222,7 +222,7 @@ jobs:
222
222
  # HEAD_SHA (v0.6.10+) — see workflow.yml.tmpl for design notes.
223
223
  HEAD_SHA: ${{ github.event.pull_request.head.sha }}
224
224
  # Per-section byte budgets — see workflow.yml.tmpl for design notes.
225
- MAX_DIFF_BYTES: '80000'
225
+ MAX_DIFF_BYTES: '5000000'
226
226
  MAX_COMMENT_BYTES: '20000'
227
227
  MAX_SKILL_BYTES: '4000'
228
228
  # Thinking-budget cap (v0.6.8) — see workflow.yml.tmpl for design notes.
@@ -283,6 +283,40 @@ jobs:
283
283
 
284
284
  $CALIBRATION"
285
285
 
286
+ # Wave 5a (D.2.X) — see workflow.yml.tmpl for design notes.
287
+ - name: Post inline review threads
288
+ if: success() && steps.clud-bug-review.outputs.structured_output != ''
289
+ continue-on-error: true
290
+ env:
291
+ GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
292
+ REPO: ${{ github.repository }}
293
+ PR_NUMBER: ${{ github.event.pull_request.number }}
294
+ HEAD_SHA: ${{ github.event.pull_request.head.sha }}
295
+ STRUCTURED: ${{ steps.clud-bug-review.outputs.structured_output }}
296
+ run: |
297
+ set -euo pipefail
298
+ RESULT=$(printf '%s\n' "$STRUCTURED" | npx --yes clud-bug@{{CLUD_BUG_VERSION}} post-inline-threads --stdin)
299
+ echo "::notice title=inline-threads::$RESULT"
300
+
301
+ # Wave 5b (D.2.6) — see workflow.yml.tmpl for design notes.
302
+ - name: Auto-resolve fixed threads
303
+ if: success() && github.event.action == 'synchronize'
304
+ continue-on-error: true
305
+ env:
306
+ GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
307
+ ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }}
308
+ REPO: ${{ github.repository }}
309
+ PR_NUMBER: ${{ github.event.pull_request.number }}
310
+ # Optional fine-grained PAT (Pull requests: write). Present → the
311
+ # workflow resolves fixed threads like the hosted App. Absent (the
312
+ # default; an unset secret renders empty) → graceful "verified fixed"
313
+ # reply only, since the Actions GITHUB_TOKEN can't resolve threads.
314
+ CLUD_BUG_RESOLVE_PAT: ${{ secrets.CLUD_BUG_RESOLVE_PAT }}
315
+ run: |
316
+ set -euo pipefail
317
+ RESULT=$(npx --yes clud-bug@{{CLUD_BUG_VERSION}} resolve-threads)
318
+ echo "::notice title=auto-resolve::$RESULT"
319
+
286
320
  # v0.6.29 / Component 4 — see workflow.yml.tmpl for design notes.
287
321
  - name: Update skill-usage tracking
288
322
  if: success() && steps.clud-bug-review.outputs.structured_output != ''
@@ -366,9 +400,52 @@ jobs:
366
400
  # Strict-mode gate — composite action; see workflow.yml.tmpl for design notes.
367
401
  - name: Strict mode — fail check on critical findings
368
402
  if: success()
369
- uses: thrillmade/clud-bug/.github/actions/strict-mode-gate@v0.6.34
403
+ uses: thrillmade/clud-bug/.github/actions/strict-mode-gate@v0.7.0-rc.11
370
404
  with:
371
405
  github-token: ${{ secrets.GITHUB_TOKEN }}
372
406
  # v0.6.22 / 0.0.O: summary now posted by github-actions[bot].
373
407
  # See workflow.yml.tmpl for design notes.
374
408
  bot-login: 'github-actions[bot]'
409
+
410
+ # v0.7.0-rc.3 — SPEC §7.2.1 formal-review event poster.
411
+ # See workflow.yml.tmpl for full design rationale; this step
412
+ # bridges the canonical-ruleset `required_approving_review_count: 1`
413
+ # floor on the npm workflow path. Best-effort: never fails the
414
+ # workflow (continue-on-error). Drive-by exploit guard: external
415
+ # contributors NEVER get APPROVE.
416
+ - name: Formal review — APPROVE / REQUEST_CHANGES / COMMENT
417
+ if: always() && steps.clud-bug-review.outputs.structured_output != ''
418
+ continue-on-error: true
419
+ env:
420
+ GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
421
+ PR_NUMBER: ${{ github.event.pull_request.number }}
422
+ REPO: ${{ github.repository }}
423
+ HEAD_SHA: ${{ github.event.pull_request.head.sha }}
424
+ STRUCTURED: ${{ steps.clud-bug-review.outputs.structured_output }}
425
+ PR_AUTHOR_LOGIN: ${{ github.event.pull_request.user.login }}
426
+ PR_AUTHOR_ASSOCIATION: ${{ github.event.pull_request.author_association }}
427
+ BASE_REF: ${{ github.event.pull_request.base.ref }}
428
+ run: |
429
+ set -uo pipefail
430
+ STRICT_MODE=false
431
+ if git show "origin/${BASE_REF}:.claude/skills/.clud-bug.json" > /tmp/base-manifest.json 2>/dev/null; then
432
+ if jq -e '.strictMode == true' /tmp/base-manifest.json > /dev/null 2>&1; then
433
+ STRICT_MODE=true
434
+ fi
435
+ fi
436
+ export STRICT_MODE
437
+ VERDICT=$(printf '%s\n' "$STRUCTURED" \
438
+ | npx --yes clud-bug@{{CLUD_BUG_VERSION}} select-review-event --stdin \
439
+ | tail -n1)
440
+ VERDICT="${VERDICT:-skip}"
441
+ echo "::notice title=Clud Bug 🐛::Formal review verdict: $VERDICT (strictMode=$STRICT_MODE, author_assoc=$PR_AUTHOR_ASSOCIATION)"
442
+ if [ "$VERDICT" = "skip" ]; then
443
+ exit 0
444
+ fi
445
+ BODY=$(printf 'Automated formal review by clud-bug — see the summary comment for the substantive findings.\n\nVerdict: **%s**\n\n<!-- clud-bug-formal-review: workflow-path v0.7.0-rc.3 -->' "$VERDICT")
446
+ gh api -X POST "/repos/$REPO/pulls/$PR_NUMBER/reviews" \
447
+ -f event="$VERDICT" \
448
+ -f commit_id="$HEAD_SHA" \
449
+ -f body="$BODY" \
450
+ > /dev/null \
451
+ || echo "::warning title=Clud Bug 🐛::Formal review POST failed (likely 422 self-PR or missing perms); degrading to comment-only."
@@ -1,4 +1,4 @@
1
- # clud-bug-template-version: v12
1
+ # clud-bug-template-version: v14
2
2
  name: Clud Bug 🐛 Crawls Your Code
3
3
 
4
4
  on:
@@ -222,7 +222,7 @@ jobs:
222
222
  # HEAD_SHA (v0.6.10+) — see workflow.yml.tmpl for design notes.
223
223
  HEAD_SHA: ${{ github.event.pull_request.head.sha }}
224
224
  # Per-section byte budgets — see workflow.yml.tmpl for design notes.
225
- MAX_DIFF_BYTES: '80000'
225
+ MAX_DIFF_BYTES: '5000000'
226
226
  MAX_COMMENT_BYTES: '20000'
227
227
  MAX_SKILL_BYTES: '4000'
228
228
  # Thinking-budget cap (v0.6.8) — see workflow.yml.tmpl for design notes.
@@ -283,6 +283,40 @@ jobs:
283
283
 
284
284
  $CALIBRATION"
285
285
 
286
+ # Wave 5a (D.2.X) — see workflow.yml.tmpl for design notes.
287
+ - name: Post inline review threads
288
+ if: success() && steps.clud-bug-review.outputs.structured_output != ''
289
+ continue-on-error: true
290
+ env:
291
+ GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
292
+ REPO: ${{ github.repository }}
293
+ PR_NUMBER: ${{ github.event.pull_request.number }}
294
+ HEAD_SHA: ${{ github.event.pull_request.head.sha }}
295
+ STRUCTURED: ${{ steps.clud-bug-review.outputs.structured_output }}
296
+ run: |
297
+ set -euo pipefail
298
+ RESULT=$(printf '%s\n' "$STRUCTURED" | npx --yes clud-bug@{{CLUD_BUG_VERSION}} post-inline-threads --stdin)
299
+ echo "::notice title=inline-threads::$RESULT"
300
+
301
+ # Wave 5b (D.2.6) — see workflow.yml.tmpl for design notes.
302
+ - name: Auto-resolve fixed threads
303
+ if: success() && github.event.action == 'synchronize'
304
+ continue-on-error: true
305
+ env:
306
+ GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
307
+ ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }}
308
+ REPO: ${{ github.repository }}
309
+ PR_NUMBER: ${{ github.event.pull_request.number }}
310
+ # Optional fine-grained PAT (Pull requests: write). Present → the
311
+ # workflow resolves fixed threads like the hosted App. Absent (the
312
+ # default; an unset secret renders empty) → graceful "verified fixed"
313
+ # reply only, since the Actions GITHUB_TOKEN can't resolve threads.
314
+ CLUD_BUG_RESOLVE_PAT: ${{ secrets.CLUD_BUG_RESOLVE_PAT }}
315
+ run: |
316
+ set -euo pipefail
317
+ RESULT=$(npx --yes clud-bug@{{CLUD_BUG_VERSION}} resolve-threads)
318
+ echo "::notice title=auto-resolve::$RESULT"
319
+
286
320
  # v0.6.29 / Component 4 — see workflow.yml.tmpl for design notes.
287
321
  - name: Update skill-usage tracking
288
322
  if: success() && steps.clud-bug-review.outputs.structured_output != ''
@@ -366,9 +400,52 @@ jobs:
366
400
  # Strict-mode gate — composite action; see workflow.yml.tmpl for design notes.
367
401
  - name: Strict mode — fail check on critical findings
368
402
  if: success()
369
- uses: thrillmade/clud-bug/.github/actions/strict-mode-gate@v0.6.34
403
+ uses: thrillmade/clud-bug/.github/actions/strict-mode-gate@v0.7.0-rc.11
370
404
  with:
371
405
  github-token: ${{ secrets.GITHUB_TOKEN }}
372
406
  # v0.6.22 / 0.0.O: summary now posted by github-actions[bot].
373
407
  # See workflow.yml.tmpl for design notes.
374
408
  bot-login: 'github-actions[bot]'
409
+
410
+ # v0.7.0-rc.3 — SPEC §7.2.1 formal-review event poster.
411
+ # See workflow.yml.tmpl for full design rationale; this step
412
+ # bridges the canonical-ruleset `required_approving_review_count: 1`
413
+ # floor on the npm workflow path. Best-effort: never fails the
414
+ # workflow (continue-on-error). Drive-by exploit guard: external
415
+ # contributors NEVER get APPROVE.
416
+ - name: Formal review — APPROVE / REQUEST_CHANGES / COMMENT
417
+ if: always() && steps.clud-bug-review.outputs.structured_output != ''
418
+ continue-on-error: true
419
+ env:
420
+ GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
421
+ PR_NUMBER: ${{ github.event.pull_request.number }}
422
+ REPO: ${{ github.repository }}
423
+ HEAD_SHA: ${{ github.event.pull_request.head.sha }}
424
+ STRUCTURED: ${{ steps.clud-bug-review.outputs.structured_output }}
425
+ PR_AUTHOR_LOGIN: ${{ github.event.pull_request.user.login }}
426
+ PR_AUTHOR_ASSOCIATION: ${{ github.event.pull_request.author_association }}
427
+ BASE_REF: ${{ github.event.pull_request.base.ref }}
428
+ run: |
429
+ set -uo pipefail
430
+ STRICT_MODE=false
431
+ if git show "origin/${BASE_REF}:.claude/skills/.clud-bug.json" > /tmp/base-manifest.json 2>/dev/null; then
432
+ if jq -e '.strictMode == true' /tmp/base-manifest.json > /dev/null 2>&1; then
433
+ STRICT_MODE=true
434
+ fi
435
+ fi
436
+ export STRICT_MODE
437
+ VERDICT=$(printf '%s\n' "$STRUCTURED" \
438
+ | npx --yes clud-bug@{{CLUD_BUG_VERSION}} select-review-event --stdin \
439
+ | tail -n1)
440
+ VERDICT="${VERDICT:-skip}"
441
+ echo "::notice title=Clud Bug 🐛::Formal review verdict: $VERDICT (strictMode=$STRICT_MODE, author_assoc=$PR_AUTHOR_ASSOCIATION)"
442
+ if [ "$VERDICT" = "skip" ]; then
443
+ exit 0
444
+ fi
445
+ BODY=$(printf 'Automated formal review by clud-bug — see the summary comment for the substantive findings.\n\nVerdict: **%s**\n\n<!-- clud-bug-formal-review: workflow-path v0.7.0-rc.3 -->' "$VERDICT")
446
+ gh api -X POST "/repos/$REPO/pulls/$PR_NUMBER/reviews" \
447
+ -f event="$VERDICT" \
448
+ -f commit_id="$HEAD_SHA" \
449
+ -f body="$BODY" \
450
+ > /dev/null \
451
+ || echo "::warning title=Clud Bug 🐛::Formal review POST failed (likely 422 self-PR or missing perms); degrading to comment-only."
@@ -1,4 +1,4 @@
1
- # clud-bug-template-version: v12
1
+ # clud-bug-template-version: v14
2
2
  name: Clud Bug 🐛 Crawls Your Code
3
3
 
4
4
  on:
@@ -396,12 +396,21 @@ jobs:
396
396
  # <prior_sha>..HEAD` (delta) when the SHA is still in HEAD's
397
397
  # ancestry. Fix-push reviews ingest only the new bytes.
398
398
  HEAD_SHA: ${{ github.event.pull_request.head.sha }}
399
- # Per-section byte budgets (v0.6.4). The system-prompt instructs
400
- # Claude to cap each per-PR input fetch with `head -c`. Caching
401
- # covers the stable system prefix; capping covers the variable
402
- # suffix (diff, comments, skills). Override per-repo by setting
403
- # these env vars in the consuming workflow if defaults don't fit.
404
- MAX_DIFF_BYTES: '80000'
399
+ # Per-section byte budgets (v0.6.4, MAX_DIFF_BYTES bumped 2026-06-08).
400
+ # The system-prompt instructs Claude to cap each per-PR input fetch
401
+ # with `head -c`. Caching covers the stable system prefix; capping
402
+ # covers the variable suffix (diff, comments, skills). Override
403
+ # per-repo by setting these env vars in the consuming workflow if
404
+ # defaults don't fit.
405
+ #
406
+ # 2026-06-08 CEO directive (v0.6.35): MAX_DIFF_BYTES bumped from
407
+ # 80000 (80KB) → 5000000 (5MB). The old default silently truncated
408
+ # any PR diff > 80KB, leading to half-reviews on real-world PRs.
409
+ # CEO: "a large diff should NEVER be a blocker or guard." 5MB is
410
+ # far above realistic single-PR diff sizes but bounded enough that
411
+ # the runner doesn't OOM. Repos that want stricter discipline can
412
+ # still set lower values per-repo.
413
+ MAX_DIFF_BYTES: '5000000'
405
414
  MAX_COMMENT_BYTES: '20000'
406
415
  MAX_SKILL_BYTES: '4000'
407
416
  # MAX_THINKING_TOKENS caps Claude Code's extended-thinking budget per
@@ -494,6 +503,69 @@ jobs:
494
503
 
495
504
  $CALIBRATION"
496
505
 
506
+ # v0.7.0-rc.7 / Wave 5a (D.2.X): post per-finding inline review
507
+ # threads alongside the summary comment. Each thread is anchored
508
+ # to a file + line in the diff and is a first-class GitHub review
509
+ # thread users can reply to. Each thread body carries a hidden
510
+ # `<!-- finding-id: <hash> -->` marker so Wave 5b (rc.8) auto-
511
+ # resolve can re-match findings on subsequent fix-pushes without
512
+ # any persistent state.
513
+ #
514
+ # Posted IN ADDITION TO the summary comment above — they serve
515
+ # different UX needs: the summary is the at-a-glance digest; the
516
+ # inline threads are where conversation + resolution happens.
517
+ #
518
+ # `continue-on-error` so a partial GraphQL/REST failure doesn't
519
+ # fail the whole review; the verb itself swallows errors into its
520
+ # stdout JSON and exits 0.
521
+ - name: Post inline review threads
522
+ if: success() && steps.clud-bug-review.outputs.structured_output != ''
523
+ continue-on-error: true
524
+ env:
525
+ GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
526
+ REPO: ${{ github.repository }}
527
+ PR_NUMBER: ${{ github.event.pull_request.number }}
528
+ HEAD_SHA: ${{ github.event.pull_request.head.sha }}
529
+ STRUCTURED: ${{ steps.clud-bug-review.outputs.structured_output }}
530
+ run: |
531
+ set -euo pipefail
532
+ RESULT=$(printf '%s\n' "$STRUCTURED" | npx --yes clud-bug@{{CLUD_BUG_VERSION}} post-inline-threads --stdin)
533
+ echo "::notice title=inline-threads::$RESULT"
534
+
535
+ # v0.7.0-rc.8 / Wave 5b (D.2.6): on fix-push events
536
+ # (pull_request.synchronize), ask the Anthropic Messages API per
537
+ # bot-authored unresolved inline thread whether the new commit
538
+ # addressed the original finding. ADDRESSED → resolve the thread
539
+ # + post a marker reply; UNCERTAIN / NOT_ADDRESSED → leave open.
540
+ # Fail-closed: verifier errors route to UNCERTAIN (never silently
541
+ # dismiss).
542
+ #
543
+ # Gated on `synchronize` because:
544
+ # - `opened` events have no prior threads to resolve.
545
+ # - Re-running on every event would waste verifier $ on unchanged
546
+ # state.
547
+ #
548
+ # The verb re-derives prior-finding context from the
549
+ # `<!-- finding-id: ... -->` markers Wave 5a embeds in each
550
+ # comment body, so no persistent state is needed across pushes.
551
+ - name: Auto-resolve fixed threads
552
+ if: success() && github.event.action == 'synchronize'
553
+ continue-on-error: true
554
+ env:
555
+ GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
556
+ ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }}
557
+ REPO: ${{ github.repository }}
558
+ PR_NUMBER: ${{ github.event.pull_request.number }}
559
+ # Optional fine-grained PAT (Pull requests: write). Present → the
560
+ # workflow resolves fixed threads like the hosted App. Absent (the
561
+ # default; an unset secret renders empty) → graceful "verified fixed"
562
+ # reply only, since the Actions GITHUB_TOKEN can't resolve threads.
563
+ CLUD_BUG_RESOLVE_PAT: ${{ secrets.CLUD_BUG_RESOLVE_PAT }}
564
+ run: |
565
+ set -euo pipefail
566
+ RESULT=$(npx --yes clud-bug@{{CLUD_BUG_VERSION}} resolve-threads)
567
+ echo "::notice title=auto-resolve::$RESULT"
568
+
497
569
  # v0.6.29 / Component 4: pipe structured_output through
498
570
  # `clud-bug update-skill-usage` to compute the per-skill loads +
499
571
  # citations delta from this one review. Writes to the ephemeral
@@ -632,7 +704,7 @@ jobs:
632
704
  # Letting the action's own failure fail the check is louder and right.
633
705
  - name: Strict mode — fail check on critical findings
634
706
  if: success()
635
- uses: thrillmade/clud-bug/.github/actions/strict-mode-gate@v0.6.34
707
+ uses: thrillmade/clud-bug/.github/actions/strict-mode-gate@v0.7.0-rc.11
636
708
  with:
637
709
  github-token: ${{ secrets.GITHUB_TOKEN }}
638
710
  # v0.6.22 / 0.0.O: the summary is now posted by the workflow
@@ -642,3 +714,98 @@ jobs:
642
714
  # never matches the new summary author → strict mode falls
643
715
  # open advisory for every install that opted in.
644
716
  bot-login: 'github-actions[bot]'
717
+
718
+ # v0.7.0-rc.3 — SPEC §7.2.1 formal-review event poster.
719
+ #
720
+ # Why this step exists: the canonical ruleset (SPEC §7.2) pins
721
+ # `required_approving_review_count: 1`. Before this step, the
722
+ # workflow path posted only a summary issue comment + a
723
+ # `clud-bug-review` check-run — neither of which counts as an
724
+ # approving review. So every PR on the workflow path required a
725
+ # human to click Approve, even when the bot's verdict was clean.
726
+ #
727
+ # This step bridges that gap: it pipes the same structured_output
728
+ # the render step consumed through `clud-bug select-review-event`
729
+ # (SPEC §7.2.1 rule table) and, on org-trusted authors, posts a
730
+ # formal `pulls.createReview` with `event=APPROVE` so the
731
+ # `required_approving_review_count: 1` floor flips automatically.
732
+ #
733
+ # Drive-by exploit guard: external contributors NEVER get APPROVE.
734
+ # The select-review-event verdict for any author in
735
+ # {NONE, FIRST_TIME_CONTRIBUTOR, FIRST_TIMER, MANNEQUIN} is forced
736
+ # to COMMENT — a human reviewer must explicitly Approve. See
737
+ # SPEC §7.2.1 precondition #3.
738
+ #
739
+ # Best-effort contract: this step MUST NEVER fail the workflow.
740
+ # `continue-on-error: true` ensures a malformed payload, network
741
+ # blip, or rate-limit on the formal-review API can't undo the
742
+ # already-posted summary comment. Worst case: no formal review is
743
+ # posted, falling back to today's comment-only behavior (= the
744
+ # pre-rc.3 status quo).
745
+ #
746
+ # Self-PR guard: when the PR author is `clud-bug[bot]` (D.7
747
+ # migration fan-out path that clud-bug-app authors), the verdict
748
+ # is "skip" — GitHub returns 422 on self-review, so we short-
749
+ # circuit before the network call.
750
+ - name: Formal review — APPROVE / REQUEST_CHANGES / COMMENT
751
+ if: always() && steps.clud-bug-review.outputs.structured_output != ''
752
+ continue-on-error: true
753
+ env:
754
+ GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
755
+ PR_NUMBER: ${{ github.event.pull_request.number }}
756
+ REPO: ${{ github.repository }}
757
+ HEAD_SHA: ${{ github.event.pull_request.head.sha }}
758
+ STRUCTURED: ${{ steps.clud-bug-review.outputs.structured_output }}
759
+ # SPEC §7.2.1 fields. The select-review-event command reads
760
+ # these from env (NOT stdin) so the workflow doesn't have to
761
+ # construct a nested JSON shape.
762
+ PR_AUTHOR_LOGIN: ${{ github.event.pull_request.user.login }}
763
+ PR_AUTHOR_ASSOCIATION: ${{ github.event.pull_request.author_association }}
764
+ BASE_REF: ${{ github.event.pull_request.base.ref }}
765
+ run: |
766
+ set -uo pipefail
767
+
768
+ # Resolve strictMode from the BASE ref's manifest — same
769
+ # discipline as strict-mode-gate (a PR can't opt itself out
770
+ # of strict mode by editing its own .clud-bug.json). Best-
771
+ # effort: any error here falls through to STRICT_MODE=false.
772
+ STRICT_MODE=false
773
+ if git show "origin/${BASE_REF}:.claude/skills/.clud-bug.json" > /tmp/base-manifest.json 2>/dev/null; then
774
+ if jq -e '.strictMode == true' /tmp/base-manifest.json > /dev/null 2>&1; then
775
+ STRICT_MODE=true
776
+ fi
777
+ fi
778
+ export STRICT_MODE
779
+
780
+ # Compute the verdict (one of: APPROVE / REQUEST_CHANGES /
781
+ # COMMENT / skip). The command degrades to "skip" on any
782
+ # caller-side error (malformed JSON, missing env), so we never
783
+ # need a fallback in shell.
784
+ VERDICT=$(printf '%s\n' "$STRUCTURED" \
785
+ | npx --yes clud-bug@{{CLUD_BUG_VERSION}} select-review-event --stdin \
786
+ | tail -n1)
787
+ VERDICT="${VERDICT:-skip}"
788
+
789
+ echo "::notice title=Clud Bug 🐛::Formal review verdict: $VERDICT (strictMode=$STRICT_MODE, author_assoc=$PR_AUTHOR_ASSOCIATION)"
790
+
791
+ if [ "$VERDICT" = "skip" ]; then
792
+ # Self-PR or caller-error case. No formal review posted;
793
+ # the summary comment + check-run remain the visible review
794
+ # surface. This is the pre-rc.3 status quo.
795
+ exit 0
796
+ fi
797
+
798
+ # Body is short + machine-pingable: human reviewers see the
799
+ # summary issue comment for the substantive review surface;
800
+ # the formal-review body is a cross-link.
801
+ BODY=$(printf 'Automated formal review by clud-bug — see the summary comment for the substantive findings.\n\nVerdict: **%s**\n\n<!-- clud-bug-formal-review: workflow-path v0.7.0-rc.3 -->' "$VERDICT")
802
+
803
+ # gh api fires `pulls.createReview` with the verdict event.
804
+ # commit_id pins the review to the exact SHA we reviewed so a
805
+ # later push doesn't auto-extend the approval scope.
806
+ gh api -X POST "/repos/$REPO/pulls/$PR_NUMBER/reviews" \
807
+ -f event="$VERDICT" \
808
+ -f commit_id="$HEAD_SHA" \
809
+ -f body="$BODY" \
810
+ > /dev/null \
811
+ || echo "::warning title=Clud Bug 🐛::Formal review POST failed (likely 422 self-PR or missing perms); degrading to comment-only."