@olegkoval/agent-skills 1.26.0 → 1.28.0
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/.claude-plugin/plugin.json +2 -1
- package/README.md +7 -3
- package/catalog/skills.json +18 -0
- package/package.json +5 -3
- package/packages/software-development/lekker-review/SKILL.md +519 -0
- package/packages/software-development/lekker-review/adapters/claude/plugin.json +5 -0
- package/packages/software-development/lekker-review/adapters/claude/skills/lekker-review/SKILL.md +520 -0
- package/packages/software-development/lekker-review/adapters/claude/skills/lekker-review/references/agents/completeness-critic.md +21 -0
- package/packages/software-development/lekker-review/adapters/claude/skills/lekker-review/references/agents/conventions.md +124 -0
- package/packages/software-development/lekker-review/adapters/claude/skills/lekker-review/references/agents/fix-verifier.md +84 -0
- package/packages/software-development/lekker-review/adapters/claude/skills/lekker-review/references/agents/fixer.md +120 -0
- package/packages/software-development/lekker-review/adapters/claude/skills/lekker-review/references/agents/implementation.md +53 -0
- package/packages/software-development/lekker-review/adapters/claude/skills/lekker-review/references/agents/prover.md +135 -0
- package/packages/software-development/lekker-review/adapters/claude/skills/lekker-review/references/agents/quality.md +72 -0
- package/packages/software-development/lekker-review/adapters/claude/skills/lekker-review/references/agents/simplification.md +45 -0
- package/packages/software-development/lekker-review/adapters/claude/skills/lekker-review/references/agents/test-quality.md +170 -0
- package/packages/software-development/lekker-review/adapters/claude/skills/lekker-review/references/agents/triage-logic.md +27 -0
- package/packages/software-development/lekker-review/adapters/claude/skills/lekker-review/references/agents/triage-quality.md +41 -0
- package/packages/software-development/lekker-review/adapters/claude/skills/lekker-review/references/agents/verifier.md +295 -0
- package/packages/software-development/lekker-review/adapters/claude/skills/lekker-review/references/artifact-page.md +143 -0
- package/packages/software-development/lekker-review/adapters/claude/skills/lekker-review/references/context-gathering.md +162 -0
- package/packages/software-development/lekker-review/adapters/claude/skills/lekker-review/references/fix-mode.md +329 -0
- package/packages/software-development/lekker-review/adapters/claude/skills/lekker-review/references/github-post.md +205 -0
- package/packages/software-development/lekker-review/adapters/claude/skills/lekker-review/references/house-rules.md +76 -0
- package/packages/software-development/lekker-review/adapters/claude/skills/lekker-review/references/output-format.md +232 -0
- package/packages/software-development/lekker-review/adapters/claude/skills/lekker-review/scripts/changed-files.sh +77 -0
- package/packages/software-development/lekker-review/adapters/claude/skills/lekker-review/scripts/setup-worktree.sh +337 -0
- package/packages/software-development/lekker-review/adapters/claude/skills/lekker-review/scripts/verify-fixes.sh +231 -0
- package/packages/software-development/lekker-review/fix-workflow.js +273 -0
- package/packages/software-development/lekker-review/references/agents/completeness-critic.md +21 -0
- package/packages/software-development/lekker-review/references/agents/conventions.md +124 -0
- package/packages/software-development/lekker-review/references/agents/fix-verifier.md +84 -0
- package/packages/software-development/lekker-review/references/agents/fixer.md +120 -0
- package/packages/software-development/lekker-review/references/agents/implementation.md +53 -0
- package/packages/software-development/lekker-review/references/agents/prover.md +135 -0
- package/packages/software-development/lekker-review/references/agents/quality.md +72 -0
- package/packages/software-development/lekker-review/references/agents/simplification.md +45 -0
- package/packages/software-development/lekker-review/references/agents/test-quality.md +170 -0
- package/packages/software-development/lekker-review/references/agents/triage-logic.md +27 -0
- package/packages/software-development/lekker-review/references/agents/triage-quality.md +41 -0
- package/packages/software-development/lekker-review/references/agents/verifier.md +295 -0
- package/packages/software-development/lekker-review/references/artifact-page.md +143 -0
- package/packages/software-development/lekker-review/references/context-gathering.md +162 -0
- package/packages/software-development/lekker-review/references/fix-mode.md +329 -0
- package/packages/software-development/lekker-review/references/github-post.md +205 -0
- package/packages/software-development/lekker-review/references/house-rules.md +76 -0
- package/packages/software-development/lekker-review/references/output-format.md +232 -0
- package/packages/software-development/lekker-review/scripts/changed-files.sh +77 -0
- package/packages/software-development/lekker-review/scripts/setup-worktree.sh +337 -0
- package/packages/software-development/lekker-review/scripts/verify-fixes.sh +231 -0
- package/packages/software-development/lekker-review/workflow.js +602 -0
- package/site/assets/paperbag.css +707 -0
- package/site/assets/paperbag.js +218 -0
- package/site/build.mjs +380 -0
|
@@ -0,0 +1,329 @@
|
|
|
1
|
+
# fix-mode.md -- lekker-review `--fix` procedure
|
|
2
|
+
|
|
3
|
+
Run this AFTER the review has been printed and saved to `~/code-reviews/`, and
|
|
4
|
+
ONLY when `FIX_MODE=true` (either `--fix` was passed, or the user answered yes to
|
|
5
|
+
the post-review offer).
|
|
6
|
+
|
|
7
|
+
Fix mode turns verified findings into real commits on the PR branch. It edits
|
|
8
|
+
only the isolated review worktree, never the user's checkout, and it never
|
|
9
|
+
pushes without explicit confirmation.
|
|
10
|
+
|
|
11
|
+
**Never fix and push in the same breath as reporting.** Committing is local and
|
|
12
|
+
reversible; pushing writes to someone else's branch and is outward-facing.
|
|
13
|
+
|
|
14
|
+
---
|
|
15
|
+
|
|
16
|
+
## Step 1 -- Preconditions (all must hold, else stop and report)
|
|
17
|
+
|
|
18
|
+
| Precondition | Check | If it fails |
|
|
19
|
+
|--------------|-------|-------------|
|
|
20
|
+
| Worktree exists | `WORKTREE_PATH` non-null and the dir exists | Run `scripts/setup-worktree.sh` now, then continue. Fix mode cannot work from the diff alone. |
|
|
21
|
+
| Worktree is clean | `git -C <WORKTREE_PATH> status --porcelain` is empty | Stop. Report the dirty paths -- something already edited it. |
|
|
22
|
+
| Head still current | `git -C <repoRoot> fetch origin <PR_BRANCH>` then compare `git rev-parse origin/<PR_BRANCH>` to `headSha` | Head moved during the review. Stop, report both shas, tell the user to re-run: the review is stale and fixes could clobber new work. |
|
|
23
|
+
| PR is open | `gh pr view <PR_NUMBER> --repo <REPO_SLUG> --json state,mergedAt` | Stop if MERGED or CLOSED. |
|
|
24
|
+
| PR is not from a fork you cannot write to | `gh pr view --json headRepositoryOwner,maintainerCanModify` | If the head repo is a fork and `maintainerCanModify` is false, fixes can be committed locally but NOT pushed. Say so up front, before spending agents. |
|
|
25
|
+
|
|
26
|
+
The worktree checkout is a **detached HEAD** at `origin/<PR_BRANCH>` (see
|
|
27
|
+
`setup-worktree.sh`). That is intentional -- do not create or check out a
|
|
28
|
+
branch in it. Commits land on the detached HEAD and are pushed with an explicit
|
|
29
|
+
refspec in Step 6.
|
|
30
|
+
|
|
31
|
+
---
|
|
32
|
+
|
|
33
|
+
## Step 2 -- Select the findings to fix
|
|
34
|
+
|
|
35
|
+
Eligible finding = severity `critical` or `important`, has a non-empty `fix`
|
|
36
|
+
field, and its `file` exists in the worktree.
|
|
37
|
+
|
|
38
|
+
- Findings without a `fix` field are review-only. List them as "not
|
|
39
|
+
auto-fixable" in the report; never guess a fix.
|
|
40
|
+
- `observation` and `idiomatic` findings are NEVER auto-fixed. They are
|
|
41
|
+
judgment calls and non-blocking by definition.
|
|
42
|
+
- `PR-1` (title prefix) is not a code fix. Never edit the PR title as part of
|
|
43
|
+
fix mode -- it stays a `⛔ CANNOT MERGE` instruction for the author.
|
|
44
|
+
- Skip any finding whose `file` is generated (`*/generated/*`, lockfiles,
|
|
45
|
+
`*.snap`, build output). Report it as skipped-generated.
|
|
46
|
+
|
|
47
|
+
If the user chose "Critical only" at the offer prompt, filter to `critical`.
|
|
48
|
+
|
|
49
|
+
If nothing is eligible: say so in one line and skip to Step 8. Do not run the
|
|
50
|
+
workflow with an empty finding list.
|
|
51
|
+
|
|
52
|
+
Write the selected findings to `<scratchpad>/fix-findings.json` (receipt), then
|
|
53
|
+
state the plan before spending agents:
|
|
54
|
+
|
|
55
|
+
```
|
|
56
|
+
Fixing <N> finding(s) across <M> file(s): <file list>
|
|
57
|
+
Not auto-fixable: <N> (<reasons>)
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
---
|
|
61
|
+
|
|
62
|
+
## Step 3 -- Run the fix workflow
|
|
63
|
+
|
|
64
|
+
```
|
|
65
|
+
Workflow tool:
|
|
66
|
+
scriptPath: ${CLAUDE_PLUGIN_ROOT}/fix-workflow.js
|
|
67
|
+
args: {
|
|
68
|
+
repoSlug,
|
|
69
|
+
prNumber,
|
|
70
|
+
worktreePath: "<WORKTREE_PATH>",
|
|
71
|
+
diffFile: "<scratchpad>/pr.diff",
|
|
72
|
+
contextFile: "<scratchpad>/context.json",
|
|
73
|
+
promptDir: "${CLAUDE_PLUGIN_ROOT}/references/agents",
|
|
74
|
+
findings: [ <the selected finding objects, verbatim> ]
|
|
75
|
+
}
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
Pass `findings` as a real JSON array, not a stringified one. The workflow groups
|
|
79
|
+
by file (one agent per file, so no two agents ever edit the same file), applies
|
|
80
|
+
the fix, then runs a read-only fix-verifier over the actual `git diff`. A
|
|
81
|
+
verdict other than `good` buys exactly one retry, then stops.
|
|
82
|
+
|
|
83
|
+
Return value:
|
|
84
|
+
`{groups, droppedGroups, agentCount, retryCount, outputTokens, turnTokensTotal}`,
|
|
85
|
+
one `groups` entry per file with `results[]`, `filesTouched[]`, `verdict`,
|
|
86
|
+
`problems[]`, `committable`. `outputTokens` is the fix workflow's own spend
|
|
87
|
+
(already excluding the review workflow that ran before it); `turnTokensTotal` is
|
|
88
|
+
the whole turn's pool. Report the former on the `Fix agents:` cost line.
|
|
89
|
+
|
|
90
|
+
If the Workflow tool is unavailable: fall back to launching one Agent per file
|
|
91
|
+
group on `sonnet` with `references/agents/fixer.md`, then one Agent per group
|
|
92
|
+
with `references/agents/fix-verifier.md`. Same rules, same verdict handling.
|
|
93
|
+
State the fallback in the report.
|
|
94
|
+
|
|
95
|
+
---
|
|
96
|
+
|
|
97
|
+
## Step 4 -- Revert what did not earn a commit
|
|
98
|
+
|
|
99
|
+
For every group with `committable: false` that touched files:
|
|
100
|
+
|
|
101
|
+
```bash
|
|
102
|
+
git -C <WORKTREE_PATH> checkout -- <each path in filesTouched>
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
Then confirm the revert landed:
|
|
106
|
+
|
|
107
|
+
```bash
|
|
108
|
+
git -C <WORKTREE_PATH> status --porcelain
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
Only committable groups' files may remain modified. Any leftover untracked file
|
|
112
|
+
from a reverted group gets removed explicitly (`rm -f <path>`), never with
|
|
113
|
+
`git clean -fd` (too blunt for a shared worktree).
|
|
114
|
+
|
|
115
|
+
`harmful` verdicts are a normal outcome, not a failure of the run: the finding
|
|
116
|
+
simply stays a review comment for the author. Report it as such.
|
|
117
|
+
|
|
118
|
+
---
|
|
119
|
+
|
|
120
|
+
## Step 5 -- Verify the fixed tree (fresh post-condition)
|
|
121
|
+
|
|
122
|
+
```bash
|
|
123
|
+
~/.claude/skills/lekker-review/scripts/verify-fixes.sh \
|
|
124
|
+
<WORKTREE_PATH> <scratchpad>/fix-verify.json tests
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
Pass `tests` only when the diff touched logic and the repo has a `test` script;
|
|
128
|
+
pass `no-tests` for doc/config-only fixes or when the suite needs live infra.
|
|
129
|
+
|
|
130
|
+
Read the JSON and compare against the pre-fix baseline in `worktree.json`:
|
|
131
|
+
|
|
132
|
+
- `tscChangedTail` / `tscErrorCount` -- compare against the same two baseline
|
|
133
|
+
keys. `tscChangedTail` is the attributable set (errors in files this branch
|
|
134
|
+
touched, which now includes the files the fix agents wrote); an entry there
|
|
135
|
+
that is not in the baseline was introduced by the fixes. A rise in
|
|
136
|
+
`tscErrorCount` with no new `tscChangedTail` entry means the fix broke a file
|
|
137
|
+
it does not own - treat that as introduced too. Revert the offending group's
|
|
138
|
+
files (Step 4) and mark those findings `failed`. Never commit a tree with
|
|
139
|
+
newly-introduced type errors.
|
|
140
|
+
- `eslintTail` -- same comparison. Both runs lint only changed files, so the
|
|
141
|
+
comparison is like-for-like; check `eslintScope` matches the baseline's
|
|
142
|
+
(`changed-files` vs `full-fallback`) before trusting a diff between the two.
|
|
143
|
+
- `testTail` / `testExitCode` -- a newly failing test caused by a fix means
|
|
144
|
+
revert that group. A test that already failed on the baseline head is not
|
|
145
|
+
yours; say so explicitly rather than silently ignoring it.
|
|
146
|
+
- `dirtyPaths` -- must contain only files declared by committable groups. An
|
|
147
|
+
undeclared path is a red flag: revert it and report.
|
|
148
|
+
|
|
149
|
+
If a check was skipped (no `node_modules`, no config), say `skipped` in the
|
|
150
|
+
report. Skipped is a state, not a pass.
|
|
151
|
+
|
|
152
|
+
---
|
|
153
|
+
|
|
154
|
+
## Step 5b -- Proof flip (red → green)
|
|
155
|
+
|
|
156
|
+
For every group that is still `committable` after Step 5, collect the
|
|
157
|
+
findings in that group that carry `proof.proven === true` (the
|
|
158
|
+
`<scratchpad>/fix-findings.json` sidecar written in Step 2 has the `proof`
|
|
159
|
+
objects, including `testCode` and `testCommand`, alongside each finding). If a
|
|
160
|
+
committable group has no proven findings, skip it -- there is nothing to flip.
|
|
161
|
+
|
|
162
|
+
For each proven finding in a committable group:
|
|
163
|
+
|
|
164
|
+
1. **Re-materialize the test**: write `proof.testCode` back to its original
|
|
165
|
+
filename (the same `lekker-proof-<file-slug>-<line>.test.ts` name it was captured
|
|
166
|
+
under) at the worktree root.
|
|
167
|
+
2. **Run** exactly `proof.testCommand` (Bash `timeout` 120000).
|
|
168
|
+
3. **Judge**:
|
|
169
|
+
- **PASSES now** -> the fix demonstrably resolves the finding. Record
|
|
170
|
+
`proofFlip: green` for that finding in the Step 8 status table.
|
|
171
|
+
- **STILL FAILS with the same assertion** -> the fix did not fix the bug.
|
|
172
|
+
The group is NOT committable regardless of the fix-verifier's `good`
|
|
173
|
+
verdict -- revert it (Step 4 procedure) and mark its findings `failed`
|
|
174
|
+
with reason `proof still red after fix`. An executed test outranks a
|
|
175
|
+
reviewer agent's opinion.
|
|
176
|
+
- **Fails for a NEW, unrelated reason** (import broke, different error) ->
|
|
177
|
+
the fix likely broke something else; same outcome: revert the group,
|
|
178
|
+
mark its findings `failed`, and quote the new error in the reason.
|
|
179
|
+
4. **Delete the test file** and verify with `git -C <WORKTREE_PATH> status
|
|
180
|
+
--porcelain` that only the fix edits remain -- no stray proof file, no
|
|
181
|
+
other drift.
|
|
182
|
+
|
|
183
|
+
A group reverted at this step no longer participates in Step 6 (Commit) --
|
|
184
|
+
treat it exactly like a Step 4 revert. Re-run the `git status --porcelain`
|
|
185
|
+
check after any revert triggered here before moving on.
|
|
186
|
+
|
|
187
|
+
---
|
|
188
|
+
|
|
189
|
+
## Step 6 -- Commit (local only)
|
|
190
|
+
|
|
191
|
+
One commit per file group, in group order. Stage explicitly -- never `git add -A`,
|
|
192
|
+
never `git add .`:
|
|
193
|
+
|
|
194
|
+
```bash
|
|
195
|
+
git -C <WORKTREE_PATH> add -- <filesTouched for this group>
|
|
196
|
+
git -C <WORKTREE_PATH> commit -m "<subject>" -m "<body>"
|
|
197
|
+
```
|
|
198
|
+
|
|
199
|
+
Subject: `<TICKET_PREFIX> review fix: <short label>` where `TICKET_PREFIX` is the
|
|
200
|
+
`[TICKET-NNN]` from the PR title when there is one, omitted otherwise. Keep the
|
|
201
|
+
subject under 72 chars.
|
|
202
|
+
|
|
203
|
+
Body: one `- ` line per applied finding, using the fixer's `summary`, then:
|
|
204
|
+
|
|
205
|
+
```
|
|
206
|
+
Applied from lekker-review: <REVIEW_FILE>
|
|
207
|
+
|
|
208
|
+
Co-Authored-By: Claude Code <noreply@anthropic.com>
|
|
209
|
+
```
|
|
210
|
+
|
|
211
|
+
If two groups declared the same file, commit them together as one commit and
|
|
212
|
+
say so in the report.
|
|
213
|
+
|
|
214
|
+
Receipt after committing:
|
|
215
|
+
|
|
216
|
+
```bash
|
|
217
|
+
git -C <WORKTREE_PATH> log --oneline <headSha>..HEAD
|
|
218
|
+
git -C <WORKTREE_PATH> status --porcelain # must be empty
|
|
219
|
+
```
|
|
220
|
+
|
|
221
|
+
---
|
|
222
|
+
|
|
223
|
+
## Step 7 -- Push (requires explicit confirmation)
|
|
224
|
+
|
|
225
|
+
Show the user, before asking:
|
|
226
|
+
|
|
227
|
+
- the commit list (`git log --oneline <headSha>..HEAD`)
|
|
228
|
+
- the full diffstat (`git diff --stat <headSha>..HEAD`)
|
|
229
|
+
- the per-finding table from Step 8
|
|
230
|
+
|
|
231
|
+
Then ask, in a single question: push these `<N>` commit(s) to
|
|
232
|
+
`<PR_BRANCH>` on `<REPO_SLUG>`, or leave them local?
|
|
233
|
+
|
|
234
|
+
**Unattended runs (cron, `/loop`, background agent): never push, never ask.**
|
|
235
|
+
Stop after Step 6, keep the worktree, and report the worktree path plus the
|
|
236
|
+
exact push command so a human can release it. This matches the standing
|
|
237
|
+
unattended-run rule: stage the artifact, a human releases it.
|
|
238
|
+
|
|
239
|
+
On confirmed push:
|
|
240
|
+
|
|
241
|
+
```bash
|
|
242
|
+
git -C <repoRoot> fetch origin <PR_BRANCH>
|
|
243
|
+
# guard: origin must still be at the sha we based the fixes on
|
|
244
|
+
git -C <repoRoot> rev-parse origin/<PR_BRANCH> # must equal <headSha>
|
|
245
|
+
git -C <WORKTREE_PATH> push origin HEAD:refs/heads/<PR_BRANCH>
|
|
246
|
+
```
|
|
247
|
+
|
|
248
|
+
- If the guard sha differs, ABORT the push. Report that the branch moved and
|
|
249
|
+
leave the commits local. Never `--force`, never `--force-with-lease`, never
|
|
250
|
+
rebase someone else's branch.
|
|
251
|
+
- Never push to `main`, `master`, `staging`, or `develop`, whatever the branch
|
|
252
|
+
variables say. Stop if `PR_BRANCH` is one of those.
|
|
253
|
+
|
|
254
|
+
Post-condition (fresh source, not the push output):
|
|
255
|
+
|
|
256
|
+
```bash
|
|
257
|
+
gh pr view <PR_NUMBER> --repo <REPO_SLUG> --json headRefOid,mergeStateStatus
|
|
258
|
+
```
|
|
259
|
+
|
|
260
|
+
Confirm `headRefOid` equals the local HEAD sha. Print
|
|
261
|
+
`✓ Pushed <N> commit(s) -> <PR_URL> (head now <new short sha>)`. If it does not
|
|
262
|
+
match, say the push is unconfirmed and stop -- do not retry.
|
|
263
|
+
|
|
264
|
+
Do NOT also post the fixed findings as inline review comments. When `--post` and
|
|
265
|
+
`--fix` both ran, post only the findings that were NOT applied; a comment asking
|
|
266
|
+
for a change you already committed is noise.
|
|
267
|
+
|
|
268
|
+
---
|
|
269
|
+
|
|
270
|
+
## Step 8 -- Report and record
|
|
271
|
+
|
|
272
|
+
Print a table:
|
|
273
|
+
|
|
274
|
+
| # | Finding | File | Status | proofFlip | Note |
|
|
275
|
+
|---|---------|------|--------|-----------|------|
|
|
276
|
+
| 1 | <title> | `<file>:<line>` | ✅ applied | green | <fixer summary> |
|
|
277
|
+
| 2 | <title> | `<file>:<line>` | ↩️ reverted | still-red | <verifier problem, or "proof still red after fix"> |
|
|
278
|
+
| 3 | <title> | `<file>:<line>` | ⏭️ skipped | n/a | <reason, e.g. needs cross-file change> |
|
|
279
|
+
| 4 | <title> | `<file>:<line>` | ❌ failed | n/a | <what blocked it> |
|
|
280
|
+
|
|
281
|
+
`proofFlip` is `green` (proof re-ran and passed), `still-red` (proof re-ran and
|
|
282
|
+
still failed, so the group was reverted per Step 5b), or `n/a` (the finding
|
|
283
|
+
carried no `proof.proven === true`, so Step 5b never ran for it).
|
|
284
|
+
|
|
285
|
+
Then append this section to `REVIEW_FILE` (the saved review), so the record and
|
|
286
|
+
the review never drift apart:
|
|
287
|
+
|
|
288
|
+
```markdown
|
|
289
|
+
---
|
|
290
|
+
|
|
291
|
+
## 🔧 Fixes applied
|
|
292
|
+
|
|
293
|
+
**Base:** `<headShaShort>` · **Commits:** <N> · **Pushed:** <yes, head now `<sha>` | no, local only at <WORKTREE_PATH>>
|
|
294
|
+
**Checks:** tsc <clean | N new errors | skipped> · eslint <...> · tests <passed | failed | skipped>
|
|
295
|
+
**Fix agents:** <N> (<retryCount> retried)
|
|
296
|
+
**Proof flips:** <M green / K still-red / rest n/a> *(include only when at least one finding carried `proof.proven === true`)*
|
|
297
|
+
|
|
298
|
+
| # | Finding | File | Status | proofFlip | Note |
|
|
299
|
+
...same table...
|
|
300
|
+
```
|
|
301
|
+
|
|
302
|
+
Re-read the file after writing and emit `✓ Fixes recorded -> <REVIEW_FILE>`.
|
|
303
|
+
|
|
304
|
+
Add one line to the `## 💰 Review Cost` block for fix-mode spend:
|
|
305
|
+
|
|
306
|
+
```
|
|
307
|
+
Fix agents: <N> (sonnet) — <outputTokens> output tokens, ~$<X.XX>
|
|
308
|
+
```
|
|
309
|
+
|
|
310
|
+
---
|
|
311
|
+
|
|
312
|
+
## Step 9 -- Cleanup override
|
|
313
|
+
|
|
314
|
+
The normal cleanup step removes the worktree. In fix mode:
|
|
315
|
+
|
|
316
|
+
- **Pushed successfully** -> clean up as usual.
|
|
317
|
+
- **Commits exist but were not pushed** -> KEEP the worktree and the repo clone.
|
|
318
|
+
Print the path and the push command. Deleting it would destroy the only copy
|
|
319
|
+
of the work.
|
|
320
|
+
- **Nothing was committed** -> clean up as usual.
|
|
321
|
+
|
|
322
|
+
---
|
|
323
|
+
|
|
324
|
+
## Failure rules
|
|
325
|
+
|
|
326
|
+
- Two identical failures = stop and diagnose. No loops.
|
|
327
|
+
- Never claim a fix landed without the `git log` / `git status` receipt.
|
|
328
|
+
- Never present the review's proposed `fix` text as though it were applied. Only
|
|
329
|
+
a committed diff counts.
|
|
@@ -0,0 +1,205 @@
|
|
|
1
|
+
# github-post.md -- lekker-review --post flag procedure
|
|
2
|
+
|
|
3
|
+
Execute this procedure AFTER the review file has been saved to `~/code-reviews/`
|
|
4
|
+
and ONLY when the user passed `--post`.
|
|
5
|
+
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
## Step 1 -- Build the payload
|
|
9
|
+
|
|
10
|
+
Construct a JSON payload at `/tmp/lekker-post-$$.json` with the structure:
|
|
11
|
+
|
|
12
|
+
```json
|
|
13
|
+
{
|
|
14
|
+
"body": "<summary section>",
|
|
15
|
+
"comments": [
|
|
16
|
+
{
|
|
17
|
+
"path": "<relative file path>",
|
|
18
|
+
"line": <line number>,
|
|
19
|
+
"side": "RIGHT",
|
|
20
|
+
"body": "<finding title + why + fix in GitHub markdown>"
|
|
21
|
+
}
|
|
22
|
+
]
|
|
23
|
+
}
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
Rules:
|
|
27
|
+
|
|
28
|
+
- **Do NOT include an `event` field.** Omitting it creates a PENDING review,
|
|
29
|
+
visible only to the requesting user until they submit it. NEVER submit the
|
|
30
|
+
review programmatically.
|
|
31
|
+
- Include one comment entry for every Critical and Important finding whose
|
|
32
|
+
`file:line` falls within the diff hunks of this PR (see Step 2 for how to
|
|
33
|
+
determine commentability).
|
|
34
|
+
- **Keep every comment body to 2-4 sentences and under ~700 characters**
|
|
35
|
+
(excluding any suggestion block). Inline comments are read one at a time in a
|
|
36
|
+
narrow column; a long one does not get read, so length actively costs you the
|
|
37
|
+
fix. The detail belongs only in the saved review file (`~/code-reviews/*.md`).
|
|
38
|
+
Do NOT reproduce the file's full Critical/Important write-up inline.
|
|
39
|
+
|
|
40
|
+
- **Open with the ask, in the imperative.** The first clause must be the action
|
|
41
|
+
the author takes ("Return early here", "Extract one shared winner-picker",
|
|
42
|
+
"Raise to 250", "Add a double with `session`"). Evidence comes after, and only
|
|
43
|
+
the evidence that makes the ask credible. Never open with a bolded severity
|
|
44
|
+
label, a restated finding title, or a preamble — the author already knows they
|
|
45
|
+
are reading a review comment.
|
|
46
|
+
|
|
47
|
+
```
|
|
48
|
+
✗ **Important — two implementations of "largest fulfillment order" with
|
|
49
|
+
different tie-break keys.** This ranks by value → units → id; `x.ts:104`
|
|
50
|
+
ranks by shipped qty → id. Diverging input: one shared line referenced by
|
|
51
|
+
FO-A (qty 1, one $100 item) and FO-B (qty 3, three $10 items) — fallback
|
|
52
|
+
picks FO-A, exact picks FO-B. Because `existingCreatedLines` idempotency is
|
|
53
|
+
keyed per `fulfillmentOrderGid` with no cross-FO check, a transient
|
|
54
|
+
exact-API failure on FO-A (fallback wins, line written) followed by a
|
|
55
|
+
successful retry on FO-B (exact wins, line written) posts the shared charge
|
|
56
|
+
twice. Please extract one `pickSharedChargeWinner(candidates, size, id)`…
|
|
57
|
+
|
|
58
|
+
✓ Please extract one shared winner-picker used by both files, keyed on FO
|
|
59
|
+
value. This ranks value → units → id; `x.ts:104` ranks shipped-qty → id, so
|
|
60
|
+
FO-A (qty 1, one $100 item) vs FO-B (qty 3, three $10 items) gives A here
|
|
61
|
+
and B there. Idempotency is keyed per `fulfillmentOrderGid` with no cross-FO
|
|
62
|
+
check, so a fallback run that writes A's line followed by an exact-path
|
|
63
|
+
retry on B writes the same charge twice.
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
- **Cut every clause that does not change what the author does.** In particular:
|
|
67
|
+
no severity prefix (the review body already states the counts), no
|
|
68
|
+
"Why it's wrong:" / "Fix:" headers (that is the saved-file format, not the
|
|
69
|
+
inline format), no verifier reasoning, no restating what the PR does, no
|
|
70
|
+
second worked example once the first lands, and no sentence whose content is
|
|
71
|
+
already visible on the commented line.
|
|
72
|
+
- **Use a GitHub suggestion block for the fix whenever it's a direct code change**
|
|
73
|
+
anchored to the commented line(s) — a reviewer can apply it with one click:
|
|
74
|
+
```suggestion
|
|
75
|
+
<replacement line(s), exact drop-in for the line(s) the comment is anchored to>
|
|
76
|
+
```
|
|
77
|
+
Only use a suggestion block when it exactly replaces the commented line(s) —
|
|
78
|
+
never for fixes spanning multiple files or requiring a new function/extraction
|
|
79
|
+
elsewhere. For those, describe the fix in one sentence instead and point to
|
|
80
|
+
the saved review for detail; do not paste a plain fenced code block as a
|
|
81
|
+
substitute for a real suggestion.
|
|
82
|
+
- **Every inline comment must be ACTIONABLE** — it must ask for a concrete change
|
|
83
|
+
(fix X, add a test for Y, regenerate Z). Do NOT post informational-only or
|
|
84
|
+
FYI comments ("behaviour change, intentional", "note that…", "just flagging").
|
|
85
|
+
If there's nothing to do, there's no comment — put context like that in the
|
|
86
|
+
review body or the saved review file, never as an inline PR comment.
|
|
87
|
+
- The review-level `body` field must contain, in this order: the finding counts
|
|
88
|
+
("0 Critical / 5 Important / 6 Observations / 1 Idiomatic"), one or two
|
|
89
|
+
sentences of risk framing, then **a numbered list of the asks — one line each,
|
|
90
|
+
imperative, matching the inline comments in order**. That list is what the
|
|
91
|
+
author reads first and works from; it must be scannable in ten seconds. Then
|
|
92
|
+
any Production Signals, then a short flat list of Observations marked "no
|
|
93
|
+
action required", then the saved review file path.
|
|
94
|
+
|
|
95
|
+
Keep the body itself under ~2,500 characters. If it is longer, the asks are
|
|
96
|
+
buried — cut prose, never cut the numbered asks.
|
|
97
|
+
- Do NOT prefix the body with a banner like "## Lekker review". Do NOT praise the
|
|
98
|
+
PR or describe what it does well — no "solid", "handled well", "clean", "nice".
|
|
99
|
+
State the risk and the asks only.
|
|
100
|
+
- We use **Linear**, not Jira. Never write "Jira" in any comment or body; refer
|
|
101
|
+
to Linear ticket IDs (e.g. DUBO-201) directly.
|
|
102
|
+
|
|
103
|
+
---
|
|
104
|
+
|
|
105
|
+
## Step 2 -- Determine commentability
|
|
106
|
+
|
|
107
|
+
A line is commentable only if it appears in the diff hunks for the file. To
|
|
108
|
+
check, scan `DIFF_FILE` for the relevant hunk headers and added lines:
|
|
109
|
+
|
|
110
|
+
```bash
|
|
111
|
+
grep -n "^@@\|^+" "$DIFF_FILE" | grep -A20 "^.*+.*<relative-file-path>" | head -60
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
If the finding's `line` number does not correspond to a `+` line in the diff
|
|
115
|
+
for that file, the finding is NOT commentable -- fold it into the review body
|
|
116
|
+
under an "Additional findings" section instead.
|
|
117
|
+
|
|
118
|
+
Observation and Idiomatic findings go into the body only; never as inline
|
|
119
|
+
comments.
|
|
120
|
+
|
|
121
|
+
---
|
|
122
|
+
|
|
123
|
+
## Step 3 -- POST the review
|
|
124
|
+
|
|
125
|
+
```bash
|
|
126
|
+
gh api "repos/<REPO_SLUG>/pulls/<PR_NUMBER>/reviews" \
|
|
127
|
+
--method POST \
|
|
128
|
+
--input /tmp/lekker-post-$$.json
|
|
129
|
+
```
|
|
130
|
+
|
|
131
|
+
---
|
|
132
|
+
|
|
133
|
+
## Step 4 -- Handle 422 errors
|
|
134
|
+
|
|
135
|
+
If the API returns HTTP 422 (line not in diff):
|
|
136
|
+
|
|
137
|
+
1. Remove the offending comment object from the payload (identify it from the
|
|
138
|
+
error response body, which names the path and line).
|
|
139
|
+
2. Add its content to the review-level `body` under "Additional findings".
|
|
140
|
+
3. Retry the POST once with the updated payload.
|
|
141
|
+
|
|
142
|
+
If the same failure shape occurs a second time: stop, report the error message
|
|
143
|
+
to the user, and fall back to "paste manually" -- do not loop further.
|
|
144
|
+
|
|
145
|
+
---
|
|
146
|
+
|
|
147
|
+
## Step 5 -- Verify (fresh post-condition)
|
|
148
|
+
|
|
149
|
+
After a successful POST, immediately fetch the current review list:
|
|
150
|
+
|
|
151
|
+
```bash
|
|
152
|
+
gh api "repos/<REPO_SLUG>/pulls/<PR_NUMBER>/reviews"
|
|
153
|
+
```
|
|
154
|
+
|
|
155
|
+
Confirm:
|
|
156
|
+
- A review with `state: "PENDING"` by the current authenticated user exists.
|
|
157
|
+
- The `body` field contains the expected summary text.
|
|
158
|
+
- The comment count matches what was submitted.
|
|
159
|
+
|
|
160
|
+
Print the following to the terminal:
|
|
161
|
+
|
|
162
|
+
```
|
|
163
|
+
Posted PENDING review on <PR_URL>
|
|
164
|
+
- <N> inline comments
|
|
165
|
+
- Review ID: <id>
|
|
166
|
+
|
|
167
|
+
ACTION REQUIRED: Open GitHub in your browser to review and submit the
|
|
168
|
+
pending review. Pending reviews are only visible to you until submitted.
|
|
169
|
+
```
|
|
170
|
+
|
|
171
|
+
Clean up the temporary payload file:
|
|
172
|
+
|
|
173
|
+
```bash
|
|
174
|
+
rm -f /tmp/lekker-post-$$.json
|
|
175
|
+
```
|
|
176
|
+
|
|
177
|
+
---
|
|
178
|
+
|
|
179
|
+
## Step 6 -- Revising an already-posted PENDING review
|
|
180
|
+
|
|
181
|
+
If the user asks to shorten, reword, or re-scope the comments after posting:
|
|
182
|
+
|
|
183
|
+
- The review-level `body` alone can be edited in place:
|
|
184
|
+
`gh api repos/<REPO_SLUG>/pulls/<PR_NUMBER>/reviews/<REVIEW_ID> --method PUT --input <json with {"body": ...}>`
|
|
185
|
+
Inline comments survive this untouched.
|
|
186
|
+
- **Inline comment bodies cannot be reliably edited on a pending review** --
|
|
187
|
+
`PATCH /pulls/comments/{id}` targets submitted comments. To change them,
|
|
188
|
+
DELETE the pending review and POST a fresh one:
|
|
189
|
+
`gh api repos/<REPO_SLUG>/pulls/<PR_NUMBER>/reviews/<REVIEW_ID> --method DELETE`
|
|
190
|
+
This is safe only because a pending review is visible to nobody else. Capture
|
|
191
|
+
the existing bodies first (`--jq '.body'` and `/reviews/<id>/comments`) so
|
|
192
|
+
nothing is lost if the re-POST fails.
|
|
193
|
+
- Verify by re-fetching the pending review and its comment count. Note that
|
|
194
|
+
`line`, `original_line`, and `side` come back `null` for comments on a pending
|
|
195
|
+
review -- that is expected, not a lost anchor. A successful POST (no 422) is
|
|
196
|
+
the receipt that the anchors were accepted.
|
|
197
|
+
|
|
198
|
+
---
|
|
199
|
+
|
|
200
|
+
## Notes
|
|
201
|
+
|
|
202
|
+
- Never add an `event` field to the payload (not even `"COMMENT"`) -- that
|
|
203
|
+
would publish the review immediately to all participants.
|
|
204
|
+
- The current authenticated user is whoever `gh auth status` reports.
|
|
205
|
+
- If `gh api` is not authenticated, stop and tell the user to run `gh auth login`.
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
# House rules (customize for your org)
|
|
2
|
+
|
|
3
|
+
This file is a template. lekker-review reads it as `PROJECT_RULES` and feeds
|
|
4
|
+
it to every review agent. Replace the example rules below with your own
|
|
5
|
+
team's non-negotiable conventions — the kind of thing that should always be a
|
|
6
|
+
**Critical** finding regardless of review depth, not a matter of taste.
|
|
7
|
+
|
|
8
|
+
A hard rule in this file should be:
|
|
9
|
+
- **Unambiguous** — a reviewer agent can check it mechanically against a diff.
|
|
10
|
+
- **Non-negotiable** — violating it is always wrong, not "usually" wrong.
|
|
11
|
+
- **Cheap to verify** — the review agent shouldn't need deep domain judgment.
|
|
12
|
+
|
|
13
|
+
If you have no hard rules yet, leave this file mostly empty (just the Stack
|
|
14
|
+
context section below) and let the 5 specialist agents rely on their own
|
|
15
|
+
judgment plus the repo's own CLAUDE.md / linter config.
|
|
16
|
+
|
|
17
|
+
---
|
|
18
|
+
|
|
19
|
+
## Example hard rules (replace with your own)
|
|
20
|
+
|
|
21
|
+
### EXAMPLE-1 — Type safety (TypeScript projects)
|
|
22
|
+
- No type casts (`as X`, `<X>expr`) outside test files.
|
|
23
|
+
- No `any` outside test files; even in tests, a blatantly untyped `any[]` on a
|
|
24
|
+
known-shaped list should still be flagged.
|
|
25
|
+
|
|
26
|
+
### EXAMPLE-2 — No generated files hand-edited
|
|
27
|
+
- Files under a `generated/` directory (codegen output, ORM types, GraphQL
|
|
28
|
+
types) must never be hand-edited in a diff — they should be regenerated
|
|
29
|
+
from source and the regen step re-run.
|
|
30
|
+
|
|
31
|
+
### EXAMPLE-3 — Pagination must be complete
|
|
32
|
+
- Any paginated API call (GraphQL `nodes` connections, REST cursor pagination)
|
|
33
|
+
must fetch every page, not just the first, unless a comment explains why a
|
|
34
|
+
partial fetch is intentional.
|
|
35
|
+
|
|
36
|
+
### EXAMPLE-4 — PR title must reference its ticket
|
|
37
|
+
- PR title must start with the ticket ID in brackets (e.g. `[PROJ-123]`),
|
|
38
|
+
covering every ticket referenced in the PR's commit history.
|
|
39
|
+
- Treat a missing/incomplete prefix as **blocking**: surface a prominent
|
|
40
|
+
`⛔ CANNOT MERGE` warning and the recommended title. This is a process rule,
|
|
41
|
+
not a code-quality signal, so it should not affect a confidence score.
|
|
42
|
+
|
|
43
|
+
---
|
|
44
|
+
|
|
45
|
+
## Repo placement check (multi-repo projects only)
|
|
46
|
+
|
|
47
|
+
If your org splits related concerns across sibling repos (e.g. a "backend
|
|
48
|
+
sync" repo and a separate "storefront/app" repo), add your own repo taxonomy
|
|
49
|
+
table here so the review agent can flag code landing in the wrong repo:
|
|
50
|
+
|
|
51
|
+
```
|
|
52
|
+
| Repo pattern | Purpose |
|
|
53
|
+
|--------------------|-----------------------------------------|
|
|
54
|
+
| `<pattern-a>` | <what belongs here> |
|
|
55
|
+
| `<pattern-b>` | <what belongs here> |
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
Note any exceptions (a repo that looks like pattern A but is actually a full
|
|
59
|
+
app, a legacy folder that shouldn't be used for new code, etc.) — placement
|
|
60
|
+
checks are only useful when they account for the real exceptions in your repo
|
|
61
|
+
layout, not the naming convention alone.
|
|
62
|
+
|
|
63
|
+
---
|
|
64
|
+
|
|
65
|
+
## Stack context (fill in for your project)
|
|
66
|
+
|
|
67
|
+
Give the review agents a one-paragraph map of your stack so they don't have
|
|
68
|
+
to rediscover it from the diff every time:
|
|
69
|
+
|
|
70
|
+
- **Backend:** <languages, frameworks, ORM, database>
|
|
71
|
+
- **Frontend:** <framework, UI library, build tool>
|
|
72
|
+
- **External APIs:** <third-party integrations worth knowing about, especially
|
|
73
|
+
ones with quirks: rate limits, OAuth flows, unusual pagination>
|
|
74
|
+
- **Infra:** <how the app runs locally and in CI>
|
|
75
|
+
- **Type/codegen pipeline:** <any source → generated-type steps that need to
|
|
76
|
+
stay in sync — flag stale generated output as a finding>
|