clud-bug 0.6.3 → 0.6.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/prompts.js +64 -2
- package/lib/skills.js +23 -0
- package/package.json +1 -1
- package/templates/workflow-py.yml.tmpl +8 -2
- package/templates/workflow-ts.yml.tmpl +8 -2
- package/templates/workflow.yml.tmpl +12 -2
package/lib/prompts.js
CHANGED
|
@@ -57,6 +57,32 @@ ${focusBullets}
|
|
|
57
57
|
Skip style suggestions, minor naming issues, or anything that
|
|
58
58
|
doesn't affect correctness, security, or performance.
|
|
59
59
|
|
|
60
|
+
Section budgets (token-frugal review — v0.6.4+):
|
|
61
|
+
The workflow sets env vars MAX_DIFF_BYTES / MAX_COMMENT_BYTES /
|
|
62
|
+
MAX_SKILL_BYTES. When fetching content via the Bash tool, cap each
|
|
63
|
+
section with \`head -c\` to keep your context lean. Caching covers
|
|
64
|
+
the stable system-prompt prefix (you're reading it now) at 10% of
|
|
65
|
+
standard input cost, but variable per-PR content is NOT cached, so
|
|
66
|
+
size discipline on those fetches pays back directly.
|
|
67
|
+
|
|
68
|
+
- PR diff: \`gh pr diff "$PR_NUMBER" | head -c "$MAX_DIFF_BYTES"\`
|
|
69
|
+
(default 80,000 bytes — covers ~95% of real PRs unbruised). If
|
|
70
|
+
the output looks truncated mid-line, note it in your review and
|
|
71
|
+
request the omitted hunks via \`gh pr diff "$PR_NUMBER" --name-only\`
|
|
72
|
+
+ a targeted re-fetch of the specific files that need scrutiny.
|
|
73
|
+
|
|
74
|
+
- Skill files: \`head -c "$MAX_SKILL_BYTES" .claude/skills/<name>/SKILL.md\`
|
|
75
|
+
per file (default 4,000 bytes). Baseline skills fit easily;
|
|
76
|
+
bloated user-added skills get truncated.
|
|
77
|
+
|
|
78
|
+
- PR comments: \`gh api "repos/$REPO_OWNER/$REPO_NAME/issues/$PR_NUMBER/comments?per_page=20" --jq '.[] | select(.user.login != "claude[bot]")' | head -c "$MAX_COMMENT_BYTES"\`
|
|
79
|
+
(default 20,000 bytes, 20 most-recent). Skips your own prior
|
|
80
|
+
comments — the FIX-PUSH FLOW handles those via reviewThreads
|
|
81
|
+
GraphQL instead.
|
|
82
|
+
|
|
83
|
+
If you genuinely cannot review safely without the elided content,
|
|
84
|
+
say so plainly in the summary comment instead of speculating.
|
|
85
|
+
|
|
60
86
|
Skills are not background context — they are review rules with
|
|
61
87
|
authority. Before flagging any finding, scan the loaded skills in
|
|
62
88
|
.claude/skills/ for relevant guidance. If a skill applies, your
|
|
@@ -78,8 +104,8 @@ frontmatter at .claude/skills/<name>/SKILL.md. Two values:
|
|
|
78
104
|
|
|
79
105
|
Before writing the review, scan each loaded skill's frontmatter
|
|
80
106
|
(the first \`---\`-delimited block of its SKILL.md) to identify
|
|
81
|
-
its review_mode.
|
|
82
|
-
|
|
107
|
+
its review_mode. Read each one capped at MAX_SKILL_BYTES:
|
|
108
|
+
head -c "$MAX_SKILL_BYTES" .claude/skills/*/SKILL.md
|
|
83
109
|
|
|
84
110
|
At the end of every review, append a single-line footer:
|
|
85
111
|
Skills referenced: [skill-name-1, skill-name-2, ...]
|
|
@@ -186,6 +212,42 @@ On a first-time review, "resolved from prior" and "still
|
|
|
186
212
|
open" are both 0. On follow-up reviews after a fix-push,
|
|
187
213
|
"resolved from prior" should typically be positive.
|
|
188
214
|
|
|
215
|
+
Stats header (required, immediately under **This round:**):
|
|
216
|
+
Lead with ONE single-line stats header that uses severity emoji
|
|
217
|
+
so agents re-reading this comment on a future review pass can
|
|
218
|
+
triage at a glance (and skip parsing the body on the common
|
|
219
|
+
zero-findings case). Three tiers:
|
|
220
|
+
|
|
221
|
+
🔴 important — bugs / security / perf / missing test coverage
|
|
222
|
+
🟡 nit — minor suggestions, style nits, observations
|
|
223
|
+
🟣 pre-existing — issues that pre-date this PR (not its author's
|
|
224
|
+
fault, but worth surfacing for awareness)
|
|
225
|
+
|
|
226
|
+
Emit exactly this shape on the line immediately after **This round:**:
|
|
227
|
+
|
|
228
|
+
Found: N 🔴 / N 🟡 / N 🟣
|
|
229
|
+
|
|
230
|
+
When all three are 0 the entire substantive body is optional —
|
|
231
|
+
agents reading this header on a future re-review can stop here.
|
|
232
|
+
|
|
233
|
+
Per-finding format (severity emoji + collapsible reasoning):
|
|
234
|
+
Each finding in critical/minor/per-skill sections uses this
|
|
235
|
+
write-time-compressed format. The summary line is the load-bearing
|
|
236
|
+
claim; the long-form reasoning lives in a \`<details>\` block that
|
|
237
|
+
humans expand inline (GitHub renders it natively) but future agent
|
|
238
|
+
re-reads can skip token-cheaply.
|
|
239
|
+
|
|
240
|
+
🔴 [skill-name]: One-line claim (file:line).
|
|
241
|
+
<details><summary>Reasoning</summary>
|
|
242
|
+
|
|
243
|
+
Longer explanation: evidence anchors, suggested fix, edge cases.
|
|
244
|
+
|
|
245
|
+
</details>
|
|
246
|
+
|
|
247
|
+
Use 🔴 for important findings (the ones strict-mode gates on),
|
|
248
|
+
🟡 for nits, 🟣 for pre-existing issues. The severity emoji
|
|
249
|
+
makes the finding's tier scannable without parsing prose.
|
|
250
|
+
|
|
189
251
|
Per-skill scan block (required, immediately under the status line):
|
|
190
252
|
After the **This round:** counters, emit a "### Per-skill scan"
|
|
191
253
|
section with ONE line per loaded skill — even silent ones. This
|
package/lib/skills.js
CHANGED
|
@@ -537,6 +537,29 @@ export function selectReviewBody(comments, botLogin) {
|
|
|
537
537
|
// passing — which is the right posture: if the bot didn't post a review
|
|
538
538
|
// with the strict-mode header, there's nothing for the gate to fail on.
|
|
539
539
|
// "Loud failure for missing manifest" is handled upstream in the composite.
|
|
540
|
+
// Extract the v0.6.5+ stats header line "Found: N 🔴 / N 🟡 / N 🟣"
|
|
541
|
+
// from a review comment body. Returns {important, nit, preExisting} when
|
|
542
|
+
// found, null otherwise. The header lets agents reading the comment on a
|
|
543
|
+
// re-review triage at a glance — on the common zero-findings case, the
|
|
544
|
+
// header IS the entire substantive payload, so an ingest can short-circuit
|
|
545
|
+
// without parsing the body.
|
|
546
|
+
//
|
|
547
|
+
// The match is intentionally permissive on whitespace around the slashes
|
|
548
|
+
// and tolerates 1+ digits for each count. Severity emoji are matched
|
|
549
|
+
// literally — a future bot revision that changes the emoji would break
|
|
550
|
+
// this parser loudly, which is the intended behavior (catches drift).
|
|
551
|
+
export function extractStatsHeader(comment) {
|
|
552
|
+
if (typeof comment !== 'string' || !comment) return null;
|
|
553
|
+
const re = /Found:\s*(\d+)\s*🔴\s*\/\s*(\d+)\s*🟡\s*\/\s*(\d+)\s*🟣/u;
|
|
554
|
+
const m = comment.match(re);
|
|
555
|
+
if (!m) return null;
|
|
556
|
+
return {
|
|
557
|
+
important: parseInt(m[1], 10),
|
|
558
|
+
nit: parseInt(m[2], 10),
|
|
559
|
+
preExisting: parseInt(m[3], 10),
|
|
560
|
+
};
|
|
561
|
+
}
|
|
562
|
+
|
|
540
563
|
export function isCriticalReviewHeader(headerLine) {
|
|
541
564
|
if (typeof headerLine !== 'string') return false;
|
|
542
565
|
return /Clud Bug review — critical findings/.test(headerLine);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "clud-bug",
|
|
3
|
-
"version": "0.6.
|
|
3
|
+
"version": "0.6.5",
|
|
4
4
|
"description": "Skill-driven Claude PR review. Ship a brand-voice skill, get brand reviews. Each finding cites the skill that motivated it. CLI installs the workflow + a baseline kit; add more from skills.sh.",
|
|
5
5
|
"homepage": "https://cludbug.dev",
|
|
6
6
|
"bugs": "https://github.com/thrillmade/clud-bug/issues",
|
|
@@ -54,6 +54,12 @@ jobs:
|
|
|
54
54
|
if: steps.guard.outputs.skip != 'true'
|
|
55
55
|
env:
|
|
56
56
|
PR_NUMBER: ${{ github.event.pull_request.number }}
|
|
57
|
+
REPO_OWNER: ${{ github.repository_owner }}
|
|
58
|
+
REPO_NAME: ${{ github.event.repository.name }}
|
|
59
|
+
# Per-section byte budgets — see workflow.yml.tmpl for design notes.
|
|
60
|
+
MAX_DIFF_BYTES: '80000'
|
|
61
|
+
MAX_COMMENT_BYTES: '20000'
|
|
62
|
+
MAX_SKILL_BYTES: '4000'
|
|
57
63
|
# Stable prefix → CLI auto-cached system layer (10% cost on hits).
|
|
58
64
|
# See workflow.yml.tmpl for design notes.
|
|
59
65
|
APPEND_SYSTEM_PROMPT: |
|
|
@@ -63,7 +69,7 @@ jobs:
|
|
|
63
69
|
track_progress: true
|
|
64
70
|
show_full_output: true
|
|
65
71
|
claude_args: |
|
|
66
|
-
--allowedTools "mcp__github_inline_comment__create_inline_comment,Bash(gh pr comment:*),Bash(gh pr diff:*),Bash(gh pr view:*),Bash(gh api graphql:*),Bash(gh api repos/:*),Bash(git show:*),Bash(cat .claude/skills/.clud-bug.json),Bash(cat .claude/skills/*/SKILL.md)"
|
|
72
|
+
--allowedTools "mcp__github_inline_comment__create_inline_comment,Bash(gh pr comment:*),Bash(gh pr diff:*),Bash(gh pr view:*),Bash(gh api graphql:*),Bash(gh api repos/:*),Bash(git show:*),Bash(cat .claude/skills/.clud-bug.json),Bash(cat .claude/skills/*/SKILL.md),Bash(head:*)"
|
|
67
73
|
prompt: |
|
|
68
74
|
Review this pull request following the discipline in your
|
|
69
75
|
system prompt — every rule about skill routing, comment
|
|
@@ -73,6 +79,6 @@ jobs:
|
|
|
73
79
|
# Strict-mode gate — composite action; see workflow.yml.tmpl for design notes.
|
|
74
80
|
- name: Strict mode — fail check on critical findings
|
|
75
81
|
if: success()
|
|
76
|
-
uses: thrillmade/clud-bug/.github/actions/strict-mode-gate@v0.6.
|
|
82
|
+
uses: thrillmade/clud-bug/.github/actions/strict-mode-gate@v0.6.5
|
|
77
83
|
with:
|
|
78
84
|
github-token: ${{ secrets.GITHUB_TOKEN }}
|
|
@@ -54,6 +54,12 @@ jobs:
|
|
|
54
54
|
if: steps.guard.outputs.skip != 'true'
|
|
55
55
|
env:
|
|
56
56
|
PR_NUMBER: ${{ github.event.pull_request.number }}
|
|
57
|
+
REPO_OWNER: ${{ github.repository_owner }}
|
|
58
|
+
REPO_NAME: ${{ github.event.repository.name }}
|
|
59
|
+
# Per-section byte budgets — see workflow.yml.tmpl for design notes.
|
|
60
|
+
MAX_DIFF_BYTES: '80000'
|
|
61
|
+
MAX_COMMENT_BYTES: '20000'
|
|
62
|
+
MAX_SKILL_BYTES: '4000'
|
|
57
63
|
# Stable prefix → CLI auto-cached system layer (10% cost on hits).
|
|
58
64
|
# See workflow.yml.tmpl for design notes.
|
|
59
65
|
APPEND_SYSTEM_PROMPT: |
|
|
@@ -63,7 +69,7 @@ jobs:
|
|
|
63
69
|
track_progress: true
|
|
64
70
|
show_full_output: true
|
|
65
71
|
claude_args: |
|
|
66
|
-
--allowedTools "mcp__github_inline_comment__create_inline_comment,Bash(gh pr comment:*),Bash(gh pr diff:*),Bash(gh pr view:*),Bash(gh api graphql:*),Bash(gh api repos/:*),Bash(git show:*),Bash(cat .claude/skills/.clud-bug.json),Bash(cat .claude/skills/*/SKILL.md)"
|
|
72
|
+
--allowedTools "mcp__github_inline_comment__create_inline_comment,Bash(gh pr comment:*),Bash(gh pr diff:*),Bash(gh pr view:*),Bash(gh api graphql:*),Bash(gh api repos/:*),Bash(git show:*),Bash(cat .claude/skills/.clud-bug.json),Bash(cat .claude/skills/*/SKILL.md),Bash(head:*)"
|
|
67
73
|
prompt: |
|
|
68
74
|
Review this pull request following the discipline in your
|
|
69
75
|
system prompt — every rule about skill routing, comment
|
|
@@ -73,6 +79,6 @@ jobs:
|
|
|
73
79
|
# Strict-mode gate — composite action; see workflow.yml.tmpl for design notes.
|
|
74
80
|
- name: Strict mode — fail check on critical findings
|
|
75
81
|
if: success()
|
|
76
|
-
uses: thrillmade/clud-bug/.github/actions/strict-mode-gate@v0.6.
|
|
82
|
+
uses: thrillmade/clud-bug/.github/actions/strict-mode-gate@v0.6.5
|
|
77
83
|
with:
|
|
78
84
|
github-token: ${{ secrets.GITHUB_TOKEN }}
|
|
@@ -80,6 +80,16 @@ jobs:
|
|
|
80
80
|
if: steps.guard.outputs.skip != 'true'
|
|
81
81
|
env:
|
|
82
82
|
PR_NUMBER: ${{ github.event.pull_request.number }}
|
|
83
|
+
REPO_OWNER: ${{ github.repository_owner }}
|
|
84
|
+
REPO_NAME: ${{ github.event.repository.name }}
|
|
85
|
+
# Per-section byte budgets (v0.6.4). The system-prompt instructs
|
|
86
|
+
# Claude to cap each per-PR input fetch with `head -c`. Caching
|
|
87
|
+
# covers the stable system prefix; capping covers the variable
|
|
88
|
+
# suffix (diff, comments, skills). Override per-repo by setting
|
|
89
|
+
# these env vars in the consuming workflow if defaults don't fit.
|
|
90
|
+
MAX_DIFF_BYTES: '80000'
|
|
91
|
+
MAX_COMMENT_BYTES: '20000'
|
|
92
|
+
MAX_SKILL_BYTES: '4000'
|
|
83
93
|
# APPEND_SYSTEM_PROMPT lands inside the Claude Code CLI's auto-cached
|
|
84
94
|
# system layer (system prompt, tools, conversation history). Anthropic
|
|
85
95
|
# bills cached input tokens at 10% of standard input — within a 5-min
|
|
@@ -98,7 +108,7 @@ jobs:
|
|
|
98
108
|
# measure caching effectiveness post-rollout (per v0.6.3 plan).
|
|
99
109
|
show_full_output: true
|
|
100
110
|
claude_args: |
|
|
101
|
-
--allowedTools "mcp__github_inline_comment__create_inline_comment,Bash(gh pr comment:*),Bash(gh pr diff:*),Bash(gh pr view:*),Bash(gh api graphql:*),Bash(gh api repos/:*),Bash(git show:*),Bash(cat .claude/skills/.clud-bug.json),Bash(cat .claude/skills/*/SKILL.md)"
|
|
111
|
+
--allowedTools "mcp__github_inline_comment__create_inline_comment,Bash(gh pr comment:*),Bash(gh pr diff:*),Bash(gh pr view:*),Bash(gh api graphql:*),Bash(gh api repos/:*),Bash(git show:*),Bash(cat .claude/skills/.clud-bug.json),Bash(cat .claude/skills/*/SKILL.md),Bash(head:*)"
|
|
102
112
|
prompt: |
|
|
103
113
|
Review this pull request following the discipline in your
|
|
104
114
|
system prompt — every rule about skill routing, comment
|
|
@@ -120,6 +130,6 @@ jobs:
|
|
|
120
130
|
# Letting the action's own failure fail the check is louder and right.
|
|
121
131
|
- name: Strict mode — fail check on critical findings
|
|
122
132
|
if: success()
|
|
123
|
-
uses: thrillmade/clud-bug/.github/actions/strict-mode-gate@v0.6.
|
|
133
|
+
uses: thrillmade/clud-bug/.github/actions/strict-mode-gate@v0.6.5
|
|
124
134
|
with:
|
|
125
135
|
github-token: ${{ secrets.GITHUB_TOKEN }}
|