@modootoday/pmcp 0.5.1 → 0.7.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/dist/cli.js CHANGED
@@ -1,16 +1,29 @@
1
1
  #!/usr/bin/env node
2
+ import {
3
+ loadEmbedder,
4
+ openEntryVectors
5
+ } from "./chunk-NI2OLZPA.js";
2
6
  import {
3
7
  ConfigError,
8
+ ProjectError,
9
+ TOOLS,
10
+ doctor,
4
11
  findConfig,
5
- openDatabase,
6
- readConfig
7
- } from "./chunk-XTLANVRL.js";
12
+ project,
13
+ readConfig,
14
+ readSpec,
15
+ renderFrontmatter,
16
+ spawnRunner,
17
+ splitFrontmatter
18
+ } from "./chunk-GNJSZCRH.js";
19
+ import "./chunk-ZLELYZHL.js";
8
20
  import {
9
21
  serve
10
- } from "./chunk-ICHBC5FM.js";
22
+ } from "./chunk-POJOFL4L.js";
11
23
  import {
24
+ kindOf,
12
25
  readCatalog
13
- } from "./chunk-76UKXVUE.js";
26
+ } from "./chunk-QHFORYIN.js";
14
27
 
15
28
  // src/cli/command.ts
16
29
  var ArgumentError = class extends Error {
@@ -189,109 +202,6 @@ var Ui = class {
189
202
  }
190
203
  };
191
204
 
192
- // src/embed.ts
193
- var DEFAULT_MODEL_ID = "Xenova/all-MiniLM-L6-v2";
194
- var ENTRY_SCHEMA = `
195
- CREATE TABLE IF NOT EXISTS entry_vector (
196
- name TEXT NOT NULL,
197
- model_id TEXT NOT NULL,
198
- dims INTEGER NOT NULL,
199
- description_hash TEXT NOT NULL,
200
- vector BLOB NOT NULL,
201
- PRIMARY KEY (name, model_id)
202
- );
203
- `;
204
- var TRANSFORMERS = "@huggingface/transformers";
205
- async function loadEmbedder(modelId = DEFAULT_MODEL_ID) {
206
- let module;
207
- try {
208
- module = await import(TRANSFORMERS);
209
- } catch {
210
- return null;
211
- }
212
- const factory = module.pipeline;
213
- if (typeof factory !== "function") return null;
214
- const encode = await factory("feature-extraction", modelId);
215
- let dims = 0;
216
- return {
217
- modelId,
218
- get dims() {
219
- return dims;
220
- },
221
- async embed(text) {
222
- const output = await encode(text, { pooling: "mean", normalize: true });
223
- const vector = Float32Array.from(output.data);
224
- dims = vector.length;
225
- return vector;
226
- }
227
- };
228
- }
229
- function describeHash(description) {
230
- let hash = 2166136261;
231
- for (let i = 0; i < description.length; i++) {
232
- hash ^= description.charCodeAt(i);
233
- hash = Math.imul(hash, 16777619) >>> 0;
234
- }
235
- return hash.toString(16).padStart(8, "0");
236
- }
237
- async function openEntryVectors(path) {
238
- const opened = await openDatabase(path);
239
- if (opened === null) return null;
240
- const db = opened.db;
241
- db.exec(ENTRY_SCHEMA);
242
- return {
243
- read(modelId) {
244
- const out = /* @__PURE__ */ new Map();
245
- const rows = db.prepare(
246
- "SELECT name, dims, vector FROM entry_vector WHERE model_id = ?"
247
- ).all(modelId);
248
- for (const row of rows) {
249
- const bytes = row.vector;
250
- const vector = new Float32Array(
251
- bytes.buffer.slice(
252
- bytes.byteOffset,
253
- bytes.byteOffset + bytes.byteLength
254
- )
255
- );
256
- if (vector.length === row.dims) out.set(row.name, vector);
257
- }
258
- return out;
259
- },
260
- stale(modelId, entries) {
261
- const rows = db.prepare(
262
- "SELECT name, description_hash FROM entry_vector WHERE model_id = ?"
263
- ).all(modelId);
264
- const stored = new Map(
265
- rows.map((row) => [row.name, row.description_hash])
266
- );
267
- const out = [];
268
- for (const [name, description] of entries) {
269
- if (stored.get(name) !== describeHash(description)) out.push(name);
270
- }
271
- return out;
272
- },
273
- write(modelId, name, description, vector) {
274
- db.prepare(
275
- `INSERT INTO entry_vector (name, model_id, dims, description_hash, vector)
276
- VALUES (?, ?, ?, ?, ?)
277
- ON CONFLICT(name, model_id) DO UPDATE SET
278
- dims = excluded.dims,
279
- description_hash = excluded.description_hash,
280
- vector = excluded.vector`
281
- ).run(
282
- name,
283
- modelId,
284
- vector.length,
285
- describeHash(description),
286
- new Uint8Array(vector.buffer, vector.byteOffset, vector.byteLength)
287
- );
288
- },
289
- close() {
290
- db.close();
291
- }
292
- };
293
- }
294
-
295
205
  // src/commands/roots.ts
296
206
  var CATALOG_OPTIONS = [
297
207
  {
@@ -445,7 +355,7 @@ var indexCommand = {
445
355
  return 0;
446
356
  }
447
357
  for (const entry2 of todo) {
448
- const vector = await embedder.embed(entry2.description);
358
+ const vector = embedder.embedPassage ? await embedder.embedPassage(entry2.description) : await embedder.embed(entry2.description);
449
359
  store.write(embedder.modelId, entry2.name, entry2.description, vector);
450
360
  }
451
361
  const indexed = store.read(embedder.modelId).size;
@@ -913,8 +823,8 @@ function absent(error) {
913
823
  function packageName(name) {
914
824
  return /^(?:@[a-z0-9._-]+\/)?[a-z0-9][a-z0-9._-]*$/u.test(name);
915
825
  }
916
- function locate(name, project) {
917
- let directory = project;
826
+ function locate(name, project2) {
827
+ let directory = project2;
918
828
  for (; ; ) {
919
829
  let source;
920
830
  try {
@@ -946,9 +856,9 @@ function locate(name, project) {
946
856
  }
947
857
  }
948
858
  function readInstalledDependencies(projectDirectory) {
949
- const project = resolve(projectDirectory);
859
+ const project2 = resolve(projectDirectory);
950
860
  const manifest = JSON.parse(
951
- readFileSync2(join2(project, "package.json"), "utf8")
861
+ readFileSync2(join2(project2, "package.json"), "utf8")
952
862
  );
953
863
  if (!object(manifest))
954
864
  throw new Error("project package.json must contain an object");
@@ -972,7 +882,7 @@ function readInstalledDependencies(projectDirectory) {
972
882
  const dependencies = [];
973
883
  const issues = [];
974
884
  for (const name of [...names].sort()) {
975
- const result = locate(name, project);
885
+ const result = locate(name, project2);
976
886
  if ("reason" in result) issues.push(result);
977
887
  else dependencies.push(result);
978
888
  }
@@ -1034,12 +944,12 @@ function manifestAt(directory) {
1034
944
  return value;
1035
945
  }
1036
946
  function installContext(directory) {
1037
- const project = resolve2(directory);
1038
- const manifest = manifestAt(project);
1039
- let root = project;
1040
- let ancestor = project;
947
+ const project2 = resolve2(directory);
948
+ const manifest = manifestAt(project2);
949
+ let root = project2;
950
+ let ancestor = project2;
1041
951
  for (; ; ) {
1042
- if (ancestor !== project && existsSync(join3(ancestor, "package.json"))) {
952
+ if (ancestor !== project2 && existsSync(join3(ancestor, "package.json"))) {
1043
953
  const candidate = manifestAt(ancestor);
1044
954
  if (candidate.workspaces !== void 0) {
1045
955
  root = ancestor;
@@ -1076,7 +986,7 @@ function installContext(directory) {
1076
986
  throw new Error(
1077
987
  "declare packageManager or install project dependencies first"
1078
988
  );
1079
- if (root !== project && LOCKS.some((file) => existsSync(join3(project, file)))) {
989
+ if (root !== project2 && LOCKS.some((file) => existsSync(join3(project2, file)))) {
1080
990
  throw new Error(
1081
991
  "nested project has its own lockfile; resolve the workspace boundary first"
1082
992
  );
@@ -1084,12 +994,12 @@ function installContext(directory) {
1084
994
  const files = [
1085
995
  .../* @__PURE__ */ new Set([
1086
996
  join3(root, "package.json"),
1087
- join3(project, "package.json"),
997
+ join3(project2, "package.json"),
1088
998
  ...LOCKS.map((file) => join3(root, file))
1089
999
  ])
1090
1000
  ];
1091
1001
  return {
1092
- project,
1002
+ project: project2,
1093
1003
  root,
1094
1004
  manager,
1095
1005
  manifest,
@@ -1584,10 +1494,10 @@ function createPackageManagerRunner(userConfig, baseEnv = process.env, verifiedI
1584
1494
  integrity(packageSpec, plan) {
1585
1495
  const alreadyVerified = verifiedIntegrity?.get(packageSpec);
1586
1496
  if (alreadyVerified) return alreadyVerified;
1587
- const { manager, project } = plan.context;
1497
+ const { manager, project: project2 } = plan.context;
1588
1498
  const args = manager === "npm" ? ["view", packageSpec, "dist.integrity", "--json"] : ["info", packageSpec, "dist.integrity", "--json"];
1589
1499
  const result = spawnSync(manager, args, {
1590
- cwd: project,
1500
+ cwd: project2,
1591
1501
  env: environment(userConfig, baseEnv),
1592
1502
  encoding: "utf8",
1593
1503
  shell: false,
@@ -1701,8 +1611,8 @@ function contentDigest(files) {
1701
1611
  }
1702
1612
  return `sha256:${hash.digest("hex")}`;
1703
1613
  }
1704
- function verifyInstalledContent(project, packageName2, expected) {
1705
- const root = resolve4(project, "node_modules", ...packageName2.split("/"));
1614
+ function verifyInstalledContent(project2, packageName2, expected) {
1615
+ const root = resolve4(project2, "node_modules", ...packageName2.split("/"));
1706
1616
  const files = skillFiles(root);
1707
1617
  const actual = contentDigest(files);
1708
1618
  return {
@@ -1888,9 +1798,9 @@ async function manage(context, sync) {
1888
1798
  if (!sync && !context.args.positional.length && !context.args.flags.has("all")) {
1889
1799
  throw new ArgumentError("select a skill package or pass --all");
1890
1800
  }
1891
- const project = projectFrom(context);
1892
- const install = installContext(project);
1893
- const inventory = readInstalledDependencies(project);
1801
+ const project2 = projectFrom(context);
1802
+ const install = installContext(project2);
1803
+ const inventory = readInstalledDependencies(project2);
1894
1804
  const catalog = await remoteCatalog(context);
1895
1805
  const plan = planInstall({
1896
1806
  context: install,
@@ -1907,7 +1817,7 @@ async function manage(context, sync) {
1907
1817
  ])
1908
1818
  );
1909
1819
  const mismatched = (packages) => packages.map(
1910
- (name) => verifyInstalledContent(project, name, digests.get(name) ?? "")
1820
+ (name) => verifyInstalledContent(project2, name, digests.get(name) ?? "")
1911
1821
  ).filter((check) => !check.matched);
1912
1822
  const reportMismatch = (checks) => {
1913
1823
  for (const check of checks) {
@@ -1919,12 +1829,12 @@ async function manage(context, sync) {
1919
1829
  };
1920
1830
  const report = {
1921
1831
  catalogRevision: plan.catalogRevision,
1922
- project,
1832
+ project: project2,
1923
1833
  changes: plan.changes,
1924
1834
  command: plan.command
1925
1835
  };
1926
1836
  if (!context.args.flags.has("json")) {
1927
- context.ui.info("project", project);
1837
+ context.ui.info("project", project2);
1928
1838
  for (const entry2 of plan.changes)
1929
1839
  context.ui.line(` ${entry2.packageName}@${entry2.version}`);
1930
1840
  if (plan.changes.length)
@@ -2078,6 +1988,267 @@ var syncCommand = {
2078
1988
  run: (context) => manage(context, true)
2079
1989
  };
2080
1990
 
1991
+ // src/commands/project.ts
1992
+ import { homedir as homedir2 } from "os";
1993
+
1994
+ // src/project/edit.ts
1995
+ import {
1996
+ cpSync,
1997
+ existsSync as existsSync2,
1998
+ mkdirSync as mkdirSync3,
1999
+ readFileSync as readFileSync7,
2000
+ rmSync as rmSync3,
2001
+ statSync as statSync3,
2002
+ writeFileSync as writeFileSync3
2003
+ } from "fs";
2004
+ import { basename, dirname as dirname3, join as join7 } from "path";
2005
+ var CROSS_TOOL = ["name", "description"];
2006
+ var tomlValue = (value) => JSON.stringify(value);
2007
+ function findEntry(entries, wanted) {
2008
+ const exact = entries.filter((e) => e.name === wanted);
2009
+ if (exact.length === 1 && exact[0]) return exact[0];
2010
+ const bySlug = entries.filter(
2011
+ (e) => e.slug === wanted || e.slug.endsWith(`/${wanted}`)
2012
+ );
2013
+ if (bySlug.length === 1 && bySlug[0]) return bySlug[0];
2014
+ if (bySlug.length > 1) {
2015
+ throw new ProjectError(
2016
+ `${wanted} is ambiguous: ${bySlug.map((e) => e.name).join(", ")}`
2017
+ );
2018
+ }
2019
+ throw new ProjectError(`no catalog skill or agent named ${wanted}`);
2020
+ }
2021
+ function addEntry(root, entry2) {
2022
+ const kind = kindOf(entry2);
2023
+ if (kind !== "skill" && kind !== "agent") {
2024
+ throw new ProjectError(
2025
+ `${entry2.name} is a ${kind}; only skills and agents are added to .agents/`
2026
+ );
2027
+ }
2028
+ const { meta, body } = splitFrontmatter(readFileSync7(entry2.path, "utf8"));
2029
+ const name = basename(entry2.slug);
2030
+ if (!/^[a-z0-9][a-z0-9-]*$/u.test(name)) {
2031
+ throw new ProjectError(
2032
+ `${entry2.name}: ${name} is not a usable directory name`
2033
+ );
2034
+ }
2035
+ if (kind === "skill") {
2036
+ const dest2 = join7(root, ".agents/skills", name);
2037
+ if (existsSync2(dest2))
2038
+ throw new ProjectError(`.agents/skills/${name} already exists`);
2039
+ const source = entry2.root ?? dirname3(entry2.path);
2040
+ mkdirSync3(dirname3(dest2), { recursive: true });
2041
+ if (statSync3(source).isDirectory()) {
2042
+ cpSync(source, dest2, { recursive: true });
2043
+ } else {
2044
+ mkdirSync3(dest2);
2045
+ }
2046
+ const head = renderFrontmatter({
2047
+ ...meta,
2048
+ name,
2049
+ description: meta["description"] ?? entry2.description
2050
+ });
2051
+ writeFileSync3(
2052
+ join7(dest2, "SKILL.md"),
2053
+ `${head}
2054
+ ${body.replace(/^\n/u, "")}`
2055
+ );
2056
+ return { kind, name, path: `.agents/skills/${name}` };
2057
+ }
2058
+ const dest = join7(root, ".agents/agents", name);
2059
+ if (existsSync2(dest))
2060
+ throw new ProjectError(`.agents/agents/${name} already exists`);
2061
+ const kept = {};
2062
+ const moved = {};
2063
+ for (const [key, value] of Object.entries({ ...meta, name })) {
2064
+ if (CROSS_TOOL.includes(key)) kept[key] = value;
2065
+ else moved[key] = value;
2066
+ }
2067
+ mkdirSync3(dest, { recursive: true });
2068
+ writeFileSync3(
2069
+ join7(dest, "agent.md"),
2070
+ `${renderFrontmatter(kept)}
2071
+ ${body.replace(/^\n/u, "")}`
2072
+ );
2073
+ if (Object.keys(moved).length > 0) {
2074
+ const config = join7(root, "pmcp.toml");
2075
+ const lines = [
2076
+ `[agents.${name}.claude]`,
2077
+ ...Object.entries(moved).map(([k, v]) => `${k} = ${tomlValue(v)}`)
2078
+ ];
2079
+ const before = existsSync2(config) ? readFileSync7(config, "utf8") : "";
2080
+ const sep3 = before === "" || before.endsWith("\n\n") ? "" : "\n";
2081
+ writeFileSync3(config, `${before}${sep3}${lines.join("\n")}
2082
+ `);
2083
+ }
2084
+ return { kind, name, path: `.agents/agents/${name}/agent.md` };
2085
+ }
2086
+ function withoutTables(toml, name) {
2087
+ const own = new RegExp(
2088
+ `^\\[(skills\\.${name}|agents\\.${name}(\\.[a-z]+)?)\\]\\s*$`,
2089
+ "u"
2090
+ );
2091
+ const out = [];
2092
+ let skipping = false;
2093
+ for (const line of toml.split("\n")) {
2094
+ if (/^\[/u.test(line)) skipping = own.test(line);
2095
+ if (!skipping) out.push(line);
2096
+ }
2097
+ return out.join("\n").replace(/\n{3,}/gu, "\n\n");
2098
+ }
2099
+ function removeAsset(root, name) {
2100
+ const removed = [];
2101
+ for (const rel of [`.agents/skills/${name}`, `.agents/agents/${name}`]) {
2102
+ if (!existsSync2(join7(root, rel))) continue;
2103
+ rmSync3(join7(root, rel), { recursive: true, force: true });
2104
+ removed.push(rel);
2105
+ }
2106
+ if (removed.length === 0)
2107
+ throw new ProjectError(`no skill or agent named ${name} in .agents/`);
2108
+ const config = join7(root, "pmcp.toml");
2109
+ if (existsSync2(config)) {
2110
+ const before = readFileSync7(config, "utf8");
2111
+ const after = withoutTables(before, name);
2112
+ if (after !== before) writeFileSync3(config, after);
2113
+ }
2114
+ return removed;
2115
+ }
2116
+
2117
+ // src/commands/project.ts
2118
+ function specFrom(context) {
2119
+ const config = configFrom(context);
2120
+ if (config === null) {
2121
+ throw new ArgumentError(
2122
+ "no pmcp.toml at or above this directory; pass --config <file>"
2123
+ );
2124
+ }
2125
+ try {
2126
+ return readSpec(config);
2127
+ } catch (error) {
2128
+ throw new ArgumentError(
2129
+ error instanceof Error ? error.message : String(error)
2130
+ );
2131
+ }
2132
+ }
2133
+ function reproject(context, spec) {
2134
+ const result = project(spec, { check: false });
2135
+ for (const problem of result.problems) context.ui.error(problem);
2136
+ if (result.code !== 0) return 1;
2137
+ context.ui.success(
2138
+ `projected ${result.outputs} outputs`,
2139
+ result.pruned > 0 ? `pruned ${result.pruned}` : void 0
2140
+ );
2141
+ return 0;
2142
+ }
2143
+ var projectCommand = {
2144
+ name: "project",
2145
+ describe: "Write each agent tool's native files from .agents/ and pmcp.toml",
2146
+ usage: "pmcp project [--check] | pmcp project add <skill|agent> | pmcp project remove <name>",
2147
+ options: [
2148
+ ...CATALOG_OPTIONS,
2149
+ {
2150
+ name: "check",
2151
+ describe: "Write nothing; exit 2 when an output drifted, went stale or is undeclared.",
2152
+ boolean: true
2153
+ }
2154
+ ],
2155
+ run(context) {
2156
+ const [verb, name, ...extra] = context.args.positional;
2157
+ if (extra.length > 0)
2158
+ throw new ArgumentError(`unexpected ${extra.join(" ")}`);
2159
+ try {
2160
+ if (verb === void 0) {
2161
+ const spec = specFrom(context);
2162
+ if (!context.args.flags.has("check")) return reproject(context, spec);
2163
+ const result = project(spec, { check: true });
2164
+ for (const problem of result.problems) context.ui.error(problem);
2165
+ if (result.code !== 0) {
2166
+ context.ui.info(
2167
+ "fix",
2168
+ "pmcp project (edit .agents/ or pmcp.toml, never the outputs)"
2169
+ );
2170
+ return 2;
2171
+ }
2172
+ context.ui.success(`${result.outputs} outputs match`);
2173
+ return 0;
2174
+ }
2175
+ if (context.args.flags.has("check"))
2176
+ throw new ArgumentError("--check takes no subcommand");
2177
+ if (name === void 0) throw new ArgumentError(`${verb} needs a name`);
2178
+ if (verb === "add") {
2179
+ const spec = specFrom(context);
2180
+ const added = addEntry(
2181
+ spec.root,
2182
+ findEntry(catalogFrom(context), name)
2183
+ );
2184
+ context.ui.success(`added ${added.kind} ${added.name}`, added.path);
2185
+ return reproject(context, specFrom(context));
2186
+ }
2187
+ if (verb === "remove") {
2188
+ const spec = specFrom(context);
2189
+ for (const path of removeAsset(spec.root, name))
2190
+ context.ui.success("removed", path);
2191
+ return reproject(context, specFrom(context));
2192
+ }
2193
+ throw new ArgumentError(`unknown subcommand ${verb}`);
2194
+ } catch (error) {
2195
+ if (error instanceof ProjectError) {
2196
+ context.ui.error(error.message);
2197
+ return 1;
2198
+ }
2199
+ throw error;
2200
+ }
2201
+ }
2202
+ };
2203
+ var MARKS = {
2204
+ ok: "ok",
2205
+ fail: "FAIL",
2206
+ skip: "skip"
2207
+ };
2208
+ var doctorCommand = {
2209
+ name: "doctor",
2210
+ describe: "Ask each agent tool, through its own listing commands, whether it loads this project's assets",
2211
+ usage: "pmcp doctor [--tool <name>] [--json]",
2212
+ options: [
2213
+ {
2214
+ name: "config",
2215
+ describe: "A pmcp.toml to read instead of the nearest one.",
2216
+ placeholder: "<file>"
2217
+ },
2218
+ {
2219
+ name: "tool",
2220
+ describe: `Check only this tool (${TOOLS.join(", ")}). Repeatable.`,
2221
+ repeat: true,
2222
+ placeholder: "<name>"
2223
+ },
2224
+ { name: "json", describe: "Emit JSON rather than a table.", boolean: true }
2225
+ ],
2226
+ run(context) {
2227
+ const only = many(context.args, "tool");
2228
+ for (const tool of only) {
2229
+ if (!TOOLS.includes(tool))
2230
+ throw new ArgumentError(`unknown tool ${tool}`);
2231
+ }
2232
+ const findings = doctor(specFrom(context), {
2233
+ run: spawnRunner,
2234
+ home: context.env["HOME"] ?? homedir2(),
2235
+ ...only.length > 0 ? { only: new Set(only) } : {}
2236
+ });
2237
+ if (context.args.flags.has("json")) {
2238
+ context.ui.data(`${JSON.stringify({ findings }, null, 2)}
2239
+ `);
2240
+ } else {
2241
+ context.ui.table(
2242
+ findings.map((f) => [
2243
+ `${MARKS[f.status]} ${f.tool}`,
2244
+ f.detail ? `${f.check} (${f.detail})` : f.check
2245
+ ])
2246
+ );
2247
+ }
2248
+ return findings.some((f) => f.status === "fail") ? 1 : 0;
2249
+ }
2250
+ };
2251
+
2081
2252
  // src/commands/index.ts
2082
2253
  var COMMANDS = [
2083
2254
  serveCommand,
@@ -2089,7 +2260,9 @@ var COMMANDS = [
2089
2260
  availableCommand,
2090
2261
  previewCommand,
2091
2262
  installCommand,
2092
- syncCommand
2263
+ syncCommand,
2264
+ projectCommand,
2265
+ doctorCommand
2093
2266
  ];
2094
2267
  var PLANNED = [];
2095
2268
  var GLOBAL = /* @__PURE__ */ new Set(["-q", "--quiet", "--no-color", "--color"]);
@@ -2135,7 +2308,7 @@ function dispatch(argv, options = {}) {
2135
2308
  }
2136
2309
  return run(command, rest, { ui, env, cwd });
2137
2310
  }
2138
- var VERSION = "0.5.1";
2311
+ var VERSION = "0.7.0";
2139
2312
  async function run(command, argv, context) {
2140
2313
  try {
2141
2314
  return await command.run({
package/dist/http.d.ts CHANGED
@@ -1,5 +1,40 @@
1
1
  import { S as SkillEntry } from './catalog-5v7jrGwP.js';
2
- import { S as SkillServerOptions } from './server-Dm71qZgM.js';
2
+ import { E as Embedder, S as SkillServerOptions } from './server-wpYiAJ2n.js';
3
+
4
+ /**
5
+ * The optional encoder and the store for the vectors it produces.
6
+ *
7
+ * Neither the model nor its runtime is a dependency: a caller who wants
8
+ * semantic ranking installs the peer and runs `pmcp index`, and everything
9
+ * here degrades to null rather than throwing when that has not happened.
10
+ */
11
+
12
+ /**
13
+ * What `pmcp index` writes and what the server reads back. Multilingual, so a
14
+ * Korean intent finds an English description (measured 20261005: 8/8 Korean
15
+ * and 8/8 English intents in the top three over a 99-skill catalog).
16
+ */
17
+ declare const DEFAULT_MODEL_ID = "Xenova/multilingual-e5-small";
18
+ interface LoadEmbedderOptions {
19
+ /** Where model files live; a host bakes them into its image here. */
20
+ readonly cacheDir?: string;
21
+ /** Refuse to download, so a missing model is an error rather than a fetch. */
22
+ readonly localOnly?: boolean;
23
+ /**
24
+ * Weight precision. q8 is a quarter of fp32's size (118 MB against 470 MB for
25
+ * the default model) and ranked the same in the 20261005 measurement.
26
+ */
27
+ readonly dtype?: "q8" | "fp32";
28
+ /** Injected for tests. The optional peer is imported otherwise. */
29
+ readonly module?: unknown;
30
+ }
31
+ /**
32
+ * Loads the encoder, or returns null when the peer is not installed.
33
+ *
34
+ * Absence is not failure anywhere in this package: the caller reports it and
35
+ * ranking stays lexical.
36
+ */
37
+ declare function loadEmbedder(modelId?: string, options?: LoadEmbedderOptions): Promise<Embedder | null>;
3
38
 
4
39
  /**
5
40
  * The catalog over streamable HTTP, for a hosted skills server.
@@ -9,6 +44,15 @@ import { S as SkillServerOptions } from './server-Dm71qZgM.js';
9
44
  * tiers tiersFor() grants. The catalog is read once and filtered per request.
10
45
  */
11
46
 
47
+ /** Semantic ranking for a hosted catalog: the encoder runs in the host process. */
48
+ interface SkillHttpSemanticOptions extends Omit<LoadEmbedderOptions, "module"> {
49
+ /** Defaults to the multilingual model pmcp index uses. */
50
+ readonly modelId?: string;
51
+ /** Injected for tests, or by a host that already holds an encoder. */
52
+ readonly embedder?: Embedder;
53
+ /** Told when the encoder cannot load; ranking then stays lexical. */
54
+ readonly onError?: (error: unknown) => void;
55
+ }
12
56
  interface SkillCaller {
13
57
  /** Stable id of the signed-in user, recorded by the host, never by pmcp. */
14
58
  readonly id: string;
@@ -21,6 +65,8 @@ interface SkillHttpOptions extends SkillServerOptions {
21
65
  readonly tiersFor?: (caller: SkillCaller) => readonly string[];
22
66
  /** Sent in WWW-Authenticate on a refused request, e.g. a resource metadata URL. */
23
67
  readonly challenge?: string;
68
+ /** Encode the catalog at start so find ranks by meaning across languages. */
69
+ readonly semantic?: SkillHttpSemanticOptions;
24
70
  }
25
71
  declare const DEFAULT_TIERS: readonly string[];
26
72
  declare function visibleTo(entries: readonly SkillEntry[], tiers: readonly string[]): SkillEntry[];
@@ -28,7 +74,9 @@ interface SkillHttpHandler {
28
74
  fetch(request: Request): Promise<Response>;
29
75
  /** Re-read the catalog, for a host that deploys new skill releases in place. */
30
76
  reload(): void;
77
+ /** Settles once the catalog is encoded, or at once when ranking is lexical. */
78
+ ready(): Promise<"semantic" | "lexical">;
31
79
  }
32
80
  declare function createSkillHttpHandler(options: SkillHttpOptions): SkillHttpHandler;
33
81
 
34
- export { DEFAULT_TIERS, type SkillCaller, type SkillHttpHandler, type SkillHttpOptions, createSkillHttpHandler, visibleTo };
82
+ export { DEFAULT_MODEL_ID, DEFAULT_TIERS, Embedder, type SkillCaller, type SkillHttpHandler, type SkillHttpOptions, type SkillHttpSemanticOptions, createSkillHttpHandler, loadEmbedder, visibleTo };