@mcpc-tech/core 0.3.14 → 0.3.16

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mcpc-tech/core",
3
- "version": "0.3.14",
3
+ "version": "0.3.16",
4
4
  "homepage": "https://jsr.io/@mcpc/core",
5
5
  "dependencies": {
6
6
  "@ai-sdk/provider": "^2.0.0",
@@ -43,6 +43,11 @@
43
43
  "import": "./plugins/large-result.mjs",
44
44
  "require": "./plugins/large-result.cjs"
45
45
  },
46
+ "./plugins/skills": {
47
+ "types": "./types/src/plugins/skills.d.ts",
48
+ "import": "./plugins/skills.mjs",
49
+ "require": "./plugins/skills.cjs"
50
+ },
46
51
  "./types/*": "./types/*"
47
52
  },
48
53
  "repository": {
@@ -72,15 +72,18 @@ function createSearchPlugin(options = {}) {
72
72
  const allowedSearchDir = options.allowedDir || (0, import_node_os.tmpdir)();
73
73
  const timeoutMs = options.timeoutMs || 3e4;
74
74
  const global = options.global ?? true;
75
+ const agentName = options.agentName;
76
+ const toolName = agentName ? `${agentName}__search-tool-result` : "search-tool-result";
75
77
  const activeTimeouts = /* @__PURE__ */ new Set();
76
78
  return {
77
79
  name: "plugin-search",
78
80
  version: "1.0.0",
79
81
  configureServer: (server) => {
80
- const defaultDescription = `Search for text patterns in files and directories. Use this to find specific content, code, or information within files. Provide a simple literal string or a regular expression. If your pattern is a regex, ensure it's valid; otherwise use quotes or escape special characters to treat it as a literal string.
82
+ const defaultDescription = agentName ? `Search for text patterns in files for the "${agentName}" agent. Use this to find specific content within large tool results. Provide a simple literal string or a regular expression.
83
+ Only search within the allowed directory: ${allowedSearchDir}` : `Search for text patterns in files and directories. Use this to find specific content, code, or information within files. Provide a simple literal string or a regular expression. If your pattern is a regex, ensure it's valid; otherwise use quotes or escape special characters to treat it as a literal string.
81
84
  Only search within the allowed directory: ${allowedSearchDir}`;
82
85
  const toolDescription = options.toolDescription || defaultDescription;
83
- server.tool("search-tool-result", toolDescription, jsonSchema({
86
+ server.tool(toolName, toolDescription, jsonSchema({
84
87
  type: "object",
85
88
  properties: {
86
89
  pattern: {
@@ -295,28 +298,34 @@ function createLargeResultPlugin(options = {}) {
295
298
  const maxSize = options.maxSize || 8e3;
296
299
  const previewSize = options.previewSize || 4e3;
297
300
  let tempDir = options.tempDir || null;
298
- const configuredServers = /* @__PURE__ */ new Map();
301
+ let serverRef = null;
302
+ let agentName = null;
299
303
  const defaultSearchDescription = `Search within large tool result files that were saved due to size limits. Use when: a tool result was saved to file because it exceeded the context limit. Do NOT use this tool before calling the actual tool first. Provide specific keywords or patterns related to the content you're looking for.`;
300
- const searchConfig = {
301
- maxResults: options.search?.maxResults || 15,
302
- maxOutputSize: options.search?.maxOutputSize || 4e3,
303
- toolDescription: options.search?.toolDescription || defaultSearchDescription,
304
- global: true
305
- };
306
304
  return {
307
305
  name: "plugin-large-result-handler",
308
306
  version: "1.0.0",
309
307
  dependencies: [],
310
308
  // Search plugin will be added dynamically
311
- configureServer: async (server) => {
312
- if (!configuredServers.has(server)) {
309
+ configureServer: (server) => {
310
+ serverRef = server;
311
+ },
312
+ composeStart: async (context) => {
313
+ agentName = context.serverName;
314
+ if (serverRef) {
315
+ const searchConfig = {
316
+ maxResults: options.search?.maxResults || 15,
317
+ maxOutputSize: options.search?.maxOutputSize || 4e3,
318
+ toolDescription: options.search?.toolDescription || defaultSearchDescription,
319
+ global: true,
320
+ agentName
321
+ };
313
322
  const searchPlugin = createSearchPlugin(searchConfig);
314
- await server.addPlugin(searchPlugin);
315
- configuredServers.set(server, true);
323
+ await serverRef.addPlugin(searchPlugin);
316
324
  }
317
325
  },
318
326
  transformTool: (tool, context) => {
319
327
  const originalExecute = tool.execute;
328
+ const searchToolName = agentName ? `${agentName}__search-tool-result` : "search-tool-result";
320
329
  tool.execute = async (args) => {
321
330
  try {
322
331
  const result = await originalExecute(args);
@@ -348,7 +357,7 @@ ${preview}
348
357
  \`\`\`
349
358
 
350
359
  **To read/understand the full content:**
351
- - Use the \`search-tool-result\` tool with pattern: \`search-tool-result {"pattern": "your-search-term"}\`
360
+ - Use the \`${searchToolName}\` tool with pattern: \`${searchToolName} {"pattern": "your-search-term"}\`
352
361
  - Search supports regex patterns for advanced queries`
353
362
  }
354
363
  ]
@@ -364,7 +373,8 @@ ${preview}
364
373
  return tool;
365
374
  },
366
375
  dispose: () => {
367
- configuredServers.clear();
376
+ serverRef = null;
377
+ agentName = null;
368
378
  tempDir = null;
369
379
  }
370
380
  };
@@ -40,15 +40,18 @@ function createSearchPlugin(options = {}) {
40
40
  const allowedSearchDir = options.allowedDir || tmpdir();
41
41
  const timeoutMs = options.timeoutMs || 3e4;
42
42
  const global = options.global ?? true;
43
+ const agentName = options.agentName;
44
+ const toolName = agentName ? `${agentName}__search-tool-result` : "search-tool-result";
43
45
  const activeTimeouts = /* @__PURE__ */ new Set();
44
46
  return {
45
47
  name: "plugin-search",
46
48
  version: "1.0.0",
47
49
  configureServer: (server) => {
48
- const defaultDescription = `Search for text patterns in files and directories. Use this to find specific content, code, or information within files. Provide a simple literal string or a regular expression. If your pattern is a regex, ensure it's valid; otherwise use quotes or escape special characters to treat it as a literal string.
50
+ const defaultDescription = agentName ? `Search for text patterns in files for the "${agentName}" agent. Use this to find specific content within large tool results. Provide a simple literal string or a regular expression.
51
+ Only search within the allowed directory: ${allowedSearchDir}` : `Search for text patterns in files and directories. Use this to find specific content, code, or information within files. Provide a simple literal string or a regular expression. If your pattern is a regex, ensure it's valid; otherwise use quotes or escape special characters to treat it as a literal string.
49
52
  Only search within the allowed directory: ${allowedSearchDir}`;
50
53
  const toolDescription = options.toolDescription || defaultDescription;
51
- server.tool("search-tool-result", toolDescription, jsonSchema({
54
+ server.tool(toolName, toolDescription, jsonSchema({
52
55
  type: "object",
53
56
  properties: {
54
57
  pattern: {
@@ -263,28 +266,34 @@ function createLargeResultPlugin(options = {}) {
263
266
  const maxSize = options.maxSize || 8e3;
264
267
  const previewSize = options.previewSize || 4e3;
265
268
  let tempDir = options.tempDir || null;
266
- const configuredServers = /* @__PURE__ */ new Map();
269
+ let serverRef = null;
270
+ let agentName = null;
267
271
  const defaultSearchDescription = `Search within large tool result files that were saved due to size limits. Use when: a tool result was saved to file because it exceeded the context limit. Do NOT use this tool before calling the actual tool first. Provide specific keywords or patterns related to the content you're looking for.`;
268
- const searchConfig = {
269
- maxResults: options.search?.maxResults || 15,
270
- maxOutputSize: options.search?.maxOutputSize || 4e3,
271
- toolDescription: options.search?.toolDescription || defaultSearchDescription,
272
- global: true
273
- };
274
272
  return {
275
273
  name: "plugin-large-result-handler",
276
274
  version: "1.0.0",
277
275
  dependencies: [],
278
276
  // Search plugin will be added dynamically
279
- configureServer: async (server) => {
280
- if (!configuredServers.has(server)) {
277
+ configureServer: (server) => {
278
+ serverRef = server;
279
+ },
280
+ composeStart: async (context) => {
281
+ agentName = context.serverName;
282
+ if (serverRef) {
283
+ const searchConfig = {
284
+ maxResults: options.search?.maxResults || 15,
285
+ maxOutputSize: options.search?.maxOutputSize || 4e3,
286
+ toolDescription: options.search?.toolDescription || defaultSearchDescription,
287
+ global: true,
288
+ agentName
289
+ };
281
290
  const searchPlugin = createSearchPlugin(searchConfig);
282
- await server.addPlugin(searchPlugin);
283
- configuredServers.set(server, true);
291
+ await serverRef.addPlugin(searchPlugin);
284
292
  }
285
293
  },
286
294
  transformTool: (tool, context) => {
287
295
  const originalExecute = tool.execute;
296
+ const searchToolName = agentName ? `${agentName}__search-tool-result` : "search-tool-result";
288
297
  tool.execute = async (args) => {
289
298
  try {
290
299
  const result = await originalExecute(args);
@@ -316,7 +325,7 @@ ${preview}
316
325
  \`\`\`
317
326
 
318
327
  **To read/understand the full content:**
319
- - Use the \`search-tool-result\` tool with pattern: \`search-tool-result {"pattern": "your-search-term"}\`
328
+ - Use the \`${searchToolName}\` tool with pattern: \`${searchToolName} {"pattern": "your-search-term"}\`
320
329
  - Search supports regex patterns for advanced queries`
321
330
  }
322
331
  ]
@@ -332,7 +341,8 @@ ${preview}
332
341
  return tool;
333
342
  },
334
343
  dispose: () => {
335
- configuredServers.clear();
344
+ serverRef = null;
345
+ agentName = null;
336
346
  tempDir = null;
337
347
  }
338
348
  };
@@ -67,16 +67,19 @@ function createSearchPlugin(options = {}) {
67
67
  const allowedSearchDir = options.allowedDir || (0, import_node_os.tmpdir)();
68
68
  const timeoutMs = options.timeoutMs || 3e4;
69
69
  const global = options.global ?? true;
70
+ const agentName = options.agentName;
71
+ const toolName = agentName ? `${agentName}__search-tool-result` : "search-tool-result";
70
72
  const activeTimeouts = /* @__PURE__ */ new Set();
71
73
  return {
72
74
  name: "plugin-search",
73
75
  version: "1.0.0",
74
76
  configureServer: (server) => {
75
- const defaultDescription = `Search for text patterns in files and directories. Use this to find specific content, code, or information within files. Provide a simple literal string or a regular expression. If your pattern is a regex, ensure it's valid; otherwise use quotes or escape special characters to treat it as a literal string.
77
+ const defaultDescription = agentName ? `Search for text patterns in files for the "${agentName}" agent. Use this to find specific content within large tool results. Provide a simple literal string or a regular expression.
78
+ Only search within the allowed directory: ${allowedSearchDir}` : `Search for text patterns in files and directories. Use this to find specific content, code, or information within files. Provide a simple literal string or a regular expression. If your pattern is a regex, ensure it's valid; otherwise use quotes or escape special characters to treat it as a literal string.
76
79
  Only search within the allowed directory: ${allowedSearchDir}`;
77
80
  const toolDescription = options.toolDescription || defaultDescription;
78
81
  server.tool(
79
- "search-tool-result",
82
+ toolName,
80
83
  toolDescription,
81
84
  jsonSchema({
82
85
  type: "object",
@@ -35,16 +35,19 @@ function createSearchPlugin(options = {}) {
35
35
  const allowedSearchDir = options.allowedDir || tmpdir();
36
36
  const timeoutMs = options.timeoutMs || 3e4;
37
37
  const global = options.global ?? true;
38
+ const agentName = options.agentName;
39
+ const toolName = agentName ? `${agentName}__search-tool-result` : "search-tool-result";
38
40
  const activeTimeouts = /* @__PURE__ */ new Set();
39
41
  return {
40
42
  name: "plugin-search",
41
43
  version: "1.0.0",
42
44
  configureServer: (server) => {
43
- const defaultDescription = `Search for text patterns in files and directories. Use this to find specific content, code, or information within files. Provide a simple literal string or a regular expression. If your pattern is a regex, ensure it's valid; otherwise use quotes or escape special characters to treat it as a literal string.
45
+ const defaultDescription = agentName ? `Search for text patterns in files for the "${agentName}" agent. Use this to find specific content within large tool results. Provide a simple literal string or a regular expression.
46
+ Only search within the allowed directory: ${allowedSearchDir}` : `Search for text patterns in files and directories. Use this to find specific content, code, or information within files. Provide a simple literal string or a regular expression. If your pattern is a regex, ensure it's valid; otherwise use quotes or escape special characters to treat it as a literal string.
44
47
  Only search within the allowed directory: ${allowedSearchDir}`;
45
48
  const toolDescription = options.toolDescription || defaultDescription;
46
49
  server.tool(
47
- "search-tool-result",
50
+ toolName,
48
51
  toolDescription,
49
52
  jsonSchema({
50
53
  type: "object",
@@ -0,0 +1,231 @@
1
+ #!/usr/bin/env node
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __export = (target, all) => {
7
+ for (var name in all)
8
+ __defProp(target, name, { get: all[name], enumerable: true });
9
+ };
10
+ var __copyProps = (to, from, except, desc) => {
11
+ if (from && typeof from === "object" || typeof from === "function") {
12
+ for (let key of __getOwnPropNames(from))
13
+ if (!__hasOwnProp.call(to, key) && key !== except)
14
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
+ }
16
+ return to;
17
+ };
18
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
+
20
+ // __mcpc__core_latest/node_modules/@mcpc/core/src/plugins/skills.ts
21
+ var skills_exports = {};
22
+ __export(skills_exports, {
23
+ createPlugin: () => createPlugin,
24
+ createSkillsPlugin: () => createSkillsPlugin,
25
+ default: () => skills_default
26
+ });
27
+ module.exports = __toCommonJS(skills_exports);
28
+ var import_promises = require("node:fs/promises");
29
+ var import_node_path = require("node:path");
30
+
31
+ // __mcpc__core_latest/node_modules/@mcpc/core/src/utils/schema.js
32
+ var schemaSymbol = Symbol.for("mcpc.schema");
33
+ var vercelSchemaSymbol = Symbol.for("vercel.ai.schema");
34
+ var validatorSymbol = Symbol.for("mcpc.validator");
35
+ function jsonSchema(schema, options = {}) {
36
+ if (isWrappedSchema(schema)) {
37
+ return schema;
38
+ }
39
+ return {
40
+ [schemaSymbol]: true,
41
+ [validatorSymbol]: true,
42
+ _type: void 0,
43
+ jsonSchema: schema,
44
+ validate: options.validate
45
+ };
46
+ }
47
+ function isWrappedSchema(value) {
48
+ return typeof value === "object" && value !== null && (schemaSymbol in value && value[schemaSymbol] === true || vercelSchemaSymbol in value && value[vercelSchemaSymbol] === true);
49
+ }
50
+
51
+ // __mcpc__core_latest/node_modules/@mcpc/core/src/plugins/skills.ts
52
+ function parseFrontmatter(content) {
53
+ const match = content.match(/^---\n([\s\S]*?)\n---/);
54
+ if (!match) return null;
55
+ const yaml = match[1];
56
+ let name = "", description = "";
57
+ for (const line of yaml.split("\n")) {
58
+ const m = line.match(/^(name|description):\s*(.+)$/);
59
+ if (m) {
60
+ const value = m[2].replace(/^["']|["']$/g, "");
61
+ if (m[1] === "name") name = value;
62
+ else description = value;
63
+ }
64
+ }
65
+ return name && description ? { name, description } : null;
66
+ }
67
+ function extractBody(content) {
68
+ return content.replace(/^---\n[\s\S]*?\n---\n*/, "");
69
+ }
70
+ async function scanSkills(basePath) {
71
+ const skills = [];
72
+ try {
73
+ const entries = await (0, import_promises.readdir)(basePath, { withFileTypes: true });
74
+ for (const entry of entries) {
75
+ if (!entry.isDirectory()) continue;
76
+ const skillDir = (0, import_node_path.join)(basePath, entry.name);
77
+ const skillFile = (0, import_node_path.join)(skillDir, "SKILL.md");
78
+ try {
79
+ const content = await (0, import_promises.readFile)(skillFile, "utf-8");
80
+ const frontmatter = parseFrontmatter(content);
81
+ if (frontmatter && frontmatter.name === entry.name) {
82
+ skills.push({
83
+ ...frontmatter,
84
+ basePath: skillDir
85
+ });
86
+ }
87
+ } catch {
88
+ }
89
+ }
90
+ } catch {
91
+ }
92
+ return skills;
93
+ }
94
+ function generateToolDescription(skills, agentName) {
95
+ if (skills.length === 0) {
96
+ return "Load a skill's instructions. No skills available.";
97
+ }
98
+ const skillsList = skills.map((s) => `- ${s.name}: ${s.description}`).join("\n");
99
+ const toolName = `${agentName}__load-skill`;
100
+ return `Load a skill's instructions or reference files for the "${agentName}" agent.
101
+
102
+ Available skills:
103
+ ${skillsList}
104
+
105
+ Usage:
106
+ - ${toolName}({ skill: "skill-name" }) - Load main SKILL.md content
107
+ - ${toolName}({ skill: "skill-name", ref: "path/to/file" }) - Load reference file
108
+
109
+ Note: For scripts/ and assets/, use appropriate tools directly.`;
110
+ }
111
+ function createSkillsPlugin(options) {
112
+ const { paths } = options;
113
+ const skillsMap = /* @__PURE__ */ new Map();
114
+ let serverRef = null;
115
+ return {
116
+ name: "plugin-skills",
117
+ version: "1.0.0",
118
+ // Save server reference
119
+ configureServer: (server) => {
120
+ serverRef = server;
121
+ },
122
+ // Scan directories and register tool
123
+ composeStart: async (context) => {
124
+ skillsMap.clear();
125
+ for (const dir of paths) {
126
+ const skills = await scanSkills(dir);
127
+ for (const skill of skills) {
128
+ skillsMap.set(skill.name, skill);
129
+ }
130
+ }
131
+ const agentName = context.serverName;
132
+ const toolDescription = generateToolDescription(
133
+ Array.from(skillsMap.values()),
134
+ agentName
135
+ );
136
+ const toolName = `${agentName}__load-skill`;
137
+ if (serverRef) {
138
+ serverRef.tool(
139
+ toolName,
140
+ toolDescription,
141
+ jsonSchema({
142
+ type: "object",
143
+ properties: {
144
+ skill: {
145
+ type: "string",
146
+ description: "The skill name to load"
147
+ },
148
+ ref: {
149
+ type: "string",
150
+ description: "Optional: relative path to any file within the skill directory"
151
+ }
152
+ },
153
+ required: ["skill"]
154
+ }),
155
+ async (args) => {
156
+ const meta = skillsMap.get(args.skill);
157
+ if (!meta) {
158
+ return {
159
+ content: [
160
+ { type: "text", text: `Skill "${args.skill}" not found` }
161
+ ],
162
+ isError: true
163
+ };
164
+ }
165
+ if (args.ref) {
166
+ const refPath = (0, import_node_path.resolve)(meta.basePath, args.ref);
167
+ const relPath = (0, import_node_path.relative)(meta.basePath, refPath);
168
+ if (relPath.startsWith("..")) {
169
+ return {
170
+ content: [{
171
+ type: "text",
172
+ text: `Invalid path: ${args.ref}`
173
+ }],
174
+ isError: true
175
+ };
176
+ }
177
+ const dir = relPath.split(/[/\\]/)[0];
178
+ if (dir === "scripts" || dir === "assets") {
179
+ return {
180
+ content: [{ type: "text", text: `Path: ${refPath}` }]
181
+ };
182
+ }
183
+ try {
184
+ const content = await (0, import_promises.readFile)(refPath, "utf-8");
185
+ return { content: [{ type: "text", text: content }] };
186
+ } catch {
187
+ return {
188
+ content: [{
189
+ type: "text",
190
+ text: `File not found: ${args.ref}`
191
+ }],
192
+ isError: true
193
+ };
194
+ }
195
+ }
196
+ try {
197
+ const content = await (0, import_promises.readFile)(
198
+ (0, import_node_path.join)(meta.basePath, "SKILL.md"),
199
+ "utf-8"
200
+ );
201
+ const body = extractBody(content);
202
+ return { content: [{ type: "text", text: body }] };
203
+ } catch {
204
+ return {
205
+ content: [
206
+ { type: "text", text: `Failed to load skill: ${args.skill}` }
207
+ ],
208
+ isError: true
209
+ };
210
+ }
211
+ },
212
+ { internal: false }
213
+ );
214
+ }
215
+ },
216
+ dispose: () => {
217
+ skillsMap.clear();
218
+ serverRef = null;
219
+ }
220
+ };
221
+ }
222
+ function createPlugin(params) {
223
+ const paths = params.paths?.split(",").map((p) => p.trim()).filter(Boolean) || [];
224
+ return createSkillsPlugin({ paths });
225
+ }
226
+ var skills_default = createSkillsPlugin;
227
+ // Annotate the CommonJS export names for ESM import in node:
228
+ 0 && (module.exports = {
229
+ createPlugin,
230
+ createSkillsPlugin
231
+ });
@@ -0,0 +1,209 @@
1
+ #!/usr/bin/env node
2
+ import { createRequire } from 'node:module';
3
+ const require = createRequire(import.meta.url);
4
+
5
+ // __mcpc__core_latest/node_modules/@mcpc/core/src/plugins/skills.ts
6
+ import { readdir, readFile } from "node:fs/promises";
7
+ import { join, relative, resolve } from "node:path";
8
+
9
+ // __mcpc__core_latest/node_modules/@mcpc/core/src/utils/schema.js
10
+ var schemaSymbol = Symbol.for("mcpc.schema");
11
+ var vercelSchemaSymbol = Symbol.for("vercel.ai.schema");
12
+ var validatorSymbol = Symbol.for("mcpc.validator");
13
+ function jsonSchema(schema, options = {}) {
14
+ if (isWrappedSchema(schema)) {
15
+ return schema;
16
+ }
17
+ return {
18
+ [schemaSymbol]: true,
19
+ [validatorSymbol]: true,
20
+ _type: void 0,
21
+ jsonSchema: schema,
22
+ validate: options.validate
23
+ };
24
+ }
25
+ function isWrappedSchema(value) {
26
+ return typeof value === "object" && value !== null && (schemaSymbol in value && value[schemaSymbol] === true || vercelSchemaSymbol in value && value[vercelSchemaSymbol] === true);
27
+ }
28
+
29
+ // __mcpc__core_latest/node_modules/@mcpc/core/src/plugins/skills.ts
30
+ function parseFrontmatter(content) {
31
+ const match = content.match(/^---\n([\s\S]*?)\n---/);
32
+ if (!match) return null;
33
+ const yaml = match[1];
34
+ let name = "", description = "";
35
+ for (const line of yaml.split("\n")) {
36
+ const m = line.match(/^(name|description):\s*(.+)$/);
37
+ if (m) {
38
+ const value = m[2].replace(/^["']|["']$/g, "");
39
+ if (m[1] === "name") name = value;
40
+ else description = value;
41
+ }
42
+ }
43
+ return name && description ? { name, description } : null;
44
+ }
45
+ function extractBody(content) {
46
+ return content.replace(/^---\n[\s\S]*?\n---\n*/, "");
47
+ }
48
+ async function scanSkills(basePath) {
49
+ const skills = [];
50
+ try {
51
+ const entries = await readdir(basePath, { withFileTypes: true });
52
+ for (const entry of entries) {
53
+ if (!entry.isDirectory()) continue;
54
+ const skillDir = join(basePath, entry.name);
55
+ const skillFile = join(skillDir, "SKILL.md");
56
+ try {
57
+ const content = await readFile(skillFile, "utf-8");
58
+ const frontmatter = parseFrontmatter(content);
59
+ if (frontmatter && frontmatter.name === entry.name) {
60
+ skills.push({
61
+ ...frontmatter,
62
+ basePath: skillDir
63
+ });
64
+ }
65
+ } catch {
66
+ }
67
+ }
68
+ } catch {
69
+ }
70
+ return skills;
71
+ }
72
+ function generateToolDescription(skills, agentName) {
73
+ if (skills.length === 0) {
74
+ return "Load a skill's instructions. No skills available.";
75
+ }
76
+ const skillsList = skills.map((s) => `- ${s.name}: ${s.description}`).join("\n");
77
+ const toolName = `${agentName}__load-skill`;
78
+ return `Load a skill's instructions or reference files for the "${agentName}" agent.
79
+
80
+ Available skills:
81
+ ${skillsList}
82
+
83
+ Usage:
84
+ - ${toolName}({ skill: "skill-name" }) - Load main SKILL.md content
85
+ - ${toolName}({ skill: "skill-name", ref: "path/to/file" }) - Load reference file
86
+
87
+ Note: For scripts/ and assets/, use appropriate tools directly.`;
88
+ }
89
+ function createSkillsPlugin(options) {
90
+ const { paths } = options;
91
+ const skillsMap = /* @__PURE__ */ new Map();
92
+ let serverRef = null;
93
+ return {
94
+ name: "plugin-skills",
95
+ version: "1.0.0",
96
+ // Save server reference
97
+ configureServer: (server) => {
98
+ serverRef = server;
99
+ },
100
+ // Scan directories and register tool
101
+ composeStart: async (context) => {
102
+ skillsMap.clear();
103
+ for (const dir of paths) {
104
+ const skills = await scanSkills(dir);
105
+ for (const skill of skills) {
106
+ skillsMap.set(skill.name, skill);
107
+ }
108
+ }
109
+ const agentName = context.serverName;
110
+ const toolDescription = generateToolDescription(
111
+ Array.from(skillsMap.values()),
112
+ agentName
113
+ );
114
+ const toolName = `${agentName}__load-skill`;
115
+ if (serverRef) {
116
+ serverRef.tool(
117
+ toolName,
118
+ toolDescription,
119
+ jsonSchema({
120
+ type: "object",
121
+ properties: {
122
+ skill: {
123
+ type: "string",
124
+ description: "The skill name to load"
125
+ },
126
+ ref: {
127
+ type: "string",
128
+ description: "Optional: relative path to any file within the skill directory"
129
+ }
130
+ },
131
+ required: ["skill"]
132
+ }),
133
+ async (args) => {
134
+ const meta = skillsMap.get(args.skill);
135
+ if (!meta) {
136
+ return {
137
+ content: [
138
+ { type: "text", text: `Skill "${args.skill}" not found` }
139
+ ],
140
+ isError: true
141
+ };
142
+ }
143
+ if (args.ref) {
144
+ const refPath = resolve(meta.basePath, args.ref);
145
+ const relPath = relative(meta.basePath, refPath);
146
+ if (relPath.startsWith("..")) {
147
+ return {
148
+ content: [{
149
+ type: "text",
150
+ text: `Invalid path: ${args.ref}`
151
+ }],
152
+ isError: true
153
+ };
154
+ }
155
+ const dir = relPath.split(/[/\\]/)[0];
156
+ if (dir === "scripts" || dir === "assets") {
157
+ return {
158
+ content: [{ type: "text", text: `Path: ${refPath}` }]
159
+ };
160
+ }
161
+ try {
162
+ const content = await readFile(refPath, "utf-8");
163
+ return { content: [{ type: "text", text: content }] };
164
+ } catch {
165
+ return {
166
+ content: [{
167
+ type: "text",
168
+ text: `File not found: ${args.ref}`
169
+ }],
170
+ isError: true
171
+ };
172
+ }
173
+ }
174
+ try {
175
+ const content = await readFile(
176
+ join(meta.basePath, "SKILL.md"),
177
+ "utf-8"
178
+ );
179
+ const body = extractBody(content);
180
+ return { content: [{ type: "text", text: body }] };
181
+ } catch {
182
+ return {
183
+ content: [
184
+ { type: "text", text: `Failed to load skill: ${args.skill}` }
185
+ ],
186
+ isError: true
187
+ };
188
+ }
189
+ },
190
+ { internal: false }
191
+ );
192
+ }
193
+ },
194
+ dispose: () => {
195
+ skillsMap.clear();
196
+ serverRef = null;
197
+ }
198
+ };
199
+ }
200
+ function createPlugin(params) {
201
+ const paths = params.paths?.split(",").map((p) => p.trim()).filter(Boolean) || [];
202
+ return createSkillsPlugin({ paths });
203
+ }
204
+ var skills_default = createSkillsPlugin;
205
+ export {
206
+ createPlugin,
207
+ createSkillsPlugin,
208
+ skills_default as default
209
+ };