@modootoday/pmcp 0.8.2 → 0.9.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.
package/README.md CHANGED
@@ -142,6 +142,22 @@ breaks the specification is reported, and `pmcp validate [<skill-dir>...]` check
142
142
  directories or every skill the catalog reaches (name rules and length, description and
143
143
  compatibility length, field types, name matching the directory, duplicate names).
144
144
 
145
+ `metadata` keeps strings, string lists and maps of those one level down, so
146
+ `requires: {mcp, bin, env, capabilities, gpu-gb}` reaches `skill_describe`; deeper
147
+ nesting is dropped.
148
+
149
+ Since 0.9.0 a skill can list `metadata.verified-runtimes`, a list drawn from `claude-code`,
150
+ `codex-cli`, `gemini-cli`, `grok-cli` and `antigravity`, meaning its effect was verified on
151
+ that runtime. `skill_find` and `skill_catalog` items carry `verifiedRuntimes` (omitted when
152
+ empty) and accept `runtime` and `verifiedOnly`. `runtime` never removes a skill: it marks
153
+ each item `verified` and lists verified ones first (within a package group in
154
+ `skill_catalog`). `verifiedOnly` drops the rest, keeping those verified on `runtime`, or on
155
+ any runtime when none is given. Without `runtime` the answer is ordered exactly as before.
156
+ A server can opt in with `rankByClientRuntime: true`: then, when `runtime` is not passed and
157
+ the MCP client's name is recognised (`claude-code`, `codex`, `gemini`, `grok`,
158
+ `antigravity`), that runtime is used for the ordering only, never for filtering.
159
+ `skill_find` answers with `runtime`, the one the ordering used, or `null`.
160
+
145
161
  `pmcp serve --prompts` also offers one prompt per skill, for hosts that turn prompts into
146
162
  commands; the prompt's text is the skill body and its file list, with an optional `task`.
147
163
 
@@ -1,3 +1,26 @@
1
+ /**
2
+ * SKILL.md frontmatter, read as YAML the way a host reads it, and checked against
3
+ * the Agent Skills specification (https://agentskills.io/specification).
4
+ */
5
+ type MetadataLeaf = string | readonly string[];
6
+ /** A metadata value: a leaf, or a map of leaves one level below the metadata key. */
7
+ type MetadataValue = MetadataLeaf | {
8
+ readonly [key: string]: MetadataLeaf;
9
+ };
10
+ /**
11
+ * Parsed frontmatter. A value with an unquoted ": " is a common authoring slip
12
+ * the client guide says to recover from by quoting it, so that is retried once.
13
+ */
14
+ declare function frontmatterObject(source: string): Record<string, unknown> | null;
15
+ declare const NAME_MAX = 64;
16
+ declare const DESCRIPTION_MAX = 1024;
17
+ declare const COMPATIBILITY_MAX = 500;
18
+ /**
19
+ * What the specification requires of one SKILL.md, as messages; empty when valid.
20
+ * directory is the name of the folder holding it.
21
+ */
22
+ declare function specProblems(front: Record<string, unknown> | null, directory: string): string[];
23
+
1
24
  /**
2
25
  * The skills the installed packages brought with them.
3
26
  *
@@ -5,6 +28,7 @@
5
28
  * maintains: installing a package is how its skill arrives and uninstalling it
6
29
  * is how the skill leaves, so the catalog is always true of the project.
7
30
  */
31
+
8
32
  interface SkillEntry {
9
33
  /** `<package>/<slug>`. Unique, and stable while the package is installed. */
10
34
  readonly name: string;
@@ -16,8 +40,8 @@ interface SkillEntry {
16
40
  readonly path: string;
17
41
  /** open, free or paid. Set for marketplace skills, absent for packages. */
18
42
  readonly tier?: string;
19
- /** The frontmatter `metadata:` block, one level deep. */
20
- readonly metadata?: Readonly<Record<string, string | readonly string[]>>;
43
+ /** The frontmatter `metadata:` block; maps such as `requires` are kept one level down. */
44
+ readonly metadata?: Readonly<Record<string, MetadataValue>>;
21
45
  /** Extra search terms. Ranked with the description, never used as triggers. */
22
46
  readonly keywords?: readonly string[];
23
47
  /** What the entry is. Absent means a skill. */
@@ -94,4 +118,4 @@ declare function withoutBody({ path, ...rest }: SkillEntry): Omit<SkillEntry, "p
94
118
  /** Path relative to a root, for a message a reader can act on. */
95
119
  declare function displayPath(root: string, entry: SkillEntry): string;
96
120
 
97
- export { type AssetKind as A, type CatalogOptions as C, MAX_SKILL_DEPTH as M, type SkillEntry as S, ASSET_KINDS as a, SKIPPED_DIRS as b, readCatalog as c, displayPath as d, readFrontmatter as e, kindOf as k, readBody as r, withoutBody as w };
121
+ export { type AssetKind as A, type CatalogOptions as C, DESCRIPTION_MAX as D, type MetadataValue as M, NAME_MAX as N, type SkillEntry as S, ASSET_KINDS as a, COMPATIBILITY_MAX as b, MAX_SKILL_DEPTH as c, type MetadataLeaf as d, SKIPPED_DIRS as e, displayPath as f, frontmatterObject as g, readCatalog as h, readFrontmatter as i, kindOf as k, readBody as r, specProblems as s, withoutBody as w };
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  normaliseIntent
3
- } from "./chunk-UGRHZHHC.js";
3
+ } from "./chunk-PXNRZXL6.js";
4
4
 
5
5
  // src/cache.ts
6
6
  async function openDatabase(path) {
@@ -131,4 +131,4 @@ export {
131
131
  DEFAULT_INTENT_CACHE_LIMIT,
132
132
  openIntentCache
133
133
  };
134
- //# sourceMappingURL=chunk-IRQTGYHA.js.map
134
+ //# sourceMappingURL=chunk-AKPSLZRJ.js.map
@@ -2,7 +2,7 @@ import {
2
2
  frontmatterObject,
3
3
  readCatalog,
4
4
  specProblems
5
- } from "./chunk-UGRHZHHC.js";
5
+ } from "./chunk-PXNRZXL6.js";
6
6
 
7
7
  // src/config.ts
8
8
  import { existsSync, readFileSync } from "fs";
@@ -1139,4 +1139,4 @@ export {
1139
1139
  validateSkillDir,
1140
1140
  validateCatalog
1141
1141
  };
1142
- //# sourceMappingURL=chunk-O2P5AIHX.js.map
1142
+ //# sourceMappingURL=chunk-PWEAKJZ3.js.map
@@ -47,15 +47,31 @@ function stringFields(front) {
47
47
  }
48
48
  return out;
49
49
  }
50
+ function leafOf(value) {
51
+ if (typeof value === "string") return value;
52
+ if (typeof value === "number" || typeof value === "boolean")
53
+ return String(value);
54
+ if (Array.isArray(value))
55
+ return value.filter((v) => typeof v === "string");
56
+ return void 0;
57
+ }
50
58
  function metadataOf(front) {
51
59
  const out = {};
52
60
  const meta = asObject(front?.["metadata"]);
53
61
  for (const [key, value] of Object.entries(meta ?? {})) {
54
- if (typeof value === "string") out[key] = value;
55
- else if (typeof value === "number" || typeof value === "boolean")
56
- out[key] = String(value);
57
- else if (Array.isArray(value))
58
- out[key] = value.filter((v) => typeof v === "string");
62
+ const leaf = leafOf(value);
63
+ if (leaf !== void 0) {
64
+ out[key] = leaf;
65
+ continue;
66
+ }
67
+ const nested = asObject(value);
68
+ if (nested === null) continue;
69
+ const map = {};
70
+ for (const [inner, innerValue] of Object.entries(nested)) {
71
+ const innerLeaf = leafOf(innerValue);
72
+ if (innerLeaf !== void 0) map[inner] = innerLeaf;
73
+ }
74
+ if (Object.keys(map).length > 0) out[key] = map;
59
75
  }
60
76
  return out;
61
77
  }
@@ -377,7 +393,8 @@ function readFrontmatterText(source) {
377
393
  var asString = (value) => typeof value === "string" ? value : void 0;
378
394
  var asList = (value) => {
379
395
  if (value === void 0) return [];
380
- return typeof value === "string" ? [value] : value;
396
+ if (typeof value === "string") return [value];
397
+ return Array.isArray(value) ? value : [];
381
398
  };
382
399
  function readJson(path) {
383
400
  try {
@@ -1018,6 +1035,44 @@ function bundleSkill(entry) {
1018
1035
  };
1019
1036
  }
1020
1037
 
1038
+ // src/runtime.ts
1039
+ import { CLIENT_INFO_META_KEY } from "@modelcontextprotocol/server";
1040
+ var RUNTIMES = [
1041
+ "claude-code",
1042
+ "codex-cli",
1043
+ "gemini-cli",
1044
+ "grok-cli",
1045
+ "antigravity"
1046
+ ];
1047
+ var VERIFIED_RUNTIMES_KEY = "verified-runtimes";
1048
+ var isRuntime = (value) => RUNTIMES.includes(value);
1049
+ function verifiedRuntimesOf(metadata) {
1050
+ const raw = metadata?.[VERIFIED_RUNTIMES_KEY];
1051
+ if (raw === void 0) return [];
1052
+ const words = typeof raw === "string" ? raw.split(/[\s,]+/u) : Array.isArray(raw) ? raw.map((word) => String(word).trim()) : [];
1053
+ return [...new Set(words.filter(isRuntime))];
1054
+ }
1055
+ var CLIENT_PATTERNS = [
1056
+ [/claude[-_ ]?code/u, "claude-code"],
1057
+ [/codex/u, "codex-cli"],
1058
+ [/gemini/u, "gemini-cli"],
1059
+ [/grok/u, "grok-cli"],
1060
+ [/antigravity/u, "antigravity"]
1061
+ ];
1062
+ function runtimeOfClient(name) {
1063
+ if (!name) return null;
1064
+ const lower = name.toLowerCase();
1065
+ for (const [pattern, runtime] of CLIENT_PATTERNS)
1066
+ if (pattern.test(lower)) return runtime;
1067
+ return null;
1068
+ }
1069
+ function detectRuntime(server, ctx) {
1070
+ const envelope = ctx?.mcpReq?.envelope;
1071
+ const fromEnvelope = envelope?.[CLIENT_INFO_META_KEY]?.name;
1072
+ if (typeof fromEnvelope === "string") return runtimeOfClient(fromEnvelope);
1073
+ return runtimeOfClient(server.server?.getClientVersion?.()?.name);
1074
+ }
1075
+
1021
1076
  // src/server.ts
1022
1077
  import { readFileSync as readFileSync6 } from "fs";
1023
1078
  var DESCRIBE_FILE_LIMIT = FILE_LIST_LIMIT;
@@ -1041,14 +1096,33 @@ function matches(entry, filters) {
1041
1096
  return false;
1042
1097
  if (filters.medium !== void 0 && field("medium") !== filters.medium)
1043
1098
  return false;
1099
+ if (filters.verifiedOnly) {
1100
+ const verified = verifiedRuntimesOf(entry.metadata);
1101
+ if (filters.runtime === void 0) return verified.length > 0;
1102
+ return verified.includes(filters.runtime);
1103
+ }
1044
1104
  return true;
1045
1105
  }
1046
- function catalogItem(entry) {
1106
+ function verification(entry, runtime) {
1107
+ const verifiedRuntimes = verifiedRuntimesOf(entry?.metadata);
1108
+ return {
1109
+ ...verifiedRuntimes.length > 0 ? { verifiedRuntimes } : {},
1110
+ ...runtime === null ? {} : { verified: verifiedRuntimes.includes(runtime) }
1111
+ };
1112
+ }
1113
+ function verifiedFirst(items) {
1114
+ return [
1115
+ ...items.filter((item) => item.verified === true),
1116
+ ...items.filter((item) => item.verified !== true)
1117
+ ];
1118
+ }
1119
+ function catalogItem(entry, runtime) {
1047
1120
  return {
1048
1121
  name: entry.name,
1049
1122
  description: entry.description,
1050
1123
  ...entry.tier === void 0 ? {} : { tier: entry.tier },
1051
- ...kindOf(entry) === "skill" ? {} : { kind: kindOf(entry) }
1124
+ ...kindOf(entry) === "skill" ? {} : { kind: kindOf(entry) },
1125
+ ...verification(entry, runtime)
1052
1126
  };
1053
1127
  }
1054
1128
  function createSkillTools(options) {
@@ -1073,19 +1147,27 @@ function createSkillTools(options) {
1073
1147
  * path. Paged by package so a large catalog never arrives in one answer.
1074
1148
  */
1075
1149
  catalog(request = {}) {
1150
+ const client = options.rankByClientRuntime ? request.clientRuntime : null;
1151
+ const runtime = request.runtime ?? client ?? null;
1076
1152
  const byPackage = /* @__PURE__ */ new Map();
1077
1153
  let count = 0;
1078
1154
  for (const entry of catalog()) {
1079
- if (!matches(entry, { tier: request.tier, kind: request.kind }))
1155
+ if (!matches(entry, {
1156
+ tier: request.tier,
1157
+ kind: request.kind,
1158
+ runtime: request.runtime,
1159
+ verifiedOnly: request.verifiedOnly
1160
+ }))
1080
1161
  continue;
1081
1162
  count += 1;
1082
1163
  const list = byPackage.get(entry.package) ?? [];
1083
- list.push(catalogItem(entry));
1164
+ list.push(catalogItem(entry, runtime));
1084
1165
  byPackage.set(entry.package, list);
1085
1166
  }
1086
- const groups = [...byPackage.entries()].sort(
1087
- ([a], [b]) => a.localeCompare(b)
1088
- );
1167
+ const groups = [...byPackage.entries()].sort(([a], [b]) => a.localeCompare(b)).map(([pkg, skills]) => [
1168
+ pkg,
1169
+ runtime === null ? skills : verifiedFirst(skills)
1170
+ ]);
1089
1171
  const size = Math.min(
1090
1172
  Math.max(request.pageSize ?? CATALOG_PAGE_SIZE, 1),
1091
1173
  CATALOG_PAGE_MAX
@@ -1101,7 +1183,9 @@ function createSkillTools(options) {
1101
1183
  };
1102
1184
  },
1103
1185
  /** Ranked names. Returns; never loads a body. */
1104
- find(intent, limit, filters) {
1186
+ find(intent, limit, filters, clientRuntime) {
1187
+ const client = options.rankByClientRuntime ? clientRuntime : null;
1188
+ const runtime = filters?.runtime ?? client ?? null;
1105
1189
  const scoped = catalog().filter((entry) => matches(entry, filters)).map(
1106
1190
  (entry) => entry.keywords && entry.keywords.length > 0 ? {
1107
1191
  ...entry,
@@ -1111,17 +1195,26 @@ function createSkillTools(options) {
1111
1195
  return find({
1112
1196
  entries: scoped,
1113
1197
  intent,
1114
- limit,
1198
+ limit: runtime === null ? limit : scoped.length,
1115
1199
  embedder: options.embedder,
1116
1200
  cache: options.cache,
1117
1201
  vectors: options.vectors
1118
- }).then((result) => ({
1119
- ...result,
1120
- matches: result.matches.map((match) => ({
1121
- ...match,
1122
- description: catalog().find((entry) => entry.name === match.name)?.description ?? match.description
1123
- }))
1124
- }));
1202
+ }).then((result) => {
1203
+ const marked = result.matches.map((match) => {
1204
+ const entry = byName(match.name) ?? void 0;
1205
+ return {
1206
+ ...match,
1207
+ description: entry?.description ?? match.description,
1208
+ ...verification(entry, runtime)
1209
+ };
1210
+ });
1211
+ const ordered = runtime === null ? marked : verifiedFirst(marked);
1212
+ return {
1213
+ ...result,
1214
+ runtime,
1215
+ matches: runtime === null ? ordered : ordered.slice(0, limit ?? DEFAULT_FIND_LIMIT)
1216
+ };
1217
+ });
1125
1218
  },
1126
1219
  /** Every property of one skill and the files it carries, without bodies. */
1127
1220
  describe(name) {
@@ -1310,11 +1403,14 @@ function registerSkillsExtension(server, skills, options = {}) {
1310
1403
  // src/tools/schemas.ts
1311
1404
  import { z as z3 } from "zod";
1312
1405
  var kind = z3.enum(ASSET_KINDS);
1406
+ var runtimeSchema = z3.enum(RUNTIMES);
1313
1407
  var catalogItemSchema = z3.object({
1314
1408
  name: z3.string(),
1315
1409
  description: z3.string(),
1316
1410
  tier: z3.string().optional(),
1317
- kind: kind.optional()
1411
+ kind: kind.optional(),
1412
+ verifiedRuntimes: z3.array(runtimeSchema).optional(),
1413
+ verified: z3.boolean().optional()
1318
1414
  });
1319
1415
  var catalogResponseSchema = z3.object({
1320
1416
  count: z3.number().int(),
@@ -1327,12 +1423,15 @@ var catalogResponseSchema = z3.object({
1327
1423
  });
1328
1424
  var findResultSchema = z3.object({
1329
1425
  ranking: z3.enum(["semantic", "lexical"]),
1426
+ runtime: runtimeSchema.nullable(),
1330
1427
  matches: z3.array(
1331
1428
  z3.object({
1332
1429
  name: z3.string(),
1333
1430
  package: z3.string(),
1334
1431
  description: z3.string(),
1335
- score: z3.number()
1432
+ score: z3.number(),
1433
+ verifiedRuntimes: z3.array(runtimeSchema).optional(),
1434
+ verified: z3.boolean().optional()
1336
1435
  })
1337
1436
  )
1338
1437
  });
@@ -1341,6 +1440,10 @@ var skillFileSchema = z3.object({
1341
1440
  bytes: z3.number().int(),
1342
1441
  sha256: z3.string()
1343
1442
  });
1443
+ var metadataLeafSchema = z3.union([
1444
+ z3.string(),
1445
+ z3.array(z3.string()).readonly()
1446
+ ]);
1344
1447
  var describeResponseSchema = z3.object({
1345
1448
  name: z3.string(),
1346
1449
  kind,
@@ -1349,7 +1452,10 @@ var describeResponseSchema = z3.object({
1349
1452
  tier: z3.string().optional(),
1350
1453
  metadata: z3.record(
1351
1454
  z3.string(),
1352
- z3.union([z3.string(), z3.array(z3.string()).readonly()])
1455
+ z3.union([
1456
+ metadataLeafSchema,
1457
+ z3.record(z3.string(), metadataLeafSchema).readonly()
1458
+ ])
1353
1459
  ),
1354
1460
  frontmatter: z3.string(),
1355
1461
  files: z3.array(skillFileSchema),
@@ -1414,6 +1520,12 @@ var kindInput = z4.enum(["skill", "agent", "hook", "mcp", "any"]).optional().des
1414
1520
  "skill (default), agent, hook, mcp, or any. Commands are skills; agents, hooks and MCP servers are installed with pmcp add rather than read."
1415
1521
  );
1416
1522
  var tierInput = z4.enum(["open", "free", "paid", "internal"]).optional();
1523
+ var runtimeInput = runtimeSchema.optional().describe(
1524
+ "A runtime (claude-code, codex-cli, gemini-cli, grok-cli, antigravity). Skills whose metadata.verified-runtimes lists it are marked verified and listed first; the rest are kept. Without it, the runtime of the connected client is used for the same ordering when it is recognised."
1525
+ );
1526
+ var verifiedOnlyInput = z4.boolean().optional().describe(
1527
+ "Drop skills that are not verified: on the given runtime, or on any runtime when none is given. The detected client runtime never filters."
1528
+ );
1417
1529
  var skillNameInput = z4.string().min(1).describe("A skill name as skill_find or skill_catalog returns it.");
1418
1530
  var asText = (value) => ({
1419
1531
  content: [{ type: "text", text: JSON.stringify(value, null, 2) }]
@@ -1502,16 +1614,23 @@ function registerCatalogTool(server, tools) {
1502
1614
  "skill_catalog",
1503
1615
  {
1504
1616
  ...readOnlyTool("List skills"),
1505
- description: "Every skill the installed packages and marketplaces ship, grouped by package or plugin, with names, one-line descriptions and tier, and no bodies. Paged by group. With kind it lists agents, hooks or MCP servers instead.",
1617
+ description: "Every skill the installed packages and marketplaces ship, grouped by package or plugin, with names, one-line descriptions and tier, and no bodies. Paged by group. With kind it lists agents, hooks or MCP servers instead. Items list the runtimes they were verified on (verifiedRuntimes). With runtime, verified items are marked and listed first within their group but the others are kept; verifiedOnly drops the unverified ones.",
1506
1618
  inputSchema: z7.object({
1507
1619
  page: z7.number().int().min(1).optional(),
1508
1620
  pageSize: z7.number().int().min(1).max(20).optional(),
1509
1621
  tier: tierInput,
1510
- kind: kindInput
1622
+ kind: kindInput,
1623
+ runtime: runtimeInput,
1624
+ verifiedOnly: verifiedOnlyInput
1511
1625
  }),
1512
1626
  outputSchema: catalogResponseSchema
1513
1627
  },
1514
- async (request) => structured(tools.catalog(request))
1628
+ async (request, ctx) => structured(
1629
+ tools.catalog({
1630
+ ...request,
1631
+ clientRuntime: detectRuntime(server, ctx)
1632
+ })
1633
+ )
1515
1634
  );
1516
1635
  }
1517
1636
 
@@ -1522,7 +1641,7 @@ function registerDescribeTool(server, tools) {
1522
1641
  "skill_describe",
1523
1642
  {
1524
1643
  ...readOnlyTool("Describe a skill"),
1525
- description: "One skill's frontmatter, metadata (tier, level, requirements, licence, approval), and the files it carries with sizes and sha256, without any body.",
1644
+ description: "One skill's frontmatter, metadata (tier, level, requirements as a nested requires map, verified-runtimes, licence, approval), and the files it carries with sizes and sha256, without any body.",
1526
1645
  inputSchema: z8.object({ name: skillNameInput }),
1527
1646
  outputSchema: describeResponseSchema
1528
1647
  },
@@ -1540,10 +1659,12 @@ function registerFindTool(server, tools) {
1540
1659
  "skill_find",
1541
1660
  {
1542
1661
  ...readOnlyTool("Find skills"),
1543
- description: "Skill names ranked against an intent, with descriptions and scores, and no bodies. The ranking compares the intent with skill descriptions, so a full sentence matches better than a single keyword.",
1662
+ description: "Skill names ranked against an intent, with descriptions and scores, and no bodies. The ranking compares the intent with skill descriptions, so a full sentence matches better than a single keyword. Each match lists the runtimes it was verified on (verifiedRuntimes). With runtime, verified matches are marked and listed first but the others are kept; verifiedOnly drops the unverified ones. The answer's runtime is the one the ordering used, or null.",
1544
1663
  inputSchema: z9.object({
1545
1664
  intent: z9.string().min(1).max(256).describe("What the task is, as a sentence."),
1546
1665
  limit: z9.number().int().min(1).max(25).optional(),
1666
+ runtime: runtimeInput,
1667
+ verifiedOnly: verifiedOnlyInput,
1547
1668
  filters: z9.object({
1548
1669
  kind: kindInput,
1549
1670
  tier: tierInput,
@@ -1555,7 +1676,14 @@ function registerFindTool(server, tools) {
1555
1676
  }),
1556
1677
  outputSchema: findResultSchema
1557
1678
  },
1558
- async ({ intent, limit, filters }) => structured(await tools.find(intent, limit, filters))
1679
+ async ({ intent, limit, runtime, verifiedOnly, filters }, ctx) => structured(
1680
+ await tools.find(
1681
+ intent,
1682
+ limit,
1683
+ { ...filters, runtime, verifiedOnly },
1684
+ detectRuntime(server, ctx)
1685
+ )
1686
+ )
1559
1687
  );
1560
1688
  }
1561
1689
 
@@ -1590,7 +1718,7 @@ function registerReadTool(server, tools) {
1590
1718
 
1591
1719
  // src/mcp.ts
1592
1720
  var SERVER_NAME = "pmcp";
1593
- var SERVER_VERSION = "0.8.2";
1721
+ var SERVER_VERSION = "0.9.0";
1594
1722
  function registerSkillTools(server, tools) {
1595
1723
  registerCatalogTool(server, tools);
1596
1724
  registerFindTool(server, tools);
@@ -1645,6 +1773,10 @@ export {
1645
1773
  cosine,
1646
1774
  find,
1647
1775
  bundleSkill,
1776
+ RUNTIMES,
1777
+ verifiedRuntimesOf,
1778
+ runtimeOfClient,
1779
+ detectRuntime,
1648
1780
  DESCRIBE_FILE_LIMIT,
1649
1781
  CATALOG_PAGE_SIZE,
1650
1782
  CATALOG_PAGE_MAX,
@@ -1661,4 +1793,4 @@ export {
1661
1793
  registerSkillTools,
1662
1794
  createSkillServer
1663
1795
  };
1664
- //# sourceMappingURL=chunk-UGRHZHHC.js.map
1796
+ //# sourceMappingURL=chunk-PXNRZXL6.js.map
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  openDatabase
3
- } from "./chunk-IRQTGYHA.js";
3
+ } from "./chunk-AKPSLZRJ.js";
4
4
 
5
5
  // src/embed.ts
6
6
  var DEFAULT_MODEL_ID = "Xenova/multilingual-e5-small";
@@ -157,4 +157,4 @@ export {
157
157
  encodeEntries,
158
158
  openEntryVectors
159
159
  };
160
- //# sourceMappingURL=chunk-3JNWCUHA.js.map
160
+ //# sourceMappingURL=chunk-RYOLBTSW.js.map
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  createSkillServer
3
- } from "./chunk-UGRHZHHC.js";
3
+ } from "./chunk-PXNRZXL6.js";
4
4
 
5
5
  // src/stdio.ts
6
6
  import { serveStdio } from "@modelcontextprotocol/server/stdio";
@@ -38,4 +38,4 @@ export {
38
38
  serve,
39
39
  main
40
40
  };
41
- //# sourceMappingURL=chunk-UW7HTILA.js.map
41
+ //# sourceMappingURL=chunk-Y7UX36AC.js.map
package/dist/cli.js CHANGED
@@ -2,7 +2,7 @@
2
2
  import {
3
3
  loadEmbedder,
4
4
  openEntryVectors
5
- } from "./chunk-3JNWCUHA.js";
5
+ } from "./chunk-RYOLBTSW.js";
6
6
  import {
7
7
  ConfigError,
8
8
  ProjectError,
@@ -17,15 +17,15 @@ import {
17
17
  splitFrontmatter,
18
18
  validateCatalog,
19
19
  validateSkillDir
20
- } from "./chunk-O2P5AIHX.js";
21
- import "./chunk-IRQTGYHA.js";
20
+ } from "./chunk-PWEAKJZ3.js";
21
+ import "./chunk-AKPSLZRJ.js";
22
22
  import {
23
23
  serve
24
- } from "./chunk-UW7HTILA.js";
24
+ } from "./chunk-Y7UX36AC.js";
25
25
  import {
26
26
  kindOf,
27
27
  readCatalog
28
- } from "./chunk-UGRHZHHC.js";
28
+ } from "./chunk-PXNRZXL6.js";
29
29
 
30
30
  // src/cli/command.ts
31
31
  var ArgumentError = class extends Error {
@@ -2347,7 +2347,7 @@ function dispatch(argv, options = {}) {
2347
2347
  }
2348
2348
  return run(command, rest, { ui, env, cwd });
2349
2349
  }
2350
- var VERSION = "0.8.2";
2350
+ var VERSION = "0.9.0";
2351
2351
  async function run(command, argv, context) {
2352
2352
  try {
2353
2353
  return await command.run({
package/dist/http.d.ts CHANGED
@@ -1,5 +1,5 @@
1
- import { S as SkillEntry } from './catalog-CS0j6-0U.js';
2
- import { E as Embedder, S as SkillServerOptions } from './server-CLyCpwZb.js';
1
+ import { S as SkillEntry } from './catalog-BU5VLLyd.js';
2
+ import { E as Embedder, S as SkillServerOptions } from './server-BBZDjzWZ.js';
3
3
  import 'zod';
4
4
 
5
5
  /**
@@ -74,6 +74,7 @@ interface SkillCaller {
74
74
  readonly claims?: Readonly<Record<string, unknown>>;
75
75
  }
76
76
  interface SkillHttpOptions extends SkillServerOptions {
77
+ /** Gets the Request the host's fetch received; read headers only, the body is still unread. */
77
78
  readonly authorize: (request: Request) => SkillCaller | undefined | Promise<SkillCaller | undefined>;
78
79
  /** Tiers a caller may list and load. Package skills without a tier count as open. */
79
80
  readonly tiersFor?: (caller: SkillCaller) => readonly string[];
package/dist/http.js CHANGED
@@ -2,12 +2,12 @@ import {
2
2
  DEFAULT_MODEL_ID,
3
3
  encodeEntries,
4
4
  loadEmbedder
5
- } from "./chunk-3JNWCUHA.js";
6
- import "./chunk-IRQTGYHA.js";
5
+ } from "./chunk-RYOLBTSW.js";
6
+ import "./chunk-AKPSLZRJ.js";
7
7
  import {
8
8
  createSkillServer,
9
9
  readCatalog
10
- } from "./chunk-UGRHZHHC.js";
10
+ } from "./chunk-PXNRZXL6.js";
11
11
 
12
12
  // src/http.ts
13
13
  import {
@@ -166,12 +166,7 @@ function createSkillHttpHandler(options) {
166
166
  };
167
167
  const limit = options.rateLimit ? createRateLimiter(options.rateLimit) : void 0;
168
168
  const serve = async (request) => {
169
- const capped = await capBody(
170
- request,
171
- options.maxRequestBytes ?? DEFAULT_MAX_REQUEST_BYTES
172
- );
173
- if (capped instanceof Response) return capped;
174
- const caller = await options.authorize(capped);
169
+ const caller = await options.authorize(request);
175
170
  if (!caller) {
176
171
  return new Response(JSON.stringify({ error: "unauthorized" }), {
177
172
  status: 401,
@@ -183,6 +178,11 @@ function createSkillHttpHandler(options) {
183
178
  }
184
179
  const limited = limit?.(caller.id);
185
180
  if (limited) return limited;
181
+ const capped = await capBody(
182
+ request,
183
+ options.maxRequestBytes ?? DEFAULT_MAX_REQUEST_BYTES
184
+ );
185
+ if (capped instanceof Response) return capped;
186
186
  return handlerFor(tiersFor(caller)).fetch(capped, {
187
187
  authInfo: {
188
188
  token: "",
package/dist/index.d.ts CHANGED
@@ -1,7 +1,7 @@
1
- import { I as IntentCache, S as SkillServerOptions, a as SkillTools } from './server-CLyCpwZb.js';
2
- export { B as BundleFile, C as CATALOG_PAGE_MAX, b as CATALOG_PAGE_SIZE, c as CallResponse, d as CatalogItem, e as CatalogResponse, f as Classified, D as DEFAULT_FIND_LIMIT, g as DESCRIBE_FILE_LIMIT, E as Embedder, F as FileKind, h as FindOptions, i as FindResult, j as IntentCacheStats, K as KindFilter, M as Match, R as READ_BUDGET_BYTES, k as Ranking, l as ReadResult, m as SkillBundle, n as SkillFile, o as SkillFileContent, p as SkillFileListing, q as SkillFilters, r as bundleResponseSchema, s as bundleSkill, t as catalogResponseSchema, u as classify, v as cosine, w as createSkillTools, x as describeResponseSchema, y as find, z as findResultSchema, A as isUtf8Text, G as lexicalScore, H as listSkillFiles, J as mimeOf, L as normaliseIntent, N as readSkillFile } from './server-CLyCpwZb.js';
3
- import { S as SkillEntry, C as CatalogOptions } from './catalog-CS0j6-0U.js';
4
- export { a as ASSET_KINDS, A as AssetKind, M as MAX_SKILL_DEPTH, b as SKIPPED_DIRS, d as displayPath, k as kindOf, r as readBody, c as readCatalog, e as readFrontmatter, w as withoutBody } from './catalog-CS0j6-0U.js';
1
+ import { I as IntentCache, S as SkillServerOptions, a as SkillTools } from './server-BBZDjzWZ.js';
2
+ export { B as BundleFile, C as CATALOG_PAGE_MAX, b as CATALOG_PAGE_SIZE, c as CallResponse, d as CatalogItem, e as CatalogResponse, f as Classified, D as DEFAULT_FIND_LIMIT, g as DESCRIBE_FILE_LIMIT, E as Embedder, F as FileKind, h as FindOptions, i as FindResult, j as IntentCacheStats, K as KindFilter, M as Match, R as READ_BUDGET_BYTES, k as RUNTIMES, l as Ranking, m as ReadResult, n as Runtime, o as SkillBundle, p as SkillFile, q as SkillFileContent, r as SkillFileListing, s as SkillFilters, t as bundleResponseSchema, u as bundleSkill, v as catalogResponseSchema, w as classify, x as cosine, y as createSkillTools, z as describeResponseSchema, A as detectRuntime, G as find, H as findResultSchema, J as isUtf8Text, L as lexicalScore, N as listSkillFiles, O as mimeOf, P as normaliseIntent, Q as readSkillFile, T as runtimeOfClient, U as verifiedRuntimesOf } from './server-BBZDjzWZ.js';
3
+ import { S as SkillEntry, M as MetadataValue, C as CatalogOptions } from './catalog-BU5VLLyd.js';
4
+ export { a as ASSET_KINDS, A as AssetKind, b as COMPATIBILITY_MAX, D as DESCRIPTION_MAX, c as MAX_SKILL_DEPTH, d as MetadataLeaf, N as NAME_MAX, e as SKIPPED_DIRS, f as displayPath, k as kindOf, g as parseSkillFrontmatter, r as readBody, h as readCatalog, i as readFrontmatter, s as specProblems, w as withoutBody } from './catalog-BU5VLLyd.js';
5
5
  import { McpServer } from '@modelcontextprotocol/server';
6
6
  import 'zod';
7
7
 
@@ -37,25 +37,6 @@ declare const DEFAULT_INTENT_CACHE_LIMIT = 4096;
37
37
  */
38
38
  declare function openIntentCache(options: IntentCacheOptions): Promise<IntentCache | null>;
39
39
 
40
- /**
41
- * SKILL.md frontmatter, read as YAML the way a host reads it, and checked against
42
- * the Agent Skills specification (https://agentskills.io/specification).
43
- */
44
- type MetadataValue = string | readonly string[];
45
- /**
46
- * Parsed frontmatter. A value with an unquoted ": " is a common authoring slip
47
- * the client guide says to recover from by quoting it, so that is retried once.
48
- */
49
- declare function frontmatterObject(source: string): Record<string, unknown> | null;
50
- declare const NAME_MAX = 64;
51
- declare const DESCRIPTION_MAX = 1024;
52
- declare const COMPATIBILITY_MAX = 500;
53
- /**
54
- * What the specification requires of one SKILL.md, as messages; empty when valid.
55
- * directory is the name of the folder holding it.
56
- */
57
- declare function specProblems(front: Record<string, unknown> | null, directory: string): string[];
58
-
59
40
  /**
60
41
  * Assets laid out as an agent plugin marketplace: a directory holding
61
42
  * `.claude-plugin/marketplace.json`, whose plugins keep skills, commands,
@@ -68,7 +49,7 @@ interface Rejection {
68
49
  readonly path: string;
69
50
  readonly reason: string;
70
51
  }
71
- /** The `metadata:` map of a frontmatter, one level deep: strings and string lists. */
52
+ /** The `metadata:` map of a frontmatter: strings, string lists and maps of those. */
72
53
  declare function readMetadata(source: string): Record<string, MetadataValue>;
73
54
  /** The raw frontmatter text between the fences, for skill_describe. */
74
55
  declare function readFrontmatterText(source: string): string;
@@ -304,7 +285,7 @@ declare function resolveSkillFileUri(uri: string, entries: readonly SkillEntry[]
304
285
 
305
286
  /** Reported to the host on connect. */
306
287
  declare const SERVER_NAME = "pmcp";
307
- declare const SERVER_VERSION = "0.8.2";
288
+ declare const SERVER_VERSION = "0.9.0";
308
289
  /**
309
290
  * Registers the skill_* tools on a server.
310
291
  *
@@ -356,4 +337,4 @@ declare function registerSkillResources(server: McpServer, skills: () => readonl
356
337
  declare const promptName: (entry: Pick<SkillEntry, "name">) => string;
357
338
  declare function registerSkillPrompts(server: McpServer, tools: SkillTools): void;
358
339
 
359
- export { COMPATIBILITY_MAX, CONFIG_FILE, CatalogOptions, type CatalogSection, ConfigError, DEFAULT_INTENT_CACHE_LIMIT, DESCRIPTION_MAX, type Finding$1 as Finding, IntentCache, type IntentCacheOptions, LOCK_FILE, type McpServerSpec, type MetadataValue, NAME_MAX, type Output, type PackageRulesSpec, type ProjectConfig, ProjectError, type ProjectResult, type ProjectSpec, type Rejection, type Runner, SERVER_NAME, SERVER_VERSION, SKILLS_EXTENSION, SkillEntry, type SkillExtensionEntry, type SkillMcpOptions, type SkillResource, SkillServerOptions, SkillTools, TOOLS, type Tool, type Finding as ValidationFinding, assetRoot, createSkillServer, deadGlobs, deriveName, doctor, extensionEntry, findConfig, openIntentCache, frontmatterObject as parseSkillFrontmatter, plan, project, promptName, readConfig, readFrontmatterText, readMarketplace, readMetadata, readSpec, registerSkillPrompts, registerSkillResources, registerSkillTools, registerSkillsExtension, resolveSkillFileUri, skillFileUri, skillFileUri as skillUri, specProblems, validateCatalog, validateSkillDir };
340
+ export { CONFIG_FILE, CatalogOptions, type CatalogSection, ConfigError, DEFAULT_INTENT_CACHE_LIMIT, type Finding$1 as Finding, IntentCache, type IntentCacheOptions, LOCK_FILE, type McpServerSpec, MetadataValue, type Output, type PackageRulesSpec, type ProjectConfig, ProjectError, type ProjectResult, type ProjectSpec, type Rejection, type Runner, SERVER_NAME, SERVER_VERSION, SKILLS_EXTENSION, SkillEntry, type SkillExtensionEntry, type SkillMcpOptions, type SkillResource, SkillServerOptions, SkillTools, TOOLS, type Tool, type Finding as ValidationFinding, assetRoot, createSkillServer, deadGlobs, deriveName, doctor, extensionEntry, findConfig, openIntentCache, plan, project, promptName, readConfig, readFrontmatterText, readMarketplace, readMetadata, readSpec, registerSkillPrompts, registerSkillResources, registerSkillTools, registerSkillsExtension, resolveSkillFileUri, skillFileUri, skillFileUri as skillUri, validateCatalog, validateSkillDir };
package/dist/index.js CHANGED
@@ -14,11 +14,11 @@ import {
14
14
  readSpec,
15
15
  validateCatalog,
16
16
  validateSkillDir
17
- } from "./chunk-O2P5AIHX.js";
17
+ } from "./chunk-PWEAKJZ3.js";
18
18
  import {
19
19
  DEFAULT_INTENT_CACHE_LIMIT,
20
20
  openIntentCache
21
- } from "./chunk-IRQTGYHA.js";
21
+ } from "./chunk-AKPSLZRJ.js";
22
22
  import {
23
23
  ASSET_KINDS,
24
24
  CATALOG_PAGE_MAX,
@@ -30,6 +30,7 @@ import {
30
30
  MAX_SKILL_DEPTH,
31
31
  NAME_MAX,
32
32
  READ_BUDGET_BYTES,
33
+ RUNTIMES,
33
34
  SERVER_NAME,
34
35
  SERVER_VERSION,
35
36
  SKILLS_EXTENSION,
@@ -43,6 +44,7 @@ import {
43
44
  createSkillServer,
44
45
  createSkillTools,
45
46
  describeResponseSchema,
47
+ detectRuntime,
46
48
  displayPath,
47
49
  extensionEntry,
48
50
  find,
@@ -67,10 +69,12 @@ import {
67
69
  registerSkillTools,
68
70
  registerSkillsExtension,
69
71
  resolveSkillFileUri,
72
+ runtimeOfClient,
70
73
  skillFileUri,
71
74
  specProblems,
75
+ verifiedRuntimesOf,
72
76
  withoutBody
73
- } from "./chunk-UGRHZHHC.js";
77
+ } from "./chunk-PXNRZXL6.js";
74
78
  export {
75
79
  ASSET_KINDS,
76
80
  CATALOG_PAGE_MAX,
@@ -87,6 +91,7 @@ export {
87
91
  NAME_MAX,
88
92
  ProjectError,
89
93
  READ_BUDGET_BYTES,
94
+ RUNTIMES,
90
95
  SERVER_NAME,
91
96
  SERVER_VERSION,
92
97
  SKILLS_EXTENSION,
@@ -103,6 +108,7 @@ export {
103
108
  deadGlobs,
104
109
  deriveName,
105
110
  describeResponseSchema,
111
+ detectRuntime,
106
112
  displayPath,
107
113
  doctor,
108
114
  extensionEntry,
@@ -134,11 +140,13 @@ export {
134
140
  registerSkillTools,
135
141
  registerSkillsExtension,
136
142
  resolveSkillFileUri,
143
+ runtimeOfClient,
137
144
  skillFileUri,
138
145
  skillFileUri as skillUri,
139
146
  specProblems,
140
147
  validateCatalog,
141
148
  validateSkillDir,
149
+ verifiedRuntimesOf,
142
150
  withoutBody
143
151
  };
144
152
  //# sourceMappingURL=index.js.map
@@ -1,4 +1,4 @@
1
- import { S as SkillEntry, C as CatalogOptions, A as AssetKind } from './catalog-CS0j6-0U.js';
1
+ import { S as SkillEntry, M as MetadataValue, C as CatalogOptions, A as AssetKind } from './catalog-BU5VLLyd.js';
2
2
  import { z } from 'zod';
3
3
 
4
4
  /**
@@ -179,6 +179,36 @@ type ReadResult = SkillFileContent | FileRefusal | {
179
179
  };
180
180
  declare function readSkillFile(entry: SkillEntry, wanted?: string, budget?: number): ReadResult;
181
181
 
182
+ /**
183
+ * Agent runtimes a skill can declare itself verified on, and the mapping from
184
+ * an MCP client's reported name to one of them.
185
+ */
186
+
187
+ declare const RUNTIMES: readonly ["claude-code", "codex-cli", "gemini-cli", "grok-cli", "antigravity"];
188
+ type Runtime = (typeof RUNTIMES)[number];
189
+ /** The runtimes a metadata block lists as verified; unknown values are dropped. */
190
+ declare function verifiedRuntimesOf(metadata: Readonly<Record<string, MetadataValue>> | undefined): Runtime[];
191
+ /** The runtime an MCP client name stands for; null when it is not recognised. */
192
+ declare function runtimeOfClient(name: string | undefined): Runtime | null;
193
+ interface ClientSource {
194
+ readonly server?: {
195
+ getClientVersion?: () => {
196
+ readonly name?: string;
197
+ } | undefined;
198
+ };
199
+ }
200
+ interface RequestContext {
201
+ readonly mcpReq?: {
202
+ readonly envelope?: object;
203
+ };
204
+ }
205
+ /**
206
+ * The runtime of the client making this request. The per-request envelope is
207
+ * read first, then the initialize-scoped identity; a stateless caller has
208
+ * neither and gets null.
209
+ */
210
+ declare function detectRuntime(server: ClientSource, ctx?: RequestContext): Runtime | null;
211
+
182
212
  /**
183
213
  * The shapes the tools answer with, defined once: the TypeScript types are
184
214
  * inferred from these schemas and the same schemas are each tool's outputSchema,
@@ -195,6 +225,14 @@ declare const catalogItemSchema: z.ZodObject<{
195
225
  hook: "hook";
196
226
  mcp: "mcp";
197
227
  }>>;
228
+ verifiedRuntimes: z.ZodOptional<z.ZodArray<z.ZodEnum<{
229
+ "claude-code": "claude-code";
230
+ "codex-cli": "codex-cli";
231
+ "gemini-cli": "gemini-cli";
232
+ "grok-cli": "grok-cli";
233
+ antigravity: "antigravity";
234
+ }>>>;
235
+ verified: z.ZodOptional<z.ZodBoolean>;
198
236
  }, z.core.$strip>;
199
237
  declare const catalogResponseSchema: z.ZodObject<{
200
238
  count: z.ZodNumber;
@@ -213,6 +251,14 @@ declare const catalogResponseSchema: z.ZodObject<{
213
251
  hook: "hook";
214
252
  mcp: "mcp";
215
253
  }>>;
254
+ verifiedRuntimes: z.ZodOptional<z.ZodArray<z.ZodEnum<{
255
+ "claude-code": "claude-code";
256
+ "codex-cli": "codex-cli";
257
+ "gemini-cli": "gemini-cli";
258
+ "grok-cli": "grok-cli";
259
+ antigravity: "antigravity";
260
+ }>>>;
261
+ verified: z.ZodOptional<z.ZodBoolean>;
216
262
  }, z.core.$strip>>;
217
263
  }, z.core.$strip>>;
218
264
  }, z.core.$strip>;
@@ -221,11 +267,26 @@ declare const findResultSchema: z.ZodObject<{
221
267
  semantic: "semantic";
222
268
  lexical: "lexical";
223
269
  }>;
270
+ runtime: z.ZodNullable<z.ZodEnum<{
271
+ "claude-code": "claude-code";
272
+ "codex-cli": "codex-cli";
273
+ "gemini-cli": "gemini-cli";
274
+ "grok-cli": "grok-cli";
275
+ antigravity: "antigravity";
276
+ }>>;
224
277
  matches: z.ZodArray<z.ZodObject<{
225
278
  name: z.ZodString;
226
279
  package: z.ZodString;
227
280
  description: z.ZodString;
228
281
  score: z.ZodNumber;
282
+ verifiedRuntimes: z.ZodOptional<z.ZodArray<z.ZodEnum<{
283
+ "claude-code": "claude-code";
284
+ "codex-cli": "codex-cli";
285
+ "gemini-cli": "gemini-cli";
286
+ "grok-cli": "grok-cli";
287
+ antigravity: "antigravity";
288
+ }>>>;
289
+ verified: z.ZodOptional<z.ZodBoolean>;
229
290
  }, z.core.$strip>>;
230
291
  }, z.core.$strip>;
231
292
  declare const describeResponseSchema: z.ZodObject<{
@@ -239,7 +300,7 @@ declare const describeResponseSchema: z.ZodObject<{
239
300
  package: z.ZodString;
240
301
  description: z.ZodString;
241
302
  tier: z.ZodOptional<z.ZodString>;
242
- metadata: z.ZodRecord<z.ZodString, z.ZodUnion<readonly [z.ZodString, z.ZodReadonly<z.ZodArray<z.ZodString>>]>>;
303
+ metadata: z.ZodRecord<z.ZodString, z.ZodUnion<readonly [z.ZodUnion<readonly [z.ZodString, z.ZodReadonly<z.ZodArray<z.ZodString>>]>, z.ZodReadonly<z.ZodRecord<z.ZodString, z.ZodUnion<readonly [z.ZodString, z.ZodReadonly<z.ZodArray<z.ZodString>>]>>>]>>;
243
304
  frontmatter: z.ZodString;
244
305
  files: z.ZodArray<z.ZodObject<{
245
306
  path: z.ZodString;
@@ -261,6 +322,7 @@ declare const bundleResponseSchema: z.ZodObject<{
261
322
  }, z.core.$strip>;
262
323
  type CatalogItem = z.infer<typeof catalogItemSchema>;
263
324
  type CatalogResponse = z.infer<typeof catalogResponseSchema>;
325
+ type FindResponse = z.infer<typeof findResultSchema>;
264
326
  type DescribeResponse = z.infer<typeof describeResponseSchema>;
265
327
 
266
328
  /**
@@ -288,6 +350,10 @@ interface SkillFilters {
288
350
  readonly level?: string;
289
351
  readonly domain?: string;
290
352
  readonly medium?: string;
353
+ /** The runtime verified skills are ranked and marked for. Never filters by itself. */
354
+ readonly runtime?: Runtime;
355
+ /** Keep only skills verified on `runtime`, or on any runtime when it is unset. */
356
+ readonly verifiedOnly?: boolean;
291
357
  }
292
358
  interface SkillServerOptions extends CatalogOptions {
293
359
  readonly embedder?: Embedder;
@@ -295,6 +361,8 @@ interface SkillServerOptions extends CatalogOptions {
295
361
  readonly vectors?: ReadonlyMap<string, Float32Array>;
296
362
  /** Injected for tests. Reads the catalog off disk otherwise. */
297
363
  readonly loadCatalog?: (options: CatalogOptions) => SkillEntry[];
364
+ /** Off by default so a call without a runtime input ranks exactly as before. */
365
+ readonly rankByClientRuntime?: boolean;
298
366
  }
299
367
 
300
368
  interface CallResponse {
@@ -321,9 +389,13 @@ declare function createSkillTools(options: SkillServerOptions): {
321
389
  pageSize?: number;
322
390
  tier?: string;
323
391
  kind?: KindFilter;
392
+ runtime?: Runtime;
393
+ verifiedOnly?: boolean;
394
+ /** The caller's own runtime, for ordering only. */
395
+ clientRuntime?: Runtime | null;
324
396
  }): CatalogResponse;
325
397
  /** Ranked names. Returns; never loads a body. */
326
- find(intent: string, limit?: number, filters?: SkillFilters): Promise<FindResult>;
398
+ find(intent: string, limit?: number, filters?: SkillFilters, clientRuntime?: Runtime | null): Promise<FindResponse>;
327
399
  /** Every property of one skill and the files it carries, without bodies. */
328
400
  describe(name: string): DescribeResponse | null;
329
401
  /**
@@ -349,4 +421,4 @@ declare function createSkillTools(options: SkillServerOptions): {
349
421
  };
350
422
  type SkillTools = ReturnType<typeof createSkillTools>;
351
423
 
352
- export { isUtf8Text as A, type BundleFile as B, CATALOG_PAGE_MAX as C, DEFAULT_FIND_LIMIT as D, type Embedder as E, type FileKind as F, lexicalScore as G, listSkillFiles as H, type IntentCache as I, mimeOf as J, type KindFilter as K, normaliseIntent as L, type Match as M, readSkillFile as N, READ_BUDGET_BYTES as R, type SkillServerOptions as S, type SkillTools as a, CATALOG_PAGE_SIZE as b, type CallResponse as c, type CatalogItem as d, type CatalogResponse as e, type Classified as f, DESCRIBE_FILE_LIMIT as g, type FindOptions as h, type FindResult as i, type IntentCacheStats as j, type Ranking as k, type ReadResult as l, type SkillBundle as m, type SkillFile as n, type SkillFileContent as o, type SkillFileListing as p, type SkillFilters as q, bundleResponseSchema as r, bundleSkill as s, catalogResponseSchema as t, classify as u, cosine as v, createSkillTools as w, describeResponseSchema as x, find as y, findResultSchema as z };
424
+ export { detectRuntime as A, type BundleFile as B, CATALOG_PAGE_MAX as C, DEFAULT_FIND_LIMIT as D, type Embedder as E, type FileKind as F, find as G, findResultSchema as H, type IntentCache as I, isUtf8Text as J, type KindFilter as K, lexicalScore as L, type Match as M, listSkillFiles as N, mimeOf as O, normaliseIntent as P, readSkillFile as Q, READ_BUDGET_BYTES as R, type SkillServerOptions as S, runtimeOfClient as T, verifiedRuntimesOf as U, type SkillTools as a, CATALOG_PAGE_SIZE as b, type CallResponse as c, type CatalogItem as d, type CatalogResponse as e, type Classified as f, DESCRIBE_FILE_LIMIT as g, type FindOptions as h, type FindResult as i, type IntentCacheStats as j, RUNTIMES as k, type Ranking as l, type ReadResult as m, type Runtime as n, type SkillBundle as o, type SkillFile as p, type SkillFileContent as q, type SkillFileListing as r, type SkillFilters as s, bundleResponseSchema as t, bundleSkill as u, catalogResponseSchema as v, classify as w, cosine as x, createSkillTools as y, describeResponseSchema as z };
package/dist/stdio.d.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  #!/usr/bin/env node
2
- import { C as CatalogOptions } from './catalog-CS0j6-0U.js';
2
+ import { C as CatalogOptions } from './catalog-BU5VLLyd.js';
3
3
 
4
4
  /**
5
5
  * The stdio entry a host launches.
package/dist/stdio.js CHANGED
@@ -3,8 +3,8 @@ import {
3
3
  main,
4
4
  resolveRoots,
5
5
  serve
6
- } from "./chunk-UW7HTILA.js";
7
- import "./chunk-UGRHZHHC.js";
6
+ } from "./chunk-Y7UX36AC.js";
7
+ import "./chunk-PXNRZXL6.js";
8
8
  export {
9
9
  main,
10
10
  resolveRoots,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@modootoday/pmcp",
3
- "version": "0.8.2",
3
+ "version": "0.9.0",
4
4
  "license": "Elastic-2.0",
5
5
  "author": "modootoday",
6
6
  "description": "An MCP server that finds the skills your installed packages already ship. Reads SKILL.md out of node_modules by shape rather than by path, so it sees the skills, .agent, .claude, .gemini and .codex conventions alike, and keeps session startup flat as the number of installed skills grows.",