@olegkoval/agent-skills 1.43.0 → 1.44.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 (49) hide show
  1. package/adapters/claude/olko-github-pr/skills/lekker-review/SKILL.md +85 -2
  2. package/adapters/claude/olko-github-pr/skills/lekker-review/references/pricing.json +9 -0
  3. package/adapters/claude/olko-github-pr/skills/lekker-review/references/revmux/lenses/lekker-conventions.md +158 -0
  4. package/adapters/claude/olko-github-pr/skills/lekker-review/references/revmux/lenses/lekker-implementation.md +76 -0
  5. package/adapters/claude/olko-github-pr/skills/lekker-review/references/revmux/lenses/lekker-quality.md +87 -0
  6. package/adapters/claude/olko-github-pr/skills/lekker-review/references/revmux/lenses/lekker-simplification.md +63 -0
  7. package/adapters/claude/olko-github-pr/skills/lekker-review/references/revmux/lenses/lekker-test-quality.md +172 -0
  8. package/adapters/claude/olko-github-pr/skills/lekker-review/references/revmux/phase4-comparison.md +42 -0
  9. package/adapters/claude/olko-github-pr/skills/lekker-review/references/revmux/profile.md +347 -0
  10. package/adapters/claude/olko-github-pr/skills/lekker-review/references/revmux/profiles/lekker-deep.md +82 -0
  11. package/adapters/claude/olko-github-pr/skills/lekker-review/references/revmux/profiles/lekker-medium.md +81 -0
  12. package/adapters/claude/olko-github-pr/skills/lekker-review/scripts/fixtures/context.json +3 -0
  13. package/adapters/claude/olko-github-pr/skills/lekker-review/scripts/fixtures/house-rules.md +11 -0
  14. package/adapters/claude/olko-github-pr/skills/lekker-review/scripts/fixtures/revmux-report.json +179 -0
  15. package/adapters/claude/olko-github-pr/skills/lekker-review/scripts/install-revmux-prompts.sh +66 -0
  16. package/adapters/claude/olko-github-pr/skills/lekker-review/scripts/revmux-adapter.mjs +261 -0
  17. package/adapters/claude/olko-github-pr/skills/lekker-review/scripts/revmux-engine.sh +156 -0
  18. package/adapters/claude/olko-github-pr/skills/lekker-review/scripts/selftest.mjs +76 -0
  19. package/package.json +1 -1
  20. package/plugins/olko-apple-kit/.claude-plugin/plugin.json +1 -1
  21. package/plugins/olko-creative/.claude-plugin/plugin.json +1 -1
  22. package/plugins/olko-garmin-kit/.claude-plugin/plugin.json +1 -1
  23. package/plugins/olko-git-tools/.claude-plugin/plugin.json +1 -1
  24. package/plugins/olko-github-pr/.claude-plugin/plugin.json +1 -1
  25. package/plugins/olko-github-pr/skills/lekker-review/SKILL.md +85 -2
  26. package/plugins/olko-github-pr/skills/lekker-review/references/pricing.json +9 -0
  27. package/plugins/olko-github-pr/skills/lekker-review/references/revmux/lenses/lekker-conventions.md +158 -0
  28. package/plugins/olko-github-pr/skills/lekker-review/references/revmux/lenses/lekker-implementation.md +76 -0
  29. package/plugins/olko-github-pr/skills/lekker-review/references/revmux/lenses/lekker-quality.md +87 -0
  30. package/plugins/olko-github-pr/skills/lekker-review/references/revmux/lenses/lekker-simplification.md +63 -0
  31. package/plugins/olko-github-pr/skills/lekker-review/references/revmux/lenses/lekker-test-quality.md +172 -0
  32. package/plugins/olko-github-pr/skills/lekker-review/references/revmux/phase4-comparison.md +42 -0
  33. package/plugins/olko-github-pr/skills/lekker-review/references/revmux/profile.md +347 -0
  34. package/plugins/olko-github-pr/skills/lekker-review/references/revmux/profiles/lekker-deep.md +82 -0
  35. package/plugins/olko-github-pr/skills/lekker-review/references/revmux/profiles/lekker-medium.md +81 -0
  36. package/plugins/olko-github-pr/skills/lekker-review/scripts/fixtures/context.json +3 -0
  37. package/plugins/olko-github-pr/skills/lekker-review/scripts/fixtures/house-rules.md +11 -0
  38. package/plugins/olko-github-pr/skills/lekker-review/scripts/fixtures/revmux-report.json +179 -0
  39. package/plugins/olko-github-pr/skills/lekker-review/scripts/install-revmux-prompts.sh +66 -0
  40. package/plugins/olko-github-pr/skills/lekker-review/scripts/revmux-adapter.mjs +261 -0
  41. package/plugins/olko-github-pr/skills/lekker-review/scripts/revmux-engine.sh +156 -0
  42. package/plugins/olko-github-pr/skills/lekker-review/scripts/selftest.mjs +76 -0
  43. package/plugins/olko-github-pr/skills/lekker-review/workflow.js +43 -6
  44. package/plugins/olko-obsidian/.claude-plugin/plugin.json +1 -1
  45. package/plugins/olko-product/.claude-plugin/plugin.json +1 -1
  46. package/plugins/olko-reflection/.claude-plugin/plugin.json +1 -1
  47. package/plugins/olko-release/.claude-plugin/plugin.json +1 -1
  48. package/plugins/olko-skill-meta/.claude-plugin/plugin.json +1 -1
  49. package/plugins/olko-web-ops/.claude-plugin/plugin.json +1 -1
@@ -183,5 +183,81 @@ if (!hasRouting) {
183
183
  }
184
184
  }
185
185
 
186
+ console.log('\nrevmux adapter: fixture mapping')
187
+ {
188
+ const { execFileSync, spawnSync } = await import('node:child_process')
189
+ const fixturePath = join(SKILL, 'scripts', 'fixtures', 'revmux-report.json')
190
+ const contextPath = join(SKILL, 'scripts', 'fixtures', 'context.json')
191
+ const pricingPath = join(SKILL, 'references', 'pricing.json')
192
+ const adapterPath = join(SKILL, 'scripts', 'revmux-adapter.mjs')
193
+ const adapterArgs = [adapterPath, fixturePath, '--pricing', pricingPath, '--context', contextPath]
194
+ const out = execFileSync('node', adapterArgs, { encoding: 'utf8' })
195
+ const adapted = JSON.parse(out)
196
+
197
+ check('engine tag', adapted.engine, 'revmux')
198
+ check('critical confirmed kept critical',
199
+ adapted.findings.some(f => f.title.includes('Race between webhook retry') && f.severity === 'critical'), true)
200
+ check('major refined -> important, agreedBy from 2 sources',
201
+ (() => {
202
+ const f = adapted.findings.find(f => f.title.includes('Discount stacking'))
203
+ return f && f.severity === 'important' && Array.isArray(f.agreedBy) && f.agreedBy.length === 2
204
+ })(), true)
205
+ check('minor + lekker-conventions lens -> idiomatic',
206
+ adapted.findings.find(f => f.title.includes('naming matrix'))?.severity, 'idiomatic')
207
+ check('immaterial verdict dropped, not re-promoted',
208
+ adapted.findings.some(f => f.title.includes('Unused import')), false)
209
+ check('rejected non-hard-rule dropped',
210
+ adapted.findings.some(f => f.title.includes('double-count a tip')), false)
211
+ check('TS-1 rejected but corroborated by quoted code IS re-promoted to critical',
212
+ (() => {
213
+ const f = adapted.findings.find(f => f.title.includes('Unsafe cast on inventory adjustment'))
214
+ return f && f.severity === 'critical' && f.rule === 'TS-1'
215
+ })(), true)
216
+ check('TS-1 rejected with no corroborating code stays dropped',
217
+ adapted.findings.some(f => f.title.includes('Type safety concern in inventory handler')), false)
218
+ check('prose without an extracted snippet leaves badCode empty',
219
+ adapted.findings.find(f => f.title.includes('no retry backoff'))?.badCode, '')
220
+ check('configured custom hard rule with quoted code is re-promoted',
221
+ adapted.findings.find(f => f.title.includes('Session token is logged'))?.severity, 'critical')
222
+ check('configured custom hard rule without quoted code stays dropped',
223
+ adapted.findings.some(f => f.title.includes('Possible session concern')), false)
224
+ check('pre_existing becomes observation with Pre-existing: prefix',
225
+ (() => {
226
+ const f = adapted.findings.find(f => f.title.includes('no retry backoff'))
227
+ return f && f.severity === 'observation' && f.description.startsWith('Pre-existing:')
228
+ })(), true)
229
+ check('open_questions pass through as questions',
230
+ adapted.questions.length, 1)
231
+ check('degraded agent surfaced by name',
232
+ adapted.degraded, ['adversarial'])
233
+ check('droppedCount counts four rejected or immaterial findings', adapted.droppedCount, 4)
234
+ check('hardRuleCount counts built-in and custom re-promotions', adapted.hardRuleCount, 2)
235
+ check('totalUsd computed from known pricing', typeof adapted.totalUsd === 'number' && adapted.totalUsd > 0, true)
236
+ check('malformed token rows do not make totalUsd NaN', Number.isFinite(adapted.totalUsd), true)
237
+ check('malformed token rows keep their own usd unknown',
238
+ adapted.agents.find(a => a.name === 'malformed-cost')?.usd, null)
239
+ check('no pricingMissing when all models are priced', adapted.pricingMissing, undefined)
240
+ check('test-quality coverage verdict is populated from attributed findings',
241
+ adapted.coverageVerdict.includes('Operator-flip mutation'), true)
242
+ check('mutation-slip summary is populated from attributed findings',
243
+ adapted.mutationSlip.includes('retry guard'), true)
244
+ check('mock smells are structured from attributed findings', adapted.mockSmells.length, 1)
245
+
246
+ const noPricingOut = execFileSync('node', [adapterPath, fixturePath, '--context', contextPath], { encoding: 'utf8' })
247
+ const noPricingAdapted = JSON.parse(noPricingOut)
248
+ check('without a pricing file every model is pricingMissing',
249
+ noPricingAdapted.pricingMissing?.includes('claude-sonnet-5'), true)
250
+ check('without a pricing file totalUsd is null', noPricingAdapted.totalUsd, null)
251
+
252
+ for (const [label, badArgs] of [
253
+ ['report', [adapterPath, join(SKILL, 'SKILL.md')]],
254
+ ['pricing', [adapterPath, fixturePath, '--pricing', join(SKILL, 'SKILL.md'), '--context', contextPath]],
255
+ ]) {
256
+ const failedRun = spawnSync('node', badArgs, { encoding: 'utf8' })
257
+ check(`invalid ${label} JSON exits 2`, failedRun.status, 2)
258
+ check(`invalid ${label} JSON has a clear error`, failedRun.stderr.includes(`${label} JSON`), true)
259
+ }
260
+ }
261
+
186
262
  console.log(failed === 0 ? '\nall checks passed\n' : `\n${failed} check(s) FAILED\n`)
187
263
  process.exit(failed === 0 ? 0 : 1)
@@ -364,8 +364,14 @@ const {
364
364
  reviewBatchPlan,
365
365
  maxConcurrent,
366
366
  targetLabel: targetLabelArg,
367
+ engine: engineArg,
368
+ findingsFile,
367
369
  } = input
368
370
 
371
+ // 'revmux' skips straight to Prove on pre-computed findings, so Prove's
372
+ // worktree/depth rules aren't duplicated in the adapter.
373
+ const ENGINE = (engineArg === 'revmux') ? 'revmux' : 'workflow'
374
+
369
375
  const targetLabel = targetLabelArg || `PR #${prNumber}`
370
376
 
371
377
  if (!repoSlug || (!prNumber && !targetLabelArg) || !depth || !diffFile || !contextFile || !promptDir) {
@@ -374,6 +380,9 @@ if (!repoSlug || (!prNumber && !targetLabelArg) || !depth || !diffFile || !conte
374
380
  '): ' + JSON.stringify({ repoSlug, prNumber, targetLabel, depth, diffFile, contextFile, promptDir })
375
381
  )
376
382
  }
383
+ if (ENGINE === 'revmux' && !findingsFile) {
384
+ throw new Error('lekker-review workflow: engine "revmux" requires findingsFile (adapter output)')
385
+ }
377
386
 
378
387
  // Concurrency. The review stage is self-limiting: five dimensions means five
379
388
  // agents, so it runs them all at once. The other stages are not. Verify,
@@ -386,7 +395,7 @@ const REVIEW_PLAN = (Array.isArray(reviewBatchPlan) && reviewBatchPlan.length >
386
395
  const FANOUT_PLAN = [Math.max(1, maxConcurrent || 5)]
387
396
  const targetMetadata = JSON.stringify({ targetLabel })
388
397
 
389
- log(`args ok: ${targetLabel} in ${repoSlug}, depth=${depth}, reviewPlan=[${REVIEW_PLAN}], fanout=${FANOUT_PLAN[0]}`)
398
+ log(`args ok: ${targetLabel} in ${repoSlug}, depth=${depth}, reviewPlan=[${REVIEW_PLAN}], fanout=${FANOUT_PLAN[0]}, engine=${ENGINE}`)
390
399
 
391
400
  const budgetAtStart = budget.spent()
392
401
 
@@ -580,6 +589,32 @@ const budgetAtStart = budget.spent()
580
589
  // contradictory verdicts) on the same issue found by two dimensions.
581
590
  // -------------------------------------------------------------------------
582
591
 
592
+ let finalFindings
593
+ let implementationResult = {}
594
+ let testQualityResult = {}
595
+ let revmuxPassthrough = null
596
+
597
+ if (ENGINE === 'revmux') {
598
+ const adapterOutput = JSON.parse(readFileSync(findingsFile, 'utf8'))
599
+ finalFindings = (adapterOutput.findings || []).map(function(f) {
600
+ return Object.assign({}, f)
601
+ })
602
+ droppedCount = adapterOutput.droppedCount || 0
603
+ hardRuleCount = adapterOutput.hardRuleCount || 0
604
+ agentCount = adapterOutput.agentCount || 0
605
+ implementationResult = adapterOutput
606
+ testQualityResult = adapterOutput
607
+ revmuxPassthrough = {
608
+ questions: adapterOutput.questions || [],
609
+ agents: adapterOutput.agents || [],
610
+ degraded: adapterOutput.degraded || [],
611
+ totalTokens: adapterOutput.totalTokens,
612
+ totalUsd: adapterOutput.totalUsd,
613
+ pricingMissing: adapterOutput.pricingMissing || [],
614
+ }
615
+ log(`revmux engine: loaded ${finalFindings.length} finding(s) from ${findingsFile} (dropped=${droppedCount}, hardRule=${hardRuleCount}); skipping Review/Verify/Critic`)
616
+ } else {
617
+
583
618
  phase('Review')
584
619
 
585
620
  log(`Review: ${dimensions.length} dimension(s) in batches of [${REVIEW_PLAN}]`)
@@ -589,10 +624,10 @@ const budgetAtStart = budget.spent()
589
624
  }), REVIEW_PLAN)
590
625
 
591
626
  const reviewResults = reviewed.filter(Boolean)
592
- const implementationResult = reviewResults.find(function(result) {
627
+ implementationResult = reviewResults.find(function(result) {
593
628
  return result.key === 'implementation'
594
629
  }) || {}
595
- const testQualityResult = reviewResults.find(function(result) {
630
+ testQualityResult = reviewResults.find(function(result) {
596
631
  return result.key === 'test-quality'
597
632
  }) || {}
598
633
  const deduped = dedup(reviewResults.flatMap(function(result) {
@@ -613,7 +648,7 @@ const budgetAtStart = budget.spent()
613
648
  // Critic (deep only)
614
649
  // -------------------------------------------------------------------------
615
650
 
616
- let finalFindings = verifiedFindings
651
+ finalFindings = verifiedFindings
617
652
 
618
653
  if (depth === 'deep') {
619
654
  phase('Critic')
@@ -712,6 +747,8 @@ const budgetAtStart = budget.spent()
712
747
  }
713
748
  }
714
749
 
750
+ } // end ENGINE === 'workflow' branch
751
+
715
752
  // -------------------------------------------------------------------------
716
753
  // Prove: for each Critical finding (excluding hard rules, which are policy
717
754
  // violations with no runtime failure to demonstrate), attempt to produce an
@@ -791,7 +828,7 @@ const budgetAtStart = budget.spent()
791
828
  return clean
792
829
  })
793
830
 
794
- return {
831
+ return Object.assign({
795
832
  findings: output,
796
833
  droppedCount,
797
834
  downgradedCount,
@@ -805,4 +842,4 @@ const budgetAtStart = budget.spent()
805
842
  mockSmells: Array.isArray(testQualityResult.mockSmells) ? testQualityResult.mockSmells : [],
806
843
  outputTokens: budget.spent() - budgetAtStart,
807
844
  turnTokensTotal: budget.spent(),
808
- }
845
+ }, Object.assign({ engine: ENGINE }, revmuxPassthrough || {}))
@@ -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.43.0",
4
+ "version": "1.44.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, launch plans.",
4
- "version": "1.43.0",
4
+ "version": "1.44.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.43.0",
4
+ "version": "1.44.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.43.0",
4
+ "version": "1.44.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.43.0",
4
+ "version": "1.44.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.43.0",
4
+ "version": "1.44.0",
5
5
  "author": {
6
6
  "name": "Oleg Koval"
7
7
  },