activo 0.4.4 → 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 (161) 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 +203 -384
  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/analyzePatterns.d.ts +3 -0
  62. package/dist/core/tools/analyzePatterns.d.ts.map +1 -0
  63. package/dist/core/tools/analyzePatterns.js +293 -0
  64. package/dist/core/tools/analyzePatterns.js.map +1 -0
  65. package/dist/core/tools/apexPaths.d.ts +14 -0
  66. package/dist/core/tools/apexPaths.d.ts.map +1 -0
  67. package/dist/core/tools/apexPaths.js +54 -0
  68. package/dist/core/tools/apexPaths.js.map +1 -0
  69. package/dist/core/tools/apexUtils.d.ts +36 -0
  70. package/dist/core/tools/apexUtils.d.ts.map +1 -0
  71. package/dist/core/tools/apexUtils.js +83 -0
  72. package/dist/core/tools/apexUtils.js.map +1 -0
  73. package/dist/core/tools/explainIssue.d.ts +3 -0
  74. package/dist/core/tools/explainIssue.d.ts.map +1 -0
  75. package/dist/core/tools/explainIssue.js +181 -0
  76. package/dist/core/tools/explainIssue.js.map +1 -0
  77. package/dist/core/tools/fixGen.d.ts +3 -0
  78. package/dist/core/tools/fixGen.d.ts.map +1 -0
  79. package/dist/core/tools/fixGen.js +338 -0
  80. package/dist/core/tools/fixGen.js.map +1 -0
  81. package/dist/core/tools/generateImprovements.d.ts +21 -0
  82. package/dist/core/tools/generateImprovements.d.ts.map +1 -0
  83. package/dist/core/tools/generateImprovements.js +602 -0
  84. package/dist/core/tools/generateImprovements.js.map +1 -0
  85. package/dist/core/tools/generateReport.d.ts +3 -0
  86. package/dist/core/tools/generateReport.d.ts.map +1 -0
  87. package/dist/core/tools/generateReport.js +315 -0
  88. package/dist/core/tools/generateReport.js.map +1 -0
  89. package/dist/core/tools/index.d.ts +7 -0
  90. package/dist/core/tools/index.d.ts.map +1 -1
  91. package/dist/core/tools/index.js +62 -23
  92. package/dist/core/tools/index.js.map +1 -1
  93. package/dist/core/tools/recommendProfile.d.ts +3 -0
  94. package/dist/core/tools/recommendProfile.d.ts.map +1 -0
  95. package/dist/core/tools/recommendProfile.js +334 -0
  96. package/dist/core/tools/recommendProfile.js.map +1 -0
  97. package/dist/core/tools/ruleGen.d.ts +3 -0
  98. package/dist/core/tools/ruleGen.d.ts.map +1 -0
  99. package/dist/core/tools/ruleGen.js +1103 -0
  100. package/dist/core/tools/ruleGen.js.map +1 -0
  101. package/dist/core/tools/standards.d.ts.map +1 -1
  102. package/dist/core/tools/standards.js +7 -3
  103. package/dist/core/tools/standards.js.map +1 -1
  104. package/dist/ui/App.d.ts.map +1 -1
  105. package/dist/ui/App.js +86 -35
  106. package/dist/ui/App.js.map +1 -1
  107. package/dist/ui/components/InputBox.d.ts +1 -3
  108. package/dist/ui/components/InputBox.d.ts.map +1 -1
  109. package/dist/ui/components/InputBox.js +146 -5
  110. package/dist/ui/components/InputBox.js.map +1 -1
  111. package/dist/ui/components/MessageList.d.ts +3 -1
  112. package/dist/ui/components/MessageList.d.ts.map +1 -1
  113. package/dist/ui/components/MessageList.js +13 -7
  114. package/dist/ui/components/MessageList.js.map +1 -1
  115. package/dist/ui/components/StatusBar.d.ts +1 -1
  116. package/dist/ui/components/StatusBar.d.ts.map +1 -1
  117. package/dist/ui/components/StatusBar.js +3 -2
  118. package/dist/ui/components/StatusBar.js.map +1 -1
  119. package/dist/ui/components/ToolStatus.d.ts +3 -1
  120. package/dist/ui/components/ToolStatus.d.ts.map +1 -1
  121. package/dist/ui/components/ToolStatus.js +19 -4
  122. package/dist/ui/components/ToolStatus.js.map +1 -1
  123. package/package.json +7 -1
  124. package/demo.gif +0 -0
  125. package/demo.tape +0 -53
  126. package/screenshot.png +0 -0
  127. package/src/cli/banner.ts +0 -38
  128. package/src/cli/headless.ts +0 -63
  129. package/src/cli/index.ts +0 -57
  130. package/src/core/agent.ts +0 -711
  131. package/src/core/commands.ts +0 -118
  132. package/src/core/config.ts +0 -98
  133. package/src/core/conversation.ts +0 -235
  134. package/src/core/llm/ollama.ts +0 -351
  135. package/src/core/mcp/client.ts +0 -143
  136. package/src/core/tools/analyzeAll.ts +0 -482
  137. package/src/core/tools/ast.ts +0 -826
  138. package/src/core/tools/builtIn.ts +0 -221
  139. package/src/core/tools/cache.ts +0 -570
  140. package/src/core/tools/cssAnalysis.ts +0 -324
  141. package/src/core/tools/dependencyAnalysis.ts +0 -363
  142. package/src/core/tools/embeddings.ts +0 -746
  143. package/src/core/tools/frontendAst.ts +0 -802
  144. package/src/core/tools/htmlAnalysis.ts +0 -466
  145. package/src/core/tools/index.ts +0 -160
  146. package/src/core/tools/javaAst.ts +0 -1030
  147. package/src/core/tools/javaQuality.integration.test.ts +0 -537
  148. package/src/core/tools/memory.ts +0 -655
  149. package/src/core/tools/mybatisAnalysis.ts +0 -322
  150. package/src/core/tools/openapiAnalysis.ts +0 -431
  151. package/src/core/tools/pythonAnalysis.ts +0 -477
  152. package/src/core/tools/sqlAnalysis.ts +0 -298
  153. package/src/core/tools/standards.test.ts +0 -186
  154. package/src/core/tools/standards.ts +0 -889
  155. package/src/core/tools/types.ts +0 -38
  156. package/src/ui/App.tsx +0 -334
  157. package/src/ui/components/InputBox.tsx +0 -37
  158. package/src/ui/components/MessageList.tsx +0 -80
  159. package/src/ui/components/StatusBar.tsx +0 -36
  160. package/src/ui/components/ToolStatus.tsx +0 -38
  161. 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
- }