@olegkoval/agent-skills 1.67.0 → 1.68.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.
Files changed (21) hide show
  1. package/adapters/claude/olko-github-pr/skills/lekker-review/SKILL.md +29 -11
  2. package/adapters/claude/olko-github-pr/skills/lekker-review/references/reviewed-before-push.md +94 -0
  3. package/adapters/claude/olko-github-pr/skills/lekker-review/references/reviewed-before-push.yml +57 -0
  4. package/adapters/claude/olko-github-pr/skills/lekker-review/scripts/review-label.mjs +90 -0
  5. package/package.json +1 -1
  6. package/plugins/olko-apple-kit/.claude-plugin/plugin.json +1 -1
  7. package/plugins/olko-creative/.claude-plugin/plugin.json +1 -1
  8. package/plugins/olko-garmin-kit/.claude-plugin/plugin.json +1 -1
  9. package/plugins/olko-git-tools/.claude-plugin/plugin.json +1 -1
  10. package/plugins/olko-github-pr/.claude-plugin/plugin.json +1 -1
  11. package/plugins/olko-github-pr/skills/lekker-review/README.md +10 -0
  12. package/plugins/olko-github-pr/skills/lekker-review/SKILL.md +29 -11
  13. package/plugins/olko-github-pr/skills/lekker-review/references/reviewed-before-push.md +94 -0
  14. package/plugins/olko-github-pr/skills/lekker-review/references/reviewed-before-push.yml +57 -0
  15. package/plugins/olko-github-pr/skills/lekker-review/scripts/review-label.mjs +90 -0
  16. package/plugins/olko-obsidian/.claude-plugin/plugin.json +1 -1
  17. package/plugins/olko-product/.claude-plugin/plugin.json +1 -1
  18. package/plugins/olko-reflection/.claude-plugin/plugin.json +1 -1
  19. package/plugins/olko-release/.claude-plugin/plugin.json +1 -1
  20. package/plugins/olko-skill-meta/.claude-plugin/plugin.json +1 -1
  21. package/plugins/olko-web-ops/.claude-plugin/plugin.json +1 -1
@@ -1139,8 +1139,17 @@ printf '%s\n' "$REVIEW_FILE" > ~/.cache/lekker-review/reviewed/<headSha>
1139
1139
  ```
1140
1140
 
1141
1141
  Write it against the sha that was actually reviewed. When fix mode later adds
1142
- commits, write a marker for the NEW head sha too - a gate keys on the tip
1143
- that is about to be pushed, and a marker for a superseded sha would be a lie.
1142
+ commits, write a marker for the new head only after fix verification and
1143
+ relevant tests pass. Any unrelated edits require a fresh review; never copy a
1144
+ marker to an unreviewed SHA.
1145
+
1146
+ **PR label for branch reviews:** follow `references/reviewed-before-push.md`.
1147
+ After a complete, non-degraded local review and settling all Critical/Important
1148
+ findings, save the final-head receipt as `<scratchpad>/pre-push-review.json`
1149
+ BEFORE pushing. That reference defines the receipt schema and one-time cleanup
1150
+ workflow setup. The label is exactly `reviewed-before-push` (no AI prefix).
1151
+ A legacy SHA/path marker alone does not qualify. PR-mode reviews cannot earn
1152
+ this label.
1144
1153
 
1145
1154
  **Close the run log** right after the receipt, then print the review:
1146
1155
 
@@ -1314,33 +1323,42 @@ Ask once, via AskUserQuestion:
1314
1323
 
1315
1324
  Rules for each answer:
1316
1325
 
1317
- - **Yes:** push with `git push -u origin "$local_branch"`, then create the PR
1326
+ - **Yes:** set `PREDICTED_AT=$(date -u +%Y-%m-%dT%H:%M:%SZ)` before pushing
1327
+ or publishing, including when a PR already exists. Then push with
1328
+ `git push -u origin "$local_branch"` and create or locate the PR. Create it
1318
1329
  with `gh pr create --repo "$repo_slug" --base "$base_ref" --head
1319
1330
  "$local_branch" --title "$pr_title" --body-file "$pr_body_file"`. Derive the title
1320
1331
  from the commit log (the recommended prefix plus a summary of the change) and
1321
1332
  the body from a short summary of what the branch does - do not leave either
1322
- as a placeholder. Report the PR url. Then record the prediction against the
1323
- new PR number - a branch-mode review is the ideal case for this, because the
1324
- prediction provably predates every bot comment. Record only the findings fix
1333
+ as a placeholder. Report the PR url. If an eligible pre-push receipt was
1334
+ saved, publish it using `scripts/review-label.mjs` as described in
1335
+ `references/reviewed-before-push.md`. This posts the commit/engine/depth/result
1336
+ evidence and applies `reviewed-before-push` only to the matching live head.
1337
+ If cleanup is not installed, omit the label and report the setup requirement;
1338
+ do not undo the successful PR creation. For an existing PR found after a
1339
+ branch-mode push, use the same helper and head check. Then record the prediction
1340
+ against the created or existing PR number using the saved `PREDICTED_AT`;
1341
+ scoring uses it to include bot comments triggered by the push or PR creation,
1342
+ even if they arrive before the record step. Record only the findings fix
1325
1343
  mode did NOT apply (every row of the fixes table that is not `✅ applied`):
1326
1344
  an applied fix is gone from the code the bots read, so they cannot raise it,
1327
1345
  and recording it would sink precision for doing exactly what branch mode is
1328
1346
  for. Build `<scratchpad>/unfixed.json` (a bare array is fine) from the merged
1329
1347
  `findings.json` minus the findings fix mode applied; when fix mode did not
1330
- run or applied nothing, it is the whole merged set. Take
1331
- `PREDICTED_AT=$(date -u +%Y-%m-%dT%H:%M:%SZ)` just BEFORE `gh pr create`, so
1332
- a bot comment that lands before the record step still counts:
1348
+ run or applied nothing, it is the whole merged set. Keep the timestamp captured
1349
+ before the push; do not replace it at the record step:
1333
1350
 
1334
1351
  ```bash
1335
1352
  node ${SKILL_ROOT}/scripts/bot-precision.mjs record \
1336
- --repo "$repo_slug" --pr <NEW_PR_NUMBER> --predicted <scratchpad>/unfixed.json \
1353
+ --repo "$repo_slug" --pr <PR_NUMBER> --predicted <scratchpad>/unfixed.json \
1337
1354
  --at "$PREDICTED_AT"
1338
1355
  ```
1339
1356
 
1340
1357
  The review is already saved locally; offer `--post` on the new PR number only if the user asks - findings that fix
1341
1358
  mode already applied must never be posted as review comments.
1342
1359
  - **Push only:** `git push -u origin "$local_branch"` and stop. Say in one line
1343
- that no PR was created.
1360
+ that no PR was created. Keep any eligible pre-push receipt for publication
1361
+ when a matching PR is later created; no PR means no label yet.
1344
1362
  - **No:** stop. Print the branch name and the review file path.
1345
1363
 
1346
1364
  **Unattended runs never ask and never create a PR** (see the operating contract
@@ -0,0 +1,94 @@
1
+ # Reviewed before push
2
+
3
+ `reviewed-before-push` records a completed local branch review of the current
4
+ PR head. It is informational: it does not satisfy CI, required remote review,
5
+ or the human-review marker for risky changes. The review comment records the
6
+ full head/base SHAs, engine, depth, timestamp, and result. It is an attestation
7
+ by the publishing user, not cryptographic proof that review preceded a push.
8
+
9
+ ## Install stale-label cleanup once per repository
10
+
11
+ Copy `references/reviewed-before-push.yml` into the target repository as
12
+ `.github/workflows/reviewed-before-push.yml` and land it on the default branch
13
+ through that repository's normal review process. Do this before the local
14
+ review whose receipt will be published. Do not add a workflow commit after
15
+ review and then label that unreviewed commit.
16
+
17
+ The workflow uses only GitHub API data, with no PR checkout. On new commits or
18
+ receipt edits/deletion it removes the label unless a receipt from an owner,
19
+ member, or collaborator matches the live head. Pagination includes all receipt
20
+ comments. It does not add labels or replace merge gates. A newly reviewed head
21
+ can be labeled again by the publisher. Cleanup is asynchronous; the label is
22
+ not a merge-authorization signal. Workflows disabled by repository policy or
23
+ Actions outages can delay removal.
24
+
25
+ The helper refuses to publish if the cleanup workflow is absent. If setup is
26
+ missing, keep the local review and PR creation successful, omit the label, and
27
+ report the missing setup. Never silently install a write-capable workflow in
28
+ another repository. A push-only run keeps the receipt locally until a PR exists.
29
+
30
+ ## Record before pushing
31
+
32
+ Only in `MODE=branch`, after the review engine completed without degraded or
33
+ missing required dimensions, settle every Critical/Important finding. Either
34
+ fix it with verifier/test evidence or explicitly rebut it with a reason. Open
35
+ observations may remain. A file containing only a review path or a SHA marker
36
+ is not sufficient evidence.
37
+
38
+ Save `<scratchpad>/pre-push-review.json` before the push:
39
+
40
+ ```json
41
+ {
42
+ "version": 1,
43
+ "mode": "branch",
44
+ "result": "passed",
45
+ "headSha": "<full reviewed final local HEAD>",
46
+ "baseSha": "<full merge-base used by this review>",
47
+ "engine": "codex",
48
+ "depth": "medium",
49
+ "reviewedAt": "<UTC ISO timestamp when this review completed>",
50
+ "findings": [
51
+ {
52
+ "severity": "important",
53
+ "disposition": "fixed",
54
+ "evidence": "<actual fix verification and relevant test result>"
55
+ }
56
+ ]
57
+ }
58
+ ```
59
+
60
+ Use an empty `findings` array when the review found nothing. Otherwise include
61
+ every finding in the merged review and lint set. Allowed dispositions are
62
+ `fixed`, `rebutted`, and `open`; `open` is permitted only for observations and
63
+ idiomatic suggestions. Rebuttals require specific evidence too. Set engine and
64
+ depth to the values actually used. Keep the saved full review locally; finding
65
+ text, evidence text, and local paths are not uploaded by the helper.
66
+
67
+ `reviewedAt` must be a valid UTC ISO timestamp in `YYYY-MM-DDTHH:mm:ssZ`
68
+ format, optionally with fractional seconds before `Z` (for example,
69
+ `2026-10-29T09:00:00.123Z`). Date-only strings, timezone offsets, and invalid
70
+ calendar dates are rejected by the publisher and cleanup workflow.
71
+
72
+ After fixes, the receipt must describe the final SHA: fix verification and
73
+ relevant tests must pass, and the only intervening edits must be those verified
74
+ fixes. Any unrelated edit requires a fresh review. Never copy a receipt to a
75
+ new SHA just to make the label apply.
76
+
77
+ ## Publish after pushing and creating or locating the PR
78
+
79
+ Resolve the helper relative to the selected `SKILL.md` (same directory's
80
+ `scripts/review-label.mjs`, including in Codex). Invoke with separate process
81
+ arguments, or independently shell-quote each value:
82
+
83
+ ```bash
84
+ node "<SKILL_ROOT>/scripts/review-label.mjs" \
85
+ --repo "<owner/repo>" --pr "<number>" \
86
+ --receipt "<scratchpad>/pre-push-review.json"
87
+ ```
88
+
89
+ The helper checks the live open PR head, posts the receipt, creates the label
90
+ if needed, and applies it. It checks the head before and after labeling, and
91
+ removes the label if a concurrent push changed the head. Errors are failures
92
+ to publish the label, not a failed local review. Do not claim the label was
93
+ applied when the helper failed. Do not use this helper for a review performed
94
+ in `MODE=pr` after pushing.
@@ -0,0 +1,57 @@
1
+ # Install this file on the target repository's default branch as
2
+ # .github/workflows/reviewed-before-push.yml before publishing review labels.
3
+ name: Reviewed before push
4
+ on:
5
+ pull_request_target:
6
+ types: [opened, reopened, synchronize, edited, labeled]
7
+ issue_comment:
8
+ types: [created, edited, deleted]
9
+ permissions:
10
+ contents: read
11
+ issues: write
12
+ pull-requests: read
13
+ concurrency:
14
+ group: reviewed-before-push-${{ github.event.pull_request.number || github.event.issue.number }}
15
+ cancel-in-progress: false
16
+ jobs:
17
+ reconcile:
18
+ if: github.event.pull_request || github.event.issue.pull_request
19
+ runs-on: ubuntu-latest
20
+ steps:
21
+ # No checkout: never execute code from the PR with this write token.
22
+ - uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0
23
+ with:
24
+ script: |
25
+ const label = 'reviewed-before-push';
26
+ function isUtcTimestamp(value) {
27
+ const match = typeof value === 'string' && value.match(/^(\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2})(?:\.(\d+))?Z$/);
28
+ if (!match || match[0] !== value) return false;
29
+ const time = Date.parse(value);
30
+ const canonical = `${match[1]}.${(match[2] || '').padEnd(3, '0').slice(0, 3)}Z`;
31
+ return Number.isFinite(time) && new Date(time).toISOString() === canonical;
32
+ }
33
+ const { owner, repo } = context.repo;
34
+ const issue_number = context.payload.pull_request?.number || context.payload.issue.number;
35
+ const { data: pr } = await github.rest.pulls.get({ owner, repo, pull_number: issue_number });
36
+ if (!pr.labels.some(item => item.name === label)) return;
37
+ const comments = await github.paginate(github.rest.issues.listComments, { owner, repo, issue_number, per_page: 100 });
38
+ const valid = comments.some(comment => {
39
+ if (!['OWNER', 'MEMBER', 'COLLABORATOR'].includes(comment.author_association)) return false;
40
+ const match = comment.body?.match(/<!-- lekker:reviewed-before-push (\{[^\n]*\}) -->/);
41
+ if (!match) return false;
42
+ try {
43
+ const r = JSON.parse(match[1]);
44
+ return r.version === 1 && r.mode === 'branch' && r.result === 'passed'
45
+ && r.headSha === pr.head.sha && /^[a-f0-9]{40}$/.test(r.baseSha)
46
+ && ['workflow', 'codex', 'revmux'].includes(r.engine)
47
+ && ['scan', 'medium', 'deep', 'deps'].includes(r.depth)
48
+ && isUtcTimestamp(r.reviewedAt);
49
+ } catch { return false; }
50
+ });
51
+ if (!valid) {
52
+ try {
53
+ await github.rest.issues.removeLabel({ owner, repo, issue_number, name: label });
54
+ } catch (error) {
55
+ if (error.status !== 404) throw error;
56
+ }
57
+ }
@@ -0,0 +1,90 @@
1
+ #!/usr/bin/env node
2
+ // Publish a local branch-review receipt using gh; PR-controlled values never enter shell source.
3
+ import { execFileSync } from 'node:child_process';
4
+ import { readFileSync } from 'node:fs';
5
+ import { fileURLToPath } from 'node:url';
6
+
7
+ export const LABEL = 'reviewed-before-push';
8
+ export const PREFIX = '<!-- lekker:reviewed-before-push ';
9
+ const SHA = /^[a-f0-9]{40}$/;
10
+
11
+ function isUtcTimestamp(value) {
12
+ const match = typeof value === 'string' && value.match(/^(\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2})(?:\.(\d+))?Z$/);
13
+ if (!match || match[0] !== value) return false;
14
+ const time = Date.parse(value);
15
+ const canonical = `${match[1]}.${(match[2] || '').padEnd(3, '0').slice(0, 3)}Z`;
16
+ return Number.isFinite(time) && new Date(time).toISOString() === canonical;
17
+ }
18
+
19
+ export function validateReceipt(receipt) {
20
+ if (receipt?.version !== 1 || receipt.mode !== 'branch' || receipt.result !== 'passed'
21
+ || !SHA.test(receipt.headSha) || !SHA.test(receipt.baseSha)
22
+ || !['workflow', 'codex', 'revmux'].includes(receipt.engine)
23
+ || !['scan', 'medium', 'deep', 'deps'].includes(receipt.depth)
24
+ || !isUtcTimestamp(receipt.reviewedAt)
25
+ || !Array.isArray(receipt.findings)) {
26
+ throw new Error('Invalid branch-review receipt');
27
+ }
28
+ for (const finding of receipt.findings) {
29
+ if (!['critical', 'important', 'observation', 'idiomatic'].includes(finding.severity)
30
+ || !['fixed', 'rebutted', 'open'].includes(finding.disposition)
31
+ || (['critical', 'important'].includes(finding.severity) && finding.disposition === 'open')
32
+ || (['fixed', 'rebutted'].includes(finding.disposition) && !finding.evidence?.trim())) {
33
+ throw new Error('Findings require dispositions and evidence; no open Critical/Important finding is allowed');
34
+ }
35
+ }
36
+ return receipt;
37
+ }
38
+
39
+ export function reviewComment(receipt) {
40
+ validateReceipt(receipt);
41
+ // Only publish the attestation, not local paths or potentially sensitive finding text.
42
+ const { version, mode, result, headSha, baseSha, engine, depth, reviewedAt } = receipt;
43
+ const attestation = { version, mode, result, headSha, baseSha, engine, depth, reviewedAt };
44
+ return `Reviewed before push\n\nCommit: \`${headSha}\`\nBase: \`${baseSha}\`\nEngine: ${engine}\nDepth: ${depth}\nReviewed at: ${reviewedAt}\nResult: passed; no unresolved Critical/Important findings.\n\nThis records a local review; required CI and remote review gates still apply.\n\n${PREFIX}${JSON.stringify(attestation)} -->`;
45
+ }
46
+
47
+ export function publishReview({ repo, pr, receipt }, run = execFileSync) {
48
+ if (!/^[\w.-]+\/[\w.-]+$/.test(repo) || !/^[1-9]\d*$/.test(String(pr))) {
49
+ throw new Error('Expected --repo owner/repo and a positive --pr number');
50
+ }
51
+ const body = reviewComment(receipt);
52
+ const gh = (args, input) => run('gh', args, { encoding: 'utf8', input });
53
+ const readHead = () => JSON.parse(gh(['pr', 'view', String(pr), '--repo', repo, '--json', 'headRefOid,state']));
54
+ const ensureCurrent = () => {
55
+ const current = readHead();
56
+ if (current.state !== 'OPEN' || current.headRefOid !== receipt.headSha) {
57
+ throw new Error('PR is closed or its head differs from the reviewed commit; label withheld');
58
+ }
59
+ };
60
+ ensureCurrent();
61
+ // The installation is explicit: do not silently add a privileged workflow to someone else's repo.
62
+ gh(['api', `repos/${repo}/contents/.github/workflows/reviewed-before-push.yml`]);
63
+ gh(['api', '--method', 'POST', `repos/${repo}/issues/${pr}/comments`, '--input', '-'], JSON.stringify({ body }));
64
+ gh(['label', 'create', LABEL, '--repo', repo, '--color', '0E8A16', '--description', 'Local review completed for the current PR head before push', '--force']);
65
+ ensureCurrent();
66
+ gh(['pr', 'edit', String(pr), '--repo', repo, '--add-label', LABEL]);
67
+ // Catch a concurrent push after adding the label. The workflow also reconciles later pushes.
68
+ try {
69
+ ensureCurrent();
70
+ } catch (error) {
71
+ gh(['pr', 'edit', String(pr), '--repo', repo, '--remove-label', LABEL]);
72
+ throw error;
73
+ }
74
+ return { label: LABEL, headSha: receipt.headSha };
75
+ }
76
+
77
+ function main(argv) {
78
+ const options = {};
79
+ for (let i = 0; i < argv.length; i += 2) {
80
+ if (!['--repo', '--pr', '--receipt'].includes(argv[i]) || !argv[i + 1] || options[argv[i]]) {
81
+ throw new Error('Usage: review-label.mjs --repo owner/repo --pr N --receipt receipt.json');
82
+ }
83
+ options[argv[i]] = argv[i + 1];
84
+ }
85
+ if (!options['--receipt']) throw new Error('--receipt is required');
86
+ const receipt = JSON.parse(readFileSync(options['--receipt'], 'utf8'));
87
+ console.log(JSON.stringify(publishReview({ repo: options['--repo'], pr: options['--pr'], receipt })));
88
+ }
89
+
90
+ if (process.argv[1] === fileURLToPath(import.meta.url)) main(process.argv.slice(2));
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@olegkoval/agent-skills",
3
- "version": "1.67.0",
3
+ "version": "1.68.0",
4
4
  "private": false,
5
5
  "publishConfig": {
6
6
  "access": "public"
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "olko-apple-kit",
3
3
  "description": "Build and ship Apple platform apps: macOS menubar apps, App Store submissions.",
4
- "version": "1.67.0",
4
+ "version": "1.68.0",
5
5
  "author": {
6
6
  "name": "Oleg Koval"
7
7
  },
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "olko-creative",
3
3
  "description": "Creative and personal projects: photo galleries, music players, listings, wiki editing.",
4
- "version": "1.67.0",
4
+ "version": "1.68.0",
5
5
  "author": {
6
6
  "name": "Oleg Koval"
7
7
  },
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "olko-garmin-kit",
3
3
  "description": "Build, test and publish Garmin Connect IQ watch faces.",
4
- "version": "1.67.0",
4
+ "version": "1.68.0",
5
5
  "author": {
6
6
  "name": "Oleg Koval"
7
7
  },
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "olko-git-tools",
3
3
  "description": "Everyday git and GitHub CLI operations: conventional commits, branch hygiene.",
4
- "version": "1.67.0",
4
+ "version": "1.68.0",
5
5
  "author": {
6
6
  "name": "Oleg Koval"
7
7
  },
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "olko-github-pr",
3
3
  "description": "Drive GitHub pull requests to merge-ready: review-bot loops, CI fixes, descriptions, dependency triage.",
4
- "version": "1.67.0",
4
+ "version": "1.68.0",
5
5
  "author": {
6
6
  "name": "Oleg Koval"
7
7
  },
@@ -60,3 +60,13 @@ the diff touches migrations or `*.sql`, `medium` otherwise.
60
60
 
61
61
  The posters are self-contained HTML in `assets/`. Open either file in a browser
62
62
  at a 1280x720 viewport and screenshot it to regenerate the PNG.
63
+
64
+ ## Pre-push review label
65
+
66
+ Branch-mode reviews can apply `reviewed-before-push` after pushing and opening
67
+ or locating the PR. A comment records the reviewed commit, engine, depth, and
68
+ result; unresolved Critical/Important findings prevent labeling. Install the
69
+ [cleanup workflow](references/reviewed-before-push.yml) on the target repo's
70
+ default branch first so new, unreviewed commits lose the label. See the
71
+ [receipt and setup procedure](references/reviewed-before-push.md). This label
72
+ provides visibility and does not replace required remote review or CI.
@@ -1138,8 +1138,17 @@ printf '%s\n' "$REVIEW_FILE" > ~/.cache/lekker-review/reviewed/<headSha>
1138
1138
  ```
1139
1139
 
1140
1140
  Write it against the sha that was actually reviewed. When fix mode later adds
1141
- commits, write a marker for the NEW head sha too - a gate keys on the tip
1142
- that is about to be pushed, and a marker for a superseded sha would be a lie.
1141
+ commits, write a marker for the new head only after fix verification and
1142
+ relevant tests pass. Any unrelated edits require a fresh review; never copy a
1143
+ marker to an unreviewed SHA.
1144
+
1145
+ **PR label for branch reviews:** follow `references/reviewed-before-push.md`.
1146
+ After a complete, non-degraded local review and settling all Critical/Important
1147
+ findings, save the final-head receipt as `<scratchpad>/pre-push-review.json`
1148
+ BEFORE pushing. That reference defines the receipt schema and one-time cleanup
1149
+ workflow setup. The label is exactly `reviewed-before-push` (no AI prefix).
1150
+ A legacy SHA/path marker alone does not qualify. PR-mode reviews cannot earn
1151
+ this label.
1143
1152
 
1144
1153
  **Close the run log** right after the receipt, then print the review:
1145
1154
 
@@ -1313,33 +1322,42 @@ Ask once, via AskUserQuestion:
1313
1322
 
1314
1323
  Rules for each answer:
1315
1324
 
1316
- - **Yes:** push with `git push -u origin "$local_branch"`, then create the PR
1325
+ - **Yes:** set `PREDICTED_AT=$(date -u +%Y-%m-%dT%H:%M:%SZ)` before pushing
1326
+ or publishing, including when a PR already exists. Then push with
1327
+ `git push -u origin "$local_branch"` and create or locate the PR. Create it
1317
1328
  with `gh pr create --repo "$repo_slug" --base "$base_ref" --head
1318
1329
  "$local_branch" --title "$pr_title" --body-file "$pr_body_file"`. Derive the title
1319
1330
  from the commit log (the recommended prefix plus a summary of the change) and
1320
1331
  the body from a short summary of what the branch does - do not leave either
1321
- as a placeholder. Report the PR url. Then record the prediction against the
1322
- new PR number - a branch-mode review is the ideal case for this, because the
1323
- prediction provably predates every bot comment. Record only the findings fix
1332
+ as a placeholder. Report the PR url. If an eligible pre-push receipt was
1333
+ saved, publish it using `scripts/review-label.mjs` as described in
1334
+ `references/reviewed-before-push.md`. This posts the commit/engine/depth/result
1335
+ evidence and applies `reviewed-before-push` only to the matching live head.
1336
+ If cleanup is not installed, omit the label and report the setup requirement;
1337
+ do not undo the successful PR creation. For an existing PR found after a
1338
+ branch-mode push, use the same helper and head check. Then record the prediction
1339
+ against the created or existing PR number using the saved `PREDICTED_AT`;
1340
+ scoring uses it to include bot comments triggered by the push or PR creation,
1341
+ even if they arrive before the record step. Record only the findings fix
1324
1342
  mode did NOT apply (every row of the fixes table that is not `✅ applied`):
1325
1343
  an applied fix is gone from the code the bots read, so they cannot raise it,
1326
1344
  and recording it would sink precision for doing exactly what branch mode is
1327
1345
  for. Build `<scratchpad>/unfixed.json` (a bare array is fine) from the merged
1328
1346
  `findings.json` minus the findings fix mode applied; when fix mode did not
1329
- run or applied nothing, it is the whole merged set. Take
1330
- `PREDICTED_AT=$(date -u +%Y-%m-%dT%H:%M:%SZ)` just BEFORE `gh pr create`, so
1331
- a bot comment that lands before the record step still counts:
1347
+ run or applied nothing, it is the whole merged set. Keep the timestamp captured
1348
+ before the push; do not replace it at the record step:
1332
1349
 
1333
1350
  ```bash
1334
1351
  node ${SKILL_ROOT}/scripts/bot-precision.mjs record \
1335
- --repo "$repo_slug" --pr <NEW_PR_NUMBER> --predicted <scratchpad>/unfixed.json \
1352
+ --repo "$repo_slug" --pr <PR_NUMBER> --predicted <scratchpad>/unfixed.json \
1336
1353
  --at "$PREDICTED_AT"
1337
1354
  ```
1338
1355
 
1339
1356
  The review is already saved locally; offer `--post` on the new PR number only if the user asks - findings that fix
1340
1357
  mode already applied must never be posted as review comments.
1341
1358
  - **Push only:** `git push -u origin "$local_branch"` and stop. Say in one line
1342
- that no PR was created.
1359
+ that no PR was created. Keep any eligible pre-push receipt for publication
1360
+ when a matching PR is later created; no PR means no label yet.
1343
1361
  - **No:** stop. Print the branch name and the review file path.
1344
1362
 
1345
1363
  **Unattended runs never ask and never create a PR** (see the operating contract
@@ -0,0 +1,94 @@
1
+ # Reviewed before push
2
+
3
+ `reviewed-before-push` records a completed local branch review of the current
4
+ PR head. It is informational: it does not satisfy CI, required remote review,
5
+ or the human-review marker for risky changes. The review comment records the
6
+ full head/base SHAs, engine, depth, timestamp, and result. It is an attestation
7
+ by the publishing user, not cryptographic proof that review preceded a push.
8
+
9
+ ## Install stale-label cleanup once per repository
10
+
11
+ Copy `references/reviewed-before-push.yml` into the target repository as
12
+ `.github/workflows/reviewed-before-push.yml` and land it on the default branch
13
+ through that repository's normal review process. Do this before the local
14
+ review whose receipt will be published. Do not add a workflow commit after
15
+ review and then label that unreviewed commit.
16
+
17
+ The workflow uses only GitHub API data, with no PR checkout. On new commits or
18
+ receipt edits/deletion it removes the label unless a receipt from an owner,
19
+ member, or collaborator matches the live head. Pagination includes all receipt
20
+ comments. It does not add labels or replace merge gates. A newly reviewed head
21
+ can be labeled again by the publisher. Cleanup is asynchronous; the label is
22
+ not a merge-authorization signal. Workflows disabled by repository policy or
23
+ Actions outages can delay removal.
24
+
25
+ The helper refuses to publish if the cleanup workflow is absent. If setup is
26
+ missing, keep the local review and PR creation successful, omit the label, and
27
+ report the missing setup. Never silently install a write-capable workflow in
28
+ another repository. A push-only run keeps the receipt locally until a PR exists.
29
+
30
+ ## Record before pushing
31
+
32
+ Only in `MODE=branch`, after the review engine completed without degraded or
33
+ missing required dimensions, settle every Critical/Important finding. Either
34
+ fix it with verifier/test evidence or explicitly rebut it with a reason. Open
35
+ observations may remain. A file containing only a review path or a SHA marker
36
+ is not sufficient evidence.
37
+
38
+ Save `<scratchpad>/pre-push-review.json` before the push:
39
+
40
+ ```json
41
+ {
42
+ "version": 1,
43
+ "mode": "branch",
44
+ "result": "passed",
45
+ "headSha": "<full reviewed final local HEAD>",
46
+ "baseSha": "<full merge-base used by this review>",
47
+ "engine": "codex",
48
+ "depth": "medium",
49
+ "reviewedAt": "<UTC ISO timestamp when this review completed>",
50
+ "findings": [
51
+ {
52
+ "severity": "important",
53
+ "disposition": "fixed",
54
+ "evidence": "<actual fix verification and relevant test result>"
55
+ }
56
+ ]
57
+ }
58
+ ```
59
+
60
+ Use an empty `findings` array when the review found nothing. Otherwise include
61
+ every finding in the merged review and lint set. Allowed dispositions are
62
+ `fixed`, `rebutted`, and `open`; `open` is permitted only for observations and
63
+ idiomatic suggestions. Rebuttals require specific evidence too. Set engine and
64
+ depth to the values actually used. Keep the saved full review locally; finding
65
+ text, evidence text, and local paths are not uploaded by the helper.
66
+
67
+ `reviewedAt` must be a valid UTC ISO timestamp in `YYYY-MM-DDTHH:mm:ssZ`
68
+ format, optionally with fractional seconds before `Z` (for example,
69
+ `2026-10-29T09:00:00.123Z`). Date-only strings, timezone offsets, and invalid
70
+ calendar dates are rejected by the publisher and cleanup workflow.
71
+
72
+ After fixes, the receipt must describe the final SHA: fix verification and
73
+ relevant tests must pass, and the only intervening edits must be those verified
74
+ fixes. Any unrelated edit requires a fresh review. Never copy a receipt to a
75
+ new SHA just to make the label apply.
76
+
77
+ ## Publish after pushing and creating or locating the PR
78
+
79
+ Resolve the helper relative to the selected `SKILL.md` (same directory's
80
+ `scripts/review-label.mjs`, including in Codex). Invoke with separate process
81
+ arguments, or independently shell-quote each value:
82
+
83
+ ```bash
84
+ node "<SKILL_ROOT>/scripts/review-label.mjs" \
85
+ --repo "<owner/repo>" --pr "<number>" \
86
+ --receipt "<scratchpad>/pre-push-review.json"
87
+ ```
88
+
89
+ The helper checks the live open PR head, posts the receipt, creates the label
90
+ if needed, and applies it. It checks the head before and after labeling, and
91
+ removes the label if a concurrent push changed the head. Errors are failures
92
+ to publish the label, not a failed local review. Do not claim the label was
93
+ applied when the helper failed. Do not use this helper for a review performed
94
+ in `MODE=pr` after pushing.
@@ -0,0 +1,57 @@
1
+ # Install this file on the target repository's default branch as
2
+ # .github/workflows/reviewed-before-push.yml before publishing review labels.
3
+ name: Reviewed before push
4
+ on:
5
+ pull_request_target:
6
+ types: [opened, reopened, synchronize, edited, labeled]
7
+ issue_comment:
8
+ types: [created, edited, deleted]
9
+ permissions:
10
+ contents: read
11
+ issues: write
12
+ pull-requests: read
13
+ concurrency:
14
+ group: reviewed-before-push-${{ github.event.pull_request.number || github.event.issue.number }}
15
+ cancel-in-progress: false
16
+ jobs:
17
+ reconcile:
18
+ if: github.event.pull_request || github.event.issue.pull_request
19
+ runs-on: ubuntu-latest
20
+ steps:
21
+ # No checkout: never execute code from the PR with this write token.
22
+ - uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0
23
+ with:
24
+ script: |
25
+ const label = 'reviewed-before-push';
26
+ function isUtcTimestamp(value) {
27
+ const match = typeof value === 'string' && value.match(/^(\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2})(?:\.(\d+))?Z$/);
28
+ if (!match || match[0] !== value) return false;
29
+ const time = Date.parse(value);
30
+ const canonical = `${match[1]}.${(match[2] || '').padEnd(3, '0').slice(0, 3)}Z`;
31
+ return Number.isFinite(time) && new Date(time).toISOString() === canonical;
32
+ }
33
+ const { owner, repo } = context.repo;
34
+ const issue_number = context.payload.pull_request?.number || context.payload.issue.number;
35
+ const { data: pr } = await github.rest.pulls.get({ owner, repo, pull_number: issue_number });
36
+ if (!pr.labels.some(item => item.name === label)) return;
37
+ const comments = await github.paginate(github.rest.issues.listComments, { owner, repo, issue_number, per_page: 100 });
38
+ const valid = comments.some(comment => {
39
+ if (!['OWNER', 'MEMBER', 'COLLABORATOR'].includes(comment.author_association)) return false;
40
+ const match = comment.body?.match(/<!-- lekker:reviewed-before-push (\{[^\n]*\}) -->/);
41
+ if (!match) return false;
42
+ try {
43
+ const r = JSON.parse(match[1]);
44
+ return r.version === 1 && r.mode === 'branch' && r.result === 'passed'
45
+ && r.headSha === pr.head.sha && /^[a-f0-9]{40}$/.test(r.baseSha)
46
+ && ['workflow', 'codex', 'revmux'].includes(r.engine)
47
+ && ['scan', 'medium', 'deep', 'deps'].includes(r.depth)
48
+ && isUtcTimestamp(r.reviewedAt);
49
+ } catch { return false; }
50
+ });
51
+ if (!valid) {
52
+ try {
53
+ await github.rest.issues.removeLabel({ owner, repo, issue_number, name: label });
54
+ } catch (error) {
55
+ if (error.status !== 404) throw error;
56
+ }
57
+ }
@@ -0,0 +1,90 @@
1
+ #!/usr/bin/env node
2
+ // Publish a local branch-review receipt using gh; PR-controlled values never enter shell source.
3
+ import { execFileSync } from 'node:child_process';
4
+ import { readFileSync } from 'node:fs';
5
+ import { fileURLToPath } from 'node:url';
6
+
7
+ export const LABEL = 'reviewed-before-push';
8
+ export const PREFIX = '<!-- lekker:reviewed-before-push ';
9
+ const SHA = /^[a-f0-9]{40}$/;
10
+
11
+ function isUtcTimestamp(value) {
12
+ const match = typeof value === 'string' && value.match(/^(\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2})(?:\.(\d+))?Z$/);
13
+ if (!match || match[0] !== value) return false;
14
+ const time = Date.parse(value);
15
+ const canonical = `${match[1]}.${(match[2] || '').padEnd(3, '0').slice(0, 3)}Z`;
16
+ return Number.isFinite(time) && new Date(time).toISOString() === canonical;
17
+ }
18
+
19
+ export function validateReceipt(receipt) {
20
+ if (receipt?.version !== 1 || receipt.mode !== 'branch' || receipt.result !== 'passed'
21
+ || !SHA.test(receipt.headSha) || !SHA.test(receipt.baseSha)
22
+ || !['workflow', 'codex', 'revmux'].includes(receipt.engine)
23
+ || !['scan', 'medium', 'deep', 'deps'].includes(receipt.depth)
24
+ || !isUtcTimestamp(receipt.reviewedAt)
25
+ || !Array.isArray(receipt.findings)) {
26
+ throw new Error('Invalid branch-review receipt');
27
+ }
28
+ for (const finding of receipt.findings) {
29
+ if (!['critical', 'important', 'observation', 'idiomatic'].includes(finding.severity)
30
+ || !['fixed', 'rebutted', 'open'].includes(finding.disposition)
31
+ || (['critical', 'important'].includes(finding.severity) && finding.disposition === 'open')
32
+ || (['fixed', 'rebutted'].includes(finding.disposition) && !finding.evidence?.trim())) {
33
+ throw new Error('Findings require dispositions and evidence; no open Critical/Important finding is allowed');
34
+ }
35
+ }
36
+ return receipt;
37
+ }
38
+
39
+ export function reviewComment(receipt) {
40
+ validateReceipt(receipt);
41
+ // Only publish the attestation, not local paths or potentially sensitive finding text.
42
+ const { version, mode, result, headSha, baseSha, engine, depth, reviewedAt } = receipt;
43
+ const attestation = { version, mode, result, headSha, baseSha, engine, depth, reviewedAt };
44
+ return `Reviewed before push\n\nCommit: \`${headSha}\`\nBase: \`${baseSha}\`\nEngine: ${engine}\nDepth: ${depth}\nReviewed at: ${reviewedAt}\nResult: passed; no unresolved Critical/Important findings.\n\nThis records a local review; required CI and remote review gates still apply.\n\n${PREFIX}${JSON.stringify(attestation)} -->`;
45
+ }
46
+
47
+ export function publishReview({ repo, pr, receipt }, run = execFileSync) {
48
+ if (!/^[\w.-]+\/[\w.-]+$/.test(repo) || !/^[1-9]\d*$/.test(String(pr))) {
49
+ throw new Error('Expected --repo owner/repo and a positive --pr number');
50
+ }
51
+ const body = reviewComment(receipt);
52
+ const gh = (args, input) => run('gh', args, { encoding: 'utf8', input });
53
+ const readHead = () => JSON.parse(gh(['pr', 'view', String(pr), '--repo', repo, '--json', 'headRefOid,state']));
54
+ const ensureCurrent = () => {
55
+ const current = readHead();
56
+ if (current.state !== 'OPEN' || current.headRefOid !== receipt.headSha) {
57
+ throw new Error('PR is closed or its head differs from the reviewed commit; label withheld');
58
+ }
59
+ };
60
+ ensureCurrent();
61
+ // The installation is explicit: do not silently add a privileged workflow to someone else's repo.
62
+ gh(['api', `repos/${repo}/contents/.github/workflows/reviewed-before-push.yml`]);
63
+ gh(['api', '--method', 'POST', `repos/${repo}/issues/${pr}/comments`, '--input', '-'], JSON.stringify({ body }));
64
+ gh(['label', 'create', LABEL, '--repo', repo, '--color', '0E8A16', '--description', 'Local review completed for the current PR head before push', '--force']);
65
+ ensureCurrent();
66
+ gh(['pr', 'edit', String(pr), '--repo', repo, '--add-label', LABEL]);
67
+ // Catch a concurrent push after adding the label. The workflow also reconciles later pushes.
68
+ try {
69
+ ensureCurrent();
70
+ } catch (error) {
71
+ gh(['pr', 'edit', String(pr), '--repo', repo, '--remove-label', LABEL]);
72
+ throw error;
73
+ }
74
+ return { label: LABEL, headSha: receipt.headSha };
75
+ }
76
+
77
+ function main(argv) {
78
+ const options = {};
79
+ for (let i = 0; i < argv.length; i += 2) {
80
+ if (!['--repo', '--pr', '--receipt'].includes(argv[i]) || !argv[i + 1] || options[argv[i]]) {
81
+ throw new Error('Usage: review-label.mjs --repo owner/repo --pr N --receipt receipt.json');
82
+ }
83
+ options[argv[i]] = argv[i + 1];
84
+ }
85
+ if (!options['--receipt']) throw new Error('--receipt is required');
86
+ const receipt = JSON.parse(readFileSync(options['--receipt'], 'utf8'));
87
+ console.log(JSON.stringify(publishReview({ repo: options['--repo'], pr: options['--pr'], receipt })));
88
+ }
89
+
90
+ if (process.argv[1] === fileURLToPath(import.meta.url)) main(process.argv.slice(2));
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "olko-obsidian",
3
3
  "description": "Keep an Obsidian vault in sync with work: PR sync, task rollover, morning routine.",
4
- "version": "1.67.0",
4
+ "version": "1.68.0",
5
5
  "author": {
6
6
  "name": "Oleg Koval"
7
7
  },
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "olko-product",
3
3
  "description": "Take a product idea to a shippable build: MVP passes, full-stack scaffolds, UX/UI quality loops, launch plans.",
4
- "version": "1.67.0",
4
+ "version": "1.68.0",
5
5
  "author": {
6
6
  "name": "Oleg Koval"
7
7
  },
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "olko-reflection",
3
3
  "description": "Look back and improve: self-critique, retrospectives, performance review, rapid learning.",
4
- "version": "1.67.0",
4
+ "version": "1.68.0",
5
5
  "author": {
6
6
  "name": "Oleg Koval"
7
7
  },
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "olko-release",
3
3
  "description": "Ship a release: semantic-release setup, changelogs, store listing copy, release-day routine.",
4
- "version": "1.67.0",
4
+ "version": "1.68.0",
5
5
  "author": {
6
6
  "name": "Oleg Koval"
7
7
  },
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "olko-skill-meta",
3
3
  "description": "Author and maintain agent skills and the AI toolchain itself.",
4
- "version": "1.67.0",
4
+ "version": "1.68.0",
5
5
  "author": {
6
6
  "name": "Oleg Koval"
7
7
  },
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "olko-web-ops",
3
3
  "description": "Operate a website: WAF rules, search console audits, analytics bootstrap, docs indexes.",
4
- "version": "1.67.0",
4
+ "version": "1.68.0",
5
5
  "author": {
6
6
  "name": "Oleg Koval"
7
7
  },