clud-bug 0.6.14 → 0.6.16

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 CHANGED
@@ -151,6 +151,16 @@ At the end of every review, append a single-line footer:
151
151
  If you genuinely cited none, list "[none]" and explain why no
152
152
  installed skill applied to this diff.
153
153
 
154
+ Output-token budget (v0.6.16 / 0.0.X):
155
+ Keep total output under ~600 tokens. Per finding:
156
+ - One-sentence claim
157
+ - <details>Reasoning</details> ≤ 80 words
158
+ - No code quotes > 2 lines
159
+ - Omit reasoning details that don't change the verdict
160
+ This isn't a hard cap — the SDK doesn't expose max_tokens — but a
161
+ discipline. Verbose output costs the consuming repo on every review;
162
+ brevity compounds across the org.
163
+
154
164
  Incremental-diff handshake (v0.6.10+) — emit the SHA marker:
155
165
  At the very end of the summary comment (after the Skills-referenced
156
166
  footer, on its own line), append the HTML marker that the next
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "clud-bug",
3
- "version": "0.6.14",
3
+ "version": "0.6.16",
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",
@@ -6,7 +6,7 @@ on:
6
6
  types: [opened, synchronize]
7
7
 
8
8
  jobs:
9
- # Pre-flight (v0.6.14 / 0.0.W) — see workflow.yml.tmpl for design notes.
9
+ # Pre-flight (v0.6.14 / 0.0.W + v0.6.15 / 0.0.R) — see workflow.yml.tmpl.
10
10
  paths-check:
11
11
  runs-on: ubuntu-latest
12
12
  permissions:
@@ -14,6 +14,7 @@ jobs:
14
14
  pull-requests: read
15
15
  outputs:
16
16
  is_workflow_only: ${{ steps.classify.outputs.is_workflow_only }}
17
+ model: ${{ steps.classify.outputs.model }}
17
18
  steps:
18
19
  - name: Classify PR diff
19
20
  id: classify
@@ -21,9 +22,15 @@ jobs:
21
22
  GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
22
23
  PR_NUMBER: ${{ github.event.pull_request.number }}
23
24
  REPO: ${{ github.repository }}
25
+ PR_AUTHOR: ${{ github.event.pull_request.user.login }}
24
26
  run: |
25
27
  CHANGED=$(gh pr diff "$PR_NUMBER" -R "$REPO" --name-only)
26
- if [ -z "$CHANGED" ]; then echo "is_workflow_only=false" >> "$GITHUB_OUTPUT"; exit 0; fi
28
+ MODEL=claude-sonnet-4-6
29
+ if [ -z "$CHANGED" ]; then
30
+ echo "is_workflow_only=false" >> "$GITHUB_OUTPUT"
31
+ echo "model=$MODEL" >> "$GITHUB_OUTPUT"
32
+ exit 0
33
+ fi
27
34
  IS_WORKFLOW_ONLY=true
28
35
  while IFS= read -r f; do
29
36
  case "$f" in
@@ -35,7 +42,38 @@ jobs:
35
42
  echo "is_workflow_only=$IS_WORKFLOW_ONLY" >> "$GITHUB_OUTPUT"
36
43
  if [ "$IS_WORKFLOW_ONLY" = "true" ]; then
37
44
  echo "::notice title=Clud Bug 🐛::Skipping LLM review — workflow-only PR."
45
+ echo "model=$MODEL" >> "$GITHUB_OUTPUT"
46
+ exit 0
47
+ fi
48
+ # Triviality (0.0.R): dep-bumping bot OR small dep-manifest diff.
49
+ IS_TRIVIAL=false
50
+ case "$PR_AUTHOR" in
51
+ dependabot\[bot\]|renovate\[bot\]) IS_TRIVIAL=true ;;
52
+ esac
53
+ if [ "$IS_TRIVIAL" = "false" ]; then
54
+ DIFF_SIZE=$(gh pr diff "$PR_NUMBER" -R "$REPO" | wc -c | tr -d ' ')
55
+ if [ "$DIFF_SIZE" -lt 2048 ]; then
56
+ ALL_TRIVIAL=true
57
+ while IFS= read -r f; do
58
+ case "$f" in
59
+ package.json|*/package.json|package-lock.json|*/package-lock.json) ;;
60
+ pnpm-lock.yaml|*/pnpm-lock.yaml|yarn.lock|*/yarn.lock) ;;
61
+ requirements*.txt|*/requirements*.txt) ;;
62
+ pyproject.toml|*/pyproject.toml|poetry.lock|*/poetry.lock|uv.lock|*/uv.lock) ;;
63
+ Gemfile|*/Gemfile|Gemfile.lock|*/Gemfile.lock) ;;
64
+ go.mod|*/go.mod|go.sum|*/go.sum) ;;
65
+ Cargo.toml|*/Cargo.toml|Cargo.lock|*/Cargo.lock) ;;
66
+ *) ALL_TRIVIAL=false; break ;;
67
+ esac
68
+ done <<< "$CHANGED"
69
+ [ "$ALL_TRIVIAL" = "true" ] && IS_TRIVIAL=true
70
+ fi
71
+ fi
72
+ if [ "$IS_TRIVIAL" = "true" ]; then
73
+ MODEL=claude-haiku-4-5-20251001
74
+ echo "::notice title=Clud Bug 🐛::Trivial PR — routing to Haiku."
38
75
  fi
76
+ echo "model=$MODEL" >> "$GITHUB_OUTPUT"
39
77
 
40
78
  clud-bug-review:
41
79
  needs: paths-check
@@ -106,7 +144,7 @@ jobs:
106
144
  track_progress: true
107
145
  show_full_output: true
108
146
  claude_args: |
109
- --model claude-sonnet-4-6
147
+ --model ${{ needs.paths-check.outputs.model }}
110
148
  --max-turns 15
111
149
  --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(git diff:*),Bash(git merge-base:*),Bash(cat .claude/skills/.clud-bug.json),Bash(cat .claude/skills/*/SKILL.md),Bash(head:*)"
112
150
  prompt: |
@@ -118,6 +156,6 @@ jobs:
118
156
  # Strict-mode gate — composite action; see workflow.yml.tmpl for design notes.
119
157
  - name: Strict mode — fail check on critical findings
120
158
  if: success()
121
- uses: thrillmade/clud-bug/.github/actions/strict-mode-gate@v0.6.14
159
+ uses: thrillmade/clud-bug/.github/actions/strict-mode-gate@v0.6.16
122
160
  with:
123
161
  github-token: ${{ secrets.GITHUB_TOKEN }}
@@ -6,7 +6,7 @@ on:
6
6
  types: [opened, synchronize]
7
7
 
8
8
  jobs:
9
- # Pre-flight (v0.6.14 / 0.0.W) — see workflow.yml.tmpl for design notes.
9
+ # Pre-flight (v0.6.14 / 0.0.W + v0.6.15 / 0.0.R) — see workflow.yml.tmpl.
10
10
  paths-check:
11
11
  runs-on: ubuntu-latest
12
12
  permissions:
@@ -14,6 +14,7 @@ jobs:
14
14
  pull-requests: read
15
15
  outputs:
16
16
  is_workflow_only: ${{ steps.classify.outputs.is_workflow_only }}
17
+ model: ${{ steps.classify.outputs.model }}
17
18
  steps:
18
19
  - name: Classify PR diff
19
20
  id: classify
@@ -21,9 +22,15 @@ jobs:
21
22
  GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
22
23
  PR_NUMBER: ${{ github.event.pull_request.number }}
23
24
  REPO: ${{ github.repository }}
25
+ PR_AUTHOR: ${{ github.event.pull_request.user.login }}
24
26
  run: |
25
27
  CHANGED=$(gh pr diff "$PR_NUMBER" -R "$REPO" --name-only)
26
- if [ -z "$CHANGED" ]; then echo "is_workflow_only=false" >> "$GITHUB_OUTPUT"; exit 0; fi
28
+ MODEL=claude-sonnet-4-6
29
+ if [ -z "$CHANGED" ]; then
30
+ echo "is_workflow_only=false" >> "$GITHUB_OUTPUT"
31
+ echo "model=$MODEL" >> "$GITHUB_OUTPUT"
32
+ exit 0
33
+ fi
27
34
  IS_WORKFLOW_ONLY=true
28
35
  while IFS= read -r f; do
29
36
  case "$f" in
@@ -35,7 +42,38 @@ jobs:
35
42
  echo "is_workflow_only=$IS_WORKFLOW_ONLY" >> "$GITHUB_OUTPUT"
36
43
  if [ "$IS_WORKFLOW_ONLY" = "true" ]; then
37
44
  echo "::notice title=Clud Bug 🐛::Skipping LLM review — workflow-only PR."
45
+ echo "model=$MODEL" >> "$GITHUB_OUTPUT"
46
+ exit 0
47
+ fi
48
+ # Triviality (0.0.R): dep-bumping bot OR small dep-manifest diff.
49
+ IS_TRIVIAL=false
50
+ case "$PR_AUTHOR" in
51
+ dependabot\[bot\]|renovate\[bot\]) IS_TRIVIAL=true ;;
52
+ esac
53
+ if [ "$IS_TRIVIAL" = "false" ]; then
54
+ DIFF_SIZE=$(gh pr diff "$PR_NUMBER" -R "$REPO" | wc -c | tr -d ' ')
55
+ if [ "$DIFF_SIZE" -lt 2048 ]; then
56
+ ALL_TRIVIAL=true
57
+ while IFS= read -r f; do
58
+ case "$f" in
59
+ package.json|*/package.json|package-lock.json|*/package-lock.json) ;;
60
+ pnpm-lock.yaml|*/pnpm-lock.yaml|yarn.lock|*/yarn.lock) ;;
61
+ requirements*.txt|*/requirements*.txt) ;;
62
+ pyproject.toml|*/pyproject.toml|poetry.lock|*/poetry.lock|uv.lock|*/uv.lock) ;;
63
+ Gemfile|*/Gemfile|Gemfile.lock|*/Gemfile.lock) ;;
64
+ go.mod|*/go.mod|go.sum|*/go.sum) ;;
65
+ Cargo.toml|*/Cargo.toml|Cargo.lock|*/Cargo.lock) ;;
66
+ *) ALL_TRIVIAL=false; break ;;
67
+ esac
68
+ done <<< "$CHANGED"
69
+ [ "$ALL_TRIVIAL" = "true" ] && IS_TRIVIAL=true
70
+ fi
71
+ fi
72
+ if [ "$IS_TRIVIAL" = "true" ]; then
73
+ MODEL=claude-haiku-4-5-20251001
74
+ echo "::notice title=Clud Bug 🐛::Trivial PR — routing to Haiku."
38
75
  fi
76
+ echo "model=$MODEL" >> "$GITHUB_OUTPUT"
39
77
 
40
78
  clud-bug-review:
41
79
  needs: paths-check
@@ -106,7 +144,7 @@ jobs:
106
144
  track_progress: true
107
145
  show_full_output: true
108
146
  claude_args: |
109
- --model claude-sonnet-4-6
147
+ --model ${{ needs.paths-check.outputs.model }}
110
148
  --max-turns 15
111
149
  --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(git diff:*),Bash(git merge-base:*),Bash(cat .claude/skills/.clud-bug.json),Bash(cat .claude/skills/*/SKILL.md),Bash(head:*)"
112
150
  prompt: |
@@ -118,6 +156,6 @@ jobs:
118
156
  # Strict-mode gate — composite action; see workflow.yml.tmpl for design notes.
119
157
  - name: Strict mode — fail check on critical findings
120
158
  if: success()
121
- uses: thrillmade/clud-bug/.github/actions/strict-mode-gate@v0.6.14
159
+ uses: thrillmade/clud-bug/.github/actions/strict-mode-gate@v0.6.16
122
160
  with:
123
161
  github-token: ${{ secrets.GITHUB_TOKEN }}
@@ -6,15 +6,21 @@ on:
6
6
  types: [opened, synchronize]
7
7
 
8
8
  jobs:
9
- # Pre-flight (v0.6.14 / 0.0.W): if the PR ONLY touches clud-bug workflow
10
- # files or the strict-mode-gate composite action, skip the LLM review
11
- # entirely. claude-code-action would refuse to run on such a PR anyway
12
- # (self-modification guard required for security), and a template
13
- # re-render has no useful review surface. Skipping turns a previously
14
- # required-admin-bypass merge into a normal one, AND saves the LLM
15
- # call cost. Security: the classifier requires ALL changed files to
16
- # match the allow-list a mixed PR (workflow + code) still runs the
17
- # review normally.
9
+ # Pre-flight: classify the PR diff to decide (a) whether to skip the
10
+ # LLM review entirely, and (b) which model to route to.
11
+ #
12
+ # (a) Workflow-only PRs (v0.6.14 / 0.0.W): if every changed file
13
+ # matches `.github/workflows/clud-bug-*.yml` or
14
+ # `.github/actions/strict-mode-gate/**`, the LLM call is skipped
15
+ # entirely claude-code-action would refuse anyway (self-modification
16
+ # guard), and template re-renders have no useful review surface.
17
+ # Skipping converts what were admin-bypass merges into normal ones.
18
+ #
19
+ # (b) Trivial PRs (v0.6.15 / 0.0.R): if the PR author is a dep-bumping
20
+ # bot (dependabot, renovate) OR the diff is small (<2KB) AND only
21
+ # touches dependency-manifest files, route the review to Haiku
22
+ # ($0.80/MTok input vs Sonnet's $3) — another ~75% cost reduction on
23
+ # this PR class. Sonnet remains the default for everything else.
18
24
  paths-check:
19
25
  runs-on: ubuntu-latest
20
26
  permissions:
@@ -22,6 +28,7 @@ jobs:
22
28
  pull-requests: read
23
29
  outputs:
24
30
  is_workflow_only: ${{ steps.classify.outputs.is_workflow_only }}
31
+ model: ${{ steps.classify.outputs.model }}
25
32
  steps:
26
33
  - name: Classify PR diff
27
34
  id: classify
@@ -29,12 +36,17 @@ jobs:
29
36
  GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
30
37
  PR_NUMBER: ${{ github.event.pull_request.number }}
31
38
  REPO: ${{ github.repository }}
39
+ PR_AUTHOR: ${{ github.event.pull_request.user.login }}
32
40
  run: |
33
41
  CHANGED=$(gh pr diff "$PR_NUMBER" -R "$REPO" --name-only)
42
+ MODEL=claude-sonnet-4-6 # default
34
43
  if [ -z "$CHANGED" ]; then
35
44
  echo "is_workflow_only=false" >> "$GITHUB_OUTPUT"
45
+ echo "model=$MODEL" >> "$GITHUB_OUTPUT"
36
46
  exit 0
37
47
  fi
48
+
49
+ # --- (a) workflow-only classifier ---
38
50
  IS_WORKFLOW_ONLY=true
39
51
  while IFS= read -r f; do
40
52
  case "$f" in
@@ -45,8 +57,50 @@ jobs:
45
57
  done <<< "$CHANGED"
46
58
  echo "is_workflow_only=$IS_WORKFLOW_ONLY" >> "$GITHUB_OUTPUT"
47
59
  if [ "$IS_WORKFLOW_ONLY" = "true" ]; then
48
- echo "::notice title=Clud Bug 🐛::Skipping LLM review — PR only touches workflow files (claude-code-action would refuse anyway due to self-modification guard)."
60
+ echo "::notice title=Clud Bug 🐛::Skipping LLM review — PR only touches workflow files."
61
+ echo "model=$MODEL" >> "$GITHUB_OUTPUT"
62
+ exit 0
63
+ fi
64
+
65
+ # --- (b) triviality classifier ---
66
+ IS_TRIVIAL=false
67
+ # Bot authors that exclusively open dep-bump PRs go straight
68
+ # to Haiku regardless of diff size — lockfile churn can be huge
69
+ # but the review surface is shallow.
70
+ case "$PR_AUTHOR" in
71
+ dependabot\[bot\]|renovate\[bot\]) IS_TRIVIAL=true ;;
72
+ esac
73
+ # Otherwise: diff < 2KB AND every file matches the dep-manifest
74
+ # allow-list. Manual lockfile fixes / small version pins
75
+ # qualify; real feature work does not.
76
+ if [ "$IS_TRIVIAL" = "false" ]; then
77
+ DIFF_SIZE=$(gh pr diff "$PR_NUMBER" -R "$REPO" | wc -c | tr -d ' ')
78
+ if [ "$DIFF_SIZE" -lt 2048 ]; then
79
+ ALL_TRIVIAL=true
80
+ while IFS= read -r f; do
81
+ case "$f" in
82
+ package.json|*/package.json) ;;
83
+ package-lock.json|*/package-lock.json) ;;
84
+ pnpm-lock.yaml|*/pnpm-lock.yaml) ;;
85
+ yarn.lock|*/yarn.lock) ;;
86
+ requirements*.txt|*/requirements*.txt) ;;
87
+ pyproject.toml|*/pyproject.toml) ;;
88
+ poetry.lock|*/poetry.lock) ;;
89
+ uv.lock|*/uv.lock) ;;
90
+ Gemfile|*/Gemfile|Gemfile.lock|*/Gemfile.lock) ;;
91
+ go.mod|*/go.mod|go.sum|*/go.sum) ;;
92
+ Cargo.toml|*/Cargo.toml|Cargo.lock|*/Cargo.lock) ;;
93
+ *) ALL_TRIVIAL=false; break ;;
94
+ esac
95
+ done <<< "$CHANGED"
96
+ [ "$ALL_TRIVIAL" = "true" ] && IS_TRIVIAL=true
97
+ fi
98
+ fi
99
+ if [ "$IS_TRIVIAL" = "true" ]; then
100
+ MODEL=claude-haiku-4-5-20251001
101
+ echo "::notice title=Clud Bug 🐛::Trivial PR detected (dep bump / bot author) — routing to Haiku for ~75% cost reduction."
49
102
  fi
103
+ echo "model=$MODEL" >> "$GITHUB_OUTPUT"
50
104
 
51
105
  clud-bug-review:
52
106
  needs: paths-check
@@ -164,8 +218,12 @@ jobs:
164
218
  # cache_creation_input_tokens in the run's result JSON so we can
165
219
  # measure caching effectiveness post-rollout (per v0.6.3 plan).
166
220
  show_full_output: true
221
+ # v0.6.15 / 0.0.R: --model is dynamic. paths-check classifies
222
+ # the PR as trivial (Haiku) or default (Sonnet). Override
223
+ # per-repo by editing the rendered workflow if you want a
224
+ # specific model for a specific repo.
167
225
  claude_args: |
168
- --model claude-sonnet-4-6
226
+ --model ${{ needs.paths-check.outputs.model }}
169
227
  --max-turns 15
170
228
  --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(git diff:*),Bash(git merge-base:*),Bash(cat .claude/skills/.clud-bug.json),Bash(cat .claude/skills/*/SKILL.md),Bash(head:*)"
171
229
  prompt: |
@@ -189,6 +247,6 @@ jobs:
189
247
  # Letting the action's own failure fail the check is louder and right.
190
248
  - name: Strict mode — fail check on critical findings
191
249
  if: success()
192
- uses: thrillmade/clud-bug/.github/actions/strict-mode-gate@v0.6.14
250
+ uses: thrillmade/clud-bug/.github/actions/strict-mode-gate@v0.6.16
193
251
  with:
194
252
  github-token: ${{ secrets.GITHUB_TOKEN }}