mewkit 1.16.1 → 1.18.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.
Files changed (83) hide show
  1. package/dist/commands/build-plugin.d.ts +6 -0
  2. package/dist/commands/build-plugin.d.ts.map +1 -1
  3. package/dist/commands/build-plugin.js +3 -3
  4. package/dist/commands/build-plugin.js.map +1 -1
  5. package/dist/commands/plan.d.ts +7 -0
  6. package/dist/commands/plan.d.ts.map +1 -0
  7. package/dist/commands/plan.js +124 -0
  8. package/dist/commands/plan.js.map +1 -0
  9. package/dist/commands/providers.js +15 -0
  10. package/dist/commands/providers.js.map +1 -1
  11. package/dist/commands/validate.d.ts +9 -1
  12. package/dist/commands/validate.d.ts.map +1 -1
  13. package/dist/commands/validate.js +93 -1
  14. package/dist/commands/validate.js.map +1 -1
  15. package/dist/core/build-inventory.d.ts +25 -0
  16. package/dist/core/build-inventory.d.ts.map +1 -1
  17. package/dist/core/build-inventory.js +83 -2
  18. package/dist/core/build-inventory.js.map +1 -1
  19. package/dist/core/capability.d.ts +24 -24
  20. package/dist/core/check-agent-conformance.d.ts +14 -0
  21. package/dist/core/check-agent-conformance.d.ts.map +1 -0
  22. package/dist/core/check-agent-conformance.js +127 -0
  23. package/dist/core/check-agent-conformance.js.map +1 -0
  24. package/dist/core/check-docs-references.d.ts.map +1 -1
  25. package/dist/core/check-docs-references.js +6 -0
  26. package/dist/core/check-docs-references.js.map +1 -1
  27. package/dist/core/check-gate-authority.d.ts +40 -0
  28. package/dist/core/check-gate-authority.d.ts.map +1 -0
  29. package/dist/core/check-gate-authority.js +313 -0
  30. package/dist/core/check-gate-authority.js.map +1 -0
  31. package/dist/core/check-generic-core-tokens.d.ts +12 -0
  32. package/dist/core/check-generic-core-tokens.d.ts.map +1 -0
  33. package/dist/core/check-generic-core-tokens.js +67 -0
  34. package/dist/core/check-generic-core-tokens.js.map +1 -0
  35. package/dist/core/check-operation-conformance.d.ts +27 -0
  36. package/dist/core/check-operation-conformance.d.ts.map +1 -0
  37. package/dist/core/check-operation-conformance.js +91 -0
  38. package/dist/core/check-operation-conformance.js.map +1 -0
  39. package/dist/core/check-plugin-parity.d.ts +15 -0
  40. package/dist/core/check-plugin-parity.d.ts.map +1 -0
  41. package/dist/core/check-plugin-parity.js +130 -0
  42. package/dist/core/check-plugin-parity.js.map +1 -0
  43. package/dist/core/check-pseudo-capabilities.d.ts +15 -0
  44. package/dist/core/check-pseudo-capabilities.d.ts.map +1 -0
  45. package/dist/core/check-pseudo-capabilities.js +89 -0
  46. package/dist/core/check-pseudo-capabilities.js.map +1 -0
  47. package/dist/core/check-stale-index.d.ts.map +1 -1
  48. package/dist/core/check-stale-index.js +7 -0
  49. package/dist/core/check-stale-index.js.map +1 -1
  50. package/dist/core/check-workflow-drift.d.ts +9 -4
  51. package/dist/core/check-workflow-drift.d.ts.map +1 -1
  52. package/dist/core/check-workflow-drift.js +33 -29
  53. package/dist/core/check-workflow-drift.js.map +1 -1
  54. package/dist/core/plan-parser.d.ts +40 -0
  55. package/dist/core/plan-parser.d.ts.map +1 -0
  56. package/dist/core/plan-parser.js +126 -0
  57. package/dist/core/plan-parser.js.map +1 -0
  58. package/dist/core/plugin-payload.d.ts.map +1 -1
  59. package/dist/core/plugin-payload.js +9 -0
  60. package/dist/core/plugin-payload.js.map +1 -1
  61. package/dist/core/provider-adapter.d.ts +4 -0
  62. package/dist/core/provider-adapter.d.ts.map +1 -1
  63. package/dist/core/provider-adapter.js +2 -0
  64. package/dist/core/provider-adapter.js.map +1 -1
  65. package/dist/core/provider-operations.d.ts +51 -0
  66. package/dist/core/provider-operations.d.ts.map +1 -0
  67. package/dist/core/provider-operations.js +171 -0
  68. package/dist/core/provider-operations.js.map +1 -0
  69. package/dist/core/substrate.d.ts +2 -2
  70. package/dist/core/substrate.d.ts.map +1 -1
  71. package/dist/core/substrate.js +3 -4
  72. package/dist/core/substrate.js.map +1 -1
  73. package/dist/index.js +18 -0
  74. package/dist/index.js.map +1 -1
  75. package/dist/migrate/model-taxonomy.d.ts +32 -0
  76. package/dist/migrate/model-taxonomy.d.ts.map +1 -1
  77. package/dist/migrate/model-taxonomy.js +59 -0
  78. package/dist/migrate/model-taxonomy.js.map +1 -1
  79. package/dist/migrate/providers/codex/capabilities.d.ts.map +1 -1
  80. package/dist/migrate/providers/codex/capabilities.js +6 -0
  81. package/dist/migrate/providers/codex/capabilities.js.map +1 -1
  82. package/dist/migrate/reconcile/portable-registry.d.ts +6 -6
  83. package/package.json +2 -2
@@ -0,0 +1,313 @@
1
+ import fs from "node:fs";
2
+ import path from "node:path";
3
+ /** Suppression marker for prose that legitimately QUOTES the anti-pattern. */
4
+ const ALLOW_MARKER = "lint-allow-gate-authority";
5
+ /**
6
+ * Statements that grant automated gate approval. Each entry is scoped to an
7
+ * explicit `Gate 1` / `Gate 2` reference (or an unambiguous euphemism) so that
8
+ * unrelated vocabulary — a skill's own "HARD GATE", a domain "gate" metaphor —
9
+ * cannot trip the check.
10
+ */
11
+ const PATTERNS = [
12
+ {
13
+ name: "auto-approve → gate",
14
+ // The digit is REQUIRED. Without it this matches the bare word "gate" and
15
+ // fires on every domain metaphor ("the quality gate stays manual").
16
+ //
17
+ // The gap is deliberately TIGHT. In every real instance the verb and its
18
+ // gate are adjacent ("auto-approves Gate 2"). A wide gap lets one match
19
+ // span two clauses, so a negated first clause swallows the gate reference
20
+ // belonging to an asserting second clause — and the violation vanishes.
21
+ re: /auto[-\s]?approv\w*[^.\n]{0,20}\bgates?\s*[12]\b/gi,
22
+ expected: "automation executes between gates; a human approves the gate",
23
+ },
24
+ {
25
+ name: "gate → auto-approved",
26
+ re: /\bgate\s*[12]\b[^.\n]{0,30}auto[-\s]?approv\w*/gi,
27
+ expected: "automation executes between gates; a human approves the gate",
28
+ },
29
+ {
30
+ name: "gate bound to an auto value",
31
+ re: /\bgate\s*[12]\s*:\s*auto/gi,
32
+ expected: "Gate 1 / Gate 2 are human in every mode",
33
+ },
34
+ {
35
+ name: "gate offering an auto alternative",
36
+ re: /\bgate\s*[12]\b[^.\n]{0,30}\[[^\]\n]*auto[^\]\n]*\]/gi,
37
+ expected: "the only gate outcome is human approval — drop the auto alternative",
38
+ },
39
+ {
40
+ name: "stamp treated as authority",
41
+ re: /\bstamp\s+counts\b/gi,
42
+ expected: "an evaluator stamp is evidence presented at the gate, never the approval",
43
+ },
44
+ {
45
+ name: "gate prompt skipped",
46
+ re: /\bskips?\s+gate\s*[12]\b[^.\n]{0,30}(prompt|user)/gi,
47
+ expected: "present the gate; a passing pre-check is evidence, not approval",
48
+ },
49
+ ];
50
+ /**
51
+ * Words that flip a claim from ASSERTING automated approval to FORBIDDING it.
52
+ * "Gate 2 is never auto-approved" states the contract — it must not be flagged.
53
+ */
54
+ const NEGATION_RE = /\b(never|not|n't|no|none|cannot|can't|forbidden|prohibited|non-negotiable|mandatory|requires?\s+human|human\s+approval|explicitly\s+typed)\b/i;
55
+ /**
56
+ * How far back from a match to look for the word that negates it. A negation
57
+ * governs the clause it introduces, so it sits immediately before the claim
58
+ * ("but never auto-approves Gate 2"), not in some unrelated later clause.
59
+ */
60
+ const NEGATION_LOOKBEHIND = 48;
61
+ /**
62
+ * True when the matched claim is negated rather than asserted.
63
+ *
64
+ * Scope matters enormously here. Testing the WHOLE line lets any incidental
65
+ * negation elsewhere in the sentence disarm a real violation — e.g.
66
+ * "auto-approves Gate 2 ... so no separate human click is required" is a
67
+ * genuine violation whose "no" belongs to a different clause entirely. A safety
68
+ * lint that misses its own threat model because of a distant "no" is worse than
69
+ * no lint: it reports green over the exact regression it exists to catch.
70
+ */
71
+ function isNegated(line, matchStart, matchText) {
72
+ const before = line.slice(Math.max(0, matchStart - NEGATION_LOOKBEHIND), matchStart);
73
+ return NEGATION_RE.test(before) || NEGATION_RE.test(matchText);
74
+ }
75
+ /** True when the line is nothing but the suppression comment. */
76
+ function isStandaloneMarker(line) {
77
+ return /^\s*<!--\s*lint-allow-gate-authority\s*-->\s*$/.test(line);
78
+ }
79
+ /** Scan one file's prose for statements granting automated gate authority. */
80
+ export function scanForGateAuthority(root, relPath) {
81
+ const abs = path.join(root, relPath);
82
+ if (!fs.existsSync(abs))
83
+ return [];
84
+ const violations = [];
85
+ const lines = fs.readFileSync(abs, "utf-8").split("\n");
86
+ lines.forEach((text, idx) => {
87
+ // A marker on the offending line suppresses that line. A marker on its own
88
+ // line above suppresses the line below — the form used where a trailing
89
+ // comment would render into prose (table rows, list items).
90
+ //
91
+ // The standalone requirement matters: an INLINE marker must not leak onto
92
+ // the next line, or one suppressed line silently disarms its neighbour.
93
+ if (text.includes(ALLOW_MARKER))
94
+ return;
95
+ if (idx > 0 && isStandaloneMarker(lines[idx - 1]))
96
+ return;
97
+ // Negation is evaluated per MATCH, and EVERY match is examined — not just
98
+ // the first. A line may state the contract and then carve an exception out
99
+ // of it ("Gate 2 is never auto-approved, but fast mode auto-approves Gate 2
100
+ // when tests pass"): the negated first clause must not excuse the second.
101
+ for (const { re, expected } of PATTERNS) {
102
+ for (const m of text.matchAll(re)) {
103
+ if (isNegated(text, m.index, m[0]))
104
+ continue;
105
+ violations.push({ file: relPath, line: idx + 1, found: text.trim(), expected });
106
+ return; // one finding per line is enough to locate and fix it
107
+ }
108
+ }
109
+ });
110
+ return violations;
111
+ }
112
+ /** Collect every `.md` file under `dir`, relative to `root`. */
113
+ function collectMarkdown(root, dir, acc = []) {
114
+ const abs = path.join(root, dir);
115
+ if (!fs.existsSync(abs))
116
+ return acc;
117
+ for (const entry of fs.readdirSync(abs, { withFileTypes: true })) {
118
+ const rel = path.join(dir, entry.name);
119
+ if (entry.isDirectory()) {
120
+ if (entry.name === "node_modules" || entry.name.startsWith(".git"))
121
+ continue;
122
+ collectMarkdown(root, rel, acc);
123
+ }
124
+ else if (entry.isFile() && entry.name.endsWith(".md")) {
125
+ acc.push(rel);
126
+ }
127
+ }
128
+ return acc;
129
+ }
130
+ // ─── Command-vs-skill drift ──────────────────────────────────────────────────
131
+ //
132
+ // A slash command and its same-named skill are two descriptions of one behavior,
133
+ // and two descriptions drift. The rule (skill-authoring-rules.md → Commands vs
134
+ // Skills): the command is a DISPATCHER — usage, flags, dispatch, and a concise
135
+ // safety note pointing at the authority. The skill owns the procedure.
136
+ //
137
+ // When a command re-states the workflow, the two copies disagree the moment
138
+ // either changes, and an agent reading the command follows a stale procedure it
139
+ // has no reason to distrust. That is exactly the `/mk:fix` defect this lint
140
+ // exists to keep closed: the command described a Simple path that skipped the
141
+ // scout its own skill marked MANDATORY.
142
+ //
143
+ // Gate semantics are NOT re-detected here — `checkGateAuthority` above is the
144
+ // one gate-phrase detector, deliberately shared. Two blacklists drift apart, and
145
+ // the weaker one becomes the de-facto contract.
146
+ /**
147
+ * The dispatchers this check contracts.
148
+ *
149
+ * Deliberately an allowlist, not "every same-name pair". Calibrating against all
150
+ * paired commands surfaced 7 REAL drift findings (0 false positives) in six
151
+ * commands outside this contract — autobuild, docs-init, help, retro, review,
152
+ * ship — e.g. `review.md` carries a full "### Execution Steps" procedure that
153
+ * duplicates its skill's. Those are pre-existing and each needs a considered
154
+ * rewrite, not a lint flip; widening this set is the follow-up that does them.
155
+ *
156
+ * So this set is a floor that holds the line where it was drawn, not a claim
157
+ * that the rest are clean. They are not. Widen it as each is thinned.
158
+ */
159
+ const GOVERNED_DISPATCHERS = new Set(["fix", "cook", "plan", "advise"]);
160
+ /** Governed same-name command/skill pairs — the only files this drift check reads. */
161
+ function pairedCommands(root) {
162
+ const cmdDir = path.join(root, ".claude", "commands", "mk");
163
+ const skillsDir = path.join(root, ".claude", "skills");
164
+ if (!fs.existsSync(cmdDir) || !fs.existsSync(skillsDir))
165
+ return [];
166
+ return fs
167
+ .readdirSync(cmdDir)
168
+ .filter((f) => f.endsWith(".md"))
169
+ .filter((f) => GOVERNED_DISPATCHERS.has(f.replace(/\.md$/, "")))
170
+ // A command with no same-name skill has nowhere to delegate its procedure to,
171
+ // so the same prose there is correct (skill-authoring-rules.md: "not every
172
+ // command has a matching SKILL.md, and that is intentional").
173
+ .filter((f) => fs.existsSync(path.join(skillsDir, f.replace(/\.md$/, ""), "SKILL.md")))
174
+ .map((f) => path.join(".claude", "commands", "mk", f));
175
+ }
176
+ /**
177
+ * Prose that belongs to the SKILL, found in a command file.
178
+ *
179
+ * Scoped tightly on purpose. A command legitimately carries usage, flags, a
180
+ * dispatch line, and a safety note — flagging those would make the lint noise,
181
+ * and a noisy lint gets disabled. These patterns target the two things a
182
+ * dispatcher can never own: step-by-step procedure, and memory writes.
183
+ */
184
+ const COMMAND_DRIFT_PATTERNS = [
185
+ {
186
+ name: "numbered workflow steps",
187
+ // "1. Do X" / "2. Then Y" — a procedure. One numbered line is a list; the
188
+ // pattern needs a SECOND step on a later line to fire, so a lone "1." in a
189
+ // safety note stays clean.
190
+ //
191
+ // `[ \t]*`, never `\s*`: `\s` matches newlines, so with `m` the match could
192
+ // begin on the preceding blank line and report a line number one too low —
193
+ // which silently pointed the allow-marker lookup at the wrong line.
194
+ re: /^[ \t]*2\.[ \t]+\S/gm,
195
+ expected: "the skill owns the procedure — the command dispatches to it",
196
+ },
197
+ {
198
+ name: "memory-write instruction",
199
+ re: /\b(Edit|write|append|update)\b[^.\n]{0,40}\.claude\/memory\//gi,
200
+ expected: "memory writes belong to the skill's capture step, not the command",
201
+ },
202
+ {
203
+ name: "memory store schema",
204
+ re: /\b(fixes|review-patterns|architecture-decisions|security-findings)\.(json|md)\b/gi,
205
+ expected: "the store's schema is the skill's business; the command must not restate it",
206
+ },
207
+ {
208
+ name: "complexity classification table",
209
+ re: /\|\s*(Simple|Standard|Complex|Moderate|Parallel)\s*\|/gi,
210
+ expected: "classification is the skill's routing decision, not the command's",
211
+ },
212
+ ];
213
+ /** Scan one command file for skill-owned prose. */
214
+ export function scanCommandForDrift(root, relPath) {
215
+ const abs = path.join(root, relPath);
216
+ if (!fs.existsSync(abs))
217
+ return [];
218
+ const findings = [];
219
+ const lines = fs.readFileSync(abs, "utf-8").split("\n");
220
+ const body = lines.join("\n");
221
+ for (const { re, expected } of COMMAND_DRIFT_PATTERNS) {
222
+ re.lastIndex = 0;
223
+ const m = re.exec(body);
224
+ if (!m)
225
+ continue;
226
+ // Locate the match's line for an actionable file:line.
227
+ const line = body.slice(0, m.index).split("\n").length;
228
+ if (lines[line - 1]?.includes(ALLOW_MARKER))
229
+ continue;
230
+ findings.push({ file: relPath, line, found: m[0].trim().slice(0, 80), expected });
231
+ }
232
+ return findings;
233
+ }
234
+ /**
235
+ * Command-vs-skill drift for every same-name pair.
236
+ *
237
+ * Scoped to PAIRED commands only. A standalone command (no matching skill) has
238
+ * nowhere to delegate its procedure to, so the same prose there is correct —
239
+ * per skill-authoring-rules.md, "not every command has a matching SKILL.md, and
240
+ * that is intentional".
241
+ */
242
+ export function checkCommandDrift(root) {
243
+ const commands = pairedCommands(root);
244
+ if (commands.length === 0) {
245
+ return [{ name: "Command-vs-skill drift", status: "pass", detail: "no same-name command/skill pairs", section: "Gates" }];
246
+ }
247
+ const findings = commands.flatMap((rel) => scanCommandForDrift(root, rel));
248
+ if (findings.length === 0) {
249
+ return [
250
+ {
251
+ name: "No command-vs-skill drift",
252
+ status: "pass",
253
+ detail: `${commands.length} paired command(s) are dispatchers: ${commands.map((c) => path.basename(c, ".md")).join(", ")}`,
254
+ section: "Gates",
255
+ },
256
+ ];
257
+ }
258
+ return [
259
+ {
260
+ name: `Command-vs-skill drift (${findings.length})`,
261
+ status: "fail",
262
+ detail: findings
263
+ .map((f) => `${f.file}:${f.line} found "${f.found}" — expected "${f.expected}"`)
264
+ .join("\n "),
265
+ section: "Gates",
266
+ },
267
+ ];
268
+ }
269
+ /**
270
+ * Run the gate-authority check over a tree of prose.
271
+ *
272
+ * `root` is the directory the scan is relative to; `scanDirs` are subtrees
273
+ * within it. Defaults to the canonical `.claude` tree, and is reused verbatim
274
+ * against the generated `plugin/` tree to prove canonical↔plugin parity.
275
+ */
276
+ export function checkGateAuthority(root, opts = {}) {
277
+ const scanDirs = opts.scanDirs ?? [".claude"];
278
+ const present = scanDirs.filter((dir) => fs.existsSync(path.join(root, dir)));
279
+ if (present.length === 0) {
280
+ return [
281
+ {
282
+ name: "Gate-authority scan target",
283
+ status: opts.missingRootSeverity ?? "fail",
284
+ detail: `No scan target found under ${root}: ${scanDirs.join(", ")}`,
285
+ section: "Gates",
286
+ },
287
+ ];
288
+ }
289
+ const files = present.flatMap((dir) => collectMarkdown(root, dir));
290
+ const violations = files.flatMap((rel) => scanForGateAuthority(root, rel));
291
+ if (violations.length === 0) {
292
+ return [
293
+ {
294
+ name: "No automated gate-approval claims",
295
+ status: "pass",
296
+ detail: `${files.length} prose files scanned across ${present.join(", ")}`,
297
+ section: "Gates",
298
+ },
299
+ ];
300
+ }
301
+ const detail = violations
302
+ .map((v) => `${v.file}:${v.line} found "${v.found}" — expected "${v.expected}"`)
303
+ .join("\n ");
304
+ return [
305
+ {
306
+ name: `Automated gate-approval claims (${violations.length})`,
307
+ status: "fail",
308
+ detail,
309
+ section: "Gates",
310
+ },
311
+ ];
312
+ }
313
+ //# sourceMappingURL=check-gate-authority.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"check-gate-authority.js","sourceRoot":"","sources":["../../src/core/check-gate-authority.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,12 @@
1
+ export type GenericCoreTokenCategory = "provider-tool" | "model-or-tier" | "context-window" | "brand";
2
+ export interface GenericCoreTokenFinding {
3
+ file: string;
4
+ line: number;
5
+ token: string;
6
+ category: GenericCoreTokenCategory;
7
+ }
8
+ /** Finds provider-specific prose in canonical skill bodies. Initial callers report, not block. */
9
+ export declare function findGenericCoreTokens(root: string, scanDir?: string): GenericCoreTokenFinding[];
10
+ /** Compact deterministic baseline for validation output and future cleanup tracking. */
11
+ export declare function summarizeGenericCoreTokens(findings: readonly GenericCoreTokenFinding[]): string;
12
+ //# sourceMappingURL=check-generic-core-tokens.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"check-generic-core-tokens.d.ts","sourceRoot":"","sources":["../../src/core/check-generic-core-tokens.ts"],"names":[],"mappings":"AAGA,MAAM,MAAM,wBAAwB,GAAG,eAAe,GAAG,eAAe,GAAG,gBAAgB,GAAG,OAAO,CAAC;AAEtG,MAAM,WAAW,uBAAuB;IACvC,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,wBAAwB,CAAC;CACnC;AA8CD,kGAAkG;AAClG,wBAAgB,qBAAqB,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,SAAW,GAAG,uBAAuB,EAAE,CAejG;AAED,wFAAwF;AACxF,wBAAgB,0BAA0B,CAAC,QAAQ,EAAE,SAAS,uBAAuB,EAAE,GAAG,MAAM,CAM/F"}
@@ -0,0 +1,67 @@
1
+ import fs from "node:fs";
2
+ import path from "node:path";
3
+ const TOKEN_RULES = [
4
+ { category: "provider-tool", pattern: /\bAskUserQuestion\b|\bAgent\s*\(|\bTask\s*\(/g },
5
+ { category: "model-or-tier", pattern: /\b(?:haiku|sonnet|opus|claude-[a-z0-9.-]+)\b/gi },
6
+ { category: "context-window", pattern: /\b\d{2,3}K\b|\b(?:[5-9]\d|100)%\s+(?:of\s+)?(?:the\s+)?(?:context|token)\b/gi },
7
+ { category: "brand", pattern: /\bmeowkit\b/gi },
8
+ ];
9
+ function markdownFiles(root, dir = "skills", files = []) {
10
+ const absolute = path.join(root, dir);
11
+ if (!fs.existsSync(absolute))
12
+ return files;
13
+ for (const entry of fs.readdirSync(absolute, { withFileTypes: true })) {
14
+ const relative = path.join(dir, entry.name);
15
+ if (entry.isDirectory())
16
+ markdownFiles(root, relative, files);
17
+ else if (dir !== "skills" && entry.isFile() && entry.name.endsWith(".md"))
18
+ files.push(relative);
19
+ }
20
+ return files.sort();
21
+ }
22
+ function bodyLines(content) {
23
+ const lines = content.split(/\r?\n/);
24
+ const bodyStart = lines[0] === "---" ? lines.indexOf("---", 1) + 1 : 0;
25
+ let codeFence = false;
26
+ return lines.slice(bodyStart).map((text, index) => {
27
+ if (/^\s*```/.test(text))
28
+ codeFence = !codeFence;
29
+ return { text, line: bodyStart + index + 1, codeFence };
30
+ });
31
+ }
32
+ function isCliBrandMention(line, index, token, codeFence) {
33
+ const before = line.slice(0, index);
34
+ const after = line.slice(index + token.length);
35
+ const lowercaseCommand = token === "mewkit" && /^\s+\S+/.test(after);
36
+ return ((lowercaseCommand && /\bnpx\s+$/i.test(before)) ||
37
+ (lowercaseCommand && (before.match(/\`/g)?.length ?? 0) % 2 === 1) ||
38
+ (codeFence && /^\s*(?:[$>]\s*)?(?:npx\s+)?mewkit\b/.test(line)));
39
+ }
40
+ /** Finds provider-specific prose in canonical skill bodies. Initial callers report, not block. */
41
+ export function findGenericCoreTokens(root, scanDir = "skills") {
42
+ const findings = [];
43
+ for (const file of markdownFiles(root, scanDir)) {
44
+ const lines = bodyLines(fs.readFileSync(path.join(root, file), "utf-8"));
45
+ for (const line of lines) {
46
+ for (const rule of TOKEN_RULES) {
47
+ rule.pattern.lastIndex = 0;
48
+ for (const match of line.text.matchAll(rule.pattern)) {
49
+ if (rule.category === "brand" && isCliBrandMention(line.text, match.index ?? 0, match[0], line.codeFence))
50
+ continue;
51
+ findings.push({ file, line: line.line, token: match[0], category: rule.category });
52
+ }
53
+ }
54
+ }
55
+ }
56
+ return findings;
57
+ }
58
+ /** Compact deterministic baseline for validation output and future cleanup tracking. */
59
+ export function summarizeGenericCoreTokens(findings) {
60
+ const counts = new Map();
61
+ for (const finding of findings)
62
+ counts.set(finding.category, (counts.get(finding.category) ?? 0) + 1);
63
+ return ["provider-tool", "model-or-tier", "context-window", "brand"]
64
+ .map((category) => `${category}=${counts.get(category) ?? 0}`)
65
+ .join(", ");
66
+ }
67
+ //# sourceMappingURL=check-generic-core-tokens.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"check-generic-core-tokens.js","sourceRoot":"","sources":["../../src/core/check-generic-core-tokens.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,27 @@
1
+ import { type LogicalOperation, type OperationSupport } from "./provider-operations.js";
2
+ /**
3
+ * Claude Code host tool → the logical operation it realizes. Trusted constant; a unit
4
+ * test asserts every value is a real `LogicalOperation`, so it can never drift from the
5
+ * operation set. Keys are BASE tool names (scoped forms like `Bash(git:*)` are normalized
6
+ * to `Bash` before lookup).
7
+ */
8
+ export declare const TOOL_TO_OPERATION: Record<string, LogicalOperation>;
9
+ export interface OperationConformanceFinding {
10
+ skill: string;
11
+ operation: LogicalOperation;
12
+ provider: string;
13
+ support: OperationSupport;
14
+ }
15
+ /**
16
+ * For every installed skill, resolve the operations it references (via declared tools)
17
+ * and record, per advertised provider, each operation whose support is not `supported`.
18
+ * Disclosed degradation (`local-fallback`) and hard gaps (`unsupported`/`unknown`) are all
19
+ * surfaced so a cross-harness projection never advertises an operation the host cannot honor.
20
+ */
21
+ export declare function findOperationConformance(claudeDir: string): OperationConformanceFinding[];
22
+ /** `unsupported`/`unknown` = the operation genuinely fails or is untested on that provider;
23
+ * `local-fallback` = disclosed graceful degradation. Only the former are blocking-worthy. */
24
+ export declare function isBlockingGap(finding: OperationConformanceFinding): boolean;
25
+ /** Compact deterministic per-provider summary for validate output. */
26
+ export declare function summarizeOperationConformance(findings: readonly OperationConformanceFinding[]): string;
27
+ //# sourceMappingURL=check-operation-conformance.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"check-operation-conformance.d.ts","sourceRoot":"","sources":["../../src/core/check-operation-conformance.ts"],"names":[],"mappings":"AAYA,OAAO,EAAqB,KAAK,gBAAgB,EAAE,KAAK,gBAAgB,EAAE,MAAM,0BAA0B,CAAC;AAE3G;;;;;GAKG;AACH,eAAO,MAAM,iBAAiB,EAAE,MAAM,CAAC,MAAM,EAAE,gBAAgB,CAS9D,CAAC;AAyBF,MAAM,WAAW,2BAA2B;IAC3C,KAAK,EAAE,MAAM,CAAC;IACd,SAAS,EAAE,gBAAgB,CAAC;IAC5B,QAAQ,EAAE,MAAM,CAAC;IACjB,OAAO,EAAE,gBAAgB,CAAC;CAC1B;AAED;;;;;GAKG;AACH,wBAAgB,wBAAwB,CAAC,SAAS,EAAE,MAAM,GAAG,2BAA2B,EAAE,CAczF;AAED;6FAC6F;AAC7F,wBAAgB,aAAa,CAAC,OAAO,EAAE,2BAA2B,GAAG,OAAO,CAE3E;AAED,sEAAsE;AACtE,wBAAgB,6BAA6B,CAAC,QAAQ,EAAE,SAAS,2BAA2B,EAAE,GAAG,MAAM,CAOtG"}
@@ -0,0 +1,91 @@
1
+ // Operation-level conformance: which logical operations does each installed skill
2
+ // reference, and are they honored on every advertised provider? Without this, a
3
+ // cross-harness payload can silently ship a skill whose operation the target host
4
+ // cannot perform — the exact "silent degrade" the portability work exists to prevent.
5
+ //
6
+ // The reference signal is a skill's `allowed-tools` frontmatter: the host tools its
7
+ // author declared. That is DESCRIPTIVE metadata, not a runnable string — each tool
8
+ // maps to a LOGICAL operation through a trusted constant, exactly as `invocation.id`
9
+ // does. Frontmatter still cannot NAME a logical operation (see provider-operations.ts):
10
+ // it names a host tool; the adapter, not the author, resolves the operation.
11
+ import { enumerateArtifacts, readFrontmatter } from "./build-inventory.js";
12
+ import { ADAPTED_PROVIDERS } from "./provider-adapter.js";
13
+ import { getOperationShape } from "./provider-operations.js";
14
+ /**
15
+ * Claude Code host tool → the logical operation it realizes. Trusted constant; a unit
16
+ * test asserts every value is a real `LogicalOperation`, so it can never drift from the
17
+ * operation set. Keys are BASE tool names (scoped forms like `Bash(git:*)` are normalized
18
+ * to `Bash` before lookup).
19
+ */
20
+ export const TOOL_TO_OPERATION = {
21
+ AskUserQuestion: "ask_user",
22
+ Bash: "run_shell",
23
+ Agent: "delegate_agent",
24
+ Task: "delegate_agent",
25
+ TaskCreate: "manage_plan",
26
+ TaskUpdate: "manage_plan",
27
+ TaskList: "manage_plan",
28
+ TaskGet: "manage_plan",
29
+ };
30
+ /** `Bash(git:*)` → `Bash`, `Task(Explore)` → `Task`, ` Read ` → `Read`. */
31
+ function baseToolName(raw) {
32
+ return raw.trim().replace(/\(.*$/, "").trim();
33
+ }
34
+ /** Read a skill's declared host tools from `allowed-tools` (YAML array or comma scalar). */
35
+ function declaredTools(meta) {
36
+ const value = meta["allowed-tools"];
37
+ if (Array.isArray(value))
38
+ return value.filter((tool) => typeof tool === "string");
39
+ if (typeof value === "string")
40
+ return value.split(",").map((tool) => tool.trim()).filter(Boolean);
41
+ return [];
42
+ }
43
+ /** The distinct logical operations a set of declared tools references. */
44
+ function operationsForTools(tools) {
45
+ const operations = new Set();
46
+ for (const tool of tools) {
47
+ const operation = TOOL_TO_OPERATION[baseToolName(tool)];
48
+ if (operation)
49
+ operations.add(operation);
50
+ }
51
+ return [...operations];
52
+ }
53
+ /**
54
+ * For every installed skill, resolve the operations it references (via declared tools)
55
+ * and record, per advertised provider, each operation whose support is not `supported`.
56
+ * Disclosed degradation (`local-fallback`) and hard gaps (`unsupported`/`unknown`) are all
57
+ * surfaced so a cross-harness projection never advertises an operation the host cannot honor.
58
+ */
59
+ export function findOperationConformance(claudeDir) {
60
+ const { refs } = enumerateArtifacts(claudeDir);
61
+ const findings = [];
62
+ for (const ref of refs) {
63
+ if (ref.type !== "skill")
64
+ continue;
65
+ const operations = operationsForTools(declaredTools(readFrontmatter(ref.abs)));
66
+ for (const operation of operations) {
67
+ for (const provider of ADAPTED_PROVIDERS) {
68
+ const support = getOperationShape(provider, operation).support;
69
+ if (support !== "supported")
70
+ findings.push({ skill: ref.id, operation, provider, support });
71
+ }
72
+ }
73
+ }
74
+ return findings;
75
+ }
76
+ /** `unsupported`/`unknown` = the operation genuinely fails or is untested on that provider;
77
+ * `local-fallback` = disclosed graceful degradation. Only the former are blocking-worthy. */
78
+ export function isBlockingGap(finding) {
79
+ return finding.support === "unsupported" || finding.support === "unknown";
80
+ }
81
+ /** Compact deterministic per-provider summary for validate output. */
82
+ export function summarizeOperationConformance(findings) {
83
+ const byProvider = new Map();
84
+ for (const finding of findings)
85
+ byProvider.set(finding.provider, (byProvider.get(finding.provider) ?? 0) + 1);
86
+ return [...byProvider.entries()]
87
+ .sort(([a], [b]) => (a < b ? -1 : a > b ? 1 : 0))
88
+ .map(([provider, count]) => `${provider}=${count}`)
89
+ .join(", ");
90
+ }
91
+ //# sourceMappingURL=check-operation-conformance.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"check-operation-conformance.js","sourceRoot":"","sources":["../../src/core/check-operation-conformance.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,15 @@
1
+ import type { CheckResult } from "../commands/validate.js";
2
+ export interface ParityDivergence {
3
+ file: string;
4
+ kind: "missing-in-plugin" | "stale-in-plugin" | "extra-in-plugin";
5
+ }
6
+ /**
7
+ * Regenerate the payload into a temp dir and diff it against `plugin/`.
8
+ *
9
+ * Returns every divergence. The caller decides severity — `validate` fails, so
10
+ * that a stale plugin cannot reach a release.
11
+ */
12
+ export declare function diffPluginParity(projectRoot: string): ParityDivergence[];
13
+ /** Parity as a validate CheckResult. */
14
+ export declare function checkPluginParity(projectRoot: string): CheckResult[];
15
+ //# sourceMappingURL=check-plugin-parity.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"check-plugin-parity.d.ts","sourceRoot":"","sources":["../../src/core/check-plugin-parity.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,yBAAyB,CAAC;AAqC3D,MAAM,WAAW,gBAAgB;IAChC,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,mBAAmB,GAAG,iBAAiB,GAAG,iBAAiB,CAAC;CAClE;AAED;;;;;GAKG;AACH,wBAAgB,gBAAgB,CAAC,WAAW,EAAE,MAAM,GAAG,gBAAgB,EAAE,CAuCxE;AAED,wCAAwC;AACxC,wBAAgB,iBAAiB,CAAC,WAAW,EAAE,MAAM,GAAG,WAAW,EAAE,CA6CpE"}