@mcpc-tech/core 0.3.38 → 0.3.40
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/bash.cjs +198 -0
- package/plugins/bash.mjs +164 -0
- package/plugins/skills.cjs +8 -2
- package/plugins/skills.mjs +8 -2
- package/plugins.cjs +154 -2
- package/plugins.mjs +153 -2
- package/types/plugins.d.ts +1 -0
- package/types/plugins.d.ts.map +1 -1
- package/types/src/plugins/bash.d.ts +37 -0
- package/types/src/plugins/bash.d.ts.map +1 -0
- package/types/src/plugins/skills.d.ts.map +1 -1
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@mcpc-tech/core",
|
|
3
|
-
"version": "0.3.
|
|
3
|
+
"version": "0.3.40",
|
|
4
4
|
"homepage": "https://jsr.io/@mcpc/core",
|
|
5
5
|
"dependencies": {
|
|
6
6
|
"@ai-sdk/provider": "^2.0.0",
|
|
@@ -48,6 +48,11 @@
|
|
|
48
48
|
"import": "./plugins/skills.mjs",
|
|
49
49
|
"require": "./plugins/skills.cjs"
|
|
50
50
|
},
|
|
51
|
+
"./plugins/bash": {
|
|
52
|
+
"types": "./types/src/plugins/bash.d.ts",
|
|
53
|
+
"import": "./plugins/bash.mjs",
|
|
54
|
+
"require": "./plugins/bash.cjs"
|
|
55
|
+
},
|
|
51
56
|
"./types/*": "./types/*"
|
|
52
57
|
},
|
|
53
58
|
"repository": {
|
package/plugins/bash.cjs
ADDED
|
@@ -0,0 +1,198 @@
|
|
|
1
|
+
var __create = Object.create;
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
6
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
7
|
+
var __export = (target, all) => {
|
|
8
|
+
for (var name in all)
|
|
9
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
10
|
+
};
|
|
11
|
+
var __copyProps = (to, from, except, desc) => {
|
|
12
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
13
|
+
for (let key of __getOwnPropNames(from))
|
|
14
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
15
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
16
|
+
}
|
|
17
|
+
return to;
|
|
18
|
+
};
|
|
19
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
20
|
+
// If the importer is in node compatibility mode or this is not an ESM
|
|
21
|
+
// file that has been converted to a CommonJS file using a Babel-
|
|
22
|
+
// compatible transform (i.e. "__esModule" has not been set), then set
|
|
23
|
+
// "default" to the CommonJS "module.exports" for node compatibility.
|
|
24
|
+
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
25
|
+
mod
|
|
26
|
+
));
|
|
27
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
28
|
+
|
|
29
|
+
// __mcpc__core_latest/node_modules/@mcpc/core/src/plugins/bash.ts
|
|
30
|
+
var bash_exports = {};
|
|
31
|
+
__export(bash_exports, {
|
|
32
|
+
createBashPlugin: () => createBashPlugin,
|
|
33
|
+
createPlugin: () => createPlugin,
|
|
34
|
+
default: () => bash_default,
|
|
35
|
+
executeBash: () => executeBash,
|
|
36
|
+
truncateOutput: () => truncateOutput
|
|
37
|
+
});
|
|
38
|
+
module.exports = __toCommonJS(bash_exports);
|
|
39
|
+
var import_node_child_process = require("node:child_process");
|
|
40
|
+
var import_node_process = __toESM(require("node:process"), 1);
|
|
41
|
+
var DEFAULT_MAX_BYTES = 1e5;
|
|
42
|
+
var DEFAULT_MAX_LINES = 2e3;
|
|
43
|
+
var DEFAULT_TIMEOUT_MS = 6e4;
|
|
44
|
+
function truncateOutput(stdout, stderr, maxBytes = DEFAULT_MAX_BYTES, maxLines = DEFAULT_MAX_LINES) {
|
|
45
|
+
const fullOutput = (stderr ? `STDERR:
|
|
46
|
+
${stderr}
|
|
47
|
+
|
|
48
|
+
STDOUT:
|
|
49
|
+
` : "") + stdout;
|
|
50
|
+
const lines = fullOutput.split("\n");
|
|
51
|
+
if (lines.length > maxLines) {
|
|
52
|
+
const truncatedLines = lines.slice(-maxLines);
|
|
53
|
+
return {
|
|
54
|
+
output: `[OUTPUT TRUNCATED] Showing last ${maxLines} lines of ${lines.length} total
|
|
55
|
+
|
|
56
|
+
` + truncatedLines.join("\n"),
|
|
57
|
+
truncated: true
|
|
58
|
+
};
|
|
59
|
+
}
|
|
60
|
+
if (fullOutput.length > maxBytes) {
|
|
61
|
+
const truncatedBytes = fullOutput.slice(-maxBytes);
|
|
62
|
+
return {
|
|
63
|
+
output: `[OUTPUT TRUNCATED] Showing last ${maxBytes} bytes of ${fullOutput.length} total
|
|
64
|
+
|
|
65
|
+
` + truncatedBytes,
|
|
66
|
+
truncated: true
|
|
67
|
+
};
|
|
68
|
+
}
|
|
69
|
+
return { output: fullOutput, truncated: false };
|
|
70
|
+
}
|
|
71
|
+
function executeBash(command, cwd, timeoutMs) {
|
|
72
|
+
return new Promise((resolve) => {
|
|
73
|
+
const stdout = [];
|
|
74
|
+
const stderr = [];
|
|
75
|
+
const proc = (0, import_node_child_process.spawn)("bash", ["-c", command], {
|
|
76
|
+
cwd,
|
|
77
|
+
stdio: ["ignore", "pipe", "pipe"]
|
|
78
|
+
});
|
|
79
|
+
proc.stdout?.on("data", (data) => {
|
|
80
|
+
stdout.push(data.toString());
|
|
81
|
+
});
|
|
82
|
+
proc.stderr?.on("data", (data) => {
|
|
83
|
+
stderr.push(data.toString());
|
|
84
|
+
});
|
|
85
|
+
proc.on("close", (code) => {
|
|
86
|
+
resolve({
|
|
87
|
+
stdout: stdout.join(""),
|
|
88
|
+
stderr: stderr.join(""),
|
|
89
|
+
exitCode: code
|
|
90
|
+
});
|
|
91
|
+
});
|
|
92
|
+
proc.on("error", (err) => {
|
|
93
|
+
resolve({
|
|
94
|
+
stdout: "",
|
|
95
|
+
stderr: err.message,
|
|
96
|
+
exitCode: null
|
|
97
|
+
});
|
|
98
|
+
});
|
|
99
|
+
setTimeout(() => {
|
|
100
|
+
proc.kill("SIGTERM");
|
|
101
|
+
resolve({
|
|
102
|
+
stdout: stdout.join(""),
|
|
103
|
+
stderr: stderr.join("") + "\n\n[TIMEOUT] Command execution timed out",
|
|
104
|
+
exitCode: null
|
|
105
|
+
});
|
|
106
|
+
}, timeoutMs);
|
|
107
|
+
});
|
|
108
|
+
}
|
|
109
|
+
function createBashPlugin(options = {}) {
|
|
110
|
+
const { maxBytes, maxLines, timeoutMs } = {
|
|
111
|
+
maxBytes: DEFAULT_MAX_BYTES,
|
|
112
|
+
maxLines: DEFAULT_MAX_LINES,
|
|
113
|
+
timeoutMs: DEFAULT_TIMEOUT_MS,
|
|
114
|
+
...options
|
|
115
|
+
};
|
|
116
|
+
let serverRef = null;
|
|
117
|
+
return {
|
|
118
|
+
name: "plugin-bash",
|
|
119
|
+
version: "1.0.0",
|
|
120
|
+
// Store server reference for tool registration
|
|
121
|
+
configureServer: (server) => {
|
|
122
|
+
serverRef = server;
|
|
123
|
+
},
|
|
124
|
+
// Register bash tool with agent name prefix
|
|
125
|
+
composeStart: (context) => {
|
|
126
|
+
if (!serverRef) return;
|
|
127
|
+
const agentName = context.serverName;
|
|
128
|
+
const toolName = `${agentName}__bash`;
|
|
129
|
+
serverRef.tool(
|
|
130
|
+
toolName,
|
|
131
|
+
"Execute a bash command and return its output.\n\nUse this for:\n- Running shell commands\n- Executing scripts\n- System operations\n\nNote: Output is truncated if too large.",
|
|
132
|
+
{
|
|
133
|
+
type: "object",
|
|
134
|
+
properties: {
|
|
135
|
+
command: {
|
|
136
|
+
type: "string",
|
|
137
|
+
description: "The bash command to execute"
|
|
138
|
+
},
|
|
139
|
+
cwd: {
|
|
140
|
+
type: "string",
|
|
141
|
+
description: "Optional: Working directory for the command (defaults to current directory)"
|
|
142
|
+
}
|
|
143
|
+
},
|
|
144
|
+
required: ["command"]
|
|
145
|
+
},
|
|
146
|
+
async (args) => {
|
|
147
|
+
const cwd = args.cwd || import_node_process.default.cwd();
|
|
148
|
+
const result = await executeBash(args.command, cwd, timeoutMs);
|
|
149
|
+
const { output, truncated } = truncateOutput(
|
|
150
|
+
result.stdout,
|
|
151
|
+
result.stderr,
|
|
152
|
+
maxBytes,
|
|
153
|
+
maxLines
|
|
154
|
+
);
|
|
155
|
+
let finalOutput = output;
|
|
156
|
+
if (result.exitCode !== null && result.exitCode !== 0) {
|
|
157
|
+
finalOutput = `[EXIT CODE: ${result.exitCode}]
|
|
158
|
+
` + finalOutput;
|
|
159
|
+
}
|
|
160
|
+
if (truncated) {
|
|
161
|
+
finalOutput += `
|
|
162
|
+
|
|
163
|
+
[Note: Output was truncated]`;
|
|
164
|
+
}
|
|
165
|
+
return {
|
|
166
|
+
content: [{ type: "text", text: finalOutput }],
|
|
167
|
+
isError: result.exitCode !== null && result.exitCode !== 0
|
|
168
|
+
};
|
|
169
|
+
},
|
|
170
|
+
{ internal: true }
|
|
171
|
+
);
|
|
172
|
+
}
|
|
173
|
+
};
|
|
174
|
+
}
|
|
175
|
+
function createPlugin(params) {
|
|
176
|
+
const options = {};
|
|
177
|
+
if (params.maxBytes) {
|
|
178
|
+
const parsed = parseInt(params.maxBytes, 10);
|
|
179
|
+
if (!isNaN(parsed)) options.maxBytes = parsed;
|
|
180
|
+
}
|
|
181
|
+
if (params.maxLines) {
|
|
182
|
+
const parsed = parseInt(params.maxLines, 10);
|
|
183
|
+
if (!isNaN(parsed)) options.maxLines = parsed;
|
|
184
|
+
}
|
|
185
|
+
if (params.timeout) {
|
|
186
|
+
const parsed = parseInt(params.timeout, 10);
|
|
187
|
+
if (!isNaN(parsed)) options.timeoutMs = parsed * 1e3;
|
|
188
|
+
}
|
|
189
|
+
return createBashPlugin(options);
|
|
190
|
+
}
|
|
191
|
+
var bash_default = createBashPlugin;
|
|
192
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
193
|
+
0 && (module.exports = {
|
|
194
|
+
createBashPlugin,
|
|
195
|
+
createPlugin,
|
|
196
|
+
executeBash,
|
|
197
|
+
truncateOutput
|
|
198
|
+
});
|
package/plugins/bash.mjs
ADDED
|
@@ -0,0 +1,164 @@
|
|
|
1
|
+
import { createRequire } from 'node:module';
|
|
2
|
+
const require = createRequire(import.meta.url);
|
|
3
|
+
|
|
4
|
+
// __mcpc__core_latest/node_modules/@mcpc/core/src/plugins/bash.ts
|
|
5
|
+
import { spawn } from "node:child_process";
|
|
6
|
+
import process from "node:process";
|
|
7
|
+
var DEFAULT_MAX_BYTES = 1e5;
|
|
8
|
+
var DEFAULT_MAX_LINES = 2e3;
|
|
9
|
+
var DEFAULT_TIMEOUT_MS = 6e4;
|
|
10
|
+
function truncateOutput(stdout, stderr, maxBytes = DEFAULT_MAX_BYTES, maxLines = DEFAULT_MAX_LINES) {
|
|
11
|
+
const fullOutput = (stderr ? `STDERR:
|
|
12
|
+
${stderr}
|
|
13
|
+
|
|
14
|
+
STDOUT:
|
|
15
|
+
` : "") + stdout;
|
|
16
|
+
const lines = fullOutput.split("\n");
|
|
17
|
+
if (lines.length > maxLines) {
|
|
18
|
+
const truncatedLines = lines.slice(-maxLines);
|
|
19
|
+
return {
|
|
20
|
+
output: `[OUTPUT TRUNCATED] Showing last ${maxLines} lines of ${lines.length} total
|
|
21
|
+
|
|
22
|
+
` + truncatedLines.join("\n"),
|
|
23
|
+
truncated: true
|
|
24
|
+
};
|
|
25
|
+
}
|
|
26
|
+
if (fullOutput.length > maxBytes) {
|
|
27
|
+
const truncatedBytes = fullOutput.slice(-maxBytes);
|
|
28
|
+
return {
|
|
29
|
+
output: `[OUTPUT TRUNCATED] Showing last ${maxBytes} bytes of ${fullOutput.length} total
|
|
30
|
+
|
|
31
|
+
` + truncatedBytes,
|
|
32
|
+
truncated: true
|
|
33
|
+
};
|
|
34
|
+
}
|
|
35
|
+
return { output: fullOutput, truncated: false };
|
|
36
|
+
}
|
|
37
|
+
function executeBash(command, cwd, timeoutMs) {
|
|
38
|
+
return new Promise((resolve) => {
|
|
39
|
+
const stdout = [];
|
|
40
|
+
const stderr = [];
|
|
41
|
+
const proc = spawn("bash", ["-c", command], {
|
|
42
|
+
cwd,
|
|
43
|
+
stdio: ["ignore", "pipe", "pipe"]
|
|
44
|
+
});
|
|
45
|
+
proc.stdout?.on("data", (data) => {
|
|
46
|
+
stdout.push(data.toString());
|
|
47
|
+
});
|
|
48
|
+
proc.stderr?.on("data", (data) => {
|
|
49
|
+
stderr.push(data.toString());
|
|
50
|
+
});
|
|
51
|
+
proc.on("close", (code) => {
|
|
52
|
+
resolve({
|
|
53
|
+
stdout: stdout.join(""),
|
|
54
|
+
stderr: stderr.join(""),
|
|
55
|
+
exitCode: code
|
|
56
|
+
});
|
|
57
|
+
});
|
|
58
|
+
proc.on("error", (err) => {
|
|
59
|
+
resolve({
|
|
60
|
+
stdout: "",
|
|
61
|
+
stderr: err.message,
|
|
62
|
+
exitCode: null
|
|
63
|
+
});
|
|
64
|
+
});
|
|
65
|
+
setTimeout(() => {
|
|
66
|
+
proc.kill("SIGTERM");
|
|
67
|
+
resolve({
|
|
68
|
+
stdout: stdout.join(""),
|
|
69
|
+
stderr: stderr.join("") + "\n\n[TIMEOUT] Command execution timed out",
|
|
70
|
+
exitCode: null
|
|
71
|
+
});
|
|
72
|
+
}, timeoutMs);
|
|
73
|
+
});
|
|
74
|
+
}
|
|
75
|
+
function createBashPlugin(options = {}) {
|
|
76
|
+
const { maxBytes, maxLines, timeoutMs } = {
|
|
77
|
+
maxBytes: DEFAULT_MAX_BYTES,
|
|
78
|
+
maxLines: DEFAULT_MAX_LINES,
|
|
79
|
+
timeoutMs: DEFAULT_TIMEOUT_MS,
|
|
80
|
+
...options
|
|
81
|
+
};
|
|
82
|
+
let serverRef = null;
|
|
83
|
+
return {
|
|
84
|
+
name: "plugin-bash",
|
|
85
|
+
version: "1.0.0",
|
|
86
|
+
// Store server reference for tool registration
|
|
87
|
+
configureServer: (server) => {
|
|
88
|
+
serverRef = server;
|
|
89
|
+
},
|
|
90
|
+
// Register bash tool with agent name prefix
|
|
91
|
+
composeStart: (context) => {
|
|
92
|
+
if (!serverRef) return;
|
|
93
|
+
const agentName = context.serverName;
|
|
94
|
+
const toolName = `${agentName}__bash`;
|
|
95
|
+
serverRef.tool(
|
|
96
|
+
toolName,
|
|
97
|
+
"Execute a bash command and return its output.\n\nUse this for:\n- Running shell commands\n- Executing scripts\n- System operations\n\nNote: Output is truncated if too large.",
|
|
98
|
+
{
|
|
99
|
+
type: "object",
|
|
100
|
+
properties: {
|
|
101
|
+
command: {
|
|
102
|
+
type: "string",
|
|
103
|
+
description: "The bash command to execute"
|
|
104
|
+
},
|
|
105
|
+
cwd: {
|
|
106
|
+
type: "string",
|
|
107
|
+
description: "Optional: Working directory for the command (defaults to current directory)"
|
|
108
|
+
}
|
|
109
|
+
},
|
|
110
|
+
required: ["command"]
|
|
111
|
+
},
|
|
112
|
+
async (args) => {
|
|
113
|
+
const cwd = args.cwd || process.cwd();
|
|
114
|
+
const result = await executeBash(args.command, cwd, timeoutMs);
|
|
115
|
+
const { output, truncated } = truncateOutput(
|
|
116
|
+
result.stdout,
|
|
117
|
+
result.stderr,
|
|
118
|
+
maxBytes,
|
|
119
|
+
maxLines
|
|
120
|
+
);
|
|
121
|
+
let finalOutput = output;
|
|
122
|
+
if (result.exitCode !== null && result.exitCode !== 0) {
|
|
123
|
+
finalOutput = `[EXIT CODE: ${result.exitCode}]
|
|
124
|
+
` + finalOutput;
|
|
125
|
+
}
|
|
126
|
+
if (truncated) {
|
|
127
|
+
finalOutput += `
|
|
128
|
+
|
|
129
|
+
[Note: Output was truncated]`;
|
|
130
|
+
}
|
|
131
|
+
return {
|
|
132
|
+
content: [{ type: "text", text: finalOutput }],
|
|
133
|
+
isError: result.exitCode !== null && result.exitCode !== 0
|
|
134
|
+
};
|
|
135
|
+
},
|
|
136
|
+
{ internal: true }
|
|
137
|
+
);
|
|
138
|
+
}
|
|
139
|
+
};
|
|
140
|
+
}
|
|
141
|
+
function createPlugin(params) {
|
|
142
|
+
const options = {};
|
|
143
|
+
if (params.maxBytes) {
|
|
144
|
+
const parsed = parseInt(params.maxBytes, 10);
|
|
145
|
+
if (!isNaN(parsed)) options.maxBytes = parsed;
|
|
146
|
+
}
|
|
147
|
+
if (params.maxLines) {
|
|
148
|
+
const parsed = parseInt(params.maxLines, 10);
|
|
149
|
+
if (!isNaN(parsed)) options.maxLines = parsed;
|
|
150
|
+
}
|
|
151
|
+
if (params.timeout) {
|
|
152
|
+
const parsed = parseInt(params.timeout, 10);
|
|
153
|
+
if (!isNaN(parsed)) options.timeoutMs = parsed * 1e3;
|
|
154
|
+
}
|
|
155
|
+
return createBashPlugin(options);
|
|
156
|
+
}
|
|
157
|
+
var bash_default = createBashPlugin;
|
|
158
|
+
export {
|
|
159
|
+
createBashPlugin,
|
|
160
|
+
createPlugin,
|
|
161
|
+
bash_default as default,
|
|
162
|
+
executeBash,
|
|
163
|
+
truncateOutput
|
|
164
|
+
};
|
package/plugins/skills.cjs
CHANGED
|
@@ -105,7 +105,7 @@ Usage:
|
|
|
105
105
|
- ${toolName}({ skill: "skill-name" }) - Load main SKILL.md content
|
|
106
106
|
- ${toolName}({ skill: "skill-name", ref: "path/to/file" }) - Load reference file
|
|
107
107
|
|
|
108
|
-
Note: For scripts
|
|
108
|
+
Note: For scripts/, use the bash tool with the script path to execute.`;
|
|
109
109
|
}
|
|
110
110
|
function createSkillsPlugin(options) {
|
|
111
111
|
const { paths } = options;
|
|
@@ -205,7 +205,13 @@ Available skills: ${available.join(", ")}` : "\n\nNo skills available.";
|
|
|
205
205
|
"utf-8"
|
|
206
206
|
);
|
|
207
207
|
const body = extractBody(content);
|
|
208
|
-
|
|
208
|
+
const skillPathInfo = `
|
|
209
|
+
---
|
|
210
|
+
Skill path: ${meta.basePath}
|
|
211
|
+
`;
|
|
212
|
+
return {
|
|
213
|
+
content: [{ type: "text", text: body + skillPathInfo }]
|
|
214
|
+
};
|
|
209
215
|
} catch {
|
|
210
216
|
return {
|
|
211
217
|
content: [
|
package/plugins/skills.mjs
CHANGED
|
@@ -83,7 +83,7 @@ Usage:
|
|
|
83
83
|
- ${toolName}({ skill: "skill-name" }) - Load main SKILL.md content
|
|
84
84
|
- ${toolName}({ skill: "skill-name", ref: "path/to/file" }) - Load reference file
|
|
85
85
|
|
|
86
|
-
Note: For scripts
|
|
86
|
+
Note: For scripts/, use the bash tool with the script path to execute.`;
|
|
87
87
|
}
|
|
88
88
|
function createSkillsPlugin(options) {
|
|
89
89
|
const { paths } = options;
|
|
@@ -183,7 +183,13 @@ Available skills: ${available.join(", ")}` : "\n\nNo skills available.";
|
|
|
183
183
|
"utf-8"
|
|
184
184
|
);
|
|
185
185
|
const body = extractBody(content);
|
|
186
|
-
|
|
186
|
+
const skillPathInfo = `
|
|
187
|
+
---
|
|
188
|
+
Skill path: ${meta.basePath}
|
|
189
|
+
`;
|
|
190
|
+
return {
|
|
191
|
+
content: [{ type: "text", text: body + skillPathInfo }]
|
|
192
|
+
};
|
|
187
193
|
} catch {
|
|
188
194
|
return {
|
|
189
195
|
content: [
|
package/plugins.cjs
CHANGED
|
@@ -29,6 +29,7 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
|
|
|
29
29
|
// __mcpc__core_latest/node_modules/@mcpc/core/plugins.ts
|
|
30
30
|
var plugins_exports = {};
|
|
31
31
|
__export(plugins_exports, {
|
|
32
|
+
createBashPlugin: () => createBashPlugin,
|
|
32
33
|
createLargeResultPlugin: () => createLargeResultPlugin,
|
|
33
34
|
createSearchPlugin: () => createSearchPlugin,
|
|
34
35
|
createSkillsPlugin: () => createSkillsPlugin,
|
|
@@ -447,7 +448,7 @@ Usage:
|
|
|
447
448
|
- ${toolName}({ skill: "skill-name" }) - Load main SKILL.md content
|
|
448
449
|
- ${toolName}({ skill: "skill-name", ref: "path/to/file" }) - Load reference file
|
|
449
450
|
|
|
450
|
-
Note: For scripts
|
|
451
|
+
Note: For scripts/, use the bash tool with the script path to execute.`;
|
|
451
452
|
}
|
|
452
453
|
function createSkillsPlugin(options) {
|
|
453
454
|
const { paths } = options;
|
|
@@ -555,11 +556,15 @@ Available skills: ${available.join(", ")}` : "\n\nNo skills available.";
|
|
|
555
556
|
try {
|
|
556
557
|
const content = await (0, import_promises2.readFile)((0, import_node_path4.join)(meta.basePath, "SKILL.md"), "utf-8");
|
|
557
558
|
const body = extractBody(content);
|
|
559
|
+
const skillPathInfo = `
|
|
560
|
+
---
|
|
561
|
+
Skill path: ${meta.basePath}
|
|
562
|
+
`;
|
|
558
563
|
return {
|
|
559
564
|
content: [
|
|
560
565
|
{
|
|
561
566
|
type: "text",
|
|
562
|
-
text: body
|
|
567
|
+
text: body + skillPathInfo
|
|
563
568
|
}
|
|
564
569
|
]
|
|
565
570
|
};
|
|
@@ -585,8 +590,155 @@ Available skills: ${available.join(", ")}` : "\n\nNo skills available.";
|
|
|
585
590
|
}
|
|
586
591
|
};
|
|
587
592
|
}
|
|
593
|
+
|
|
594
|
+
// __mcpc__core_latest/node_modules/@mcpc/core/src/plugins/bash.js
|
|
595
|
+
var import_node_child_process = require("node:child_process");
|
|
596
|
+
var import_node_process = __toESM(require("node:process"), 1);
|
|
597
|
+
var DEFAULT_MAX_BYTES = 1e5;
|
|
598
|
+
var DEFAULT_MAX_LINES = 2e3;
|
|
599
|
+
var DEFAULT_TIMEOUT_MS = 6e4;
|
|
600
|
+
function truncateOutput(stdout, stderr, maxBytes = DEFAULT_MAX_BYTES, maxLines = DEFAULT_MAX_LINES) {
|
|
601
|
+
const fullOutput = (stderr ? `STDERR:
|
|
602
|
+
${stderr}
|
|
603
|
+
|
|
604
|
+
STDOUT:
|
|
605
|
+
` : "") + stdout;
|
|
606
|
+
const lines = fullOutput.split("\n");
|
|
607
|
+
if (lines.length > maxLines) {
|
|
608
|
+
const truncatedLines = lines.slice(-maxLines);
|
|
609
|
+
return {
|
|
610
|
+
output: `[OUTPUT TRUNCATED] Showing last ${maxLines} lines of ${lines.length} total
|
|
611
|
+
|
|
612
|
+
` + truncatedLines.join("\n"),
|
|
613
|
+
truncated: true
|
|
614
|
+
};
|
|
615
|
+
}
|
|
616
|
+
if (fullOutput.length > maxBytes) {
|
|
617
|
+
const truncatedBytes = fullOutput.slice(-maxBytes);
|
|
618
|
+
return {
|
|
619
|
+
output: `[OUTPUT TRUNCATED] Showing last ${maxBytes} bytes of ${fullOutput.length} total
|
|
620
|
+
|
|
621
|
+
` + truncatedBytes,
|
|
622
|
+
truncated: true
|
|
623
|
+
};
|
|
624
|
+
}
|
|
625
|
+
return {
|
|
626
|
+
output: fullOutput,
|
|
627
|
+
truncated: false
|
|
628
|
+
};
|
|
629
|
+
}
|
|
630
|
+
function executeBash(command, cwd, timeoutMs) {
|
|
631
|
+
return new Promise((resolve3) => {
|
|
632
|
+
const stdout = [];
|
|
633
|
+
const stderr = [];
|
|
634
|
+
const proc = (0, import_node_child_process.spawn)("bash", [
|
|
635
|
+
"-c",
|
|
636
|
+
command
|
|
637
|
+
], {
|
|
638
|
+
cwd,
|
|
639
|
+
stdio: [
|
|
640
|
+
"ignore",
|
|
641
|
+
"pipe",
|
|
642
|
+
"pipe"
|
|
643
|
+
]
|
|
644
|
+
});
|
|
645
|
+
proc.stdout?.on("data", (data) => {
|
|
646
|
+
stdout.push(data.toString());
|
|
647
|
+
});
|
|
648
|
+
proc.stderr?.on("data", (data) => {
|
|
649
|
+
stderr.push(data.toString());
|
|
650
|
+
});
|
|
651
|
+
proc.on("close", (code) => {
|
|
652
|
+
resolve3({
|
|
653
|
+
stdout: stdout.join(""),
|
|
654
|
+
stderr: stderr.join(""),
|
|
655
|
+
exitCode: code
|
|
656
|
+
});
|
|
657
|
+
});
|
|
658
|
+
proc.on("error", (err) => {
|
|
659
|
+
resolve3({
|
|
660
|
+
stdout: "",
|
|
661
|
+
stderr: err.message,
|
|
662
|
+
exitCode: null
|
|
663
|
+
});
|
|
664
|
+
});
|
|
665
|
+
setTimeout(() => {
|
|
666
|
+
proc.kill("SIGTERM");
|
|
667
|
+
resolve3({
|
|
668
|
+
stdout: stdout.join(""),
|
|
669
|
+
stderr: stderr.join("") + "\n\n[TIMEOUT] Command execution timed out",
|
|
670
|
+
exitCode: null
|
|
671
|
+
});
|
|
672
|
+
}, timeoutMs);
|
|
673
|
+
});
|
|
674
|
+
}
|
|
675
|
+
function createBashPlugin(options = {}) {
|
|
676
|
+
const { maxBytes, maxLines, timeoutMs } = {
|
|
677
|
+
maxBytes: DEFAULT_MAX_BYTES,
|
|
678
|
+
maxLines: DEFAULT_MAX_LINES,
|
|
679
|
+
timeoutMs: DEFAULT_TIMEOUT_MS,
|
|
680
|
+
...options
|
|
681
|
+
};
|
|
682
|
+
let serverRef = null;
|
|
683
|
+
return {
|
|
684
|
+
name: "plugin-bash",
|
|
685
|
+
version: "1.0.0",
|
|
686
|
+
// Store server reference for tool registration
|
|
687
|
+
configureServer: (server) => {
|
|
688
|
+
serverRef = server;
|
|
689
|
+
},
|
|
690
|
+
// Register bash tool with agent name prefix
|
|
691
|
+
composeStart: (context) => {
|
|
692
|
+
if (!serverRef) return;
|
|
693
|
+
const agentName = context.serverName;
|
|
694
|
+
const toolName = `${agentName}__bash`;
|
|
695
|
+
serverRef.tool(toolName, "Execute a bash command and return its output.\n\nUse this for:\n- Running shell commands\n- Executing scripts\n- System operations\n\nNote: Output is truncated if too large.", {
|
|
696
|
+
type: "object",
|
|
697
|
+
properties: {
|
|
698
|
+
command: {
|
|
699
|
+
type: "string",
|
|
700
|
+
description: "The bash command to execute"
|
|
701
|
+
},
|
|
702
|
+
cwd: {
|
|
703
|
+
type: "string",
|
|
704
|
+
description: "Optional: Working directory for the command (defaults to current directory)"
|
|
705
|
+
}
|
|
706
|
+
},
|
|
707
|
+
required: [
|
|
708
|
+
"command"
|
|
709
|
+
]
|
|
710
|
+
}, async (args) => {
|
|
711
|
+
const cwd = args.cwd || import_node_process.default.cwd();
|
|
712
|
+
const result = await executeBash(args.command, cwd, timeoutMs);
|
|
713
|
+
const { output, truncated } = truncateOutput(result.stdout, result.stderr, maxBytes, maxLines);
|
|
714
|
+
let finalOutput = output;
|
|
715
|
+
if (result.exitCode !== null && result.exitCode !== 0) {
|
|
716
|
+
finalOutput = `[EXIT CODE: ${result.exitCode}]
|
|
717
|
+
` + finalOutput;
|
|
718
|
+
}
|
|
719
|
+
if (truncated) {
|
|
720
|
+
finalOutput += `
|
|
721
|
+
|
|
722
|
+
[Note: Output was truncated]`;
|
|
723
|
+
}
|
|
724
|
+
return {
|
|
725
|
+
content: [
|
|
726
|
+
{
|
|
727
|
+
type: "text",
|
|
728
|
+
text: finalOutput
|
|
729
|
+
}
|
|
730
|
+
],
|
|
731
|
+
isError: result.exitCode !== null && result.exitCode !== 0
|
|
732
|
+
};
|
|
733
|
+
}, {
|
|
734
|
+
internal: true
|
|
735
|
+
});
|
|
736
|
+
}
|
|
737
|
+
};
|
|
738
|
+
}
|
|
588
739
|
// Annotate the CommonJS export names for ESM import in node:
|
|
589
740
|
0 && (module.exports = {
|
|
741
|
+
createBashPlugin,
|
|
590
742
|
createLargeResultPlugin,
|
|
591
743
|
createSearchPlugin,
|
|
592
744
|
createSkillsPlugin,
|
package/plugins.mjs
CHANGED
|
@@ -411,7 +411,7 @@ Usage:
|
|
|
411
411
|
- ${toolName}({ skill: "skill-name" }) - Load main SKILL.md content
|
|
412
412
|
- ${toolName}({ skill: "skill-name", ref: "path/to/file" }) - Load reference file
|
|
413
413
|
|
|
414
|
-
Note: For scripts
|
|
414
|
+
Note: For scripts/, use the bash tool with the script path to execute.`;
|
|
415
415
|
}
|
|
416
416
|
function createSkillsPlugin(options) {
|
|
417
417
|
const { paths } = options;
|
|
@@ -519,11 +519,15 @@ Available skills: ${available.join(", ")}` : "\n\nNo skills available.";
|
|
|
519
519
|
try {
|
|
520
520
|
const content = await readFile(join2(meta.basePath, "SKILL.md"), "utf-8");
|
|
521
521
|
const body = extractBody(content);
|
|
522
|
+
const skillPathInfo = `
|
|
523
|
+
---
|
|
524
|
+
Skill path: ${meta.basePath}
|
|
525
|
+
`;
|
|
522
526
|
return {
|
|
523
527
|
content: [
|
|
524
528
|
{
|
|
525
529
|
type: "text",
|
|
526
|
-
text: body
|
|
530
|
+
text: body + skillPathInfo
|
|
527
531
|
}
|
|
528
532
|
]
|
|
529
533
|
};
|
|
@@ -549,7 +553,154 @@ Available skills: ${available.join(", ")}` : "\n\nNo skills available.";
|
|
|
549
553
|
}
|
|
550
554
|
};
|
|
551
555
|
}
|
|
556
|
+
|
|
557
|
+
// __mcpc__core_latest/node_modules/@mcpc/core/src/plugins/bash.js
|
|
558
|
+
import { spawn } from "node:child_process";
|
|
559
|
+
import process from "node:process";
|
|
560
|
+
var DEFAULT_MAX_BYTES = 1e5;
|
|
561
|
+
var DEFAULT_MAX_LINES = 2e3;
|
|
562
|
+
var DEFAULT_TIMEOUT_MS = 6e4;
|
|
563
|
+
function truncateOutput(stdout, stderr, maxBytes = DEFAULT_MAX_BYTES, maxLines = DEFAULT_MAX_LINES) {
|
|
564
|
+
const fullOutput = (stderr ? `STDERR:
|
|
565
|
+
${stderr}
|
|
566
|
+
|
|
567
|
+
STDOUT:
|
|
568
|
+
` : "") + stdout;
|
|
569
|
+
const lines = fullOutput.split("\n");
|
|
570
|
+
if (lines.length > maxLines) {
|
|
571
|
+
const truncatedLines = lines.slice(-maxLines);
|
|
572
|
+
return {
|
|
573
|
+
output: `[OUTPUT TRUNCATED] Showing last ${maxLines} lines of ${lines.length} total
|
|
574
|
+
|
|
575
|
+
` + truncatedLines.join("\n"),
|
|
576
|
+
truncated: true
|
|
577
|
+
};
|
|
578
|
+
}
|
|
579
|
+
if (fullOutput.length > maxBytes) {
|
|
580
|
+
const truncatedBytes = fullOutput.slice(-maxBytes);
|
|
581
|
+
return {
|
|
582
|
+
output: `[OUTPUT TRUNCATED] Showing last ${maxBytes} bytes of ${fullOutput.length} total
|
|
583
|
+
|
|
584
|
+
` + truncatedBytes,
|
|
585
|
+
truncated: true
|
|
586
|
+
};
|
|
587
|
+
}
|
|
588
|
+
return {
|
|
589
|
+
output: fullOutput,
|
|
590
|
+
truncated: false
|
|
591
|
+
};
|
|
592
|
+
}
|
|
593
|
+
function executeBash(command, cwd, timeoutMs) {
|
|
594
|
+
return new Promise((resolve3) => {
|
|
595
|
+
const stdout = [];
|
|
596
|
+
const stderr = [];
|
|
597
|
+
const proc = spawn("bash", [
|
|
598
|
+
"-c",
|
|
599
|
+
command
|
|
600
|
+
], {
|
|
601
|
+
cwd,
|
|
602
|
+
stdio: [
|
|
603
|
+
"ignore",
|
|
604
|
+
"pipe",
|
|
605
|
+
"pipe"
|
|
606
|
+
]
|
|
607
|
+
});
|
|
608
|
+
proc.stdout?.on("data", (data) => {
|
|
609
|
+
stdout.push(data.toString());
|
|
610
|
+
});
|
|
611
|
+
proc.stderr?.on("data", (data) => {
|
|
612
|
+
stderr.push(data.toString());
|
|
613
|
+
});
|
|
614
|
+
proc.on("close", (code) => {
|
|
615
|
+
resolve3({
|
|
616
|
+
stdout: stdout.join(""),
|
|
617
|
+
stderr: stderr.join(""),
|
|
618
|
+
exitCode: code
|
|
619
|
+
});
|
|
620
|
+
});
|
|
621
|
+
proc.on("error", (err) => {
|
|
622
|
+
resolve3({
|
|
623
|
+
stdout: "",
|
|
624
|
+
stderr: err.message,
|
|
625
|
+
exitCode: null
|
|
626
|
+
});
|
|
627
|
+
});
|
|
628
|
+
setTimeout(() => {
|
|
629
|
+
proc.kill("SIGTERM");
|
|
630
|
+
resolve3({
|
|
631
|
+
stdout: stdout.join(""),
|
|
632
|
+
stderr: stderr.join("") + "\n\n[TIMEOUT] Command execution timed out",
|
|
633
|
+
exitCode: null
|
|
634
|
+
});
|
|
635
|
+
}, timeoutMs);
|
|
636
|
+
});
|
|
637
|
+
}
|
|
638
|
+
function createBashPlugin(options = {}) {
|
|
639
|
+
const { maxBytes, maxLines, timeoutMs } = {
|
|
640
|
+
maxBytes: DEFAULT_MAX_BYTES,
|
|
641
|
+
maxLines: DEFAULT_MAX_LINES,
|
|
642
|
+
timeoutMs: DEFAULT_TIMEOUT_MS,
|
|
643
|
+
...options
|
|
644
|
+
};
|
|
645
|
+
let serverRef = null;
|
|
646
|
+
return {
|
|
647
|
+
name: "plugin-bash",
|
|
648
|
+
version: "1.0.0",
|
|
649
|
+
// Store server reference for tool registration
|
|
650
|
+
configureServer: (server) => {
|
|
651
|
+
serverRef = server;
|
|
652
|
+
},
|
|
653
|
+
// Register bash tool with agent name prefix
|
|
654
|
+
composeStart: (context) => {
|
|
655
|
+
if (!serverRef) return;
|
|
656
|
+
const agentName = context.serverName;
|
|
657
|
+
const toolName = `${agentName}__bash`;
|
|
658
|
+
serverRef.tool(toolName, "Execute a bash command and return its output.\n\nUse this for:\n- Running shell commands\n- Executing scripts\n- System operations\n\nNote: Output is truncated if too large.", {
|
|
659
|
+
type: "object",
|
|
660
|
+
properties: {
|
|
661
|
+
command: {
|
|
662
|
+
type: "string",
|
|
663
|
+
description: "The bash command to execute"
|
|
664
|
+
},
|
|
665
|
+
cwd: {
|
|
666
|
+
type: "string",
|
|
667
|
+
description: "Optional: Working directory for the command (defaults to current directory)"
|
|
668
|
+
}
|
|
669
|
+
},
|
|
670
|
+
required: [
|
|
671
|
+
"command"
|
|
672
|
+
]
|
|
673
|
+
}, async (args) => {
|
|
674
|
+
const cwd = args.cwd || process.cwd();
|
|
675
|
+
const result = await executeBash(args.command, cwd, timeoutMs);
|
|
676
|
+
const { output, truncated } = truncateOutput(result.stdout, result.stderr, maxBytes, maxLines);
|
|
677
|
+
let finalOutput = output;
|
|
678
|
+
if (result.exitCode !== null && result.exitCode !== 0) {
|
|
679
|
+
finalOutput = `[EXIT CODE: ${result.exitCode}]
|
|
680
|
+
` + finalOutput;
|
|
681
|
+
}
|
|
682
|
+
if (truncated) {
|
|
683
|
+
finalOutput += `
|
|
684
|
+
|
|
685
|
+
[Note: Output was truncated]`;
|
|
686
|
+
}
|
|
687
|
+
return {
|
|
688
|
+
content: [
|
|
689
|
+
{
|
|
690
|
+
type: "text",
|
|
691
|
+
text: finalOutput
|
|
692
|
+
}
|
|
693
|
+
],
|
|
694
|
+
isError: result.exitCode !== null && result.exitCode !== 0
|
|
695
|
+
};
|
|
696
|
+
}, {
|
|
697
|
+
internal: true
|
|
698
|
+
});
|
|
699
|
+
}
|
|
700
|
+
};
|
|
701
|
+
}
|
|
552
702
|
export {
|
|
703
|
+
createBashPlugin,
|
|
553
704
|
createLargeResultPlugin,
|
|
554
705
|
createSearchPlugin,
|
|
555
706
|
createSkillsPlugin,
|
package/types/plugins.d.ts
CHANGED
|
@@ -38,6 +38,7 @@
|
|
|
38
38
|
*/ export { createSearchPlugin } from "./src/plugins/search-tool.js";
|
|
39
39
|
export { createLargeResultPlugin } from "./src/plugins/large-result.js";
|
|
40
40
|
export { createSkillsPlugin } from "./src/plugins/skills.js";
|
|
41
|
+
export { createBashPlugin } from "./src/plugins/bash.js";
|
|
41
42
|
export { default as defaultSearchPlugin } from "./src/plugins/search-tool.js";
|
|
42
43
|
export { default as defaultLargeResultPlugin } from "./src/plugins/large-result.js";
|
|
43
44
|
export type { SearchOptions } from "./src/plugins/search-tool.js";
|
package/types/plugins.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"plugins.d.ts","sources":["../plugins.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAqCC,GAGD,SAAS,kBAAkB,uCAAuC;AAClE,SAAS,uBAAuB,wCAAwC;AACxE,SAAS,kBAAkB,kCAAkC;
|
|
1
|
+
{"version":3,"file":"plugins.d.ts","sources":["../plugins.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAqCC,GAGD,SAAS,kBAAkB,uCAAuC;AAClE,SAAS,uBAAuB,wCAAwC;AACxE,SAAS,kBAAkB,kCAAkC;AAC7D,SAAS,gBAAgB,gCAAgC;AAGzD,SAAS,WAAW,mBAAmB,uCAAuC;AAC9E,SAAS,WAAW,wBAAwB,wCAAwC;AAGpF,cAAc,aAAa,uCAAuC"}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import type { ToolPlugin } from "../plugin-types.js";
|
|
2
|
+
export interface BashPluginOptions {
|
|
3
|
+
/** Maximum output bytes to return */ maxBytes?: number;
|
|
4
|
+
/** Maximum output lines to return */ maxLines?: number;
|
|
5
|
+
/** Command execution timeout in ms */ timeoutMs?: number;
|
|
6
|
+
}
|
|
7
|
+
/**
|
|
8
|
+
* Truncate output to prevent context pollution
|
|
9
|
+
*/ export declare function truncateOutput(stdout: string, stderr: string, maxBytes?: number, maxLines?: number): {
|
|
10
|
+
output: string;
|
|
11
|
+
truncated: boolean;
|
|
12
|
+
};
|
|
13
|
+
/**
|
|
14
|
+
* Execute a bash command
|
|
15
|
+
*/ export declare function executeBash(command: string, cwd: string, timeoutMs: number): Promise<{
|
|
16
|
+
stdout: string;
|
|
17
|
+
stderr: string;
|
|
18
|
+
exitCode: number | null;
|
|
19
|
+
}>;
|
|
20
|
+
/**
|
|
21
|
+
* Create a bash plugin that provides command execution capability
|
|
22
|
+
*/ export declare function createBashPlugin(options?: BashPluginOptions): ToolPlugin;
|
|
23
|
+
/**
|
|
24
|
+
* Factory function for parameterized usage via string path
|
|
25
|
+
*
|
|
26
|
+
* Supports query parameters:
|
|
27
|
+
* - maxBytes: Maximum output bytes (default: 100000)
|
|
28
|
+
* - maxLines: Maximum output lines (default: 2000)
|
|
29
|
+
* - timeout: Timeout in seconds (default: 60)
|
|
30
|
+
*
|
|
31
|
+
* @example
|
|
32
|
+
* ```ts
|
|
33
|
+
* plugins: ["@mcpc/core/plugins/bash?maxBytes=50000&timeout=30"]
|
|
34
|
+
* ```
|
|
35
|
+
*/ export declare function createPlugin(params: Record<string, string>): ToolPlugin;
|
|
36
|
+
export default createBashPlugin;
|
|
37
|
+
//# sourceMappingURL=bash.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"bash.d.ts","sources":["../../../src/plugins/bash.ts"],"names":[],"mappings":"AAWA,cAAmC,UAAU,6BAA6B;AAS1E,iBAAiB;EACf,mCAAmC,GACnC,WAAW,MAAM;EACjB,mCAAmC,GACnC,WAAW,MAAM;EACjB,oCAAoC,GACpC,YAAY,MAAM;;AAGpB;;CAEC,GACD,OAAO,iBAAS,eACd,QAAQ,MAAM,EACd,QAAQ,MAAM,EACd,WAAU,MAAM,AAAoB,EACpC,WAAU,MAAM,AAAoB;EACjC,QAAQ,MAAM;EAAE,WAAW,OAAO;;AA6BvC;;CAEC,GACD,OAAO,iBAAS,YACd,SAAS,MAAM,EACf,KAAK,MAAM,EACX,WAAW,MAAM,GAChB;EAAU,QAAQ,MAAM;EAAE,QAAQ,MAAM;EAAE,UAAU,MAAM,GAAG,IAAI;;AA+CpE;;CAEC,GACD,OAAO,iBAAS,iBAAiB,UAAS,iBAAsB,GAAG;AA+EnE;;;;;;;;;;;;CAYC,GACD,OAAO,iBAAS,aAAa,QAAQ,OAAO,MAAM,EAAE,MAAM,CAAC,GAAG;AAqB9D,eAAe,iBAAiB"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"skills.d.ts","sources":["../../../src/plugins/skills.ts"],"names":[],"mappings":"AAOA,cAAmC,UAAU,6BAA6B;UAWhE;EACR,mCAAmC,GACnC,OAAO,MAAM;;AAoGf;;CAEC,GACD,OAAO,iBAAS,mBAAmB,SAAS,mBAAmB,GAAG;
|
|
1
|
+
{"version":3,"file":"skills.d.ts","sources":["../../../src/plugins/skills.ts"],"names":[],"mappings":"AAOA,cAAmC,UAAU,6BAA6B;UAWhE;EACR,mCAAmC,GACnC,OAAO,MAAM;;AAoGf;;CAEC,GACD,OAAO,iBAAS,mBAAmB,SAAS,mBAAmB,GAAG;AAkJlE;;;;;;;;;;;;;CAaC,GACD,OAAO,iBAAS,aAAa,QAAQ,OAAO,MAAM,EAAE,MAAM,CAAC,GAAG;AAM9D,eAAe,mBAAmB"}
|