@olegkoval/agent-skills 1.52.0 → 1.54.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/.github/copilot-instructions.md +1 -0
- package/.github/prompts/codexloop.prompt.md +31 -7
- package/.github/prompts/nas-actions-migration.prompt.md +74 -0
- package/.github/prompts/pr-description-writer.prompt.md +25 -2
- package/.kiro/steering/codexloop.md +31 -7
- package/.windsurf/rules/codexloop.md +31 -7
- package/README.md +1 -0
- package/adapters/claude/olko-github-pr/skills/codexloop/SKILL.md +31 -7
- package/adapters/claude/olko-github-pr/skills/lekker-review/SKILL.md +97 -29
- package/adapters/claude/olko-github-pr/skills/lekker-review/references/agents/deps.md +54 -0
- package/adapters/claude/olko-github-pr/skills/lekker-review/references/artifact-page.md +39 -14
- package/adapters/claude/olko-github-pr/skills/lekker-review/references/codex-workflow.md +1 -0
- package/adapters/claude/olko-github-pr/skills/lekker-review/references/github-post.md +3 -1
- package/adapters/claude/olko-github-pr/skills/lekker-review/references/output-format.md +11 -10
- package/adapters/claude/olko-github-pr/skills/lekker-review/references/pricing.json +12 -11
- package/adapters/claude/olko-github-pr/skills/lekker-review/scripts/deps-only.mjs +95 -0
- package/adapters/claude/olko-github-pr/skills/lekker-review/scripts/selftest.mjs +70 -6
- package/adapters/claude/olko-github-pr/skills/lekker-review/scripts/setup-worktree.sh +136 -16
- package/adapters/claude/olko-github-pr/skills/lekker-review/scripts/validate-lines.mjs +122 -0
- package/adapters/claude/olko-github-pr/skills/nas-actions-migration/SKILL.md +85 -0
- package/adapters/claude/olko-github-pr/skills/pr-description-writer/SKILL.md +26 -3
- package/adapters/codex/olko-github-pr/README.md +1 -0
- package/adapters/cursor/olko-github-pr/skills/codexloop/SKILL.md +31 -7
- package/adapters/cursor/olko-github-pr/skills/nas-actions-migration/SKILL.md +85 -0
- package/adapters/cursor/olko-github-pr/skills/pr-description-writer/SKILL.md +26 -3
- package/adapters/grok/olko-github-pr/skills/codexloop/SKILL.md +31 -7
- package/adapters/grok/olko-github-pr/skills/nas-actions-migration/SKILL.md +85 -0
- package/adapters/grok/olko-github-pr/skills/pr-description-writer/SKILL.md +26 -3
- package/catalog/skills.json +21 -0
- package/package.json +1 -1
- package/plugins/olko-apple-kit/.claude-plugin/plugin.json +1 -1
- package/plugins/olko-creative/.claude-plugin/plugin.json +1 -1
- package/plugins/olko-garmin-kit/.claude-plugin/plugin.json +1 -1
- package/plugins/olko-git-tools/.claude-plugin/plugin.json +1 -1
- package/plugins/olko-github-pr/.claude-plugin/plugin.json +1 -1
- package/plugins/olko-github-pr/skills/codexloop/SKILL.md +31 -7
- package/plugins/olko-github-pr/skills/lekker-review/SKILL.md +97 -29
- package/plugins/olko-github-pr/skills/lekker-review/references/agents/deps.md +54 -0
- package/plugins/olko-github-pr/skills/lekker-review/references/artifact-page.md +39 -14
- package/plugins/olko-github-pr/skills/lekker-review/references/codex-workflow.md +1 -0
- package/plugins/olko-github-pr/skills/lekker-review/references/github-post.md +3 -1
- package/plugins/olko-github-pr/skills/lekker-review/references/output-format.md +11 -10
- package/plugins/olko-github-pr/skills/lekker-review/references/pricing.json +12 -11
- package/plugins/olko-github-pr/skills/lekker-review/scripts/deps-only.mjs +95 -0
- package/plugins/olko-github-pr/skills/lekker-review/scripts/selftest.mjs +70 -6
- package/plugins/olko-github-pr/skills/lekker-review/scripts/setup-worktree.sh +136 -16
- package/plugins/olko-github-pr/skills/lekker-review/scripts/validate-lines.mjs +122 -0
- package/plugins/olko-github-pr/skills/lekker-review/workflow.js +43 -23
- package/plugins/olko-github-pr/skills/nas-actions-migration/SKILL.md +84 -0
- package/plugins/olko-github-pr/skills/pr-description-writer/SKILL.md +26 -3
- package/plugins/olko-obsidian/.claude-plugin/plugin.json +1 -1
- package/plugins/olko-product/.claude-plugin/plugin.json +1 -1
- package/plugins/olko-reflection/.claude-plugin/plugin.json +1 -1
- package/plugins/olko-release/.claude-plugin/plugin.json +1 -1
- package/plugins/olko-skill-meta/.claude-plugin/plugin.json +1 -1
- package/plugins/olko-web-ops/.claude-plugin/plugin.json +1 -1
- package/scripts/lib/catalog.mjs +1 -1
|
@@ -45,7 +45,7 @@ metadata:
|
|
|
45
45
|
- multi-agent
|
|
46
46
|
- workflow
|
|
47
47
|
- quality
|
|
48
|
-
argument-hint: "<github-pr-url | repo pr-number | repo pr-title | branch [ref]> [scan|medium|deep] [--post] [--fix] [--base <ref>]"
|
|
48
|
+
argument-hint: "<github-pr-url | repo pr-number | repo pr-title | branch [ref]> [scan|medium|deep|deps] [--post] [--fix] [--base <ref>]"
|
|
49
49
|
---
|
|
50
50
|
<!-- Generated by scripts/build-adapters.sh. Do not edit directly. -->
|
|
51
51
|
|
|
@@ -245,11 +245,17 @@ Then:
|
|
|
245
245
|
`LOCAL_BRANCH` is `main`, `master`, `develop`, `staging`, or `production`, stop
|
|
246
246
|
and say so.
|
|
247
247
|
|
|
248
|
-
**Depth:** explicit keyword `scan`, `medium`, or `
|
|
249
|
-
the
|
|
250
|
-
`gh pr view <PR_NUMBER> --repo <REPO_SLUG> --json additions,deletions,changedFiles
|
|
251
|
-
|
|
252
|
-
`git diff --
|
|
248
|
+
**Depth:** explicit keyword `scan`, `medium`, `deep` or `deps` wins. If absent,
|
|
249
|
+
get the per-file stat - in `pr` mode from
|
|
250
|
+
`gh pr view <PR_NUMBER> --repo <REPO_SLUG> --json additions,deletions,changedFiles,files,baseRefName,state,mergeCommit`
|
|
251
|
+
(keep `baseRefName` as `BASE_BRANCH` and `changedFiles` as `EXPECTED_FILES` for
|
|
252
|
+
Track A; when `state` is `MERGED`, keep `mergeCommit.oid` as `MERGE_COMMIT`), in `branch` mode from `git diff --numstat <MERGE_BASE> HEAD` - and
|
|
253
|
+
apply AUTO-DEPTH. Lockfiles (`package-lock.json`, `npm-shrinkwrap.json`,
|
|
254
|
+
`yarn.lock`, `pnpm-lock.yaml`, `bun.lock`, `bun.lockb`) do NOT count toward
|
|
255
|
+
additions+deletions: a regenerated lockfile is thousands of lines nobody reads.
|
|
256
|
+
- `deps` (candidate) if every changed file is a lockfile or a `package.json`.
|
|
257
|
+
Confirmed after Track A by `scripts/deps-only.mjs` (see "Confirm deps depth");
|
|
258
|
+
until then run Track B as for `scan`.
|
|
253
259
|
- `scan` if additions+deletions < 150 AND changedFiles <= 5
|
|
254
260
|
- `deep` if additions+deletions > 800 OR changedFiles > 25 OR diff touches
|
|
255
261
|
`migrations/` or `*.sql`
|
|
@@ -272,7 +278,8 @@ still needs explicit confirmation (Step 4).
|
|
|
272
278
|
|
|
273
279
|
**`--base <ref>` flag (branch mode only):** overrides base-ref detection. Passed
|
|
274
280
|
through to the scripts as `LEKKER_BASE_REF`. Ignored in `pr` mode, where the
|
|
275
|
-
base comes from the PR
|
|
281
|
+
base comes from the PR: Track A passes `LEKKER_BASE_REF=origin/<BASE_BRANCH>`
|
|
282
|
+
itself, so the script fetches the base and diffs against its current tip.
|
|
276
283
|
|
|
277
284
|
**`--no-fix` flag:** parse and store as `FIX_MODE=false`, and do not offer fixes
|
|
278
285
|
in Step 4. Use it for a read-only pre-push look.
|
|
@@ -288,8 +295,8 @@ to `workflow` for `HOST=claude` and `codex` for `HOST=codex`. Reject an explicit
|
|
|
288
295
|
engine that does not exist on the current host (`workflow` requires Claude's
|
|
289
296
|
Workflow tool; `codex` requires Codex native collaboration). `revmux` is
|
|
290
297
|
allowed only at depth `medium` or `deep` - revmux's
|
|
291
|
-
scripts reject `scan` (see Depth gate). If depth resolves to `scan`
|
|
292
|
-
or auto), force `ENGINE` back to the current host's native engine regardless of
|
|
298
|
+
scripts reject `scan` (see Depth gate). If depth resolves to `scan` or `deps`
|
|
299
|
+
(explicit or auto), force `ENGINE` back to the current host's native engine regardless of
|
|
293
300
|
the flag and note `engine forced to <workflow|codex> - revmux needs
|
|
294
301
|
medium/deep` in the review header.
|
|
295
302
|
|
|
@@ -310,19 +317,19 @@ page for this PR.
|
|
|
310
317
|
|
|
311
318
|
## Depth gate
|
|
312
319
|
|
|
313
|
-
| Step | scan | medium | deep |
|
|
314
|
-
|
|
315
|
-
| Context: issue-tracker/CI/diff/existing-reviews | always | always | always |
|
|
316
|
-
| Context: chat/docs/framework-docs/monitoring/prior-review-memory (optional, MCP-dependent) | skip | included | included + broader recall |
|
|
317
|
-
| Worktree + static checks | skip (WORKTREE_PATH=null) unless `--fix` | included | included |
|
|
318
|
-
| Review agents | 2 triage (haiku) | 5 specialists (sonnet) | 5 specialists (sonnet) |
|
|
319
|
-
| Per-finding verification | Criticals + Importants | Criticals + Importants | Criticals + Importants |
|
|
320
|
-
| Completeness critic | skip | skip | included |
|
|
321
|
-
| Proof-of-bug (failing test per Critical or composed-boundary Important) | skip
|
|
322
|
-
| Living review artifact | included | included | included |
|
|
323
|
-
| Housekeeping (optional memory/notes writeback) | skip | included | included |
|
|
324
|
-
| `--post` | supported | supported | supported |
|
|
325
|
-
| `--fix` / fix offer | supported (forces worktree) | supported | supported |
|
|
320
|
+
| Step | 📦 deps | scan | medium | deep |
|
|
321
|
+
|-----------------------------|-----------------------|-----------------------|---------------------|----------------------------|
|
|
322
|
+
| Context: issue-tracker/CI/diff/existing-reviews | always | always | always | always |
|
|
323
|
+
| Context: chat/docs/framework-docs/monitoring/prior-review-memory (optional, MCP-dependent) | skip | skip | included | included + broader recall |
|
|
324
|
+
| Worktree + static checks | included (`npm ci` per changed lockfile) | skip (WORKTREE_PATH=null) unless `--fix` | included | included |
|
|
325
|
+
| Review agents | 1 deps checklist | 2 triage (haiku) | 5 specialists (sonnet) | 5 specialists (sonnet) |
|
|
326
|
+
| Per-finding verification | none | Criticals + Importants | Criticals + Importants | Criticals + Importants |
|
|
327
|
+
| Completeness critic | skip | skip | skip | included |
|
|
328
|
+
| Proof-of-bug (failing test per Critical or composed-boundary Important) | skip | skip | included (max 5) | included (max 5) |
|
|
329
|
+
| Living review artifact | included | included | included | included |
|
|
330
|
+
| Housekeeping (optional memory/notes writeback) | skip | skip | included | included |
|
|
331
|
+
| `--post` | supported | supported | supported | supported |
|
|
332
|
+
| `--fix` / fix offer | supported | supported (forces worktree) | supported | supported |
|
|
326
333
|
|
|
327
334
|
For scan: note `⚡ scan - worktree unavailable, static checks skipped` in the
|
|
328
335
|
review header. When `--fix` forced the worktree at scan depth, drop that note
|
|
@@ -351,7 +358,19 @@ Fire both tracks in the same turn.
|
|
|
351
358
|
Run via Bash with `run_in_background`:
|
|
352
359
|
|
|
353
360
|
```bash
|
|
354
|
-
# MODE=pr -
|
|
361
|
+
# MODE=pr - fetches origin/<PR_BRANCH> AND origin/<BASE_BRANCH>, then checks out
|
|
362
|
+
# the PR branch. Without the base fetch the merge-base is whatever this clone
|
|
363
|
+
# last saw, and the file list widens (65 files instead of 9 on one PR).
|
|
364
|
+
# LEKKER_EXPECTED_FILES lets the script report a list that still disagrees.
|
|
365
|
+
LEKKER_BASE_REF=origin/<BASE_BRANCH> LEKKER_EXPECTED_FILES=<EXPECTED_FILES> \
|
|
366
|
+
${SKILL_ROOT}/scripts/setup-worktree.sh \
|
|
367
|
+
<REPO_SLUG> <PR_BRANCH> <scratchpad>/worktree.json [PREV_SHA]
|
|
368
|
+
|
|
369
|
+
# MODE=pr, PR already MERGED - the head is inside the base branch now, so
|
|
370
|
+
# merge-base(head, origin/<BASE_BRANCH>) is the head and the diff is empty.
|
|
371
|
+
# Diff against the base as it was just before the merge instead.
|
|
372
|
+
LEKKER_BASE_BRANCH=<BASE_BRANCH> LEKKER_BASE_REF=<MERGE_COMMIT>^1 \
|
|
373
|
+
LEKKER_EXPECTED_FILES=<EXPECTED_FILES> \
|
|
355
374
|
${SKILL_ROOT}/scripts/setup-worktree.sh \
|
|
356
375
|
<REPO_SLUG> <PR_BRANCH> <scratchpad>/worktree.json [PREV_SHA]
|
|
357
376
|
```
|
|
@@ -369,7 +388,32 @@ ${SKILL_ROOT}/scripts/setup-worktree.sh \
|
|
|
369
388
|
On completion, read `worktree.json`. Keys emitted:
|
|
370
389
|
`worktreePath`, `repoRoot`, `headSha`, `headShaShort`, `tscTail`,
|
|
371
390
|
`tscChangedTail`, `tscErrorCount`, `eslintTail`, `eslintScope`, `changedFiles`,
|
|
372
|
-
`baseRef`, `mergeBase`, `projectRules`, `deltaFile`, `notes`.
|
|
391
|
+
`baseRef`, `mergeBase`, `projectRules`, `deltaFile`, `notes`, `depsInstall`.
|
|
392
|
+
|
|
393
|
+
`notes` containing `changed-files-mismatch:<got>-vs-<expected>` means the
|
|
394
|
+
merge-base still disagrees with the PR. Use the `files` list from `gh pr view`
|
|
395
|
+
as the changed-file list for the review header and agents, and say so in the
|
|
396
|
+
header; the static-check scoping is the script's best effort.
|
|
397
|
+
|
|
398
|
+
`depsInstall` is non-empty when the diff changed a lockfile: one row per
|
|
399
|
+
lockfile dir, `{dir, status: ok|failed|timeout, tail?}`. The script ran
|
|
400
|
+
`npm ci --ignore-scripts` there instead of symlinking the repo's
|
|
401
|
+
`node_modules`, which holds the pre-PR dependency tree. A row that is not `ok`
|
|
402
|
+
is evidence for the review (a lockfile `npm ci` rejects fails the deploy too),
|
|
403
|
+
not a reason to stop. Set `LEKKER_NO_INSTALL=1` to skip the install. Lockfile
|
|
404
|
+
dirs using yarn, pnpm or bun are not installed (note `deps-install-unsupported`).
|
|
405
|
+
|
|
406
|
+
**Confirm deps depth** (only when Step 0 picked the `deps` candidate):
|
|
407
|
+
|
|
408
|
+
```bash
|
|
409
|
+
node ${SKILL_ROOT}/scripts/deps-only.mjs \
|
|
410
|
+
<worktreePath> <mergeBase> <changedFiles...> > <scratchpad>/deps-report.json
|
|
411
|
+
```
|
|
412
|
+
|
|
413
|
+
`kind: "deps"` confirms it; pass the report as `depsReport` in CONTEXT_FILE.
|
|
414
|
+
`kind: "mixed"` (a `scripts`, `name` or other non-dependency key changed, or a
|
|
415
|
+
`package.json` was added) means re-apply AUTO-DEPTH without the `deps` rule, and
|
|
416
|
+
fetch the Track B sources the new depth includes before Step 2.
|
|
373
417
|
|
|
374
418
|
`mergeBase` is the commit the file list was scoped against. Branch mode
|
|
375
419
|
generates its diff from that exact sha (below), so the diff the agents read and
|
|
@@ -469,7 +513,10 @@ Write `<scratchpad>/context.json` with keys:
|
|
|
469
513
|
"deltaFile": "<worktree.json deltaFile, or null>",
|
|
470
514
|
"houseRulesFile": "${SKILL_ROOT}/references/house-rules.md",
|
|
471
515
|
"reviewTarget": "<TARGET_LABEL, e.g. 'PR #412' or 'branch feat/offline-orders'>",
|
|
472
|
-
"prePush": "<true in MODE=branch, false in MODE=pr>"
|
|
516
|
+
"prePush": "<true in MODE=branch, false in MODE=pr>",
|
|
517
|
+
"depsReport": "<deps-report.json contents at depth deps, else null>",
|
|
518
|
+
"depsInstall": "<worktree.json depsInstall>",
|
|
519
|
+
"prBody": "<PR body at depth deps, else omit>"
|
|
473
520
|
}
|
|
474
521
|
```
|
|
475
522
|
|
|
@@ -539,7 +586,7 @@ that only when a specific run needs a smaller footprint.
|
|
|
539
586
|
|
|
540
587
|
The workflow runs three phases:
|
|
541
588
|
|
|
542
|
-
- **Review:** scan uses `[triage-quality, triage-logic]` on `haiku`; medium/deep
|
|
589
|
+
- **Review:** deps uses the single `deps` checklist agent; scan uses `[triage-quality, triage-logic]` on `haiku`; medium/deep
|
|
543
590
|
use 5 specialists (quality, implementation, simplification, conventions,
|
|
544
591
|
test-quality) on `sonnet`. Agents receive DIFF_FILE + CONTEXT_FILE by path.
|
|
545
592
|
All five run concurrently: the stage is self-limiting at one agent per
|
|
@@ -552,8 +599,9 @@ The workflow runs three phases:
|
|
|
552
599
|
description/badCode/fix of the set - a Critical is never demoted by an
|
|
553
600
|
Observation someone else filed at the same line - and records every
|
|
554
601
|
contributing dimension in `agreedBy`.
|
|
555
|
-
- **Verify:** every Critical and Important is checked at
|
|
556
|
-
can affect the verdict.
|
|
602
|
+
- **Verify:** every Critical and Important is checked at scan, medium and deep because it
|
|
603
|
+
can affect the verdict. The `deps` depth verifies nothing: its findings are advisory
|
|
604
|
+
checklist facts (audit delta, install result) with nothing for a verifier to refute. Hard-rule findings (`rule` set) use the verifier's
|
|
557
605
|
diff-anchor and rule-applicability checks instead of runtime challenges.
|
|
558
606
|
Each verifier runs the five-challenge adversarial refutation from
|
|
559
607
|
`references/agents/verifier.md` against one finding, returns
|
|
@@ -728,6 +776,23 @@ codebase. Never on taste alone. These land in their own section, not in
|
|
|
728
776
|
Critical/Important. A finding without a cited precedent from the codebase is
|
|
729
777
|
dropped.
|
|
730
778
|
|
|
779
|
+
**Validate line numbers first.** When there is a worktree, write the workflow's
|
|
780
|
+
`findings` to `<scratchpad>/findings.json` and run
|
|
781
|
+
|
|
782
|
+
```bash
|
|
783
|
+
node ${SKILL_ROOT}/scripts/validate-lines.mjs \
|
|
784
|
+
<scratchpad>/findings.json <worktreePath>
|
|
785
|
+
```
|
|
786
|
+
|
|
787
|
+
It checks each `line` against the file at HEAD using the finding's `badCode`:
|
|
788
|
+
kept when it is within 3 lines, re-anchored on a unique match
|
|
789
|
+
(`lineRemapped: true`), or set to `null` when the code is not in the file
|
|
790
|
+
(a `pr.diff` line number cited as a file line). Use the rewritten file from
|
|
791
|
+
here on. A `null` line is a PR-level finding: cite the file without a line, and
|
|
792
|
+
never post it as an inline comment. With no worktree (scan), skip this and do
|
|
793
|
+
not claim the lines were checked. Print the summary counts only when something
|
|
794
|
+
was remapped or nulled.
|
|
795
|
+
|
|
731
796
|
**Pick the closer** (skip when `FUN=false`): once the verdict is decided, run
|
|
732
797
|
the picker ONCE and keep its JSON as `CLOSER` for the rest of the run, so the
|
|
733
798
|
terminal, saved file, artifact and GitHub body all show the same joke:
|
|
@@ -827,7 +892,10 @@ post.
|
|
|
827
892
|
## Step 3.5 - Living review artifact (skip when ARTIFACT=false)
|
|
828
893
|
|
|
829
894
|
Immediately after printing the review, follow `references/artifact-page.md`.
|
|
830
|
-
Claude
|
|
895
|
+
On Claude, the renderer subagent only writes the HTML and returns its path; the
|
|
896
|
+
main loop fetches the closer image into a base64 `data:` URI file
|
|
897
|
+
(`CLOSER_DATAURI_FILE`), reads the HTML, checks its `<title>` and that it has no
|
|
898
|
+
external `<img>`, and publishes it through Artifact. Codex uses a publish-capable artifact tool
|
|
831
899
|
when one is already available; otherwise it writes or updates the stable local
|
|
832
900
|
self-contained HTML path defined there. The page is the living version of the
|
|
833
901
|
review: verdict header, since-last-review timeline, findings with proof panels.
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
# deps - lekker-review agent prompt
|
|
2
|
+
You will receive in your task message: REPO_SLUG, PR_NUMBER, PR_URL, DIFF_FILE, CONTEXT_FILE (JSON), WORKTREE_PATH.
|
|
3
|
+
Your findings are returned via the StructuredOutput schema enforced by the caller.
|
|
4
|
+
|
|
5
|
+
This PR changes only lockfiles and the dependency keys of `package.json`
|
|
6
|
+
(`depsReport` in CONTEXT_FILE says which keys, per file). You are the ONLY
|
|
7
|
+
reviewer, so cover the whole checklist. Skip lockfile churn line by line: a
|
|
8
|
+
regenerated lockfile is not reviewable by eye, and the install and audit below
|
|
9
|
+
are the evidence for it.
|
|
10
|
+
|
|
11
|
+
Inputs from CONTEXT_FILE:
|
|
12
|
+
- `depsReport`: `{ packageJsons: [{ file, depKeysChanged }], lockDirs }`.
|
|
13
|
+
- `depsInstall`: per lockfile dir, `{ dir, status: ok|failed|timeout, tail? }`
|
|
14
|
+
from `npm ci --ignore-scripts` in the worktree. Empty means none ran.
|
|
15
|
+
- `prBody`, `ciStatus`, `existingReviews` (skip anything already raised).
|
|
16
|
+
|
|
17
|
+
Checklist, in order:
|
|
18
|
+
|
|
19
|
+
1. **Reason per change.** Every added or raised version, and every new
|
|
20
|
+
`overrides`/`resolutions` entry, has a stated reason: an advisory id
|
|
21
|
+
(GHSA/CVE), a Dependabot alert, or a line in the PR body. No reason ->
|
|
22
|
+
`observation`.
|
|
23
|
+
2. **Overrides that force a major.** For each override, read the dependant's
|
|
24
|
+
own declared range (`WORKTREE_PATH/<dir>/node_modules/<dependant>/package.json`
|
|
25
|
+
or `npm ls <pkg>` in that dir). An override pinning a major the dependant does
|
|
26
|
+
not declare -> `observation` asking for a removal ticket, naming the
|
|
27
|
+
condition that lets it go (dependant upgrade).
|
|
28
|
+
3. **Runtime compatibility.** A new major that drops a Node version: compare
|
|
29
|
+
with `engines.node` and with the runtime image (`Dockerfile` `FROM`, CI
|
|
30
|
+
`node-version`). An actual mismatch -> `important`.
|
|
31
|
+
4. **Install.** Any `depsInstall` row not `ok` -> `important`, quoting the tail.
|
|
32
|
+
A lockfile that `npm ci` rejects will fail the deploy too.
|
|
33
|
+
5. **Audit delta.** In each `lockDirs` dir run
|
|
34
|
+
`npm audit --omit=dev --json` in WORKTREE_PATH (head), and compare with the
|
|
35
|
+
advisories the PR body says it fixes. A high/critical advisory still present
|
|
36
|
+
that the PR claims to fix -> `important`. One introduced by the bump ->
|
|
37
|
+
`important`. Pre-existing ones with no fix -> one `observation`, not one per
|
|
38
|
+
advisory. If `npm audit` cannot run (no network), say so in that observation;
|
|
39
|
+
never report it as clean.
|
|
40
|
+
Read the whole `prBody` first: when it already names the residual advisories
|
|
41
|
+
or says the audit check stays red, say that in the observation and ask for
|
|
42
|
+
nothing; never request a note the author already wrote.
|
|
43
|
+
6. **Runtime vs dev.** Note which bumps reach production (`dependencies`) and
|
|
44
|
+
which are dev-only; a runtime major bump with no test or changelog note in
|
|
45
|
+
the PR body -> `observation`.
|
|
46
|
+
|
|
47
|
+
Rules:
|
|
48
|
+
- `file` + `line`: anchor on the `package.json` line of the dependency or
|
|
49
|
+
override (1-based line in the file at HEAD), never on a lockfile line.
|
|
50
|
+
- `badCode`: that `package.json` line verbatim. `fix`: the concrete change or
|
|
51
|
+
the ticket to open.
|
|
52
|
+
- No Critical findings: a dependency bump that breaks something shows up as a
|
|
53
|
+
failed install, a failed check or an advisory, which are `important`.
|
|
54
|
+
- Do not re-review lockfile integrity hashes or resolved URLs.
|
|
@@ -38,6 +38,25 @@ All of the following are already in hand after Step 3 of SKILL.md:
|
|
|
38
38
|
|
|
39
39
|
### Claude Code
|
|
40
40
|
|
|
41
|
+
The subagent RENDERS; the main loop PUBLISHES. Leaf agents run without the
|
|
42
|
+
Artifact tool (a renderer can write the page and then be unable to publish
|
|
43
|
+
it), so never ask the subagent to publish.
|
|
44
|
+
|
|
45
|
+
**Closer image (main loop, before launching):** when `CLOSER` is set, fetch its
|
|
46
|
+
image so the page can show it inline. The page CSP blocks external images but
|
|
47
|
+
not `data:` URIs.
|
|
48
|
+
|
|
49
|
+
```bash
|
|
50
|
+
# xkcd: the strip image (`img`); gif: the gif itself (`url`). Cap 500 KB, 10 s.
|
|
51
|
+
curl -sfL --max-time 10 --max-filesize 512000 -o <scratchpad>/closer-img <image url> \
|
|
52
|
+
&& [ "$(wc -c < <scratchpad>/closer-img)" -le 512000 ] \
|
|
53
|
+
&& echo "data:<image/png or image/gif>;base64,$(base64 < <scratchpad>/closer-img | tr -d '\n')" \
|
|
54
|
+
> <scratchpad>/closer-datauri.txt
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
Pass `CLOSER_DATAURI_FILE=<scratchpad>/closer-datauri.txt` when that file
|
|
58
|
+
exists; otherwise omit it and the card stays link-only.
|
|
59
|
+
|
|
41
60
|
Launch exactly ONE `general-purpose` agent, `model: sonnet`, in the
|
|
42
61
|
background. Do not block printing the review on it (see Hard rules).
|
|
43
62
|
|
|
@@ -53,17 +72,12 @@ Read the findings at <findings.json path> and the saved review at
|
|
|
53
72
|
Write ONE self-contained HTML file to the session scratchpad:
|
|
54
73
|
review-pr-<PR_NUMBER>-<repo-short>.html
|
|
55
74
|
|
|
56
|
-
Follow the page specification below exactly.
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
- description: <one sentence, e.g. "Living code review for PR #<N> --
|
|
61
|
-
findings update as commits land">
|
|
62
|
-
- url: <PREV_ARTIFACT_TARGET> (include ONLY when the target is a validated
|
|
63
|
-
http or https URL, so the SAME published artifact updates in place; omit
|
|
64
|
-
the `url` parameter for null or local-path targets)
|
|
75
|
+
Follow the page specification below exactly. The <title> is
|
|
76
|
+
"Review: <repo-short> #<PR_NUMBER>". CLOSER=<closer JSON, or empty>.
|
|
77
|
+
CLOSER_DATAURI_FILE=<path, or empty>. Do NOT publish the page and do not look
|
|
78
|
+
for an Artifact tool: the caller publishes it.
|
|
65
79
|
|
|
66
|
-
Return ONLY the
|
|
80
|
+
Return ONLY the absolute path of the HTML file as your final text.
|
|
67
81
|
|
|
68
82
|
--- PAGE SPECIFICATION ---
|
|
69
83
|
<paste Step 3 verbatim here>
|
|
@@ -157,8 +171,11 @@ Hard requirements for the HTML page:
|
|
|
157
171
|
kept concise (verdict + gaps + cost table; no need to reproduce every
|
|
158
172
|
sentence).
|
|
159
173
|
- **Closer footer** (when the caller passes `CLOSER`): a small last card with
|
|
160
|
-
the closer's title (or `alt`) as a link to its `url`.
|
|
161
|
-
|
|
174
|
+
the closer's title (or `alt`) as a link to its `url`. When
|
|
175
|
+
`CLOSER_DATAURI_FILE` is set, read it and render
|
|
176
|
+
`<img src="<its contents>" alt="<title or alt>">` above the link, at
|
|
177
|
+
`max-width:100%; height:auto`. Never point `<img>` at an external URL: the
|
|
178
|
+
CSP blocks it. Skip the card when `CLOSER` is empty.
|
|
162
179
|
- **Layout:** every code block (`badCode`, `fix`, `redOutput`, `testCode`)
|
|
163
180
|
horizontally scrollable within its own container; the page body itself must
|
|
164
181
|
never scroll horizontally. Keep total page weight sane -- plain `<pre>`
|
|
@@ -170,7 +187,15 @@ Hard requirements for the HTML page:
|
|
|
170
187
|
|
|
171
188
|
## Step 4 -- Record the artifact target (fresh post-condition)
|
|
172
189
|
|
|
173
|
-
When the renderer completes:
|
|
190
|
+
When the renderer completes (Claude Code: the subagent returns the HTML path):
|
|
191
|
+
|
|
192
|
+
1. Read the HTML file in full (the Artifact tool publishes only files that were
|
|
193
|
+
read), and check that it has a `<title>` and no external `<img src="http`.
|
|
194
|
+
2. Publish with the Artifact tool: `file_path` = that path, `description` = one
|
|
195
|
+
sentence ("Living code review for PR #<N>; findings update as commits
|
|
196
|
+
land"), and `url: <PREV_ARTIFACT_TARGET>` ONLY when it is a validated `http`
|
|
197
|
+
or `https` URL, so the same artifact updates in place. On a first publish
|
|
198
|
+
add `icon: "review"`; omit `icon` on a republish so the page keeps its icon.
|
|
174
199
|
|
|
175
200
|
**On success (URL or stable local HTML path returned):**
|
|
176
201
|
1. Append or refresh a `**Artifact:** <target>` line in the saved review file's
|
|
@@ -203,5 +228,5 @@ When the renderer completes:
|
|
|
203
228
|
- Never include secrets or tokens from context. The page contains only what
|
|
204
229
|
the saved review file already contains -- nothing pulled fresh from
|
|
205
230
|
scratchpad context that isn't already in the review.
|
|
206
|
-
-
|
|
231
|
+
- Set the artifact icon only on the first publish; never change it on
|
|
207
232
|
republish.
|
|
@@ -60,6 +60,7 @@ unavailable; do not infer what it meant from prose.
|
|
|
60
60
|
|
|
61
61
|
Select dimensions exactly as the Claude workflow does:
|
|
62
62
|
|
|
63
|
+
- deps: `deps` (single checklist agent; no verifier, no prover)
|
|
63
64
|
- scan: `triage-quality`, `triage-logic`
|
|
64
65
|
- medium/deep: `quality`, `implementation`, `simplification`, `conventions`,
|
|
65
66
|
`test-quality`
|
|
@@ -30,7 +30,9 @@ Rules:
|
|
|
30
30
|
review programmatically.
|
|
31
31
|
- Include one comment entry for every Critical and Important finding whose
|
|
32
32
|
`file:line` falls within the diff hunks of this PR (see Step 2 for how to
|
|
33
|
-
determine commentability).
|
|
33
|
+
determine commentability). A finding with `line: null` (set by
|
|
34
|
+
`scripts/validate-lines.mjs` when its quoted code is not in the file) is
|
|
35
|
+
never an inline comment: list it in the review body instead.
|
|
34
36
|
- **Keep every comment body to 2-4 sentences and under ~700 characters**
|
|
35
37
|
(excluding any suggestion block). Inline comments are read one at a time in a
|
|
36
38
|
narrow column; a long one does not get read, so length actively costs you the
|
|
@@ -23,7 +23,7 @@ Output the review as a markdown response (not via printf). No ANSI escapes.
|
|
|
23
23
|
**Findings:** <X Critical / Y Important / Z Observations / W Idiomatic>
|
|
24
24
|
**Proofs:** <M proven / N attempted> *(include only when N > 0)*
|
|
25
25
|
**CI:** <✅ All passing | ⚠️ N failing: check-name | ⏳ Pending | N/A>
|
|
26
|
-
**Depth:**
|
|
26
|
+
**Depth:** <📦 deps | ⚡ scan | 🔍 medium | 🔬 deep>
|
|
27
27
|
**Engine:** <workflow | codex | revmux>
|
|
28
28
|
|
|
29
29
|
---
|
|
@@ -215,7 +215,7 @@ if empty.)*
|
|
|
215
215
|
## 💰 Review Cost
|
|
216
216
|
|
|
217
217
|
```
|
|
218
|
-
Depth:
|
|
218
|
+
Depth: <📦 deps | ⚡ scan | 🔍 medium | 🔬 deep>
|
|
219
219
|
Diff size: ~<N> lines (~<N> tokens)
|
|
220
220
|
Agents run: <N total>: <breakdown, e.g. "5 reviewers (sonnet) + 6 verifiers (sonnet) + 2 provers (sonnet) + 1 critic (sonnet)">
|
|
221
221
|
Rule checks: <N> hard-rule finding(s) validated with rule-specific checks (omit the line when 0)
|
|
@@ -228,16 +228,17 @@ Input tokens: ~<N> ← estimated: diff tokens × agent passes + context fil
|
|
|
228
228
|
Cost: ~$<X.XX> (output actual, input estimated; blended across model tiers below)
|
|
229
229
|
```
|
|
230
230
|
|
|
231
|
-
Per-MTok pricing (input/output)
|
|
232
|
-
- claude-fable-5-1: $10 / $50
|
|
233
|
-
- claude-opus-5-5: $
|
|
234
|
-
- claude-
|
|
235
|
-
- claude-
|
|
236
|
-
- claude-
|
|
237
|
-
- claude-
|
|
238
|
-
- claude-sonnet-4-6 / claude-sonnet-5: $3 / $15
|
|
231
|
+
Per-MTok pricing (input/output) - verified 2026-10-15 from the claude-api reference (`shared/models.md`); re-check there if models changed:
|
|
232
|
+
- claude-fable-5-1 / claude-fable-5: $10 / $50
|
|
233
|
+
- claude-opus-5-5: $4 / $20
|
|
234
|
+
- claude-opus-5 / claude-opus-4-8: $5 / $25
|
|
235
|
+
- claude-sonnet-5-5 / claude-sonnet-5: $2 / $10
|
|
236
|
+
- claude-sonnet-4-6: $3 / $15
|
|
237
|
+
- claude-haiku-5-5: $0.10 / $0.50 (prompt <=100K tokens; $0.50 / $2.50 above)
|
|
239
238
|
- claude-haiku-4-5: $1 / $5
|
|
240
239
|
|
|
240
|
+
The main-loop line uses the session model's rate from this list. When the session model is not listed, say so in the cost block rather than leaving the main loop out silently.
|
|
241
|
+
|
|
241
242
|
Reviewer agents, verifiers, provers, and the critic all run on sonnet; triage and housekeeping on haiku. Only the main loop (context gathering + this synthesis) runs on the session model: use the session model's actual ID for that tier.
|
|
242
243
|
|
|
243
244
|
For the Codex engine, use the model and usage metadata actually exposed by the
|
|
@@ -1,13 +1,14 @@
|
|
|
1
1
|
{
|
|
2
|
-
"note": "USD per million tokens, keyed by revmux's actual_model. revmux runs `claude --print` under subscription (Max plan) auth, so nothing here is a real API bill; this is an API-list-price ESTIMATE for the cost block only. Where a model exposes separate input/output prices, usd = tokens/1e6 * output price (output-only, not blended), because revmux reports a single combined `tokens` figure per agent with no input/output split to weight a blend. verified
|
|
3
|
-
"claude-fable-5-1": { "input": 10,
|
|
4
|
-
"claude-
|
|
5
|
-
"claude-
|
|
6
|
-
"claude-
|
|
7
|
-
"claude-
|
|
8
|
-
"claude-sonnet-5":
|
|
9
|
-
"claude-haiku-
|
|
10
|
-
"
|
|
11
|
-
"
|
|
12
|
-
"
|
|
2
|
+
"note": "USD per million tokens, keyed by revmux's actual_model. revmux runs `claude --print` under subscription (Max plan) auth, so nothing here is a real API bill; this is an API-list-price ESTIMATE for the cost block only. Where a model exposes separate input/output prices, usd = tokens/1e6 * output price (output-only, not blended), because revmux reports a single combined `tokens` figure per agent with no input/output split to weight a blend. Rates verified 2026-10-15 against the claude-api skill reference (shared/models.md, shared/model-migration.md). Haiku 5.5 has two rate cards; the entry is the <=100K-prompt card. The bare tier aliases (opus/sonnet/haiku) follow the current model of each tier. Re-check there when a model changes.",
|
|
3
|
+
"claude-fable-5-1": { "input": 10, "output": 50, "blended": 30, "verified": "2026-10-15" },
|
|
4
|
+
"claude-fable-5": { "input": 10, "output": 50, "blended": 30, "verified": "2026-10-15" },
|
|
5
|
+
"claude-opus-5-5": { "input": 4, "output": 20, "blended": 12, "verified": "2026-10-15" },
|
|
6
|
+
"claude-opus-5": { "input": 5, "output": 25, "blended": 15, "verified": "2026-10-15" },
|
|
7
|
+
"claude-sonnet-5-5": { "input": 2, "output": 10, "blended": 6, "verified": "2026-10-15" },
|
|
8
|
+
"claude-sonnet-5": { "input": 2, "output": 10, "blended": 6, "verified": "2026-10-15" },
|
|
9
|
+
"claude-haiku-5-5": { "input": 0.1, "output": 0.5, "blended": 0.3, "verified": "2026-10-15" },
|
|
10
|
+
"claude-haiku-4-5-20251001": { "input": 1, "output": 5, "blended": 3, "verified": "2026-10-15" },
|
|
11
|
+
"opus": { "input": 4, "output": 20, "blended": 12, "verified": "2026-10-15" },
|
|
12
|
+
"sonnet": { "input": 2, "output": 10, "blended": 6, "verified": "2026-10-15" },
|
|
13
|
+
"haiku": { "input": 0.1, "output": 0.5, "blended": 0.3, "verified": "2026-10-15" }
|
|
13
14
|
}
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
// Decides whether a PR is a pure dependency change: every changed file is a
|
|
3
|
+
// lockfile or a package.json, and each package.json differs only in its
|
|
4
|
+
// dependency keys. Such a PR gets the one-agent `deps` depth; anything else is
|
|
5
|
+
// `mixed` and falls back to the normal depth rules.
|
|
6
|
+
//
|
|
7
|
+
// node deps-only.mjs <worktreePath> <mergeBase> <changed file>...
|
|
8
|
+
//
|
|
9
|
+
// Prints JSON: { kind: "deps"|"mixed", packageJsons, lockDirs, otherFiles }.
|
|
10
|
+
// Exit 0 in both cases; exit 2 only on bad arguments.
|
|
11
|
+
import { execFileSync } from 'node:child_process'
|
|
12
|
+
import { realpathSync } from 'node:fs'
|
|
13
|
+
import { fileURLToPath } from 'node:url'
|
|
14
|
+
import { basename, dirname } from 'node:path'
|
|
15
|
+
|
|
16
|
+
export const LOCKFILES = new Set([
|
|
17
|
+
'package-lock.json', 'npm-shrinkwrap.json', 'yarn.lock', 'pnpm-lock.yaml', 'bun.lock', 'bun.lockb',
|
|
18
|
+
])
|
|
19
|
+
// `engines` is here because a dependency bump that needs a newer runtime
|
|
20
|
+
// raises it in the same PR; the deps agent checks it against the runtime image.
|
|
21
|
+
export const DEP_KEYS = new Set([
|
|
22
|
+
'dependencies', 'devDependencies', 'peerDependencies', 'optionalDependencies',
|
|
23
|
+
'overrides', 'resolutions', 'engines',
|
|
24
|
+
])
|
|
25
|
+
|
|
26
|
+
function changedKeys(before, after) {
|
|
27
|
+
const keys = new Set([...Object.keys(before), ...Object.keys(after)])
|
|
28
|
+
return [...keys].filter(k => JSON.stringify(before[k]) !== JSON.stringify(after[k])).sort()
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
// readAt(rev, path) returns the file text at that revision, or null when the
|
|
32
|
+
// file does not exist there. Injected so the selftest can drive it with fixtures.
|
|
33
|
+
export function classify(files, readAt, base = 'BASE', head = 'HEAD') {
|
|
34
|
+
const packageJsons = []
|
|
35
|
+
const lockDirs = []
|
|
36
|
+
const otherFiles = []
|
|
37
|
+
for (const file of files) {
|
|
38
|
+
const name = basename(file)
|
|
39
|
+
if (LOCKFILES.has(name)) {
|
|
40
|
+
lockDirs.push(dirname(file))
|
|
41
|
+
continue
|
|
42
|
+
}
|
|
43
|
+
if (name !== 'package.json') {
|
|
44
|
+
otherFiles.push(file)
|
|
45
|
+
continue
|
|
46
|
+
}
|
|
47
|
+
let before, after
|
|
48
|
+
try {
|
|
49
|
+
const b = readAt(base, file), a = readAt(head, file)
|
|
50
|
+
if (b == null || a == null) throw new Error('missing on one side')
|
|
51
|
+
before = JSON.parse(b)
|
|
52
|
+
after = JSON.parse(a)
|
|
53
|
+
if (!before || !after || typeof before !== 'object' || typeof after !== 'object') throw new Error('not an object')
|
|
54
|
+
} catch {
|
|
55
|
+
// Added, deleted or unparseable: a new or removed workspace is not a bump.
|
|
56
|
+
packageJsons.push({ file, depKeysChanged: [], otherKeysChanged: ['<added, removed or unparseable>'] })
|
|
57
|
+
continue
|
|
58
|
+
}
|
|
59
|
+
const keys = changedKeys(before, after)
|
|
60
|
+
packageJsons.push({
|
|
61
|
+
file,
|
|
62
|
+
depKeysChanged: keys.filter(k => DEP_KEYS.has(k)),
|
|
63
|
+
otherKeysChanged: keys.filter(k => !DEP_KEYS.has(k)),
|
|
64
|
+
})
|
|
65
|
+
}
|
|
66
|
+
const pure = otherFiles.length === 0
|
|
67
|
+
&& packageJsons.every(p => p.otherKeysChanged.length === 0)
|
|
68
|
+
&& (lockDirs.length > 0 || packageJsons.length > 0)
|
|
69
|
+
return { kind: pure ? 'deps' : 'mixed', packageJsons, lockDirs: [...new Set(lockDirs)].sort(), otherFiles }
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
function gitReader(worktree) {
|
|
73
|
+
return (rev, path) => {
|
|
74
|
+
try {
|
|
75
|
+
return execFileSync('git', ['-C', worktree, 'show', `${rev}:${path}`], {
|
|
76
|
+
encoding: 'utf8', stdio: ['ignore', 'pipe', 'ignore'], maxBuffer: 64 * 1024 * 1024,
|
|
77
|
+
})
|
|
78
|
+
} catch {
|
|
79
|
+
return null
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
function isMain() {
|
|
85
|
+
try { return realpathSync(process.argv[1]) === realpathSync(fileURLToPath(import.meta.url)) } catch { return false }
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
if (isMain()) {
|
|
89
|
+
const [worktree, mergeBase, ...files] = process.argv.slice(2)
|
|
90
|
+
if (!worktree || !mergeBase || files.length === 0) {
|
|
91
|
+
console.error('usage: deps-only.mjs <worktreePath> <mergeBase> <changed file>...')
|
|
92
|
+
process.exit(2)
|
|
93
|
+
}
|
|
94
|
+
console.log(JSON.stringify(classify(files, gitReader(worktree), mergeBase, 'HEAD'), null, 2))
|
|
95
|
+
}
|