@olegkoval/agent-skills 1.75.0 → 1.75.1
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/scripts/eval-runner.mjs +34 -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/lekker-review/scripts/eval-runner.mjs +34 -0
- 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
|
@@ -49,6 +49,9 @@ export function caseKey(e) {
|
|
|
49
49
|
}
|
|
50
50
|
|
|
51
51
|
const SHA = /^[0-9a-f]{7,40}$/i;
|
|
52
|
+
const FULL_SHA = /^[0-9a-f]{40}$/i;
|
|
53
|
+
const RUN_ID = /^[A-Za-z0-9][A-Za-z0-9._-]*$/;
|
|
54
|
+
const SEVERITIES = new Set(['critical', 'important', 'observation', 'idiomatic']);
|
|
52
55
|
|
|
53
56
|
const isMultiRun = (v) => Array.isArray(v) && v.length > 0 && v.every(Array.isArray);
|
|
54
57
|
|
|
@@ -71,6 +74,37 @@ export function validateManifest(manifest) {
|
|
|
71
74
|
return prs;
|
|
72
75
|
}
|
|
73
76
|
|
|
77
|
+
export function normalizeArchivedEvidence(entry, run, worktree, document) {
|
|
78
|
+
const key = caseKey(entry);
|
|
79
|
+
const unscored = (reason) => ({ key, reason });
|
|
80
|
+
if (typeof entry.runId !== 'string' || !RUN_ID.test(entry.runId)) return unscored('unsafe or missing runId');
|
|
81
|
+
if (typeof entry.sha !== 'string' || !FULL_SHA.test(entry.sha)) return unscored('manifest needs a full 40-character sha');
|
|
82
|
+
if (!run) return unscored('run.json missing or malformed');
|
|
83
|
+
if (run.runId !== entry.runId) return unscored('runId mismatch');
|
|
84
|
+
if (run.status !== 'ok') return unscored('run status is not ok');
|
|
85
|
+
if (!['lgtm', 'lgtm-with-changes', 'needs-work'].includes(run.verdict)) return unscored('run verdict is missing or invalid');
|
|
86
|
+
if (run.review?.name !== 'lekker-review-core' || run.review.status !== 'completed') return unscored('completed review record unavailable');
|
|
87
|
+
if (run.repo !== entry.repo || run.target !== `pr-${entry.pr}`) return unscored('run repo or target mismatch');
|
|
88
|
+
if (!worktree) return unscored('worktree.json missing or malformed');
|
|
89
|
+
if (typeof worktree.headSha !== 'string' || !FULL_SHA.test(worktree.headSha)) return unscored('worktree headSha is not a full SHA');
|
|
90
|
+
if (worktree.headSha.toLowerCase() !== entry.sha.toLowerCase()) return unscored('worktree headSha mismatch');
|
|
91
|
+
const findings = Array.isArray(document) ? document : document?.findings;
|
|
92
|
+
if (!Array.isArray(findings)) return unscored('findings.json missing or malformed');
|
|
93
|
+
if (findings.some((f) => !f || typeof f.file !== 'string' || !f.file.trim() || !SEVERITIES.has(f.severity)
|
|
94
|
+
|| !(f.line === null || (Number.isInteger(f.line) && f.line > 0)))) {
|
|
95
|
+
return unscored('findings.json contains a malformed finding');
|
|
96
|
+
}
|
|
97
|
+
return { key, findings, reason: null };
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
// Validate archive references before reading any run directories.
|
|
101
|
+
export function validateArchiveRunIds(entries) {
|
|
102
|
+
const duplicate = entries.find((entry, index) => entry.runId
|
|
103
|
+
&& entries.slice(0, index).some(previous => previous.runId === entry.runId));
|
|
104
|
+
if (duplicate) throw new Error(`archive manifest reuses runId ${duplicate.runId}`);
|
|
105
|
+
return entries;
|
|
106
|
+
}
|
|
107
|
+
|
|
74
108
|
export function score(manifest, results) {
|
|
75
109
|
const rows = validateManifest(manifest).map((e) => {
|
|
76
110
|
const key = caseKey(e);
|
package/package.json
CHANGED
|
@@ -49,6 +49,9 @@ export function caseKey(e) {
|
|
|
49
49
|
}
|
|
50
50
|
|
|
51
51
|
const SHA = /^[0-9a-f]{7,40}$/i;
|
|
52
|
+
const FULL_SHA = /^[0-9a-f]{40}$/i;
|
|
53
|
+
const RUN_ID = /^[A-Za-z0-9][A-Za-z0-9._-]*$/;
|
|
54
|
+
const SEVERITIES = new Set(['critical', 'important', 'observation', 'idiomatic']);
|
|
52
55
|
|
|
53
56
|
const isMultiRun = (v) => Array.isArray(v) && v.length > 0 && v.every(Array.isArray);
|
|
54
57
|
|
|
@@ -71,6 +74,37 @@ export function validateManifest(manifest) {
|
|
|
71
74
|
return prs;
|
|
72
75
|
}
|
|
73
76
|
|
|
77
|
+
export function normalizeArchivedEvidence(entry, run, worktree, document) {
|
|
78
|
+
const key = caseKey(entry);
|
|
79
|
+
const unscored = (reason) => ({ key, reason });
|
|
80
|
+
if (typeof entry.runId !== 'string' || !RUN_ID.test(entry.runId)) return unscored('unsafe or missing runId');
|
|
81
|
+
if (typeof entry.sha !== 'string' || !FULL_SHA.test(entry.sha)) return unscored('manifest needs a full 40-character sha');
|
|
82
|
+
if (!run) return unscored('run.json missing or malformed');
|
|
83
|
+
if (run.runId !== entry.runId) return unscored('runId mismatch');
|
|
84
|
+
if (run.status !== 'ok') return unscored('run status is not ok');
|
|
85
|
+
if (!['lgtm', 'lgtm-with-changes', 'needs-work'].includes(run.verdict)) return unscored('run verdict is missing or invalid');
|
|
86
|
+
if (run.review?.name !== 'lekker-review-core' || run.review.status !== 'completed') return unscored('completed review record unavailable');
|
|
87
|
+
if (run.repo !== entry.repo || run.target !== `pr-${entry.pr}`) return unscored('run repo or target mismatch');
|
|
88
|
+
if (!worktree) return unscored('worktree.json missing or malformed');
|
|
89
|
+
if (typeof worktree.headSha !== 'string' || !FULL_SHA.test(worktree.headSha)) return unscored('worktree headSha is not a full SHA');
|
|
90
|
+
if (worktree.headSha.toLowerCase() !== entry.sha.toLowerCase()) return unscored('worktree headSha mismatch');
|
|
91
|
+
const findings = Array.isArray(document) ? document : document?.findings;
|
|
92
|
+
if (!Array.isArray(findings)) return unscored('findings.json missing or malformed');
|
|
93
|
+
if (findings.some((f) => !f || typeof f.file !== 'string' || !f.file.trim() || !SEVERITIES.has(f.severity)
|
|
94
|
+
|| !(f.line === null || (Number.isInteger(f.line) && f.line > 0)))) {
|
|
95
|
+
return unscored('findings.json contains a malformed finding');
|
|
96
|
+
}
|
|
97
|
+
return { key, findings, reason: null };
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
// Validate archive references before reading any run directories.
|
|
101
|
+
export function validateArchiveRunIds(entries) {
|
|
102
|
+
const duplicate = entries.find((entry, index) => entry.runId
|
|
103
|
+
&& entries.slice(0, index).some(previous => previous.runId === entry.runId));
|
|
104
|
+
if (duplicate) throw new Error(`archive manifest reuses runId ${duplicate.runId}`);
|
|
105
|
+
return entries;
|
|
106
|
+
}
|
|
107
|
+
|
|
74
108
|
export function score(manifest, results) {
|
|
75
109
|
const rows = validateManifest(manifest).map((e) => {
|
|
76
110
|
const key = caseKey(e);
|