opencode-lazy-loader 1.0.0 → 1.0.1
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/index.d.ts +19 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +59 -0
- package/dist/index.js.map +1 -0
- package/dist/skill-loader.d.ts +27 -0
- package/dist/skill-loader.d.ts.map +1 -0
- package/dist/skill-loader.js +197 -0
- package/dist/skill-loader.js.map +1 -0
- package/dist/skill-mcp-manager.d.ts +26 -0
- package/dist/skill-mcp-manager.d.ts.map +1 -0
- package/dist/skill-mcp-manager.js +284 -0
- package/dist/skill-mcp-manager.js.map +1 -0
- package/dist/tools/skill-mcp.d.ts +13 -0
- package/dist/tools/skill-mcp.d.ts.map +1 -0
- package/dist/tools/skill-mcp.js +162 -0
- package/dist/tools/skill-mcp.js.map +1 -0
- package/dist/tools/skill.d.ts +13 -0
- package/dist/tools/skill.d.ts.map +1 -0
- package/dist/tools/skill.js +160 -0
- package/dist/tools/skill.js.map +1 -0
- package/dist/types.d.ts +70 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +2 -0
- package/dist/types.js.map +1 -0
- package/dist/utils/env-vars.d.ts +15 -0
- package/dist/utils/env-vars.d.ts.map +1 -0
- package/dist/utils/env-vars.js +59 -0
- package/dist/utils/env-vars.js.map +1 -0
- package/dist/utils/frontmatter.d.ts +10 -0
- package/dist/utils/frontmatter.d.ts.map +1 -0
- package/dist/utils/frontmatter.js +44 -0
- package/dist/utils/frontmatter.js.map +1 -0
- package/package.json +5 -4
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { type ToolDefinition } from '@opencode-ai/plugin';
|
|
2
|
+
import type { LoadedSkill } from '../types.js';
|
|
3
|
+
import type { SkillMcpManager } from '../skill-mcp-manager.js';
|
|
4
|
+
export interface CreateSkillMcpToolOptions {
|
|
5
|
+
manager: SkillMcpManager;
|
|
6
|
+
getLoadedSkills: () => LoadedSkill[];
|
|
7
|
+
getSessionID: () => string;
|
|
8
|
+
}
|
|
9
|
+
/**
|
|
10
|
+
* Create the skill_mcp tool
|
|
11
|
+
*/
|
|
12
|
+
export declare function createSkillMcpTool(options: CreateSkillMcpToolOptions): ToolDefinition;
|
|
13
|
+
//# sourceMappingURL=skill-mcp.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"skill-mcp.d.ts","sourceRoot":"","sources":["../../src/tools/skill-mcp.ts"],"names":[],"mappings":"AAAA,OAAO,EAAQ,KAAK,cAAc,EAAE,MAAM,qBAAqB,CAAA;AAC/D,OAAO,KAAK,EAAE,WAAW,EAAmB,MAAM,aAAa,CAAA;AAC/D,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,yBAAyB,CAAA;AAqI9D,MAAM,WAAW,yBAAyB;IACxC,OAAO,EAAE,eAAe,CAAA;IACxB,eAAe,EAAE,MAAM,WAAW,EAAE,CAAA;IACpC,YAAY,EAAE,MAAM,MAAM,CAAA;CAC3B;AAED;;GAEG;AACH,wBAAgB,kBAAkB,CAAC,OAAO,EAAE,yBAAyB,GAAG,cAAc,CAoErF"}
|
|
@@ -0,0 +1,162 @@
|
|
|
1
|
+
import { tool } from '@opencode-ai/plugin';
|
|
2
|
+
const SKILL_MCP_DESCRIPTION = `Invoke MCP server operations from skill-embedded MCPs. Requires mcp_name plus exactly one of: tool_name, resource_name, or prompt_name.`;
|
|
3
|
+
/**
|
|
4
|
+
* Validate that exactly one operation parameter is provided
|
|
5
|
+
*/
|
|
6
|
+
function validateOperationParams(args) {
|
|
7
|
+
const operations = [];
|
|
8
|
+
if (args.tool_name) {
|
|
9
|
+
operations.push({ type: 'tool', name: args.tool_name });
|
|
10
|
+
}
|
|
11
|
+
if (args.resource_name) {
|
|
12
|
+
operations.push({ type: 'resource', name: args.resource_name });
|
|
13
|
+
}
|
|
14
|
+
if (args.prompt_name) {
|
|
15
|
+
operations.push({ type: 'prompt', name: args.prompt_name });
|
|
16
|
+
}
|
|
17
|
+
if (operations.length === 0) {
|
|
18
|
+
throw new Error(`Missing operation. Exactly one of tool_name, resource_name, or prompt_name must be specified.\n\n` +
|
|
19
|
+
`Examples:\n` +
|
|
20
|
+
` skill_mcp(mcp_name="sqlite", tool_name="query", arguments='{"sql": "SELECT * FROM users"}')\n` +
|
|
21
|
+
` skill_mcp(mcp_name="memory", resource_name="memory://notes")\n` +
|
|
22
|
+
` skill_mcp(mcp_name="helper", prompt_name="summarize", arguments='{"text": "..."}')`);
|
|
23
|
+
}
|
|
24
|
+
if (operations.length > 1) {
|
|
25
|
+
const provided = [
|
|
26
|
+
args.tool_name && `tool_name="${args.tool_name}"`,
|
|
27
|
+
args.resource_name && `resource_name="${args.resource_name}"`,
|
|
28
|
+
args.prompt_name && `prompt_name="${args.prompt_name}"`
|
|
29
|
+
].filter(Boolean).join(', ');
|
|
30
|
+
throw new Error(`Multiple operations specified. Exactly one of tool_name, resource_name, or prompt_name must be provided.\n\n` +
|
|
31
|
+
`Received: ${provided}\n\n` +
|
|
32
|
+
`Use separate calls for each operation.`);
|
|
33
|
+
}
|
|
34
|
+
return operations[0];
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* Find an MCP server configuration by name across all skills
|
|
38
|
+
*/
|
|
39
|
+
function findMcpServer(mcpName, skills) {
|
|
40
|
+
for (const skill of skills) {
|
|
41
|
+
if (skill.mcpConfig && mcpName in skill.mcpConfig) {
|
|
42
|
+
return { skill, config: skill.mcpConfig[mcpName] };
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
return null;
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* Format available MCPs for error message
|
|
49
|
+
*/
|
|
50
|
+
function formatAvailableMcps(skills) {
|
|
51
|
+
const mcps = [];
|
|
52
|
+
for (const skill of skills) {
|
|
53
|
+
if (skill.mcpConfig) {
|
|
54
|
+
for (const serverName of Object.keys(skill.mcpConfig)) {
|
|
55
|
+
mcps.push(` - "${serverName}" from skill "${skill.name}"`);
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
return mcps.length > 0 ? mcps.join('\n') : ' (none found)';
|
|
60
|
+
}
|
|
61
|
+
/**
|
|
62
|
+
* Parse JSON arguments string
|
|
63
|
+
*/
|
|
64
|
+
function parseArguments(argsJson) {
|
|
65
|
+
if (!argsJson) {
|
|
66
|
+
return {};
|
|
67
|
+
}
|
|
68
|
+
try {
|
|
69
|
+
const parsed = JSON.parse(argsJson);
|
|
70
|
+
if (typeof parsed !== 'object' || parsed === null) {
|
|
71
|
+
throw new Error('Arguments must be a JSON object');
|
|
72
|
+
}
|
|
73
|
+
return parsed;
|
|
74
|
+
}
|
|
75
|
+
catch (error) {
|
|
76
|
+
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
77
|
+
throw new Error(`Invalid arguments JSON: ${errorMessage}\n\n` +
|
|
78
|
+
`Expected a valid JSON object, e.g.: '{"key": "value"}'\n` +
|
|
79
|
+
`Received: ${argsJson}`);
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
/**
|
|
83
|
+
* Apply grep filter to output
|
|
84
|
+
*/
|
|
85
|
+
function applyGrepFilter(output, pattern) {
|
|
86
|
+
if (!pattern) {
|
|
87
|
+
return output;
|
|
88
|
+
}
|
|
89
|
+
try {
|
|
90
|
+
const regex = new RegExp(pattern, 'i');
|
|
91
|
+
const lines = output.split('\n');
|
|
92
|
+
const filtered = lines.filter((line) => regex.test(line));
|
|
93
|
+
return filtered.length > 0
|
|
94
|
+
? filtered.join('\n')
|
|
95
|
+
: `[grep] No lines matched pattern: ${pattern}`;
|
|
96
|
+
}
|
|
97
|
+
catch {
|
|
98
|
+
return output;
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
/**
|
|
102
|
+
* Create the skill_mcp tool
|
|
103
|
+
*/
|
|
104
|
+
export function createSkillMcpTool(options) {
|
|
105
|
+
const { manager, getLoadedSkills, getSessionID } = options;
|
|
106
|
+
return tool({
|
|
107
|
+
description: SKILL_MCP_DESCRIPTION,
|
|
108
|
+
args: {
|
|
109
|
+
mcp_name: tool.schema.string().describe('Name of the MCP server from skill config'),
|
|
110
|
+
tool_name: tool.schema.string().optional().describe('MCP tool to call'),
|
|
111
|
+
resource_name: tool.schema.string().optional().describe('MCP resource URI to read'),
|
|
112
|
+
prompt_name: tool.schema.string().optional().describe('MCP prompt to get'),
|
|
113
|
+
arguments: tool.schema.string().optional().describe('JSON string of arguments'),
|
|
114
|
+
grep: tool.schema.string().optional().describe('Regex pattern to filter output lines (only matching lines returned)')
|
|
115
|
+
},
|
|
116
|
+
async execute(args) {
|
|
117
|
+
const operation = validateOperationParams(args);
|
|
118
|
+
const skills = getLoadedSkills();
|
|
119
|
+
const found = findMcpServer(args.mcp_name, skills);
|
|
120
|
+
if (!found) {
|
|
121
|
+
throw new Error(`MCP server "${args.mcp_name}" not found.\n\n` +
|
|
122
|
+
`Available MCP servers in loaded skills:\n` +
|
|
123
|
+
formatAvailableMcps(skills) + '\n\n' +
|
|
124
|
+
`Hint: Load the skill first using the 'skill' tool, then call skill_mcp.`);
|
|
125
|
+
}
|
|
126
|
+
const info = {
|
|
127
|
+
serverName: args.mcp_name,
|
|
128
|
+
skillName: found.skill.name,
|
|
129
|
+
sessionID: getSessionID()
|
|
130
|
+
};
|
|
131
|
+
const context = {
|
|
132
|
+
config: found.config,
|
|
133
|
+
skillName: found.skill.name
|
|
134
|
+
};
|
|
135
|
+
const parsedArgs = parseArguments(args.arguments);
|
|
136
|
+
let output;
|
|
137
|
+
switch (operation.type) {
|
|
138
|
+
case 'tool': {
|
|
139
|
+
const result = await manager.callTool(info, context, operation.name, parsedArgs);
|
|
140
|
+
output = JSON.stringify(result, null, 2);
|
|
141
|
+
break;
|
|
142
|
+
}
|
|
143
|
+
case 'resource': {
|
|
144
|
+
const result = await manager.readResource(info, context, operation.name);
|
|
145
|
+
output = JSON.stringify(result, null, 2);
|
|
146
|
+
break;
|
|
147
|
+
}
|
|
148
|
+
case 'prompt': {
|
|
149
|
+
const stringArgs = {};
|
|
150
|
+
for (const [key, value] of Object.entries(parsedArgs)) {
|
|
151
|
+
stringArgs[key] = String(value);
|
|
152
|
+
}
|
|
153
|
+
const result = await manager.getPrompt(info, context, operation.name, stringArgs);
|
|
154
|
+
output = JSON.stringify(result, null, 2);
|
|
155
|
+
break;
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
return applyGrepFilter(output, args.grep);
|
|
159
|
+
}
|
|
160
|
+
});
|
|
161
|
+
}
|
|
162
|
+
//# sourceMappingURL=skill-mcp.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"skill-mcp.js","sourceRoot":"","sources":["../../src/tools/skill-mcp.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAuB,MAAM,qBAAqB,CAAA;AAI/D,MAAM,qBAAqB,GACzB,yIAAyI,CAAA;AAO3I;;GAEG;AACH,SAAS,uBAAuB,CAAC,IAIhC;IACC,MAAM,UAAU,GAAoB,EAAE,CAAA;IAEtC,IAAI,IAAI,CAAC,SAAS,EAAE,CAAC;QACnB,UAAU,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,IAAI,CAAC,SAAS,EAAE,CAAC,CAAA;IACzD,CAAC;IACD,IAAI,IAAI,CAAC,aAAa,EAAE,CAAC;QACvB,UAAU,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,UAAU,EAAE,IAAI,EAAE,IAAI,CAAC,aAAa,EAAE,CAAC,CAAA;IACjE,CAAC;IACD,IAAI,IAAI,CAAC,WAAW,EAAE,CAAC;QACrB,UAAU,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,QAAQ,EAAE,IAAI,EAAE,IAAI,CAAC,WAAW,EAAE,CAAC,CAAA;IAC7D,CAAC;IAED,IAAI,UAAU,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QAC5B,MAAM,IAAI,KAAK,CACb,mGAAmG;YACnG,aAAa;YACb,iGAAiG;YACjG,kEAAkE;YAClE,sFAAsF,CACvF,CAAA;IACH,CAAC;IAED,IAAI,UAAU,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QAC1B,MAAM,QAAQ,GAAG;YACf,IAAI,CAAC,SAAS,IAAI,cAAc,IAAI,CAAC,SAAS,GAAG;YACjD,IAAI,CAAC,aAAa,IAAI,kBAAkB,IAAI,CAAC,aAAa,GAAG;YAC7D,IAAI,CAAC,WAAW,IAAI,gBAAgB,IAAI,CAAC,WAAW,GAAG;SACxD,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAA;QAE5B,MAAM,IAAI,KAAK,CACb,8GAA8G;YAC9G,aAAa,QAAQ,MAAM;YAC3B,wCAAwC,CACzC,CAAA;IACH,CAAC;IAED,OAAO,UAAU,CAAC,CAAC,CAAC,CAAA;AACtB,CAAC;AAED;;GAEG;AACH,SAAS,aAAa,CACpB,OAAe,EACf,MAAqB;IAErB,KAAK,MAAM,KAAK,IAAI,MAAM,EAAE,CAAC;QAC3B,IAAI,KAAK,CAAC,SAAS,IAAI,OAAO,IAAI,KAAK,CAAC,SAAS,EAAE,CAAC;YAClD,OAAO,EAAE,KAAK,EAAE,MAAM,EAAE,KAAK,CAAC,SAAS,CAAC,OAAO,CAAC,EAAE,CAAA;QACpD,CAAC;IACH,CAAC;IACD,OAAO,IAAI,CAAA;AACb,CAAC;AAED;;GAEG;AACH,SAAS,mBAAmB,CAAC,MAAqB;IAChD,MAAM,IAAI,GAAa,EAAE,CAAA;IAEzB,KAAK,MAAM,KAAK,IAAI,MAAM,EAAE,CAAC;QAC3B,IAAI,KAAK,CAAC,SAAS,EAAE,CAAC;YACpB,KAAK,MAAM,UAAU,IAAI,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,SAAS,CAAC,EAAE,CAAC;gBACtD,IAAI,CAAC,IAAI,CAAC,QAAQ,UAAU,iBAAiB,KAAK,CAAC,IAAI,GAAG,CAAC,CAAA;YAC7D,CAAC;QACH,CAAC;IACH,CAAC;IAED,OAAO,IAAI,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,gBAAgB,CAAA;AAC7D,CAAC;AAED;;GAEG;AACH,SAAS,cAAc,CAAC,QAAiB;IACvC,IAAI,CAAC,QAAQ,EAAE,CAAC;QACd,OAAO,EAAE,CAAA;IACX,CAAC;IAED,IAAI,CAAC;QACH,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAA;QACnC,IAAI,OAAO,MAAM,KAAK,QAAQ,IAAI,MAAM,KAAK,IAAI,EAAE,CAAC;YAClD,MAAM,IAAI,KAAK,CAAC,iCAAiC,CAAC,CAAA;QACpD,CAAC;QACD,OAAO,MAAiC,CAAA;IAC1C,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,MAAM,YAAY,GAAG,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAA;QAC3E,MAAM,IAAI,KAAK,CACb,2BAA2B,YAAY,MAAM;YAC7C,0DAA0D;YAC1D,aAAa,QAAQ,EAAE,CACxB,CAAA;IACH,CAAC;AACH,CAAC;AAED;;GAEG;AACH,SAAS,eAAe,CAAC,MAAc,EAAE,OAAgB;IACvD,IAAI,CAAC,OAAO,EAAE,CAAC;QACb,OAAO,MAAM,CAAA;IACf,CAAC;IAED,IAAI,CAAC;QACH,MAAM,KAAK,GAAG,IAAI,MAAM,CAAC,OAAO,EAAE,GAAG,CAAC,CAAA;QACtC,MAAM,KAAK,GAAG,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,CAAA;QAChC,MAAM,QAAQ,GAAG,KAAK,CAAC,MAAM,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAA;QACzD,OAAO,QAAQ,CAAC,MAAM,GAAG,CAAC;YACxB,CAAC,CAAC,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC;YACrB,CAAC,CAAC,oCAAoC,OAAO,EAAE,CAAA;IACnD,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,MAAM,CAAA;IACf,CAAC;AACH,CAAC;AAQD;;GAEG;AACH,MAAM,UAAU,kBAAkB,CAAC,OAAkC;IACnE,MAAM,EAAE,OAAO,EAAE,eAAe,EAAE,YAAY,EAAE,GAAG,OAAO,CAAA;IAE1D,OAAO,IAAI,CAAC;QACV,WAAW,EAAE,qBAAqB;QAClC,IAAI,EAAE;YACJ,QAAQ,EAAE,IAAI,CAAC,MAAM,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,0CAA0C,CAAC;YACnF,SAAS,EAAE,IAAI,CAAC,MAAM,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,kBAAkB,CAAC;YACvE,aAAa,EAAE,IAAI,CAAC,MAAM,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,0BAA0B,CAAC;YACnF,WAAW,EAAE,IAAI,CAAC,MAAM,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,mBAAmB,CAAC;YAC1E,SAAS,EAAE,IAAI,CAAC,MAAM,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,0BAA0B,CAAC;YAC/E,IAAI,EAAE,IAAI,CAAC,MAAM,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAC5C,qEAAqE,CACtE;SACF;QACD,KAAK,CAAC,OAAO,CAAC,IAAI;YAChB,MAAM,SAAS,GAAG,uBAAuB,CAAC,IAAI,CAAC,CAAA;YAC/C,MAAM,MAAM,GAAG,eAAe,EAAE,CAAA;YAChC,MAAM,KAAK,GAAG,aAAa,CAAC,IAAI,CAAC,QAAQ,EAAE,MAAM,CAAC,CAAA;YAElD,IAAI,CAAC,KAAK,EAAE,CAAC;gBACX,MAAM,IAAI,KAAK,CACb,eAAe,IAAI,CAAC,QAAQ,kBAAkB;oBAC9C,2CAA2C;oBAC3C,mBAAmB,CAAC,MAAM,CAAC,GAAG,MAAM;oBACpC,yEAAyE,CAC1E,CAAA;YACH,CAAC;YAED,MAAM,IAAI,GAAG;gBACX,UAAU,EAAE,IAAI,CAAC,QAAQ;gBACzB,SAAS,EAAE,KAAK,CAAC,KAAK,CAAC,IAAI;gBAC3B,SAAS,EAAE,YAAY,EAAE;aAC1B,CAAA;YAED,MAAM,OAAO,GAAG;gBACd,MAAM,EAAE,KAAK,CAAC,MAAM;gBACpB,SAAS,EAAE,KAAK,CAAC,KAAK,CAAC,IAAI;aAC5B,CAAA;YAED,MAAM,UAAU,GAAG,cAAc,CAAC,IAAI,CAAC,SAAS,CAAC,CAAA;YACjD,IAAI,MAAc,CAAA;YAElB,QAAQ,SAAS,CAAC,IAAI,EAAE,CAAC;gBACvB,KAAK,MAAM,CAAC,CAAC,CAAC;oBACZ,MAAM,MAAM,GAAG,MAAM,OAAO,CAAC,QAAQ,CAAC,IAAI,EAAE,OAAO,EAAE,SAAS,CAAC,IAAI,EAAE,UAAU,CAAC,CAAA;oBAChF,MAAM,GAAG,IAAI,CAAC,SAAS,CAAC,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC,CAAA;oBACxC,MAAK;gBACP,CAAC;gBACD,KAAK,UAAU,CAAC,CAAC,CAAC;oBAChB,MAAM,MAAM,GAAG,MAAM,OAAO,CAAC,YAAY,CAAC,IAAI,EAAE,OAAO,EAAE,SAAS,CAAC,IAAI,CAAC,CAAA;oBACxE,MAAM,GAAG,IAAI,CAAC,SAAS,CAAC,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC,CAAA;oBACxC,MAAK;gBACP,CAAC;gBACD,KAAK,QAAQ,CAAC,CAAC,CAAC;oBACd,MAAM,UAAU,GAA2B,EAAE,CAAA;oBAC7C,KAAK,MAAM,CAAC,GAAG,EAAE,KAAK,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,UAAU,CAAC,EAAE,CAAC;wBACtD,UAAU,CAAC,GAAG,CAAC,GAAG,MAAM,CAAC,KAAK,CAAC,CAAA;oBACjC,CAAC;oBACD,MAAM,MAAM,GAAG,MAAM,OAAO,CAAC,SAAS,CAAC,IAAI,EAAE,OAAO,EAAE,SAAS,CAAC,IAAI,EAAE,UAAU,CAAC,CAAA;oBACjF,MAAM,GAAG,IAAI,CAAC,SAAS,CAAC,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC,CAAA;oBACxC,MAAK;gBACP,CAAC;YACH,CAAC;YAED,OAAO,eAAe,CAAC,MAAM,EAAE,IAAI,CAAC,IAAI,CAAC,CAAA;QAC3C,CAAC;KACF,CAAC,CAAA;AACJ,CAAC"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { type ToolDefinition } from '@opencode-ai/plugin';
|
|
2
|
+
import type { LoadedSkill } from '../types.js';
|
|
3
|
+
import type { SkillMcpManager } from '../skill-mcp-manager.js';
|
|
4
|
+
export interface CreateSkillToolOptions {
|
|
5
|
+
skills: LoadedSkill[];
|
|
6
|
+
mcpManager?: SkillMcpManager;
|
|
7
|
+
getSessionID?: () => string;
|
|
8
|
+
}
|
|
9
|
+
/**
|
|
10
|
+
* Create the skill tool
|
|
11
|
+
*/
|
|
12
|
+
export declare function createSkillTool(options: CreateSkillToolOptions): ToolDefinition;
|
|
13
|
+
//# sourceMappingURL=skill.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"skill.d.ts","sourceRoot":"","sources":["../../src/tools/skill.ts"],"names":[],"mappings":"AAAA,OAAO,EAAQ,KAAK,cAAc,EAAE,MAAM,qBAAqB,CAAA;AAE/D,OAAO,KAAK,EAAE,WAAW,EAAmB,MAAM,aAAa,CAAA;AAC/D,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,yBAAyB,CAAA;AAqK9D,MAAM,WAAW,sBAAsB;IACrC,MAAM,EAAE,WAAW,EAAE,CAAA;IACrB,UAAU,CAAC,EAAE,eAAe,CAAA;IAC5B,YAAY,CAAC,EAAE,MAAM,MAAM,CAAA;CAC5B;AAED;;GAEG;AACH,wBAAgB,eAAe,CAAC,OAAO,EAAE,sBAAsB,GAAG,cAAc,CAgD/E"}
|
|
@@ -0,0 +1,160 @@
|
|
|
1
|
+
import { tool } from '@opencode-ai/plugin';
|
|
2
|
+
import { dirname } from 'path';
|
|
3
|
+
import { parseFrontmatter } from '../utils/frontmatter.js';
|
|
4
|
+
const TOOL_DESCRIPTION_NO_SKILLS = 'Load a skill to get detailed instructions for a specific task. No skills are currently available.';
|
|
5
|
+
const TOOL_DESCRIPTION_PREFIX = `Load a skill to get detailed instructions for a specific task.
|
|
6
|
+
|
|
7
|
+
Skills provide specialized knowledge and step-by-step guidance.
|
|
8
|
+
Use this when a task matches an available skill's description.`;
|
|
9
|
+
/**
|
|
10
|
+
* Convert loaded skill to info for display
|
|
11
|
+
*/
|
|
12
|
+
function loadedSkillToInfo(skill) {
|
|
13
|
+
return {
|
|
14
|
+
name: skill.name,
|
|
15
|
+
description: skill.definition.description || '',
|
|
16
|
+
scope: skill.scope
|
|
17
|
+
};
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* Format skills as XML for tool description
|
|
21
|
+
*/
|
|
22
|
+
function formatSkillsXml(skills) {
|
|
23
|
+
if (skills.length === 0)
|
|
24
|
+
return '';
|
|
25
|
+
const skillsXml = skills.map((skill) => {
|
|
26
|
+
return [
|
|
27
|
+
' <skill>',
|
|
28
|
+
` <name>${skill.name}</name>`,
|
|
29
|
+
` <description>${skill.description}</description>`,
|
|
30
|
+
' </skill>'
|
|
31
|
+
].join('\n');
|
|
32
|
+
}).join('\n');
|
|
33
|
+
return `
|
|
34
|
+
|
|
35
|
+
<available_skills>
|
|
36
|
+
${skillsXml}
|
|
37
|
+
</available_skills>`;
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* Extract skill body content
|
|
41
|
+
*/
|
|
42
|
+
async function extractSkillBody(skill) {
|
|
43
|
+
if (skill.lazyContent) {
|
|
44
|
+
const fullTemplate = await skill.lazyContent.load();
|
|
45
|
+
const templateMatch = fullTemplate.match(/<skill-instruction>([\s\S]*?)<\/skill-instruction>/);
|
|
46
|
+
return templateMatch ? templateMatch[1].trim() : fullTemplate;
|
|
47
|
+
}
|
|
48
|
+
if (skill.path) {
|
|
49
|
+
const { readFileSync } = await import('fs');
|
|
50
|
+
const content = readFileSync(skill.path, 'utf-8');
|
|
51
|
+
const { body } = parseFrontmatter(content);
|
|
52
|
+
return body.trim();
|
|
53
|
+
}
|
|
54
|
+
const templateMatch = skill.definition.template?.match(/<skill-instruction>([\s\S]*?)<\/skill-instruction>/);
|
|
55
|
+
return templateMatch ? templateMatch[1].trim() : skill.definition.template || '';
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* Format MCP capabilities for display
|
|
59
|
+
*/
|
|
60
|
+
async function formatMcpCapabilities(skill, manager, sessionID) {
|
|
61
|
+
if (!skill.mcpConfig || Object.keys(skill.mcpConfig).length === 0) {
|
|
62
|
+
return null;
|
|
63
|
+
}
|
|
64
|
+
const sections = ['', '## Available MCP Servers', ''];
|
|
65
|
+
for (const [serverName, config] of Object.entries(skill.mcpConfig)) {
|
|
66
|
+
const info = {
|
|
67
|
+
serverName,
|
|
68
|
+
skillName: skill.name,
|
|
69
|
+
sessionID
|
|
70
|
+
};
|
|
71
|
+
const context = {
|
|
72
|
+
config: config,
|
|
73
|
+
skillName: skill.name
|
|
74
|
+
};
|
|
75
|
+
sections.push(`### ${serverName}`);
|
|
76
|
+
sections.push('');
|
|
77
|
+
try {
|
|
78
|
+
const [tools, resources, prompts] = await Promise.all([
|
|
79
|
+
manager.listTools(info, context).catch(() => []),
|
|
80
|
+
manager.listResources(info, context).catch(() => []),
|
|
81
|
+
manager.listPrompts(info, context).catch(() => [])
|
|
82
|
+
]);
|
|
83
|
+
if (tools.length > 0) {
|
|
84
|
+
sections.push('**Tools:**');
|
|
85
|
+
sections.push('');
|
|
86
|
+
for (const t of tools) {
|
|
87
|
+
sections.push(`#### \`${t.name}\``);
|
|
88
|
+
if (t.description) {
|
|
89
|
+
sections.push(t.description);
|
|
90
|
+
}
|
|
91
|
+
sections.push('');
|
|
92
|
+
sections.push('**inputSchema:**');
|
|
93
|
+
sections.push('```json');
|
|
94
|
+
sections.push(JSON.stringify(t.inputSchema, null, 2));
|
|
95
|
+
sections.push('```');
|
|
96
|
+
sections.push('');
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
if (resources.length > 0) {
|
|
100
|
+
sections.push(`**Resources**: ${resources.map((r) => r.uri).join(', ')}`);
|
|
101
|
+
}
|
|
102
|
+
if (prompts.length > 0) {
|
|
103
|
+
sections.push(`**Prompts**: ${prompts.map((p) => p.name).join(', ')}`);
|
|
104
|
+
}
|
|
105
|
+
if (tools.length === 0 && resources.length === 0 && prompts.length === 0) {
|
|
106
|
+
sections.push('*No capabilities discovered*');
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
catch (error) {
|
|
110
|
+
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
111
|
+
sections.push(`*Failed to connect: ${errorMessage.split('\n')[0]}*`);
|
|
112
|
+
}
|
|
113
|
+
sections.push('');
|
|
114
|
+
sections.push(`Use \`skill_mcp\` tool with \`mcp_name="${serverName}"\` to invoke.`);
|
|
115
|
+
sections.push('');
|
|
116
|
+
}
|
|
117
|
+
return sections.join('\n');
|
|
118
|
+
}
|
|
119
|
+
/**
|
|
120
|
+
* Create the skill tool
|
|
121
|
+
*/
|
|
122
|
+
export function createSkillTool(options) {
|
|
123
|
+
const { skills, mcpManager, getSessionID } = options;
|
|
124
|
+
// Build description with available skills
|
|
125
|
+
const skillInfos = skills.map(loadedSkillToInfo);
|
|
126
|
+
const description = skillInfos.length === 0
|
|
127
|
+
? TOOL_DESCRIPTION_NO_SKILLS
|
|
128
|
+
: TOOL_DESCRIPTION_PREFIX + formatSkillsXml(skillInfos);
|
|
129
|
+
return tool({
|
|
130
|
+
description,
|
|
131
|
+
args: {
|
|
132
|
+
name: tool.schema.string().describe("The skill identifier from available_skills (e.g., 'code-review' or 'my-skill')")
|
|
133
|
+
},
|
|
134
|
+
async execute(args) {
|
|
135
|
+
const skill = skills.find((s) => s.name === args.name);
|
|
136
|
+
if (!skill) {
|
|
137
|
+
const available = skills.map((s) => s.name).join(', ');
|
|
138
|
+
throw new Error(`Skill "${args.name}" not found. Available skills: ${available || 'none'}`);
|
|
139
|
+
}
|
|
140
|
+
const body = await extractSkillBody(skill);
|
|
141
|
+
const dir = skill.path ? dirname(skill.path) : skill.resolvedPath || process.cwd();
|
|
142
|
+
const output = [
|
|
143
|
+
`## Skill: ${skill.name}`,
|
|
144
|
+
'',
|
|
145
|
+
`**Base directory**: ${dir}`,
|
|
146
|
+
'',
|
|
147
|
+
body
|
|
148
|
+
];
|
|
149
|
+
// Add MCP capabilities if manager available
|
|
150
|
+
if (mcpManager && getSessionID && skill.mcpConfig) {
|
|
151
|
+
const mcpInfo = await formatMcpCapabilities(skill, mcpManager, getSessionID());
|
|
152
|
+
if (mcpInfo) {
|
|
153
|
+
output.push(mcpInfo);
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
return output.join('\n');
|
|
157
|
+
}
|
|
158
|
+
});
|
|
159
|
+
}
|
|
160
|
+
//# sourceMappingURL=skill.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"skill.js","sourceRoot":"","sources":["../../src/tools/skill.ts"],"names":[],"mappings":"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"}
|
package/dist/types.d.ts
ADDED
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Configuration for an MCP server
|
|
3
|
+
*/
|
|
4
|
+
export interface McpServerConfig {
|
|
5
|
+
command?: string | string[];
|
|
6
|
+
environment?: Record<string, string>;
|
|
7
|
+
}
|
|
8
|
+
/**
|
|
9
|
+
* Skill scope - where the skill was loaded from
|
|
10
|
+
*/
|
|
11
|
+
export type SkillScope = 'opencode' | 'opencode-project';
|
|
12
|
+
/**
|
|
13
|
+
* Lazy content loader for skill templates
|
|
14
|
+
*/
|
|
15
|
+
export interface LazyContent {
|
|
16
|
+
loaded: boolean;
|
|
17
|
+
content?: string;
|
|
18
|
+
load: () => Promise<string>;
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* Skill definition stored with the skill
|
|
22
|
+
*/
|
|
23
|
+
export interface SkillDefinition {
|
|
24
|
+
name: string;
|
|
25
|
+
description: string;
|
|
26
|
+
template: string;
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* A loaded skill with all metadata
|
|
30
|
+
*/
|
|
31
|
+
export interface LoadedSkill {
|
|
32
|
+
name: string;
|
|
33
|
+
path?: string;
|
|
34
|
+
resolvedPath?: string;
|
|
35
|
+
definition: SkillDefinition;
|
|
36
|
+
scope: SkillScope;
|
|
37
|
+
mcpConfig?: Record<string, McpServerConfig>;
|
|
38
|
+
lazyContent?: LazyContent;
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* Information needed to identify an MCP client connection
|
|
42
|
+
*/
|
|
43
|
+
export interface McpClientInfo {
|
|
44
|
+
sessionID: string;
|
|
45
|
+
skillName: string;
|
|
46
|
+
serverName: string;
|
|
47
|
+
}
|
|
48
|
+
/**
|
|
49
|
+
* Context for MCP operations
|
|
50
|
+
*/
|
|
51
|
+
export interface McpContext {
|
|
52
|
+
config: McpServerConfig;
|
|
53
|
+
skillName: string;
|
|
54
|
+
}
|
|
55
|
+
/**
|
|
56
|
+
* Parsed frontmatter data from skill markdown
|
|
57
|
+
*/
|
|
58
|
+
export interface SkillFrontmatter {
|
|
59
|
+
name?: string;
|
|
60
|
+
description?: string;
|
|
61
|
+
mcp?: Record<string, McpServerConfig>;
|
|
62
|
+
}
|
|
63
|
+
/**
|
|
64
|
+
* Result of parsing a markdown file with frontmatter
|
|
65
|
+
*/
|
|
66
|
+
export interface ParsedFrontmatter {
|
|
67
|
+
data: SkillFrontmatter;
|
|
68
|
+
body: string;
|
|
69
|
+
}
|
|
70
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,MAAM,WAAW,eAAe;IAC9B,OAAO,CAAC,EAAE,MAAM,GAAG,MAAM,EAAE,CAAA;IAC3B,WAAW,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;CACrC;AAED;;GAEG;AACH,MAAM,MAAM,UAAU,GAAG,UAAU,GAAG,kBAAkB,CAAA;AAExD;;GAEG;AACH,MAAM,WAAW,WAAW;IAC1B,MAAM,EAAE,OAAO,CAAA;IACf,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,IAAI,EAAE,MAAM,OAAO,CAAC,MAAM,CAAC,CAAA;CAC5B;AAED;;GAEG;AACH,MAAM,WAAW,eAAe;IAC9B,IAAI,EAAE,MAAM,CAAA;IACZ,WAAW,EAAE,MAAM,CAAA;IACnB,QAAQ,EAAE,MAAM,CAAA;CACjB;AAED;;GAEG;AACH,MAAM,WAAW,WAAW;IAC1B,IAAI,EAAE,MAAM,CAAA;IACZ,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,YAAY,CAAC,EAAE,MAAM,CAAA;IACrB,UAAU,EAAE,eAAe,CAAA;IAC3B,KAAK,EAAE,UAAU,CAAA;IACjB,SAAS,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,eAAe,CAAC,CAAA;IAC3C,WAAW,CAAC,EAAE,WAAW,CAAA;CAC1B;AAED;;GAEG;AACH,MAAM,WAAW,aAAa;IAC5B,SAAS,EAAE,MAAM,CAAA;IACjB,SAAS,EAAE,MAAM,CAAA;IACjB,UAAU,EAAE,MAAM,CAAA;CACnB;AAED;;GAEG;AACH,MAAM,WAAW,UAAU;IACzB,MAAM,EAAE,eAAe,CAAA;IACvB,SAAS,EAAE,MAAM,CAAA;CAClB;AAED;;GAEG;AACH,MAAM,WAAW,gBAAgB;IAC/B,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,GAAG,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,eAAe,CAAC,CAAA;CACtC;AAED;;GAEG;AACH,MAAM,WAAW,iBAAiB;IAChC,IAAI,EAAE,gBAAgB,CAAA;IACtB,IAAI,EAAE,MAAM,CAAA;CACb"}
|
package/dist/types.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Expand environment variables in a string
|
|
3
|
+
* Supports ${VAR} and ${VAR:-default} syntax
|
|
4
|
+
*/
|
|
5
|
+
export declare function expandEnvVars(value: string): string;
|
|
6
|
+
/**
|
|
7
|
+
* Recursively expand environment variables in an object
|
|
8
|
+
*/
|
|
9
|
+
export declare function expandEnvVarsInObject<T>(obj: T): T;
|
|
10
|
+
/**
|
|
11
|
+
* Create a clean environment for MCP processes
|
|
12
|
+
* Merges process.env with custom env vars, expanding variables
|
|
13
|
+
*/
|
|
14
|
+
export declare function createCleanMcpEnvironment(customEnv?: Record<string, string>): Record<string, string>;
|
|
15
|
+
//# sourceMappingURL=env-vars.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"env-vars.d.ts","sourceRoot":"","sources":["../../src/utils/env-vars.ts"],"names":[],"mappings":"AAEA;;;GAGG;AACH,wBAAgB,aAAa,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAOnD;AAED;;GAEG;AACH,wBAAgB,qBAAqB,CAAC,CAAC,EAAE,GAAG,EAAE,CAAC,GAAG,CAAC,CAkBlD;AAED;;;GAGG;AACH,wBAAgB,yBAAyB,CACvC,SAAS,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GACjC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CA6BxB"}
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Expand environment variables in a string
|
|
3
|
+
* Supports ${VAR} and ${VAR:-default} syntax
|
|
4
|
+
*/
|
|
5
|
+
export function expandEnvVars(value) {
|
|
6
|
+
return value.replace(/\$\{([^}:]+)(?::-([^}]*))?\}/g, (_, varName, defaultValue) => {
|
|
7
|
+
return process.env[varName] ?? defaultValue ?? '';
|
|
8
|
+
});
|
|
9
|
+
}
|
|
10
|
+
/**
|
|
11
|
+
* Recursively expand environment variables in an object
|
|
12
|
+
*/
|
|
13
|
+
export function expandEnvVarsInObject(obj) {
|
|
14
|
+
if (typeof obj === 'string') {
|
|
15
|
+
return expandEnvVars(obj);
|
|
16
|
+
}
|
|
17
|
+
if (Array.isArray(obj)) {
|
|
18
|
+
return obj.map(expandEnvVarsInObject);
|
|
19
|
+
}
|
|
20
|
+
if (obj && typeof obj === 'object') {
|
|
21
|
+
const result = {};
|
|
22
|
+
for (const [key, value] of Object.entries(obj)) {
|
|
23
|
+
result[key] = expandEnvVarsInObject(value);
|
|
24
|
+
}
|
|
25
|
+
return result;
|
|
26
|
+
}
|
|
27
|
+
return obj;
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* Create a clean environment for MCP processes
|
|
31
|
+
* Merges process.env with custom env vars, expanding variables
|
|
32
|
+
*/
|
|
33
|
+
export function createCleanMcpEnvironment(customEnv) {
|
|
34
|
+
const baseEnv = {};
|
|
35
|
+
// Copy essential environment variables
|
|
36
|
+
const essentialVars = [
|
|
37
|
+
'PATH',
|
|
38
|
+
'HOME',
|
|
39
|
+
'USER',
|
|
40
|
+
'SHELL',
|
|
41
|
+
'TERM',
|
|
42
|
+
'NODE_ENV',
|
|
43
|
+
'npm_config_registry',
|
|
44
|
+
'npm_config_cache'
|
|
45
|
+
];
|
|
46
|
+
for (const varName of essentialVars) {
|
|
47
|
+
if (process.env[varName]) {
|
|
48
|
+
baseEnv[varName] = process.env[varName];
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
// Merge custom env vars with expansion
|
|
52
|
+
if (customEnv) {
|
|
53
|
+
for (const [key, value] of Object.entries(customEnv)) {
|
|
54
|
+
baseEnv[key] = expandEnvVars(value);
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
return baseEnv;
|
|
58
|
+
}
|
|
59
|
+
//# sourceMappingURL=env-vars.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"env-vars.js","sourceRoot":"","sources":["../../src/utils/env-vars.ts"],"names":[],"mappings":"AAEA;;;GAGG;AACH,MAAM,UAAU,aAAa,CAAC,KAAa;IACzC,OAAO,KAAK,CAAC,OAAO,CAClB,+BAA+B,EAC/B,CAAC,CAAC,EAAE,OAAe,EAAE,YAAqB,EAAE,EAAE;QAC5C,OAAO,OAAO,CAAC,GAAG,CAAC,OAAO,CAAC,IAAI,YAAY,IAAI,EAAE,CAAA;IACnD,CAAC,CACF,CAAA;AACH,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,qBAAqB,CAAI,GAAM;IAC7C,IAAI,OAAO,GAAG,KAAK,QAAQ,EAAE,CAAC;QAC5B,OAAO,aAAa,CAAC,GAAG,CAAM,CAAA;IAChC,CAAC;IAED,IAAI,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC;QACvB,OAAO,GAAG,CAAC,GAAG,CAAC,qBAAqB,CAAM,CAAA;IAC5C,CAAC;IAED,IAAI,GAAG,IAAI,OAAO,GAAG,KAAK,QAAQ,EAAE,CAAC;QACnC,MAAM,MAAM,GAA4B,EAAE,CAAA;QAC1C,KAAK,MAAM,CAAC,GAAG,EAAE,KAAK,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC;YAC/C,MAAM,CAAC,GAAG,CAAC,GAAG,qBAAqB,CAAC,KAAK,CAAC,CAAA;QAC5C,CAAC;QACD,OAAO,MAAW,CAAA;IACpB,CAAC;IAED,OAAO,GAAG,CAAA;AACZ,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,yBAAyB,CACvC,SAAkC;IAElC,MAAM,OAAO,GAA2B,EAAE,CAAA;IAE1C,uCAAuC;IACvC,MAAM,aAAa,GAAG;QACpB,MAAM;QACN,MAAM;QACN,MAAM;QACN,OAAO;QACP,MAAM;QACN,UAAU;QACV,qBAAqB;QACrB,kBAAkB;KACnB,CAAA;IAED,KAAK,MAAM,OAAO,IAAI,aAAa,EAAE,CAAC;QACpC,IAAI,OAAO,CAAC,GAAG,CAAC,OAAO,CAAC,EAAE,CAAC;YACzB,OAAO,CAAC,OAAO,CAAC,GAAG,OAAO,CAAC,GAAG,CAAC,OAAO,CAAE,CAAA;QAC1C,CAAC;IACH,CAAC;IAED,uCAAuC;IACvC,IAAI,SAAS,EAAE,CAAC;QACd,KAAK,MAAM,CAAC,GAAG,EAAE,KAAK,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,SAAS,CAAC,EAAE,CAAC;YACrD,OAAO,CAAC,GAAG,CAAC,GAAG,aAAa,CAAC,KAAK,CAAC,CAAA;QACrC,CAAC;IACH,CAAC;IAED,OAAO,OAAO,CAAA;AAChB,CAAC"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type { ParsedFrontmatter, McpServerConfig } from '../types.js';
|
|
2
|
+
/**
|
|
3
|
+
* Parse YAML frontmatter from markdown content
|
|
4
|
+
*/
|
|
5
|
+
export declare function parseFrontmatter(content: string): ParsedFrontmatter;
|
|
6
|
+
/**
|
|
7
|
+
* Parse MCP config specifically from frontmatter content
|
|
8
|
+
*/
|
|
9
|
+
export declare function parseSkillMcpConfigFromFrontmatter(content: string): Record<string, McpServerConfig> | undefined;
|
|
10
|
+
//# sourceMappingURL=frontmatter.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"frontmatter.d.ts","sourceRoot":"","sources":["../../src/utils/frontmatter.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,iBAAiB,EAAoB,eAAe,EAAE,MAAM,aAAa,CAAA;AAEvF;;GAEG;AACH,wBAAgB,gBAAgB,CAAC,OAAO,EAAE,MAAM,GAAG,iBAAiB,CAoBnE;AAED;;GAEG;AACH,wBAAgB,kCAAkC,CAChD,OAAO,EAAE,MAAM,GACd,MAAM,CAAC,MAAM,EAAE,eAAe,CAAC,GAAG,SAAS,CAiB7C"}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import * as yaml from 'js-yaml';
|
|
2
|
+
/**
|
|
3
|
+
* Parse YAML frontmatter from markdown content
|
|
4
|
+
*/
|
|
5
|
+
export function parseFrontmatter(content) {
|
|
6
|
+
const frontmatterMatch = content.match(/^---\r?\n([\s\S]*?)\r?\n---/);
|
|
7
|
+
if (!frontmatterMatch) {
|
|
8
|
+
return {
|
|
9
|
+
data: {},
|
|
10
|
+
body: content
|
|
11
|
+
};
|
|
12
|
+
}
|
|
13
|
+
try {
|
|
14
|
+
const data = yaml.load(frontmatterMatch[1]);
|
|
15
|
+
const body = content.slice(frontmatterMatch[0].length).trim();
|
|
16
|
+
return { data: data || {}, body };
|
|
17
|
+
}
|
|
18
|
+
catch {
|
|
19
|
+
return {
|
|
20
|
+
data: {},
|
|
21
|
+
body: content
|
|
22
|
+
};
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* Parse MCP config specifically from frontmatter content
|
|
27
|
+
*/
|
|
28
|
+
export function parseSkillMcpConfigFromFrontmatter(content) {
|
|
29
|
+
const frontmatterMatch = content.match(/^---\r?\n([\s\S]*?)\r?\n---/);
|
|
30
|
+
if (!frontmatterMatch) {
|
|
31
|
+
return undefined;
|
|
32
|
+
}
|
|
33
|
+
try {
|
|
34
|
+
const parsed = yaml.load(frontmatterMatch[1]);
|
|
35
|
+
if (parsed && typeof parsed === 'object' && 'mcp' in parsed && parsed.mcp) {
|
|
36
|
+
return parsed.mcp;
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
catch {
|
|
40
|
+
return undefined;
|
|
41
|
+
}
|
|
42
|
+
return undefined;
|
|
43
|
+
}
|
|
44
|
+
//# sourceMappingURL=frontmatter.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"frontmatter.js","sourceRoot":"","sources":["../../src/utils/frontmatter.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,IAAI,MAAM,SAAS,CAAA;AAG/B;;GAEG;AACH,MAAM,UAAU,gBAAgB,CAAC,OAAe;IAC9C,MAAM,gBAAgB,GAAG,OAAO,CAAC,KAAK,CAAC,6BAA6B,CAAC,CAAA;IAErE,IAAI,CAAC,gBAAgB,EAAE,CAAC;QACtB,OAAO;YACL,IAAI,EAAE,EAAE;YACR,IAAI,EAAE,OAAO;SACd,CAAA;IACH,CAAC;IAED,IAAI,CAAC;QACH,MAAM,IAAI,GAAG,IAAI,CAAC,IAAI,CAAC,gBAAgB,CAAC,CAAC,CAAC,CAAqB,CAAA;QAC/D,MAAM,IAAI,GAAG,OAAO,CAAC,KAAK,CAAC,gBAAgB,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,IAAI,EAAE,CAAA;QAC7D,OAAO,EAAE,IAAI,EAAE,IAAI,IAAI,EAAE,EAAE,IAAI,EAAE,CAAA;IACnC,CAAC;IAAC,MAAM,CAAC;QACP,OAAO;YACL,IAAI,EAAE,EAAE;YACR,IAAI,EAAE,OAAO;SACd,CAAA;IACH,CAAC;AACH,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,kCAAkC,CAChD,OAAe;IAEf,MAAM,gBAAgB,GAAG,OAAO,CAAC,KAAK,CAAC,6BAA6B,CAAC,CAAA;IAErE,IAAI,CAAC,gBAAgB,EAAE,CAAC;QACtB,OAAO,SAAS,CAAA;IAClB,CAAC;IAED,IAAI,CAAC;QACH,MAAM,MAAM,GAAG,IAAI,CAAC,IAAI,CAAC,gBAAgB,CAAC,CAAC,CAAC,CAA8C,CAAA;QAC1F,IAAI,MAAM,IAAI,OAAO,MAAM,KAAK,QAAQ,IAAI,KAAK,IAAI,MAAM,IAAI,MAAM,CAAC,GAAG,EAAE,CAAC;YAC1E,OAAO,MAAM,CAAC,GAAG,CAAA;QACnB,CAAC;IACH,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,SAAS,CAAA;IAClB,CAAC;IAED,OAAO,SAAS,CAAA;AAClB,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,14 +1,15 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "opencode-lazy-loader",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.1",
|
|
4
4
|
"description": "OpenCode plugin for lazy-loading skill-embedded MCP servers",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.js",
|
|
7
7
|
"types": "dist/index.d.ts",
|
|
8
8
|
"scripts": {
|
|
9
|
-
"build": "tsc",
|
|
10
|
-
"watch": "tsc --watch",
|
|
11
|
-
"clean": "rm -rf dist"
|
|
9
|
+
"build": "npx tsc",
|
|
10
|
+
"watch": "npx tsc --watch",
|
|
11
|
+
"clean": "rm -rf dist",
|
|
12
|
+
"prepack": "npm run clean && npm run build"
|
|
12
13
|
},
|
|
13
14
|
"keywords": [
|
|
14
15
|
"opencode",
|