@seandong/seno 0.1.0

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 (104) hide show
  1. package/README.md +70 -0
  2. package/dist/agent/conversation.d.ts +39 -0
  3. package/dist/agent/conversation.js +60 -0
  4. package/dist/agent/conversation.js.map +1 -0
  5. package/dist/agent/loop.d.ts +41 -0
  6. package/dist/agent/loop.js +203 -0
  7. package/dist/agent/loop.js.map +1 -0
  8. package/dist/agent/session.d.ts +63 -0
  9. package/dist/agent/session.js +135 -0
  10. package/dist/agent/session.js.map +1 -0
  11. package/dist/cli/commands.d.ts +52 -0
  12. package/dist/cli/commands.js +667 -0
  13. package/dist/cli/commands.js.map +1 -0
  14. package/dist/cli/logger.d.ts +38 -0
  15. package/dist/cli/logger.js +79 -0
  16. package/dist/cli/logger.js.map +1 -0
  17. package/dist/cli/output.d.ts +75 -0
  18. package/dist/cli/output.js +305 -0
  19. package/dist/cli/output.js.map +1 -0
  20. package/dist/cli/prompt.d.ts +30 -0
  21. package/dist/cli/prompt.js +196 -0
  22. package/dist/cli/prompt.js.map +1 -0
  23. package/dist/cli/repl.d.ts +27 -0
  24. package/dist/cli/repl.js +485 -0
  25. package/dist/cli/repl.js.map +1 -0
  26. package/dist/commands/init.d.ts +4 -0
  27. package/dist/commands/init.js +170 -0
  28. package/dist/commands/init.js.map +1 -0
  29. package/dist/commands/model.d.ts +10 -0
  30. package/dist/commands/model.js +270 -0
  31. package/dist/commands/model.js.map +1 -0
  32. package/dist/config/manager.d.ts +67 -0
  33. package/dist/config/manager.js +194 -0
  34. package/dist/config/manager.js.map +1 -0
  35. package/dist/config/types.d.ts +98 -0
  36. package/dist/config/types.js +2 -0
  37. package/dist/config/types.js.map +1 -0
  38. package/dist/errors.d.ts +37 -0
  39. package/dist/errors.js +54 -0
  40. package/dist/errors.js.map +1 -0
  41. package/dist/index.d.ts +2 -0
  42. package/dist/index.js +185 -0
  43. package/dist/index.js.map +1 -0
  44. package/dist/llm/anthropic.d.ts +27 -0
  45. package/dist/llm/anthropic.js +189 -0
  46. package/dist/llm/anthropic.js.map +1 -0
  47. package/dist/llm/factory.d.ts +47 -0
  48. package/dist/llm/factory.js +163 -0
  49. package/dist/llm/factory.js.map +1 -0
  50. package/dist/llm/openai-codex.d.ts +45 -0
  51. package/dist/llm/openai-codex.js +398 -0
  52. package/dist/llm/openai-codex.js.map +1 -0
  53. package/dist/llm/openai.d.ts +16 -0
  54. package/dist/llm/openai.js +288 -0
  55. package/dist/llm/openai.js.map +1 -0
  56. package/dist/llm/provider.d.ts +19 -0
  57. package/dist/llm/provider.js +2 -0
  58. package/dist/llm/provider.js.map +1 -0
  59. package/dist/llm/types.d.ts +102 -0
  60. package/dist/llm/types.js +2 -0
  61. package/dist/llm/types.js.map +1 -0
  62. package/dist/mcp/bridge.d.ts +30 -0
  63. package/dist/mcp/bridge.js +73 -0
  64. package/dist/mcp/bridge.js.map +1 -0
  65. package/dist/mcp/config.d.ts +6 -0
  66. package/dist/mcp/config.js +26 -0
  67. package/dist/mcp/config.js.map +1 -0
  68. package/dist/mcp/manager.d.ts +54 -0
  69. package/dist/mcp/manager.js +171 -0
  70. package/dist/mcp/manager.js.map +1 -0
  71. package/dist/prompts/system.d.ts +14 -0
  72. package/dist/prompts/system.js +194 -0
  73. package/dist/prompts/system.js.map +1 -0
  74. package/dist/skills/loader.d.ts +7 -0
  75. package/dist/skills/loader.js +81 -0
  76. package/dist/skills/loader.js.map +1 -0
  77. package/dist/skills/registry.d.ts +48 -0
  78. package/dist/skills/registry.js +104 -0
  79. package/dist/skills/registry.js.map +1 -0
  80. package/dist/skills/sync.d.ts +34 -0
  81. package/dist/skills/sync.js +179 -0
  82. package/dist/skills/sync.js.map +1 -0
  83. package/dist/skills/types.d.ts +29 -0
  84. package/dist/skills/types.js +2 -0
  85. package/dist/skills/types.js.map +1 -0
  86. package/dist/tools/ask.d.ts +16 -0
  87. package/dist/tools/ask.js +57 -0
  88. package/dist/tools/ask.js.map +1 -0
  89. package/dist/tools/registry.d.ts +54 -0
  90. package/dist/tools/registry.js +114 -0
  91. package/dist/tools/registry.js.map +1 -0
  92. package/dist/tools/shell.d.ts +10 -0
  93. package/dist/tools/shell.js +131 -0
  94. package/dist/tools/shell.js.map +1 -0
  95. package/dist/tools/ssh.d.ts +40 -0
  96. package/dist/tools/ssh.js +302 -0
  97. package/dist/tools/ssh.js.map +1 -0
  98. package/dist/tools/types.d.ts +20 -0
  99. package/dist/tools/types.js +2 -0
  100. package/dist/tools/types.js.map +1 -0
  101. package/dist/utils/retry.d.ts +20 -0
  102. package/dist/utils/retry.js +33 -0
  103. package/dist/utils/retry.js.map +1 -0
  104. package/package.json +51 -0
@@ -0,0 +1,288 @@
1
+ import OpenAI from 'openai';
2
+ import { logger } from '../cli/logger.js';
3
+ import { LLMError } from '../errors.js';
4
+ import { withRetry } from '../utils/retry.js';
5
+ const DEFAULT_MODEL = 'gpt-4o';
6
+ const DEFAULT_MAX_TOKENS = 8192;
7
+ /**
8
+ * OpenAI LLM Provider
9
+ *
10
+ * 实现统一 LLMProvider 接口,内部将 Anthropic 格式的消息/工具转换为 OpenAI 格式,
11
+ * 并将 OpenAI 流式响应转换回统一的 StreamEvent。
12
+ *
13
+ * 同时支持 API Key 和 OAuth access_token(OpenAI SDK 的 apiKey 参数兼容两者)。
14
+ */
15
+ export class OpenAIProvider {
16
+ name = 'openai';
17
+ client;
18
+ constructor(apiKeyOrToken, baseUrl) {
19
+ this.client = new OpenAI({
20
+ apiKey: apiKeyOrToken,
21
+ ...(baseUrl ? { baseURL: baseUrl } : {}),
22
+ });
23
+ }
24
+ async *chat(messages, tools, options) {
25
+ const model = options?.model || DEFAULT_MODEL;
26
+ const maxTokens = options?.maxTokens || DEFAULT_MAX_TOKENS;
27
+ // 构造请求参数
28
+ const openaiMessages = convertMessages(messages, options?.system);
29
+ const params = {
30
+ model,
31
+ max_tokens: maxTokens,
32
+ messages: openaiMessages,
33
+ stream: true,
34
+ stream_options: { include_usage: true },
35
+ };
36
+ if (options?.temperature !== undefined) {
37
+ params.temperature = options.temperature;
38
+ }
39
+ if (tools.length > 0) {
40
+ params.tools = convertTools(tools);
41
+ }
42
+ logger.debug('llm', `→ Request: model=${model}, tools=${tools.length}, messages=${messages.length}`);
43
+ // 创建流(带重试)
44
+ let stream;
45
+ try {
46
+ stream = await withRetry(() => this.client.chat.completions.create(params), {
47
+ maxRetries: 3,
48
+ baseDelayMs: 1000,
49
+ maxDelayMs: 8000,
50
+ shouldRetry: (e) => isRetryableError(e),
51
+ });
52
+ }
53
+ catch (error) {
54
+ yield { type: 'error', error: classifyError(error) };
55
+ return;
56
+ }
57
+ // 处理流式事件
58
+ try {
59
+ const activeToolCalls = new Map();
60
+ let inputTokens = 0;
61
+ for await (const chunk of stream) {
62
+ const choice = chunk.choices?.[0];
63
+ // usage chunk (最后一个 chunk,choices 为空)
64
+ if (chunk.usage) {
65
+ inputTokens = chunk.usage.prompt_tokens || 0;
66
+ }
67
+ if (!choice)
68
+ continue;
69
+ const delta = choice.delta;
70
+ // 文本内容
71
+ if (delta?.content) {
72
+ yield { type: 'text_delta', text: delta.content };
73
+ }
74
+ // tool_calls
75
+ if (delta?.tool_calls) {
76
+ for (const tc of delta.tool_calls) {
77
+ const idx = tc.index;
78
+ if (!activeToolCalls.has(idx)) {
79
+ // 新的 tool_call 开始
80
+ activeToolCalls.set(idx, {
81
+ id: tc.id || '',
82
+ name: tc.function?.name || '',
83
+ started: false,
84
+ });
85
+ }
86
+ const state = activeToolCalls.get(idx);
87
+ // 更新 id/name(可能在后续 chunk 中到达)
88
+ if (tc.id)
89
+ state.id = tc.id;
90
+ if (tc.function?.name)
91
+ state.name = tc.function.name;
92
+ // 发送 tool_use_start(首次有足够信息时)
93
+ if (!state.started && state.id && state.name) {
94
+ state.started = true;
95
+ yield { type: 'tool_use_start', id: state.id, name: state.name };
96
+ }
97
+ // 发送参数增量
98
+ if (tc.function?.arguments) {
99
+ yield { type: 'tool_use_delta', input_json: tc.function.arguments };
100
+ }
101
+ }
102
+ }
103
+ // finish_reason
104
+ if (choice.finish_reason) {
105
+ // 结束所有活跃的 tool_calls
106
+ for (const [, state] of activeToolCalls) {
107
+ if (state.started) {
108
+ yield { type: 'tool_use_end' };
109
+ }
110
+ }
111
+ activeToolCalls.clear();
112
+ const outputTokens = chunk.usage?.completion_tokens || 0;
113
+ const stopReason = mapFinishReason(choice.finish_reason);
114
+ logger.debug('llm', `← Response: stop=${stopReason}, in=${inputTokens}, out=${outputTokens}`);
115
+ yield {
116
+ type: 'message_end',
117
+ stop_reason: stopReason,
118
+ usage: { inputTokens, outputTokens },
119
+ };
120
+ }
121
+ }
122
+ }
123
+ catch (error) {
124
+ yield {
125
+ type: 'error',
126
+ error: error instanceof Error ? error : new Error(String(error)),
127
+ };
128
+ }
129
+ }
130
+ }
131
+ /**
132
+ * 将 Anthropic 格式的 Message[] 转换为 OpenAI ChatCompletionMessageParam[]
133
+ */
134
+ function convertMessages(messages, system) {
135
+ const result = [];
136
+ // system prompt
137
+ if (system) {
138
+ result.push({ role: 'system', content: system });
139
+ }
140
+ for (const msg of messages) {
141
+ if (typeof msg.content === 'string') {
142
+ result.push({ role: msg.role, content: msg.content });
143
+ continue;
144
+ }
145
+ // ContentBlock[] 消息需要拆分处理
146
+ if (msg.role === 'assistant') {
147
+ result.push(convertAssistantMessage(msg.content));
148
+ }
149
+ else {
150
+ // user 消息可能包含 tool_result blocks
151
+ const toolResults = msg.content.filter((b) => b.type === 'tool_result');
152
+ const nonToolBlocks = msg.content.filter((b) => b.type !== 'tool_result');
153
+ // 先添加普通 user 内容
154
+ if (nonToolBlocks.length > 0) {
155
+ const text = nonToolBlocks
156
+ .filter((b) => b.type === 'text')
157
+ .map((b) => b.text)
158
+ .join('');
159
+ if (text) {
160
+ result.push({ role: 'user', content: text });
161
+ }
162
+ }
163
+ // tool_result → OpenAI tool role messages
164
+ for (const tr of toolResults) {
165
+ result.push({
166
+ role: 'tool',
167
+ tool_call_id: tr.tool_use_id,
168
+ content: tr.content,
169
+ });
170
+ }
171
+ }
172
+ }
173
+ return result;
174
+ }
175
+ /**
176
+ * 将 assistant 消息的 ContentBlock[] 转换为 OpenAI assistant message
177
+ */
178
+ function convertAssistantMessage(blocks) {
179
+ let textContent = '';
180
+ const toolCalls = [];
181
+ for (const block of blocks) {
182
+ if (block.type === 'text') {
183
+ textContent += block.text;
184
+ }
185
+ else if (block.type === 'tool_use') {
186
+ const toolUse = block;
187
+ toolCalls.push({
188
+ id: toolUse.id,
189
+ type: 'function',
190
+ function: {
191
+ name: toolUse.name,
192
+ arguments: JSON.stringify(toolUse.input),
193
+ },
194
+ });
195
+ }
196
+ }
197
+ const msg = {
198
+ role: 'assistant',
199
+ content: textContent || null,
200
+ };
201
+ if (toolCalls.length > 0) {
202
+ msg.tool_calls = toolCalls;
203
+ }
204
+ return msg;
205
+ }
206
+ /**
207
+ * 将 Anthropic 格式的 ToolDefinition[] 转换为 OpenAI 格式
208
+ */
209
+ function convertTools(tools) {
210
+ return tools.map((tool) => ({
211
+ type: 'function',
212
+ function: {
213
+ name: tool.name,
214
+ description: tool.description,
215
+ parameters: tool.input_schema,
216
+ },
217
+ }));
218
+ }
219
+ /**
220
+ * 映射 OpenAI finish_reason 到统一的 stop_reason
221
+ */
222
+ function mapFinishReason(reason) {
223
+ switch (reason) {
224
+ case 'stop':
225
+ return 'end_turn';
226
+ case 'tool_calls':
227
+ return 'tool_use';
228
+ case 'length':
229
+ return 'max_tokens';
230
+ default:
231
+ return reason;
232
+ }
233
+ }
234
+ /**
235
+ * 判断 API 错误是否可重试
236
+ */
237
+ function isRetryableError(error) {
238
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
239
+ const status = error?.status;
240
+ if (status === 429 || status === 500 || status === 502 || status === 503) {
241
+ return true;
242
+ }
243
+ const message = error instanceof Error ? error.message : String(error);
244
+ if (message.includes('fetch') ||
245
+ message.includes('network') ||
246
+ message.includes('ECONNREFUSED') ||
247
+ message.includes('ETIMEDOUT')) {
248
+ return true;
249
+ }
250
+ return false;
251
+ }
252
+ /**
253
+ * 将原始错误转换为 LLMError
254
+ */
255
+ function classifyError(error) {
256
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
257
+ const status = error?.status;
258
+ const message = error instanceof Error ? error.message : String(error);
259
+ switch (status) {
260
+ case 401:
261
+ return new LLMError('API 认证失败,请检查 API Key 或 OAuth token 配置', 401, false);
262
+ case 400: {
263
+ if (message.includes('context') ||
264
+ message.includes('too long') ||
265
+ message.includes('max tokens') ||
266
+ message.includes('too many')) {
267
+ return new LLMError(message, 400, false);
268
+ }
269
+ return new LLMError(`请求参数错误: ${message}`, 400, false);
270
+ }
271
+ case 429:
272
+ return new LLMError('API 请求频率超限,已重试仍失败', 429, true);
273
+ case 500:
274
+ case 502:
275
+ case 503:
276
+ return new LLMError(`OpenAI API 服务暂时不可用 (${status}),已重试仍失败`, status, true);
277
+ default: {
278
+ if (message.includes('fetch') ||
279
+ message.includes('network') ||
280
+ message.includes('ECONNREFUSED') ||
281
+ message.includes('ETIMEDOUT')) {
282
+ return new LLMError('网络连接失败,请检查网络', undefined, true);
283
+ }
284
+ return new LLMError(message, status);
285
+ }
286
+ }
287
+ }
288
+ //# sourceMappingURL=openai.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"openai.js","sourceRoot":"","sources":["../../src/llm/openai.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,19 @@
1
+ import type { Message, ToolDefinition, ChatOptions, StreamEvent } from './types.js';
2
+ /**
3
+ * LLM Provider 统一接口
4
+ *
5
+ * 所有 LLM 提供商实现此接口。
6
+ * 使用 AsyncIterable<StreamEvent> 作为返回类型,支持 for await...of 消费。
7
+ */
8
+ export interface LLMProvider {
9
+ /** Provider 名称标识 */
10
+ readonly name: string;
11
+ /**
12
+ * 流式对话调用
13
+ * @param messages 消息历史
14
+ * @param tools 工具定义列表(可为空数组表示无工具)
15
+ * @param options 调用选项
16
+ * @returns 异步可迭代的事件流
17
+ */
18
+ chat(messages: Message[], tools: ToolDefinition[], options?: ChatOptions): AsyncIterable<StreamEvent>;
19
+ }
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=provider.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"provider.js","sourceRoot":"","sources":["../../src/llm/provider.ts"],"names":[],"mappings":""}
@@ -0,0 +1,102 @@
1
+ /**
2
+ * 消息角色
3
+ */
4
+ export type Role = 'user' | 'assistant';
5
+ /**
6
+ * 文本内容块
7
+ */
8
+ export interface TextBlock {
9
+ type: 'text';
10
+ text: string;
11
+ }
12
+ /**
13
+ * 工具调用内容块
14
+ */
15
+ export interface ToolUseBlock {
16
+ type: 'tool_use';
17
+ id: string;
18
+ name: string;
19
+ input: Record<string, unknown>;
20
+ }
21
+ /**
22
+ * 工具执行结果内容块
23
+ */
24
+ export interface ToolResultBlock {
25
+ type: 'tool_result';
26
+ tool_use_id: string;
27
+ content: string;
28
+ is_error?: boolean;
29
+ }
30
+ /**
31
+ * 内容块类型
32
+ */
33
+ export type ContentBlock = TextBlock | ToolUseBlock | ToolResultBlock;
34
+ /**
35
+ * 消息类型(兼容 Anthropic API 格式)
36
+ */
37
+ export interface Message {
38
+ role: Role;
39
+ content: string | ContentBlock[];
40
+ }
41
+ /**
42
+ * 工具定义(Anthropic 格式)
43
+ */
44
+ export interface ToolDefinition {
45
+ name: string;
46
+ description: string;
47
+ input_schema: Record<string, unknown>;
48
+ }
49
+ /**
50
+ * Token 使用统计
51
+ */
52
+ export interface TokenUsage {
53
+ inputTokens: number;
54
+ outputTokens: number;
55
+ }
56
+ /**
57
+ * 流式事件类型
58
+ */
59
+ export type StreamEvent = {
60
+ type: 'turn_start';
61
+ } | {
62
+ type: 'text_delta';
63
+ text: string;
64
+ } | {
65
+ type: 'tool_use_start';
66
+ id: string;
67
+ name: string;
68
+ } | {
69
+ type: 'tool_use_delta';
70
+ input_json: string;
71
+ } | {
72
+ type: 'tool_use_end';
73
+ } | {
74
+ type: 'tool_execute_start';
75
+ name: string;
76
+ args: Record<string, unknown>;
77
+ } | {
78
+ type: 'tool_execute_end';
79
+ name: string;
80
+ result: string;
81
+ isError?: boolean;
82
+ } | {
83
+ type: 'message_end';
84
+ stop_reason: string;
85
+ usage?: TokenUsage;
86
+ } | {
87
+ type: 'error';
88
+ error: Error;
89
+ };
90
+ /**
91
+ * LLM 调用选项
92
+ */
93
+ export interface ChatOptions {
94
+ /** 模型名称 */
95
+ model?: string;
96
+ /** 最大输出 token 数 */
97
+ maxTokens?: number;
98
+ /** 系统提示词 */
99
+ system?: string;
100
+ /** 温度参数 */
101
+ temperature?: number;
102
+ }
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/llm/types.ts"],"names":[],"mappings":""}
@@ -0,0 +1,30 @@
1
+ import type { MCPManager } from './manager.js';
2
+ /**
3
+ * Anthropic Tool 定义格式
4
+ */
5
+ export interface AnthropicToolDef {
6
+ name: string;
7
+ description: string;
8
+ input_schema: Record<string, unknown>;
9
+ }
10
+ /**
11
+ * Tool 调用结果
12
+ */
13
+ export interface ToolResult {
14
+ content: string;
15
+ isError: boolean;
16
+ }
17
+ /**
18
+ * 将所有 MCP 工具转换为 Anthropic Tool 格式
19
+ * 工具名添加 {server}__ 前缀以区分来源
20
+ */
21
+ export declare function getToolDefinitions(manager: MCPManager): AnthropicToolDef[];
22
+ /**
23
+ * 解析带命名空间前缀的工具名
24
+ * @returns [serverName, toolName] 或 null(如果不含前缀)
25
+ */
26
+ export declare function parseToolName(prefixedName: string): [string, string] | null;
27
+ /**
28
+ * 根据带前缀的工具名路由到正确的 MCP Server 并调用
29
+ */
30
+ export declare function callMcpTool(manager: MCPManager, prefixedName: string, args: Record<string, unknown>): Promise<ToolResult>;
@@ -0,0 +1,73 @@
1
+ /** 命名空间分隔符 */
2
+ const NAMESPACE_SEPARATOR = '__';
3
+ /**
4
+ * 将所有 MCP 工具转换为 Anthropic Tool 格式
5
+ * 工具名添加 {server}__ 前缀以区分来源
6
+ */
7
+ export function getToolDefinitions(manager) {
8
+ const allTools = manager.getAllTools();
9
+ const definitions = [];
10
+ for (const [serverName, tools] of allTools) {
11
+ for (const tool of tools) {
12
+ definitions.push({
13
+ name: `${serverName}${NAMESPACE_SEPARATOR}${tool.name}`,
14
+ description: tool.description || '',
15
+ input_schema: tool.inputSchema || {
16
+ type: 'object',
17
+ properties: {},
18
+ },
19
+ });
20
+ }
21
+ }
22
+ return definitions;
23
+ }
24
+ /**
25
+ * 解析带命名空间前缀的工具名
26
+ * @returns [serverName, toolName] 或 null(如果不含前缀)
27
+ */
28
+ export function parseToolName(prefixedName) {
29
+ const idx = prefixedName.indexOf(NAMESPACE_SEPARATOR);
30
+ if (idx === -1)
31
+ return null;
32
+ const serverName = prefixedName.slice(0, idx);
33
+ const toolName = prefixedName.slice(idx + NAMESPACE_SEPARATOR.length);
34
+ return [serverName, toolName];
35
+ }
36
+ /**
37
+ * 根据带前缀的工具名路由到正确的 MCP Server 并调用
38
+ */
39
+ export async function callMcpTool(manager, prefixedName, args) {
40
+ const parsed = parseToolName(prefixedName);
41
+ if (!parsed) {
42
+ return {
43
+ content: `工具名格式错误,缺少服务器前缀: ${prefixedName}`,
44
+ isError: true,
45
+ };
46
+ }
47
+ const [serverName, toolName] = parsed;
48
+ try {
49
+ const result = await manager.callTool(serverName, toolName, args);
50
+ // 提取文本内容
51
+ const response = result;
52
+ if (response.content && Array.isArray(response.content)) {
53
+ const textParts = response.content
54
+ .filter((c) => c.type === 'text' && c.text)
55
+ .map((c) => c.text);
56
+ return {
57
+ content: textParts.join('\n') || JSON.stringify(result),
58
+ isError: response.isError || false,
59
+ };
60
+ }
61
+ return {
62
+ content: JSON.stringify(result),
63
+ isError: false,
64
+ };
65
+ }
66
+ catch (error) {
67
+ return {
68
+ content: `MCP 工具调用失败 [${serverName}/${toolName}]: ${error instanceof Error ? error.message : String(error)}`,
69
+ isError: true,
70
+ };
71
+ }
72
+ }
73
+ //# sourceMappingURL=bridge.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"bridge.js","sourceRoot":"","sources":["../../src/mcp/bridge.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,6 @@
1
+ import type { SenoConfig, McpServerConfig } from '../config/types.js';
2
+ /**
3
+ * 根据用户配置生成 MCP Server 配置列表
4
+ * 内置 ONES MCP(必需)和 Context7 MCP(可选)
5
+ */
6
+ export declare function getMcpServerConfigs(config: SenoConfig): McpServerConfig[];
@@ -0,0 +1,26 @@
1
+ /**
2
+ * 根据用户配置生成 MCP Server 配置列表
3
+ * 内置 ONES MCP(必需)和 Context7 MCP(可选)
4
+ */
5
+ export function getMcpServerConfigs(config) {
6
+ const servers = [
7
+ // ONES MCP Server(必需)
8
+ // 通过 mcp-remote 桥接远程服务器,自动处理 OAuth 认证
9
+ {
10
+ name: 'ones',
11
+ command: 'npx',
12
+ args: ['mcp-remote', config.ones_mcp_url],
13
+ required: true,
14
+ },
15
+ // Context7 MCP Server(可选)
16
+ // 提供第三方库文档搜索能力
17
+ {
18
+ name: 'context7',
19
+ command: 'npx',
20
+ args: ['-y', '@upstash/context7-mcp'],
21
+ required: false,
22
+ },
23
+ ];
24
+ return servers;
25
+ }
26
+ //# sourceMappingURL=config.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config.js","sourceRoot":"","sources":["../../src/mcp/config.ts"],"names":[],"mappings":"AAEA;;;GAGG;AACH,MAAM,UAAU,mBAAmB,CAAC,MAAkB;IACpD,MAAM,OAAO,GAAsB;QACjC,sBAAsB;QACtB,sCAAsC;QACtC;YACE,IAAI,EAAE,MAAM;YACZ,OAAO,EAAE,KAAK;YACd,IAAI,EAAE,CAAC,YAAY,EAAE,MAAM,CAAC,YAAY,CAAC;YACzC,QAAQ,EAAE,IAAI;SACf;QACD,0BAA0B;QAC1B,eAAe;QACf;YACE,IAAI,EAAE,UAAU;YAChB,OAAO,EAAE,KAAK;YACd,IAAI,EAAE,CAAC,IAAI,EAAE,uBAAuB,CAAC;YACrC,QAAQ,EAAE,KAAK;SAChB;KACF,CAAC;IAEF,OAAO,OAAO,CAAC;AACjB,CAAC"}
@@ -0,0 +1,54 @@
1
+ import type { McpServerConfig } from '../config/types.js';
2
+ import type { Tool } from '@modelcontextprotocol/sdk/types.js';
3
+ export interface UserInfo {
4
+ id: string;
5
+ name: string;
6
+ email: string;
7
+ }
8
+ /**
9
+ * MCP 多服务器连接管理器
10
+ * 管理多个 MCP Server 的生命周期:连接、工具发现、调用、断开
11
+ */
12
+ export declare class MCPManager {
13
+ private connections;
14
+ private _userInfo;
15
+ /**
16
+ * 当前用户信息(从 ONES MCP who_am_i 获取)
17
+ */
18
+ get userInfo(): UserInfo | null;
19
+ /**
20
+ * 并行连接所有 MCP 服务器
21
+ * required 服务器连接失败会抛出错误
22
+ * optional 服务器连接失败仅输出警告
23
+ */
24
+ connectAll(servers: McpServerConfig[]): Promise<void>;
25
+ /**
26
+ * 连接单个 MCP 服务器
27
+ */
28
+ private connectServer;
29
+ /**
30
+ * 通过 ONES MCP 的 who_am_i 获取用户身份
31
+ */
32
+ private fetchUserInfo;
33
+ /**
34
+ * 获取指定服务器的工具列表
35
+ */
36
+ getTools(serverName: string): Tool[];
37
+ /**
38
+ * 获取所有已连接服务器的工具列表
39
+ */
40
+ getAllTools(): Map<string, Tool[]>;
41
+ /**
42
+ * 获取所有已连接的服务器名称
43
+ */
44
+ getConnectedServers(): string[];
45
+ /**
46
+ * 调用指定服务器的工具
47
+ * 调用失败时尝试断开重连一次
48
+ */
49
+ callTool(serverName: string, toolName: string, args: Record<string, unknown>): Promise<unknown>;
50
+ /**
51
+ * 断开所有 MCP 连接,清理子进程
52
+ */
53
+ disconnectAll(): Promise<void>;
54
+ }