@next-open-ai/openclawx 0.6.6

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.
Files changed (198) hide show
  1. package/README.md +523 -0
  2. package/apps/desktop/README.md +210 -0
  3. package/apps/desktop/renderer/dist/assets/index-CYkSfhcp.css +10 -0
  4. package/apps/desktop/renderer/dist/assets/index-FI6O25Ms.js +89 -0
  5. package/apps/desktop/renderer/dist/index.html +22 -0
  6. package/dist/cli/cli.d.ts +2 -0
  7. package/dist/cli/cli.js +198 -0
  8. package/dist/cli/service.d.ts +13 -0
  9. package/dist/cli/service.js +243 -0
  10. package/dist/cli.d.ts +5 -0
  11. package/dist/cli.js +5 -0
  12. package/dist/core/agent/agent-dir.d.ts +14 -0
  13. package/dist/core/agent/agent-dir.js +75 -0
  14. package/dist/core/agent/agent-manager.d.ts +64 -0
  15. package/dist/core/agent/agent-manager.js +278 -0
  16. package/dist/core/agent/config-manager.d.ts +25 -0
  17. package/dist/core/agent/config-manager.js +84 -0
  18. package/dist/core/agent/run.d.ts +26 -0
  19. package/dist/core/agent/run.js +65 -0
  20. package/dist/core/agent/skills.d.ts +20 -0
  21. package/dist/core/agent/skills.js +86 -0
  22. package/dist/core/config/desktop-config.d.ts +90 -0
  23. package/dist/core/config/desktop-config.js +521 -0
  24. package/dist/core/config/provider-support-default.d.ts +21 -0
  25. package/dist/core/config/provider-support-default.js +57 -0
  26. package/dist/core/installer/index.d.ts +1 -0
  27. package/dist/core/installer/index.js +1 -0
  28. package/dist/core/installer/skill-installer.d.ts +39 -0
  29. package/dist/core/installer/skill-installer.js +215 -0
  30. package/dist/core/mcp/adapter.d.ts +17 -0
  31. package/dist/core/mcp/adapter.js +49 -0
  32. package/dist/core/mcp/client.d.ts +24 -0
  33. package/dist/core/mcp/client.js +70 -0
  34. package/dist/core/mcp/config.d.ts +22 -0
  35. package/dist/core/mcp/config.js +69 -0
  36. package/dist/core/mcp/index.d.ts +18 -0
  37. package/dist/core/mcp/index.js +20 -0
  38. package/dist/core/mcp/operator.d.ts +15 -0
  39. package/dist/core/mcp/operator.js +72 -0
  40. package/dist/core/mcp/transport/index.d.ts +11 -0
  41. package/dist/core/mcp/transport/index.js +16 -0
  42. package/dist/core/mcp/transport/sse.d.ts +20 -0
  43. package/dist/core/mcp/transport/sse.js +82 -0
  44. package/dist/core/mcp/transport/stdio.d.ts +32 -0
  45. package/dist/core/mcp/transport/stdio.js +132 -0
  46. package/dist/core/mcp/types.d.ts +72 -0
  47. package/dist/core/mcp/types.js +5 -0
  48. package/dist/core/memory/build-summary.d.ts +6 -0
  49. package/dist/core/memory/build-summary.js +27 -0
  50. package/dist/core/memory/compaction-extension.d.ts +6 -0
  51. package/dist/core/memory/compaction-extension.js +23 -0
  52. package/dist/core/memory/embedding.d.ts +4 -0
  53. package/dist/core/memory/embedding.js +15 -0
  54. package/dist/core/memory/index.d.ts +29 -0
  55. package/dist/core/memory/index.js +70 -0
  56. package/dist/core/memory/remote-embedding.d.ts +10 -0
  57. package/dist/core/memory/remote-embedding.js +36 -0
  58. package/dist/core/memory/types.d.ts +16 -0
  59. package/dist/core/memory/types.js +1 -0
  60. package/dist/core/memory/vector-store.d.ts +15 -0
  61. package/dist/core/memory/vector-store.js +65 -0
  62. package/dist/core/tools/bookmark-tool.d.ts +9 -0
  63. package/dist/core/tools/bookmark-tool.js +118 -0
  64. package/dist/core/tools/browser-tool.d.ts +10 -0
  65. package/dist/core/tools/browser-tool.js +362 -0
  66. package/dist/core/tools/index.d.ts +4 -0
  67. package/dist/core/tools/index.js +4 -0
  68. package/dist/core/tools/install-skill-tool.d.ts +6 -0
  69. package/dist/core/tools/install-skill-tool.js +53 -0
  70. package/dist/core/tools/save-experience-tool.d.ts +5 -0
  71. package/dist/core/tools/save-experience-tool.js +54 -0
  72. package/dist/gateway/auth-hooks.d.ts +17 -0
  73. package/dist/gateway/auth-hooks.js +19 -0
  74. package/dist/gateway/backend-url.d.ts +2 -0
  75. package/dist/gateway/backend-url.js +11 -0
  76. package/dist/gateway/channel-handler.d.ts +6 -0
  77. package/dist/gateway/channel-handler.js +3 -0
  78. package/dist/gateway/clients.d.ts +5 -0
  79. package/dist/gateway/clients.js +4 -0
  80. package/dist/gateway/connection-handler.d.ts +6 -0
  81. package/dist/gateway/connection-handler.js +48 -0
  82. package/dist/gateway/index.d.ts +3 -0
  83. package/dist/gateway/index.js +2 -0
  84. package/dist/gateway/message-handler.d.ts +5 -0
  85. package/dist/gateway/message-handler.js +65 -0
  86. package/dist/gateway/methods/agent-cancel.d.ts +10 -0
  87. package/dist/gateway/methods/agent-cancel.js +17 -0
  88. package/dist/gateway/methods/agent-chat.d.ts +8 -0
  89. package/dist/gateway/methods/agent-chat.js +148 -0
  90. package/dist/gateway/methods/connect.d.ts +9 -0
  91. package/dist/gateway/methods/connect.js +18 -0
  92. package/dist/gateway/methods/install-skill-from-path.d.ts +13 -0
  93. package/dist/gateway/methods/install-skill-from-path.js +15 -0
  94. package/dist/gateway/methods/install-skill-from-upload.d.ts +14 -0
  95. package/dist/gateway/methods/install-skill-from-upload.js +13 -0
  96. package/dist/gateway/methods/run-scheduled-task.d.ts +15 -0
  97. package/dist/gateway/methods/run-scheduled-task.js +127 -0
  98. package/dist/gateway/paths.d.ts +20 -0
  99. package/dist/gateway/paths.js +19 -0
  100. package/dist/gateway/server.d.ts +8 -0
  101. package/dist/gateway/server.js +190 -0
  102. package/dist/gateway/sse-handler.d.ts +6 -0
  103. package/dist/gateway/sse-handler.js +3 -0
  104. package/dist/gateway/types.d.ts +90 -0
  105. package/dist/gateway/types.js +1 -0
  106. package/dist/gateway/utils.d.ts +22 -0
  107. package/dist/gateway/utils.js +67 -0
  108. package/dist/gateway/voice-handler.d.ts +12 -0
  109. package/dist/gateway/voice-handler.js +18 -0
  110. package/dist/index.d.ts +5 -0
  111. package/dist/index.js +5 -0
  112. package/dist/server/agent-config/agent-config.controller.d.ts +30 -0
  113. package/dist/server/agent-config/agent-config.controller.js +83 -0
  114. package/dist/server/agent-config/agent-config.module.d.ts +2 -0
  115. package/dist/server/agent-config/agent-config.module.js +19 -0
  116. package/dist/server/agent-config/agent-config.service.d.ts +53 -0
  117. package/dist/server/agent-config/agent-config.service.js +213 -0
  118. package/dist/server/agents/agents.controller.d.ts +41 -0
  119. package/dist/server/agents/agents.controller.js +118 -0
  120. package/dist/server/agents/agents.gateway.d.ts +21 -0
  121. package/dist/server/agents/agents.gateway.js +103 -0
  122. package/dist/server/agents/agents.module.d.ts +2 -0
  123. package/dist/server/agents/agents.module.js +20 -0
  124. package/dist/server/agents/agents.service.d.ts +63 -0
  125. package/dist/server/agents/agents.service.js +169 -0
  126. package/dist/server/app.module.d.ts +2 -0
  127. package/dist/server/app.module.js +38 -0
  128. package/dist/server/auth/auth.controller.d.ts +20 -0
  129. package/dist/server/auth/auth.controller.js +64 -0
  130. package/dist/server/auth/auth.module.d.ts +2 -0
  131. package/dist/server/auth/auth.module.js +19 -0
  132. package/dist/server/bootstrap.d.ts +15 -0
  133. package/dist/server/bootstrap.js +38 -0
  134. package/dist/server/config/config.controller.d.ts +73 -0
  135. package/dist/server/config/config.controller.js +95 -0
  136. package/dist/server/config/config.module.d.ts +2 -0
  137. package/dist/server/config/config.module.js +21 -0
  138. package/dist/server/config/config.service.d.ts +82 -0
  139. package/dist/server/config/config.service.js +123 -0
  140. package/dist/server/database/database.module.d.ts +2 -0
  141. package/dist/server/database/database.module.js +18 -0
  142. package/dist/server/database/database.service.d.ts +26 -0
  143. package/dist/server/database/database.service.js +253 -0
  144. package/dist/server/main.d.ts +1 -0
  145. package/dist/server/main.js +9 -0
  146. package/dist/server/saved-items/saved-items.controller.d.ts +57 -0
  147. package/dist/server/saved-items/saved-items.controller.js +229 -0
  148. package/dist/server/saved-items/saved-items.module.d.ts +2 -0
  149. package/dist/server/saved-items/saved-items.module.js +25 -0
  150. package/dist/server/saved-items/saved-items.service.d.ts +31 -0
  151. package/dist/server/saved-items/saved-items.service.js +105 -0
  152. package/dist/server/saved-items/tags.controller.d.ts +30 -0
  153. package/dist/server/saved-items/tags.controller.js +85 -0
  154. package/dist/server/saved-items/tags.service.d.ts +24 -0
  155. package/dist/server/saved-items/tags.service.js +84 -0
  156. package/dist/server/skills/skills.controller.d.ts +63 -0
  157. package/dist/server/skills/skills.controller.js +194 -0
  158. package/dist/server/skills/skills.module.d.ts +2 -0
  159. package/dist/server/skills/skills.module.js +22 -0
  160. package/dist/server/skills/skills.service.d.ts +65 -0
  161. package/dist/server/skills/skills.service.js +388 -0
  162. package/dist/server/tasks/tasks.controller.d.ts +52 -0
  163. package/dist/server/tasks/tasks.controller.js +163 -0
  164. package/dist/server/tasks/tasks.module.d.ts +2 -0
  165. package/dist/server/tasks/tasks.module.js +23 -0
  166. package/dist/server/tasks/tasks.service.d.ts +86 -0
  167. package/dist/server/tasks/tasks.service.js +327 -0
  168. package/dist/server/usage/usage.controller.d.ts +12 -0
  169. package/dist/server/usage/usage.controller.js +46 -0
  170. package/dist/server/usage/usage.module.d.ts +2 -0
  171. package/dist/server/usage/usage.module.js +19 -0
  172. package/dist/server/usage/usage.service.d.ts +21 -0
  173. package/dist/server/usage/usage.service.js +55 -0
  174. package/dist/server/users/users.controller.d.ts +35 -0
  175. package/dist/server/users/users.controller.js +69 -0
  176. package/dist/server/users/users.module.d.ts +2 -0
  177. package/dist/server/users/users.module.js +19 -0
  178. package/dist/server/users/users.service.d.ts +39 -0
  179. package/dist/server/users/users.service.js +140 -0
  180. package/dist/server/workspace/workspace.controller.d.ts +24 -0
  181. package/dist/server/workspace/workspace.controller.js +132 -0
  182. package/dist/server/workspace/workspace.module.d.ts +2 -0
  183. package/dist/server/workspace/workspace.module.js +21 -0
  184. package/dist/server/workspace/workspace.service.d.ts +36 -0
  185. package/dist/server/workspace/workspace.service.js +142 -0
  186. package/package.json +90 -0
  187. package/skills/agent-browser/SKILL.md +207 -0
  188. package/skills/agent-browser/references/authentication.md +202 -0
  189. package/skills/agent-browser/references/commands.md +259 -0
  190. package/skills/agent-browser/references/proxy-support.md +188 -0
  191. package/skills/agent-browser/references/session-management.md +193 -0
  192. package/skills/agent-browser/references/snapshot-refs.md +194 -0
  193. package/skills/agent-browser/references/video-recording.md +173 -0
  194. package/skills/agent-browser/templates/authenticated-session.sh +97 -0
  195. package/skills/agent-browser/templates/capture-workflow.sh +69 -0
  196. package/skills/agent-browser/templates/form-automation.sh +62 -0
  197. package/skills/find-skills/SKILL.md +140 -0
  198. package/skills/url-bookmark/SKILL.md +36 -0
@@ -0,0 +1,215 @@
1
+ /**
2
+ * 核心安装模块:按 URL 或按路径安装技能到全局或工作区,不依赖 Nest。
3
+ * 供 install_skill 工具、Gateway、CLI 等统一使用。
4
+ */
5
+ import { readFile, readdir, stat, mkdir, rm, cp, realpath } from "fs/promises";
6
+ import { existsSync } from "fs";
7
+ import { join, resolve, basename } from "path";
8
+ import { tmpdir } from "os";
9
+ import { randomUUID } from "crypto";
10
+ import AdmZip from "adm-zip";
11
+ import { exec } from "child_process";
12
+ import { promisify } from "util";
13
+ import { homedir } from "os";
14
+ import { getOpenbotAgentDir, getOpenbotWorkspaceDir } from "../agent/agent-dir.js";
15
+ const execAsync = promisify(exec);
16
+ function getDesktopDir() {
17
+ const home = process.env.HOME || process.env.USERPROFILE || homedir();
18
+ return join(home, ".openbot", "desktop");
19
+ }
20
+ /** 解析 targetAgentId 得到安装目标:global 或 workspace + 工作区名 */
21
+ export async function resolveInstallTarget(targetAgentId) {
22
+ const tid = (targetAgentId ?? "").trim().toLowerCase();
23
+ if (tid === "global" || tid === "all") {
24
+ return { scope: "global", workspace: "default" };
25
+ }
26
+ if (!tid) {
27
+ return { scope: "workspace", workspace: "default" };
28
+ }
29
+ const agentsPath = join(getDesktopDir(), "agents.json");
30
+ if (!existsSync(agentsPath)) {
31
+ return { scope: "workspace", workspace: tid };
32
+ }
33
+ try {
34
+ const raw = await readFile(agentsPath, "utf-8");
35
+ const data = JSON.parse(raw);
36
+ const agents = Array.isArray(data.agents) ? data.agents : [];
37
+ const agent = agents.find((a) => a.id === tid);
38
+ const workspace = agent?.workspace?.trim() || tid;
39
+ return { scope: "workspace", workspace };
40
+ }
41
+ catch {
42
+ return { scope: "workspace", workspace: tid };
43
+ }
44
+ }
45
+ function getGlobalSkillsDir() {
46
+ return join(getOpenbotAgentDir(), "skills");
47
+ }
48
+ function getWorkspaceSkillsDir(workspaceName) {
49
+ return join(getOpenbotWorkspaceDir(), workspaceName, "skills");
50
+ }
51
+ /**
52
+ * 通过 npx skills add 安装技能到指定目录(与 Nest SkillsService 逻辑一致)。
53
+ */
54
+ export async function installSkillByUrl(url, options = { scope: "global", workspace: "default" }) {
55
+ const scope = options.scope ?? "global";
56
+ const workspaceName = options.workspace ?? "default";
57
+ const targetDir = scope === "workspace"
58
+ ? getWorkspaceSkillsDir(workspaceName)
59
+ : getGlobalSkillsDir();
60
+ const tempDir = join(tmpdir(), `openbot-skills-${randomUUID()}`);
61
+ const tempAgentsSkills = join(tempDir, ".agents", "skills");
62
+ const tempPiSkills = join(tempDir, ".pi", "skills");
63
+ let stdout = "";
64
+ let stderr = "";
65
+ try {
66
+ await mkdir(tempPiSkills, { recursive: true });
67
+ const { stdout: out, stderr: err } = await execAsync(`npx skills add "${url.trim()}" -a pi -y`, { cwd: tempDir, maxBuffer: 4 * 1024 * 1024 });
68
+ stdout = out || "";
69
+ stderr = err || "";
70
+ await mkdir(targetDir, { recursive: true });
71
+ const sourceDir = existsSync(tempAgentsSkills) ? tempAgentsSkills : tempPiSkills;
72
+ const entries = await readdir(sourceDir).catch(() => []);
73
+ for (const entry of entries) {
74
+ const src = join(sourceDir, entry);
75
+ const entryStat = await stat(src).catch(() => null);
76
+ if (!entryStat?.isDirectory())
77
+ continue;
78
+ const dest = join(targetDir, entry);
79
+ const srcResolved = await realpath(src).catch(() => src);
80
+ await cp(srcResolved, dest, { recursive: true });
81
+ }
82
+ }
83
+ finally {
84
+ await rm(tempDir, { recursive: true, force: true }).catch(() => { });
85
+ }
86
+ return { stdout, stderr, installDir: targetDir };
87
+ }
88
+ const SKILL_NAME_REGEX = /^[a-zA-Z0-9_-]+$/;
89
+ /**
90
+ * 从本地目录安装技能:将指定目录复制到目标 skills 目录。
91
+ */
92
+ export async function installSkillFromPath(localPath, options = { scope: "global", workspace: "default" }) {
93
+ const pathToUse = resolve(localPath.trim());
94
+ if (!existsSync(pathToUse)) {
95
+ throw new Error("本地路径不存在");
96
+ }
97
+ const pathStat = await stat(pathToUse);
98
+ if (!pathStat.isDirectory()) {
99
+ throw new Error("请选择技能目录");
100
+ }
101
+ const skillMdPath = join(pathToUse, "SKILL.md");
102
+ if (!existsSync(skillMdPath)) {
103
+ throw new Error("该目录下未找到 SKILL.md,不是有效的技能目录");
104
+ }
105
+ const scope = options.scope ?? "global";
106
+ const workspaceName = options.workspace ?? "default";
107
+ const targetDir = scope === "workspace"
108
+ ? getWorkspaceSkillsDir(workspaceName)
109
+ : getGlobalSkillsDir();
110
+ const baseName = basename(pathToUse) || "skill";
111
+ if (!baseName || !SKILL_NAME_REGEX.test(baseName)) {
112
+ throw new Error("技能目录名须为英文、数字、下划线或连字符");
113
+ }
114
+ const destPath = join(targetDir, baseName);
115
+ await mkdir(targetDir, { recursive: true });
116
+ if (existsSync(destPath)) {
117
+ await rm(destPath, { recursive: true });
118
+ }
119
+ const srcResolved = await realpath(pathToUse).catch(() => pathToUse);
120
+ await cp(srcResolved, destPath, { recursive: true });
121
+ return { installDir: targetDir, name: baseName };
122
+ }
123
+ /** 上传 zip 包最大体积(字节) */
124
+ const MAX_UPLOAD_ZIP_BYTES = 10 * 1024 * 1024;
125
+ /** 解压后忽略的条目(系统/打包产生的噪音) */
126
+ const IGNORED_ZIP_ENTRIES = new Set(["__MACOSX", ".DS_Store", ".git", "Thumbs.db"]);
127
+ function isIgnoredZipEntry(name) {
128
+ if (!name || name.includes(".."))
129
+ return true;
130
+ if (IGNORED_ZIP_ENTRIES.has(name))
131
+ return true;
132
+ if (name.startsWith("."))
133
+ return true;
134
+ return false;
135
+ }
136
+ /**
137
+ * 从上传的 zip 安装技能:解压到临时目录,校验为单个技能目录(含 SKILL.md),再复制到目标。
138
+ * 支持两种 zip 结构:① 单个顶层目录且内含 SKILL.md;② 根目录直接含 SKILL.md(将视为技能根目录)。
139
+ */
140
+ export async function installSkillFromUpload(zipBuffer, options = { scope: "global", workspace: "default" }) {
141
+ if (zipBuffer.length > MAX_UPLOAD_ZIP_BYTES) {
142
+ throw new Error("zip 包不能超过 10MB");
143
+ }
144
+ const tempDir = join(tmpdir(), `openbot-upload-${randomUUID()}`);
145
+ try {
146
+ await mkdir(tempDir, { recursive: true });
147
+ const zip = new AdmZip(zipBuffer);
148
+ zip.extractAllTo(tempDir, true);
149
+ const allEntries = await readdir(tempDir);
150
+ const entries = allEntries.filter((e) => !isIgnoredZipEntry(e));
151
+ let skillPath;
152
+ if (entries.length === 0) {
153
+ throw new Error("zip 解压后未得到有效内容,请检查 zip 是否包含技能目录或 SKILL.md");
154
+ }
155
+ if (entries.length === 1) {
156
+ const singleName = entries[0];
157
+ const candidatePath = join(tempDir, singleName);
158
+ const statEntry = await stat(candidatePath);
159
+ if (statEntry.isDirectory()) {
160
+ const skillMdInDir = join(candidatePath, "SKILL.md");
161
+ if (existsSync(skillMdInDir)) {
162
+ skillPath = candidatePath;
163
+ }
164
+ else {
165
+ throw new Error("该目录下未找到 SKILL.md,请确保 zip 内技能目录根目录含有 SKILL.md 文件");
166
+ }
167
+ }
168
+ else {
169
+ if (existsSync(join(tempDir, "SKILL.md"))) {
170
+ throw new Error("zip 根目录含有 SKILL.md,但根目录下还有其它文件,请将整个技能放在一个子目录内再打包");
171
+ }
172
+ throw new Error("zip 内未找到包含 SKILL.md 的技能目录,请检查打包方式");
173
+ }
174
+ }
175
+ else {
176
+ const skillMdAtRoot = existsSync(join(tempDir, "SKILL.md"));
177
+ const dirsWithSkillMd = [];
178
+ for (const e of entries) {
179
+ const p = join(tempDir, e);
180
+ const st = await stat(p).catch(() => null);
181
+ if (st?.isDirectory() && existsSync(join(p, "SKILL.md")))
182
+ dirsWithSkillMd.push(p);
183
+ }
184
+ if (dirsWithSkillMd.length === 1) {
185
+ skillPath = dirsWithSkillMd[0];
186
+ }
187
+ else if (dirsWithSkillMd.length > 1) {
188
+ throw new Error("zip 内包含多个技能目录,请只保留一个技能目录再打包");
189
+ }
190
+ else if (skillMdAtRoot) {
191
+ skillPath = tempDir;
192
+ }
193
+ else {
194
+ throw new Error("zip 内未找到包含 SKILL.md 的技能目录;若为多文件打包,请将 SKILL.md 放在 zip 根目录或单个子目录内");
195
+ }
196
+ }
197
+ if (skillPath === tempDir) {
198
+ const baseName = "skill";
199
+ const wrappedDir = join(tmpdir(), `openbot-skill-wrap-${randomUUID()}`);
200
+ try {
201
+ await mkdir(wrappedDir, { recursive: true });
202
+ const destPath = join(wrappedDir, baseName);
203
+ await cp(tempDir, destPath, { recursive: true });
204
+ return await installSkillFromPath(destPath, options);
205
+ }
206
+ finally {
207
+ await rm(wrappedDir, { recursive: true, force: true }).catch(() => { });
208
+ }
209
+ }
210
+ return await installSkillFromPath(skillPath, options);
211
+ }
212
+ finally {
213
+ await rm(tempDir, { recursive: true, force: true }).catch(() => { });
214
+ }
215
+ }
@@ -0,0 +1,17 @@
1
+ /**
2
+ * MCP Tool 转为 pi-coding-agent ToolDefinition 的适配层。
3
+ */
4
+ import type { ToolDefinition } from "@mariozechner/pi-coding-agent";
5
+ import type { McpTool } from "./types.js";
6
+ import type { McpClient } from "./client.js";
7
+ /**
8
+ * 将单个 MCP 工具封装为 pi-coding-agent 的 ToolDefinition。
9
+ * @param tool MCP tools/list 返回的项
10
+ * @param client 已连接的 McpClient,用于 callTool
11
+ * @param serverId 可选前缀,用于避免多 MCP 时工具名冲突
12
+ */
13
+ export declare function mcpToolToToolDefinition(tool: McpTool, client: McpClient, serverId?: string): ToolDefinition;
14
+ /**
15
+ * 将某 MCP 客户端的全部工具转为 ToolDefinition 数组。
16
+ */
17
+ export declare function mcpToolsToToolDefinitions(tools: McpTool[], client: McpClient, serverId?: string): ToolDefinition[];
@@ -0,0 +1,49 @@
1
+ /**
2
+ * MCP Tool 转为 pi-coding-agent ToolDefinition 的适配层。
3
+ */
4
+ import { Type } from "@sinclair/typebox";
5
+ /** 通用参数:MCP 工具接受任意 JSON 对象作为 arguments */
6
+ const McpToolParamsSchema = Type.Record(Type.String(), Type.Any());
7
+ /**
8
+ * 将单个 MCP 工具封装为 pi-coding-agent 的 ToolDefinition。
9
+ * @param tool MCP tools/list 返回的项
10
+ * @param client 已连接的 McpClient,用于 callTool
11
+ * @param serverId 可选前缀,用于避免多 MCP 时工具名冲突
12
+ */
13
+ export function mcpToolToToolDefinition(tool, client, serverId) {
14
+ const name = serverId ? `${serverId}_${tool.name}` : tool.name;
15
+ const description = (tool.description ?? "").trim() || `MCP tool: ${tool.name}`;
16
+ return {
17
+ name,
18
+ label: tool.name,
19
+ description,
20
+ parameters: McpToolParamsSchema,
21
+ execute: async (_toolCallId, params, _signal, _onUpdate, _ctx) => {
22
+ const args = params && typeof params === "object" ? params : {};
23
+ try {
24
+ const result = await client.callTool(tool.name, args);
25
+ const text = result.content
26
+ ?.filter((c) => c.type === "text")
27
+ .map((c) => c.text)
28
+ .join("\n") ?? (result.isError ? "MCP 调用返回错误" : "");
29
+ return {
30
+ content: [{ type: "text", text }],
31
+ details: result.isError ? { isError: true } : undefined,
32
+ };
33
+ }
34
+ catch (err) {
35
+ const msg = err instanceof Error ? err.message : String(err);
36
+ return {
37
+ content: [{ type: "text", text: `MCP 调用失败: ${msg}` }],
38
+ details: undefined,
39
+ };
40
+ }
41
+ },
42
+ };
43
+ }
44
+ /**
45
+ * 将某 MCP 客户端的全部工具转为 ToolDefinition 数组。
46
+ */
47
+ export function mcpToolsToToolDefinitions(tools, client, serverId) {
48
+ return tools.map((t) => mcpToolToToolDefinition(t, client, serverId));
49
+ }
@@ -0,0 +1,24 @@
1
+ /**
2
+ * MCP 客户端:连接、list_tools、call_tool、断开。
3
+ * 支持 stdio(本地进程)与 sse(远程 HTTP)两种传输。
4
+ */
5
+ import type { McpTool, McpToolCallResult, IMcpTransport } from "./types.js";
6
+ import type { McpServerConfig } from "./types.js";
7
+ export interface McpClientOptions {
8
+ initTimeoutMs?: number;
9
+ requestTimeoutMs?: number;
10
+ }
11
+ export declare class McpClient {
12
+ private transport;
13
+ private _tools;
14
+ private _requestId;
15
+ constructor(configOrTransport: McpServerConfig | IMcpTransport, options?: McpClientOptions);
16
+ /** 建立连接并完成握手;成功后可使用 listTools / callTool */
17
+ connect(): Promise<void>;
18
+ /** 获取工具列表(会缓存;断开重连后需重新 list) */
19
+ listTools(): Promise<McpTool[]>;
20
+ /** 调用指定工具 */
21
+ callTool(name: string, args: Record<string, unknown>): Promise<McpToolCallResult>;
22
+ close(): Promise<void>;
23
+ get isConnected(): boolean;
24
+ }
@@ -0,0 +1,70 @@
1
+ /**
2
+ * MCP 客户端:连接、list_tools、call_tool、断开。
3
+ * 支持 stdio(本地进程)与 sse(远程 HTTP)两种传输。
4
+ */
5
+ import { createTransport } from "./transport/index.js";
6
+ export class McpClient {
7
+ transport;
8
+ _tools = null;
9
+ _requestId = 0;
10
+ constructor(configOrTransport, options = {}) {
11
+ if (typeof configOrTransport.request === "function" &&
12
+ typeof configOrTransport.start === "function") {
13
+ this.transport = configOrTransport;
14
+ }
15
+ else {
16
+ this.transport = createTransport(configOrTransport, {
17
+ initTimeoutMs: options.initTimeoutMs,
18
+ requestTimeoutMs: options.requestTimeoutMs,
19
+ });
20
+ }
21
+ }
22
+ /** 建立连接并完成握手;成功后可使用 listTools / callTool */
23
+ async connect() {
24
+ await this.transport.start();
25
+ }
26
+ /** 获取工具列表(会缓存;断开重连后需重新 list) */
27
+ async listTools() {
28
+ if (this._tools !== null) {
29
+ return this._tools;
30
+ }
31
+ const res = await this.transport.request({
32
+ jsonrpc: "2.0",
33
+ id: ++this._requestId,
34
+ method: "tools/list",
35
+ });
36
+ if (res.error) {
37
+ throw new Error(`MCP tools/list failed: ${res.error.message}`);
38
+ }
39
+ const list = res.result?.tools;
40
+ this._tools = Array.isArray(list) ? list : [];
41
+ return this._tools;
42
+ }
43
+ /** 调用指定工具 */
44
+ async callTool(name, args) {
45
+ const res = await this.transport.request({
46
+ jsonrpc: "2.0",
47
+ id: ++this._requestId,
48
+ method: "tools/call",
49
+ params: { name, arguments: args ?? {} },
50
+ });
51
+ if (res.error) {
52
+ return {
53
+ content: [{ type: "text", text: `MCP call_tool error: ${res.error.message}` }],
54
+ isError: true,
55
+ };
56
+ }
57
+ const result = res.result;
58
+ if (!result || !Array.isArray(result.content)) {
59
+ return { content: [{ type: "text", text: "Invalid MCP tools/call result" }], isError: true };
60
+ }
61
+ return result;
62
+ }
63
+ async close() {
64
+ this._tools = null;
65
+ await this.transport.close();
66
+ }
67
+ get isConnected() {
68
+ return this.transport.isConnected;
69
+ }
70
+ }
@@ -0,0 +1,22 @@
1
+ /**
2
+ * MCP 配置解析与校验。
3
+ * 从 getOrCreateSession 的 options.mcpServers 中取出并规范化,支持 stdio 与 sse。
4
+ */
5
+ import type { McpServerConfig, McpServerConfigStdio, McpServerConfigSse } from "./types.js";
6
+ /**
7
+ * 从会话选项里解析出本会话启用的 MCP 服务器配置列表。
8
+ * 支持 stdio(本地进程)与 sse(远程 HTTP)。
9
+ */
10
+ export declare function resolveMcpServersForSession(mcpServers: McpServerConfig[] | undefined): McpServerConfig[];
11
+ /**
12
+ * 为 stdio 配置生成缓存键(用于 Operator 复用同一进程连接)
13
+ */
14
+ export declare function stdioConfigKey(config: McpServerConfigStdio): string;
15
+ /**
16
+ * 为 sse 配置生成缓存键
17
+ */
18
+ export declare function sseConfigKey(config: McpServerConfigSse): string;
19
+ /**
20
+ * 任意 MCP 配置的缓存键
21
+ */
22
+ export declare function mcpConfigKey(config: McpServerConfig): string;
@@ -0,0 +1,69 @@
1
+ /**
2
+ * MCP 配置解析与校验。
3
+ * 从 getOrCreateSession 的 options.mcpServers 中取出并规范化,支持 stdio 与 sse。
4
+ */
5
+ /**
6
+ * 从会话选项里解析出本会话启用的 MCP 服务器配置列表。
7
+ * 支持 stdio(本地进程)与 sse(远程 HTTP)。
8
+ */
9
+ export function resolveMcpServersForSession(mcpServers) {
10
+ if (!Array.isArray(mcpServers) || mcpServers.length === 0) {
11
+ return [];
12
+ }
13
+ const result = [];
14
+ for (const s of mcpServers) {
15
+ if (!s || typeof s !== "object")
16
+ continue;
17
+ if (s.transport === "stdio") {
18
+ if (typeof s.command !== "string" || !s.command.trim()) {
19
+ console.warn("[mcp] 跳过无效 stdio 配置:缺少或无效 command");
20
+ continue;
21
+ }
22
+ result.push({
23
+ transport: "stdio",
24
+ command: s.command.trim(),
25
+ args: Array.isArray(s.args) ? s.args : undefined,
26
+ env: s.env && typeof s.env === "object" ? s.env : undefined,
27
+ });
28
+ }
29
+ else if (s.transport === "sse") {
30
+ const url = s.url?.trim();
31
+ if (!url) {
32
+ console.warn("[mcp] 跳过无效 sse 配置:缺少或无效 url");
33
+ continue;
34
+ }
35
+ result.push({
36
+ transport: "sse",
37
+ url,
38
+ headers: s.headers && typeof s.headers === "object" ? s.headers : undefined,
39
+ });
40
+ }
41
+ else {
42
+ console.warn("[mcp] 未知 transport:", s.transport);
43
+ }
44
+ }
45
+ return result;
46
+ }
47
+ /**
48
+ * 为 stdio 配置生成缓存键(用于 Operator 复用同一进程连接)
49
+ */
50
+ export function stdioConfigKey(config) {
51
+ const args = (config.args ?? []).join(" ");
52
+ const envStr = config.env ? JSON.stringify(config.env) : "";
53
+ return `stdio:${config.command}\0${args}\0${envStr}`;
54
+ }
55
+ /**
56
+ * 为 sse 配置生成缓存键
57
+ */
58
+ export function sseConfigKey(config) {
59
+ const headersStr = config.headers ? JSON.stringify(config.headers) : "";
60
+ return `sse:${config.url}\0${headersStr}`;
61
+ }
62
+ /**
63
+ * 任意 MCP 配置的缓存键
64
+ */
65
+ export function mcpConfigKey(config) {
66
+ if (config.transport === "stdio")
67
+ return stdioConfigKey(config);
68
+ return sseConfigKey(config);
69
+ }
@@ -0,0 +1,18 @@
1
+ /**
2
+ * Core MCP 模块:为 SessionAgent 提供 MCP Tools 能力(Client 端)。
3
+ * 配置在创建 Session 时通过 options.mcpServers 传入,与 Skill 类似。
4
+ */
5
+ import type { ToolDefinition } from "@mariozechner/pi-coding-agent";
6
+ import type { McpServerConfig } from "./types.js";
7
+ export type { McpServerConfig, McpServerConfigStdio, McpServerConfigSse, McpTool } from "./types.js";
8
+ export { resolveMcpServersForSession, stdioConfigKey, sseConfigKey, mcpConfigKey } from "./config.js";
9
+ export { McpClient } from "./client.js";
10
+ export { getMcpToolDefinitions, shutdownMcpClients } from "./operator.js";
11
+ export { mcpToolToToolDefinition, mcpToolsToToolDefinitions } from "./adapter.js";
12
+ /**
13
+ * 根据会话选项中的 mcpServers 配置,返回该会话可用的 MCP 工具(ToolDefinition 数组)。
14
+ * 在 AgentManager.getOrCreateSession 中调用,并入 customTools。
15
+ */
16
+ export declare function createMcpToolsForSession(options: {
17
+ mcpServers?: McpServerConfig[];
18
+ }): Promise<ToolDefinition[]>;
@@ -0,0 +1,20 @@
1
+ /**
2
+ * Core MCP 模块:为 SessionAgent 提供 MCP Tools 能力(Client 端)。
3
+ * 配置在创建 Session 时通过 options.mcpServers 传入,与 Skill 类似。
4
+ */
5
+ import { resolveMcpServersForSession } from "./config.js";
6
+ import { getMcpToolDefinitions } from "./operator.js";
7
+ export { resolveMcpServersForSession, stdioConfigKey, sseConfigKey, mcpConfigKey } from "./config.js";
8
+ export { McpClient } from "./client.js";
9
+ export { getMcpToolDefinitions, shutdownMcpClients } from "./operator.js";
10
+ export { mcpToolToToolDefinition, mcpToolsToToolDefinitions } from "./adapter.js";
11
+ /**
12
+ * 根据会话选项中的 mcpServers 配置,返回该会话可用的 MCP 工具(ToolDefinition 数组)。
13
+ * 在 AgentManager.getOrCreateSession 中调用,并入 customTools。
14
+ */
15
+ export async function createMcpToolsForSession(options) {
16
+ const configs = resolveMcpServersForSession(options.mcpServers);
17
+ if (configs.length === 0)
18
+ return [];
19
+ return getMcpToolDefinitions(configs);
20
+ }
@@ -0,0 +1,15 @@
1
+ /**
2
+ * MCP Operator:管理 MCP 客户端生命周期,按配置为会话提供 ToolDefinition 列表。
3
+ * 支持 stdio(本地)与 sse(远程)两种传输。
4
+ */
5
+ import type { McpServerConfig } from "./types.js";
6
+ import type { ToolDefinition } from "@mariozechner/pi-coding-agent";
7
+ /**
8
+ * 为给定 MCP 服务器配置列表获取或创建客户端,并返回其工具对应的 ToolDefinition 数组。
9
+ * 连接失败或 list_tools 失败的 server 会被跳过并打日志,不阻塞整体。
10
+ */
11
+ export declare function getMcpToolDefinitions(serverConfigs: McpServerConfig[]): Promise<ToolDefinition[]>;
12
+ /**
13
+ * 关闭并移除所有缓存的 MCP 客户端(进程退出或显式清理时调用)。
14
+ */
15
+ export declare function shutdownMcpClients(): Promise<void>;
@@ -0,0 +1,72 @@
1
+ /**
2
+ * MCP Operator:管理 MCP 客户端生命周期,按配置为会话提供 ToolDefinition 列表。
3
+ * 支持 stdio(本地)与 sse(远程)两种传输。
4
+ */
5
+ import { mcpConfigKey } from "./config.js";
6
+ import { McpClient } from "./client.js";
7
+ import { mcpToolsToToolDefinitions } from "./adapter.js";
8
+ /** 按配置键缓存的客户端 */
9
+ const clientCache = new Map();
10
+ function configLabel(config) {
11
+ if (config.transport === "stdio")
12
+ return config.command;
13
+ return config.url;
14
+ }
15
+ /**
16
+ * 为给定 MCP 服务器配置列表获取或创建客户端,并返回其工具对应的 ToolDefinition 数组。
17
+ * 连接失败或 list_tools 失败的 server 会被跳过并打日志,不阻塞整体。
18
+ */
19
+ export async function getMcpToolDefinitions(serverConfigs) {
20
+ const allTools = [];
21
+ for (let i = 0; i < serverConfigs.length; i++) {
22
+ const config = serverConfigs[i];
23
+ const key = mcpConfigKey(config);
24
+ let client = clientCache.get(key);
25
+ if (!client) {
26
+ client = new McpClient(config);
27
+ try {
28
+ await client.connect();
29
+ clientCache.set(key, client);
30
+ }
31
+ catch (err) {
32
+ console.warn(`[mcp] 连接失败 (${configLabel(config)}):`, err instanceof Error ? err.message : err);
33
+ continue;
34
+ }
35
+ }
36
+ if (!client.isConnected) {
37
+ clientCache.delete(key);
38
+ try {
39
+ await client.close();
40
+ }
41
+ catch { }
42
+ const newClient = new McpClient(config);
43
+ try {
44
+ await newClient.connect();
45
+ clientCache.set(key, newClient);
46
+ client = newClient;
47
+ }
48
+ catch (err) {
49
+ console.warn(`[mcp] 重连失败 (${configLabel(config)}):`, err instanceof Error ? err.message : err);
50
+ continue;
51
+ }
52
+ }
53
+ try {
54
+ const tools = await client.listTools();
55
+ const serverId = `mcp${i}`;
56
+ const definitions = mcpToolsToToolDefinitions(tools, client, serverId);
57
+ allTools.push(...definitions);
58
+ }
59
+ catch (err) {
60
+ console.warn(`[mcp] list_tools 失败 (${configLabel(config)}):`, err instanceof Error ? err.message : err);
61
+ }
62
+ }
63
+ return allTools;
64
+ }
65
+ /**
66
+ * 关闭并移除所有缓存的 MCP 客户端(进程退出或显式清理时调用)。
67
+ */
68
+ export async function shutdownMcpClients() {
69
+ const closeAll = Array.from(clientCache.values()).map((c) => c.close().catch(() => { }));
70
+ clientCache.clear();
71
+ await Promise.all(closeAll);
72
+ }
@@ -0,0 +1,11 @@
1
+ import type { McpServerConfig, IMcpTransport } from "../types.js";
2
+ export interface TransportOptions {
3
+ initTimeoutMs?: number;
4
+ requestTimeoutMs?: number;
5
+ }
6
+ /**
7
+ * 根据配置创建对应的传输层实例。
8
+ */
9
+ export declare function createTransport(config: McpServerConfig, options?: TransportOptions): IMcpTransport;
10
+ export { StdioTransport } from "./stdio.js";
11
+ export { SseTransport } from "./sse.js";
@@ -0,0 +1,16 @@
1
+ import { StdioTransport } from "./stdio.js";
2
+ import { SseTransport } from "./sse.js";
3
+ /**
4
+ * 根据配置创建对应的传输层实例。
5
+ */
6
+ export function createTransport(config, options) {
7
+ if (config.transport === "stdio") {
8
+ return new StdioTransport(config, options);
9
+ }
10
+ if (config.transport === "sse") {
11
+ return new SseTransport(config, options);
12
+ }
13
+ throw new Error(`Unsupported MCP transport: ${config.transport}`);
14
+ }
15
+ export { StdioTransport } from "./stdio.js";
16
+ export { SseTransport } from "./sse.js";
@@ -0,0 +1,20 @@
1
+ /**
2
+ * MCP SSE/HTTP 传输:通过 HTTP POST 向远程 URL 发送 JSON-RPC 请求,响应在 response body。
3
+ */
4
+ import type { McpServerConfigSse } from "../types.js";
5
+ import type { JsonRpcRequest, JsonRpcResponse } from "../types.js";
6
+ export interface SseTransportOptions {
7
+ initTimeoutMs?: number;
8
+ requestTimeoutMs?: number;
9
+ }
10
+ export declare class SseTransport {
11
+ private config;
12
+ private initTimeoutMs;
13
+ private requestTimeoutMs;
14
+ private _connected;
15
+ constructor(config: McpServerConfigSse, options?: SseTransportOptions);
16
+ start(): Promise<void>;
17
+ request(req: JsonRpcRequest, timeoutMs?: number): Promise<JsonRpcResponse>;
18
+ close(): Promise<void>;
19
+ get isConnected(): boolean;
20
+ }