@shareai-lab/kode-sdk 2.7.1 → 2.7.2
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/core/agent/breakpoint-manager.js +36 -0
- package/dist/core/agent/message-queue.js +57 -0
- package/dist/core/agent/permission-manager.js +32 -0
- package/dist/core/agent/todo-manager.js +91 -0
- package/dist/core/agent/tool-runner.js +45 -0
- package/dist/core/agent.js +2035 -0
- package/dist/core/config.js +2 -0
- package/dist/core/context-manager.js +241 -0
- package/dist/core/errors.js +49 -0
- package/dist/core/events.js +329 -0
- package/dist/core/file-pool.d.ts +2 -0
- package/dist/core/file-pool.js +125 -0
- package/dist/core/hooks.js +71 -0
- package/dist/core/permission-modes.js +61 -0
- package/dist/core/pool.js +301 -0
- package/dist/core/room.js +57 -0
- package/dist/core/scheduler.js +58 -0
- package/dist/core/skills/index.js +20 -0
- package/dist/core/skills/management-manager.js +557 -0
- package/dist/core/skills/manager.js +243 -0
- package/dist/core/skills/operation-queue.js +113 -0
- package/dist/core/skills/sandbox-file-manager.js +183 -0
- package/dist/core/skills/types.js +9 -0
- package/dist/core/skills/xml-generator.js +70 -0
- package/dist/core/template.js +35 -0
- package/dist/core/time-bridge.js +100 -0
- package/dist/core/todo.js +89 -0
- package/dist/core/types.js +3 -0
- package/dist/index.js +148 -60461
- package/dist/infra/db/postgres/postgres-store.js +1073 -0
- package/dist/infra/db/sqlite/sqlite-store.js +800 -0
- package/dist/infra/e2b/e2b-fs.js +128 -0
- package/dist/infra/e2b/e2b-sandbox.js +156 -0
- package/dist/infra/e2b/e2b-template.js +105 -0
- package/dist/infra/e2b/index.js +9 -0
- package/dist/infra/e2b/types.js +2 -0
- package/dist/infra/provider.js +67 -0
- package/dist/infra/providers/anthropic.js +308 -0
- package/dist/infra/providers/core/errors.js +353 -0
- package/dist/infra/providers/core/fork.js +418 -0
- package/dist/infra/providers/core/index.js +76 -0
- package/dist/infra/providers/core/logger.js +191 -0
- package/dist/infra/providers/core/retry.js +189 -0
- package/dist/infra/providers/core/usage.js +376 -0
- package/dist/infra/providers/gemini.js +493 -0
- package/dist/infra/providers/index.js +83 -0
- package/dist/infra/providers/openai.js +662 -0
- package/dist/infra/providers/types.js +20 -0
- package/dist/infra/providers/utils.js +400 -0
- package/dist/infra/sandbox-factory.js +30 -0
- package/dist/infra/sandbox.js +243 -0
- package/dist/infra/store/factory.js +80 -0
- package/dist/infra/store/index.js +26 -0
- package/dist/infra/store/json-store.js +606 -0
- package/dist/infra/store/types.js +2 -0
- package/dist/infra/store.js +29 -0
- package/dist/tools/bash_kill/index.js +35 -0
- package/dist/tools/bash_kill/prompt.js +14 -0
- package/dist/tools/bash_logs/index.js +40 -0
- package/dist/tools/bash_logs/prompt.js +14 -0
- package/dist/tools/bash_run/index.js +61 -0
- package/dist/tools/bash_run/prompt.js +18 -0
- package/dist/tools/builtin.js +26 -0
- package/dist/tools/define.js +214 -0
- package/dist/tools/fs_edit/index.js +62 -0
- package/dist/tools/fs_edit/prompt.js +15 -0
- package/dist/tools/fs_glob/index.js +40 -0
- package/dist/tools/fs_glob/prompt.js +15 -0
- package/dist/tools/fs_grep/index.js +66 -0
- package/dist/tools/fs_grep/prompt.js +16 -0
- package/dist/tools/fs_multi_edit/index.js +106 -0
- package/dist/tools/fs_multi_edit/prompt.js +16 -0
- package/dist/tools/fs_read/index.js +40 -0
- package/dist/tools/fs_read/prompt.js +16 -0
- package/dist/tools/fs_write/index.js +40 -0
- package/dist/tools/fs_write/prompt.js +15 -0
- package/dist/tools/index.js +61 -0
- package/dist/tools/mcp.js +185 -0
- package/dist/tools/registry.js +26 -0
- package/dist/tools/scripts.js +205 -0
- package/dist/tools/skills.js +115 -0
- package/dist/tools/task_run/index.js +58 -0
- package/dist/tools/task_run/prompt.js +25 -0
- package/dist/tools/todo_read/index.js +29 -0
- package/dist/tools/todo_read/prompt.js +18 -0
- package/dist/tools/todo_write/index.js +42 -0
- package/dist/tools/todo_write/prompt.js +23 -0
- package/dist/tools/tool.js +211 -0
- package/dist/tools/toolkit.js +98 -0
- package/dist/tools/type-inference.js +207 -0
- package/dist/utils/agent-id.js +28 -0
- package/dist/utils/logger.js +44 -0
- package/dist/utils/session-id.js +64 -0
- package/package.json +7 -38
- package/dist/index.js.map +0 -7
- package/dist/index.mjs +0 -60385
- package/dist/index.mjs.map +0 -7
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.FsMultiEdit = void 0;
|
|
4
|
+
const tool_1 = require("../tool");
|
|
5
|
+
const zod_1 = require("zod");
|
|
6
|
+
const type_inference_1 = require("../type-inference");
|
|
7
|
+
const prompt_1 = require("./prompt");
|
|
8
|
+
const editSchema = zod_1.z.object({
|
|
9
|
+
path: type_inference_1.patterns.filePath('File path'),
|
|
10
|
+
find: zod_1.z.string().describe('Existing text to replace'),
|
|
11
|
+
replace: zod_1.z.string().describe('Replacement text'),
|
|
12
|
+
replace_all: zod_1.z.boolean().optional().describe('Replace all occurrences (default: false)'),
|
|
13
|
+
});
|
|
14
|
+
exports.FsMultiEdit = (0, tool_1.tool)({
|
|
15
|
+
name: 'fs_multi_edit',
|
|
16
|
+
description: prompt_1.DESCRIPTION,
|
|
17
|
+
parameters: zod_1.z.object({
|
|
18
|
+
edits: zod_1.z.array(editSchema).describe('List of edit operations'),
|
|
19
|
+
}),
|
|
20
|
+
async execute(args, ctx) {
|
|
21
|
+
const { edits } = args;
|
|
22
|
+
const results = [];
|
|
23
|
+
for (const edit of edits) {
|
|
24
|
+
try {
|
|
25
|
+
const freshness = await ctx.services?.filePool?.validateWrite(edit.path);
|
|
26
|
+
if (freshness && !freshness.isFresh) {
|
|
27
|
+
results.push({
|
|
28
|
+
path: edit.path,
|
|
29
|
+
replacements: 0,
|
|
30
|
+
status: 'skipped',
|
|
31
|
+
message: 'File changed externally',
|
|
32
|
+
});
|
|
33
|
+
continue;
|
|
34
|
+
}
|
|
35
|
+
const content = await ctx.sandbox.fs.read(edit.path);
|
|
36
|
+
if (edit.replace_all) {
|
|
37
|
+
const occurrences = content.split(edit.find).length - 1;
|
|
38
|
+
if (occurrences === 0) {
|
|
39
|
+
results.push({
|
|
40
|
+
path: edit.path,
|
|
41
|
+
replacements: 0,
|
|
42
|
+
status: 'skipped',
|
|
43
|
+
message: 'Pattern not found',
|
|
44
|
+
});
|
|
45
|
+
continue;
|
|
46
|
+
}
|
|
47
|
+
const updated = content.split(edit.find).join(edit.replace);
|
|
48
|
+
await ctx.sandbox.fs.write(edit.path, updated);
|
|
49
|
+
await ctx.services?.filePool?.recordEdit(edit.path);
|
|
50
|
+
results.push({
|
|
51
|
+
path: edit.path,
|
|
52
|
+
replacements: occurrences,
|
|
53
|
+
status: 'ok',
|
|
54
|
+
});
|
|
55
|
+
}
|
|
56
|
+
else {
|
|
57
|
+
const index = content.indexOf(edit.find);
|
|
58
|
+
if (index === -1) {
|
|
59
|
+
results.push({
|
|
60
|
+
path: edit.path,
|
|
61
|
+
replacements: 0,
|
|
62
|
+
status: 'skipped',
|
|
63
|
+
message: 'Pattern not found',
|
|
64
|
+
});
|
|
65
|
+
continue;
|
|
66
|
+
}
|
|
67
|
+
const occurrences = content.split(edit.find).length - 1;
|
|
68
|
+
if (occurrences > 1) {
|
|
69
|
+
results.push({
|
|
70
|
+
path: edit.path,
|
|
71
|
+
replacements: 0,
|
|
72
|
+
status: 'skipped',
|
|
73
|
+
message: `Pattern occurs ${occurrences} times; set replace_all=true if intended`,
|
|
74
|
+
});
|
|
75
|
+
continue;
|
|
76
|
+
}
|
|
77
|
+
const updated = content.replace(edit.find, edit.replace);
|
|
78
|
+
await ctx.sandbox.fs.write(edit.path, updated);
|
|
79
|
+
await ctx.services?.filePool?.recordEdit(edit.path);
|
|
80
|
+
results.push({
|
|
81
|
+
path: edit.path,
|
|
82
|
+
replacements: 1,
|
|
83
|
+
status: 'ok',
|
|
84
|
+
});
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
catch (error) {
|
|
88
|
+
results.push({
|
|
89
|
+
path: edit.path,
|
|
90
|
+
replacements: 0,
|
|
91
|
+
status: 'error',
|
|
92
|
+
message: error?.message || String(error),
|
|
93
|
+
});
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
return {
|
|
97
|
+
ok: results.every((r) => r.status === 'ok'),
|
|
98
|
+
results,
|
|
99
|
+
};
|
|
100
|
+
},
|
|
101
|
+
metadata: {
|
|
102
|
+
readonly: false,
|
|
103
|
+
version: '1.0',
|
|
104
|
+
},
|
|
105
|
+
});
|
|
106
|
+
exports.FsMultiEdit.prompt = prompt_1.PROMPT;
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.PROMPT = exports.DESCRIPTION = void 0;
|
|
4
|
+
exports.DESCRIPTION = 'Apply multiple string replacements across files';
|
|
5
|
+
exports.PROMPT = `Batch apply targeted edits across files.
|
|
6
|
+
|
|
7
|
+
Guidelines:
|
|
8
|
+
- Each operation specifies a path and the text to replace.
|
|
9
|
+
- Use fs_read to verify context beforehand.
|
|
10
|
+
- All edits are applied sequentially; failures are isolated per file.
|
|
11
|
+
- Each edit includes status feedback (ok, skipped, or error).
|
|
12
|
+
|
|
13
|
+
Safety/Limitations:
|
|
14
|
+
- Freshness validation prevents conflicts with external modifications.
|
|
15
|
+
- Failed edits are reported but don't halt the batch.
|
|
16
|
+
- Non-unique patterns require explicit replace_all flag.`;
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.FsRead = void 0;
|
|
4
|
+
const tool_1 = require("../tool");
|
|
5
|
+
const zod_1 = require("zod");
|
|
6
|
+
const type_inference_1 = require("../type-inference");
|
|
7
|
+
const prompt_1 = require("./prompt");
|
|
8
|
+
exports.FsRead = (0, tool_1.tool)({
|
|
9
|
+
name: 'fs_read',
|
|
10
|
+
description: prompt_1.DESCRIPTION,
|
|
11
|
+
parameters: zod_1.z.object({
|
|
12
|
+
path: type_inference_1.patterns.filePath('Path to file relative to sandbox root'),
|
|
13
|
+
offset: type_inference_1.patterns.optionalNumber('Line offset (1-indexed)'),
|
|
14
|
+
limit: type_inference_1.patterns.optionalNumber('Max lines to read'),
|
|
15
|
+
}),
|
|
16
|
+
async execute(args, ctx) {
|
|
17
|
+
const { path, offset, limit } = args;
|
|
18
|
+
const content = await ctx.sandbox.fs.read(path);
|
|
19
|
+
const lines = content.split('\n');
|
|
20
|
+
const startLine = offset ? offset - 1 : 0;
|
|
21
|
+
const endLine = limit ? startLine + limit : lines.length;
|
|
22
|
+
const selected = lines.slice(startLine, endLine);
|
|
23
|
+
await ctx.services?.filePool?.recordRead(path);
|
|
24
|
+
const truncated = endLine < lines.length;
|
|
25
|
+
const result = selected.join('\n');
|
|
26
|
+
return {
|
|
27
|
+
path,
|
|
28
|
+
offset: startLine + 1,
|
|
29
|
+
limit: selected.length,
|
|
30
|
+
truncated,
|
|
31
|
+
totalLines: lines.length,
|
|
32
|
+
content: result,
|
|
33
|
+
};
|
|
34
|
+
},
|
|
35
|
+
metadata: {
|
|
36
|
+
readonly: true,
|
|
37
|
+
version: '1.0',
|
|
38
|
+
},
|
|
39
|
+
});
|
|
40
|
+
exports.FsRead.prompt = prompt_1.PROMPT;
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.PROMPT = exports.DESCRIPTION = void 0;
|
|
4
|
+
exports.DESCRIPTION = 'Read contents from a file';
|
|
5
|
+
exports.PROMPT = `Use this tool to inspect files within the sandboxed workspace.
|
|
6
|
+
|
|
7
|
+
Usage guidance:
|
|
8
|
+
- Always pass paths relative to the sandbox working directory.
|
|
9
|
+
- You may optionally provide "offset" and "limit" to control the slice of lines to inspect.
|
|
10
|
+
- Large files will be truncated to keep responses compact; request additional ranges if needed.
|
|
11
|
+
- Prefer batching adjacent reads in a single turn to minimize context churn.
|
|
12
|
+
|
|
13
|
+
Safety/Limitations:
|
|
14
|
+
- This tool is read-only and integrates with FilePool for conflict detection.
|
|
15
|
+
- File modifications are tracked to warn about stale reads.
|
|
16
|
+
- Paths must stay inside the sandbox root directory.`;
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.FsWrite = void 0;
|
|
4
|
+
const tool_1 = require("../tool");
|
|
5
|
+
const zod_1 = require("zod");
|
|
6
|
+
const type_inference_1 = require("../type-inference");
|
|
7
|
+
const prompt_1 = require("./prompt");
|
|
8
|
+
exports.FsWrite = (0, tool_1.tool)({
|
|
9
|
+
name: 'fs_write',
|
|
10
|
+
description: prompt_1.DESCRIPTION,
|
|
11
|
+
parameters: zod_1.z.object({
|
|
12
|
+
path: type_inference_1.patterns.filePath('Path to file within the sandbox'),
|
|
13
|
+
content: zod_1.z.string().describe('Content to write'),
|
|
14
|
+
}),
|
|
15
|
+
async execute(args, ctx) {
|
|
16
|
+
const { path, content } = args;
|
|
17
|
+
const freshness = await ctx.services?.filePool?.validateWrite(path);
|
|
18
|
+
if (freshness && !freshness.isFresh) {
|
|
19
|
+
return {
|
|
20
|
+
ok: false,
|
|
21
|
+
error: 'File appears to have changed externally. Please read it again before writing.',
|
|
22
|
+
};
|
|
23
|
+
}
|
|
24
|
+
await ctx.sandbox.fs.write(path, content);
|
|
25
|
+
await ctx.services?.filePool?.recordEdit(path);
|
|
26
|
+
const bytes = Buffer.byteLength(content, 'utf8');
|
|
27
|
+
const lines = content.split('\n').length;
|
|
28
|
+
return {
|
|
29
|
+
ok: true,
|
|
30
|
+
path,
|
|
31
|
+
bytes,
|
|
32
|
+
lines,
|
|
33
|
+
};
|
|
34
|
+
},
|
|
35
|
+
metadata: {
|
|
36
|
+
readonly: false,
|
|
37
|
+
version: '1.0',
|
|
38
|
+
},
|
|
39
|
+
});
|
|
40
|
+
exports.FsWrite.prompt = prompt_1.PROMPT;
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.PROMPT = exports.DESCRIPTION = void 0;
|
|
4
|
+
exports.DESCRIPTION = 'Write contents to a file (creates or overwrites)';
|
|
5
|
+
exports.PROMPT = `Use this tool to create or overwrite files inside the sandbox.
|
|
6
|
+
|
|
7
|
+
Guidelines:
|
|
8
|
+
- Paths must stay inside the sandbox root. The SDK will deny attempts to escape the workspace.
|
|
9
|
+
- Provide the full target contents. The previous file body will be replaced.
|
|
10
|
+
- Pair with fs_read when editing existing files so the FilePool can validate freshness.
|
|
11
|
+
- The tool returns the number of bytes written for auditing purposes.
|
|
12
|
+
|
|
13
|
+
Safety/Limitations:
|
|
14
|
+
- File freshness validation ensures you don't overwrite externally modified files.
|
|
15
|
+
- Large file writes are allowed but may impact performance.`;
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
35
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
+
exports.createScriptsTool = exports.createSkillsTool = exports.builtin = exports.globalToolRegistry = exports.ToolRegistry = exports.disconnectAllMCP = exports.disconnectMCP = exports.getMCPTools = exports.extractTools = exports.defineTools = exports.defineTool = exports.tools = exports.tool = void 0;
|
|
37
|
+
// 统一的工具定义 API (v2.0 推荐)
|
|
38
|
+
var tool_1 = require("./tool");
|
|
39
|
+
Object.defineProperty(exports, "tool", { enumerable: true, get: function () { return tool_1.tool; } });
|
|
40
|
+
Object.defineProperty(exports, "tools", { enumerable: true, get: function () { return tool_1.tools; } });
|
|
41
|
+
// 简化的工具定义 API (保留兼容)
|
|
42
|
+
var define_1 = require("./define");
|
|
43
|
+
Object.defineProperty(exports, "defineTool", { enumerable: true, get: function () { return define_1.defineTool; } });
|
|
44
|
+
Object.defineProperty(exports, "defineTools", { enumerable: true, get: function () { return define_1.defineTools; } });
|
|
45
|
+
Object.defineProperty(exports, "extractTools", { enumerable: true, get: function () { return define_1.extractTools; } });
|
|
46
|
+
// MCP 集成
|
|
47
|
+
var mcp_1 = require("./mcp");
|
|
48
|
+
Object.defineProperty(exports, "getMCPTools", { enumerable: true, get: function () { return mcp_1.getMCPTools; } });
|
|
49
|
+
Object.defineProperty(exports, "disconnectMCP", { enumerable: true, get: function () { return mcp_1.disconnectMCP; } });
|
|
50
|
+
Object.defineProperty(exports, "disconnectAllMCP", { enumerable: true, get: function () { return mcp_1.disconnectAllMCP; } });
|
|
51
|
+
// 工具注册表
|
|
52
|
+
var registry_1 = require("./registry");
|
|
53
|
+
Object.defineProperty(exports, "ToolRegistry", { enumerable: true, get: function () { return registry_1.ToolRegistry; } });
|
|
54
|
+
Object.defineProperty(exports, "globalToolRegistry", { enumerable: true, get: function () { return registry_1.globalToolRegistry; } });
|
|
55
|
+
// 内置工具
|
|
56
|
+
exports.builtin = __importStar(require("./builtin"));
|
|
57
|
+
// Skills 工具
|
|
58
|
+
var skills_1 = require("./skills");
|
|
59
|
+
Object.defineProperty(exports, "createSkillsTool", { enumerable: true, get: function () { return skills_1.createSkillsTool; } });
|
|
60
|
+
var scripts_1 = require("./scripts");
|
|
61
|
+
Object.defineProperty(exports, "createScriptsTool", { enumerable: true, get: function () { return scripts_1.createScriptsTool; } });
|
|
@@ -0,0 +1,185 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.getMCPTools = getMCPTools;
|
|
4
|
+
exports.disconnectMCP = disconnectMCP;
|
|
5
|
+
exports.disconnectAllMCP = disconnectAllMCP;
|
|
6
|
+
const index_js_1 = require("@modelcontextprotocol/sdk/client/index.js");
|
|
7
|
+
const stdio_js_1 = require("@modelcontextprotocol/sdk/client/stdio.js");
|
|
8
|
+
const sse_js_1 = require("@modelcontextprotocol/sdk/client/sse.js");
|
|
9
|
+
const registry_1 = require("./registry");
|
|
10
|
+
/**
|
|
11
|
+
* MCP Client 管理器
|
|
12
|
+
*
|
|
13
|
+
* 维护 MCP 客户端连接,支持多种传输方式
|
|
14
|
+
*/
|
|
15
|
+
class MCPClientManager {
|
|
16
|
+
constructor() {
|
|
17
|
+
this.clients = new Map();
|
|
18
|
+
this.transports = new Map();
|
|
19
|
+
}
|
|
20
|
+
async connect(serverName, config) {
|
|
21
|
+
// 如果已连接,返回现有客户端
|
|
22
|
+
if (this.clients.has(serverName)) {
|
|
23
|
+
return this.clients.get(serverName);
|
|
24
|
+
}
|
|
25
|
+
// 创建 transport
|
|
26
|
+
let transport;
|
|
27
|
+
if (config.transport === 'stdio') {
|
|
28
|
+
if (!config.command) {
|
|
29
|
+
throw new Error('command is required for stdio transport');
|
|
30
|
+
}
|
|
31
|
+
transport = new stdio_js_1.StdioClientTransport({
|
|
32
|
+
command: config.command,
|
|
33
|
+
args: config.args || [],
|
|
34
|
+
env: config.env,
|
|
35
|
+
});
|
|
36
|
+
}
|
|
37
|
+
else if (config.transport === 'sse' || config.transport === 'http') {
|
|
38
|
+
if (!config.url) {
|
|
39
|
+
throw new Error('url is required for sse/http transport');
|
|
40
|
+
}
|
|
41
|
+
transport = new sse_js_1.SSEClientTransport(new URL(config.url));
|
|
42
|
+
}
|
|
43
|
+
else {
|
|
44
|
+
throw new Error(`Unsupported transport type: ${config.transport}`);
|
|
45
|
+
}
|
|
46
|
+
// 创建客户端
|
|
47
|
+
const client = new index_js_1.Client({
|
|
48
|
+
name: 'kode-sdk',
|
|
49
|
+
version: '2.0.0',
|
|
50
|
+
}, {
|
|
51
|
+
capabilities: {},
|
|
52
|
+
});
|
|
53
|
+
// 连接
|
|
54
|
+
await client.connect(transport);
|
|
55
|
+
// 缓存
|
|
56
|
+
this.clients.set(serverName, client);
|
|
57
|
+
this.transports.set(serverName, transport);
|
|
58
|
+
return client;
|
|
59
|
+
}
|
|
60
|
+
async disconnect(serverName) {
|
|
61
|
+
const client = this.clients.get(serverName);
|
|
62
|
+
if (client) {
|
|
63
|
+
await client.close();
|
|
64
|
+
this.clients.delete(serverName);
|
|
65
|
+
}
|
|
66
|
+
const transport = this.transports.get(serverName);
|
|
67
|
+
if (transport) {
|
|
68
|
+
await transport.close();
|
|
69
|
+
this.transports.delete(serverName);
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
async disconnectAll() {
|
|
73
|
+
const servers = Array.from(this.clients.keys());
|
|
74
|
+
await Promise.all(servers.map((name) => this.disconnect(name)));
|
|
75
|
+
}
|
|
76
|
+
getClient(serverName) {
|
|
77
|
+
return this.clients.get(serverName);
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
const mcpManager = new MCPClientManager();
|
|
81
|
+
/**
|
|
82
|
+
* 获取 MCP 工具
|
|
83
|
+
*
|
|
84
|
+
* 连接到 MCP 服务器并将其工具转换为 ToolInstance[]
|
|
85
|
+
*
|
|
86
|
+
* @example
|
|
87
|
+
* ```ts
|
|
88
|
+
* // Stdio transport
|
|
89
|
+
* const tools = await getMCPTools({
|
|
90
|
+
* transport: 'stdio',
|
|
91
|
+
* command: 'uvx',
|
|
92
|
+
* args: ['mcp-server-git'],
|
|
93
|
+
* serverName: 'git'
|
|
94
|
+
* });
|
|
95
|
+
*
|
|
96
|
+
* // HTTP/SSE transport
|
|
97
|
+
* const tools = await getMCPTools({
|
|
98
|
+
* transport: 'sse',
|
|
99
|
+
* url: 'http://localhost:3000/mcp',
|
|
100
|
+
* serverName: 'company',
|
|
101
|
+
* include: ['search', 'summarize']
|
|
102
|
+
* });
|
|
103
|
+
* ```
|
|
104
|
+
*/
|
|
105
|
+
async function getMCPTools(config) {
|
|
106
|
+
const serverName = config.serverName || 'default';
|
|
107
|
+
// 连接到 MCP 服务器
|
|
108
|
+
const client = await mcpManager.connect(serverName, config);
|
|
109
|
+
// 列出可用工具
|
|
110
|
+
const toolsResponse = await client.listTools();
|
|
111
|
+
const mcpTools = toolsResponse.tools;
|
|
112
|
+
// 过滤工具
|
|
113
|
+
let filtered = mcpTools;
|
|
114
|
+
if (config.include) {
|
|
115
|
+
filtered = filtered.filter((tool) => config.include.includes(tool.name));
|
|
116
|
+
}
|
|
117
|
+
if (config.exclude) {
|
|
118
|
+
filtered = filtered.filter((tool) => !config.exclude.includes(tool.name));
|
|
119
|
+
}
|
|
120
|
+
// 转换为 ToolInstance[]
|
|
121
|
+
const toolInstances = filtered.map((mcpTool) => {
|
|
122
|
+
// 生成命名空间化的工具名:mcp__serverName__toolName
|
|
123
|
+
const toolName = `mcp__${serverName}__${mcpTool.name}`;
|
|
124
|
+
const toolInstance = {
|
|
125
|
+
name: toolName,
|
|
126
|
+
description: mcpTool.description || `MCP tool: ${mcpTool.name}`,
|
|
127
|
+
input_schema: mcpTool.inputSchema,
|
|
128
|
+
async exec(args, _ctx) {
|
|
129
|
+
try {
|
|
130
|
+
// 调用 MCP 工具
|
|
131
|
+
const result = await client.callTool({
|
|
132
|
+
name: mcpTool.name,
|
|
133
|
+
arguments: args,
|
|
134
|
+
});
|
|
135
|
+
// 返回结果
|
|
136
|
+
return {
|
|
137
|
+
content: result.content,
|
|
138
|
+
isError: result.isError,
|
|
139
|
+
};
|
|
140
|
+
}
|
|
141
|
+
catch (error) {
|
|
142
|
+
throw new Error(`MCP tool execution failed: ${error}`);
|
|
143
|
+
}
|
|
144
|
+
},
|
|
145
|
+
toDescriptor() {
|
|
146
|
+
return {
|
|
147
|
+
source: 'mcp',
|
|
148
|
+
name: toolName,
|
|
149
|
+
registryId: toolName,
|
|
150
|
+
metadata: {
|
|
151
|
+
mcpServer: serverName,
|
|
152
|
+
mcpToolName: mcpTool.name,
|
|
153
|
+
transport: config.transport,
|
|
154
|
+
},
|
|
155
|
+
config: {
|
|
156
|
+
serverName,
|
|
157
|
+
transport: config.transport,
|
|
158
|
+
url: config.url,
|
|
159
|
+
command: config.command,
|
|
160
|
+
args: config.args,
|
|
161
|
+
},
|
|
162
|
+
};
|
|
163
|
+
},
|
|
164
|
+
};
|
|
165
|
+
// 自动注册到 global registry(支持 Resume)
|
|
166
|
+
registry_1.globalToolRegistry.register(toolName, (_registryConfig) => {
|
|
167
|
+
// Resume 时重建 MCP 连接
|
|
168
|
+
return toolInstance;
|
|
169
|
+
});
|
|
170
|
+
return toolInstance;
|
|
171
|
+
});
|
|
172
|
+
return toolInstances;
|
|
173
|
+
}
|
|
174
|
+
/**
|
|
175
|
+
* 断开 MCP 服务器连接
|
|
176
|
+
*/
|
|
177
|
+
async function disconnectMCP(serverName) {
|
|
178
|
+
await mcpManager.disconnect(serverName);
|
|
179
|
+
}
|
|
180
|
+
/**
|
|
181
|
+
* 断开所有 MCP 服务器连接
|
|
182
|
+
*/
|
|
183
|
+
async function disconnectAllMCP() {
|
|
184
|
+
await mcpManager.disconnectAll();
|
|
185
|
+
}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.globalToolRegistry = exports.ToolRegistry = void 0;
|
|
4
|
+
class ToolRegistry {
|
|
5
|
+
constructor() {
|
|
6
|
+
this.factories = new Map();
|
|
7
|
+
}
|
|
8
|
+
register(id, factory) {
|
|
9
|
+
this.factories.set(id, factory);
|
|
10
|
+
}
|
|
11
|
+
has(id) {
|
|
12
|
+
return this.factories.has(id);
|
|
13
|
+
}
|
|
14
|
+
create(id, config) {
|
|
15
|
+
const factory = this.factories.get(id);
|
|
16
|
+
if (!factory) {
|
|
17
|
+
throw new Error(`Tool not registered: ${id}`);
|
|
18
|
+
}
|
|
19
|
+
return factory(config);
|
|
20
|
+
}
|
|
21
|
+
list() {
|
|
22
|
+
return Array.from(this.factories.keys());
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
exports.ToolRegistry = ToolRegistry;
|
|
26
|
+
exports.globalToolRegistry = new ToolRegistry();
|