@modootoday/pmcp 0.4.0 → 0.5.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.
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  normaliseIntent
3
- } from "./chunk-BFET6MFN.js";
3
+ } from "./chunk-JOQTOVTJ.js";
4
4
 
5
5
  // src/cache.ts
6
6
  async function openDatabase(path) {
@@ -126,9 +126,68 @@ async function openIntentCache(options) {
126
126
  };
127
127
  }
128
128
 
129
+ // src/config.ts
130
+ import { existsSync, readFileSync } from "fs";
131
+ import { dirname, join, resolve } from "path";
132
+ import { parse } from "smol-toml";
133
+ var CONFIG_FILE = "pmcp.toml";
134
+ var ConfigError = class extends Error {
135
+ constructor(path, message) {
136
+ super(`${path}: ${message}`);
137
+ this.name = "ConfigError";
138
+ }
139
+ };
140
+ var PATH_KEYS = ["roots", "workspaces", "packages", "marketplaces"];
141
+ var CATALOG_KEYS = /* @__PURE__ */ new Set([...PATH_KEYS, "scopes"]);
142
+ function findConfig(start) {
143
+ let dir = resolve(start);
144
+ for (; ; ) {
145
+ const candidate = join(dir, CONFIG_FILE);
146
+ if (existsSync(candidate)) return candidate;
147
+ const parent = dirname(dir);
148
+ if (parent === dir) return null;
149
+ dir = parent;
150
+ }
151
+ }
152
+ function stringList(path, key, value) {
153
+ if (!Array.isArray(value) || !value.every((v) => typeof v === "string")) {
154
+ throw new ConfigError(path, `[catalog] ${key} must be a list of strings`);
155
+ }
156
+ return value;
157
+ }
158
+ function readConfig(path) {
159
+ const absolute = resolve(path);
160
+ const dir = dirname(absolute);
161
+ let raw;
162
+ try {
163
+ raw = parse(readFileSync(absolute, "utf8"));
164
+ } catch (error) {
165
+ const reason = error instanceof Error ? error.message : "unreadable";
166
+ throw new ConfigError(absolute, reason.split("\n")[0] ?? reason);
167
+ }
168
+ const section = raw["catalog"];
169
+ if (section === void 0) return { path: absolute, dir, catalog: {}, raw };
170
+ if (section === null || typeof section !== "object" || Array.isArray(section)) {
171
+ throw new ConfigError(absolute, "[catalog] must be a table");
172
+ }
173
+ const catalog = {};
174
+ for (const [key, value] of Object.entries(section)) {
175
+ if (!CATALOG_KEYS.has(key)) {
176
+ throw new ConfigError(absolute, `unknown key [catalog] ${key}`);
177
+ }
178
+ const list = stringList(absolute, key, value);
179
+ catalog[key] = key === "scopes" ? list : list.map((p) => resolve(dir, p));
180
+ }
181
+ return { path: absolute, dir, catalog, raw };
182
+ }
183
+
129
184
  export {
130
185
  openDatabase,
131
186
  DEFAULT_INTENT_CACHE_LIMIT,
132
- openIntentCache
187
+ openIntentCache,
188
+ CONFIG_FILE,
189
+ ConfigError,
190
+ findConfig,
191
+ readConfig
133
192
  };
134
- //# sourceMappingURL=chunk-RBT3ISF4.js.map
193
+ //# sourceMappingURL=chunk-PUGLIJYM.js.map
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  createSkillServer
3
- } from "./chunk-BFET6MFN.js";
3
+ } from "./chunk-JOQTOVTJ.js";
4
4
 
5
5
  // src/stdio.ts
6
6
  import { serveStdio } from "@modelcontextprotocol/server/stdio";
@@ -35,4 +35,4 @@ export {
35
35
  serve,
36
36
  main
37
37
  };
38
- //# sourceMappingURL=chunk-JL5BCIQM.js.map
38
+ //# sourceMappingURL=chunk-X4LYYULW.js.map
package/dist/cli.js CHANGED
@@ -1,13 +1,16 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
- openDatabase
4
- } from "./chunk-RBT3ISF4.js";
3
+ ConfigError,
4
+ findConfig,
5
+ openDatabase,
6
+ readConfig
7
+ } from "./chunk-PUGLIJYM.js";
5
8
  import {
6
9
  serve
7
- } from "./chunk-JL5BCIQM.js";
10
+ } from "./chunk-X4LYYULW.js";
8
11
  import {
9
12
  readCatalog
10
- } from "./chunk-BFET6MFN.js";
13
+ } from "./chunk-JOQTOVTJ.js";
11
14
 
12
15
  // src/cli/command.ts
13
16
  var ArgumentError = class extends Error {
@@ -320,17 +323,48 @@ var CATALOG_OPTIONS = [
320
323
  describe: "A workspace root, or a glob of them: each root and every member its workspaces globs name. Repeatable.",
321
324
  repeat: true,
322
325
  placeholder: "<dir>"
326
+ },
327
+ {
328
+ name: "config",
329
+ describe: "A pmcp.toml to read instead of the nearest one at or above the working directory.",
330
+ placeholder: "<file>"
331
+ },
332
+ {
333
+ name: "no-config",
334
+ describe: "Ignore pmcp.toml; only the flags given count.",
335
+ boolean: true
323
336
  }
324
337
  ];
338
+ function configFrom(context) {
339
+ if (context.args.flags.has("no-config")) return null;
340
+ const named = one(context.args, "config");
341
+ const path = named ?? findConfig(context.cwd);
342
+ if (path === null) return null;
343
+ try {
344
+ return readConfig(path);
345
+ } catch (error) {
346
+ if (error instanceof ConfigError) throw new ArgumentError(error.message);
347
+ if (named !== void 0) throw new ArgumentError(`cannot read ${named}`);
348
+ throw error;
349
+ }
350
+ }
325
351
  function rootsFrom(context) {
326
352
  const given = many(context.args, "root");
327
- return given.length > 0 ? given : [`${context.cwd}/node_modules`];
353
+ if (given.length > 0) return given;
354
+ const config = configFrom(context);
355
+ if (config?.catalog.roots !== void 0) return config.catalog.roots;
356
+ return [`${config?.dir ?? context.cwd}/node_modules`];
328
357
  }
329
358
  function catalogOptionsFrom(context, onReject) {
330
- const scopes = many(context.args, "scope");
331
- const marketplaces = many(context.args, "marketplace");
332
- const packages = many(context.args, "package");
333
- const workspaces = many(context.args, "workspace");
359
+ const config = configFrom(context)?.catalog ?? {};
360
+ const pick = (flag, fromFile) => {
361
+ const given = many(context.args, flag);
362
+ return given.length > 0 ? given : fromFile ?? [];
363
+ };
364
+ const scopes = pick("scope", config.scopes);
365
+ const marketplaces = pick("marketplace", config.marketplaces);
366
+ const packages = pick("package", config.packages);
367
+ const workspaces = pick("workspace", config.workspaces);
334
368
  return {
335
369
  roots: rootsFrom(context),
336
370
  ...scopes.length > 0 ? { scopes } : {},
@@ -449,7 +483,7 @@ var indexCommand = {
449
483
  var listCommand = {
450
484
  name: "list",
451
485
  describe: "List the skills discovered in node_modules and marketplaces",
452
- usage: "pmcp list [--root <dir>] [--scope <prefix>] [--marketplace <dir>] [--package <dir>] [--workspace <dir|glob>] [--json]",
486
+ usage: "pmcp list [--root <dir>] [--scope <prefix>] [--marketplace <dir>] [--package <dir>] [--workspace <dir|glob>] [--config <file> | --no-config] [--json]",
453
487
  options: [
454
488
  ...CATALOG_OPTIONS,
455
489
  { name: "json", describe: "Emit JSON rather than a table.", boolean: true }
@@ -474,12 +508,28 @@ var listCommand = {
474
508
  return 1;
475
509
  }
476
510
  context.ui.table(
477
- entries.map((entry2) => [
478
- entry2.tier === void 0 ? entry2.name : `${entry2.name} [${entry2.tier}]`,
479
- entry2.description
480
- ])
511
+ entries.map((entry2) => {
512
+ const tags = [entry2.kind, entry2.tier].filter(Boolean).join(", ");
513
+ return [
514
+ tags === "" ? entry2.name : `${entry2.name} [${tags}]`,
515
+ entry2.description
516
+ ];
517
+ })
518
+ );
519
+ const counts = /* @__PURE__ */ new Map();
520
+ for (const entry2 of entries) {
521
+ const kind = entry2.kind ?? "skill";
522
+ counts.set(kind, (counts.get(kind) ?? 0) + 1);
523
+ }
524
+ const plural = {
525
+ skill: "skills",
526
+ agent: "agents",
527
+ hook: "hooks",
528
+ mcp: "MCP servers"
529
+ };
530
+ context.ui.success(
531
+ [...counts].map(([kind, n]) => `${n} ${plural[kind] ?? kind}`).join(", ")
481
532
  );
482
- context.ui.success(`${entries.length} skills`);
483
533
  return rejected.length === 0 ? 0 : 1;
484
534
  }
485
535
  };
@@ -488,7 +538,7 @@ var listCommand = {
488
538
  var serveCommand = {
489
539
  name: "serve",
490
540
  describe: "Run the MCP server on stdio (the default with no command)",
491
- usage: "pmcp serve [--root <dir>] [--scope <prefix>] [--marketplace <dir>] [--package <dir>] [--workspace <dir>]",
541
+ usage: "pmcp serve [--root <dir>] [--scope <prefix>] [--marketplace <dir>] [--package <dir>] [--workspace <dir>] [--config <file> | --no-config]",
492
542
  options: [...CATALOG_OPTIONS],
493
543
  run(context) {
494
544
  serve(catalogOptionsFrom(context));
@@ -2085,7 +2135,7 @@ function dispatch(argv, options = {}) {
2085
2135
  }
2086
2136
  return run(command, rest, { ui, env, cwd });
2087
2137
  }
2088
- var VERSION = "0.4.0";
2138
+ var VERSION = "0.5.0";
2089
2139
  async function run(command, argv, context) {
2090
2140
  try {
2091
2141
  return await command.run({
package/dist/http.d.ts CHANGED
@@ -1,5 +1,5 @@
1
- import { S as SkillEntry } from './catalog-BiPLcbLu.js';
2
- import { S as SkillServerOptions } from './server-dNFrR_Zh.js';
1
+ import { S as SkillEntry } from './catalog-5v7jrGwP.js';
2
+ import { S as SkillServerOptions } from './server-Dm71qZgM.js';
3
3
 
4
4
  /**
5
5
  * The catalog over streamable HTTP, for a hosted skills server.
package/dist/http.js CHANGED
@@ -1,7 +1,7 @@
1
1
  import {
2
2
  createSkillServer,
3
3
  readCatalog
4
- } from "./chunk-BFET6MFN.js";
4
+ } from "./chunk-JOQTOVTJ.js";
5
5
 
6
6
  // src/http.ts
7
7
  import {
package/dist/index.d.ts CHANGED
@@ -1,7 +1,7 @@
1
- import { I as IntentCache, S as SkillServerOptions, a as SkillTools } from './server-dNFrR_Zh.js';
2
- export { C as CATALOG_PAGE_MAX, b as CATALOG_PAGE_SIZE, c as CallResponse, d as CatalogResponse, D as DEFAULT_FIND_LIMIT, e as DESCRIBE_FILE_LIMIT, E as Embedder, F as FindOptions, f as FindResult, g as IntentCacheStats, M as Match, R as READ_BUDGET_BYTES, h as Ranking, i as ReadResult, j as SkillFilters, k as cosine, l as createSkillTools, m as find, n as lexicalScore, o as normaliseIntent } from './server-dNFrR_Zh.js';
3
- import { S as SkillEntry } from './catalog-BiPLcbLu.js';
4
- export { C as CatalogOptions, M as MAX_SKILL_DEPTH, a as SKIPPED_DIRS, d as displayPath, r as readBody, b as readCatalog, c as readFrontmatter, w as withoutBody } from './catalog-BiPLcbLu.js';
1
+ import { I as IntentCache, S as SkillServerOptions, a as SkillTools } from './server-Dm71qZgM.js';
2
+ export { C as CATALOG_PAGE_MAX, b as CATALOG_PAGE_SIZE, c as CallResponse, d as CatalogItem, e as CatalogResponse, D as DEFAULT_FIND_LIMIT, f as DESCRIBE_FILE_LIMIT, E as Embedder, F as FindOptions, g as FindResult, h as IntentCacheStats, K as KindFilter, M as Match, R as READ_BUDGET_BYTES, i as Ranking, j as ReadResult, k as SkillFilters, l as cosine, m as createSkillTools, n as find, o as lexicalScore, p as normaliseIntent } from './server-Dm71qZgM.js';
3
+ import { S as SkillEntry } from './catalog-5v7jrGwP.js';
4
+ export { a as ASSET_KINDS, A as AssetKind, C as CatalogOptions, 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-5v7jrGwP.js';
5
5
  import { McpServer } from '@modelcontextprotocol/server';
6
6
 
7
7
  /**
@@ -37,14 +37,14 @@ declare const DEFAULT_INTENT_CACHE_LIMIT = 4096;
37
37
  declare function openIntentCache(options: IntentCacheOptions): Promise<IntentCache | null>;
38
38
 
39
39
  /**
40
- * Skills laid out as an agent plugin marketplace: a directory holding
41
- * `.claude-plugin/marketplace.json`, whose plugins keep skills at
42
- * `skills/<skill>/SKILL.md`. No package.json is involved, which is why the
43
- * node_modules walk never saw them.
40
+ * Assets laid out as an agent plugin marketplace: a directory holding
41
+ * `.claude-plugin/marketplace.json`, whose plugins keep skills, commands,
42
+ * agents, hooks and MCP servers in the plugin format's own places. No
43
+ * package.json is involved, which is why the node_modules walk never saw them.
44
44
  */
45
45
 
46
46
  type MetadataValue = string | readonly string[];
47
- /** Why a skill was left out rather than served. */
47
+ /** Why an asset was left out rather than served. */
48
48
  interface Rejection {
49
49
  readonly path: string;
50
50
  readonly reason: string;
@@ -56,11 +56,48 @@ interface Rejection {
56
56
  declare function readMetadata(source: string): Record<string, MetadataValue>;
57
57
  /** The raw frontmatter text between the fences, for skill_describe. */
58
58
  declare function readFrontmatterText(source: string): string;
59
+ /** Every asset one marketplace lists. */
60
+ declare function readMarketplace(dir: string, onReject?: (rejection: Rejection) => void): SkillEntry[];
61
+ /** The directory or single file an entry's describe and read may open. */
62
+ declare const assetRoot: (entry: Pick<SkillEntry, "root" | "path">) => string;
63
+
59
64
  /**
60
- * Every skill one marketplace lists. A skill whose own tier disagrees with the
61
- * marketplace's is rejected: a mislabelled tier is how a private skill leaks.
65
+ * `pmcp.toml`, the project's one record of where its catalog lives.
66
+ *
67
+ * Paths in it are relative to the file, so the same file works from any
68
+ * directory a host starts pmcp in. Only `[catalog]` is read here; the other
69
+ * sections belong to the projector and are kept as given.
62
70
  */
63
- declare function readMarketplace(dir: string, onReject?: (rejection: Rejection) => void): SkillEntry[];
71
+ declare const CONFIG_FILE = "pmcp.toml";
72
+ /** What `[catalog]` may say. Each mirrors the repeatable CLI flag of the same meaning. */
73
+ interface CatalogSection {
74
+ readonly roots?: readonly string[];
75
+ readonly scopes?: readonly string[];
76
+ readonly workspaces?: readonly string[];
77
+ readonly packages?: readonly string[];
78
+ readonly marketplaces?: readonly string[];
79
+ }
80
+ interface ProjectConfig {
81
+ /** Absolute path of the file read. */
82
+ readonly path: string;
83
+ /** Its directory; every relative path in the file resolves against it. */
84
+ readonly dir: string;
85
+ /** `[catalog]` with paths already absolute. */
86
+ readonly catalog: CatalogSection;
87
+ /** The whole document, for sections this module does not interpret. */
88
+ readonly raw: Readonly<Record<string, unknown>>;
89
+ }
90
+ declare class ConfigError extends Error {
91
+ constructor(path: string, message: string);
92
+ }
93
+ /** The nearest pmcp.toml at or above start, or null when there is none. */
94
+ declare function findConfig(start: string): string | null;
95
+ /**
96
+ * Reads and checks one file. An unknown key under `[catalog]` is an error
97
+ * rather than ignored, for the same reason an unknown flag is: a misspelt
98
+ * `workspace = [...]` must not look like it worked.
99
+ */
100
+ declare function readConfig(path: string): ProjectConfig;
64
101
 
65
102
  /**
66
103
  * The five tools, spoken over MCP.
@@ -81,11 +118,42 @@ declare const SERVER_NAME = "pmcp";
81
118
  */
82
119
  declare function registerSkillTools(server: McpServer, tools: SkillTools): McpServer;
83
120
  /**
84
- * A server with the five tools registered.
121
+ * A server with the five tools and the Skills extension registered.
85
122
  *
86
123
  * The catalog is read on first use rather than here, so a host that connects
87
124
  * and never asks pays nothing for the walk.
88
125
  */
89
126
  declare function createSkillServer(options: SkillServerOptions): McpServer;
90
127
 
91
- export { DEFAULT_INTENT_CACHE_LIMIT, IntentCache, type IntentCacheOptions, type MetadataValue, type Rejection, SERVER_NAME, SkillEntry, SkillServerOptions, SkillTools, createSkillServer, openIntentCache, readFrontmatterText, readMarketplace, readMetadata, registerSkillTools };
128
+ /**
129
+ * The MCP Skills extension (SEP-2640): `skills/list`, `skills/get` and the
130
+ * skill files as `skill://pmcp/<name>/<file>` resources, so a host that speaks
131
+ * the extension loads skills natively instead of through the skill_* tools.
132
+ */
133
+
134
+ declare const SKILLS_EXTENSION = "io.modelcontextprotocol/skills";
135
+ interface SkillResource {
136
+ readonly uri: string;
137
+ readonly digest: string;
138
+ readonly size: number;
139
+ }
140
+ interface SkillExtensionEntry {
141
+ readonly uri: string;
142
+ readonly frontmatter: Readonly<Record<string, unknown>>;
143
+ readonly resources: readonly SkillResource[];
144
+ }
145
+ declare const skillUri: (entry: Pick<SkillEntry, "name">, file?: string) => string;
146
+ /**
147
+ * The extension's entry for one catalog skill, or null when the skill cannot
148
+ * be served under SEP-2640: not a directory with SKILL.md, a frontmatter name
149
+ * that is missing, invalid or unlike its path, or over the per-skill limits.
150
+ * Such a skill stays reachable through the skill_* tools.
151
+ */
152
+ declare function extensionEntry(entry: SkillEntry): SkillExtensionEntry | null;
153
+ /**
154
+ * Declares the extension and its methods on a server, over the skills the
155
+ * catalog function returns. Must run before the server connects.
156
+ */
157
+ declare function registerSkillsExtension(server: McpServer, skills: () => readonly SkillEntry[]): void;
158
+
159
+ export { CONFIG_FILE, type CatalogSection, ConfigError, DEFAULT_INTENT_CACHE_LIMIT, IntentCache, type IntentCacheOptions, type MetadataValue, type ProjectConfig, type Rejection, SERVER_NAME, SKILLS_EXTENSION, SkillEntry, type SkillExtensionEntry, type SkillResource, SkillServerOptions, SkillTools, assetRoot, createSkillServer, extensionEntry, findConfig, openIntentCache, readConfig, readFrontmatterText, readMarketplace, readMetadata, registerSkillTools, registerSkillsExtension, skillUri };
package/dist/index.js CHANGED
@@ -1,8 +1,13 @@
1
1
  import {
2
+ CONFIG_FILE,
3
+ ConfigError,
2
4
  DEFAULT_INTENT_CACHE_LIMIT,
3
- openIntentCache
4
- } from "./chunk-RBT3ISF4.js";
5
+ findConfig,
6
+ openIntentCache,
7
+ readConfig
8
+ } from "./chunk-PUGLIJYM.js";
5
9
  import {
10
+ ASSET_KINDS,
6
11
  CATALOG_PAGE_MAX,
7
12
  CATALOG_PAGE_SIZE,
8
13
  DEFAULT_FIND_LIMIT,
@@ -10,12 +15,16 @@ import {
10
15
  MAX_SKILL_DEPTH,
11
16
  READ_BUDGET_BYTES,
12
17
  SERVER_NAME,
18
+ SKILLS_EXTENSION,
13
19
  SKIPPED_DIRS,
20
+ assetRoot,
14
21
  cosine,
15
22
  createSkillServer,
16
23
  createSkillTools,
17
24
  displayPath,
25
+ extensionEntry,
18
26
  find,
27
+ kindOf,
19
28
  lexicalScore,
20
29
  normaliseIntent,
21
30
  readBody,
@@ -25,33 +34,46 @@ import {
25
34
  readMarketplace,
26
35
  readMetadata,
27
36
  registerSkillTools,
37
+ registerSkillsExtension,
38
+ skillUri,
28
39
  withoutBody
29
- } from "./chunk-BFET6MFN.js";
40
+ } from "./chunk-JOQTOVTJ.js";
30
41
  export {
42
+ ASSET_KINDS,
31
43
  CATALOG_PAGE_MAX,
32
44
  CATALOG_PAGE_SIZE,
45
+ CONFIG_FILE,
46
+ ConfigError,
33
47
  DEFAULT_FIND_LIMIT,
34
48
  DEFAULT_INTENT_CACHE_LIMIT,
35
49
  DESCRIBE_FILE_LIMIT,
36
50
  MAX_SKILL_DEPTH,
37
51
  READ_BUDGET_BYTES,
38
52
  SERVER_NAME,
53
+ SKILLS_EXTENSION,
39
54
  SKIPPED_DIRS,
55
+ assetRoot,
40
56
  cosine,
41
57
  createSkillServer,
42
58
  createSkillTools,
43
59
  displayPath,
60
+ extensionEntry,
44
61
  find,
62
+ findConfig,
63
+ kindOf,
45
64
  lexicalScore,
46
65
  normaliseIntent,
47
66
  openIntentCache,
48
67
  readBody,
49
68
  readCatalog,
69
+ readConfig,
50
70
  readFrontmatter,
51
71
  readFrontmatterText,
52
72
  readMarketplace,
53
73
  readMetadata,
54
74
  registerSkillTools,
75
+ registerSkillsExtension,
76
+ skillUri,
55
77
  withoutBody
56
78
  };
57
79
  //# sourceMappingURL=index.js.map
@@ -1,4 +1,4 @@
1
- import { S as SkillEntry, C as CatalogOptions } from './catalog-BiPLcbLu.js';
1
+ import { S as SkillEntry, C as CatalogOptions, A as AssetKind } from './catalog-5v7jrGwP.js';
2
2
 
3
3
  /**
4
4
  * The intent key and the cache contract.
@@ -99,8 +99,14 @@ declare const READ_BUDGET_BYTES: number;
99
99
  declare const DESCRIBE_FILE_LIMIT = 200;
100
100
  declare const CATALOG_PAGE_SIZE = 8;
101
101
  declare const CATALOG_PAGE_MAX = 20;
102
- /** Equality filters over catalog fields. Unset keys match everything. */
102
+ /** A kind filter value: one kind, or every kind. */
103
+ type KindFilter = AssetKind | "any";
104
+ /**
105
+ * Equality filters over catalog fields. Unset keys match everything except
106
+ * kind, which defaults to skill so a search for a skill never returns a hook.
107
+ */
103
108
  interface SkillFilters {
109
+ readonly kind?: KindFilter;
104
110
  readonly tier?: string;
105
111
  readonly package?: string;
106
112
  readonly level?: string;
@@ -133,13 +139,16 @@ interface CatalogResponse {
133
139
  readonly hasNext: boolean;
134
140
  readonly packages: readonly {
135
141
  readonly package: string;
136
- readonly skills: readonly {
137
- readonly name: string;
138
- readonly description: string;
139
- readonly tier?: string;
140
- }[];
142
+ readonly skills: readonly CatalogItem[];
141
143
  }[];
142
144
  }
145
+ /** One catalog line. `kind` appears only for an asset that is not a skill. */
146
+ interface CatalogItem {
147
+ readonly name: string;
148
+ readonly description: string;
149
+ readonly tier?: string;
150
+ readonly kind?: AssetKind;
151
+ }
143
152
  interface CallResponse {
144
153
  readonly name: string;
145
154
  readonly body: string;
@@ -160,12 +169,14 @@ declare function createSkillTools(options: SkillServerOptions): {
160
169
  page?: number;
161
170
  pageSize?: number;
162
171
  tier?: string;
172
+ kind?: KindFilter;
163
173
  }): CatalogResponse;
164
174
  /** Ranked names. Returns; never loads a body. */
165
175
  find(intent: string, limit?: number, filters?: SkillFilters): Promise<FindResult>;
166
176
  /** Every property of one skill and the files it carries, without bodies. */
167
177
  describe(name: string): {
168
178
  name: string;
179
+ kind: "agent" | "skill" | "hook" | "mcp";
169
180
  package: string;
170
181
  description: string;
171
182
  tier: string | undefined;
@@ -188,7 +199,9 @@ declare function createSkillTools(options: SkillServerOptions): {
188
199
  /** Drops the memoised catalog, so the next call re-reads the tree. */
189
200
  refresh(): void;
190
201
  entries: () => Omit<SkillEntry, "path">[];
202
+ /** The catalog with paths, for the Skills extension. The same array until refresh. */
203
+ skills: () => readonly SkillEntry[];
191
204
  };
192
205
  type SkillTools = ReturnType<typeof createSkillTools>;
193
206
 
194
- export { CATALOG_PAGE_MAX as C, DEFAULT_FIND_LIMIT as D, type Embedder as E, type FindOptions as F, type IntentCache as I, type Match as M, READ_BUDGET_BYTES as R, type SkillServerOptions as S, type SkillTools as a, CATALOG_PAGE_SIZE as b, type CallResponse as c, type CatalogResponse as d, DESCRIBE_FILE_LIMIT as e, type FindResult as f, type IntentCacheStats as g, type Ranking as h, type ReadResult as i, type SkillFilters as j, cosine as k, createSkillTools as l, find as m, lexicalScore as n, normaliseIntent as o };
207
+ export { CATALOG_PAGE_MAX as C, DEFAULT_FIND_LIMIT as D, type Embedder as E, type FindOptions as F, type IntentCache as I, type KindFilter as K, type Match as M, 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, DESCRIBE_FILE_LIMIT as f, type FindResult as g, type IntentCacheStats as h, type Ranking as i, type ReadResult as j, type SkillFilters as k, cosine as l, createSkillTools as m, find as n, lexicalScore as o, normaliseIntent as p };
package/dist/stdio.d.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  #!/usr/bin/env node
2
- import { C as CatalogOptions } from './catalog-BiPLcbLu.js';
2
+ import { C as CatalogOptions } from './catalog-5v7jrGwP.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-JL5BCIQM.js";
7
- import "./chunk-BFET6MFN.js";
6
+ } from "./chunk-X4LYYULW.js";
7
+ import "./chunk-JOQTOVTJ.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.4.0",
3
+ "version": "0.5.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.",
@@ -75,7 +75,9 @@
75
75
  "dependencies": {
76
76
  "@modelcontextprotocol/server": "^2.0.0",
77
77
  "zod": "^4.5.1",
78
- "semver": "7.8.5"
78
+ "semver": "7.8.5",
79
+ "smol-toml": "1.8.0",
80
+ "yaml": "2.9.0"
79
81
  },
80
82
  "peerDependencies": {
81
83
  "@huggingface/transformers": ">=3"