@vibe-agent-toolkit/agent-skills 0.2.0-rc.5 → 0.2.0-rc.6
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/dist/index.d.ts +4 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +9 -2
- package/dist/index.js.map +1 -1
- package/dist/post-build-checks.d.ts +29 -0
- package/dist/post-build-checks.d.ts.map +1 -1
- package/dist/post-build-checks.js +33 -0
- package/dist/post-build-checks.js.map +1 -1
- package/dist/skill-identity.d.ts +10 -0
- package/dist/skill-identity.d.ts.map +1 -1
- package/dist/skill-identity.js +12 -0
- package/dist/skill-identity.js.map +1 -1
- package/dist/skill-packager.d.ts.map +1 -1
- package/dist/skill-packager.js +26 -1
- package/dist/skill-packager.js.map +1 -1
- package/dist/skill-test/eval-fragment.d.ts +26 -26
- package/dist/validators/mcp-tool-qualification.d.ts +158 -0
- package/dist/validators/mcp-tool-qualification.d.ts.map +1 -0
- package/dist/validators/mcp-tool-qualification.js +467 -0
- package/dist/validators/mcp-tool-qualification.js.map +1 -0
- package/dist/validators/packaged-size-limit.d.ts +296 -0
- package/dist/validators/packaged-size-limit.d.ts.map +1 -0
- package/dist/validators/packaged-size-limit.js +494 -0
- package/dist/validators/packaged-size-limit.js.map +1 -0
- package/dist/validators/packaging-validator.d.ts +10 -0
- package/dist/validators/packaging-validator.d.ts.map +1 -1
- package/dist/validators/packaging-validator.js +72 -4
- package/dist/validators/packaging-validator.js.map +1 -1
- package/dist/validators/referenced-path-missing.d.ts +202 -0
- package/dist/validators/referenced-path-missing.d.ts.map +1 -0
- package/dist/validators/referenced-path-missing.js +358 -0
- package/dist/validators/referenced-path-missing.js.map +1 -0
- package/dist/validators/skill-validator.d.ts.map +1 -1
- package/dist/validators/skill-validator.js +29 -0
- package/dist/validators/skill-validator.js.map +1 -1
- package/package.json +5 -5
|
@@ -226,19 +226,6 @@ export declare const EvalFragmentSchema: z.ZodObject<{
|
|
|
226
226
|
}[];
|
|
227
227
|
evalId: string;
|
|
228
228
|
runNonce: string;
|
|
229
|
-
degraded?: {
|
|
230
|
-
detail: string;
|
|
231
|
-
reason: "transcript-unparsed" | "cwd-unknown" | "cwd-untracked" | "transcript-malformed" | "glob-unexpanded";
|
|
232
|
-
evalId?: string | undefined;
|
|
233
|
-
} | undefined;
|
|
234
|
-
arm?: "with" | "without" | undefined;
|
|
235
|
-
friction?: {
|
|
236
|
-
message: string;
|
|
237
|
-
severity: "high" | "medium" | "low";
|
|
238
|
-
category: "path-assumption" | "undeclared-dependency" | "ambient-propping" | "doc-engine-drift" | "missing-bundled-file" | "tool-expectation";
|
|
239
|
-
evidence?: string | undefined;
|
|
240
|
-
subjectFile?: string | undefined;
|
|
241
|
-
}[] | undefined;
|
|
242
229
|
tool?: {
|
|
243
230
|
passed: boolean;
|
|
244
231
|
mustRun?: {
|
|
@@ -262,19 +249,6 @@ export declare const EvalFragmentSchema: z.ZodObject<{
|
|
|
262
249
|
evidence?: string | undefined;
|
|
263
250
|
}[] | undefined;
|
|
264
251
|
} | undefined;
|
|
265
|
-
contamination?: {
|
|
266
|
-
match: string;
|
|
267
|
-
kind: "harness-path" | "declared-executable" | "sibling-arm" | "vat-private-dir" | "skill-content";
|
|
268
|
-
excerpt: string;
|
|
269
|
-
}[] | undefined;
|
|
270
|
-
}, {
|
|
271
|
-
expectations: {
|
|
272
|
-
text: string;
|
|
273
|
-
passed: boolean;
|
|
274
|
-
evidence?: string | undefined;
|
|
275
|
-
}[];
|
|
276
|
-
evalId: string;
|
|
277
|
-
runNonce: string;
|
|
278
252
|
degraded?: {
|
|
279
253
|
detail: string;
|
|
280
254
|
reason: "transcript-unparsed" | "cwd-unknown" | "cwd-untracked" | "transcript-malformed" | "glob-unexpanded";
|
|
@@ -288,6 +262,19 @@ export declare const EvalFragmentSchema: z.ZodObject<{
|
|
|
288
262
|
evidence?: string | undefined;
|
|
289
263
|
subjectFile?: string | undefined;
|
|
290
264
|
}[] | undefined;
|
|
265
|
+
contamination?: {
|
|
266
|
+
match: string;
|
|
267
|
+
kind: "harness-path" | "declared-executable" | "sibling-arm" | "vat-private-dir" | "skill-content";
|
|
268
|
+
excerpt: string;
|
|
269
|
+
}[] | undefined;
|
|
270
|
+
}, {
|
|
271
|
+
expectations: {
|
|
272
|
+
text: string;
|
|
273
|
+
passed: boolean;
|
|
274
|
+
evidence?: string | undefined;
|
|
275
|
+
}[];
|
|
276
|
+
evalId: string;
|
|
277
|
+
runNonce: string;
|
|
291
278
|
tool?: {
|
|
292
279
|
passed: boolean;
|
|
293
280
|
mustRun?: {
|
|
@@ -311,6 +298,19 @@ export declare const EvalFragmentSchema: z.ZodObject<{
|
|
|
311
298
|
evidence?: string | undefined;
|
|
312
299
|
}[] | undefined;
|
|
313
300
|
} | undefined;
|
|
301
|
+
degraded?: {
|
|
302
|
+
detail: string;
|
|
303
|
+
reason: "transcript-unparsed" | "cwd-unknown" | "cwd-untracked" | "transcript-malformed" | "glob-unexpanded";
|
|
304
|
+
evalId?: string | undefined;
|
|
305
|
+
} | undefined;
|
|
306
|
+
arm?: "with" | "without" | undefined;
|
|
307
|
+
friction?: {
|
|
308
|
+
message: string;
|
|
309
|
+
severity: "high" | "medium" | "low";
|
|
310
|
+
category: "path-assumption" | "undeclared-dependency" | "ambient-propping" | "doc-engine-drift" | "missing-bundled-file" | "tool-expectation";
|
|
311
|
+
evidence?: string | undefined;
|
|
312
|
+
subjectFile?: string | undefined;
|
|
313
|
+
}[] | undefined;
|
|
314
314
|
contamination?: {
|
|
315
315
|
match: string;
|
|
316
316
|
kind: "harness-path" | "declared-executable" | "sibling-arm" | "vat-private-dir" | "skill-content";
|
|
@@ -0,0 +1,158 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* MCP_TOOL_NAME_UNQUALIFIED — a skill document tells an agent to call an MCP
|
|
3
|
+
* tool by its bare name, in a document that elsewhere spells that same tool
|
|
4
|
+
* fully-qualified.
|
|
5
|
+
*
|
|
6
|
+
* Anthropic's skill-authoring guidance: "Without the server prefix, Claude may
|
|
7
|
+
* fail to locate the tool, especially when multiple MCP servers are available."
|
|
8
|
+
* VAT's own `vat skill review` checklist has carried this as a `[A]` manual item
|
|
9
|
+
* marked "Not enforced by any validation code; a shift-left candidate awaiting
|
|
10
|
+
* corpus evidence per docs/validation-rule-design.md, since a bare identifier in
|
|
11
|
+
* prose is only a defect when the skill actually drives MCP." The reservation is
|
|
12
|
+
* exactly right, and it is what shapes the detector below.
|
|
13
|
+
*
|
|
14
|
+
* ## The document supplies its own vocabulary
|
|
15
|
+
*
|
|
16
|
+
* A bare snake_case identifier is not evidence of anything — `page_size`,
|
|
17
|
+
* `next_page_token` and `whiteboard_id` are all over these documents. What makes
|
|
18
|
+
* an identifier an MCP *tool name* is that the SAME document also writes it
|
|
19
|
+
* fully-qualified, in one of the two spellings a reader will meet:
|
|
20
|
+
*
|
|
21
|
+
* - `mcp__<server>__<tool>` — the Claude Code form, also how `allowed-tools`
|
|
22
|
+
* frontmatter names them.
|
|
23
|
+
* - `ServerName:tool_name` — the API form Anthropic's guidance prescribes.
|
|
24
|
+
*
|
|
25
|
+
* So the detector never guesses. It reads the qualified names the document
|
|
26
|
+
* already contains, and then reports the places that document names one of those
|
|
27
|
+
* same tools bare. A document that does not drive MCP has an empty vocabulary and
|
|
28
|
+
* cannot produce a finding — which dissolves the checklist's reservation rather
|
|
29
|
+
* than arguing with it.
|
|
30
|
+
*
|
|
31
|
+
* ## Prose supplies the vocabulary; frontmatter does not
|
|
32
|
+
*
|
|
33
|
+
* Leading YAML frontmatter is stripped here, in the detector, before anything is
|
|
34
|
+
* read from it. An `allowed-tools:` list of `mcp__…` names is a manifest, not the
|
|
35
|
+
* document contradicting itself, so it must not seed the vocabulary — and a bare
|
|
36
|
+
* name in the body below it is then simply a document that never qualified the
|
|
37
|
+
* tool at all.
|
|
38
|
+
*
|
|
39
|
+
* Enforcing that HERE rather than at each call site is deliberate, and it is the
|
|
40
|
+
* only place it has ever held. ⛔ An earlier version of this paragraph said the
|
|
41
|
+
* SKILL.md lane in `packaging-validator.ts` "happened to pass a
|
|
42
|
+
* frontmatter-stripped slice" while the bundled-`.md` lane passed whole files.
|
|
43
|
+
* It does not and never did: `parseFileCached(...).content` is the raw source
|
|
44
|
+
* verbatim — that file says so itself, 190 lines above the call — so BOTH lanes
|
|
45
|
+
* fed frontmatter to the detector until this stripping landed.
|
|
46
|
+
*
|
|
47
|
+
* ## The uppercase rule in the API form, and why it is load-bearing
|
|
48
|
+
*
|
|
49
|
+
* The server half must be spelled the way Anthropic's own examples spell one —
|
|
50
|
+
* uppercase FIRST, no underscore (`GitHub:create_issue`,
|
|
51
|
+
* `BigQuery:bigquery_schema`). Without that rule the
|
|
52
|
+
* pattern also matches two things that are emphatically not MCP tools:
|
|
53
|
+
*
|
|
54
|
+
* - **Node builtin specifiers** — `node:child_process` yields a "tool" named
|
|
55
|
+
* `child_process`, and VAT's own `packages/utils/README.md` then reports a
|
|
56
|
+
* finding on a table of exported function names.
|
|
57
|
+
* - **OAuth scope strings** — `whiteboard:read:list_whiteboards` and
|
|
58
|
+
* `cloud_recording:read:list_user_recordings`, both live in a partner-built
|
|
59
|
+
* plugin in the install corpus.
|
|
60
|
+
*
|
|
61
|
+
* Neither was visible on the two adopter corpora; both were visible on the
|
|
62
|
+
* authoring project, which is precisely the population check
|
|
63
|
+
* `docs/validation-rule-design.md` requires and the reason it requires it.
|
|
64
|
+
*
|
|
65
|
+
* ## Measured fire rate, re-measured 2026-09-07
|
|
66
|
+
*
|
|
67
|
+
* Population = documents that spell at least one MCP tool fully-qualified.
|
|
68
|
+
*
|
|
69
|
+
* | Corpus | docs | population | firing | occurrences |
|
|
70
|
+
* |---|---|---|---|---|
|
|
71
|
+
* | VAT itself (`packages/**\/*.md`, dist + node_modules excluded) | 206 | 3 | **0** | 0 |
|
|
72
|
+
* | installed skills (`SKILL.md` under `~/.claude/plugins`, `~/.claude/skills`) | 678 | 28 | 7 | 11 |
|
|
73
|
+
*
|
|
74
|
+
* ⛔ **Every number this table used to carry was taken by the camelCase-blind
|
|
75
|
+
* matcher, so re-taking them was not optional.** A corpus measured by a matcher
|
|
76
|
+
* that cannot see a whole family of names has already excluded that family from
|
|
77
|
+
* its own population count, and "zero false positives" over such a corpus is a
|
|
78
|
+
* statement about the blindness as much as about the rule. Both rows above were
|
|
79
|
+
* re-run with the fixed detector, driving the exported functions directly, over
|
|
80
|
+
* a corpus re-enumerated on the day.
|
|
81
|
+
*
|
|
82
|
+
* What moved, A/B on the same files with HEAD's module and this one:
|
|
83
|
+
*
|
|
84
|
+
* - **Authoring project: population 2 → 3.** One document newly enters the
|
|
85
|
+
* population, because it spells two camelCase tools (`generateHaiku`,
|
|
86
|
+
* `generateName`) that the old matcher could not see at all. Firing stays 0.
|
|
87
|
+
* - **Installed skills: nothing moved** — 28 / 7 / 11 before and after,
|
|
88
|
+
* character for character, with no vocabulary entry gained or lost. The
|
|
89
|
+
* installed corpus is snake_case throughout, which is Anthropic's own
|
|
90
|
+
* convention and therefore exactly the population least able to expose this
|
|
91
|
+
* defect. Its silence is not evidence the defect was small.
|
|
92
|
+
* - The corpus itself grew 677 → 678 `SKILL.md` between the two measurement
|
|
93
|
+
* dates; the delta above is A/B on the SAME 678 files, so it is a property of
|
|
94
|
+
* the detector rather than of the corpus.
|
|
95
|
+
*
|
|
96
|
+
* All 11 occurrences were read: every one names a tool bare that the same
|
|
97
|
+
* document qualifies in its own prose. Zero false positives.
|
|
98
|
+
*
|
|
99
|
+
* The SHIPPED command was re-run on the same corpus rather than trusted to
|
|
100
|
+
* agree with the probe — `vat audit --user`, 852 skills scanned, reproducing
|
|
101
|
+
* the installed-skills row occurrence for occurrence and line for line (plus
|
|
102
|
+
* the 4 linked-file occurrences `docs/validation-codes.md` records, which the
|
|
103
|
+
* probe above does not traverse).
|
|
104
|
+
*
|
|
105
|
+
* The frontmatter-including detector, run over the same 678 documents, reports
|
|
106
|
+
* 19 occurrences from the same 7 documents. The extra 8 are four copies of one
|
|
107
|
+
* skill naming `create_repository` and `create_branch` bare, whose only
|
|
108
|
+
* qualified spelling is its `allowed-tools:` frontmatter.
|
|
109
|
+
*
|
|
110
|
+
* ⛔ Those 8 WERE shipped. This paragraph used to claim the SKILL.md lane had
|
|
111
|
+
* "always passed a frontmatter-stripped slice" and that the 19 therefore
|
|
112
|
+
* described the probe rather than the product. `parseFileCached(...).content` is
|
|
113
|
+
* the raw file, frontmatter and all, so the shipped lane emitted every one of
|
|
114
|
+
* them. The 19 → 11 delta is a real behaviour change this detector made, not a
|
|
115
|
+
* correction to a probe.
|
|
116
|
+
*
|
|
117
|
+
* `warning`, not `error`: with a single MCP server mounted the bare name
|
|
118
|
+
* usually resolves, so the skill is degraded rather than broken.
|
|
119
|
+
*/
|
|
120
|
+
import { type ValidationIssue } from '@vibe-agent-toolkit/schema';
|
|
121
|
+
/**
|
|
122
|
+
* Every MCP tool name `content` spells fully-qualified in its body, in either
|
|
123
|
+
* spelling. Frontmatter supplies nothing; see the module docstring.
|
|
124
|
+
*
|
|
125
|
+
* Exported for tests: this set IS the detector's premise, and pinning it directly
|
|
126
|
+
* is cheaper and clearer than inferring it from emitted issues.
|
|
127
|
+
*/
|
|
128
|
+
export declare function qualifiedMcpToolNames(content: string): Set<string>;
|
|
129
|
+
/**
|
|
130
|
+
* Emit one `MCP_TOOL_NAME_UNQUALIFIED` per (line, bare tool name).
|
|
131
|
+
*
|
|
132
|
+
* Per instance rather than per document, each carrying the bare tool name as
|
|
133
|
+
* `link`, because `applyAllowFilter` matches an allow glob against `location` OR
|
|
134
|
+
* `link`. That is what lets an adopter waive one identifier:
|
|
135
|
+
*
|
|
136
|
+
* ```yaml
|
|
137
|
+
* validation:
|
|
138
|
+
* allow:
|
|
139
|
+
* MCP_TOOL_NAME_UNQUALIFIED:
|
|
140
|
+
* - paths: ["get_me"]
|
|
141
|
+
* reason: "Named bare in the availability-probe step on purpose; the
|
|
142
|
+
* qualified form is three lines above."
|
|
143
|
+
* ```
|
|
144
|
+
*
|
|
145
|
+
* …while a different bare tool name in the same document still fires. Waiver
|
|
146
|
+
* granularity is the emitter's decision, not the allow machinery's.
|
|
147
|
+
*
|
|
148
|
+
* Only inline code spans count. An agent copies what is in a code span; the same
|
|
149
|
+
* word in running prose is discussion of the tool rather than an instruction to
|
|
150
|
+
* call it. This is a design choice, not a measured one — the corpus numbers in
|
|
151
|
+
* the module docstring were all taken with the code-span rule already applied, so
|
|
152
|
+
* nothing here says what admitting prose would have cost.
|
|
153
|
+
*
|
|
154
|
+
* @param content Raw markdown of one skill document, frontmatter and all.
|
|
155
|
+
* @param docLocation Project-relative path of that document, for the anchor.
|
|
156
|
+
*/
|
|
157
|
+
export declare function collectUnqualifiedMcpToolIssues(content: string, docLocation: string, issues: ValidationIssue[]): void;
|
|
158
|
+
//# sourceMappingURL=mcp-tool-qualification.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"mcp-tool-qualification.d.ts","sourceRoot":"","sources":["../../src/validators/mcp-tool-qualification.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAsHG;AAEH,OAAO,EAAiB,KAAK,eAAe,EAAE,MAAM,4BAA4B,CAAC;AAgRjF;;;;;;GAMG;AACH,wBAAgB,qBAAqB,CAAC,OAAO,EAAE,MAAM,GAAG,GAAG,CAAC,MAAM,CAAC,CAElE;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AACH,wBAAgB,+BAA+B,CAC7C,OAAO,EAAE,MAAM,EACf,WAAW,EAAE,MAAM,EACnB,MAAM,EAAE,eAAe,EAAE,GACxB,IAAI,CA6CN"}
|