@mcpc-tech/core 0.3.14 → 0.3.15
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 +6 -1
- package/plugins/large-result.cjs +25 -15
- package/plugins/large-result.mjs +25 -15
- package/plugins/search.cjs +5 -2
- package/plugins/search.mjs +5 -2
- package/plugins/skills.cjs +229 -0
- package/plugins/skills.mjs +207 -0
- package/plugins.cjs +224 -17
- package/plugins.mjs +223 -17
- package/types/plugins.d.ts +1 -0
- package/types/plugins.d.ts.map +1 -1
- package/types/src/plugins/large-result.d.ts.map +1 -1
- package/types/src/plugins/search-tool.d.ts +1 -0
- package/types/src/plugins/search-tool.d.ts.map +1 -1
- package/types/src/plugins/skills.d.ts +23 -0
- package/types/src/plugins/skills.d.ts.map +1 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@mcpc-tech/core",
|
|
3
|
-
"version": "0.3.
|
|
3
|
+
"version": "0.3.15",
|
|
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": {
|
package/plugins/large-result.cjs
CHANGED
|
@@ -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
|
|
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(
|
|
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
|
-
|
|
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:
|
|
312
|
-
|
|
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
|
|
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 \`
|
|
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
|
-
|
|
376
|
+
serverRef = null;
|
|
377
|
+
agentName = null;
|
|
368
378
|
tempDir = null;
|
|
369
379
|
}
|
|
370
380
|
};
|
package/plugins/large-result.mjs
CHANGED
|
@@ -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
|
|
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(
|
|
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
|
-
|
|
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:
|
|
280
|
-
|
|
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
|
|
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 \`
|
|
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
|
-
|
|
344
|
+
serverRef = null;
|
|
345
|
+
agentName = null;
|
|
336
346
|
tempDir = null;
|
|
337
347
|
}
|
|
338
348
|
};
|
package/plugins/search.cjs
CHANGED
|
@@ -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
|
|
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
|
-
|
|
82
|
+
toolName,
|
|
80
83
|
toolDescription,
|
|
81
84
|
jsonSchema({
|
|
82
85
|
type: "object",
|
package/plugins/search.mjs
CHANGED
|
@@ -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
|
|
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
|
-
|
|
50
|
+
toolName,
|
|
48
51
|
toolDescription,
|
|
49
52
|
jsonSchema({
|
|
50
53
|
type: "object",
|
|
@@ -0,0 +1,229 @@
|
|
|
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
|
+
const result = {};
|
|
57
|
+
for (const line of yaml.split("\n")) {
|
|
58
|
+
if (line.trim() === "metadata:") {
|
|
59
|
+
result.metadata = {};
|
|
60
|
+
continue;
|
|
61
|
+
}
|
|
62
|
+
const metadataMatch = line.match(/^\s{2}(\w+):\s*"?([^"]*)"?$/);
|
|
63
|
+
if (metadataMatch && result.metadata) {
|
|
64
|
+
result.metadata[metadataMatch[1]] = metadataMatch[2];
|
|
65
|
+
continue;
|
|
66
|
+
}
|
|
67
|
+
const fieldMatch = line.match(/^(\S+):\s*(.*)$/);
|
|
68
|
+
if (fieldMatch) {
|
|
69
|
+
const [, key, value] = fieldMatch;
|
|
70
|
+
result[key] = value.replace(/^["']|["']$/g, "");
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
if (!result.name || !result.description) return null;
|
|
74
|
+
return result;
|
|
75
|
+
}
|
|
76
|
+
function extractBody(content) {
|
|
77
|
+
return content.replace(/^---\n[\s\S]*?\n---\n*/, "");
|
|
78
|
+
}
|
|
79
|
+
async function scanSkills(basePath) {
|
|
80
|
+
const skills = [];
|
|
81
|
+
try {
|
|
82
|
+
const entries = await (0, import_promises.readdir)(basePath, { withFileTypes: true });
|
|
83
|
+
for (const entry of entries) {
|
|
84
|
+
if (!entry.isDirectory()) continue;
|
|
85
|
+
const skillDir = (0, import_node_path.join)(basePath, entry.name);
|
|
86
|
+
const skillFile = (0, import_node_path.join)(skillDir, "SKILL.md");
|
|
87
|
+
try {
|
|
88
|
+
await (0, import_promises.stat)(skillFile);
|
|
89
|
+
const content = await (0, import_promises.readFile)(skillFile, "utf-8");
|
|
90
|
+
const frontmatter = parseFrontmatter(content);
|
|
91
|
+
if (frontmatter && frontmatter.name === entry.name) {
|
|
92
|
+
skills.push({
|
|
93
|
+
...frontmatter,
|
|
94
|
+
basePath: skillDir,
|
|
95
|
+
filePath: skillFile
|
|
96
|
+
});
|
|
97
|
+
}
|
|
98
|
+
} catch {
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
} catch {
|
|
102
|
+
}
|
|
103
|
+
return skills;
|
|
104
|
+
}
|
|
105
|
+
function generateToolDescription(skills, agentName) {
|
|
106
|
+
if (skills.length === 0) {
|
|
107
|
+
return "Load a skill's instructions. No skills available.";
|
|
108
|
+
}
|
|
109
|
+
const skillsList = skills.map((s) => `- ${s.name}: ${s.description}`).join("\n");
|
|
110
|
+
const toolName = `${agentName}__load-skill`;
|
|
111
|
+
return `Load a skill's detailed instructions or reference files for the "${agentName}" agent.
|
|
112
|
+
|
|
113
|
+
Available skills:
|
|
114
|
+
${skillsList}
|
|
115
|
+
|
|
116
|
+
Usage:
|
|
117
|
+
- ${toolName}({ skill: "skill-name" }) - Load main SKILL.md content
|
|
118
|
+
- ${toolName}({ skill: "skill-name", ref: "references/file.md" }) - Load reference file`;
|
|
119
|
+
}
|
|
120
|
+
function createSkillsPlugin(options) {
|
|
121
|
+
const { paths } = options;
|
|
122
|
+
const skillsMap = /* @__PURE__ */ new Map();
|
|
123
|
+
let serverRef = null;
|
|
124
|
+
return {
|
|
125
|
+
name: "plugin-skills",
|
|
126
|
+
version: "1.0.0",
|
|
127
|
+
// Save server reference
|
|
128
|
+
configureServer: (server) => {
|
|
129
|
+
serverRef = server;
|
|
130
|
+
},
|
|
131
|
+
// Scan directories and register tool
|
|
132
|
+
composeStart: async (context) => {
|
|
133
|
+
skillsMap.clear();
|
|
134
|
+
for (const dir of paths) {
|
|
135
|
+
const skills = await scanSkills(dir);
|
|
136
|
+
for (const skill of skills) {
|
|
137
|
+
skillsMap.set(skill.name, skill);
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
const agentName = context.serverName;
|
|
141
|
+
const toolDescription = generateToolDescription(
|
|
142
|
+
Array.from(skillsMap.values()),
|
|
143
|
+
agentName
|
|
144
|
+
);
|
|
145
|
+
const toolName = `${agentName}__load-skill`;
|
|
146
|
+
if (serverRef) {
|
|
147
|
+
serverRef.tool(
|
|
148
|
+
toolName,
|
|
149
|
+
toolDescription,
|
|
150
|
+
jsonSchema({
|
|
151
|
+
type: "object",
|
|
152
|
+
properties: {
|
|
153
|
+
skill: {
|
|
154
|
+
type: "string",
|
|
155
|
+
description: "The skill name to load"
|
|
156
|
+
},
|
|
157
|
+
ref: {
|
|
158
|
+
type: "string",
|
|
159
|
+
description: "Optional: relative path to a reference file within the skill directory"
|
|
160
|
+
}
|
|
161
|
+
},
|
|
162
|
+
required: ["skill"]
|
|
163
|
+
}),
|
|
164
|
+
async (args) => {
|
|
165
|
+
const meta = skillsMap.get(args.skill);
|
|
166
|
+
if (!meta) {
|
|
167
|
+
return {
|
|
168
|
+
content: [
|
|
169
|
+
{ type: "text", text: `Skill "${args.skill}" not found` }
|
|
170
|
+
],
|
|
171
|
+
isError: true
|
|
172
|
+
};
|
|
173
|
+
}
|
|
174
|
+
if (args.ref) {
|
|
175
|
+
const refPath = (0, import_node_path.resolve)(meta.basePath, args.ref);
|
|
176
|
+
const relPath = (0, import_node_path.relative)(meta.basePath, refPath);
|
|
177
|
+
if (relPath.startsWith("..")) {
|
|
178
|
+
return {
|
|
179
|
+
content: [
|
|
180
|
+
{ type: "text", text: `Invalid ref path: ${args.ref}` }
|
|
181
|
+
],
|
|
182
|
+
isError: true
|
|
183
|
+
};
|
|
184
|
+
}
|
|
185
|
+
try {
|
|
186
|
+
const content = await (0, import_promises.readFile)(refPath, "utf-8");
|
|
187
|
+
return { content: [{ type: "text", text: content }] };
|
|
188
|
+
} catch {
|
|
189
|
+
return {
|
|
190
|
+
content: [
|
|
191
|
+
{ type: "text", text: `File not found: ${args.ref}` }
|
|
192
|
+
],
|
|
193
|
+
isError: true
|
|
194
|
+
};
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
try {
|
|
198
|
+
const content = await (0, import_promises.readFile)(meta.filePath, "utf-8");
|
|
199
|
+
const body = extractBody(content);
|
|
200
|
+
return { content: [{ type: "text", text: body }] };
|
|
201
|
+
} catch {
|
|
202
|
+
return {
|
|
203
|
+
content: [
|
|
204
|
+
{ type: "text", text: `Failed to load skill: ${args.skill}` }
|
|
205
|
+
],
|
|
206
|
+
isError: true
|
|
207
|
+
};
|
|
208
|
+
}
|
|
209
|
+
},
|
|
210
|
+
{ internal: false }
|
|
211
|
+
);
|
|
212
|
+
}
|
|
213
|
+
},
|
|
214
|
+
dispose: () => {
|
|
215
|
+
skillsMap.clear();
|
|
216
|
+
serverRef = null;
|
|
217
|
+
}
|
|
218
|
+
};
|
|
219
|
+
}
|
|
220
|
+
function createPlugin(params) {
|
|
221
|
+
const paths = params.paths?.split(",").map((p) => p.trim()).filter(Boolean) || [];
|
|
222
|
+
return createSkillsPlugin({ paths });
|
|
223
|
+
}
|
|
224
|
+
var skills_default = createSkillsPlugin;
|
|
225
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
226
|
+
0 && (module.exports = {
|
|
227
|
+
createPlugin,
|
|
228
|
+
createSkillsPlugin
|
|
229
|
+
});
|
|
@@ -0,0 +1,207 @@
|
|
|
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, stat } 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
|
+
const result = {};
|
|
35
|
+
for (const line of yaml.split("\n")) {
|
|
36
|
+
if (line.trim() === "metadata:") {
|
|
37
|
+
result.metadata = {};
|
|
38
|
+
continue;
|
|
39
|
+
}
|
|
40
|
+
const metadataMatch = line.match(/^\s{2}(\w+):\s*"?([^"]*)"?$/);
|
|
41
|
+
if (metadataMatch && result.metadata) {
|
|
42
|
+
result.metadata[metadataMatch[1]] = metadataMatch[2];
|
|
43
|
+
continue;
|
|
44
|
+
}
|
|
45
|
+
const fieldMatch = line.match(/^(\S+):\s*(.*)$/);
|
|
46
|
+
if (fieldMatch) {
|
|
47
|
+
const [, key, value] = fieldMatch;
|
|
48
|
+
result[key] = value.replace(/^["']|["']$/g, "");
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
if (!result.name || !result.description) return null;
|
|
52
|
+
return result;
|
|
53
|
+
}
|
|
54
|
+
function extractBody(content) {
|
|
55
|
+
return content.replace(/^---\n[\s\S]*?\n---\n*/, "");
|
|
56
|
+
}
|
|
57
|
+
async function scanSkills(basePath) {
|
|
58
|
+
const skills = [];
|
|
59
|
+
try {
|
|
60
|
+
const entries = await readdir(basePath, { withFileTypes: true });
|
|
61
|
+
for (const entry of entries) {
|
|
62
|
+
if (!entry.isDirectory()) continue;
|
|
63
|
+
const skillDir = join(basePath, entry.name);
|
|
64
|
+
const skillFile = join(skillDir, "SKILL.md");
|
|
65
|
+
try {
|
|
66
|
+
await stat(skillFile);
|
|
67
|
+
const content = await readFile(skillFile, "utf-8");
|
|
68
|
+
const frontmatter = parseFrontmatter(content);
|
|
69
|
+
if (frontmatter && frontmatter.name === entry.name) {
|
|
70
|
+
skills.push({
|
|
71
|
+
...frontmatter,
|
|
72
|
+
basePath: skillDir,
|
|
73
|
+
filePath: skillFile
|
|
74
|
+
});
|
|
75
|
+
}
|
|
76
|
+
} catch {
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
} catch {
|
|
80
|
+
}
|
|
81
|
+
return skills;
|
|
82
|
+
}
|
|
83
|
+
function generateToolDescription(skills, agentName) {
|
|
84
|
+
if (skills.length === 0) {
|
|
85
|
+
return "Load a skill's instructions. No skills available.";
|
|
86
|
+
}
|
|
87
|
+
const skillsList = skills.map((s) => `- ${s.name}: ${s.description}`).join("\n");
|
|
88
|
+
const toolName = `${agentName}__load-skill`;
|
|
89
|
+
return `Load a skill's detailed instructions or reference files for the "${agentName}" agent.
|
|
90
|
+
|
|
91
|
+
Available skills:
|
|
92
|
+
${skillsList}
|
|
93
|
+
|
|
94
|
+
Usage:
|
|
95
|
+
- ${toolName}({ skill: "skill-name" }) - Load main SKILL.md content
|
|
96
|
+
- ${toolName}({ skill: "skill-name", ref: "references/file.md" }) - Load reference file`;
|
|
97
|
+
}
|
|
98
|
+
function createSkillsPlugin(options) {
|
|
99
|
+
const { paths } = options;
|
|
100
|
+
const skillsMap = /* @__PURE__ */ new Map();
|
|
101
|
+
let serverRef = null;
|
|
102
|
+
return {
|
|
103
|
+
name: "plugin-skills",
|
|
104
|
+
version: "1.0.0",
|
|
105
|
+
// Save server reference
|
|
106
|
+
configureServer: (server) => {
|
|
107
|
+
serverRef = server;
|
|
108
|
+
},
|
|
109
|
+
// Scan directories and register tool
|
|
110
|
+
composeStart: async (context) => {
|
|
111
|
+
skillsMap.clear();
|
|
112
|
+
for (const dir of paths) {
|
|
113
|
+
const skills = await scanSkills(dir);
|
|
114
|
+
for (const skill of skills) {
|
|
115
|
+
skillsMap.set(skill.name, skill);
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
const agentName = context.serverName;
|
|
119
|
+
const toolDescription = generateToolDescription(
|
|
120
|
+
Array.from(skillsMap.values()),
|
|
121
|
+
agentName
|
|
122
|
+
);
|
|
123
|
+
const toolName = `${agentName}__load-skill`;
|
|
124
|
+
if (serverRef) {
|
|
125
|
+
serverRef.tool(
|
|
126
|
+
toolName,
|
|
127
|
+
toolDescription,
|
|
128
|
+
jsonSchema({
|
|
129
|
+
type: "object",
|
|
130
|
+
properties: {
|
|
131
|
+
skill: {
|
|
132
|
+
type: "string",
|
|
133
|
+
description: "The skill name to load"
|
|
134
|
+
},
|
|
135
|
+
ref: {
|
|
136
|
+
type: "string",
|
|
137
|
+
description: "Optional: relative path to a reference file within the skill directory"
|
|
138
|
+
}
|
|
139
|
+
},
|
|
140
|
+
required: ["skill"]
|
|
141
|
+
}),
|
|
142
|
+
async (args) => {
|
|
143
|
+
const meta = skillsMap.get(args.skill);
|
|
144
|
+
if (!meta) {
|
|
145
|
+
return {
|
|
146
|
+
content: [
|
|
147
|
+
{ type: "text", text: `Skill "${args.skill}" not found` }
|
|
148
|
+
],
|
|
149
|
+
isError: true
|
|
150
|
+
};
|
|
151
|
+
}
|
|
152
|
+
if (args.ref) {
|
|
153
|
+
const refPath = resolve(meta.basePath, args.ref);
|
|
154
|
+
const relPath = relative(meta.basePath, refPath);
|
|
155
|
+
if (relPath.startsWith("..")) {
|
|
156
|
+
return {
|
|
157
|
+
content: [
|
|
158
|
+
{ type: "text", text: `Invalid ref path: ${args.ref}` }
|
|
159
|
+
],
|
|
160
|
+
isError: true
|
|
161
|
+
};
|
|
162
|
+
}
|
|
163
|
+
try {
|
|
164
|
+
const content = await readFile(refPath, "utf-8");
|
|
165
|
+
return { content: [{ type: "text", text: content }] };
|
|
166
|
+
} catch {
|
|
167
|
+
return {
|
|
168
|
+
content: [
|
|
169
|
+
{ type: "text", text: `File not found: ${args.ref}` }
|
|
170
|
+
],
|
|
171
|
+
isError: true
|
|
172
|
+
};
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
try {
|
|
176
|
+
const content = await readFile(meta.filePath, "utf-8");
|
|
177
|
+
const body = extractBody(content);
|
|
178
|
+
return { content: [{ type: "text", text: body }] };
|
|
179
|
+
} catch {
|
|
180
|
+
return {
|
|
181
|
+
content: [
|
|
182
|
+
{ type: "text", text: `Failed to load skill: ${args.skill}` }
|
|
183
|
+
],
|
|
184
|
+
isError: true
|
|
185
|
+
};
|
|
186
|
+
}
|
|
187
|
+
},
|
|
188
|
+
{ internal: false }
|
|
189
|
+
);
|
|
190
|
+
}
|
|
191
|
+
},
|
|
192
|
+
dispose: () => {
|
|
193
|
+
skillsMap.clear();
|
|
194
|
+
serverRef = null;
|
|
195
|
+
}
|
|
196
|
+
};
|
|
197
|
+
}
|
|
198
|
+
function createPlugin(params) {
|
|
199
|
+
const paths = params.paths?.split(",").map((p) => p.trim()).filter(Boolean) || [];
|
|
200
|
+
return createSkillsPlugin({ paths });
|
|
201
|
+
}
|
|
202
|
+
var skills_default = createSkillsPlugin;
|
|
203
|
+
export {
|
|
204
|
+
createPlugin,
|
|
205
|
+
createSkillsPlugin,
|
|
206
|
+
skills_default as default
|
|
207
|
+
};
|