chore: address Copilot review round 2
- verify-skills: version-gate the optional `claude plugin validate`. Probing
only for the executable failed the MANDATORY gate for anyone on a CLI older
than 2.1.233, which has no such subcommand and exits nonzero on it. Skips
below the floor; a failure now means a supported validator rejected the skills.
- skill-eval: match the invoked skill structurally. A substring test counted
`{"skill":"not-testing"}` as a hit for `testing` and inflated the rate.
- skill-eval: `runOnce` → exported `runPrompt` with an injectable `spawnFn`, so
the nonzero-exit branch is actually pinned. Reverting it now fails a test
(verified by mutation) rather than leaving the suite green.
- board-ops: filter the item lookups by repository. Issue numbers are repo-local
and these are org boards — #11 really does carry a `servers` card — so an
unfiltered `select` can move or delete the wrong card, or pass two ids.
- issue-triage: the audit's `own()` filter dropped draft cards, which carry no
`.content.repository`, so the "non-Issue on a board" check reported 0 while
the invariant was being violated. Verified against a fixture.
- pr-flow: cut the branch from the base it will target. The blanket "cut from
v2/main" was wrong for v1, whose history is unrelated.
Signed-off-by: cliffhall <cliff@futurescale.com>
This commit is contained in:
parent
4520e6aa2c
commit
ca6828916f
2 changed files with 221 additions and 17 deletions
|
|
@ -206,3 +206,30 @@ export function validateEvalCases(skillName, cases) {
|
|||
}
|
||||
return errors;
|
||||
}
|
||||
|
||||
/** First Claude Code release with `claude plugin validate`. */
|
||||
export const PLUGIN_VALIDATE_MIN_VERSION = [2, 1, 233];
|
||||
|
||||
/**
|
||||
* Read a semver triple out of `claude --version` output ("2.1.250 (Claude Code)").
|
||||
*
|
||||
* @param {string} text
|
||||
* @returns {number[] | null}
|
||||
*/
|
||||
export function parseClaudeVersion(text) {
|
||||
const m = /(\d+)\.(\d+)\.(\d+)/.exec(text);
|
||||
return m === null ? null : [Number(m[1]), Number(m[2]), Number(m[3])];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {number[]} a
|
||||
* @param {number[]} b
|
||||
* @returns {number} negative if a < b, 0 if equal, positive if a > b.
|
||||
*/
|
||||
export function compareVersions(a, b) {
|
||||
for (let i = 0; i < Math.max(a.length, b.length); i++) {
|
||||
const diff = (a[i] ?? 0) - (b[i] ?? 0);
|
||||
if (diff !== 0) return diff;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -11,6 +11,9 @@ import {
|
|||
parseSkill,
|
||||
validateEvalCases,
|
||||
listingCost,
|
||||
parseClaudeVersion,
|
||||
compareVersions,
|
||||
PLUGIN_VALIDATE_MIN_VERSION,
|
||||
} from "./skill-manifest.mjs";
|
||||
|
||||
const fm = (body) => `---\n${body}\n---\n\n# Body\n`;
|
||||
|
|
@ -198,3 +201,21 @@ test("validateEvalCases rejects malformed cases", () => {
|
|||
/expect. must be a skill name or null/,
|
||||
);
|
||||
});
|
||||
|
||||
test("parseClaudeVersion reads the CLI's version banner", () => {
|
||||
assert.deepEqual(parseClaudeVersion("2.1.250 (Claude Code)"), [2, 1, 250]);
|
||||
assert.deepEqual(parseClaudeVersion("claude 10.0.4\n"), [10, 0, 4]);
|
||||
assert.equal(parseClaudeVersion("no version here"), null);
|
||||
});
|
||||
|
||||
test("compareVersions orders the plugin-validate floor correctly", () => {
|
||||
// An older CLI has no `plugin validate` and exits nonzero on it as an unknown
|
||||
// command; failing the mandatory gate for that would be wrong, so the probe
|
||||
// must skip below the floor rather than run and fail.
|
||||
assert.ok(compareVersions([2, 1, 232], PLUGIN_VALIDATE_MIN_VERSION) < 0);
|
||||
assert.equal(compareVersions([2, 1, 233], PLUGIN_VALIDATE_MIN_VERSION), 0);
|
||||
assert.ok(compareVersions([2, 1, 250], PLUGIN_VALIDATE_MIN_VERSION) > 0);
|
||||
assert.ok(compareVersions([2, 2, 0], PLUGIN_VALIDATE_MIN_VERSION) > 0);
|
||||
assert.ok(compareVersions([3], PLUGIN_VALIDATE_MIN_VERSION) > 0);
|
||||
assert.ok(compareVersions([1, 9, 999], PLUGIN_VALIDATE_MIN_VERSION) < 0);
|
||||
});
|
||||
|
|
|
|||
Loading…
Reference in a new issue