activo 0.4.3 → 0.5.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 (166) hide show
  1. package/README.md +203 -1
  2. package/data/2026-03-04_20-54.json +181 -0
  3. package/data/2026-03-04_20-56.json +181 -0
  4. package/data/apex-rulesets/egov.yaml +469 -0
  5. package/data/apex-rulesets/modernize.yaml +687 -0
  6. package/data/apex-rulesets/quality.yaml +1677 -0
  7. package/data/apex-rulesets/rule-schema.yaml +587 -0
  8. package/data/apex-rulesets/secure.yaml +1688 -0
  9. package/data/apex-rulesets/spring.yaml +455 -0
  10. package/data/apex-rulesets/sql-format.yaml +99 -0
  11. package/data/apex-rulesets/sql-oracle.yaml +281 -0
  12. package/data/apex-rulesets/sql.yaml +1660 -0
  13. package/dist/cli/headless.d.ts.map +1 -1
  14. package/dist/cli/headless.js +32 -10
  15. package/dist/cli/headless.js.map +1 -1
  16. package/dist/cli/index.js +31 -3
  17. package/dist/cli/index.js.map +1 -1
  18. package/dist/core/agent.d.ts +3 -3
  19. package/dist/core/agent.d.ts.map +1 -1
  20. package/dist/core/agent.js +255 -17
  21. package/dist/core/agent.js.map +1 -1
  22. package/dist/core/commands.d.ts +2 -1
  23. package/dist/core/commands.d.ts.map +1 -1
  24. package/dist/core/commands.js +61 -9
  25. package/dist/core/commands.js.map +1 -1
  26. package/dist/core/config.d.ts +14 -0
  27. package/dist/core/config.d.ts.map +1 -1
  28. package/dist/core/config.js +41 -4
  29. package/dist/core/config.js.map +1 -1
  30. package/dist/core/conversation.d.ts +2 -2
  31. package/dist/core/conversation.d.ts.map +1 -1
  32. package/dist/core/conversation.js.map +1 -1
  33. package/dist/core/intentRouter.d.ts +43 -0
  34. package/dist/core/intentRouter.d.ts.map +1 -0
  35. package/dist/core/intentRouter.js +804 -0
  36. package/dist/core/intentRouter.js.map +1 -0
  37. package/dist/core/llm/anthropic.d.ts +24 -0
  38. package/dist/core/llm/anthropic.d.ts.map +1 -0
  39. package/dist/core/llm/anthropic.js +226 -0
  40. package/dist/core/llm/anthropic.js.map +1 -0
  41. package/dist/core/llm/ollama.d.ts +5 -14
  42. package/dist/core/llm/ollama.d.ts.map +1 -1
  43. package/dist/core/llm/ollama.js +3 -0
  44. package/dist/core/llm/ollama.js.map +1 -1
  45. package/dist/core/llm/types.d.ts +22 -0
  46. package/dist/core/llm/types.d.ts.map +1 -0
  47. package/dist/core/llm/types.js +2 -0
  48. package/dist/core/llm/types.js.map +1 -0
  49. package/dist/core/mcp/client.d.ts +6 -0
  50. package/dist/core/mcp/client.d.ts.map +1 -1
  51. package/dist/core/mcp/client.js +16 -0
  52. package/dist/core/mcp/client.js.map +1 -1
  53. package/dist/core/mcp/init.d.ts +12 -0
  54. package/dist/core/mcp/init.d.ts.map +1 -0
  55. package/dist/core/mcp/init.js +55 -0
  56. package/dist/core/mcp/init.js.map +1 -0
  57. package/dist/core/mcp/logger.d.ts +14 -0
  58. package/dist/core/mcp/logger.d.ts.map +1 -0
  59. package/dist/core/mcp/logger.js +50 -0
  60. package/dist/core/mcp/logger.js.map +1 -0
  61. package/dist/core/tools/analyzeAll.d.ts.map +1 -1
  62. package/dist/core/tools/analyzeAll.js +16 -28
  63. package/dist/core/tools/analyzeAll.js.map +1 -1
  64. package/dist/core/tools/analyzePatterns.d.ts +3 -0
  65. package/dist/core/tools/analyzePatterns.d.ts.map +1 -0
  66. package/dist/core/tools/analyzePatterns.js +293 -0
  67. package/dist/core/tools/analyzePatterns.js.map +1 -0
  68. package/dist/core/tools/apexPaths.d.ts +14 -0
  69. package/dist/core/tools/apexPaths.d.ts.map +1 -0
  70. package/dist/core/tools/apexPaths.js +54 -0
  71. package/dist/core/tools/apexPaths.js.map +1 -0
  72. package/dist/core/tools/apexUtils.d.ts +36 -0
  73. package/dist/core/tools/apexUtils.d.ts.map +1 -0
  74. package/dist/core/tools/apexUtils.js +83 -0
  75. package/dist/core/tools/apexUtils.js.map +1 -0
  76. package/dist/core/tools/explainIssue.d.ts +3 -0
  77. package/dist/core/tools/explainIssue.d.ts.map +1 -0
  78. package/dist/core/tools/explainIssue.js +181 -0
  79. package/dist/core/tools/explainIssue.js.map +1 -0
  80. package/dist/core/tools/fixGen.d.ts +3 -0
  81. package/dist/core/tools/fixGen.d.ts.map +1 -0
  82. package/dist/core/tools/fixGen.js +338 -0
  83. package/dist/core/tools/fixGen.js.map +1 -0
  84. package/dist/core/tools/generateImprovements.d.ts +21 -0
  85. package/dist/core/tools/generateImprovements.d.ts.map +1 -0
  86. package/dist/core/tools/generateImprovements.js +602 -0
  87. package/dist/core/tools/generateImprovements.js.map +1 -0
  88. package/dist/core/tools/generateReport.d.ts +3 -0
  89. package/dist/core/tools/generateReport.d.ts.map +1 -0
  90. package/dist/core/tools/generateReport.js +315 -0
  91. package/dist/core/tools/generateReport.js.map +1 -0
  92. package/dist/core/tools/index.d.ts +7 -0
  93. package/dist/core/tools/index.d.ts.map +1 -1
  94. package/dist/core/tools/index.js +62 -23
  95. package/dist/core/tools/index.js.map +1 -1
  96. package/dist/core/tools/javaAst.d.ts.map +1 -1
  97. package/dist/core/tools/javaAst.js +191 -0
  98. package/dist/core/tools/javaAst.js.map +1 -1
  99. package/dist/core/tools/recommendProfile.d.ts +3 -0
  100. package/dist/core/tools/recommendProfile.d.ts.map +1 -0
  101. package/dist/core/tools/recommendProfile.js +334 -0
  102. package/dist/core/tools/recommendProfile.js.map +1 -0
  103. package/dist/core/tools/ruleGen.d.ts +3 -0
  104. package/dist/core/tools/ruleGen.d.ts.map +1 -0
  105. package/dist/core/tools/ruleGen.js +1103 -0
  106. package/dist/core/tools/ruleGen.js.map +1 -0
  107. package/dist/core/tools/standards.d.ts.map +1 -1
  108. package/dist/core/tools/standards.js +7 -3
  109. package/dist/core/tools/standards.js.map +1 -1
  110. package/dist/ui/App.d.ts.map +1 -1
  111. package/dist/ui/App.js +86 -35
  112. package/dist/ui/App.js.map +1 -1
  113. package/dist/ui/components/InputBox.d.ts +1 -3
  114. package/dist/ui/components/InputBox.d.ts.map +1 -1
  115. package/dist/ui/components/InputBox.js +146 -5
  116. package/dist/ui/components/InputBox.js.map +1 -1
  117. package/dist/ui/components/MessageList.d.ts +3 -1
  118. package/dist/ui/components/MessageList.d.ts.map +1 -1
  119. package/dist/ui/components/MessageList.js +13 -7
  120. package/dist/ui/components/MessageList.js.map +1 -1
  121. package/dist/ui/components/StatusBar.d.ts +1 -1
  122. package/dist/ui/components/StatusBar.d.ts.map +1 -1
  123. package/dist/ui/components/StatusBar.js +3 -2
  124. package/dist/ui/components/StatusBar.js.map +1 -1
  125. package/dist/ui/components/ToolStatus.d.ts +3 -1
  126. package/dist/ui/components/ToolStatus.d.ts.map +1 -1
  127. package/dist/ui/components/ToolStatus.js +19 -4
  128. package/dist/ui/components/ToolStatus.js.map +1 -1
  129. package/package.json +7 -1
  130. package/demo.gif +0 -0
  131. package/demo.tape +0 -53
  132. package/screenshot.png +0 -0
  133. package/src/cli/banner.ts +0 -38
  134. package/src/cli/headless.ts +0 -63
  135. package/src/cli/index.ts +0 -57
  136. package/src/core/agent.ts +0 -237
  137. package/src/core/commands.ts +0 -118
  138. package/src/core/config.ts +0 -98
  139. package/src/core/conversation.ts +0 -235
  140. package/src/core/llm/ollama.ts +0 -351
  141. package/src/core/mcp/client.ts +0 -143
  142. package/src/core/tools/analyzeAll.ts +0 -494
  143. package/src/core/tools/ast.ts +0 -826
  144. package/src/core/tools/builtIn.ts +0 -221
  145. package/src/core/tools/cache.ts +0 -570
  146. package/src/core/tools/cssAnalysis.ts +0 -324
  147. package/src/core/tools/dependencyAnalysis.ts +0 -363
  148. package/src/core/tools/embeddings.ts +0 -746
  149. package/src/core/tools/frontendAst.ts +0 -802
  150. package/src/core/tools/htmlAnalysis.ts +0 -466
  151. package/src/core/tools/index.ts +0 -160
  152. package/src/core/tools/javaAst.ts +0 -812
  153. package/src/core/tools/memory.ts +0 -655
  154. package/src/core/tools/mybatisAnalysis.ts +0 -322
  155. package/src/core/tools/openapiAnalysis.ts +0 -431
  156. package/src/core/tools/pythonAnalysis.ts +0 -477
  157. package/src/core/tools/sqlAnalysis.ts +0 -298
  158. package/src/core/tools/standards.test.ts +0 -186
  159. package/src/core/tools/standards.ts +0 -889
  160. package/src/core/tools/types.ts +0 -38
  161. package/src/ui/App.tsx +0 -334
  162. package/src/ui/components/InputBox.tsx +0 -37
  163. package/src/ui/components/MessageList.tsx +0 -80
  164. package/src/ui/components/StatusBar.tsx +0 -36
  165. package/src/ui/components/ToolStatus.tsx +0 -38
  166. package/tsconfig.json +0 -21
@@ -1,351 +0,0 @@
1
- import { OllamaConfig } from "../config.js";
2
- import type { Tool, ToolCall } from "../tools/types.js";
3
-
4
- export interface ChatMessage {
5
- role: "system" | "user" | "assistant" | "tool";
6
- content: string;
7
- toolCalls?: ToolCall[];
8
- toolCallId?: string;
9
- }
10
-
11
- export interface StreamEvent {
12
- type: "content" | "tool_call" | "done" | "error";
13
- content?: string;
14
- toolCall?: ToolCall;
15
- error?: string;
16
- }
17
-
18
- interface OllamaChatResponse {
19
- model: string;
20
- message: {
21
- role: string;
22
- content: string;
23
- tool_calls?: Array<{
24
- function: {
25
- name: string;
26
- arguments: Record<string, unknown>;
27
- };
28
- }>;
29
- };
30
- done: boolean;
31
- }
32
-
33
- // Estimate token count for a string (rough: ~3 chars per token for mixed Korean/English)
34
- function estimateTokens(text: string): number {
35
- if (!text) return 0;
36
- return Math.ceil(text.length / 3);
37
- }
38
-
39
- // Estimate tokens for tool definitions sent to Ollama
40
- function estimateToolTokens(tools: Tool[]): number {
41
- let total = 0;
42
- for (const tool of tools) {
43
- // name + description + JSON schema overhead
44
- total += estimateTokens(tool.name) + estimateTokens(tool.description) + 20;
45
- if (tool.parameters?.properties) {
46
- for (const [key, prop] of Object.entries(tool.parameters.properties)) {
47
- total += estimateTokens(key) + estimateTokens((prop as { description?: string }).description || "") + 10;
48
- }
49
- }
50
- }
51
- return total;
52
- }
53
-
54
- // Prune messages to fit within context window
55
- function pruneMessages(
56
- messages: Array<{ role: string; content: string }>,
57
- maxContextTokens: number,
58
- toolTokens: number
59
- ): Array<{ role: string; content: string }> {
60
- if (messages.length <= 2) return messages;
61
-
62
- const responseReserve = 1000; // reserve tokens for model response
63
- const safetyBuffer = 200;
64
- const budget = maxContextTokens - toolTokens - responseReserve - safetyBuffer;
65
-
66
- // Always preserve: first message (system) and last message (user)
67
- const systemMsg = messages[0];
68
- const lastMsg = messages[messages.length - 1];
69
- const history = messages.slice(1, -1);
70
-
71
- let usedTokens = estimateTokens(systemMsg.content) + estimateTokens(lastMsg.content);
72
-
73
- // If even system + last message exceeds budget, truncate system prompt
74
- if (usedTokens > budget) {
75
- const maxSystemChars = Math.max(200, (budget - estimateTokens(lastMsg.content)) * 3);
76
- systemMsg.content = systemMsg.content.slice(0, maxSystemChars);
77
- return [systemMsg, lastMsg];
78
- }
79
-
80
- // Add messages from newest to oldest
81
- const kept: Array<{ role: string; content: string }> = [];
82
- for (let i = history.length - 1; i >= 0; i--) {
83
- const msgTokens = estimateTokens(history[i].content) + 4; // 4 tokens overhead per message
84
- if (usedTokens + msgTokens > budget) break;
85
- kept.unshift(history[i]);
86
- usedTokens += msgTokens;
87
- }
88
-
89
- return [systemMsg, ...kept, lastMsg];
90
- }
91
-
92
- export class OllamaClient {
93
- private baseUrl: string;
94
- private model: string;
95
- private contextLength: number;
96
- private keepAlive: number;
97
-
98
- constructor(config: OllamaConfig) {
99
- this.baseUrl = config.baseUrl;
100
- this.model = config.model;
101
- this.contextLength = config.contextLength;
102
- this.keepAlive = config.keepAlive;
103
- }
104
-
105
- async isConnected(): Promise<boolean> {
106
- try {
107
- const response = await fetch(`${this.baseUrl}/api/tags`);
108
- return response.ok;
109
- } catch {
110
- return false;
111
- }
112
- }
113
-
114
- async listModels(): Promise<string[]> {
115
- const response = await fetch(`${this.baseUrl}/api/tags`);
116
- if (!response.ok) throw new Error("Failed to list models");
117
- const data = (await response.json()) as { models: Array<{ name: string }> };
118
- return data.models.map((m) => m.name);
119
- }
120
-
121
- async chat(
122
- messages: ChatMessage[],
123
- tools?: Tool[]
124
- ): Promise<ChatMessage> {
125
- let ollamaMessages = this.convertMessages(messages);
126
-
127
- // Prune messages to fit within context window
128
- const toolTokens = tools?.length ? estimateToolTokens(tools) : 0;
129
- ollamaMessages = pruneMessages(ollamaMessages, this.contextLength, toolTokens);
130
-
131
- const body: Record<string, unknown> = {
132
- model: this.model,
133
- messages: ollamaMessages,
134
- stream: false,
135
- options: {
136
- num_ctx: this.contextLength,
137
- },
138
- keep_alive: this.keepAlive,
139
- };
140
-
141
- // Always add tools if provided (needed for multi-turn tool use)
142
- if (tools?.length) {
143
- body.tools = tools.map((tool) => ({
144
- type: "function",
145
- function: {
146
- name: tool.name,
147
- description: tool.description,
148
- parameters: tool.parameters,
149
- },
150
- }));
151
- }
152
-
153
- const response = await fetch(`${this.baseUrl}/api/chat`, {
154
- method: "POST",
155
- headers: { "Content-Type": "application/json" },
156
- body: JSON.stringify(body),
157
- });
158
-
159
- if (!response.ok) {
160
- const error = await response.text();
161
- throw new Error(`Ollama error: ${error}`);
162
- }
163
-
164
- const data = (await response.json()) as OllamaChatResponse;
165
- return this.parseResponse(data);
166
- }
167
-
168
- async *streamChat(
169
- messages: ChatMessage[],
170
- tools?: Tool[],
171
- abortSignal?: AbortSignal
172
- ): AsyncGenerator<StreamEvent> {
173
- let ollamaMessages = this.convertMessages(messages);
174
-
175
- // Prune messages to fit within context window
176
- const toolTokens = tools?.length ? estimateToolTokens(tools) : 0;
177
- ollamaMessages = pruneMessages(ollamaMessages, this.contextLength, toolTokens);
178
-
179
- // Use non-streaming mode when tools are provided to avoid hallucination
180
- // (LLM often outputs fake results before tool calls in streaming mode)
181
- const useStreaming = !tools?.length;
182
-
183
- const body: Record<string, unknown> = {
184
- model: this.model,
185
- messages: ollamaMessages,
186
- stream: useStreaming,
187
- options: {
188
- num_ctx: this.contextLength,
189
- },
190
- keep_alive: this.keepAlive,
191
- };
192
-
193
- // Always add tools if provided (needed for multi-turn tool use)
194
- if (tools?.length) {
195
- body.tools = tools.map((tool) => ({
196
- type: "function",
197
- function: {
198
- name: tool.name,
199
- description: tool.description,
200
- parameters: tool.parameters,
201
- },
202
- }));
203
- }
204
-
205
- const response = await fetch(`${this.baseUrl}/api/chat`, {
206
- method: "POST",
207
- headers: { "Content-Type": "application/json" },
208
- body: JSON.stringify(body),
209
- signal: abortSignal,
210
- });
211
-
212
- if (!response.ok) {
213
- const error = await response.text();
214
- yield { type: "error", error: `Ollama error: ${error}` };
215
- return;
216
- }
217
-
218
- // Non-streaming mode for tool calls (avoids hallucination where LLM outputs text before calling tools)
219
- if (!useStreaming) {
220
- const data = (await response.json()) as OllamaChatResponse;
221
-
222
- // Handle tool calls first (ignore content when tools are called)
223
- if (data.message?.tool_calls?.length) {
224
- for (const tc of data.message.tool_calls) {
225
- const toolCall: ToolCall = {
226
- id: `tc_${Date.now()}_${Math.random().toString(36).slice(2)}`,
227
- name: tc.function.name,
228
- arguments: tc.function.arguments,
229
- };
230
- yield { type: "tool_call", toolCall };
231
- }
232
- } else if (data.message?.content) {
233
- // Only yield content if no tool calls
234
- yield { type: "content", content: data.message.content };
235
- }
236
-
237
- yield { type: "done" };
238
- return;
239
- }
240
-
241
- // Streaming mode (no tools)
242
- const reader = response.body?.getReader();
243
- if (!reader) {
244
- yield { type: "error", error: "No response body" };
245
- return;
246
- }
247
-
248
- const decoder = new TextDecoder();
249
- let buffer = "";
250
-
251
- while (true) {
252
- const { done, value } = await reader.read();
253
- if (done) break;
254
-
255
- buffer += decoder.decode(value, { stream: true });
256
- const lines = buffer.split("\n");
257
- buffer = lines.pop() || "";
258
-
259
- for (const line of lines) {
260
- if (!line.trim()) continue;
261
-
262
- try {
263
- const data = JSON.parse(line) as OllamaChatResponse;
264
-
265
- if (data.message?.content) {
266
- yield { type: "content", content: data.message.content };
267
- }
268
-
269
- if (data.done) {
270
- yield { type: "done" };
271
- }
272
- } catch {
273
- // Skip invalid JSON
274
- }
275
- }
276
- }
277
- }
278
-
279
- private convertMessages(messages: ChatMessage[]): Array<{
280
- role: string;
281
- content: string;
282
- }> {
283
- return messages.map((msg) => {
284
- if (msg.role === "tool") {
285
- return {
286
- role: "tool",
287
- content: msg.content,
288
- };
289
- }
290
- return {
291
- role: msg.role,
292
- content: msg.content,
293
- };
294
- });
295
- }
296
-
297
- private parseResponse(data: OllamaChatResponse): ChatMessage {
298
- const result: ChatMessage = {
299
- role: "assistant",
300
- content: data.message.content || "",
301
- };
302
-
303
- if (data.message.tool_calls?.length) {
304
- result.toolCalls = data.message.tool_calls.map((tc, idx) => ({
305
- id: `tc_${Date.now()}_${idx}`,
306
- name: tc.function.name,
307
- arguments: tc.function.arguments,
308
- }));
309
- }
310
-
311
- return result;
312
- }
313
-
314
- getModel(): string {
315
- return this.model;
316
- }
317
-
318
- setModel(model: string): void {
319
- this.model = model;
320
- }
321
-
322
- // Generate embeddings for text
323
- async embed(text: string, model?: string): Promise<number[]> {
324
- const response = await fetch(`${this.baseUrl}/api/embeddings`, {
325
- method: "POST",
326
- headers: { "Content-Type": "application/json" },
327
- body: JSON.stringify({
328
- model: model || "nomic-embed-text",
329
- prompt: text,
330
- }),
331
- });
332
-
333
- if (!response.ok) {
334
- const error = await response.text();
335
- throw new Error(`Ollama embedding error: ${error}`);
336
- }
337
-
338
- const data = (await response.json()) as { embedding: number[] };
339
- return data.embedding;
340
- }
341
-
342
- // Generate embeddings for multiple texts (batch)
343
- async embedBatch(texts: string[], model?: string): Promise<number[][]> {
344
- const embeddings: number[][] = [];
345
- for (const text of texts) {
346
- const embedding = await this.embed(text, model);
347
- embeddings.push(embedding);
348
- }
349
- return embeddings;
350
- }
351
- }
@@ -1,143 +0,0 @@
1
- import { Client } from "@modelcontextprotocol/sdk/client/index.js";
2
- import { StdioClientTransport } from "@modelcontextprotocol/sdk/client/stdio.js";
3
- import { MCPServerConfig } from "../config.js";
4
- import { Tool, ToolResult } from "../tools/types.js";
5
-
6
- export interface MCPConnection {
7
- id: string;
8
- client: Client;
9
- transport: StdioClientTransport;
10
- tools: Tool[];
11
- }
12
-
13
- export class MCPManager {
14
- private connections: Map<string, MCPConnection> = new Map();
15
-
16
- async connect(id: string, config: MCPServerConfig): Promise<MCPConnection> {
17
- // Check if already connected
18
- if (this.connections.has(id)) {
19
- return this.connections.get(id)!;
20
- }
21
-
22
- const transport = new StdioClientTransport({
23
- command: config.command,
24
- args: config.args,
25
- env: config.env,
26
- });
27
-
28
- const client = new Client({
29
- name: "activo",
30
- version: "0.2.0",
31
- });
32
-
33
- await client.connect(transport);
34
-
35
- // Get available tools
36
- const toolsResult = await client.listTools();
37
- const tools: Tool[] = toolsResult.tools.map((t) => ({
38
- name: `mcp_${id}_${t.name}`,
39
- description: t.description || `MCP tool: ${t.name}`,
40
- parameters: {
41
- type: "object" as const,
42
- properties: (t.inputSchema as any)?.properties || {},
43
- required: (t.inputSchema as any)?.required,
44
- },
45
- handler: async (args: Record<string, unknown>): Promise<ToolResult> => {
46
- return this.callTool(id, t.name, args);
47
- },
48
- }));
49
-
50
- const connection: MCPConnection = {
51
- id,
52
- client,
53
- transport,
54
- tools,
55
- };
56
-
57
- this.connections.set(id, connection);
58
- return connection;
59
- }
60
-
61
- async disconnect(id: string): Promise<void> {
62
- const connection = this.connections.get(id);
63
- if (connection) {
64
- await connection.client.close();
65
- this.connections.delete(id);
66
- }
67
- }
68
-
69
- async disconnectAll(): Promise<void> {
70
- for (const id of this.connections.keys()) {
71
- await this.disconnect(id);
72
- }
73
- }
74
-
75
- async callTool(connectionId: string, toolName: string, args: Record<string, unknown>): Promise<ToolResult> {
76
- const connection = this.connections.get(connectionId);
77
- if (!connection) {
78
- return {
79
- success: false,
80
- content: "",
81
- error: `MCP connection not found: ${connectionId}`,
82
- };
83
- }
84
-
85
- try {
86
- const result = await connection.client.callTool({
87
- name: toolName,
88
- arguments: args,
89
- });
90
-
91
- if (result.isError) {
92
- return {
93
- success: false,
94
- content: "",
95
- error: JSON.stringify(result.content),
96
- };
97
- }
98
-
99
- const contentArray = result.content as Array<{ type: string; text?: string }>;
100
- const content = contentArray
101
- .filter((c) => c.type === "text" && c.text)
102
- .map((c) => c.text!)
103
- .join("\n");
104
-
105
- return {
106
- success: true,
107
- content,
108
- };
109
- } catch (error) {
110
- return {
111
- success: false,
112
- content: "",
113
- error: String(error),
114
- };
115
- }
116
- }
117
-
118
- getAllTools(): Tool[] {
119
- const tools: Tool[] = [];
120
- for (const connection of this.connections.values()) {
121
- tools.push(...connection.tools);
122
- }
123
- return tools;
124
- }
125
-
126
- getConnection(id: string): MCPConnection | undefined {
127
- return this.connections.get(id);
128
- }
129
-
130
- isConnected(id: string): boolean {
131
- return this.connections.has(id);
132
- }
133
- }
134
-
135
- // Singleton instance
136
- let mcpManager: MCPManager | null = null;
137
-
138
- export function getMCPManager(): MCPManager {
139
- if (!mcpManager) {
140
- mcpManager = new MCPManager();
141
- }
142
- return mcpManager;
143
- }