@olegkoval/agent-skills 1.70.0 → 1.71.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/adapters/claude/olko-github-pr/skills/lekker-review/SKILL.md +11 -2
- package/adapters/claude/olko-github-pr/skills/lekker-review/references/agents/conventions.md +3 -0
- package/adapters/claude/olko-github-pr/skills/lekker-review/references/agents/implementation.md +3 -0
- package/adapters/claude/olko-github-pr/skills/lekker-review/references/agents/quality.md +3 -0
- package/adapters/claude/olko-github-pr/skills/lekker-review/references/agents/simplification.md +3 -0
- package/adapters/claude/olko-github-pr/skills/lekker-review/references/agents/test-quality.md +3 -0
- package/adapters/claude/olko-github-pr/skills/lekker-review/references/agents/verifier.md +28 -3
- package/adapters/claude/olko-github-pr/skills/lekker-review/scripts/fixtures/project-rules/CLAUDE.md +4 -0
- package/adapters/claude/olko-github-pr/skills/lekker-review/scripts/fixtures/project-rules/planted.diff +9 -0
- package/adapters/claude/olko-github-pr/skills/lekker-review/scripts/project-rule-findings.mjs +122 -0
- package/adapters/claude/olko-github-pr/skills/lekker-review/scripts/selftest.mjs +160 -0
- package/adapters/claude/olko-github-pr/skills/lekker-review/scripts/setup-worktree.sh +63 -5
- 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/lekker-review/SKILL.md +11 -2
- package/plugins/olko-github-pr/skills/lekker-review/references/agents/conventions.md +3 -0
- package/plugins/olko-github-pr/skills/lekker-review/references/agents/implementation.md +3 -0
- package/plugins/olko-github-pr/skills/lekker-review/references/agents/quality.md +3 -0
- package/plugins/olko-github-pr/skills/lekker-review/references/agents/simplification.md +3 -0
- package/plugins/olko-github-pr/skills/lekker-review/references/agents/test-quality.md +3 -0
- package/plugins/olko-github-pr/skills/lekker-review/references/agents/verifier.md +28 -3
- package/plugins/olko-github-pr/skills/lekker-review/scripts/fixtures/project-rules/CLAUDE.md +4 -0
- package/plugins/olko-github-pr/skills/lekker-review/scripts/fixtures/project-rules/planted.diff +9 -0
- package/plugins/olko-github-pr/skills/lekker-review/scripts/project-rule-findings.mjs +122 -0
- package/plugins/olko-github-pr/skills/lekker-review/scripts/selftest.mjs +160 -0
- package/plugins/olko-github-pr/skills/lekker-review/scripts/setup-worktree.sh +63 -5
- package/plugins/olko-github-pr/skills/lekker-review/workflow.js +62 -2
- 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
|
@@ -33,6 +33,7 @@ const FINDINGS_ARRAY_SCHEMA = {
|
|
|
33
33
|
anyOf: [
|
|
34
34
|
{ properties: { severity: { enum: ['observation', 'idiomatic'] } } },
|
|
35
35
|
{ required: ['boundary'] },
|
|
36
|
+
{ required: ['rule'], properties: { rule: { pattern: '^(PROJECT:[a-z0-9]+(-[a-z0-9]+)*|weakens-project-rule)$' } } },
|
|
36
37
|
],
|
|
37
38
|
properties: {
|
|
38
39
|
file: { type: 'string' },
|
|
@@ -44,6 +45,8 @@ const FINDINGS_ARRAY_SCHEMA = {
|
|
|
44
45
|
fix: { type: 'string' },
|
|
45
46
|
precedent: { type: 'string' },
|
|
46
47
|
rule: { type: 'string', minLength: 1, pattern: '\\S' },
|
|
48
|
+
// Verbatim project rule a PROJECT:<slug> finding enforces.
|
|
49
|
+
ruleQuote: { type: 'string' },
|
|
47
50
|
boundary: BOUNDARY_SCHEMA,
|
|
48
51
|
// Short kebab-case slug naming the class of bug ("missing-null-check").
|
|
49
52
|
bugClass: { type: 'string', minLength: 1, pattern: '^[a-z0-9]+(-[a-z0-9]+)*$' },
|
|
@@ -107,6 +110,8 @@ const VERDICT_SCHEMA = {
|
|
|
107
110
|
verdict: { enum: ['confirmed', 'downgraded', 'dropped'] },
|
|
108
111
|
newSeverity: { enum: ['important', 'observation'] },
|
|
109
112
|
reasoning: { type: 'string' },
|
|
113
|
+
// True when the PROJECT-rule validator could not run (exit other than 0 or 1).
|
|
114
|
+
validatorUnavailable: { type: 'boolean' },
|
|
110
115
|
},
|
|
111
116
|
}
|
|
112
117
|
|
|
@@ -162,6 +167,23 @@ function titleTokens(title) {
|
|
|
162
167
|
}
|
|
163
168
|
|
|
164
169
|
function sameIssue(a, b) {
|
|
170
|
+
// Lens-generated slugs can differ even when they identify the same project rule.
|
|
171
|
+
const sameProjectQuote = typeof a.rule === 'string' && a.rule.startsWith('PROJECT:')
|
|
172
|
+
&& typeof b.rule === 'string' && b.rule.startsWith('PROJECT:')
|
|
173
|
+
&& typeof a.ruleQuote === 'string' && a.ruleQuote.trim() !== ''
|
|
174
|
+
&& a.ruleQuote === b.ruleQuote
|
|
175
|
+
if (typeof a.rule === 'string' && typeof b.rule === 'string' && a.rule !== b.rule
|
|
176
|
+
&& (a.rule.startsWith('PROJECT:') || b.rule.startsWith('PROJECT:'))
|
|
177
|
+
&& !sameProjectQuote) {
|
|
178
|
+
return false
|
|
179
|
+
}
|
|
180
|
+
// Two quotes of one PROJECT rule that differ are two different rule passages, not one issue.
|
|
181
|
+
if (typeof a.rule === 'string' && a.rule === b.rule && a.rule.startsWith('PROJECT:')
|
|
182
|
+
&& typeof a.ruleQuote === 'string' && a.ruleQuote.trim() !== ''
|
|
183
|
+
&& typeof b.ruleQuote === 'string' && b.ruleQuote.trim() !== ''
|
|
184
|
+
&& a.ruleQuote !== b.ruleQuote) {
|
|
185
|
+
return false
|
|
186
|
+
}
|
|
165
187
|
// Merging two classes would send one class's instances to the other's fix.
|
|
166
188
|
if (a.bugClass && b.bugClass && a.bugClass !== b.bugClass) {
|
|
167
189
|
return false
|
|
@@ -182,6 +204,22 @@ const BUG_CLASS_INSTRUCTION = `BUG CLASS: give every finding a "bugClass" (short
|
|
|
182
204
|
+ ` hit, search the whole diff for the same pattern and list every other place as`
|
|
183
205
|
+ ` "file:line" (empty array when there is none). Report the class, not just the first hit.`
|
|
184
206
|
|
|
207
|
+
const PROJECT_RULE_DIMENSIONS = ['quality', 'implementation', 'simplification', 'conventions', 'test-quality',
|
|
208
|
+
'triage-quality', 'triage-logic']
|
|
209
|
+
|
|
210
|
+
const PROJECT_RULE_INSTRUCTION = `PROJECT RULES AS HARD RULES: read "projectRules" from CONTEXT_FILE.`
|
|
211
|
+
+ ` When a changed line violates a project rule written as a prohibition or an obligation`
|
|
212
|
+
+ ` (NEVER, MUST, MUST NOT, ALWAYS, DO NOT, or a plain-English equivalent), raise a Critical`
|
|
213
|
+
+ ` finding with "rule" set to "PROJECT:<short-kebab-slug>", "ruleQuote" set to the exact`
|
|
214
|
+
+ ` sentence from the rules (use "baseProjectRules" when it is a string: it is the base`
|
|
215
|
+
+ ` branch's copy, which the PR author cannot edit; otherwise "projectRules"), and file:line`
|
|
216
|
+
+ ` on the violating line. When the diff deletes or weakens a rule line that is in`
|
|
217
|
+
+ ` baseProjectRules, raise an Important finding with rule "weakens-project-rule" quoting`
|
|
218
|
+
+ ` the removed line. One finding per rule,`
|
|
219
|
+
+ ` with every other violating site in "otherInstances". Never quote a rule that is not in`
|
|
220
|
+
+ ` the authoritative source ("baseProjectRules" when it is a string, otherwise "projectRules"). Preferences and suggestions are not hard rules: report them as ordinary`
|
|
221
|
+
+ ` findings. A REVIEW.md ignore entry narrows where you look, it never disables a rule.`
|
|
222
|
+
|
|
185
223
|
const BUG_CLASS_PATTERN = /^[a-z0-9]+(-[a-z0-9]+)*$/
|
|
186
224
|
const INSTANCE_PATTERN = new RegExp(INSTANCE_PATTERN_SOURCE)
|
|
187
225
|
|
|
@@ -234,6 +272,14 @@ function mergeFindings(a, b) {
|
|
|
234
272
|
|
|
235
273
|
if (!merged.rule && b.rule) {
|
|
236
274
|
merged.rule = b.rule
|
|
275
|
+
if (Object.prototype.hasOwnProperty.call(b, 'ruleQuote')) {
|
|
276
|
+
merged.ruleQuote = b.ruleQuote
|
|
277
|
+
} else {
|
|
278
|
+
delete merged.ruleQuote
|
|
279
|
+
}
|
|
280
|
+
} else if (merged.rule && merged.rule === b.rule && !merged.ruleQuote
|
|
281
|
+
&& typeof b.ruleQuote === 'string' && b.ruleQuote.trim()) {
|
|
282
|
+
merged.ruleQuote = b.ruleQuote
|
|
237
283
|
}
|
|
238
284
|
|
|
239
285
|
const agreedBy = []
|
|
@@ -547,7 +593,7 @@ if (Number(cycle) >= RETHINK_CYCLE) {
|
|
|
547
593
|
recurringClasses: Array.isArray(recurringClasses) ? recurringClasses : [],
|
|
548
594
|
findings: [],
|
|
549
595
|
preExisting: [],
|
|
550
|
-
droppedCount: 0, downgradedCount: 0, hardRuleCount: 0, agentCount: 0,
|
|
596
|
+
droppedCount: 0, downgradedCount: 0, hardRuleCount: 0, validatorUnavailableCount: 0, agentCount: 0,
|
|
551
597
|
proveAttemptCount: 0, provenCount: 0, suppressedCount: 0,
|
|
552
598
|
outputTokens: 0, turnTokensTotal: budget.spent(),
|
|
553
599
|
engine: ENGINE,
|
|
@@ -562,6 +608,7 @@ const budgetAtStart = budget.spent()
|
|
|
562
608
|
let droppedCount = 0
|
|
563
609
|
let downgradedCount = 0
|
|
564
610
|
let hardRuleCount = 0
|
|
611
|
+
let validatorUnavailableCount = 0
|
|
565
612
|
let provenCount = 0
|
|
566
613
|
let suppressedCount = 0
|
|
567
614
|
let proveAttemptCount = 0
|
|
@@ -613,6 +660,10 @@ const budgetAtStart = budget.spent()
|
|
|
613
660
|
|
|
614
661
|
prompt += ' ' + BUG_CLASS_INSTRUCTION
|
|
615
662
|
|
|
663
|
+
if (PROJECT_RULE_DIMENSIONS.includes(dim.key)) {
|
|
664
|
+
prompt += ' ' + PROJECT_RULE_INSTRUCTION
|
|
665
|
+
}
|
|
666
|
+
|
|
616
667
|
// The deterministic lint pre-flight has already collected every rule the
|
|
617
668
|
// repo's own eslint config fires on this diff, and those are exactly the
|
|
618
669
|
// comments the bot reviewers bill for. An agent re-reporting them costs a
|
|
@@ -650,7 +701,7 @@ const budgetAtStart = budget.spent()
|
|
|
650
701
|
`FINDING (JSON): ${JSON.stringify(finding)}.`,
|
|
651
702
|
`DIFF_FILE=${diffFile}, CONTEXT_FILE=${contextFile}, WORKTREE_PATH=${wtDisplay}.`,
|
|
652
703
|
`HOUSE_RULES_FILE: read key "houseRulesFile" from CONTEXT_FILE, then read that exact path before validating a hard rule.`,
|
|
653
|
-
`Default to dropping when uncertain.`,
|
|
704
|
+
`Default to dropping when uncertain, except when the PROJECT-rule validator was unavailable: then check by hand that the exact quote appears in baseProjectRules when it is a string, otherwise projectRules (drop if it does not), keep the finding only if it does, set validatorUnavailable true, and judge applicability.`,
|
|
654
705
|
].join(' ')
|
|
655
706
|
}
|
|
656
707
|
|
|
@@ -708,6 +759,9 @@ const budgetAtStart = budget.spent()
|
|
|
708
759
|
// A model verdict cannot replace the required production boundary map.
|
|
709
760
|
function enforceBoundary(finding) {
|
|
710
761
|
if (!shouldVerify(finding, depth)) return finding
|
|
762
|
+
// A project rule or a weakened project rule is violated by the line itself; it needs no production entry point.
|
|
763
|
+
if (typeof finding.rule === 'string'
|
|
764
|
+
&& (finding.rule.startsWith('PROJECT:') || finding.rule === 'weakens-project-rule')) return finding
|
|
711
765
|
const boundary = finding.boundary
|
|
712
766
|
const hasText = function(value) {
|
|
713
767
|
return typeof value === 'string' && value.trim().length > 0
|
|
@@ -764,6 +818,11 @@ const budgetAtStart = budget.spent()
|
|
|
764
818
|
return kept
|
|
765
819
|
}
|
|
766
820
|
|
|
821
|
+
if (verdict.validatorUnavailable === true) {
|
|
822
|
+
validatorUnavailableCount++
|
|
823
|
+
log(`PROJECT-rule validator unavailable for ${finding.file}:${finding.line}; ${verdict.verdict === 'dropped' ? 'finding dropped' : 'finding kept'}`)
|
|
824
|
+
}
|
|
825
|
+
|
|
767
826
|
if (verdict.verdict === 'dropped') {
|
|
768
827
|
droppedCount++
|
|
769
828
|
return null
|
|
@@ -1087,6 +1146,7 @@ const budgetAtStart = budget.spent()
|
|
|
1087
1146
|
droppedCount,
|
|
1088
1147
|
downgradedCount,
|
|
1089
1148
|
hardRuleCount,
|
|
1149
|
+
validatorUnavailableCount,
|
|
1090
1150
|
agentCount,
|
|
1091
1151
|
proveAttemptCount,
|
|
1092
1152
|
provenCount,
|