@yogiadhik/skillcheck 0.1.0 → 0.1.2
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/README.md +6 -2
- package/dist/cli.js +8 -4
- package/dist/lint/rules.js +15 -1
- package/dist/reporters/terminal.js +3 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -49,8 +49,12 @@ Run `npx @yogiadhik/skillcheck init <skill-dir>` to scaffold a starter file.
|
|
|
49
49
|
|
|
50
50
|
Behavioral runs call the real agent, and that costs real money.
|
|
51
51
|
skillcheck caches results by content hash — unchanged skill, unchanged
|
|
52
|
-
case, no re-run — and `--budget 2.50`
|
|
53
|
-
|
|
52
|
+
case, no re-run — and `--budget 2.50` stops the run once the cap is
|
|
53
|
+
crossed. The check happens between cases, so one long case can still
|
|
54
|
+
overshoot on its own: pair a budget with `--model haiku` to keep
|
|
55
|
+
single cases cheap. skillcheck tells you when no model is set, and
|
|
56
|
+
warns at the end if a run blew past its budget. Lint never spends
|
|
57
|
+
anything.
|
|
54
58
|
|
|
55
59
|
## CI
|
|
56
60
|
|
package/dist/cli.js
CHANGED
|
@@ -9,7 +9,7 @@ const program = new Command();
|
|
|
9
9
|
program
|
|
10
10
|
.name('skillcheck')
|
|
11
11
|
.description('lint and behavioral tests for agent skills')
|
|
12
|
-
.version('0.1.
|
|
12
|
+
.version('0.1.2');
|
|
13
13
|
program
|
|
14
14
|
.command('lint')
|
|
15
15
|
.argument('[path]', 'skill file or directory', '.')
|
|
@@ -43,18 +43,22 @@ program
|
|
|
43
43
|
.action(async (path, opts) => {
|
|
44
44
|
try {
|
|
45
45
|
const files = discoverTestFiles(path);
|
|
46
|
-
if (!opts.json)
|
|
46
|
+
if (!opts.json) {
|
|
47
47
|
console.log(`${files.length} test file(s); live agent runs cost money — cap with --budget`);
|
|
48
|
+
if (!opts.model)
|
|
49
|
+
console.log('no --model given — using the CLI default model; pass --model haiku for cheap runs');
|
|
50
|
+
}
|
|
51
|
+
const budgetUsd = opts.budget ? Number(opts.budget) : undefined;
|
|
48
52
|
const reports = await runTests(path, {
|
|
49
53
|
model: opts.model,
|
|
50
|
-
budgetUsd
|
|
54
|
+
budgetUsd,
|
|
51
55
|
timeoutMs: Number(opts.timeout) * 1000,
|
|
52
56
|
cache: opts.cache,
|
|
53
57
|
});
|
|
54
58
|
if (opts.json)
|
|
55
59
|
console.log(JSON.stringify(reports, null, 2));
|
|
56
60
|
else
|
|
57
|
-
printReports(reports);
|
|
61
|
+
printReports(reports, budgetUsd);
|
|
58
62
|
process.exitCode = reportsPass(reports) ? 0 : 1;
|
|
59
63
|
}
|
|
60
64
|
catch (e) {
|
package/dist/lint/rules.js
CHANGED
|
@@ -30,9 +30,23 @@ export const tokenBudget = (s) => {
|
|
|
30
30
|
return [finding(s, 'token-budget', 'warning', `skill is roughly ${tokens} tokens; every invocation pays this cost`)];
|
|
31
31
|
return [];
|
|
32
32
|
};
|
|
33
|
+
// links inside fenced blocks or inline code are examples, not references
|
|
34
|
+
function proseOnly(body) {
|
|
35
|
+
const kept = [];
|
|
36
|
+
let inFence = false;
|
|
37
|
+
for (const line of body.split('\n')) {
|
|
38
|
+
if (/^\s*(```|~~~)/.test(line)) {
|
|
39
|
+
inFence = !inFence;
|
|
40
|
+
continue;
|
|
41
|
+
}
|
|
42
|
+
if (!inFence)
|
|
43
|
+
kept.push(line);
|
|
44
|
+
}
|
|
45
|
+
return kept.join('\n').replace(/`[^`\n]*`/g, '');
|
|
46
|
+
}
|
|
33
47
|
export const relativeLinks = (s) => {
|
|
34
48
|
const out = [];
|
|
35
|
-
for (const m of s.body.matchAll(/\[[^\]]*\]\(([^)]+)\)/g)) {
|
|
49
|
+
for (const m of proseOnly(s.body).matchAll(/\[[^\]]*\]\(([^)]+)\)/g)) {
|
|
36
50
|
const target = m[1];
|
|
37
51
|
if (/^(https?:|mailto:|#)/.test(target))
|
|
38
52
|
continue;
|
|
@@ -7,7 +7,7 @@ export function printFindings(findings) {
|
|
|
7
7
|
const errors = findings.filter((f) => f.severity === 'error').length;
|
|
8
8
|
console.log(`\n${findings.length} finding(s), ${errors} error(s)`);
|
|
9
9
|
}
|
|
10
|
-
export function printReports(reports) {
|
|
10
|
+
export function printReports(reports, budgetUsd) {
|
|
11
11
|
let cost = 0;
|
|
12
12
|
for (const r of reports) {
|
|
13
13
|
cost += r.costUsd;
|
|
@@ -24,4 +24,6 @@ export function printReports(reports) {
|
|
|
24
24
|
console.log(pc.red(` judge: ${r.verdict.score}/10 — ${r.verdict.reasoning}`));
|
|
25
25
|
}
|
|
26
26
|
console.log(`\n${reports.length} case(s), $${cost.toFixed(4)} spent`);
|
|
27
|
+
if (budgetUsd !== undefined && cost > budgetUsd)
|
|
28
|
+
console.log(pc.yellow(`budget of $${budgetUsd} exceeded — the cap is checked between cases, so a single case can overshoot it`));
|
|
27
29
|
}
|